ClientAuthenticationMiddlewareTest   A
last analyzed

Complexity

Total Complexity 13

Size/Duplication

Total Lines 263
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 13
eloc 173
dl 0
loc 263
rs 10
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A aClientIsFullyAuthenticated() 0 34 1
A noClientIsFoundInTheRequest() 0 13 1
A aClientIdIsSetButTheClientIsNotAuthenticated() 0 37 2
A aClientIdIsSetButTheAuthenticationMethodIsNotSupportedByTheClient() 0 35 2
A getClientAuthenticationMiddleware() 0 8 1
A aClientIdIsSetButTheClientCredentialsExpired() 0 36 2
A aClientIdIsSetButTheClientIsDeleted() 0 31 2
A aClientIdIsSetButTheClientDoesNotExist() 0 25 2
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * The MIT License (MIT)
7
 *
8
 * Copyright (c) 2014-2019 Spomky-Labs
9
 *
10
 * This software may be modified and distributed under the terms
11
 * of the MIT license.  See the LICENSE file for details.
12
 */
13
14
namespace OAuth2Framework\Component\ClientAuthentication\Tests;
15
16
use OAuth2Framework\Component\ClientAuthentication\AuthenticationMethod;
17
use OAuth2Framework\Component\ClientAuthentication\AuthenticationMethodManager;
18
use OAuth2Framework\Component\ClientAuthentication\ClientAuthenticationMiddleware;
19
use OAuth2Framework\Component\ClientAuthentication\ClientSecretBasic;
20
use OAuth2Framework\Component\Core\Client\Client;
21
use OAuth2Framework\Component\Core\Client\ClientId;
22
use OAuth2Framework\Component\Core\Client\ClientRepository;
23
use OAuth2Framework\Component\Core\Message\OAuth2Error;
24
use PHPUnit\Framework\TestCase;
25
use Prophecy\Argument;
26
use Prophecy\PhpUnit\ProphecyTrait;
27
use Psr\Http\Message\ResponseInterface;
28
use Psr\Http\Message\ServerRequestInterface;
29
use Psr\Http\Server\RequestHandlerInterface;
30
31
/**
32
 * @group TokenEndpoint
33
 * @group ClientAuthenticationMiddleware
34
 *
35
 * @internal
36
 */
