Failed Conditions
Push — master ( 9eeb29...881d26 )
by Florent
16:44
created

TokenEndpointTest   A

Complexity

Total Complexity 13

Size/Duplication

Total Lines 193
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 14

Importance

Changes 0
Metric Value
wmc 13
lcom 1
cbo 14
dl 0
loc 193
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A unauthenticatedClient() 0 24 2
A theClientIsNotAllowedToUseTheGrantType() 0 32 2
A theTokenRequestIsValidAndAnAccessTokenIsIssued() 0 39 1
A getTokenEndpoint() 0 15 2
A getClientRepository() 0 20 2
A getUserAccountRepository() 0 10 2
A getAccessTokenRepository() 0 15 2
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * The MIT License (MIT)
7
 *
8
 * Copyright (c) 2014-2018 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\TokenEndpoint\Tests;
15
16
use Http\Message\MessageFactory\GuzzleMessageFactory;
17
use OAuth2Framework\Component\Core\AccessToken\AccessToken;
18
use OAuth2Framework\Component\Core\AccessToken\AccessTokenId;
19
use OAuth2Framework\Component\Core\AccessToken\AccessTokenRepository;
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\DataBag\DataBag;
24
use OAuth2Framework\Component\Core\Message\OAuth2Error;
25
use OAuth2Framework\Component\Core\ResourceOwner\ResourceOwnerId;
26
use OAuth2Framework\Component\Core\TokenType\TokenType;
27
use OAuth2Framework\Component\Core\UserAccount\UserAccountId;
28
use OAuth2Framework\Component\Core\UserAccount\UserAccountRepository;
29
use OAuth2Framework\Component\TokenEndpoint\Extension\TokenEndpointExtensionManager;
30
use OAuth2Framework\Component\TokenEndpoint\TokenEndpoint;
31
use PHPUnit\Framework\TestCase;
32
use Prophecy\Argument;
33
use Psr\Http\Message\ServerRequestInterface;
34
use Psr\Http\Server\RequestHandlerInterface;
35
36
/**
37
 * @group TokenEndpoint
38
 */
