Subversion Repositories cheapmusic

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
103 - 1
<?php
2
/*
3
 * Copyright 2010 Google Inc.
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
 *
9
 *     http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
 
18
namespace Google\Auth\Tests;
19
 
20
use Google\Auth\OAuth2;
21
use GuzzleHttp\Psr7;
22
use GuzzleHttp\Psr7\Response;
23
 
24
class OAuth2AuthorizationUriTest extends \PHPUnit_Framework_TestCase
25
{
26
    private $minimal = [
27
        'authorizationUri' => 'https://accounts.test.org/insecure/url',
28
        'redirectUri' => 'https://accounts.test.org/redirect/url',
29
        'clientId' => 'aClientID',
30
    ];
31
 
32
    /**
33
     * @expectedException InvalidArgumentException
34
     */
35
    public function testIsNullIfAuthorizationUriIsNull()
36
    {
37
        $o = new OAuth2([]);
38
        $this->assertNull($o->buildFullAuthorizationUri());
39
    }
40
 
41
    /**
42
     * @expectedException InvalidArgumentException
43
     */
44
    public function testRequiresTheClientId()
45
    {
46
        $o = new OAuth2([
47
            'authorizationUri' => 'https://accounts.test.org/auth/url',
48
            'redirectUri' => 'https://accounts.test.org/redirect/url',
49
        ]);
50
        $o->buildFullAuthorizationUri();
51
    }
52
 
53
    /**
54
     * @expectedException InvalidArgumentException
55
     */
56
    public function testRequiresTheRedirectUri()
57
    {
58
        $o = new OAuth2([
59
            'authorizationUri' => 'https://accounts.test.org/auth/url',
60
            'clientId' => 'aClientID',
61
        ]);
62
        $o->buildFullAuthorizationUri();
63
    }
64
 
65
    /**
66
     * @expectedException InvalidArgumentException
67
     */
68
    public function testCannotHavePromptAndApprovalPrompt()
69
    {
70
        $o = new OAuth2([
71
            'authorizationUri' => 'https://accounts.test.org/auth/url',
72
            'clientId' => 'aClientID',
73
        ]);
74
        $o->buildFullAuthorizationUri([
75
            'approval_prompt' => 'an approval prompt',
76
            'prompt' => 'a prompt',
77
        ]);
78
    }
79
 
80
    /**
81
     * @expectedException InvalidArgumentException
82
     */
83
    public function testCannotHaveInsecureAuthorizationUri()
84
    {
85
        $o = new OAuth2([
86
            'authorizationUri' => 'http://accounts.test.org/insecure/url',
87
            'redirectUri' => 'https://accounts.test.org/redirect/url',
88
            'clientId' => 'aClientID',
89
        ]);
90
        $o->buildFullAuthorizationUri();
91
    }
92
 
93
    /**
94
     * @expectedException InvalidArgumentException
95
     */
96
    public function testCannotHaveRelativeRedirectUri()
97
    {
98
        $o = new OAuth2([
99
            'authorizationUri' => 'http://accounts.test.org/insecure/url',
100
            'redirectUri' => '/redirect/url',
101
            'clientId' => 'aClientID',
102
        ]);
103
        $o->buildFullAuthorizationUri();
104
    }
105
 
106
    public function testHasDefaultXXXTypeParams()
107
    {
108
        $o = new OAuth2($this->minimal);
109
        $q = Psr7\parse_query($o->buildFullAuthorizationUri()->getQuery());
110
        $this->assertEquals('code', $q['response_type']);
111
        $this->assertEquals('offline', $q['access_type']);
112
    }
113
 
114
    public function testCanBeUrlObject()
115
    {
116
        $config = array_merge($this->minimal, [
117
            'authorizationUri' => Psr7\uri_for('https://another/uri'),
118
        ]);
119
        $o = new OAuth2($config);
120
        $this->assertEquals('/uri', $o->buildFullAuthorizationUri()->getPath());
121
    }
122
 
123
    public function testCanOverrideParams()
