Issues (365)

Tests/AuthorizationCodeGrantTypeTest.php (1 issue)

Severity
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\AuthorizationCodeGrant\Tests;
15
16
use OAuth2Framework\Component\AuthorizationCodeGrant\AuthorizationCodeGrantType;
17
use OAuth2Framework\Component\AuthorizationCodeGrant\AuthorizationCodeId;
18
use OAuth2Framework\Component\AuthorizationCodeGrant\AuthorizationCodeRepository;
19
use OAuth2Framework\Component\AuthorizationCodeGrant\PKCEMethod\PKCEMethodManager;
20
use OAuth2Framework\Component\AuthorizationCodeGrant\PKCEMethod\Plain;
21
use OAuth2Framework\Component\AuthorizationCodeGrant\PKCEMethod\S256;
22
use OAuth2Framework\Component\Core\Client\Client;
23
use OAuth2Framework\Component\Core\Client\ClientId;
24
use OAuth2Framework\Component\Core\DataBag\DataBag;
25
use OAuth2Framework\Component\Core\Message\OAuth2Error;
26
use OAuth2Framework\Component\Core\ResourceServer\ResourceServerId;
27
use OAuth2Framework\Component\Core\UserAccount\UserAccountId;
28
use OAuth2Framework\Component\TokenEndpoint\GrantTypeData;
29
use PHPUnit\Framework\TestCase;
30
use Prophecy\Argument;
31
use Prophecy\PhpUnit\ProphecyTrait;
32
use Prophecy\Prophecy\ObjectProphecy;
33
use Psr\Http\Message\ServerRequestInterface;
34
use Psr\Http\Message\StreamInterface;
35
36
/**
37
 * @group GrantType
38
 * @group AuthorizationCodeGrantType
39
 *
40
 * @internal
41
 */