37
final class ClientAuthenticationMiddlewareTest extends TestCase
38
{
39
    use ProphecyTrait;
40
41
    /**
42
     * @test
43
     */
44
    public function noClientIsFoundInTheRequest()
45
    {
46
        $response = $this->prophesize(ResponseInterface::class);
47
        $request = $this->prophesize(ServerRequestInterface::class);
48
        $request->getHeader('Authorization')->willReturn([])->shouldBeCalled();
49
        $handler = $this->prophesize(RequestHandlerInterface::class);
50
        $clientRepository = $this->prophesize(ClientRepository::class);
51
        $handler->handle(Argument::type(ServerRequestInterface::class))
52
            ->shouldBeCalled()
53
            ->willReturn($response->reveal())
54
        ;
55
56
        $this->getClientAuthenticationMiddleware($clientRepository->reveal())->process($request->reveal(), $handler->reveal());
57
    }
58
59
    /**
60
     * @test
61
     */
62
    public function aClientIdIsSetButTheClientDoesNotExist()
63
    {
64
        $request = $this->prophesize(ServerRequestInterface::class);
65
        $request->getHeader('Authorization')
66
            ->willReturn([
67
                'Basic '.base64_encode('FOO:BAR'),
68
            ])
69
            ->shouldBeCalled()
70
        ;
71
        $handler = $this->prophesize(RequestHandlerInterface::class);
72
        $clientRepository = $this->prophesize(ClientRepository::class);
73
        $clientRepository->find(Argument::type(ClientId::class))->willReturn(null)->shouldBeCalled();
74
        $handler->handle(Argument::type(ServerRequestInterface::class))
75
            ->shouldNotBeCalled()
76
        ;
77
78
        try {
79
            $this->getClientAuthenticationMiddleware($clientRepository->reveal())->process($request->reveal(), $handler->reveal());
80
            static::fail('An OAuth2 exception should be thrown.');
81
        } catch (OAuth2Error $e) {
82
            static::assertEquals(401, $e->getCode());
83
            static::assertEquals([
84
                'error' => 'invalid_client',
85
                'error_description' => 'Client authentication failed.',
86
            ], $e->getData());
87
        }
88
    }
89
90
    /**
91
     * @test
92
     */
93
    public function aClientIdIsSetButTheClientIsDeleted()
94
    {
95
        $client = $this->prophesize(Client::class);
96
        $client->isPublic()->willReturn(false);
97
        $client->getPublicId()->willReturn(new ClientId('FOO'));
98
        $client->getClientId()->willReturn(new ClientId('FOO'));
99
        $client->isDeleted()->willReturn(true);
100
101
        $request = $this->prophesize(ServerRequestInterface::class);
102
        $request->getHeader('Authorization')
103
            ->willReturn([
104
                'Basic '.base64_encode('FOO:BAR'),
105
            ])
106
            ->shouldBeCalled()
107
        ;
108
        $handler = $this->prophesize(RequestHandlerInterface::class);
109
        $clientRepository = $this->prophesize(ClientRepository::class);
110
        $clientRepository->find(Argument::type(ClientId::class))->willReturn($client)->shouldBeCalled();
111
        $handler->handle(Argument::type(ServerRequestInterface::class))
112
            ->shouldNotBeCalled()
113
        ;
114
115
        try {
116
            $this->getClientAuthenticationMiddleware($clientRepository->reveal())->process($request->reveal(), $handler->reveal());
117
            static::fail('An OAuth2 exception should be thrown.');
118
        } catch (OAuth2Error $e) {
119
            static::assertEquals(401, $e->getCode());
120
            static::assertEquals([
121
                'error' => 'invalid_client',
122
                'error_description' => 'Client authentication failed.',
123
            ], $e->getData());
124
        }
125
    }
126
127
    /**
128
     * @test
129
     */
130
    public function aClientIdIsSetButTheClientCredentialsExpired()
131
    {
132
        $client = $this->prophesize(Client::class);
133
        $client->isPublic()->willReturn(false);
134
        $client->getPublicId()->willReturn(new ClientId('FOO'));
135
        $client->getClientId()->willReturn(new ClientId('FOO'));
136
        $client->get('token_endpoint_auth_method')->willReturn('client_secret_basic');
137
        $client->getTokenEndpointAuthenticationMethod()->willReturn('client_secret_basic');
138
        $client->isDeleted()->willReturn(false);
139
        $client->has('client_secret')->willReturn(false);
140
        $client->get('client_secret')->willReturn('BAR');
141
        $client->areClientCredentialsExpired()->willReturn(true);
142
143
        $request = $this->prophesize(ServerRequestInterface::class);
144
        $request->getHeader('Authorization')
145
            ->willReturn([
146
                'Basic '.base64_encode('FOO:BAR'),
147
            ])
148
            ->shouldBeCalled()
149
        ;
150
        $handler = $this->prophesize(RequestHandlerInterface::class);
151
        $clientRepository = $this->prophesize(ClientRepository::class);
152
        $clientRepository->find(Argument::type(ClientId::class))->willReturn($client)->shouldBeCalled();
153
        $handler->handle(Argument::type(ServerRequestInterface::class))
154
            ->shouldNotBeCalled()
155
        ;
156
157
        try {
158
            $this->getClientAuthenticationMiddleware($clientRepository->reveal())->process($request->reveal(), $handler->reveal());
159
            static::fail('An OAuth2 exception should be thrown.');
160
        } catch (OAuth2Error $e) {
161
            static::assertEquals(401, $e->getCode());
162
            static::assertEquals([
163
                'error' => 'invalid_client',
164
                'error_description' => 'Client credentials expired.',
165
            ], $e->getData());
166
        }
167
    }
168
169
    /**
170
     * @test
171
     */
172
    public function aClientIdIsSetButTheAuthenticationMethodIsNotSupportedByTheClient()
173
    {
174
        $client = $this->prophesize(Client::class);
175
        $client->isPublic()->willReturn(false);
176
        $client->getPublicId()->willReturn(new ClientId('FOO'));
177
        $client->getClientId()->willReturn(new ClientId('FOO'));
178
        $client->has('token_endpoint_auth_method')->willReturn(true);
179
        $client->get('token_endpoint_auth_method')->willReturn('none');
180
        $client->getTokenEndpointAuthenticationMethod()->willReturn('none');
181
        $client->isDeleted()->willReturn(false);
182
        $client->areClientCredentialsExpired()->willReturn(false);
183
184
        $request = $this->prophesize(ServerRequestInterface::class);
185
        $request->getHeader('Authorization')
186
            ->willReturn([
187
                'Basic '.base64_encode('FOO:BAR'),
188
            ])
189
            ->shouldBeCalled()
190
        ;
191
        $handler = $this->prophesize(RequestHandlerInterface::class);
192
        $clientRepository = $this->prophesize(ClientRepository::class);
193
        $clientRepository->find(Argument::type(ClientId::class))->willReturn($client)->shouldBeCalled();
194
        $handler->handle(Argument::type(ServerRequestInterface::class))
195
            ->shouldNotBeCalled()
196
        ;
197
198
        try {
199
            $this->getClientAuthenticationMiddleware($clientRepository->reveal())->process($request->reveal(), $handler->reveal());
200
            static::fail('An OAuth2 exception should be thrown.');
201
        } catch (OAuth2Error $e) {
202
            static::assertEquals(401, $e->getCode());
203
            static::assertEquals([
204
                'error' => 'invalid_client',
205
                'error_description' => 'Client authentication failed.',
206
            ], $e->getData());
207
        }
208
    }
209
210
    /**
211
     * @test
212
     */
213
    public function aClientIdIsSetButTheClientIsNotAuthenticated()
214
    {
215
        $client = $this->prophesize(Client::class);
216
        $client->isPublic()->willReturn(false);
217
        $client->getPublicId()->willReturn(new ClientId('FOO'));
218
        $client->getClientId()->willReturn(new ClientId('FOO'));
219
        $client->has('token_endpoint_auth_method')->willReturn(true);
220
        $client->get('token_endpoint_auth_method')->willReturn('client_secret_basic');
221
        $client->getTokenEndpointAuthenticationMethod()->willReturn('client_secret_basic');
222
        $client->has('client_secret')->willReturn(true);
223
        $client->get('client_secret')->willReturn('BAR');
224
        $client->isDeleted()->willReturn(false);
225
        $client->areClientCredentialsExpired()->willReturn(false);
226
227
        $request = $this->prophesize(ServerRequestInterface::class);
228
        $request->getHeader('Authorization')
229
            ->willReturn([
230
                'Basic '.base64_encode('FOO:BAD_SECRET'),
231
            ])
232
            ->shouldBeCalled()
233
        ;
234
        $handler = $this->prophesize(RequestHandlerInterface::class);
235
        $clientRepository = $this->prophesize(ClientRepository::class);
236
        $clientRepository->find(Argument::type(ClientId::class))->willReturn($client)->shouldBeCalled();
237
        $handler->handle(Argument::type(ServerRequestInterface::class))
238
            ->shouldNotBeCalled()
239
        ;
240
241
        try {
242
            $this->getClientAuthenticationMiddleware($clientRepository->reveal())->process($request->reveal(), $handler->reveal());
243
            static::fail('An OAuth2 exception should be thrown.');
244
        } catch (OAuth2Error $e) {
245
            static::assertEquals(401, $e->getCode());
246
            static::assertEquals([
247
                'error' => 'invalid_client',
248
                'error_description' => 'Client authentication failed.',
249
            ], $e->getData());
250
        }
251
    }
252
253
    /**
254
     * @test
255
     */
256
    public function aClientIsFullyAuthenticated()
257
    {
258
        $client = $this->prophesize(Client::class);
259
        $client->isPublic()->willReturn(false);
260
        $client->getPublicId()->willReturn(new ClientId('FOO'));
261
        $client->getClientId()->willReturn(new ClientId('FOO'));
262
        $client->has('token_endpoint_auth_method')->willReturn(true);
263
        $client->get('token_endpoint_auth_method')->willReturn('client_secret_basic');
264
        $client->getTokenEndpointAuthenticationMethod()->willReturn('client_secret_basic');
265
        $client->has('client_secret')->willReturn(true);
266
        $client->get('client_secret')->willReturn('BAR');
267
        $client->isDeleted()->willReturn(false);
268
        $client->areClientCredentialsExpired()->willReturn(false);
269
270
        $response = $this->prophesize(ResponseInterface::class);
271
        $request = $this->prophesize(ServerRequestInterface::class);
272
        $request->getHeader('Authorization')
273
            ->willReturn([
274
                'Basic '.base64_encode('FOO:BAR'),
275
            ])
276
            ->shouldBeCalled()
277
        ;
278
        $request->withAttribute('client', $client)->shouldBeCalled()->willReturn($request->reveal());
279
        $request->withAttribute('client_authentication_method', Argument::type(AuthenticationMethod::class))->shouldBeCalled()->willReturn($request->reveal());
280
        $request->withAttribute('client_credentials', 'BAR')->shouldBeCalled()->willReturn($request->reveal());
281
        $handler = $this->prophesize(RequestHandlerInterface::class);
282
        $clientRepository = $this->prophesize(ClientRepository::class);
283
        $clientRepository->find(Argument::type(ClientId::class))->willReturn($client)->shouldBeCalled();
284
        $handler->handle(Argument::type(ServerRequestInterface::class))
285
            ->shouldBeCalled()
286
            ->willReturn($response->reveal())
287
        ;
288
289
        $this->getClientAuthenticationMiddleware($clientRepository->reveal())->process($request->reveal(), $handler->reveal());
290
    }
291
292
    private function getClientAuthenticationMiddleware(ClientRepository $clientRepository): ClientAuthenticationMiddleware
293
    {
294
        $authenticationMethodManager = new AuthenticationMethodManager();
295
        $authenticationMethodManager->add(new ClientSecretBasic('Real'));
296
297
        return new ClientAuthenticationMiddleware(
298
            $clientRepository,
299
            $authenticationMethodManager
300
        );
301
    }
302
}
303