124
    {
125
        $overrides = [
126
            'access_type' => 'o_access_type',
127
            'client_id' => 'o_client_id',
128
            'redirect_uri' => 'o_redirect_uri',
129
            'response_type' => 'o_response_type',
130
            'state' => 'o_state',
131
        ];
132
        $config = array_merge($this->minimal, ['state' => 'the_state']);
133
        $o = new OAuth2($config);
134
        $q = Psr7\parse_query($o->buildFullAuthorizationUri($overrides)->getQuery());
135
        $this->assertEquals('o_access_type', $q['access_type']);
136
        $this->assertEquals('o_client_id', $q['client_id']);
137
        $this->assertEquals('o_redirect_uri', $q['redirect_uri']);
138
        $this->assertEquals('o_response_type', $q['response_type']);
139
        $this->assertEquals('o_state', $q['state']);
140
    }
141
 
142
    public function testIncludesTheScope()
143
    {
144
        $with_strings = array_merge($this->minimal, ['scope' => 'scope1 scope2']);
145
        $o = new OAuth2($with_strings);
146
        $q = Psr7\parse_query($o->buildFullAuthorizationUri()->getQuery());
147
        $this->assertEquals('scope1 scope2', $q['scope']);
148
 
149
        $with_array = array_merge($this->minimal, [
150
            'scope' => ['scope1', 'scope2'],
151
        ]);
152
        $o = new OAuth2($with_array);
153
        $q = Psr7\parse_query($o->buildFullAuthorizationUri()->getQuery());
154
        $this->assertEquals('scope1 scope2', $q['scope']);
155
    }
156
 
157
    public function testRedirectUriPostmessageIsAllowed()
158
    {
159
        $o = new OAuth2([
160
            'authorizationUri' => 'https://accounts.test.org/insecure/url',
161
            'redirectUri' => 'postmessage',
162
            'clientId' => 'aClientID',
163
        ]);
164
        $this->assertEquals('postmessage', $o->getRedirectUri());
165
        $url = $o->buildFullAuthorizationUri();
166
        $parts = parse_url((string)$url);
167
        parse_str($parts['query'], $query);
168
        $this->assertArrayHasKey('redirect_uri', $query);
169
        $this->assertEquals('postmessage', $query['redirect_uri']);
170
    }
171
}
172
 
173
class OAuth2GrantTypeTest extends \PHPUnit_Framework_TestCase
174
{
175
    private $minimal = [
176
        'authorizationUri' => 'https://accounts.test.org/insecure/url',
177
        'redirectUri' => 'https://accounts.test.org/redirect/url',
178
        'clientId' => 'aClientID',
179
    ];
180
 
181
    public function testReturnsNullIfCannotBeInferred()
182
    {
183
        $o = new OAuth2($this->minimal);
184
        $this->assertNull($o->getGrantType());
185
    }
186
 
187
    public function testInfersAuthorizationCode()
188
    {
189
        $o = new OAuth2($this->minimal);
190
        $o->setCode('an auth code');
191
        $this->assertEquals('authorization_code', $o->getGrantType());
192
    }
193
 
194
    public function testInfersRefreshToken()
195
    {
196
        $o = new OAuth2($this->minimal);
197
        $o->setRefreshToken('a refresh token');
198
        $this->assertEquals('refresh_token', $o->getGrantType());
199
    }
200
 
201
    public function testInfersPassword()
202
    {
203
        $o = new OAuth2($this->minimal);
204
        $o->setPassword('a password');
205
        $o->setUsername('a username');
206
        $this->assertEquals('password', $o->getGrantType());
207
    }
208
 
209
    public function testInfersJwtBearer()
210
    {
211
        $o = new OAuth2($this->minimal);
212
        $o->setIssuer('an issuer');
213
        $o->setSigningKey('a key');
214
        $this->assertEquals('urn:ietf:params:oauth:grant-type:jwt-bearer',
215
            $o->getGrantType());
216
    }
217
 
218
    public function testSetsKnownTypes()
219
    {
220
        $o = new OAuth2($this->minimal);
221
        foreach (OAuth2::$knownGrantTypes as $t) {
222
            $o->setGrantType($t);
223
            $this->assertEquals($t, $o->getGrantType());
224
        }
225
    }
226
 
227
    public function testSetsUrlAsGrantType()
228
    {
229
        $o = new OAuth2($this->minimal);
230
        $o->setGrantType('http://a/grant/url');
231
        $this->assertEquals('http://a/grant/url', $o->getGrantType());
232
    }
233
}
234
 
