15 Commits

Author SHA1 Message Date
Patrick Bußmann 95cc38cd0c Removing microseconds so that Sign in with Apple works again 2021-01-17 23:19:45 +01:00
Patrick Bußmann a08ded7b3a Added Codecov and updated changelog 2021-01-17 17:46:58 +01:00
Patrick Bußmann 31c61d334b Increased library compatibility and fixed all tests 2021-01-17 17:30:28 +01:00
Patrick Bußmann d649df8313 Merge pull request #20 from zhangv/master
support Lcobucci-jwt v3.4+
2021-01-15 12:11:42 +01:00
Patrick Bußmann 6702931e2e Merge branch 'master' into master 2021-01-15 12:11:32 +01:00
Patrick Bußmann 5598a94a36 Added leeway usage to README 2021-01-05 19:33:41 +01:00
Patrick Bußmann e191fd0988 Merge remote-tracking branch 'jmalinens/use_guzzle'
# Conflicts:
#	src/Token/AppleAccessToken.php
2021-01-05 12:53:11 +01:00
Patrick Bußmann 8c49a59451 Merge remote-tracking branch 'NgSekLong/patch-1' 2021-01-05 08:53:45 +01:00
Patrick Bußmann 45903a3f90 Merge remote-tracking branch 'giganti-consultoria/master' 2021-01-05 08:53:39 +01:00
zhangv 06ef0a50d1 support Lcobucci-jwt v3.4+
and compatible to the old versions
2020-12-11 14:45:06 +08:00
Juris Malinens a6b002a062 use guzzle instance from AbstractProvider to get apple auth keys instead of file_get_contents 2020-11-27 17:05:39 +02:00
NgSekLong 1b47b8e9d3 Update README include no scope instruction
Add mention for how to disable scope "Don't need email and name", and how to modify the sample code to get back `code`

