diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e767a86..0618411 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,27 +1,30 @@ name: Test -on: [ pull_request, push ] +on: + pull_request: + push: + branches: [ master ] jobs: test: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest strategy: max-parallel: 15 fail-fast: false matrix: coverage: [ 'none' ] - php-versions: [ '7.2', '7.3', '7.4', '8.0' ] + php-versions: [ '8.0', '8.1', '8.2' ] exclude: - - php-versions: '8.0' + - php-versions: '8.2' include: - - php-versions: '8.0' + - php-versions: '8.2' coverage: 'xdebug' name: PHP ${{ matrix.php-versions }} steps: - name: Checkout - uses: actions/checkout@master + uses: actions/checkout@v3 - name: Setup PHP uses: shivammathur/setup-php@v2 @@ -40,5 +43,5 @@ jobs: run: vendor/bin/phpunit -v - name: Upload coverage results - uses: codecov/codecov-action@v1 if: matrix.coverage != 'none' + uses: codecov/codecov-action@v3 diff --git a/composer.json b/composer.json index 442cafa..0b7528f 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,7 @@ { "name": "socialiteproviders/manager", "description": "Easily add new or override built-in providers in Laravel Socialite.", + "license": "MIT", "keywords": [ "laravel", "manager", @@ -8,8 +9,6 @@ "providers", "socialite" ], - "homepage": "https://socialiteproviders.com", - "license": "MIT", "authors": [ { "name": "Andy Wendt", @@ -29,25 +28,21 @@ "homepage": "https://atymic.dev" } ], + "homepage": "https://socialiteproviders.com", + "support": { + "issues": "https://github.com/socialiteproviders/manager/issues", + "source": "https://github.com/socialiteproviders/manager" + }, "require": { - "php": "^7.2 || ^8.0", - "illuminate/support": "^6.0 || ^7.0 || ^8.0", + "php": "^8.0", + "illuminate/support": "^8.0 || ^9.0 || ^10.0 || ^11.0", "laravel/socialite": "^5.5" }, "require-dev": { "mockery/mockery": "^1.2", - "phpunit/phpunit": "^6.0 || ^9.0" - }, - "config": { - "sort-packages": true - }, - "extra": { - "laravel": { - "providers": [ - "SocialiteProviders\\Manager\\ServiceProvider" - ] - } + "phpunit/phpunit": "^9.0" }, + "minimum-stability": "stable", "autoload": { "psr-4": { "SocialiteProviders\\Manager\\": "src/" @@ -58,9 +53,14 @@ "SocialiteProviders\\Manager\\Test\\": "tests/" } }, - "minimum-stability": "stable", - "support": { - "issues": "https://github.com/socialiteproviders/manager/issues", - "source": "https://github.com/socialiteproviders/manager" + "config": { + "sort-packages": true + }, + "extra": { + "laravel": { + "providers": [ + "SocialiteProviders\\Manager\\ServiceProvider" + ] + } } } diff --git a/src/Helpers/ConfigRetriever.php b/src/Helpers/ConfigRetriever.php index c68d841..f3c2147 100644 --- a/src/Helpers/ConfigRetriever.php +++ b/src/Helpers/ConfigRetriever.php @@ -39,15 +39,15 @@ public function fromServices($providerName, array $additionalConfigKeys = []) $this->providerName = $providerName; $this->getConfigFromServicesArray($providerName); - $this->additionalConfigKeys = $additionalConfigKeys = array_unique($additionalConfigKeys + ['guzzle']); + $this->additionalConfigKeys = $additionalConfigKeys = array_unique( + array_merge($additionalConfigKeys, ['guzzle']), + ); return new Config( $this->getFromServices('client_id'), $this->getFromServices('client_secret'), $this->getFromServices('redirect'), - $this->getConfigItems($additionalConfigKeys, function ($key) { - return $this->getFromServices(strtolower($key)); - }) + $this->getConfigItems($additionalConfigKeys, fn($key) => $this->getFromServices(strtolower($key))) ); } diff --git a/src/OAuth2/AbstractProvider.php b/src/OAuth2/AbstractProvider.php index 97bbb3c..cff100b 100644 --- a/src/OAuth2/AbstractProvider.php +++ b/src/OAuth2/AbstractProvider.php @@ -18,6 +18,13 @@ abstract class AbstractProvider extends BaseProvider implements ProviderInterfac */ protected $credentialsResponseBody; + /** + * The cached user instance. + * + * @var \SocialiteProviders\Manager\OAuth2\User|null + */ + protected $user; + /** * @param string $providerName * @@ -35,6 +42,10 @@ public static function serviceContainerKey($providerName) */ public function user() { + if ($this->user) { + return $this->user; + } + if ($this->hasInvalidState()) { throw new InvalidStateException(); } @@ -42,15 +53,15 @@ public function user() $response = $this->getAccessTokenResponse($this->getCode()); $this->credentialsResponseBody = $response; - $user = $this->mapUserToObject($this->getUserByToken( + $this->user = $this->mapUserToObject($this->getUserByToken( $token = $this->parseAccessToken($response) )); - if ($user instanceof User) { - $user->setAccessTokenResponseBody($this->credentialsResponseBody); + if ($this->user instanceof User) { + $this->user->setAccessTokenResponseBody($this->credentialsResponseBody); } - return $user->setToken($token) + return $this->user->setToken($token) ->setRefreshToken($this->parseRefreshToken($response)) ->setExpiresIn($this->parseExpiresIn($response)) ->setApprovedScopes($this->parseApprovedScopes($response)); diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index c957804..1d1b1dc 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -40,9 +40,7 @@ public function register() } if (! $this->app->bound(ConfigRetrieverInterface::class)) { - $this->app->singleton(ConfigRetrieverInterface::class, function () { - return new ConfigRetriever(); - }); + $this->app->singleton(ConfigRetrieverInterface::class, fn() => new ConfigRetriever()); } } } diff --git a/src/SocialiteWasCalled.php b/src/SocialiteWasCalled.php index adec7d9..9ade289 100644 --- a/src/SocialiteWasCalled.php +++ b/src/SocialiteWasCalled.php @@ -20,10 +20,7 @@ class SocialiteWasCalled */ protected $app; - /** - * @var \SocialiteProviders\Manager\Contracts\Helpers\ConfigRetrieverInterface - */ - private $configRetriever; + private ConfigRetrieverInterface $configRetriever; /** * @param \Illuminate\Contracts\Container\Container $app diff --git a/tests/ConfigRetrieverTest.php b/tests/ConfigRetrieverTest.php index c35f9bb..99d9187 100644 --- a/tests/ConfigRetrieverTest.php +++ b/tests/ConfigRetrieverTest.php @@ -76,6 +76,39 @@ public function it_retrieves_a_config_from_the_services(): void $this->assertSame($uri, $result['redirect']); $this->assertSame($additionalConfigItem, $result['additional']); } + + /** + * @test + */ + public function it_retrieves_a_config_from_the_services_with_guzzle(): void + { + $providerName = 'test'; + $key = 'key'; + $secret = 'secret'; + $uri = 'uri'; + $additionalConfigItem = 'test'; + $config = [ + 'client_id' => $key, + 'client_secret' => $secret, + 'redirect' => $uri, + 'additional' => $additionalConfigItem, + 'guzzle' => ['verify' => false], + ]; + self::$functions + ->shouldReceive('config') + ->with("services.{$providerName}") + ->once() + ->andReturn($config); + $configRetriever = new ConfigRetriever(); + + $result = $configRetriever->fromServices($providerName, ['additional'])->get(); + + $this->assertSame($key, $result['client_id']); + $this->assertSame($secret, $result['client_secret']); + $this->assertSame($uri, $result['redirect']); + $this->assertSame($additionalConfigItem, $result['additional']); + $this->assertSame(['verify' => false], $result['guzzle']); + } } namespace SocialiteProviders\Manager\Helpers; diff --git a/tests/ConfigTest.php b/tests/ConfigTest.php index 2b2df29..70e36ef 100644 --- a/tests/ConfigTest.php +++ b/tests/ConfigTest.php @@ -54,9 +54,7 @@ public function it_allows_closure_config_redirect() $key = 'key'; $secret = 'secret'; $callbackUri = 'uri'; - $callbackFunc = function () use ($callbackUri) { - return $callbackUri; - }; + $callbackFunc = fn() => $callbackUri; $result = [ 'client_id' => $key, 'client_secret' => $secret, diff --git a/tests/OAuthTwoTest.php b/tests/OAuthTwoTest.php index 1f5ea82..a80be99 100644 --- a/tests/OAuthTwoTest.php +++ b/tests/OAuthTwoTest.php @@ -221,4 +221,59 @@ public function exceptionIsThrownIfStateIsNotSet(): void $provider = new OAuthTwoTestProviderStub($request, 'client_id', 'client_secret', 'redirect'); $provider->user(); } + + /** + * @test + */ + public function userObjectShouldBeCachedOnFirstCall(): void + { + $session = m::mock(SessionInterface::class); + $accessTokenResponseBody = '{"access_token": "access_token", "test": "test"}'; + $request = Request::create('foo', 'GET', [ + 'state' => str_repeat('A', 40), + 'code' => 'code', + ]); + $request->setSession($session); + $session + ->shouldReceive('pull') + ->once() + ->with('state') + ->andReturn(str_repeat('A', 40)); + $provider = new OAuthTwoTestProviderStub($request, 'client_id', 'client_secret', 'redirect_uri'); + + $provider->http = m::mock(stdClass::class); + $provider->http + ->shouldReceive('post') + ->once() + ->with('http://token.url', [ + 'headers' => [ + 'Accept' => 'application/json', + ], + 'form_params' => [ + 'grant_type' => 'authorization_code', + 'client_id' => 'client_id', + 'client_secret' => 'client_secret', + 'code' => 'code', + 'redirect_uri' => 'redirect_uri', + ], + ]) + ->andReturn($response = m::mock(stdClass::class)); + $response + ->shouldReceive('getBody') + ->andReturn($accessTokenResponseBody); + + $reflection = new \ReflectionClass($provider); + $reflectionProperty = $reflection->getProperty('user'); + $reflectionProperty->setAccessible(true); + + $this->assertNull($reflectionProperty->getValue($provider)); + + $firstCall = $provider->user(); + + $this->assertInstanceOf(SocialiteOAuth2User::class, $reflectionProperty->getValue($provider)); + + $secondCall = $provider->user(); + + $this->assertSame($firstCall, $secondCall); + } }