235
class OAuth2GetCacheKeyTest extends \PHPUnit_Framework_TestCase
236
{
237
    private $minimal = [
238
        'clientID' => 'aClientID',
239
    ];
240
 
241
    public function testIsNullWithNoScopes()
242
    {
243
        $o = new OAuth2($this->minimal);
244
        $this->assertNull($o->getCacheKey());
245
    }
246
 
247
    public function testIsScopeIfSingleScope()
248
    {
249
        $o = new OAuth2($this->minimal);
250
        $o->setScope('test/scope/1');
251
        $this->assertEquals('test/scope/1', $o->getCacheKey());
252
    }
253
 
254
    public function testIsAllScopesWhenScopeIsArray()
255
    {
256
        $o = new OAuth2($this->minimal);
257
        $o->setScope(['test/scope/1', 'test/scope/2']);
258
        $this->assertEquals('test/scope/1:test/scope/2', $o->getCacheKey());
259
    }
260
}
261
 
262
class OAuth2TimingTest extends \PHPUnit_Framework_TestCase
263
{
264
    private $minimal = [
265
        'authorizationUri' => 'https://accounts.test.org/insecure/url',
266
        'redirectUri' => 'https://accounts.test.org/redirect/url',
267
        'clientId' => 'aClientID',
268
    ];
269
 
270
    public function testIssuedAtDefaultsToNull()
271
    {
272
        $o = new OAuth2($this->minimal);
273
        $this->assertNull($o->getIssuedAt());
274
    }
275
 
276
    public function testExpiresAtDefaultsToNull()
277
    {
278
        $o = new OAuth2($this->minimal);
279
        $this->assertNull($o->getExpiresAt());
280
    }
281
 
282
    public function testExpiresInDefaultsToNull()
283
    {
284
        $o = new OAuth2($this->minimal);
285
        $this->assertNull($o->getExpiresIn());
286
    }
287
 
288
    public function testSettingExpiresInSetsIssuedAt()
289
    {
290
        $o = new OAuth2($this->minimal);
291
        $this->assertNull($o->getIssuedAt());
292
        $aShortWhile = 5;
293
        $o->setExpiresIn($aShortWhile);
294
        $this->assertEquals($aShortWhile, $o->getExpiresIn());
295
        $this->assertNotNull($o->getIssuedAt());
296
    }
297
 
298
    public function testSettingExpiresInSetsExpireAt()
299
    {
300
        $o = new OAuth2($this->minimal);
301
        $this->assertNull($o->getExpiresAt());
302
        $aShortWhile = 5;
303
        $o->setExpiresIn($aShortWhile);
304
        $this->assertNotNull($o->getExpiresAt());
305
        $this->assertEquals($aShortWhile, $o->getExpiresAt() - $o->getIssuedAt());
306
    }
307
 
308
    public function testIsNotExpiredByDefault()
309
    {
310
        $o = new OAuth2($this->minimal);
311
        $this->assertFalse($o->isExpired());
312
    }
313
 
314
    public function testIsNotExpiredIfExpiresAtIsOld()
315
    {
316
        $o = new OAuth2($this->minimal);
317
        $o->setExpiresAt(time() - 2);
318
        $this->assertTrue($o->isExpired());
319
    }
320
}
321
 
322
class OAuth2GeneralTest extends \PHPUnit_Framework_TestCase
323
{
324
    private $minimal = [
325
        'authorizationUri' => 'https://accounts.test.org/insecure/url',
326
        'redirectUri' => 'https://accounts.test.org/redirect/url',
327
        'clientId' => 'aClientID',
328
    ];
329
 
330
    /**
331
     * @expectedException InvalidArgumentException
332
     */
333
    public function testFailsOnUnknownSigningAlgorithm()
334
    {
335
        $o = new OAuth2($this->minimal);
336
        $o->setSigningAlgorithm('this is definitely not an algorithm name');
337
    }
338
 
339
    public function testAllowsKnownSigningAlgorithms()
340
    {
341
        $o = new OAuth2($this->minimal);
342
        foreach (OAuth2::$knownSigningAlgorithms as $a) {
343
            $o->setSigningAlgorithm($a);
344
            $this->assertEquals($a, $o->getSigningAlgorithm());
345
        }
346
    }
347
 
348
    /**
349
     * @expectedException InvalidArgumentException
350
     */
351
    public function testFailsOnRelativeRedirectUri()
352
    {
353
        $o = new OAuth2($this->minimal);
354
        $o->setRedirectUri('/relative/url');
355
    }
356
 
357
    public function testAllowsUrnRedirectUri()
358
    {
359
        $urn = 'urn:ietf:wg:oauth:2.0:oob';
360
        $o = new OAuth2($this->minimal);
361
        $o->setRedirectUri($urn);
362
        $this->assertEquals($urn, $o->getRedirectUri());
363
    }
364
}
365
 