i.e. Change all `$_POST` to `$_GET`
2020-09-10 11:07:06 +08:00
William Martins 3f23b1d156 Code Formatter 2020-07-31 16:50:28 -03:00
William Martins 81164c4b8a Use guzzle http client instead of file_get_contents
Many servers have allow_fopen_url disabled so they cant use file_get_contents to load apple keys.
2020-07-31 16:38:39 -03:00
Bogdan Dovgopol a45b7cdc9b Check if name scope is set before trying to return firstName or lastName 2020-07-23 12:06:08 +10:00
12 changed files with 324 additions and 233 deletions
+7 -2
View File
@@ -7,6 +7,8 @@ matrix:
- php: 7.1
- php: 7.2
- php: 7.3
- php: 7.4
- php: 8.0
- php: nightly
- php: hhvm-3.6
sudo: required
@@ -47,5 +49,8 @@ script:
- ./vendor/bin/phpunit --coverage-text --coverage-clover=coverage.clover
after_script:
- if [ "$TRAVIS_PHP_VERSION" == "7.1" ]; then wget https://scrutinizer-ci.com/ocular.phar; fi
- if [ "$TRAVIS_PHP_VERSION" == "7.1" ]; then php ocular.phar code-coverage:upload --format=php-clover coverage.clover; fi
- if [ "$TRAVIS_PHP_VERSION" == "7.4" ]; then wget https://scrutinizer-ci.com/ocular.phar; fi
- if [ "$TRAVIS_PHP_VERSION" == "7.4" ]; then php ocular.phar code-coverage:upload --format=php-clover coverage.clover; fi
after_success:
- bash <(curl -s https://codecov.io/bash)
+18
View File
@@ -18,6 +18,24 @@ All Notable changes to `oauth2-apple` will be documented in this file
### Security
- Nothing
## 0.2.4 - 2021-01-17
### Added
- Codecov for Code Coverage
### Fixed
- Few compatibility issues with PHP 8 and PHP 5.6 (Read [#16](https://github.com/patrickbussmann/oauth2-apple/pull/16) for more details)
## 0.2.3 - 2021-01-05
### Added
- Using guzzle http instead of file_get_contents [#14](https://github.com/patrickbussmann/oauth2-apple/pull/14)/[#17](https://github.com/patrickbussmann/oauth2-apple/pull/17) (thanks to [jmalinens](https://github.com/jmalinens) and [williamxsp](https://github.com/williamxsp))
- README no scope instruction [#15](https://github.com/patrickbussmann/oauth2-apple/pull/15) (thanks to [NgSekLong](https://github.com/NgSekLong))
- README leeway usage [#18](https://github.com/patrickbussmann/oauth2-apple/issues/18) (thanks to [lukequinnell](https://github.com/lukequinnell))
### Fixed
- Fixed getting first and last name issues [#13](https://github.com/patrickbussmann/oauth2-apple/pull/13) (thanks to [bogdandovgopol](https://github.com/bogdandovgopol))
## 0.2.1 - 2020-02-13
### Added
+10 -5
View File
@@ -1,9 +1,10 @@
# Sign in with Apple ID Provider for OAuth 2.0 Client
[![Latest Version](https://img.shields.io/github/release/patrickbussmann/oauth2-apple.svg?style=flat-square)](https://github.com/patrickbussmann/oauth2-apple/releases)
[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md)
[![Build Status](https://img.shields.io/travis/patrickbussmann/oauth2-apple/master.svg?style=flat-square)](https://travis-ci.org/patrickbussmann/oauth2-apple)
[![Build Status](https://img.shields.io/travis/patrickbussmann/oauth2-apple/main.svg?style=flat-square)](https://travis-ci.org/patrickbussmann/oauth2-apple)
[![Coverage Status](https://img.shields.io/scrutinizer/coverage/g/patrickbussmann/oauth2-apple.svg?style=flat-square)](https://scrutinizer-ci.com/g/patrickbussmann/oauth2-apple/code-structure)
[![Quality Score](https://img.shields.io/scrutinizer/g/patrickbussmann/oauth2-apple.svg?style=flat-square)](https://scrutinizer-ci.com/g/patrickbussmann/oauth2-apple)
[![codecov](https://codecov.io/gh/patrickbussmann/oauth2-apple/branch/main/graph/badge.svg?token=TN3ZNVHUXV)](https://codecov.io/gh/patrickbussmann/oauth2-apple)
[![Total Downloads](https://img.shields.io/packagist/dt/patrickbussmann/oauth2-apple.svg?style=flat-square)](https://packagist.org/packages/patrickbussmann/oauth2-apple)
This package provides Apple ID OAuth 2.0 support for the PHP League's [OAuth 2.0 Client](https://github.com/thephpleague/oauth2-client).
@@ -32,11 +33,14 @@ Usage is the same as The League's OAuth client, using `\League\OAuth2\Client\Pro
### Authorization Code Flow
```php
// $leeway is needed for clock skew
Firebase\JWT\JWT::$leeway = 60;
$provider = new League\OAuth2\Client\Provider\Apple([
'clientId' => '{apple-client-id}',
'teamId' => '{apple-team-id}', // 1A234BFK46 https://developer.apple.com/account/#/membership/ (Team ID)
'keyFileId' => '{apple-key-file-id}', // 1ABC6523AA https://developer.apple.com/account/resources/authkeys/list (Key ID)
'keyFilePath' => '{apple-key-file-path}', // __DIR__ . '/AuthKey_1ABC6523AA.p8' -> Download key above
'keyFilePath' => '{apple-key-file-path}', // __DIR__ . '/AuthKey_1ABC6523AA.p8' -> Download key above
'redirectUri' => 'https://example.com/callback-url',
]);
@@ -107,6 +111,7 @@ At the time of authoring this documentation, the following scopes are available.
Please note that you will get this informations only at the first log in of the user!
In the following log ins you'll get only the user id!
If you only want to get the user id, you can set the `scope` as ` `, then change all the `$_POST` to `$_GET`.
### Refresh Tokens
@@ -125,15 +130,15 @@ $ ./vendor/bin/phpunit
## Contributing
Please see [CONTRIBUTING](https://github.com/patrickbussmann/oauth2-apple/blob/master/CONTRIBUTING.md) for details.
Please see [CONTRIBUTING](https://github.com/patrickbussmann/oauth2-apple/blob/main/CONTRIBUTING.md) for details.
## Credits
- [All Contributors](https://github.com/patrickbussmann/oauth2-apple/contributors)
Template for this repository was the [LinkedIn](https://github.com/thephpleague/oauth2-linkedin).
Template for this repository was the [LinkedIn](https://github.com/thephpleague/oauth2-linkedin).
## License
The MIT License (MIT). Please see [License File](https://github.com/patrickbussmann/oauth2-apple/blob/master/LICENSE) for more information.
The MIT License (MIT). Please see [License File](https://github.com/patrickbussmann/oauth2-apple/blob/main/LICENSE) for more information.
+29
View File
@@ -0,0 +1,29 @@
codecov:
require_ci_to_pass: yes
coverage:
precision: 2
round: down
range: "70...100"
status:
project:
default:
target: auto
threshold: 0%
patch:
default:
target: auto
threshold: 0%
parsers:
gcov:
branch_detection:
conditional: yes
loop: yes
method: no
macro: no
comment:
layout: "reach,diff,flags,tree"
behavior: default
require_changes: false
+4 -4
View File
@@ -22,12 +22,12 @@
"league/oauth2-client": "^2.0",
"ext-json": "*",
"firebase/php-jwt": "^5.2",
"lcobucci/jwt": "^3.3"
"lcobucci/jwt": "^3.4 || ^4.0"
},
"require-dev": {
"phpunit/phpunit": "~4.0",
"mockery/mockery": "~0.9",
"squizlabs/php_codesniffer": "~2.0",
"phpunit/phpunit": "^5.7 || ^6.0 || ^9.3",
"mockery/mockery": "^1.3",
"squizlabs/php_codesniffer": "^2.3 || ^3.0",
"ext-json": "*"
},
"autoload": {
+20 -35
View File
@@ -1,37 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
bootstrap="vendor/autoload.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
>
<logging>
<log type="coverage-html"
target="./build/coverage/html"
charset="UTF-8"
highlight="false"
lowUpperBound="35"
highLowerBound="70"/>
<log type="coverage-clover"
target="./build/coverage/log/coverage.xml"/>
</logging>
<testsuites>
<testsuite name="Package Test Suite">
<directory suffix=".php">./test/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory suffix=".php">./</directory>
<exclude>
<directory suffix=".php">./vendor</directory>
<directory suffix=".php">./test</directory>
</exclude>
</whitelist>
</filter>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" backupGlobals="false" backupStaticAttributes="false" bootstrap="vendor/autoload.php" colors="true" convertErrorsToExceptions="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" processIsolation="false" stopOnFailure="false" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
<coverage>
<include>
<directory suffix=".php">./</directory>
</include>
<exclude>
<directory suffix=".php">./vendor</directory>
<directory suffix=".php">./test</directory>
</exclude>
<report>
<clover outputFile="./build/coverage/log/coverage.xml"/>
<html outputDirectory="./build/coverage/html" lowUpperBound="35" highLowerBound="70"/>
</report>
</coverage>
<logging/>
<testsuites>
<testsuite name="Package Test Suite">
<directory suffix=".php">./test/</directory>
</testsuite>
</testsuites>
</phpunit>
+25 -11
View File
@@ -4,8 +4,9 @@ namespace League\OAuth2\Client\Provider;
use Exception;
use InvalidArgumentException;
use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Signer\Ecdsa\Sha256;
use Lcobucci\JWT\Configuration;
use Lcobucci\JWT\Signer\Key\LocalFileReference;
use Lcobucci\JWT\Signer;
use Lcobucci\JWT\Signer\Key;
use League\OAuth2\Client\Grant\AbstractGrant;
use League\OAuth2\Client\Provider\Exception\AppleAccessDeniedException;
@@ -76,7 +77,7 @@ class Apple extends AbstractProvider
*/
protected function createAccessToken(array $response, AbstractGrant $grant)
{
return new AppleAccessToken($response);
return new AppleAccessToken($this->getHttpClient(), $response);
}
/**
@@ -208,32 +209,45 @@ class Apple extends AbstractProvider
*/
public function getAccessToken($grant, array $options = [])
{
$signer = new Sha256();
$time = time();
$configuration = $this->getConfiguration();
$time = new \DateTimeImmutable();
$time = $time->setTime($time->format('H'), $time->format('i'), $time->format('s'));
$expiresAt = $time->modify('+1 Hour');
$expiresAt = $expiresAt->setTime($expiresAt->format('H'), $expiresAt->format('i'), $expiresAt->format('s'));
$token = (new Builder())
$token = $configuration->builder()
->issuedBy($this->teamId)
->permittedFor('https://appleid.apple.com')
->issuedAt($time)
->expiresAt($time + 600)
->expiresAt($expiresAt)
->relatedTo($this->clientId)
->withClaim('sub', $this->clientId)
->withHeader('alg', 'ES256')
->withHeader('kid', $this->keyFileId)
->getToken($signer, $this->getLocalKey());
->getToken($configuration->signer(), $configuration->signingKey());
$options += [
'client_secret' => (string) $token
'client_secret' => $token->toString()
];
return parent::getAccessToken($grant, $options);
}
/**
* @return Configuration
*/
public function getConfiguration()
{
return Configuration::forSymmetricSigner(
Signer\Ecdsa\Sha256::create(),
$this->getLocalKey()
);
}
/**
* @return Key
*/
public function getLocalKey()
{
return new Key('file://' . $this->keyFilePath);
return LocalFileReference::file($this->keyFilePath);
}
}
+10 -2
View File
@@ -46,7 +46,11 @@ class AppleResourceOwner extends GenericResourceOwner
*/
public function getFirstName()
{
return $this->getAttribute('name')['firstName'];
$name = $this->getAttribute('name');
if (isset($name)) {
return $name['firstName'];
}
return null;
}
/**
@@ -66,7 +70,11 @@ class AppleResourceOwner extends GenericResourceOwner
*/
public function getLastName()
{
return $this->getAttribute('name')['lastName'];
$name = $this->getAttribute('name');
if (isset($name)) {
return $name['lastName'];
}
return null;
}
/**
+17 -2
View File
@@ -4,6 +4,7 @@ namespace League\OAuth2\Client\Token;
use Firebase\JWT\JWK;
use Firebase\JWT\JWT;
use GuzzleHttp\ClientInterface;
use InvalidArgumentException;
class AppleAccessToken extends AccessToken
@@ -23,17 +24,25 @@ class AppleAccessToken extends AccessToken
*/
protected $isPrivateEmail;
/**
* @var ClientInterface
*/
protected $httpClient;
/**
* Constructs an access token.
*
* @param ClientInterface $httpClient the http client to use
* @param array $options An array of options returned by the service provider
* in the access token request. The `access_token` option is required.
* @throws InvalidArgumentException if `access_token` is not provided in `$options`.
*
* @throws \Exception
*/
public function __construct(array $options = [])
public function __construct($httpClient, array $options = [])
{
$this->httpClient = $httpClient;
if (array_key_exists('refresh_token', $options)) {
if (empty($options['id_token'])) {
throw new InvalidArgumentException('Required option not passed: "id_token"');
@@ -84,7 +93,13 @@ class AppleAccessToken extends AccessToken
*/
protected function getAppleKey()
{
return JWK::parseKeySet(json_decode(file_get_contents('https://appleid.apple.com/auth/keys'), true));
$response = $this->httpClient->request('GET', 'https://appleid.apple.com/auth/keys');
if ($response) {
return JWK::parseKeySet(json_decode($response->getBody()->getContents(), true));
}
return [];
}
/**
+157 -163
View File
@@ -2,28 +2,26 @@
namespace League\OAuth2\Client\Test\Provider;
use Exception;
use GuzzleHttp\ClientInterface;
use GuzzleHttp\Psr7\Response;
use InvalidArgumentException;
use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Configuration;
use League\OAuth2\Client\Provider\Apple;
use League\OAuth2\Client\Test\Provider\TestApple;
use League\OAuth2\Client\Provider\AppleResourceOwner;
use League\OAuth2\Client\Provider\Exception\AppleAccessDeniedException;
use League\OAuth2\Client\Token\AccessToken;
use League\OAuth2\Client\Tool\QueryBuilderTrait;
use PHPUnit\Framework\TestCase;
use Mockery as m;
class AppleTest extends \PHPUnit_Framework_TestCase
class AppleTest extends TestCase
{
use QueryBuilderTrait;
/** @var Apple|\Mockery\MockInterface */
protected $provider;
protected function setUp()
/**
* @return Apple
*/
private function getProvider()
{
$this->provider = new \League\OAuth2\Client\Provider\Apple([
return new Apple([
'clientId' => 'mock.example',
'teamId' => 'mock.team.id',
'keyFileId' => 'mock.file.id',
@@ -32,62 +30,49 @@ class AppleTest extends \PHPUnit_Framework_TestCase
]);
}
public function tearDown()
public function testMissingTeamIdDuringInstantiationThrowsException()
{
m::close();
parent::tearDown();
$this->expectException('InvalidArgumentException');
new Apple([
'clientId' => 'mock.example',
'keyFileId' => 'mock.file.id',
'keyFilePath' => __DIR__ . '/p256-private-key.p8',
'redirectUri' => 'none'
]);
}
/**
* @expectedException InvalidArgumentException
*/
public function testMissingTeamIdDuringInstantiationThrowsException()
{
new \League\OAuth2\Client\Provider\Apple([
'clientId' => 'mock.example',
'keyFileId' => 'mock.file.id',
'keyFilePath' => __DIR__ . '/p256-private-key.p8',
'redirectUri' => 'none'
]);
}
public function testMissingKeyFileIdDuringInstantiationThrowsException()
{
$this->expectException('InvalidArgumentException');
new Apple([
'clientId' => 'mock.example',
'teamId' => 'mock.team.id',
'keyFilePath' => __DIR__ . '/p256-private-key.p8',
'redirectUri' => 'none'
]);
}
/**
* @expectedException InvalidArgumentException
*/
public function testMissingKeyFileIdDuringInstantiationThrowsException()
{
new \League\OAuth2\Client\Provider\Apple([
'clientId' => 'mock.example',
'teamId' => 'mock.team.id',
'keyFilePath' => __DIR__ . '/p256-private-key.p8',
'redirectUri' => 'none'
]);
}
public function testMissingKeyFilePathDuringInstantiationThrowsException()
{
$this->expectException('InvalidArgumentException');
new Apple([
'clientId' => 'mock.example',
'teamId' => 'mock.team.id',
'keyFileId' => 'mock.file.id',
'redirectUri' => 'none'
]);
}
/**
* @expectedException InvalidArgumentException
*/
public function testMissingKeyFilePathDuringInstantiationThrowsException()
{
new \League\OAuth2\Client\Provider\Apple([
'clientId' => 'mock.example',
'teamId' => 'mock.team.id',
'keyFileId' => 'mock.file.id',
'redirectUri' => 'none'
]);
}
/**
* @expectedException InvalidArgumentException
*/
public function testMissingKeyDuringInstantiationThrowsException()
{
$this->provider->getLocalKey();
}
public function testMissingKeyDuringInstantiationThrowsException()
{
$this->expectException('InvalidArgumentException');
$this->getProvider()->getLocalKey();
}
public function testAuthorizationUrl()
{
$url = $this->provider->getAuthorizationUrl();
$provider = $this->getProvider();
$url = $provider->getAuthorizationUrl();
$uri = parse_url($url);
parse_str($uri['query'], $query);
@@ -97,22 +82,24 @@ class AppleTest extends \PHPUnit_Framework_TestCase
$this->assertArrayHasKey('scope', $query);
$this->assertArrayHasKey('response_type', $query);
$this->assertArrayHasKey('response_mode', $query);
$this->assertNotNull($this->provider->getState());
$this->assertNotNull($provider->getState());
}
public function testScopes()
{
$provider = $this->getProvider();
$scopeSeparator = ' ';
$options = ['scope' => [uniqid(), uniqid()]];
$query = ['scope' => implode($scopeSeparator, $options['scope'])];
$url = $this->provider->getAuthorizationUrl($options);
$url = $provider->getAuthorizationUrl($options);
$encodedScope = $this->buildQueryString($query);
$this->assertContains($encodedScope, $url);
$this->assertNotFalse(strpos($url, $encodedScope));
}
public function testGetAuthorizationUrl()
{
$url = $this->provider->getAuthorizationUrl();
$provider = $this->getProvider();
$url = $provider->getAuthorizationUrl();
$uri = parse_url($url);
$this->assertEquals('/auth/authorize', $uri['path']);
@@ -120,135 +107,142 @@ class AppleTest extends \PHPUnit_Framework_TestCase
public function testGetBaseAccessTokenUrl()
{
$provider = $this->getProvider();
$params = [];
$url = $this->provider->getBaseAccessTokenUrl($params);
$url = $provider->getBaseAccessTokenUrl($params);
$uri = parse_url($url);
$this->assertEquals('/auth/token', $uri['path']);
}
/**
* @expectedException \Firebase\JWT\SignatureInvalidException
*/
public function testGetAccessToken()
{
$provider = new TestApple([
'clientId' => 'mock.example',
'teamId' => 'mock.team.id',
'keyFileId' => 'mock.file.id',
'keyFilePath' => __DIR__ . '/../../resources/p256-private-key.p8',
'redirectUri' => 'none'
]);
$this->expectException('UnexpectedValueException');
$provider = new TestApple([
'clientId' => 'mock.example',
'teamId' => 'mock.team.id',
'keyFileId' => 'mock.file.id',
'keyFilePath' => __DIR__ . '/../../resources/p256-private-key.p8',
'redirectUri' => 'none'
]);
$provider = m::mock($provider);
$time = time();
$token = (new Builder())
->issuedBy('test-team-id')
->permittedFor('https://appleid.apple.com')
->issuedAt($time)
->expiresAt($time + 600)
->relatedTo('test-client')
->withClaim('sub', 'test')
->withHeader('alg', 'RS256')
->withHeader('kid', 'test')
->getToken();
$client = m::mock('GuzzleHttp\ClientInterface');
$client->shouldReceive('send')
->times(1)
->andReturn(new Response(200, [], json_encode([
'access_token' => 'aad897dee58fe4f66bf220c181adaf82b.0.mrwxq.hmiE0djj1vJqoNisKmF-pA',
'token_type' => 'Bearer',
'expires_in' => 3600,
'refresh_token' => 'r4a6e8b9c50104b78bc86b0d2649353fa.0.mrwxq.54joUj40j0cpuMANRtRjfg',
'id_token' => (string) $token
])));
$provider->setHttpClient($client);
$configuration = Configuration::forUnsecuredSigner();
$provider->getAccessToken('authorization_code', [
'code' => 'hello-world'
]);
$time = new \DateTimeImmutable();
$expiresAt = $time->modify('+1 Hour');
$token = $configuration->builder()
->issuedBy('test-team-id')
->permittedFor('https://appleid.apple.com')
->issuedAt($time)
->expiresAt($expiresAt)
->relatedTo('test-client')
->withHeader('alg', 'RS256')
->withHeader('kid', 'test')
->getToken($configuration->signer(), $configuration->signingKey());
$client = m::mock(ClientInterface::class);
$client->shouldReceive('request')
->times(1)
->andReturn(new Response(200, [], file_get_contents('https://appleid.apple.com/auth/keys')));
$client->shouldReceive('send')
->times(1)
->andReturn(new Response(200, [], json_encode([
'access_token' => 'aad897dee58fe4f66bf220c181adaf82b.0.mrwxq.hmiE0djj1vJqoNisKmF-pA',
'token_type' => 'Bearer',
'expires_in' => 3600,
'refresh_token' => 'r4a6e8b9c50104b78bc86b0d2649353fa.0.mrwxq.54joUj40j0cpuMANRtRjfg',
'id_token' => $token->toString()
])));
$provider->setHttpClient($client);
$provider->getAccessToken('authorization_code', [
'code' => 'hello-world'
]);
}
public function testFetchingOwnerDetails()
{
$class = new \ReflectionClass($this->provider);
$method = $class->getMethod('fetchResourceOwnerDetails');
$method->setAccessible(true);
public function testFetchingOwnerDetails()
{
$provider = $this->getProvider();
$class = new \ReflectionClass($provider);
$method = $class->getMethod('fetchResourceOwnerDetails');
$method->setAccessible(true);
$arr = [
'name' => 'John Doe'
];
$_POST['user'] = json_encode($arr);
$data = $method->invokeArgs($this->provider, [new AccessToken(['access_token' => 'hello'])]);
$arr = [
'name' => 'John Doe'
];
$_POST['user'] = json_encode($arr);
$data = $method->invokeArgs($provider, [new AccessToken(['access_token' => 'hello'])]);
$this->assertEquals($arr, $data);
}
$this->assertEquals($arr, $data);
}
/**
* @see https://github.com/patrickbussmann/oauth2-apple/issues/12
*/
public function testFetchingOwnerDetailsIssue12()
{
$class = new \ReflectionClass($this->provider);
$method = $class->getMethod('fetchResourceOwnerDetails');
$method->setAccessible(true);
public function testFetchingOwnerDetailsIssue12()
{
$provider = $this->getProvider();
$class = new \ReflectionClass($provider);
$method = $class->getMethod('fetchResourceOwnerDetails');
$method->setAccessible(true);
$_POST['user'] = '';
$data = $method->invokeArgs($this->provider, [new AccessToken(['access_token' => 'hello'])]);
$data = $method->invokeArgs($provider, [new AccessToken(['access_token' => 'hello'])]);
$this->assertEquals([], $data);
}
$this->assertEquals([], $data);
}
/**
* @expectedException Exception
*/
public function testNotImplementedGetResourceOwnerDetailsUrl()
{
$this->provider->getResourceOwnerDetailsUrl(new AccessToken(['access_token' => 'hello']));
}
public function testNotImplementedGetResourceOwnerDetailsUrl()
{
$this->expectException('Exception');
$provider = $this->getProvider();
$provider->getResourceOwnerDetailsUrl(new AccessToken(['access_token' => 'hello']));
}
public function testCheckResponse()
{
$this->setExpectedException(AppleAccessDeniedException::class, 'invalid_client', 400);
public function testCheckResponse()
{
$this->expectException('\League\OAuth2\Client\Provider\Exception\AppleAccessDeniedException');
$provider = $this->getProvider();
$class = new \ReflectionClass($provider);
$method = $class->getMethod('checkResponse');
$method->setAccessible(true);
$class = new \ReflectionClass($this->provider);
$method = $class->getMethod('checkResponse');
$method->setAccessible(true);
$method->invokeArgs($provider, [new Response(400, []), [
'error' => 'invalid_client',
'code' => 400
]]);
}
$method->invokeArgs($this->provider, [new Response(400, []), [
'error' => 'invalid_client',
'code' => 400
]]);
}
public function testCreationOfResourceOwner()
{
$provider = $this->getProvider();
$class = new \ReflectionClass($provider);
$method = $class->getMethod('createResourceOwner');
$method->setAccessible(true);
public function testCreationOfResourceOwner()
{
$class = new \ReflectionClass($this->provider);
$method = $class->getMethod('createResourceOwner');
$method->setAccessible(true);
/** @var AppleResourceOwner $data */
$data = $method->invokeArgs($this->provider, [
[
'email' => 'john@doe.com',// <- Fake E-Mail from user input
'name' => [
'firstName' => 'John',
'lastName' => 'Doe'
]
],
new AccessToken([
'access_token' => 'hello',
'email' => 'john@doe.de',
'resource_owner_id' => '123.4.567'
])
]);
$this->assertEquals('john@doe.de', $data->getEmail());
$this->assertEquals('Doe', $data->getLastName());
$this->assertEquals('John', $data->getFirstName());
$this->assertEquals('123.4.567', $data->getId());
/** @var AppleResourceOwner $data */
$data = $method->invokeArgs($provider, [
[
'email' => 'john@doe.com',// <- Fake E-Mail from user input
'name' => [
'firstName' => 'John',
'lastName' => 'Doe'
]
],
new AccessToken([
'access_token' => 'hello',
'email' => 'john@doe.de',
'resource_owner_id' => '123.4.567'
])
]);
$this->assertEquals('john@doe.de', $data->getEmail());
$this->assertEquals('Doe', $data->getLastName());
$this->assertEquals('John', $data->getFirstName());
$this->assertEquals('123.4.567', $data->getId());
$this->assertFalse($data->isPrivateEmail());
$this->assertArrayHasKey('name', $data->toArray());
}
}
}
+10 -1
View File
@@ -2,6 +2,7 @@
namespace League\OAuth2\Client\Test\Provider;
use Lcobucci\JWT\Configuration;
use League\OAuth2\Client\Provider\Apple;
/**
@@ -12,7 +13,15 @@ use League\OAuth2\Client\Provider\Apple;
class TestApple extends Apple
{
/**
* @return \Lcobucci\JWT\Signer\Key|null
* {@inheritDoc}
*/
public function getConfiguration()
{
return Configuration::forUnsecuredSigner();
}
/**
* {@inheritDoc}
*/
public function getLocalKey()
{
+17 -8
View File
@@ -2,18 +2,13 @@
namespace League\OAuth2\Client\Test\Token;
use GuzzleHttp\Psr7\Response;
use League\OAuth2\Client\Token\AppleAccessToken;
use PHPUnit\Framework\TestCase;
use Mockery as m;
class AppleAccessTokenTest extends TestCase
{
public function tearDown()
{
m::close();
parent::tearDown();
}
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
@@ -33,7 +28,7 @@ class AppleAccessTokenTest extends TestCase
->once()
->andReturn(['examplekey']);
$accessToken = new AppleAccessToken([
$accessToken = new AppleAccessToken($this->getClient(1), [
'access_token' => 'access_token',
'token_type' => 'Bearer',
'expires_in' => 3600,
@@ -47,11 +42,25 @@ class AppleAccessTokenTest extends TestCase
public function testCreatingRefreshToken()
{
$refreshToken = new AppleAccessToken([
$refreshToken = new AppleAccessToken($this->getClient(0), [
'access_token' => 'access_token',
'token_type' => 'Bearer',
'expires_in' => 3600
]);
$this->assertEquals('access_token', $refreshToken->getToken());
}
private function getClient($times)
{
$client = m::mock('GuzzleHttp\ClientInterface');
if ($times > 0) {
$client->shouldReceive('request')
->times($times)
->withArgs(['GET', 'https://appleid.apple.com/auth/keys'])
->andReturn(new Response())
;
}
return $client;
}
}