39
final class TokenEndpointTest extends TestCase
40
{
41
    /**
42
     * @test
43
     */
44
    public function unauthenticatedClient()
45
    {
46
        $request = $this->prophesize(ServerRequestInterface::class);
47
        $request->getAttribute('grant_type')
48
            ->willReturn(new FooGrantType())
49
            ->shouldBeCalled()
50
        ;
51
        $request->getAttribute('client')
52
            ->willReturn(null)
53
            ->shouldBeCalled()
54
        ;
55
56
        $handler = $this->prophesize(RequestHandlerInterface::class);
57
58
        try {
59
            $this->getTokenEndpoint()->process($request->reveal(), $handler->reveal());
60
        } catch (OAuth2Error $e) {
61
            static::assertEquals(401, $e->getCode());
62
            static::assertEquals([
63
                'error' => 'invalid_client',
64
                'error_description' => 'Client authentication failed.',
65
            ], $e->getData());
66
        }
67
    }
68
69
    /**
70
     * @test
71
     */
72
    public function theClientIsNotAllowedToUseTheGrantType()
73
    {
74
        $client = $this->prophesize(Client::class);
75
        $client->isPublic()->willReturn(false);
76
        $client->getPublicId()->willReturn(new ClientId('CLIENT_ID'));
77
        $client->getClientId()->willReturn(new ClientId('CLIENT_ID'));
78
        $client->getOwnerId()->willReturn(new UserAccountId('OWNER_ID'));
79
        $client->isDeleted()->willReturn(false);
80
        $client->isGrantTypeAllowed('foo')->willReturn(false);
81
82
        $request = $this->prophesize(ServerRequestInterface::class);
83
        $request->getAttribute('grant_type')
84
            ->willReturn(new FooGrantType())
85
            ->shouldBeCalled()
86
        ;
87
        $request->getAttribute('client')
88
            ->willReturn($client->reveal())
89
            ->shouldBeCalled()
90
        ;
91
92
        $handler = $this->prophesize(RequestHandlerInterface::class);
93
94
        try {
95
            $this->getTokenEndpoint()->process($request->reveal(), $handler->reveal());
96
        } catch (OAuth2Error $e) {
97
            static::assertEquals(400, $e->getCode());
98
            static::assertEquals([
99
                'error' => 'unauthorized_client',
100
                'error_description' => 'The grant type "foo" is unauthorized for this client.',
101
            ], $e->getData());
102
        }
103
    }
104
105
    /**
106
     * @test
107
     */
108
    public function theTokenRequestIsValidAndAnAccessTokenIsIssued()
109
    {
110
        $client = $this->prophesize(Client::class);
111
        $client->isPublic()->willReturn(false);
112
        $client->getPublicId()->willReturn(new ClientId('CLIENT_ID'));
113
        $client->getClientId()->willReturn(new ClientId('CLIENT_ID'));
114
        $client->getOwnerId()->willReturn(new UserAccountId('OWNER_ID'));
115
        $client->isDeleted()->willReturn(false);
116
        $client->isGrantTypeAllowed('foo')->willReturn(true);
117
118
        $request = $this->prophesize(ServerRequestInterface::class);
119
        $request->getAttribute('grant_type')
120
            ->willReturn(new FooGrantType())
121
            ->shouldBeCalled()
122
        ;
123
        $request->getAttribute('client')
124
            ->willReturn($client->reveal())
125
            ->shouldBeCalled()
126
        ;
127
128
        $tokenType = $this->prophesize(TokenType::class);
129
        $tokenType->name()->willReturn('TOKEN_TYPE')->shouldBeCalled();
130
        $tokenType->getAdditionalInformation()->willReturn(['token_type_foo' => 'token_type_bar'])->shouldBeCalled();
131
        $request->getAttribute('token_type')
132
            ->willReturn($tokenType->reveal())
133
            ->shouldBeCalled()
134
        ;
135
136
        $handler = $this->prophesize(RequestHandlerInterface::class);
137
        $handler->handle(Argument::type(ServerRequestInterface::class))
138
            ->shouldNotBeCalled();
139
140
        $response = $this->getTokenEndpoint()->process($request->reveal(), $handler->reveal());
141
        $response->getBody()->rewind();
142
        $body = $response->getBody()->getContents();
143
144
        static::assertEquals(200, $response->getStatusCode());
145
        static::assertRegExp('/^\{"token_type_foo"\:"token_type_bar","token_type"\:"TOKEN_TYPE","access_token"\:"[a-f0-9]{64}","expires_in"\:\d{4}\}$/', $body);
146
    }
147
148
    /**
149
     * @var null|TokenEndpoint
150
     */
151
    private $tokenEndpoint = null;
152
153
    private function getTokenEndpoint(): TokenEndpoint
154
    {
155
        if (null === $this->tokenEndpoint) {
156
            $this->tokenEndpoint = new TokenEndpoint(
157
                $this->getClientRepository(),
158
                $this->getUserAccountRepository(),
159
                new TokenEndpointExtensionManager(),
160
                new GuzzleMessageFactory(),
161
                $this->getAccessTokenRepository(),
162
                1800
163
            );
164
        }
165
166
        return $this->tokenEndpoint;
167
    }
168
169
    /**
170
     * @var null|ClientRepository
171
     */
172
    private $clientRepository = null;
173
174
    private function getClientRepository(): ClientRepository
175
    {
176
        if (null === $this->clientRepository) {
177
            $client = $this->prophesize(Client::class);
178
            $client->isPublic()->willReturn(false);
179
            $client->getPublicId()->willReturn(new ClientId('CLIENT_ID'));
180
            $client->getClientId()->willReturn(new ClientId('CLIENT_ID'));
181
            $client->getOwnerId()->willReturn(new UserAccountId('OWNER_ID'));
182
            $client->isDeleted()->willReturn(false);
183
            $client->has('grant_types')->willReturn(true);
184
            $client->get('grant_types')->willReturn(['foo']);
185
186
            $clientRepository = $this->prophesize(ClientRepository::class);
187
            $clientRepository->find(Argument::type(ClientId::class))->willReturn($client->reveal());
188
189
            $this->clientRepository = $clientRepository->reveal();
190
        }
191
192
        return $this->clientRepository;
193
    }
194
195
    /**
196
     * @var null|UserAccountRepository
197
     */
198
    private $userAccountRepository = null;
199
200
    private function getUserAccountRepository(): UserAccountRepository
201
    {
202
        if (null === $this->userAccountRepository) {
203
            $userAccountRepository = $this->prophesize(UserAccountRepository::class);
204
205
            $this->userAccountRepository = $userAccountRepository->reveal();
206
        }
207
208
        return $this->userAccountRepository;
209
    }
210
211
    /**
212
     * @var null|AccessTokenRepository
213
     */
214
    private $accessTokenRepository = null;
215
216
    private function getAccessTokenRepository(): AccessTokenRepository
217
    {
218
        if (null === $this->accessTokenRepository) {
219
            $accessTokenRepository = $this->prophesize(AccessTokenRepository::class);
220
            $accessTokenRepository->create(Argument::type(ClientId::class), Argument::type(ResourceOwnerId::class), Argument::type(\DateTimeImmutable::class), Argument::type(DataBag::class), Argument::type(DataBag::class), Argument::any())
221
                ->will(function (array $args) {
222
                    return new AccessToken(new AccessTokenId(\bin2hex(\random_bytes(32))), $args[0], $args[1], $args[2], $args[3], $args[4], $args[5]);
223
                });
224
            $accessTokenRepository->save(Argument::type(AccessToken::class))->will(function (array $args) {
0 ignored issues
show
Unused Code introduced by
The parameter $args is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
225
            });
226
            $this->accessTokenRepository = $accessTokenRepository->reveal();
227
        }
228
229
        return $this->accessTokenRepository;
230
    }
231
}
232