366
class OAuth2JwtTest extends \PHPUnit_Framework_TestCase
367
{
368
    private $signingMinimal = [
369
        'signingKey' => 'example_key',
370
        'signingAlgorithm' => 'HS256',
371
        'scope' => 'https://www.googleapis.com/auth/userinfo.profile',
372
        'issuer' => 'app@example.com',
373
        'audience' => 'accounts.google.com',
374
        'clientId' => 'aClientID',
375
    ];
376
 
377
    /**
378
     * @expectedException DomainException
379
     */
380
    public function testFailsWithMissingAudience()
381
    {
382
        $testConfig = $this->signingMinimal;
383
        unset($testConfig['audience']);
384
        $o = new OAuth2($testConfig);
385
        $o->toJwt();
386
    }
387
 
388
    /**
389
     * @expectedException DomainException
390
     */
391
    public function testFailsWithMissingIssuer()
392
    {
393
        $testConfig = $this->signingMinimal;
394
        unset($testConfig['issuer']);
395
        $o = new OAuth2($testConfig);
396
        $o->toJwt();
397
    }
398
 
399
    /**
400
     */
401
    public function testCanHaveNoScope()
402
    {
403
        $testConfig = $this->signingMinimal;
404
        unset($testConfig['scope']);
405
        $o = new OAuth2($testConfig);
406
        $o->toJwt();
407
    }
408
 
409
    /**
410
     * @expectedException DomainException
411
     */
412
    public function testFailsWithMissingSigningKey()
413
    {
414
        $testConfig = $this->signingMinimal;
415
        unset($testConfig['signingKey']);
416
        $o = new OAuth2($testConfig);
417
        $o->toJwt();
418
    }
419
 
420
    /**
421
     * @expectedException DomainException
422
     */
423
    public function testFailsWithMissingSigningAlgorithm()
424
    {
425
        $testConfig = $this->signingMinimal;
426
        unset($testConfig['signingAlgorithm']);
427
        $o = new OAuth2($testConfig);
428
        $o->toJwt();
429
    }
430
 
431
    public function testCanHS256EncodeAValidPayload()
432
    {
433
        $testConfig = $this->signingMinimal;
434
        $o = new OAuth2($testConfig);
435
        $payload = $o->toJwt();
436
        $roundTrip = $this->jwtDecode($payload, $testConfig['signingKey'], array('HS256'));
437
        $this->assertEquals($roundTrip->iss, $testConfig['issuer']);
438
        $this->assertEquals($roundTrip->aud, $testConfig['audience']);
439
        $this->assertEquals($roundTrip->scope, $testConfig['scope']);
440
    }
441
 
442
    public function testCanRS256EncodeAValidPayload()
443
    {
444
        $publicKey = file_get_contents(__DIR__ . '/fixtures' . '/public.pem');
445
        $privateKey = file_get_contents(__DIR__ . '/fixtures' . '/private.pem');
446
        $testConfig = $this->signingMinimal;
447
        $o = new OAuth2($testConfig);
448
        $o->setSigningAlgorithm('RS256');
449
        $o->setSigningKey($privateKey);
450
        $payload = $o->toJwt();
451
        $roundTrip = $this->jwtDecode($payload, $publicKey, array('RS256'));
452
        $this->assertEquals($roundTrip->iss, $testConfig['issuer']);
453
        $this->assertEquals($roundTrip->aud, $testConfig['audience']);
454
        $this->assertEquals($roundTrip->scope, $testConfig['scope']);
455
    }
456
 
457
    private function jwtDecode()
458
    {
459
        $args = func_get_args();
460
        $class = 'JWT';
461
        if (class_exists('Firebase\JWT\JWT')) {
462
            $class = 'Firebase\JWT\JWT';
463
        }
464
 
465
        return call_user_func_array("$class::decode", $args);
466
    }
467
}
468
 