42
final class AuthorizationCodeGrantTypeTest extends TestCase
43
{
44
    use ProphecyTrait;
45
46
    /**
47
     * @var null|AuthorizationCodeGrantType
48
     */
49
    private $grantType;
50
51
    /**
52
     * @var null|PKCEMethodManager
53
     */
54
    private $pkceMethodManager;
55
56
    /**
57
     * @test
58
     */
59
    public function genericInformation()
60
    {
61
        static::assertEquals(['code'], $this->getGrantType()->associatedResponseTypes());
62
        static::assertEquals('authorization_code', $this->getGrantType()->name());
63
    }
64
65
    /**
66
     * @test
67
     */
68
    public function theRequestHaveMissingParameters()
69
    {
70
        $request = $this->buildRequest([]);
71
72
        try {
73
            $this->getGrantType()->checkRequest($request->reveal());
74
            static::fail('An OAuth2 exception should be thrown.');
75
        } catch (OAuth2Error $e) {
76
            static::assertEquals(400, $e->getCode());
77
            static::assertEquals([
78
                'error' => 'invalid_request',
79
                'error_description' => 'Missing grant type parameter(s): code, redirect_uri.',
80
            ], $e->getData());
81
        }
82
    }
83
84
    /**
85
     * @test
86
     */
87
    public function theRequestHaveAllRequiredParameters()
88
    {
89
        $request = $this->buildRequest(['code' => 'AUTHORIZATION_CODE_ID', 'redirect_uri' => 'http://localhost:8000/']);
90
91
        $this->getGrantType()->checkRequest($request->reveal());
92
        static::assertTrue(true);
93
    }
94
95
    /**
96
     * @test
97
     */
98
    public function theTokenResponseIsCorrectlyPrepared()
99
    {
100
        $client = $this->prophesize(Client::class);
101
        $request = $this->buildRequest(['code' => 'AUTHORIZATION_CODE_ID', 'redirect_uri' => 'http://localhost:8000/']);
102
        $grantTypeData = new GrantTypeData($client->reveal());
103
104
        $this->getGrantType()->prepareResponse($request->reveal(), $grantTypeData);
105
        static::assertSame($grantTypeData, $grantTypeData);
106
    }
107
108
    /**
109
     * @test
110
     */
111
    public function theGrantTypeCannotGrantTheClientAsTheCodeVerifierIsMissing()
112
    {
113
        $client = $this->prophesize(Client::class);
114
        $client->isPublic()->willReturn(false);
115
        $client->getPublicId()->willReturn(new ClientId('CLIENT_ID'));
116
117
        $request = $this->buildRequest(['code' => 'AUTHORIZATION_CODE_ID', 'redirect_uri' => 'http://localhost:8000/']);
118
        $request->getAttribute('client')->willReturn($client);
119
        $grantTypeData = new GrantTypeData($client->reveal());
120
121
        try {
122
            $this->getGrantType()->grant($request->reveal(), $grantTypeData);
123
        } catch (OAuth2Error $e) {
124
            static::assertEquals(400, $e->getCode());
125
            static::assertEquals([
126
                'error' => 'invalid_grant',
127
                'error_description' => 'The parameter "code_verifier" is missing or invalid.',
128
            ], $e->getData());
129
        }
130
    }
131
132
    /**
133
     * @test
134
     */
135
    public function theGrantTypeCanGrantTheClient()
136
    {
137
        $client = $this->prophesize(Client::class);
138
        $client->isPublic()->willReturn(false);
139
        $client->getPublicId()->willReturn(new ClientId('CLIENT_ID'));
140
141
        $request = $this->buildRequest(['code' => 'AUTHORIZATION_CODE_ID', 'redirect_uri' => 'http://localhost:8000/', 'code_verifier' => 'ABCDEFGH']);
142
        $request->getAttribute('client')->willReturn($client);
143
        $grantTypeData = new GrantTypeData($client->reveal());
144
145
        $this->getGrantType()->grant($request->reveal(), $grantTypeData);
146
        static::assertEquals('USER_ACCOUNT_ID', $grantTypeData->getResourceOwnerId()->getValue());
147
        static::assertEquals('CLIENT_ID', $grantTypeData->getClient()->getPublicId()->getValue());
148
    }
149
150
    private function getGrantType(): AuthorizationCodeGrantType
151
    {
152
        if (null === $this->grantType) {
153
            $authorizationCode = new AuthorizationCode(
154
                new AuthorizationCodeId('AUTHORIZATION_CODE_ID'),
155
                new ClientId('CLIENT_ID'),
156
                new UserAccountId('USER_ACCOUNT_ID'),
157
                [
158
                    'code_challenge' => 'ABCDEFGH',
159
                    'code_challenge_method' => 'plain',
160
                ],
161
                'http://localhost:8000/',
162
                new \DateTimeImmutable('now +1 day'),
163
                new DataBag([
164
                    'scope' => 'scope1 scope2',
165
                ]),
166
                new DataBag([]),
167
                new ResourceServerId('RESOURCE_SERVER_ID')
168
            );
169
            $authorizationCodeRepository = $this->prophesize(AuthorizationCodeRepository::class);
170
            $authorizationCodeRepository->find(new AuthorizationCodeId('AUTHORIZATION_CODE_ID'))->willReturn($authorizationCode);
171
            $authorizationCodeRepository->save(Argument::type(AuthorizationCode::class))->will(function (array $args) {
0 ignored issues
show
The parameter $args is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

171
            $authorizationCodeRepository->save(Argument::type(AuthorizationCode::class))->will(function (/** @scrutinizer ignore-unused */ array $args) {

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

Loading history...
172
            });
173
174
            $this->grantType = new AuthorizationCodeGrantType(
175
                $authorizationCodeRepository->reveal(),
176
                $this->getPkceMethodManager()
177
            );
178
        }
179
180
        return $this->grantType;
181
    }
182
183
    private function getPkceMethodManager(): PKCEMethodManager
184
    {
185
        if (null === $this->pkceMethodManager) {
186
            $this->pkceMethodManager = new PKCEMethodManager();
187
            $this->pkceMethodManager->add(new Plain());
188
            $this->pkceMethodManager->add(new S256());
189
        }
190
191
        return $this->pkceMethodManager;
192
    }
193
194
    private function buildRequest(array $data): ObjectProphecy
195
    {
196
        $body = $this->prophesize(StreamInterface::class);
197
        $body->getContents()->willReturn(http_build_query($data));
198
        $request = $this->prophesize(ServerRequestInterface::class);
199
        $request->hasHeader('Content-Type')->willReturn(true);
200
        $request->getHeader('Content-Type')->willReturn(['application/x-www-form-urlencoded']);
201
        $request->getBody()->willReturn($body->reveal());
202
        $request->getParsedBody()->willReturn([]);
203
204
        return $request;
205
    }
206
}
207