Completed
Branch master (910c19)
by Dmitri
01:43
created

DamaxApiAuthExtensionTest   A

Complexity

Total Complexity 9

Size/Duplication

Total Lines 257
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 126
dl 0
loc 257
rs 10
c 0
b 0
f 0
wmc 9
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Damax\Bundle\ApiAuthBundle\Tests\DependencyInjection;
6
7
use Damax\Bundle\ApiAuthBundle\Command\Storage\AddKeyCommand;
8
use Damax\Bundle\ApiAuthBundle\Command\Storage\LookupKeyCommand;
9
use Damax\Bundle\ApiAuthBundle\Command\Storage\RemoveKeyCommand;
10
use Damax\Bundle\ApiAuthBundle\Controller\TokenController;
11
use Damax\Bundle\ApiAuthBundle\DependencyInjection\DamaxApiAuthExtension;
12
use Damax\Bundle\ApiAuthBundle\Extractor\ChainExtractor;
13
use Damax\Bundle\ApiAuthBundle\Extractor\CookieExtractor;
14
use Damax\Bundle\ApiAuthBundle\Extractor\HeaderExtractor;
15
use Damax\Bundle\ApiAuthBundle\Extractor\QueryExtractor;
16
use Damax\Bundle\ApiAuthBundle\Jwt\Claims\OrganizationClaims;
17
use Damax\Bundle\ApiAuthBundle\Jwt\Claims\SecurityClaims;
18
use Damax\Bundle\ApiAuthBundle\Jwt\Claims\TimestampClaims;
19
use Damax\Bundle\ApiAuthBundle\Jwt\Lcobucci\Builder;
20
use Damax\Bundle\ApiAuthBundle\Jwt\Lcobucci\Parser;
21
use Damax\Bundle\ApiAuthBundle\Jwt\TokenBuilder;
22
use Damax\Bundle\ApiAuthBundle\Key\Generator\Generator;
23
use Damax\Bundle\ApiAuthBundle\Key\Generator\RandomGenerator;
24
use Damax\Bundle\ApiAuthBundle\Key\Storage\ChainStorage;
25
use Damax\Bundle\ApiAuthBundle\Key\Storage\DoctrineStorage;
26
use Damax\Bundle\ApiAuthBundle\Key\Storage\InMemoryStorage;
27
use Damax\Bundle\ApiAuthBundle\Key\Storage\Reader;
28
use Damax\Bundle\ApiAuthBundle\Key\Storage\RedisStorage;
29
use Damax\Bundle\ApiAuthBundle\Security\ApiKey\Authenticator as ApiKeyAuthenticator;
30
use Damax\Bundle\ApiAuthBundle\Security\ApiKey\StorageUserProvider;
31
use Damax\Bundle\ApiAuthBundle\Security\JsonResponseFactory;
32
use Damax\Bundle\ApiAuthBundle\Security\Jwt\Authenticator as JwtAuthenticator;
33
use Damax\Bundle\ApiAuthBundle\Security\ResponseFactory;
34
use Lcobucci\JWT\Configuration;
35
use Lcobucci\JWT\Signer\Rsa\Sha256;
36
use Matthias\SymfonyDependencyInjectionTest\PhpUnit\AbstractExtensionTestCase;
37
use Symfony\Component\DependencyInjection\Definition;
38
use Symfony\Component\DependencyInjection\Reference;
39
40
class DamaxApiAuthExtensionTest extends AbstractExtensionTestCase
41
{
42
    protected function setUp()
43
    {
44
        parent::setUp();
45
46
        $this->container->setParameter('kernel.bundles', []);
47
    }
48
49
    /**
50
     * @test
51
     */
52
    public function it_registers_response_factory()
53
    {
54
        $this->load();
55
56
        $this->assertContainerBuilderHasService(JsonResponseFactory::class);
57
        $this->assertContainerBuilderHasAlias(ResponseFactory::class, JsonResponseFactory::class);
58
    }
59
60
    /**
61
     * @test
62
     */
63
    public function it_registers_custom_response_factory()
64
    {
65
        $this->load(['response_factory_service_id' => 'factory_service_id']);
66
67
        $this->assertContainerBuilderHasService(JsonResponseFactory::class);
68
        $this->assertContainerBuilderHasAlias(ResponseFactory::class, 'factory_service_id');
69
    }
70
71
    /**
72
     * @test
73
     */
74
    public function it_registers_api_key_services()
75
    {
76
        $this->load([
77
            'api_key' => [
78
                'extractors' => [
79
                    ['type' => 'header', 'name' => 'X-Authorization', 'prefix' => 'KEY'],
80
                    ['type' => 'query', 'name' => 'api_key'],
81
                    ['type' => 'cookie', 'name' => 'api_key'],
82
                ],
83
            ],
84
        ]);
85
86
        $this->assertContainerBuilderHasService(Generator::class, RandomGenerator::class);
87
        $this->assertContainerBuilderHasServiceDefinitionWithArgument(Generator::class, 0, 20);
88
        $this->assertContainerBuilderHasService('damax.api_auth.api_key.user_provider', StorageUserProvider::class);
89
        $this->assertContainerBuilderHasService('damax.api_auth.api_key.authenticator', ApiKeyAuthenticator::class);
90
        $this->assertContainerBuilderHasService(Reader::class, ChainStorage::class);
91
92
        /** @var Definition $extractors */
93
        $extractors = $this->container
94
            ->getDefinition('damax.api_auth.api_key.authenticator')
95
            ->getArgument(0)
96
        ;
97
        $this->assertEquals(ChainExtractor::class, $extractors->getClass());
98
        $this->assertContainerBuilderHasServiceDefinitionWithArgument('damax.api_auth.api_key.authenticator', 1, ResponseFactory::class);
99
100
        // Console
101
        $this->assertContainerBuilderHasServiceDefinitionWithTag(AddKeyCommand::class, 'console.command');
102
        $this->assertContainerBuilderHasServiceDefinitionWithTag(RemoveKeyCommand::class, 'console.command');
103
        $this->assertContainerBuilderHasServiceDefinitionWithTag(LookupKeyCommand::class, 'console.command');
104
    }
105
106
    /**
107
     * @test
108
     */
109
    public function it_registers_key_extractors()
110
    {
111
        $this->load([
112
            'api_key' => [
113
                'extractors' => [
114
                    ['type' => 'header', 'name' => 'X-Authorization', 'prefix' => 'KEY'],
115
                    ['type' => 'query', 'name' => 'api_key'],
116
                    ['type' => 'cookie', 'name' => 'api_key'],
117
                ],
118
            ],
119
        ]);
120
121
        /** @var Definition[] $extractors */
122
        $extractors = $this->container
123
            ->getDefinition('damax.api_auth.api_key.authenticator')
124
            ->getArgument(0)
125
            ->getArgument(0)
126
        ;
127
128
        // Header
129
        $this->assertEquals(HeaderExtractor::class, $extractors[0]->getClass());
130
        $this->assertEquals('X-Authorization', $extractors[0]->getArgument(0));
131
        $this->assertEquals('KEY', $extractors[0]->getArgument(1));
132
133
        // Query
134
        $this->assertEquals(QueryExtractor::class, $extractors[1]->getClass());
135
        $this->assertEquals('api_key', $extractors[1]->getArgument(0));
136
137
        // Cookie
138
        $this->assertEquals(CookieExtractor::class, $extractors[2]->getClass());
139
        $this->assertEquals('api_key', $extractors[2]->getArgument(0));
140
    }
141
142
    /**
143
     * @test
144
     */
145
    public function it_registers_key_storage_drivers()
146
    {
147
        $this->load([
148
            'api_key' => [
149
                'generator' => ['key_size' => 40],
150
                'storage' => [
151
                    [
152
                        'type' => 'fixed',
153
                        'tokens' => ['john.doe' => 'ABC', 'jane.doe' => 'XYZ'],
154
                    ],
155
                    [
156
                        'type' => 'redis',
157
                        'key_prefix' => 'api_',
158
                    ],
159
                    [
160
                        'type' => 'doctrine',
161
                        'fields' => ['key' => 'id', 'identity' => 'user_id'],
162
                    ],
163
                ],
164
            ],
165
        ]);
166
167
        $this->assertContainerBuilderHasServiceDefinitionWithArgument(Generator::class, 0, 40);
168
169
        /** @var Definition[] $drivers */
170
        $drivers = $this->container->getDefinition(Reader::class)->getArgument(0);
171
172
        // In memory
173
        $this->assertEquals(InMemoryStorage::class, $drivers[0]->getClass());
174
        $this->assertEquals(['john.doe' => 'ABC', 'jane.doe' => 'XYZ'], $drivers[0]->getArgument(0));
175
176
        // Redis
177
        $this->assertEquals(RedisStorage::class, $drivers[1]->getClass());
178
        $this->assertEquals(new Reference('snc_redis.default'), $drivers[1]->getArgument(0));
179
        $this->assertEquals('api_', $drivers[1]->getArgument(1));
180
181
        // Doctrine
182
        $this->assertEquals(DoctrineStorage::class, $drivers[2]->getClass());
183
        $this->assertEquals(new Reference('database_connection'), $drivers[2]->getArgument(0));
184
        $this->assertEquals('api_key', $drivers[2]->getArgument(1));
185
        $this->assertEquals(['key' => 'id', 'identity' => 'user_id'], $drivers[2]->getArgument(2));
186
    }
187
188
    /**
189
     * @test
190
     */
191
    public function it_registers_jwt_services_with_symmetric_signer()
192
    {
193
        $key = tempnam(sys_get_temp_dir(), 'key_');
194
195
        $this->load([
196
            'jwt' => [
197
                'identity_claim' => 'username',
198
                'signer' => [
199
                    'type' => 'asymmetric',
200
                    'algorithm' => 'RS256',
201
                    'signing_key' => $key,
202
                    'verification_key' => $key,
203
                ],
204
                'parser' => [
205
                    'issuers' => ['damax', 'damax-api-auth-bundle'],
206
                    'audience' => 'symfony',
207
                ],
208
                'builder' => [
209
                    'issuer' => 'damax',
210
                    'audience' => 'zend',
211
                    'ttl' => 600,
212
                ],
213
            ],
214
        ]);
215
216
        $this->assertContainerBuilderHasService('damax.api_auth.jwt.authenticator', JwtAuthenticator::class);
217
        $this->assertContainerBuilderHasServiceDefinitionWithArgument('damax.api_auth.jwt.authenticator', 3, 'username');
218
219
        /** @var Definition $extractors */
220
        $extractors = $this->container
221
            ->getDefinition('damax.api_auth.jwt.authenticator')
222
            ->getArgument(0)
223
        ;
224
        $this->assertEquals(ChainExtractor::class, $extractors->getClass());
225
226
        /** @var Definition[] $definitions */
227
        $definitions = $extractors->getArgument(0);
228
229
        // Header
230
        $this->assertEquals(HeaderExtractor::class, $definitions[0]->getClass());
231
        $this->assertEquals('Authorization', $definitions[0]->getArgument(0));
232
        $this->assertEquals('Bearer', $definitions[0]->getArgument(1));
233
234
        $this->assertContainerBuilderHasServiceDefinitionWithArgument('damax.api_auth.jwt.authenticator', 1, ResponseFactory::class);
235
236
        /** @var Definition $parser */
237
        $parser = $this->container
238
            ->getDefinition('damax.api_auth.jwt.authenticator')
239
            ->getArgument(2)
240
        ;
241
        $this->assertEquals(Parser::class, $parser->getClass());
242
        $this->assertEquals(['damax', 'damax-api-auth-bundle'], $parser->getArgument(2));
243
        $this->assertEquals('symfony', $parser->getArgument(3));
244
245
        /** @var Definition $config */
246
        $config = $parser->getArgument(0);
247
        $this->assertEquals(Configuration::class, $config->getClass());
248
        $this->assertCount(3, $config->getArguments());
249
250
        /** @var Definition $signer */
251
        $signer = $config->getArgument(0);
252
        $this->assertEquals(Sha256::class, $signer->getClass());
253
254
        $this->assertContainerBuilderHasService('damax.api_auth.jwt.handler');
255
256
        // Builder
257
        $this->assertContainerBuilderHasService(TokenBuilder::class, Builder::class);
258
        $this->assertContainerBuilderHasServiceDefinitionWithArgument(TokenBuilder::class, 0, $config);
259
260
        // Claims
261
        $this->assertContainerBuilderHasServiceDefinitionWithArgument(TimestampClaims::class, 0);
262
        $this->assertContainerBuilderHasServiceDefinitionWithArgument(TimestampClaims::class, 1, 600);
263
        $this->assertContainerBuilderHasServiceDefinitionWithTag(TimestampClaims::class, 'damax.api_auth.jwt_claims');
264
        $this->assertContainerBuilderHasServiceDefinitionWithArgument(OrganizationClaims::class, 0, 'damax');
265
        $this->assertContainerBuilderHasServiceDefinitionWithArgument(OrganizationClaims::class, 1, 'zend');
266
        $this->assertContainerBuilderHasServiceDefinitionWithTag(OrganizationClaims::class, 'damax.api_auth.jwt_claims');
267
        $this->assertContainerBuilderHasService(SecurityClaims::class);
268
        $this->assertContainerBuilderHasServiceDefinitionWithTag(SecurityClaims::class, 'damax.api_auth.jwt_claims');
269
270
        // Controller
271
        $this->assertContainerBuilderHasServiceDefinitionWithTag(TokenController::class, 'controller.service_arguments');
272
273
        unlink($key);
274
    }
275
276
    /**
277
     * @test
278
     */
279
    public function it_configures_nelmio_api_doc_definitions()
280
    {
281
        $this->container->setParameter('kernel.bundles', ['NelmioApiDocBundle' => true]);
282
283
        $this->load();
284
285
        $config = $this->container->getExtensionConfig('nelmio_api_doc')[0];
286
287
        $this->assertArrayHasKey('documentation', $config);
288
        $this->assertArrayHasKey('definitions', $config['documentation']);
289
        $this->assertArrayHasKey('SecurityLogin', $config['documentation']['definitions']);
290
        $this->assertArrayHasKey('SecurityLoginResult', $config['documentation']['definitions']);
291
    }
292
293
    protected function getContainerExtensions(): array
294
    {
295
        return [
296
            new DamaxApiAuthExtension(),
297
        ];
298
    }
299
}
300