469
class OAuth2GenerateAccessTokenRequestTest extends \PHPUnit_Framework_TestCase
470
{
471
    private $tokenRequestMinimal = [
472
        'tokenCredentialUri' => 'https://tokens_r_us/test',
473
        'scope' => 'https://www.googleapis.com/auth/userinfo.profile',
474
        'issuer' => 'app@example.com',
475
        'audience' => 'accounts.google.com',
476
        'clientId' => 'aClientID',
477
    ];
478
 
479
    /**
480
     * @expectedException DomainException
481
     */
482
    public function testFailsIfNoTokenCredentialUri()
483
    {
484
        $testConfig = $this->tokenRequestMinimal;
485
        unset($testConfig['tokenCredentialUri']);
486
        $o = new OAuth2($testConfig);
487
        $o->generateCredentialsRequest();
488
    }
489
 
490
    /**
491
     * @expectedException DomainException
492
     */
493
    public function testFailsIfAuthorizationCodeIsMissing()
494
    {
495
        $testConfig = $this->tokenRequestMinimal;
496
        $testConfig['redirectUri'] = 'https://has/redirect/uri';
497
        $o = new OAuth2($testConfig);
498
        $o->generateCredentialsRequest();
499
    }
500
 
501
    public function testGeneratesAuthorizationCodeRequests()
502
    {
503
        $testConfig = $this->tokenRequestMinimal;
504
        $testConfig['redirectUri'] = 'https://has/redirect/uri';
505
        $o = new OAuth2($testConfig);
506
        $o->setCode('an_auth_code');
507
 
508
        // Generate the request and confirm that it's correct.
509
        $req = $o->generateCredentialsRequest();
510
        $this->assertInstanceOf('Psr\Http\Message\RequestInterface', $req);
511
        $this->assertEquals('POST', $req->getMethod());
512
        $fields = Psr7\parse_query((string)$req->getBody());
513
        $this->assertEquals('authorization_code', $fields['grant_type']);
514
        $this->assertEquals('an_auth_code', $fields['code']);
515
    }
516
 
517
    public function testGeneratesPasswordRequests()
518
    {
519
        $testConfig = $this->tokenRequestMinimal;
520
        $o = new OAuth2($testConfig);
521
        $o->setUsername('a_username');
522
        $o->setPassword('a_password');
523
 
524
        // Generate the request and confirm that it's correct.
525
        $req = $o->generateCredentialsRequest();
526
        $this->assertInstanceOf('Psr\Http\Message\RequestInterface', $req);
527
        $this->assertEquals('POST', $req->getMethod());
528
        $fields = Psr7\parse_query((string)$req->getBody());
529
        $this->assertEquals('password', $fields['grant_type']);
530
        $this->assertEquals('a_password', $fields['password']);
531
        $this->assertEquals('a_username', $fields['username']);
532
    }
533
 
534
    public function testGeneratesRefreshTokenRequests()
535
    {
536
        $testConfig = $this->tokenRequestMinimal;
537
        $o = new OAuth2($testConfig);
538
        $o->setRefreshToken('a_refresh_token');
539
 
540
        // Generate the request and confirm that it's correct.
541
        $req = $o->generateCredentialsRequest();
542
        $this->assertInstanceOf('Psr\Http\Message\RequestInterface', $req);
543
        $this->assertEquals('POST', $req->getMethod());
544
        $fields = Psr7\parse_query((string)$req->getBody());
545
        $this->assertEquals('refresh_token', $fields['grant_type']);
546
        $this->assertEquals('a_refresh_token', $fields['refresh_token']);
547
    }
548
 
549
    public function testClientSecretAddedIfSetForAuthorizationCodeRequests()
550
    {
551
        $testConfig = $this->tokenRequestMinimal;
552
        $testConfig['clientSecret'] = 'a_client_secret';
553
        $testConfig['redirectUri'] = 'https://has/redirect/uri';
554
        $o = new OAuth2($testConfig);
555
        $o->setCode('an_auth_code');
556
        $request = $o->generateCredentialsRequest();
557
        $fields = Psr7\parse_query((string)$request->getBody());
558
        $this->assertEquals('a_client_secret', $fields['client_secret']);
559
    }
560
 
561
    public function testClientSecretAddedIfSetForRefreshTokenRequests()
562
    {
563
        $testConfig = $this->tokenRequestMinimal;
564
        $testConfig['clientSecret'] = 'a_client_secret';
565
        $o = new OAuth2($testConfig);
566
        $o->setRefreshToken('a_refresh_token');
567
        $request = $o->generateCredentialsRequest();
568
        $fields = Psr7\parse_query((string)$request->getBody());
569
        $this->assertEquals('a_client_secret', $fields['client_secret']);
570
    }
571
 
572
    public function testClientSecretAddedIfSetForPasswordRequests()
573
    {
574
        $testConfig = $this->tokenRequestMinimal;
575
        $testConfig['clientSecret'] = 'a_client_secret';
576
        $o = new OAuth2($testConfig);
577
        $o->setUsername('a_username');
578
        $o->setPassword('a_password');
579
        $request = $o->generateCredentialsRequest();
580
        $fields = Psr7\parse_query((string)$request->getBody());
581
        $this->assertEquals('a_client_secret', $fields['client_secret']);
582
    }
583
 
584
    public function testGeneratesAssertionRequests()
585
    {
586
        $testConfig = $this->tokenRequestMinimal;
587
        $o = new OAuth2($testConfig);
588
        $o->setSigningKey('a_key');
589
        $o->setSigningAlgorithm('HS256');
590
 
591
        // Generate the request and confirm that it's correct.
592
        $req = $o->generateCredentialsRequest();
593
        $this->assertInstanceOf('Psr\Http\Message\RequestInterface', $req);
594
        $this->assertEquals('POST', $req->getMethod());
595
        $fields = Psr7\parse_query((string)$req->getBody());
596
        $this->assertEquals(OAuth2::JWT_URN, $fields['grant_type']);
597
        $this->assertTrue(array_key_exists('assertion', $fields));
598
    }
599
 
600
    public function testGeneratesExtendedRequests()
601
    {
602
        $testConfig = $this->tokenRequestMinimal;
603
        $o = new OAuth2($testConfig);
604
        $o->setGrantType('urn:my_test_grant_type');
605
        $o->setExtensionParams(['my_param' => 'my_value']);
606
 
607
        // Generate the request and confirm that it's correct.
608
        $req = $o->generateCredentialsRequest();
609
        $this->assertInstanceOf('Psr\Http\Message\RequestInterface', $req);
610
        $this->assertEquals('POST', $req->getMethod());
611
        $fields = Psr7\parse_query((string)$req->getBody());
612
        $this->assertEquals('my_value', $fields['my_param']);
613
        $this->assertEquals('urn:my_test_grant_type', $fields['grant_type']);
614
    }
615
}
616
 
