Failed Conditions
Push — ng ( a004c2...0b9cb0 )
by Florent
03:36
created

JwtBearerGrantTest::theAssertionIsInvalid()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 6
nc 1
nop 0
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\Bundle\Tests\Functional\Grant\JwtBearer;
15
16
use Base64Url\Base64Url;
17
use Jose\Component\Core\AlgorithmManager;
18
use Jose\Component\Core\Converter\StandardConverter;
19
use Jose\Component\Core\JWK;
20
use Jose\Component\Signature\Algorithm\HS256;
21
use Jose\Component\Signature\JWSBuilder;
22
use Jose\Component\Signature\Serializer\CompactSerializer;
23
use OAuth2Framework\Component\JwtBearerGrant\JwtBearerGrantType;
24
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
25
26
/**
27
 * @group Bundle
28
 * @group Functional
29
 * @group Grant
30
 * @group JwtBearer
31
 */
32
class JwtBearerGrantTest extends WebTestCase
33
{
34
    /**
35
     * {@inheritdoc}
36
     */
37
    protected function setUp()
38
    {
39
        if (!class_exists(JwtBearerGrantType::class)) {
40
            $this->markTestSkipped('The component "oauth2-framework/jwt-bearer-grant" is not installed.');
41
        }
42
    }
43
44
    /**
45
     * @test
46
     */
47
    public function theRequestHasNoGrantType()
48
    {
49
        $client = static::createClient();
50
        $client->request('POST', '/token/get', [], [], ['HTTPS' => 'on'], null);
51
        $response = $client->getResponse();
52
        self::assertEquals(400, $response->getStatusCode());
53
        self::assertEquals('{"error":"invalid_request","error_description":"The \"grant_type\" parameter is missing."}', $response->getContent());
54
    }
55
56
    /**
57
     * @test
58
     */
59
    public function theAssertionIsMissing()
60
    {
61
        $client = static::createClient();
62
        $client->request('POST', '/token/get', ['grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer'], [], ['HTTPS' => 'on'], null);
63
        $response = $client->getResponse();
64
        self::assertEquals(400, $response->getStatusCode());
65
        self::assertEquals('{"error":"invalid_request","error_description":"Missing grant type parameter(s): assertion."}', $response->getContent());
66
    }
67
68
    /**
69
     * @test
70
     */
71
    public function theAssertionIsInvalid()
72
    {
73
        $client = static::createClient();
74
        $client->request('POST', '/token/get', ['grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', 'assertion' => 'FOO'], [], ['HTTPS' => 'on'], null);
75
        $response = $client->getResponse();
76
        self::assertEquals(400, $response->getStatusCode());
77
        self::assertEquals('{"error":"invalid_request","error_description":"Unsupported input"}', $response->getContent());
78
    }
79
80
    /**
81
     * @test
82
     */
83
    public function theAssertionDoesNotContainTheMandatoryClaims()
84
    {
85
        $client = static::createClient();
86
        $assertion = $this->createAnAssertionWithoutClaim();
87
        $client->request('POST', '/token/get', ['grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', 'assertion' => $assertion], [], ['HTTPS' => 'on'], null);
88
        $response = $client->getResponse();
89
        self::assertEquals(400, $response->getStatusCode());
90
        self::assertEquals('{"error":"invalid_request","error_description":"The following claim(s) is/are mandatory: \"iss, sub, aud, exp\"."}', $response->getContent());
91
    }
92
93
    /**
94
     * @test
95
     */
96
    public function theAssertionDoesNotContainTheSubjectClaims()
97
    {
98
        $client = static::createClient();
99
        $assertion = $this->createAnAssertionWithoutSubject();
100
        $client->request('POST', '/token/get', ['grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', 'assertion' => $assertion], [], ['HTTPS' => 'on'], null);
101
        $response = $client->getResponse();
102
        self::assertEquals(400, $response->getStatusCode());
103
        self::assertEquals('{"error":"invalid_request","error_description":"The following claim(s) is/are mandatory: \"sub, aud, exp\"."}', $response->getContent());
104
    }
105
106
    /**
107
     * @test
108
     */
109
    public function theAssertionDoesNotContainTheAudienceClaims()
110
    {
111
        $client = static::createClient();
112
        $assertion = $this->createAnAssertionWithoutAudience();
113
        $client->request('POST', '/token/get', ['grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', 'assertion' => $assertion], [], ['HTTPS' => 'on'], null);
114
        $response = $client->getResponse();
115
        self::assertEquals(400, $response->getStatusCode());
116
        self::assertEquals('{"error":"invalid_request","error_description":"The following claim(s) is/are mandatory: \"aud, exp\"."}', $response->getContent());
117
    }
118
119
    /**
120
     * @test
121
     */
122
    public function theAssertionDoesNotContainTheExpirationTimeClaims()
123
    {
124
        $client = static::createClient();
125
        $assertion = $this->createAnAssertionWithoutExpirationTime();
126
        $client->request('POST', '/token/get', ['grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', 'assertion' => $assertion], [], ['HTTPS' => 'on'], null);
127
        $response = $client->getResponse();
128
        self::assertEquals(400, $response->getStatusCode());
129
        self::assertEquals('{"error":"invalid_request","error_description":"The following claim(s) is/are mandatory: \"exp\"."}', $response->getContent());
130
    }
131
132
    /**
133
     * @test
134
     */
135
    public function theAssertionIsValid()
136
    {
137
        $client = static::createClient();
138
        $assertion = $this->createAValidAssertion();
139
        $client->request('POST', '/token/get', ['grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', 'assertion' => $assertion], [], ['HTTPS' => 'on'], null);
140
        $response = $client->getResponse();
141
        self::assertEquals(200, $response->getStatusCode());
142
        self::assertRegexp('/\{"token_type"\:"Bearer","access_token"\:"[0-9a-zA-Z-_]+","expires_in":[0-9]{4}\}/', $response->getContent());
143
    }
144
145
    /**
146
     * @return string
147
     */
148
    private function createAnAssertionWithoutClaim(): string
149
    {
150
        $jwk = JWK::create([
151
            'kty' => 'oct',
152
            'use' => 'sig',
153
            'k'   => Base64Url::encode('secret'),
154
        ]);
155
        $claims = [];
156
157
        return $this->sign($claims, $jwk);
158
        //$jwk = JWK::createFromJson('{"kty":"RSA","n":"sLjaCStJYRr_y7_3GLlDb4bnGJ8XirSdFboYmvA38NXJ6PhIIjr-sFzfwlcpxZxz6zzjXkDFs3AcUOvC3_KRT5tn4XBOHcR6ABrT65dZTe_qalEpYeQG4oxevc01vmD_dD6Ho2O69amT4gscus2pvszFPdraMYybH24aQFztVtc","e":"AQAB","d":"By-tJhxNgpZfeoCW4rl95YYd1aF6iphnnt-PapWEINYAvOmDvWiavL86FiQHPdLr38_9CvMlVvOjIyNDLGonwHynPxAzUsT7M891N9D0cSCv9DlV3uqRVtdqF4MtWtpU5JWJ9q6auL1UPx2tJhOygu9tJ7w0bTGFwrUdb8PSnlE","p":"3p-6HWbX9YcSkeksJXW3_Y2cfZgRCUXH2or1dIidmscb4VVtTUwb-8gGzUDEq4iS_5pgLARl3O4lOHK0n6Qbrw","q":"yzdrGWwgaWqK6e9VFv3NXGeq1TEKHLkXjF7J24XWKm9lSmlssPRv0NwMPVp_CJ39BrLfFtpFr_fh0oG1sVZ5WQ","dp":"UQ6rP0VQ4G77zfCuSD1ibol_LyONIGkt6V6rHHEZoV9ZwWPPVlOd5MDh6R3p_eLOUw6scZpwVE7JcpIhPfcMtQ","dq":"Jg8g_cfkYhnUHm_2bbHm7jF0Ky1eCXcY0-9Eutpb--KVA9SuyI1fC6zKlgsG06RTKRgC9BK5DnXMU1J7ptTdMQ","qi":"17kC87NLUV6z-c-wtmbNqAkDbKmwpb2RMsGUQmhEPJwnWuwEKZpSQz776SUVwoc0xiQ8DpvU_FypflIlm6fq9w"}');
0 ignored issues
show
Unused Code Comprehensibility introduced by
55% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
159
    }
160
161
    /**
162
     * @return string
163
     */
164
    private function createAnAssertionWithoutSubject(): string
165
    {
166
        $jwk = JWK::create([
167
            'kty' => 'oct',
168
            'use' => 'sig',
169
            'k'   => Base64Url::encode('secret'),
170
        ]);
171
        $claims = ['iss' => 'CLIENT_ID_4'];
172
173
        return $this->sign($claims, $jwk);
174
    }
175
176
    /**
177
     * @return string
178
     */
179
    private function createAnAssertionWithoutAudience(): string
180
    {
181
        $jwk = JWK::create([
182
            'kty' => 'oct',
183
            'use' => 'sig',
184
            'k'   => Base64Url::encode('secret'),
185
        ]);
186
        $claims = ['iss' => 'CLIENT_ID_4', 'sub' => 'CLIENT_ID_4'];
187
188
        return $this->sign($claims, $jwk);
189
    }
190
191
    /**
192
     * @return string
193
     */
194
    private function createAnAssertionWithoutExpirationTime(): string
195
    {
196
        $jwk = JWK::create([
197
            'kty' => 'oct',
198
            'use' => 'sig',
199
            'k'   => Base64Url::encode('secret'),
200
        ]);
201
        $claims = [
202
            'iss' => 'CLIENT_ID_4',
203
            'sub' => 'CLIENT_ID_4',
204
            'aud' => 'https://oauth2.test/'
205
        ];
206
207
        return $this->sign($claims, $jwk);
208
    }
209
210
    /**
211
     * @return string
212
     */
213
    private function createAValidAssertion(): string
214
    {
215
        $jwk = JWK::create([
216
            'kty' => 'oct',
217
            'use' => 'sig',
218
            'k'   => Base64Url::encode('secret'),
219
        ]);
220
        $claims = [
221
            'iss' => 'CLIENT_ID_4',
222
            'sub' => 'CLIENT_ID_4',
223
            'aud' => 'https://oauth2.test/',
224
            'exp' => time()+3600,
225
        ];
226
227
        return $this->sign($claims, $jwk);
228
    }
229
230
/**
231
 * @param array $claims
232
 * @param JWK   $jwk
233
 *
234
 * @return string
235
 */
236
    private function sign(array $claims, JWK $jwk): string
237
    {
238
        $jsonConverter = new StandardConverter();
239
        $jwsBuilder = new JWSBuilder(
240
            $jsonConverter,
241
            AlgorithmManager::create([new HS256()])
242
        );
243
        $payload = $jsonConverter->encode($claims);
244
        $jws = $jwsBuilder
245
            ->create()
246
            ->withPayload($payload)
247
            ->addSignature($jwk, ['alg' => 'HS256'])
248
            ->build();
249
        $token = (new CompactSerializer($jsonConverter))->serialize($jws);
250
251
        return $token;
252
    }
253
}
254