617
class OAuth2FetchAuthTokenTest extends \PHPUnit_Framework_TestCase
618
{
619
    private $fetchAuthTokenMinimal = [
620
        'tokenCredentialUri' => 'https://tokens_r_us/test',
621
        'scope' => 'https://www.googleapis.com/auth/userinfo.profile',
622
        'signingKey' => 'example_key',
623
        'signingAlgorithm' => 'HS256',
624
        'issuer' => 'app@example.com',
625
        'audience' => 'accounts.google.com',
626
        'clientId' => 'aClientID',
627
    ];
628
 
629
    /**
630
     * @expectedException GuzzleHttp\Exception\ClientException
631
     */
632
    public function testFailsOn400()
633
    {
634
        $testConfig = $this->fetchAuthTokenMinimal;
635
        $httpHandler = getHandler([
636
            buildResponse(400),
637
        ]);
638
        $o = new OAuth2($testConfig);
639
        $o->fetchAuthToken($httpHandler);
640
    }
641
 
642
    /**
643
     * @expectedException GuzzleHttp\Exception\ServerException
644
     */
645
    public function testFailsOn500()
646
    {
647
        $testConfig = $this->fetchAuthTokenMinimal;
648
        $httpHandler = getHandler([
649
            buildResponse(500),
650
        ]);
651
        $o = new OAuth2($testConfig);
652
        $o->fetchAuthToken($httpHandler);
653
    }
654
 
655
    /**
656
     * @expectedException Exception
657
     * @expectedExceptionMessage Invalid JSON response
658
     */
659
    public function testFailsOnNoContentTypeIfResponseIsNotJSON()
660
    {
661
        $testConfig = $this->fetchAuthTokenMinimal;
662
        $notJson = '{"foo": , this is cannot be passed as json" "bar"}';
663
        $httpHandler = getHandler([
664
            buildResponse(200, [], Psr7\stream_for($notJson)),
665
        ]);
666
        $o = new OAuth2($testConfig);
667
        $o->fetchAuthToken($httpHandler);
668
    }
669
 
670
    public function testFetchesJsonResponseOnNoContentTypeOK()
671
    {
672
        $testConfig = $this->fetchAuthTokenMinimal;
673
        $json = '{"foo": "bar"}';
674
        $httpHandler = getHandler([
675
            buildResponse(200, [], Psr7\stream_for($json)),
676
        ]);
677
        $o = new OAuth2($testConfig);
678
        $tokens = $o->fetchAuthToken($httpHandler);
679
        $this->assertEquals($tokens['foo'], 'bar');
680
    }
681
 
682
    public function testFetchesFromFormEncodedResponseOK()
683
    {
684
        $testConfig = $this->fetchAuthTokenMinimal;
685
        $json = 'foo=bar&spice=nice';
686
        $httpHandler = getHandler([
687
            buildResponse(
688
                200,
689
                ['Content-Type' => 'application/x-www-form-urlencoded'],
690
                Psr7\stream_for($json)
691
            ),
692
        ]);
693
        $o = new OAuth2($testConfig);
694
        $tokens = $o->fetchAuthToken($httpHandler);
695
        $this->assertEquals($tokens['foo'], 'bar');
696
        $this->assertEquals($tokens['spice'], 'nice');
697
    }
698
 
699
    public function testUpdatesTokenFieldsOnFetch()
700
    {
701
        $testConfig = $this->fetchAuthTokenMinimal;
702
        $wanted_updates = [
703
            'expires_at' => '1',
704
            'expires_in' => '57',
705
            'issued_at' => '2',
706
            'access_token' => 'an_access_token',
707
            'id_token' => 'an_id_token',
708
            'refresh_token' => 'a_refresh_token',
709
        ];
710
        $json = json_encode($wanted_updates);
711
        $httpHandler = getHandler([
712
            buildResponse(200, [], Psr7\stream_for($json)),
713
        ]);
714
        $o = new OAuth2($testConfig);
715
        $this->assertNull($o->getExpiresAt());
716
        $this->assertNull($o->getExpiresIn());
717
        $this->assertNull($o->getIssuedAt());
718
        $this->assertNull($o->getAccessToken());
719
        $this->assertNull($o->getIdToken());
720
        $this->assertNull($o->getRefreshToken());
721
        $tokens = $o->fetchAuthToken($httpHandler);
722
        $this->assertEquals(1, $o->getExpiresAt());
723
        $this->assertEquals(57, $o->getExpiresIn());
724
        $this->assertEquals(2, $o->getIssuedAt());
725
        $this->assertEquals('an_access_token', $o->getAccessToken());
726
        $this->assertEquals('an_id_token', $o->getIdToken());
727
        $this->assertEquals('a_refresh_token', $o->getRefreshToken());
728
    }
729
 
730
    public function testUpdatesTokenFieldsOnFetchMissingRefreshToken()
731
    {
732
        $testConfig = $this->fetchAuthTokenMinimal;
733
        $testConfig['refresh_token'] = 'a_refresh_token';
734
        $wanted_updates = [
735
            'expires_at' => '1',
736
            'expires_in' => '57',
737
            'issued_at' => '2',
738
            'access_token' => 'an_access_token',
739
            'id_token' => 'an_id_token',
740
        ];
741
        $json = json_encode($wanted_updates);
742
        $httpHandler = getHandler([
743
            buildResponse(200, [], Psr7\stream_for($json)),
744
        ]);
745
        $o = new OAuth2($testConfig);
746
        $this->assertNull($o->getExpiresAt());
747
        $this->assertNull($o->getExpiresIn());
748
        $this->assertNull($o->getIssuedAt());
749
        $this->assertNull($o->getAccessToken());
750
        $this->assertNull($o->getIdToken());
751
        $this->assertEquals('a_refresh_token', $o->getRefreshToken());
752
        $tokens = $o->fetchAuthToken($httpHandler);
753
        $this->assertEquals(1, $o->getExpiresAt());
754
        $this->assertEquals(57, $o->getExpiresIn());
755
        $this->assertEquals(2, $o->getIssuedAt());
756
        $this->assertEquals('an_access_token', $o->getAccessToken());
757
        $this->assertEquals('an_id_token', $o->getIdToken());
758
        $this->assertEquals('a_refresh_token', $o->getRefreshToken());
759
    }
760
}
761
 
762
class OAuth2VerifyIdTokenTest extends \PHPUnit_Framework_TestCase
763
{
764
    private $publicKey;
765
    private $privateKey;
766
    private $verifyIdTokenMinimal = [
767
        'scope' => 'https://www.googleapis.com/auth/userinfo.profile',
768
        'audience' => 'myaccount.on.host.issuer.com',
769
        'issuer' => 'an.issuer.com',
770
        'clientId' => 'myaccount.on.host.issuer.com',
771
    ];
772
 
773
    public function setUp()
774
    {
775
        $this->publicKey =
776
            file_get_contents(__DIR__ . '/fixtures' . '/public.pem');
777
        $this->privateKey =
778
            file_get_contents(__DIR__ . '/fixtures' . '/private.pem');
779
    }
780
 
781
    /**
782
     * @expectedException UnexpectedValueException
783
     */
784
    public function testFailsIfIdTokenIsInvalid()
785
    {
786
        $testConfig = $this->verifyIdTokenMinimal;
787
        $not_a_jwt = 'not a jot';
788
        $o = new OAuth2($testConfig);
789
        $o->setIdToken($not_a_jwt);
790
        $o->verifyIdToken($this->publicKey);
791
    }
792
 
793
    /**
794
     * @expectedException DomainException
795
     */
796
    public function testFailsIfAudienceIsMissing()
797
    {
798
        $testConfig = $this->verifyIdTokenMinimal;
799
        $now = time();
800
        $origIdToken = [
801
            'issuer' => $testConfig['issuer'],
802
            'exp' => $now + 65, // arbitrary
803
            'iat' => $now,
804
        ];
805
        $o = new OAuth2($testConfig);
806
        $jwtIdToken = $this->jwtEncode($origIdToken, $this->privateKey, 'RS256');
807
        $o->setIdToken($jwtIdToken);
808
        $o->verifyIdToken($this->publicKey, ['RS256']);
809
    }
810
 
811
    /**
812
     * @expectedException DomainException
813
     */
814
    public function testFailsIfAudienceIsWrong()
815
    {
816
        $now = time();
817
        $testConfig = $this->verifyIdTokenMinimal;
818
        $origIdToken = [
819
            'aud' => 'a different audience',
820
            'iss' => $testConfig['issuer'],
821
            'exp' => $now + 65, // arbitrary
822
            'iat' => $now,
823
        ];
824
        $o = new OAuth2($testConfig);
825
        $jwtIdToken = $this->jwtEncode($origIdToken, $this->privateKey, 'RS256');
826
        $o->setIdToken($jwtIdToken);
827
        $o->verifyIdToken($this->publicKey, ['RS256']);
828
    }
829
 
830
    public function testShouldReturnAValidIdToken()
831
    {
832
        $testConfig = $this->verifyIdTokenMinimal;
833
        $now = time();
834
        $origIdToken = [
835
            'aud' => $testConfig['audience'],
836
            'iss' => $testConfig['issuer'],
837
            'exp' => $now + 65, // arbitrary
838
            'iat' => $now,
839
        ];
840
        $o = new OAuth2($testConfig);
841
        $alg = 'RS256';
842
        $jwtIdToken = $this->jwtEncode($origIdToken, $this->privateKey, $alg);
843
        $o->setIdToken($jwtIdToken);
844
        $roundTrip = $o->verifyIdToken($this->publicKey, array($alg));
845
        $this->assertEquals($origIdToken['aud'], $roundTrip->aud);
846
    }
847
 
848
    private function jwtEncode()
849
    {
850
        $args = func_get_args();
851
        $class = 'JWT';
852
        if (class_exists('Firebase\JWT\JWT')) {
853
            $class = 'Firebase\JWT\JWT';
854
        }
855
 
856
        return call_user_func_array("$class::encode", $args);
857
    }
858
}