From 545eafefd1fe9401e18a2760c9118e43ccb4b050 Mon Sep 17 00:00:00 2001 From: Joseph Bielawski Date: Fri, 1 Jan 2021 11:51:11 +0100 Subject: [PATCH] Rework resource owners to use Symfony Http Client internally --- CHANGELOG.md | 3 + DependencyInjection/Configuration.php | 16 - DependencyInjection/HWIOAuthExtension.php | 20 -- OAuth/ResourceOwner/AbstractResourceOwner.php | 61 ++-- OAuth/ResourceOwner/AppleResourceOwner.php | 16 +- OAuth/ResourceOwner/DropboxResourceOwner.php | 23 +- OAuth/ResourceOwner/FiwareResourceOwner.php | 2 +- .../ResourceOwner/FoursquareResourceOwner.php | 6 +- .../GenericOAuth1ResourceOwner.php | 2 +- .../GenericOAuth2ResourceOwner.php | 19 +- OAuth/ResourceOwner/JiraResourceOwner.php | 18 +- OAuth/ResourceOwner/MailRuResourceOwner.php | 26 +- .../OdnoklassnikiResourceOwner.php | 20 +- OAuth/ResourceOwner/QQResourceOwner.php | 16 +- .../SensioConnectResourceOwner.php | 28 ++ .../ResourceOwner/SinaWeiboResourceOwner.php | 19 +- OAuth/ResourceOwner/SpotifyResourceOwner.php | 19 +- .../StackExchangeResourceOwner.php | 25 +- OAuth/ResourceOwner/TraktResourceOwner.php | 17 +- .../ResourceOwner/VkontakteResourceOwner.php | 30 +- Resources/config/http_client.xml | 13 - Resources/config/util.xml | 4 +- Resources/doc/1-setting_up_the_bundle.md | 14 +- Resources/doc/index.md | 1 - .../internals/configuring_the_http_client.md | 121 ------- Resources/doc/resource_owners/fiware.md | 9 - Tests/App/config.yml | 10 +- .../HWIOAuthExtensionTest.php | 29 +- .../Controller/ConnectControllerTest.php | 46 +-- .../Controller/LoginControllerTest.php | 13 +- Tests/Functional/IntegrationTest.php | 28 +- .../ResourceOwner/AmazonResourceOwnerTest.php | 2 +- .../ResourceOwner/AppleResourceOwnerTest.php | 89 +++--- .../ResourceOwner/AsanaResourceOwnerTest.php | 2 +- .../ResourceOwner/Auth0ResourceOwnerTest.php | 136 +------- .../ResourceOwner/AzureResourceOwnerTest.php | 57 ++-- .../BitbucketResourceOwnerTest.php | 12 +- .../ResourceOwner/BitlyResourceOwnerTest.php | 2 +- .../ResourceOwner/BoxResourceOwnerTest.php | 28 +- .../BufferAppResourceOwnerTest.php | 31 +- .../ResourceOwner/CleverResourceOwnerTest.php | 10 +- .../DailymotionResourceOwnerTest.php | 6 +- .../ResourceOwner/DeezerResourceOwnerTest.php | 12 +- .../DeviantartResourceOwnerTest.php | 15 +- .../DiscogsResourceOwnerTest.php | 2 +- .../ResourceOwner/DisqusResourceOwnerTest.php | 2 +- .../DropboxResourceOwnerTest.php | 6 +- .../EveOnlineResourceOwnerTest.php | 2 +- .../EventbriteResourceOwnerTest.php | 12 +- .../FacebookResourceOwnerTest.php | 51 ++- .../ResourceOwner/FlickrResourceOwnerTest.php | 26 +- .../FoursquareResourceOwnerTest.php | 12 +- .../GenericOAuth1ResourceOwnerTest.php | 216 ++++++++----- .../GenericOAuth2ResourceOwnerTest.php | 301 ++++++++++-------- .../ResourceOwner/GeniusResourceOwnerTest.php | 2 +- .../ResourceOwner/GitHubResourceOwnerTest.php | 77 +++-- .../ResourceOwner/GitLabResourceOwnerTest.php | 13 +- .../ResourceOwner/GoogleResourceOwnerTest.php | 52 +-- .../ResourceOwner/HubicResourceOwnerTest.php | 16 +- .../InstagramResourceOwnerTest.php | 10 +- .../ItembaseResourceOwnerTest.php | 4 +- .../ResourceOwner/JiraResourceOwnerTest.php | 73 ++--- .../KeycloakResourceOwnerTest.php | 2 +- .../LinkedinResourceOwnerTest.php | 39 ++- .../ResourceOwner/MailRuResourceOwnerTest.php | 2 +- .../OdnoklassnikiResourceOwnerTest.php | 8 +- .../Office365ResourceOwnerTest.php | 2 +- .../ResourceOwner/PaypalResourceOwnerTest.php | 4 +- .../ResourceOwner/QQResourceOwnerTest.php | 72 ++++- .../ResourceOwner/RedditResourceOwnerTest.php | 2 +- .../ResourceOwner/ResourceOwnerTestCase.php | 83 ++--- .../RunKeeperResourceOwnerTest.php | 16 +- .../SalesforceResourceOwnerTest.php | 40 ++- .../SensioConnectResourceOwnerTest.php | 32 +- .../SinaWeiboResourceOwnerTest.php | 47 +-- .../ResourceOwner/SlackResourceOwnerTest.php | 2 +- .../SoundcloudResourceOwnerTest.php | 2 +- .../SpotifyResourceOwnerTest.php | 25 +- .../StackExchangeResourceOwnerTest.php | 8 +- .../StereomoodResourceOwnerTest.php | 13 +- .../ResourceOwner/StravaResourceOwnerTest.php | 14 +- .../ThirtySevenSignalsResourceOwnerTest.php | 2 +- .../ResourceOwner/ToshlResourceOwnerTest.php | 37 ++- .../ResourceOwner/TraktResourceOwnerTest.php | 12 +- .../ResourceOwner/TrelloResourceOwnerTest.php | 14 +- .../ResourceOwner/TwitchResourceOwnerTest.php | 2 +- .../TwitterResourceOwnerTest.php | 21 +- .../VkontakteResourceOwnerTest.php | 2 +- .../WindowsLiveResourceOwnerTest.php | 2 +- .../WordpressResourceOwnerTest.php | 2 +- .../ResourceOwner/XingResourceOwnerTest.php | 12 +- .../ResourceOwner/YahooResourceOwnerTest.php | 22 +- .../ResourceOwner/YandexResourceOwnerTest.php | 2 +- .../YoutubeResourceOwnerTest.php | 50 ++- composer.json | 11 +- 95 files changed, 1375 insertions(+), 1182 deletions(-) delete mode 100644 Resources/config/http_client.xml delete mode 100644 Resources/doc/internals/configuring_the_http_client.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 8177814a8..27000d935 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,9 @@ Changelog * BC Break: `ResourceOwnerMap` uses service locator instead of DI container, * BC Break: Removed abstract services: `hwi_oauth.abstract_resource_owner.generic`, `hwi_oauth.abstract_resource_owner.oauth1` & `hwi_oauth.abstract_resource_owner.oauth2`, * BC Break: Removed `setName()` method from `OAuth/ResourceOwnerInterface`, +* BC Break: changed `__construct()` argument for `OAuth/ResourceOwner/AbstractResourceOwner`, from `HttpMethodsClient $httpClient` to `HttpClientInterface $httpClient`, +* BC Break: replaced `php-http/httplug-bundle` with `symfony/http-client` +* BC Break: removed `hwi_oauth.http` configuration ## 1.4.1 (2021-07-28) * Bugfix: Define missing `hwi_oauth.connect.confirmation` parameter, diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index a3b537750..e3185a8e9 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -180,7 +180,6 @@ public function getConfigTreeBuilder() ->end() ; - $this->addHttpClientConfiguration($rootNode); $this->addConnectConfiguration($rootNode); $this->addResourceOwnersConfiguration($rootNode); @@ -431,21 +430,6 @@ private function addResourceOwnersConfiguration(ArrayNodeDefinition $node): void ; } - private function addHttpClientConfiguration(ArrayNodeDefinition $node): void - { - $node - ->children() - ->arrayNode('http') - ->addDefaultsIfNotSet() - ->children() - ->scalarNode('client')->defaultValue('httplug.client.default')->end() - ->scalarNode('message_factory')->defaultValue('httplug.message_factory.default')->end() - ->end() - ->end() - ->end() - ; - } - private function addConnectConfiguration(ArrayNodeDefinition $node): void { $node diff --git a/DependencyInjection/HWIOAuthExtension.php b/DependencyInjection/HWIOAuthExtension.php index a697e7985..17c6d2010 100644 --- a/DependencyInjection/HWIOAuthExtension.php +++ b/DependencyInjection/HWIOAuthExtension.php @@ -48,7 +48,6 @@ public function load(array $configs, ContainerBuilder $container) { $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config/')); $loader->load('controller.xml'); - $loader->load('http_client.xml'); $loader->load('oauth.xml'); $loader->load('resource_owners.xml'); $loader->load('templating.xml'); @@ -58,8 +57,6 @@ public function load(array $configs, ContainerBuilder $container) $processor = new Processor(); $config = $processor->processConfiguration(new Configuration(), $configs); - $this->createHttplugClient($container, $config); - // set current firewall if (empty($config['firewall_names'])) { throw new InvalidConfigurationException('The child node "firewall_names" at path "hwi_oauth" must be configured.'); @@ -156,23 +153,6 @@ public function getAlias() return 'hwi_oauth'; } - protected function createHttplugClient(ContainerBuilder $container, array $config) - { - $httpClientId = $config['http']['client']; - $httpMessageFactoryId = $config['http']['message_factory']; - $bundles = $container->getParameter('kernel.bundles'); - - if ('httplug.client.default' === $httpClientId && !isset($bundles['HttplugBundle'])) { - throw new InvalidConfigurationException('You must setup php-http/httplug-bundle to use the default http client service.'); - } - if ('httplug.message_factory.default' === $httpMessageFactoryId && !isset($bundles['HttplugBundle'])) { - throw new InvalidConfigurationException('You must setup php-http/httplug-bundle to use the default http message factory service.'); - } - - $container->setAlias('hwi_oauth.http.client', new Alias($config['http']['client'], true)); - $container->setAlias('hwi_oauth.http.message_factory', new Alias($config['http']['message_factory'], true)); - } - /** * Check of the connect controllers etc should be enabled. * diff --git a/OAuth/ResourceOwner/AbstractResourceOwner.php b/OAuth/ResourceOwner/AbstractResourceOwner.php index c43c89b1b..cd81224d2 100644 --- a/OAuth/ResourceOwner/AbstractResourceOwner.php +++ b/OAuth/ResourceOwner/AbstractResourceOwner.php @@ -11,8 +11,6 @@ namespace HWI\Bundle\OAuthBundle\OAuth\ResourceOwner; -use Http\Client\Common\HttpMethodsClient; -use Http\Client\Exception; use HWI\Bundle\OAuthBundle\OAuth\Exception\HttpTransportException; use HWI\Bundle\OAuthBundle\OAuth\RequestDataStorageInterface; use HWI\Bundle\OAuthBundle\OAuth\ResourceOwnerInterface; @@ -20,15 +18,16 @@ use HWI\Bundle\OAuthBundle\OAuth\Response\UserResponseInterface; use HWI\Bundle\OAuthBundle\OAuth\State\State; use HWI\Bundle\OAuthBundle\OAuth\StateInterface; -use Psr\Http\Message\ResponseInterface; +use Symfony\Component\HttpClient\Exception\JsonException; use Symfony\Component\HttpFoundation\Request as HttpRequest; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Http\HttpUtils; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; /** - * AbstractResourceOwner. - * * @author Geoffrey Bachelet * @author Alexander * @author Francisco Facioni @@ -47,7 +46,7 @@ abstract class AbstractResourceOwner implements ResourceOwnerInterface protected $paths = []; /** - * @var HttpMethodsClient + * @var HttpClientInterface */ protected $httpClient; @@ -77,14 +76,11 @@ abstract class AbstractResourceOwner implements ResourceOwnerInterface private $stateLoaded = false; /** - * @param HttpMethodsClient $httpClient Httplug client - * @param HttpUtils $httpUtils Http utils - * @param array $options Options for the resource owner - * @param string $name Name for the resource owner - * @param RequestDataStorageInterface $storage Request token storage + * @param array $options Options for the resource owner + * @param string $name Name for the resource owner */ public function __construct( - HttpMethodsClient $httpClient, + HttpClientInterface $httpClient, HttpUtils $httpUtils, array $options, string $name, @@ -295,46 +291,41 @@ protected function httpRequest($url, $content = null, array $headers = [], $meth $method = null === $content || '' === $content ? 'GET' : 'POST'; } - $headers += ['User-Agent' => 'HWIOAuthBundle (https://github.com/hwi/HWIOAuthBundle)']; + $options = ['headers' => $headers]; + $options['headers'] += ['User-Agent' => 'HWIOAuthBundle (https://github.com/hwi/HWIOAuthBundle)']; if (\is_string($content)) { - if (!isset($headers['Content-Length'])) { - $headers += ['Content-Length' => (string) \strlen($content)]; + if (!isset($options['headers']['Content-Length'])) { + $options['headers'] += ['Content-Length' => (string) \strlen($content)]; } } elseif (\is_array($content)) { - $content = http_build_query($content, '', '&'); + $options['body'] = $content; } try { - return $this->httpClient->send( + return $this->httpClient->request( $method, $url, - $headers, - $content + $options ); - } catch (Exception $e) { + } catch (TransportExceptionInterface $e) { throw new HttpTransportException('Error while sending HTTP request', $this->getName(), $e->getCode(), $e); } } - /** - * Get the 'parsed' content based on the response headers. - * - * @return array - */ - protected function getResponseContent(ResponseInterface $rawResponse) + protected function getResponseContent(ResponseInterface $rawResponse): array { - // First check that content in response exists, due too bug: https://bugs.php.net/bug.php?id=54484 - $content = (string) $rawResponse->getBody(); - if (!$content) { - return []; - } + $contentTypes = $rawResponse->getHeaders(false)['content-type'] ?? []; + if (\in_array('text/plain', $contentTypes, true)) { + parse_str($rawResponse->getContent(false), $response); - $response = json_decode($content, true); - if (\JSON_ERROR_NONE !== json_last_error()) { - parse_str($content, $response); + return $response; } - return $response; + try { + return $rawResponse->toArray(false); + } catch (JsonException $e) { + return []; + } } /** diff --git a/OAuth/ResourceOwner/AppleResourceOwner.php b/OAuth/ResourceOwner/AppleResourceOwner.php index ecea85a14..31268b40a 100644 --- a/OAuth/ResourceOwner/AppleResourceOwner.php +++ b/OAuth/ResourceOwner/AppleResourceOwner.php @@ -52,10 +52,10 @@ public function getAuthorizationUrl($redirectUri, array $extraParameters = []) public function getUserInformation(array $accessToken, array $extraParameters = []) { if (!isset($accessToken['id_token'])) { - throw new \Exception('Undefined index id_token'); + throw new \InvalidArgumentException('Undefined index id_token'); } - $jwt = self::jwt_decode($accessToken['id_token']); + $jwt = self::jwtDecode($accessToken['id_token']); $data = json_decode(base64_decode($jwt), true); if (isset($accessToken['firstName'], $accessToken['lastName'])) { @@ -105,9 +105,10 @@ public function getAccessToken(Request $request, $redirectUri, array $extraParam */ public function refreshAccessToken($refreshToken, array $extraParameters = []) { - $parameters = []; - $parameters['client_id'] = $this->options['client_id']; - $parameters['client_secret'] = $this->options['client_secret']; + $parameters = [ + 'client_id' => $this->options['client_id'], + 'client_secret' => $this->options['client_secret'], + ]; return parent::refreshAccessToken($refreshToken, array_merge($parameters, $extraParameters)); } @@ -130,7 +131,6 @@ protected function configureOptions(OptionsResolver $resolver) $resolver->setDefaults([ 'authorization_url' => 'https://appleid.apple.com/auth/authorize', 'access_token_url' => 'https://appleid.apple.com/auth/token', - 'revoke_token_url' => '', 'infos_url' => '', 'use_commas_in_scope' => false, 'display' => null, @@ -140,10 +140,10 @@ protected function configureOptions(OptionsResolver $resolver) ]); } - private static function jwt_decode($id_token) + private static function jwtDecode(string $idToken) { //// from http://stackoverflow.com/a/28748285/624544 - [, $jwt] = explode('.', $id_token, 3); + [, $jwt] = explode('.', $idToken, 3); // if the token was urlencoded, do some fixes to ensure that it is valid base64 encoded $jwt = str_replace(['-', '_'], ['+', '/'], $jwt); diff --git a/OAuth/ResourceOwner/DropboxResourceOwner.php b/OAuth/ResourceOwner/DropboxResourceOwner.php index 9af84b18a..9a22195bd 100644 --- a/OAuth/ResourceOwner/DropboxResourceOwner.php +++ b/OAuth/ResourceOwner/DropboxResourceOwner.php @@ -11,9 +11,12 @@ namespace HWI\Bundle\OAuthBundle\OAuth\ResourceOwner; +use HWI\Bundle\OAuthBundle\OAuth\Exception\HttpTransportException; use HWI\Bundle\OAuthBundle\OAuth\Response\UserResponseInterface; use HWI\Bundle\OAuthBundle\Security\Core\Authentication\Token\OAuthToken; +use Symfony\Component\HttpClient\Exception\JsonException; use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; /** * DropboxResourceOwner. @@ -44,8 +47,7 @@ public function getUserInformation(array $accessToken, ) { if ($this->options['use_bearer_authorization']) { $content = $this->httpRequest( - $this->normalizeUrl($this->options['infos_url'], - $extraParameters), + $this->normalizeUrl($this->options['infos_url'], $extraParameters), 'null', [ 'Authorization' => 'Bearer'.' '.$accessToken['access_token'], @@ -56,18 +58,21 @@ public function getUserInformation(array $accessToken, $content = $this->doGetUserInformationRequest( $this->normalizeUrl( $this->options['infos_url'], - array_merge([$this->options['attr_name'] => $accessToken['access_token']], - $extraParameters) + array_merge([$this->options['attr_name'] => $accessToken['access_token']], $extraParameters) ) ); } - $response = $this->getUserResponse(); - $response->setData((string) $content->getBody()); - $response->setResourceOwner($this); - $response->setOAuthToken(new OAuthToken($accessToken)); + try { + $response = $this->getUserResponse(); + $response->setData($content->toArray(false)); + $response->setResourceOwner($this); + $response->setOAuthToken(new OAuthToken($accessToken)); - return $response; + return $response; + } catch (TransportExceptionInterface | JsonException $e) { + throw new HttpTransportException('Error while sending HTTP request', $this->getName(), $e->getCode(), $e); + } } /** diff --git a/OAuth/ResourceOwner/FiwareResourceOwner.php b/OAuth/ResourceOwner/FiwareResourceOwner.php index 4f4c1f01c..9fe75aaf1 100644 --- a/OAuth/ResourceOwner/FiwareResourceOwner.php +++ b/OAuth/ResourceOwner/FiwareResourceOwner.php @@ -86,7 +86,7 @@ public function getUserInformation(array $accessToken, array $extraParameters = } $response = $this->getUserResponse(); - $response->setData((string) $content->getBody()); + $response->setData($content->getContent()); $response->setResourceOwner($this); $response->setOAuthToken(new OAuthToken($accessToken)); diff --git a/OAuth/ResourceOwner/FoursquareResourceOwner.php b/OAuth/ResourceOwner/FoursquareResourceOwner.php index c47e38dbb..df669b30b 100644 --- a/OAuth/ResourceOwner/FoursquareResourceOwner.php +++ b/OAuth/ResourceOwner/FoursquareResourceOwner.php @@ -11,8 +11,8 @@ namespace HWI\Bundle\OAuthBundle\OAuth\ResourceOwner; -use Psr\Http\Message\ResponseInterface; use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Contracts\HttpClient\ResponseInterface; /** * FoursquareResourceOwner. @@ -39,14 +39,14 @@ class FoursquareResourceOwner extends GenericOAuth2ResourceOwner /** * {@inheritdoc} */ - protected function getResponseContent(ResponseInterface $rawResponse) + protected function getResponseContent(ResponseInterface $rawResponse): array { $response = parent::getResponseContent($rawResponse); // Foursquare use quite custom response structure in case of error if (isset($response['meta']['errorType'])) { // Prevent to mark deprecated calls as errors - if (200 == $response['meta']['code']) { + if (200 === (int) $response['meta']['code']) { $response['error'] = $response['meta']['errorType']; // Try to add some details of error if available if (isset($response['meta']['errorMessage'])) { diff --git a/OAuth/ResourceOwner/GenericOAuth1ResourceOwner.php b/OAuth/ResourceOwner/GenericOAuth1ResourceOwner.php index 969b39ddb..a8052e9e2 100644 --- a/OAuth/ResourceOwner/GenericOAuth1ResourceOwner.php +++ b/OAuth/ResourceOwner/GenericOAuth1ResourceOwner.php @@ -53,7 +53,7 @@ public function getUserInformation(array $accessToken, array $extraParameters = $content = $this->doGetUserInformationRequest($url, $parameters); $response = $this->getUserResponse(); - $response->setData((string) $content->getBody()); + $response->setData($content->getContent()); $response->setResourceOwner($this); $response->setOAuthToken(new OAuthToken($accessToken)); diff --git a/OAuth/ResourceOwner/GenericOAuth2ResourceOwner.php b/OAuth/ResourceOwner/GenericOAuth2ResourceOwner.php index f229eafa8..006b9e47e 100644 --- a/OAuth/ResourceOwner/GenericOAuth2ResourceOwner.php +++ b/OAuth/ResourceOwner/GenericOAuth2ResourceOwner.php @@ -11,13 +11,16 @@ namespace HWI\Bundle\OAuthBundle\OAuth\ResourceOwner; +use HWI\Bundle\OAuthBundle\OAuth\Exception\HttpTransportException; use HWI\Bundle\OAuthBundle\Security\Core\Authentication\Token\OAuthToken; use HWI\Bundle\OAuthBundle\Security\Helper\NonceGenerator; use HWI\Bundle\OAuthBundle\Security\OAuthErrorHandler; +use Symfony\Component\HttpClient\Exception\JsonException; use Symfony\Component\HttpFoundation\Request as HttpRequest; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Security\Core\Exception\AuthenticationException; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; /** * @author Geoffrey Bachelet @@ -45,12 +48,16 @@ public function getUserInformation(array $accessToken, array $extraParameters = ); } - $response = $this->getUserResponse(); - $response->setData((string) $content->getBody()); - $response->setResourceOwner($this); - $response->setOAuthToken(new OAuthToken($accessToken)); - - return $response; + try { + $response = $this->getUserResponse(); + $response->setData($content->toArray(false)); + $response->setResourceOwner($this); + $response->setOAuthToken(new OAuthToken($accessToken)); + + return $response; + } catch (TransportExceptionInterface | JsonException $e) { + throw new HttpTransportException('Error while sending HTTP request', $this->getName(), $e->getCode(), $e); + } } /** diff --git a/OAuth/ResourceOwner/JiraResourceOwner.php b/OAuth/ResourceOwner/JiraResourceOwner.php index dfc893fd9..df46a6b69 100644 --- a/OAuth/ResourceOwner/JiraResourceOwner.php +++ b/OAuth/ResourceOwner/JiraResourceOwner.php @@ -11,11 +11,13 @@ namespace HWI\Bundle\OAuthBundle\OAuth\ResourceOwner; +use HWI\Bundle\OAuthBundle\OAuth\Exception\HttpTransportException; use HWI\Bundle\OAuthBundle\Security\Core\Authentication\Token\OAuthToken; use HWI\Bundle\OAuthBundle\Security\Helper\NonceGenerator; use HWI\Bundle\OAuthBundle\Security\OAuthUtils; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; /** * JiraResourceOwner. @@ -74,14 +76,18 @@ public function getUserInformation(array $accessToken, array $extraParameters = $this->options['signature_method'] ); - $content = $this->doGetUserInformationRequest($url, $parameters); + try { + $content = $this->doGetUserInformationRequest($url, $parameters); - $response = $this->getUserResponse(); - $response->setData((string) $content->getBody()); - $response->setResourceOwner($this); - $response->setOAuthToken(new OAuthToken($accessToken)); + $response = $this->getUserResponse(); + $response->setData($content->getContent(false)); + $response->setResourceOwner($this); + $response->setOAuthToken(new OAuthToken($accessToken)); - return $response; + return $response; + } catch (TransportExceptionInterface $e) { + throw new HttpTransportException('Error while sending HTTP request', $this->getName(), $e->getCode(), $e); + } } /** diff --git a/OAuth/ResourceOwner/MailRuResourceOwner.php b/OAuth/ResourceOwner/MailRuResourceOwner.php index 878df10d9..dca5d417d 100644 --- a/OAuth/ResourceOwner/MailRuResourceOwner.php +++ b/OAuth/ResourceOwner/MailRuResourceOwner.php @@ -11,8 +11,11 @@ namespace HWI\Bundle\OAuthBundle\OAuth\ResourceOwner; +use HWI\Bundle\OAuthBundle\OAuth\Exception\HttpTransportException; use HWI\Bundle\OAuthBundle\Security\Core\Authentication\Token\OAuthToken; +use Symfony\Component\HttpClient\Exception\JsonException; use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; /** * MailRuResourceOwner. @@ -49,18 +52,21 @@ public function getUserInformation(array $accessToken, array $extraParameters = $url = $this->normalizeUrl($this->options['infos_url'], $params); - $content = (string) $this->doGetUserInformationRequest($url)->getBody(); - $content = json_decode($content, true); - if (isset($content[0])) { - $content = (array) $content[0]; - } + try { + $content = $this->doGetUserInformationRequest($url)->toArray(false); + if (isset($content[0])) { + $content = (array) $content[0]; + } - $response = $this->getUserResponse(); - $response->setData($content); - $response->setResourceOwner($this); - $response->setOAuthToken(new OAuthToken($accessToken)); + $response = $this->getUserResponse(); + $response->setData($content); + $response->setResourceOwner($this); + $response->setOAuthToken(new OAuthToken($accessToken)); - return $response; + return $response; + } catch (TransportExceptionInterface | JsonException $e) { + throw new HttpTransportException('Error while sending HTTP request', $this->getName(), $e->getCode(), $e); + } } /** diff --git a/OAuth/ResourceOwner/OdnoklassnikiResourceOwner.php b/OAuth/ResourceOwner/OdnoklassnikiResourceOwner.php index 9ebf9196c..e76ac2c8f 100644 --- a/OAuth/ResourceOwner/OdnoklassnikiResourceOwner.php +++ b/OAuth/ResourceOwner/OdnoklassnikiResourceOwner.php @@ -11,9 +11,12 @@ namespace HWI\Bundle\OAuthBundle\OAuth\ResourceOwner; +use HWI\Bundle\OAuthBundle\OAuth\Exception\HttpTransportException; use HWI\Bundle\OAuthBundle\Security\Core\Authentication\Token\OAuthToken; +use Symfony\Component\HttpClient\Exception\JsonException; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; /** * OdnoklassnikiResourceOwner. @@ -61,16 +64,21 @@ public function getUserInformation(array $accessToken, array $extraParameters = md5($accessToken['access_token'].$this->options['client_secret']) )); } + $url = $this->normalizeUrl($this->options['infos_url'], $parameters); - $content = $this->doGetUserInformationRequest($url)->getBody(); + try { + $content = $this->doGetUserInformationRequest($url)->toArray(false); - $response = $this->getUserResponse(); - $response->setData((string) $content); - $response->setResourceOwner($this); - $response->setOAuthToken(new OAuthToken($accessToken)); + $response = $this->getUserResponse(); + $response->setData($content); + $response->setResourceOwner($this); + $response->setOAuthToken(new OAuthToken($accessToken)); - return $response; + return $response; + } catch (TransportExceptionInterface | JsonException $e) { + throw new HttpTransportException('Error while sending HTTP request', $this->getName(), $e->getCode(), $e); + } } /** diff --git a/OAuth/ResourceOwner/QQResourceOwner.php b/OAuth/ResourceOwner/QQResourceOwner.php index 120a28c8f..d9b059e9b 100644 --- a/OAuth/ResourceOwner/QQResourceOwner.php +++ b/OAuth/ResourceOwner/QQResourceOwner.php @@ -11,11 +11,10 @@ namespace HWI\Bundle\OAuthBundle\OAuth\ResourceOwner; -use Http\Discovery\MessageFactoryDiscovery; use HWI\Bundle\OAuthBundle\Security\Core\Authentication\Token\OAuthToken; -use Psr\Http\Message\ResponseInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Security\Core\Exception\AuthenticationException; +use Symfony\Contracts\HttpClient\ResponseInterface; /** * @final since 1.4 @@ -35,18 +34,11 @@ class QQResourceOwner extends GenericOAuth2ResourceOwner /** * {@inheritdoc} */ - public function getResponseContent(ResponseInterface $rawResponse) + public function getResponseContent(ResponseInterface $rawResponse): array { - $content = (string) $rawResponse->getBody(); + $content = $rawResponse->getContent(false); if (preg_match('/^callback\((.+)\);$/', $content, $matches)) { - $rawResponse = MessageFactoryDiscovery::find() - ->createResponse( - $rawResponse->getStatusCode(), - null, - $rawResponse->getHeaders(), - trim($matches[1]) - ) - ; + return json_decode(trim($matches[1]), true) ?: []; } return parent::getResponseContent($rawResponse); diff --git a/OAuth/ResourceOwner/SensioConnectResourceOwner.php b/OAuth/ResourceOwner/SensioConnectResourceOwner.php index 0dd45a263..ea391232c 100644 --- a/OAuth/ResourceOwner/SensioConnectResourceOwner.php +++ b/OAuth/ResourceOwner/SensioConnectResourceOwner.php @@ -11,8 +11,12 @@ namespace HWI\Bundle\OAuthBundle\OAuth\ResourceOwner; +use HWI\Bundle\OAuthBundle\OAuth\Exception\HttpTransportException; use HWI\Bundle\OAuthBundle\OAuth\Response\SensioConnectUserResponse; +use HWI\Bundle\OAuthBundle\Security\Core\Authentication\Token\OAuthToken; +use Symfony\Component\HttpClient\Exception\JsonException; use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; /** * SensioConnectResourceOwner. @@ -23,6 +27,30 @@ */ class SensioConnectResourceOwner extends GenericOAuth2ResourceOwner { + /** + * {@inheritdoc} + */ + public function getUserInformation(array $accessToken, array $extraParameters = []) + { + $content = $this->doGetUserInformationRequest( + $this->normalizeUrl( + $this->options['infos_url'], + array_merge([$this->options['attr_name'] => $accessToken['access_token']], $extraParameters) + ) + ); + + try { + $response = $this->getUserResponse(); + $response->setData($content->getContent(false)); + $response->setResourceOwner($this); + $response->setOAuthToken(new OAuthToken($accessToken)); + + return $response; + } catch (TransportExceptionInterface | JsonException $e) { + throw new HttpTransportException('Error while sending HTTP request', $this->getName(), $e->getCode(), $e); + } + } + /** * {@inheritdoc} */ diff --git a/OAuth/ResourceOwner/SinaWeiboResourceOwner.php b/OAuth/ResourceOwner/SinaWeiboResourceOwner.php index 656e90326..ebdd9f1e8 100644 --- a/OAuth/ResourceOwner/SinaWeiboResourceOwner.php +++ b/OAuth/ResourceOwner/SinaWeiboResourceOwner.php @@ -11,8 +11,11 @@ namespace HWI\Bundle\OAuthBundle\OAuth\ResourceOwner; +use HWI\Bundle\OAuthBundle\OAuth\Exception\HttpTransportException; use HWI\Bundle\OAuthBundle\Security\Core\Authentication\Token\OAuthToken; +use Symfony\Component\HttpClient\Exception\JsonException; use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; /** * @final since 1.4 @@ -39,14 +42,18 @@ public function getUserInformation(array $accessToken = null, array $extraParame 'uid' => $accessToken['uid'], ]); - $content = $this->doGetUserInformationRequest($url)->getBody(); + try { + $content = $this->doGetUserInformationRequest($url); - $response = $this->getUserResponse(); - $response->setData((string) $content); - $response->setResourceOwner($this); - $response->setOAuthToken(new OAuthToken($accessToken)); + $response = $this->getUserResponse(); + $response->setData($content->toArray(false)); + $response->setResourceOwner($this); + $response->setOAuthToken(new OAuthToken($accessToken)); - return $response; + return $response; + } catch (TransportExceptionInterface | JsonException $e) { + throw new HttpTransportException('Error while sending HTTP request', $this->getName(), $e->getCode(), $e); + } } /** diff --git a/OAuth/ResourceOwner/SpotifyResourceOwner.php b/OAuth/ResourceOwner/SpotifyResourceOwner.php index a841ea7b6..ef92eaa49 100644 --- a/OAuth/ResourceOwner/SpotifyResourceOwner.php +++ b/OAuth/ResourceOwner/SpotifyResourceOwner.php @@ -11,8 +11,11 @@ namespace HWI\Bundle\OAuthBundle\OAuth\ResourceOwner; +use HWI\Bundle\OAuthBundle\OAuth\Exception\HttpTransportException; use HWI\Bundle\OAuthBundle\Security\Core\Authentication\Token\OAuthToken; +use Symfony\Component\HttpClient\Exception\JsonException; use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; /** * @author Janne Savolainen @@ -40,14 +43,18 @@ public function getUserInformation(array $accessToken = null, array $extraParame 'access_token' => $accessToken['access_token'], ]); - $content = $this->doGetUserInformationRequest($url)->getBody(); + try { + $content = $this->doGetUserInformationRequest($url); - $response = $this->getUserResponse(); - $response->setData((string) $content); - $response->setResourceOwner($this); - $response->setOAuthToken(new OAuthToken($accessToken)); + $response = $this->getUserResponse(); + $response->setData($content->toArray(false)); + $response->setResourceOwner($this); + $response->setOAuthToken(new OAuthToken($accessToken)); - return $response; + return $response; + } catch (TransportExceptionInterface | JsonException $e) { + throw new HttpTransportException('Error while sending HTTP request', $this->getName(), $e->getCode(), $e); + } } /** diff --git a/OAuth/ResourceOwner/StackExchangeResourceOwner.php b/OAuth/ResourceOwner/StackExchangeResourceOwner.php index d300371ef..4ec161b9f 100644 --- a/OAuth/ResourceOwner/StackExchangeResourceOwner.php +++ b/OAuth/ResourceOwner/StackExchangeResourceOwner.php @@ -11,8 +11,11 @@ namespace HWI\Bundle\OAuthBundle\OAuth\ResourceOwner; +use HWI\Bundle\OAuthBundle\OAuth\Exception\HttpTransportException; use HWI\Bundle\OAuthBundle\Security\Core\Authentication\Token\OAuthToken; +use Symfony\Component\HttpClient\Exception\JsonException; use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; /** * StackExchangeResourceOwner. @@ -39,19 +42,23 @@ class StackExchangeResourceOwner extends GenericOAuth2ResourceOwner public function getUserInformation(array $accessToken, array $extraParameters = []) { $parameters = array_merge( - [$this->options['attr_name'] => $accessToken['access_token']], - ['site' => $this->options['site'], 'key' => $this->options['key']], - $extraParameters + [$this->options['attr_name'] => $accessToken['access_token']], + ['site' => $this->options['site'], 'key' => $this->options['key']], + $extraParameters ); - $content = $this->doGetUserInformationRequest($this->normalizeUrl($this->options['infos_url'], $parameters)); + try { + $content = $this->doGetUserInformationRequest($this->normalizeUrl($this->options['infos_url'], $parameters)); - $response = $this->getUserResponse(); - $response->setData((string) $content->getBody()); - $response->setResourceOwner($this); - $response->setOAuthToken(new OAuthToken($accessToken)); + $response = $this->getUserResponse(); + $response->setData($content->toArray(false)); + $response->setResourceOwner($this); + $response->setOAuthToken(new OAuthToken($accessToken)); - return $response; + return $response; + } catch (TransportExceptionInterface | JsonException $e) { + throw new HttpTransportException('Error while sending HTTP request', $this->getName(), $e->getCode(), $e); + } } /** diff --git a/OAuth/ResourceOwner/TraktResourceOwner.php b/OAuth/ResourceOwner/TraktResourceOwner.php index b9a585b93..c7aec8428 100644 --- a/OAuth/ResourceOwner/TraktResourceOwner.php +++ b/OAuth/ResourceOwner/TraktResourceOwner.php @@ -11,8 +11,11 @@ namespace HWI\Bundle\OAuthBundle\OAuth\ResourceOwner; +use HWI\Bundle\OAuthBundle\OAuth\Exception\HttpTransportException; use HWI\Bundle\OAuthBundle\Security\Core\Authentication\Token\OAuthToken; +use Symfony\Component\HttpClient\Exception\JsonException; use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; /** * TraktResourceOwner. @@ -45,12 +48,16 @@ public function getUserInformation(array $accessToken, array $extraParameters = 'trakt-api-version' => 2, ]); - $response = $this->getUserResponse(); - $response->setData((string) $content->getBody()); - $response->setResourceOwner($this); - $response->setOAuthToken(new OAuthToken($accessToken)); + try { + $response = $this->getUserResponse(); + $response->setData($content->toArray(false)); + $response->setResourceOwner($this); + $response->setOAuthToken(new OAuthToken($accessToken)); - return $response; + return $response; + } catch (TransportExceptionInterface | JsonException $e) { + throw new HttpTransportException('Error while sending HTTP request', $this->getName(), $e->getCode(), $e); + } } /** diff --git a/OAuth/ResourceOwner/VkontakteResourceOwner.php b/OAuth/ResourceOwner/VkontakteResourceOwner.php index cc3dbf576..d361fd2eb 100644 --- a/OAuth/ResourceOwner/VkontakteResourceOwner.php +++ b/OAuth/ResourceOwner/VkontakteResourceOwner.php @@ -11,9 +11,12 @@ namespace HWI\Bundle\OAuthBundle\OAuth\ResourceOwner; +use HWI\Bundle\OAuthBundle\OAuth\Exception\HttpTransportException; use HWI\Bundle\OAuthBundle\Security\Core\Authentication\Token\OAuthToken; +use Symfony\Component\HttpClient\Exception\JsonException; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; /** * VkontakteResourceOwner. @@ -51,25 +54,24 @@ public function getUserInformation(array $accessToken, array $extraParameters = 'v' => $this->options['api_version'], ]); - $content = $this->doGetUserInformationRequest($url); + try { + $response = $this->getUserResponse(); + $response->setResourceOwner($this); + $response->setOAuthToken(new OAuthToken($accessToken)); - $response = $this->getUserResponse(); - // This will translate string response into array - $response->setData((string) $content->getBody()); - $response->setResourceOwner($this); - $response->setOAuthToken(new OAuthToken($accessToken)); + $content = $this->doGetUserInformationRequest($url)->toArray(false); + $content['email'] = $accessToken['email'] ?? null; - $content = $response->getData(); - $content['email'] = $accessToken['email'] ?? null; - - $response->setData($content); + if (isset($content['response'][0]['screen_name'])) { + $content['response'][0]['nickname'] = $content['response'][0]['screen_name']; + } - if (!$response->getNickname() && isset($content['response'][0]['screen_name'])) { - $content['response'][0]['nickname'] = $content['response'][0]['screen_name']; $response->setData($content); - } - return $response; + return $response; + } catch (TransportExceptionInterface | JsonException $e) { + throw new HttpTransportException('Error while sending HTTP request', $this->getName(), $e->getCode(), $e); + } } /** diff --git a/Resources/config/http_client.xml b/Resources/config/http_client.xml deleted file mode 100644 index 334fb0539..000000000 --- a/Resources/config/http_client.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - diff --git a/Resources/config/util.xml b/Resources/config/util.xml index 2b0c6c67e..d8c4e9fbe 100644 --- a/Resources/config/util.xml +++ b/Resources/config/util.xml @@ -8,5 +8,7 @@ %hwi_oauth.target_path_domains_whitelist% + + - \ No newline at end of file + diff --git a/Resources/doc/1-setting_up_the_bundle.md b/Resources/doc/1-setting_up_the_bundle.md index c12b4709f..fab677a38 100644 --- a/Resources/doc/1-setting_up_the_bundle.md +++ b/Resources/doc/1-setting_up_the_bundle.md @@ -3,15 +3,9 @@ Step 1: Setting up the bundle ### A) Add HWIOAuthBundle to your project ```bash -composer require hwi/oauth-bundle symfony/http-client nyholm/psr7 guzzlehttp/promises php-http/httplug-bundle +composer require hwi/oauth-bundle ``` -Why `symfony/http-client` and its dependencies? We are decoupled from any HTTP messaging client thanks to [HTTPlug](http://httplug.io/). - -Why `php-http/httplug-bundle`? This is the official [Symfony integration](https://packagist.org/packages/php-http/httplug-bundle) of HTTPlug. -This makes it possible to provide the required HTTP client and message factory with ease. -The dependency is optional but you will have to [provide your own services](internals/configuring_the_http_client.md) if you don't set it up. - If you use a recent version of Symfony supporting [Symfony Flex](https://symfony.com/doc/current/quick_tour/flex_recipes.html), when prompted, accept to execute the recipes coming from the contrib repository. You'll see an error at the end of the process, it's intended. Continue straight to the second step: [configuring resource owners (Facebook, GitHub, Google, Windows Live and others](2-configuring_resource_owners.md) to fix it. @@ -22,21 +16,17 @@ If you use an old version of Symfony, follow the instructions provided in the ne Enable the bundle in the kernel: ```php -// app/AppKernel.php +// src/Kernel.php public function registerBundles() { $bundles = [ // ... - new Http\HttplugBundle\HttplugBundle(), // If you require the php-http/httplug-bundle package. new HWI\Bundle\OAuthBundle\HWIOAuthBundle(), ]; } ``` -If you don't use `HttplugBundle`, you will have to -[configure your own client service](internals/configuring_the_http_client.md). - ### C) Import the routing Import the `redirect.xml` and `login.xml` routing files in your own routing file. diff --git a/Resources/doc/index.md b/Resources/doc/index.md index ec536ac07..0f5af7b02 100644 --- a/Resources/doc/index.md +++ b/Resources/doc/index.md @@ -14,7 +14,6 @@ Getting Started With HWIOAuthBundle ## Internals - [Response object & "paths" explanation](internals/response_object_and_paths.md) -- [Configuring the HTTP Client](internals/configuring_the_http_client.md) - [Reference configuration](internals/reference_configuration.md) - [Configuring an external Resource Owner](internals/external_resource_owner.md) diff --git a/Resources/doc/internals/configuring_the_http_client.md b/Resources/doc/internals/configuring_the_http_client.md deleted file mode 100644 index 3ba62dd18..000000000 --- a/Resources/doc/internals/configuring_the_http_client.md +++ /dev/null @@ -1,121 +0,0 @@ -Internals: Configuring the HTTP Client -====================================== -As you already noticed, HWIOAuthBundle depends on [Httplug](http://httplug.io) -a lightweight library for issuing HTTP requests. - -The HTTP client configuration does now directly rely on HttplugBundle if installed. -You can see all configuration options and plugins on the -[vendor documentation](http://docs.php-http.org/en/latest/integrations/symfony-bundle.html#usage). - -If you want to use a different Httplug client/factory than the default one(s), you can specify it: - -```yaml -# app/config/config.yml - -httplug: - clients: - default: - factory: 'httplug.factory.curl' - hwi_special: - factory: 'httplug.factory.guzzle6' - -hwi_oauth: - http: - client: httplug.client.hwi_special # Default to httplug.client.default - factory: httplug.stream_factory # Default to httplug.message_factory.default -``` - -If you don't want to use the HTTPlug Bundle, the client and factory services **must be specified**. - -## Differences since 0.6+ version - -On v0.5 and below, you were able to configure your HTTP client like that: - -```yaml -# app/config/config.yml - -hwi_oauth: - http_client: - timeout: 10 # Time in seconds, after library will shutdown request, by default: 5 - verify_peer: false # Setting allowing you to turn off SSL verification, by default: true - ignore_errors: false # Setting allowing you to easier debug request errors, by default: true - max_redirects: 1 # Number of HTTP redirection request after which library will shutdown request, - # by default: 5 - proxy: "example.com:8080" # String with proxy configuration for cURL connections, ignored by default. - # "" -> don't set proxy and will use proxy system - # "example.com:8080" -> set custom proxy - # ":" -> disable proxy usage, ignoring also proxy system and ENVIRONMENT variables -``` - -As we now use Httplug, the http configuration does not rely on our bundle anymore. -Still, you can always configure Guzzle6 (if you use this client) thanks to the -[Guzzle6 adapter](http://docs.php-http.org/en/latest/clients/guzzle6-adapter.html). - -### Configure with HttplugBundle - -You need to [install and configure](../1-setting_up_the_bundle.md) the HttplugBundle first. - -Then apply your configuration trough `httplug` section: - -```yaml -# app/config/config.yml - -httplug: - clients: - default: - factory: 'httplug.factory.curl' - hwi_special: - factory: 'httplug.factory.guzzle6' - config: # You pass here the Guzzle configuration, exactly like before. - timeout: 10 - verify: false - max_redirects: 1 - ignore_errors: false - proxy: "example.com:8080" - -hwi_oauth: - http: - client: httplug.client.hwi_special # Then you specify the special service to use. -``` - -And voilĂ ! You now have your custom Guzzle 6 service with the same configuration. - -### Configure manually - -If you don't want to use HttplugBundle, you can still configure Guzzle quite easily. - -First, you have to declare your Guzzle 6 adapter and message factory as services, with your custom configuration: - -```yaml -# app/config/services.yml - -services: - guzzle_client.hwi_special: - class: Http\Adapter\Guzzle6\Client - factory: - - Http\Adapter\Guzzle6\Client - - createWithConfig - arguments: - - timeout: 10 - verify_peer: false - max_redirects: 1 - ignore_errors: false - proxy: "example.com:8080" - guzzle_client.message_factory: - class: Http\Message\MessageFactory\GuzzleMessageFactory -``` - -Then configure the bundle to use the service created above: - -```yaml -# app/config/config.yml - -hwi_oauth: - http: - client: guzzle_client.hwi_special - message_factory: guzzle_client.message_factory -``` - -That's it. Now your custom Httplug Guzzle adapter service is used. - -[Return to the index.](../index.md) diff --git a/Resources/doc/resource_owners/fiware.md b/Resources/doc/resource_owners/fiware.md index c0c5d161b..73e0a143d 100644 --- a/Resources/doc/resource_owners/fiware.md +++ b/Resources/doc/resource_owners/fiware.md @@ -17,15 +17,6 @@ If you are using the FI-WARE Lab Cloud you will have to increase the timeout for ```yaml # app/config/config.yml - -# With php-http/httplug-bundle -httplug: - clients: - default: - factory: 'httplug.factory.guzzle6' - config: - timeout: 15 - hwi_oauth: resource_owners: any_name: diff --git a/Tests/App/config.yml b/Tests/App/config.yml index fe02a02f7..2f22fb146 100644 --- a/Tests/App/config.yml +++ b/Tests/App/config.yml @@ -59,11 +59,10 @@ services: HWI\Bundle\OAuthBundle\Tests\App\Form\RegistrationFormType: ~ HWI\Bundle\OAuthBundle\Tests\App\UserProvider: ~ - Psr\Http\Client\ClientInterface: + # Must be "public" to allow replacing it with mock client + hwi_oauth.http_client: + class: Symfony\Contracts\HttpClient\HttpClientInterface public: true - synthetic: true - - Http\Message\MessageFactory\GuzzleMessageFactory: doctrine: dbal: @@ -79,9 +78,6 @@ hwi_oauth: account_connector: HWI\Bundle\OAuthBundle\Tests\App\UserProvider registration_form_handler: HWI\Bundle\OAuthBundle\Tests\App\Form\RegistrationFormHandler registration_form: HWI\Bundle\OAuthBundle\Tests\App\Form\RegistrationFormType - http: - client: Psr\Http\Client\ClientInterface - message_factory: Http\Message\MessageFactory\GuzzleMessageFactory firewall_names: [main] resource_owners: google: diff --git a/Tests/DependencyInjection/HWIOAuthExtensionTest.php b/Tests/DependencyInjection/HWIOAuthExtensionTest.php index 37fb10473..64bd7d836 100644 --- a/Tests/DependencyInjection/HWIOAuthExtensionTest.php +++ b/Tests/DependencyInjection/HWIOAuthExtensionTest.php @@ -11,8 +11,6 @@ namespace HWI\Bundle\OAuthBundle\Tests\DependencyInjection; -use Http\Client\Common\HttpMethodsClient; -use Http\HttplugBundle\HttplugBundle; use HWI\Bundle\OAuthBundle\DependencyInjection\HWIOAuthExtension; use HWI\Bundle\OAuthBundle\Tests\Fixtures\MyCustomProvider; use PHPUnit\Framework\TestCase; @@ -36,10 +34,6 @@ protected function setUp(): void parent::setUp(); $this->containerBuilder = new ContainerBuilder(); - - $this->containerBuilder->setParameter('kernel.bundles', [ - 'HttplugBundle' => new HttplugBundle(), - ]); } protected function tearDown(): void @@ -47,16 +41,6 @@ protected function tearDown(): void unset($this->containerBuilder); } - public function testHttpClientExists() - { - $this->createEmptyConfiguration(); - - $this->assertHasDefinition( - 'hwi_oauth.http_client', - HttpMethodsClient::class - ); - } - public function testConfigurationThrowsExceptionUnlessFirewallNameSet() { $this->expectException(InvalidConfigurationException::class); @@ -669,21 +653,12 @@ private function assertAlias(string $value, string $key): void $this->assertEquals($value, (string) $this->containerBuilder->getAlias($key), sprintf('%s alias is correct', $key)); } - private function assertParameter($value, string $key) + private function assertParameter($value, string $key): void { $this->assertEquals($value, $this->containerBuilder->getParameter($key), sprintf('%s parameter is correct', $key)); } - private function assertHasDefinition(string $id, ?string $className = null) - { - $this->assertTrue(($this->containerBuilder->hasDefinition($id) ?: $this->containerBuilder->hasAlias($id))); - - if (null !== $className) { - $this->assertSame($this->containerBuilder->findDefinition($id)->getClass(), $className); - } - } - - private function assertNotHasDefinition(string $id) + private function assertNotHasDefinition(string $id): void { $this->assertFalse($this->containerBuilder->hasDefinition($id) || $this->containerBuilder->hasAlias($id)); } diff --git a/Tests/Functional/Controller/ConnectControllerTest.php b/Tests/Functional/Controller/ConnectControllerTest.php index 8429ef61b..69a16829f 100644 --- a/Tests/Functional/Controller/ConnectControllerTest.php +++ b/Tests/Functional/Controller/ConnectControllerTest.php @@ -18,11 +18,11 @@ use HWI\Bundle\OAuthBundle\Security\Core\Exception\AccountNotLinkedException; use HWI\Bundle\OAuthBundle\Tests\App\AppKernel; use HWI\Bundle\OAuthBundle\Tests\Fixtures\CustomOAuthToken; -use Psr\Http\Client\ClientInterface; -use Psr\Http\Message\ResponseInterface; use Symfony\Bundle\FrameworkBundle\KernelBrowser; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Symfony\Component\BrowserKit\Cookie; +use Symfony\Component\HttpClient\MockHttpClient; +use Symfony\Component\HttpClient\Response\MockResponse; use Symfony\Component\HttpFoundation\Exception\SessionNotFoundException; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Session\SessionInterface; @@ -41,19 +41,20 @@ public static function getKernelClass(): string public function testRegistration(): void { - $mockResponse = $this->createMock(ResponseInterface::class); - $mockResponse->method('getBody') - ->willReturn(json_encode(['access_token' => 'valid-access-token'])); - - $httpClient = $this->createMock(ClientInterface::class); - $httpClient->method('sendRequest') - ->withAnyParameters() - ->willReturn($mockResponse); + $httpClient = new MockHttpClient( + function ($method, $url, $options) { + return new MockResponse( + '{"access_token":"valid-access-token"}', + [ + 'response_headers' => ['content-type' => 'application/json'], + ] + ); + } + ); $client = static::createClient(); $client->disableReboot(); - - self::$container->set(ClientInterface::class, $httpClient); + $client->getContainer()->set('hwi_oauth.http_client', $httpClient); $key = 1; $exception = new AccountNotLinkedException(); @@ -88,19 +89,20 @@ public function testRegistration(): void public function testConnectService(): void { - $response = $this->createMock(ResponseInterface::class); - $response->method('getBody') - ->willReturn(json_encode(['name' => 'foo'])); - - $httpClient = $this->createMock(ClientInterface::class); - $httpClient->method('sendRequest') - ->withAnyParameters() - ->willReturn($response); + $httpClient = new MockHttpClient( + function ($method, $url, $options) { + return new MockResponse( + '{"name":"foo"}', + [ + 'response_headers' => ['content-type' => 'application/json'], + ] + ); + } + ); $client = static::createClient(); $client->disableReboot(); - - self::$container->set(ClientInterface::class, $httpClient); + $client->getContainer()->set('hwi_oauth.http_client', $httpClient); $this->createDatabase(); diff --git a/Tests/Functional/Controller/LoginControllerTest.php b/Tests/Functional/Controller/LoginControllerTest.php index 6b9d24d32..ab1ae6288 100644 --- a/Tests/Functional/Controller/LoginControllerTest.php +++ b/Tests/Functional/Controller/LoginControllerTest.php @@ -15,22 +15,22 @@ use HWI\Bundle\OAuthBundle\Security\Core\Exception\AccountNotLinkedException; use HWI\Bundle\OAuthBundle\Tests\Fixtures\CustomOAuthToken; -use Psr\Http\Client\ClientInterface; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Symfony\Component\BrowserKit\Cookie; +use Symfony\Component\HttpClient\MockHttpClient; use Symfony\Component\HttpFoundation\Exception\SessionNotFoundException; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; use Symfony\Component\Security\Core\Security; +use Symfony\Contracts\HttpClient\HttpClientInterface; final class LoginControllerTest extends WebTestCase { public function testLoginPage(): void { $client = static::createClient(); - - self::$container->set(ClientInterface::class, $this->createMock(ClientInterface::class)); + $client->getContainer()->set('hwi_oauth.http_client', $this->createMock(HttpClientInterface::class)); $crawler = $client->request('GET', '/login_hwi/'); @@ -57,11 +57,12 @@ public function testRedirectingToRegistrationFormWithError(): void public function testLoginPageWithError(): void { - $client = static::createClient(); + $httpClient = new MockHttpClient(); - self::$container->set(ClientInterface::class, $this->createMock(ClientInterface::class)); + $client = static::createClient(); + $client->getContainer()->set('hwi_oauth.http_client', $httpClient); - $session = $this->getSession(); + $session = $client->getContainer()->get('session'); $this->logIn($client, $session); $exception = new UsernameNotFoundException(); diff --git a/Tests/Functional/IntegrationTest.php b/Tests/Functional/IntegrationTest.php index 8f525ec32..9ec7f2bde 100644 --- a/Tests/Functional/IntegrationTest.php +++ b/Tests/Functional/IntegrationTest.php @@ -13,9 +13,9 @@ namespace HWI\Bundle\OAuthBundle\Tests\Functional; -use Psr\Http\Client\ClientInterface; -use Psr\Http\Message\ResponseInterface; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; +use Symfony\Component\HttpClient\MockHttpClient; +use Symfony\Component\HttpClient\Response\MockResponse; use Symfony\Component\HttpFoundation\Response; class IntegrationTest extends WebTestCase @@ -38,8 +38,7 @@ public function testRequestRedirect(): void $this->assertSame(200, $response->getStatusCode(), 'No landing, got redirect to '.$response->headers->get('Location')); $client->disableReboot(); - - self::$container->set(ClientInterface::class, $this->createMock(ClientInterface::class)); + $client->getContainer()->set('hwi_oauth.http_client', new MockHttpClient()); $client->click($crawler->selectLink('Login')->link()); @@ -68,19 +67,20 @@ public function testRequestCheck(): void 'prompt' => 'none', ]); - $response = $this->createMock(ResponseInterface::class); - $response->method('getBody') - ->willReturn(json_encode(['access_token' => 'valid-access-token'])); - - $httpClient = $this->createMock(ClientInterface::class); - $httpClient->method('sendRequest') - ->withAnyParameters() - ->willReturn($response); + $httpClient = new MockHttpClient( + function ($method, $url, $options) { + return new MockResponse( + '{"access_token":"valid-access-token"}', + [ + 'response_headers' => ['content-type' => 'application/json'], + ] + ); + } + ); $client = static::createClient(); $client->disableReboot(); - - self::$container->set(ClientInterface::class, $httpClient); + $client->getContainer()->set('hwi_oauth.http_client', $httpClient); $client->request('GET', $redirectLoginFromService); diff --git a/Tests/OAuth/ResourceOwner/AmazonResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/AmazonResourceOwnerTest.php index 22f408c71..70cf09324 100644 --- a/Tests/OAuth/ResourceOwner/AmazonResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/AmazonResourceOwnerTest.php @@ -15,7 +15,7 @@ class AmazonResourceOwnerTest extends GenericOAuth2ResourceOwnerTest { - protected $resourceOwnerClass = AmazonResourceOwner::class; + protected string $resourceOwnerClass = AmazonResourceOwner::class; protected $userResponse = <<createResourceOwner(); + $request = new Request(['test' => 'test']); - $this->assertFalse($this->resourceOwner->handles($request)); + $this->assertFalse($resourceOwner->handles($request)); $request = new Request(['code' => 'test']); - $this->assertFalse($this->resourceOwner->handles($request)); + $this->assertFalse($resourceOwner->handles($request)); $request = new Request([], ['code' => 'test']); - $this->assertTrue($this->resourceOwner->handles($request)); + $this->assertTrue($resourceOwner->handles($request)); $request = new Request([], ['code' => 'test', 'test' => 'test']); - $this->assertTrue($this->resourceOwner->handles($request)); + $this->assertTrue($resourceOwner->handles($request)); } public function testGetAccessTokenFailedResponse() { - $this->expectException(\Symfony\Component\Security\Core\Exception\AuthenticationException::class); + $this->expectException(AuthenticationException::class); - $this->mockHttpClient('{"error": {"message": "invalid"}}', 'application/json; charset=utf-8'); $request = new Request(['code' => 'code']); - $this->resourceOwner->getAccessToken($request, 'http://redirect.to/'); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse('{"error": {"message": "invalid"}}', 'application/json; charset=utf-8'), + ] + ); + $resourceOwner->getAccessToken($request, 'http://redirect.to/'); } public function testDisplayPopup() { - $resourceOwner = $this->createResourceOwner($this->resourceOwnerName, ['display' => 'popup']); + $resourceOwner = $this->createResourceOwner(['display' => 'popup']); $this->assertEquals( $this->options['authorization_url'].'&response_type=code&client_id=clientid&scope=name+email&state=eyJzdGF0ZSI6InJhbmRvbSJ9&redirect_uri=http%3A%2F%2Fredirect.to%2F&response_mode=form_post', @@ -74,31 +84,19 @@ public function testDisplayPopup() ); } - public function testRevokeToken() - { - $this->httpResponseHttpCode = 200; - $this->mockHttpClient('{"access_token": "bar"}', 'application/json'); - - $this->assertTrue($this->resourceOwner->revokeToken('token')); - } - - public function testRevokeTokenFails() - { - $this->httpResponseHttpCode = 401; - $this->mockHttpClient('{"access_token": "bar"}', 'application/json'); - - $this->assertFalse($this->resourceOwner->revokeToken('token')); - } - public function testCustomResponseClass() { $class = CustomUserResponse::class; - $resourceOwner = $this->createResourceOwner($this->resourceOwnerName, ['user_response_class' => $class]); - - $token = '.'.base64_encode($this->userResponse); + $resourceOwner = $this->createResourceOwner( + ['user_response_class' => $class], + [], + [ + $this->createMockResponse($this->userResponse), + ] + ); /** @var CustomUserResponse $userResponse */ - $userResponse = $resourceOwner->getUserInformation(['access_token' => 'token', 'id_token' => $token]); + $userResponse = $resourceOwner->getUserInformation(['access_token' => 'token', 'id_token' => '.'.base64_encode($this->userResponse)]); $this->assertInstanceOf($class, $userResponse); $this->assertEquals('foo666', $userResponse->getUsername()); @@ -114,10 +112,18 @@ public function testGetUserInformation() { $token = '.'.base64_encode($this->userResponse); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse($this->userResponse), + ] + ); + /** - * @var \HWI\Bundle\OAuthBundle\OAuth\Response\AbstractUserResponse + * @var AbstractUserResponse */ - $userResponse = $this->resourceOwner->getUserInformation([ + $userResponse = $resourceOwner->getUserInformation([ 'access_token' => 'token', 'id_token' => $token, 'firstName' => 'Test', @@ -132,7 +138,7 @@ public function testGetUserInformation() $this->assertNull($userResponse->getRefreshToken()); $this->assertNull($userResponse->getExpiresIn()); - $userResponse = $this->resourceOwner->getUserInformation(['access_token' => 'token', 'id_token' => $token]); + $userResponse = $resourceOwner->getUserInformation(['access_token' => 'token', 'id_token' => $token]); $this->assertEquals('1', $userResponse->getUsername()); $this->assertEquals('localhost@gmail.com', $userResponse->getEmail()); $this->assertEquals('token', $userResponse->getAccessToken()); @@ -144,13 +150,16 @@ public function testGetUserInformation() public function testGetUserInformationFailure() { - $exception = new \Exception('Undefined index id_token'); - - try { - $this->resourceOwner->getUserInformation(['access_token' => 'token']); - $this->fail('An exception should have been raised'); - } catch (\Exception $e) { - $this->assertSame($exception->getMessage(), $e->getMessage()); - } + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Undefined index id_token'); + + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse($this->userResponse), + ] + ); + $resourceOwner->getUserInformation(['access_token' => 'token']); } } diff --git a/Tests/OAuth/ResourceOwner/AsanaResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/AsanaResourceOwnerTest.php index b5a2f547f..e93f4c054 100644 --- a/Tests/OAuth/ResourceOwner/AsanaResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/AsanaResourceOwnerTest.php @@ -15,7 +15,7 @@ class AsanaResourceOwnerTest extends GenericOAuth2ResourceOwnerTest { - protected $resourceOwnerClass = AsanaResourceOwner::class; + protected string $resourceOwnerClass = AsanaResourceOwner::class; protected $userResponse = <<mockHttpClientSendRequestWithRequestAssertions( - $expectedRequestUri, - $expectedRequestMethod, - $expectedAuthorizationHeader, - $expectedAuth0ClientRequestHeader, - $expectedRequestBodyContents - ); - - $request = new Request(['code' => 'somecode']); - - $this->resourceOwner->getAccessToken($request, 'http://redirect.to/'); - } - - /** - * Tests if {@see Auth0ResourceOwner::getUserInformation} would send the expected request to Auth0. - */ - public function testGetUserInformationSendsExpectedRequest(): void - { - $expectedRequestUri = 'https://example.oauth0.com/userinfo'; - $expectedRequestMethod = 'GET'; - $expectedAuthorizationHeader = [ - 'Bearer token', - ]; - $expectedAuth0ClientRequestHeader = [ - 'eyJuYW1lIjoiSFdJT0F1dGhCdW5kbGUiLCJ2ZXJzaW9uIjoidW5rbm93biIsImVudmlyb25tZW50Ijp7Im5hbWUiOiJQSFAiLCJ2ZXJzaW9uIjoiRkFLRV9QSFBfVkVSU0lPTl9GT1JfVEVTVFMifX0=', - ]; - - $this->mockHttpClientSendRequestWithRequestAssertions( - $expectedRequestUri, - $expectedRequestMethod, - $expectedAuthorizationHeader, - $expectedAuth0ClientRequestHeader, - '' - ); - - $this->resourceOwner->getUserInformation($this->tokenData); - } - - protected function setUpResourceOwner($name, HttpUtils $httpUtils, array $options) + protected function setUpResourceOwner(string $name, HttpUtils $httpUtils, array $options, array $responses): ResourceOwnerInterface { $auth0Client = base64_encode(json_encode([ 'name' => 'HWIOAuthBundle', @@ -114,67 +59,20 @@ protected function setUpResourceOwner($name, HttpUtils $httpUtils, array $option ], ])); - $options = array_merge( - $options, - [ - 'authorization_url' => '{base_url}/authorize?auth0Client='.$auth0Client, - 'access_token_url' => '{base_url}/oauth/token', - 'infos_url' => '{base_url}/userinfo', - 'auth0_client' => $auth0Client, - 'base_url' => 'https://example.oauth0.com', - ] + return parent::setUpResourceOwner( + $name, + $httpUtils, + array_merge( + $options, + [ + 'authorization_url' => '{base_url}/authorize?auth0Client='.$auth0Client, + 'access_token_url' => '{base_url}/oauth/token', + 'infos_url' => '{base_url}/userinfo', + 'auth0_client' => $auth0Client, + 'base_url' => 'https://example.oauth0.com', + ] + ), + $responses ); - - return parent::setUpResourceOwner($name, $httpUtils, $options); - } - - /** - * Mocks the {@see HttpClient::sendRequest} method with assertions on the request. - */ - private function mockHttpClientSendRequestWithRequestAssertions( - string $expectedRequestUri, - string $expectedRequestMethod, - array $expectedAuthorizationHeader, - array $expectedAuth0ClientRequestHeader, - string $expectedRequestBodyContents - ): void { - $this->httpClient->expects($this->once()) - ->method('sendRequest') - ->with( - $this->callback(function (RequestInterface $request) use ($expectedRequestUri, $expectedRequestMethod, $expectedAuthorizationHeader, $expectedAuth0ClientRequestHeader, $expectedRequestBodyContents) { - $this->assertEquals($expectedRequestUri, $request->getUri()); - $this->assertSame( - $expectedRequestMethod, - $request->getMethod(), - 'The request should be send with the expected request method.' - ); - $this->assertSame( - $expectedAuthorizationHeader, - $request->getHeader('Authorization'), - 'The Authorization header should be added to the request with the Base64 encoded client_id and client_secret or with a bearer token.' - ); - $this->assertSame( - $expectedAuth0ClientRequestHeader, - $request->getHeader('Auth0-Client'), - 'The Auth0-Client header should be added with the expected Base64 encoded version information.' - ); - $this->assertSame( - $expectedRequestBodyContents, - $request->getBody()->getContents(), - 'The request body should contain the expected content / variables.' - ); - - return true; - }) - ) - ->willReturnCallback(function (RequestInterface $request) { - return MessageFactoryDiscovery::find() - ->createResponse( - $this->httpResponseHttpCode, - null, - $request->withAddedHeader('Content-Type', 'application/json')->getHeaders(), - '{"access_token": "code"}' - ); - }); } } diff --git a/Tests/OAuth/ResourceOwner/AzureResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/AzureResourceOwnerTest.php index 69dba4651..a828d46f5 100644 --- a/Tests/OAuth/ResourceOwner/AzureResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/AzureResourceOwnerTest.php @@ -11,14 +11,14 @@ namespace HWI\Bundle\OAuthBundle\Tests\OAuth\ResourceOwner; -use Http\Client\Exception\TransferException; use HWI\Bundle\OAuthBundle\OAuth\Exception\HttpTransportException; use HWI\Bundle\OAuthBundle\OAuth\ResourceOwner\AzureResourceOwner; +use HWI\Bundle\OAuthBundle\OAuth\Response\AbstractUserResponse; use HWI\Bundle\OAuthBundle\Tests\Fixtures\CustomUserResponse; class AzureResourceOwnerTest extends GenericOAuth2ResourceOwnerTest { - protected $resourceOwnerClass = AzureResourceOwner::class; + protected string $resourceOwnerClass = AzureResourceOwner::class; protected $csrf = true; protected $userResponse = <<userResponse); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse($this->userResponse), + ] + ); + /** - * @var \HWI\Bundle\OAuthBundle\OAuth\Response\AbstractUserResponse + * @var AbstractUserResponse */ - $userResponse = $this->resourceOwner->getUserInformation([ + $userResponse = $resourceOwner->getUserInformation([ 'access_token' => 'token', - 'id_token' => $token, + 'id_token' => '.'.base64_encode($this->userResponse), ]); $this->assertEquals('1', $userResponse->getUsername()); @@ -65,16 +72,20 @@ public function testGetUserInformation() public function testCustomResponseClass() { $class = CustomUserResponse::class; - $resourceOwner = $this->createResourceOwner($this->resourceOwnerName, ['user_response_class' => $class]); - - $token = '.'.base64_encode($this->userResponse); + $resourceOwner = $this->createResourceOwner( + ['user_response_class' => $class], + [], + [ + $this->createMockResponse($this->userResponse), + ] + ); /** - * @var \HWI\Bundle\OAuthBundle\OAuth\Response\AbstractUserResponse + * @var AbstractUserResponse */ $userResponse = $resourceOwner->getUserInformation([ 'access_token' => 'token', - 'id_token' => $token, + 'id_token' => '.'.base64_encode($this->userResponse), ]); $this->assertInstanceOf($class, $userResponse); @@ -89,19 +100,15 @@ public function testCustomResponseClass() public function testGetUserInformationFailure() { - $exception = new TransferException(); - - $this->httpClient->expects($this->once()) - ->method('sendRequest') - ->will($this->throwException($exception)); - - $token = '.'.base64_encode($this->userResponse); - - try { - $this->resourceOwner->getUserInformation(['access_token' => 'token', 'id_token' => $token]); - $this->fail('An exception should have been raised'); - } catch (HttpTransportException $e) { - $this->assertSame($exception, $e->getPrevious()); - } + $this->expectException(HttpTransportException::class); + + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse('', null, 401), + ] + ); + $resourceOwner->getUserInformation(['access_token' => 'token', 'id_token' => '.'.base64_encode($this->userResponse)]); } } diff --git a/Tests/OAuth/ResourceOwner/BitbucketResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/BitbucketResourceOwnerTest.php index e03699426..1a754b143 100644 --- a/Tests/OAuth/ResourceOwner/BitbucketResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/BitbucketResourceOwnerTest.php @@ -15,7 +15,7 @@ class BitbucketResourceOwnerTest extends GenericOAuth1ResourceOwnerTest { - protected $resourceOwnerClass = BitbucketResourceOwner::class; + protected string $resourceOwnerClass = BitbucketResourceOwner::class; protected $userResponse = <<mockHttpClient($this->userResponse, 'application/json; charset=utf-8'); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse($this->userResponse, 'application/json; charset=utf-8'), + ] + ); $accessToken = ['oauth_token' => 'token', 'oauth_token_secret' => 'secret']; - $userResponse = $this->resourceOwner->getUserInformation($accessToken); + $userResponse = $resourceOwner->getUserInformation($accessToken); $this->assertEquals('1', $userResponse->getUsername()); $this->assertEquals('1', $userResponse->getNickname()); diff --git a/Tests/OAuth/ResourceOwner/BitlyResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/BitlyResourceOwnerTest.php index 75e1879bd..328ea1bbb 100644 --- a/Tests/OAuth/ResourceOwner/BitlyResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/BitlyResourceOwnerTest.php @@ -15,7 +15,7 @@ class BitlyResourceOwnerTest extends GenericOAuth2ResourceOwnerTest { - protected $resourceOwnerClass = BitlyResourceOwner::class; + protected string $resourceOwnerClass = BitlyResourceOwner::class; protected $userResponse = <<httpResponseHttpCode = 200; - $this->mockHttpClient('{"access_token": "bar"}', 'application/json'); - - $this->assertTrue($this->resourceOwner->revokeToken('token')); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse('{"access_token": "bar"}', 'application/json'), + ] + ); + + $this->assertTrue($resourceOwner->revokeToken('token')); } public function testRevokeTokenFails() { - $this->httpResponseHttpCode = 401; - $this->mockHttpClient('{"access_token": "bar"}', 'application/json'); - - $this->assertFalse($this->resourceOwner->revokeToken('token')); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse('{"access_token": "bar"}', 'application/json', 401), + ] + ); + + $this->assertFalse($resourceOwner->revokeToken('token')); } } diff --git a/Tests/OAuth/ResourceOwner/BufferAppResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/BufferAppResourceOwnerTest.php index 58d6177aa..259cb4da2 100644 --- a/Tests/OAuth/ResourceOwner/BufferAppResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/BufferAppResourceOwnerTest.php @@ -12,10 +12,12 @@ namespace HWI\Bundle\OAuthBundle\Tests\OAuth\ResourceOwner; use HWI\Bundle\OAuthBundle\OAuth\ResourceOwner\BufferAppResourceOwner; +use HWI\Bundle\OAuthBundle\OAuth\Response\AbstractUserResponse; +use Symfony\Component\Security\Core\Exception\AuthenticationException; class BufferAppResourceOwnerTest extends GenericOAuth2ResourceOwnerTest { - protected $resourceOwnerClass = BufferAppResourceOwner::class; + protected string $resourceOwnerClass = BufferAppResourceOwner::class; protected $userResponse = <<mockHttpClient($this->userResponse, 'application/json; charset=utf-8'); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse($this->userResponse, 'application/json; charset=utf-8'), + ] + ); /** - * @var \HWI\Bundle\OAuthBundle\OAuth\Response\AbstractUserResponse + * @var AbstractUserResponse */ - $userResponse = $this->resourceOwner->getUserInformation(['access_token' => 'token']); + $userResponse = $resourceOwner->getUserInformation(['access_token' => 'token']); $this->assertEquals('4f0c0a06512f7ef214000000', $userResponse->getUsername()); $this->assertEquals('4f0c0a06512f7ef214000000', $userResponse->getNickname()); @@ -47,4 +55,19 @@ public function testGetUserInformation() $this->assertNull($userResponse->getRefreshToken()); $this->assertNull($userResponse->getExpiresIn()); } + + public function testGetUserInformationFailure() + { + $this->expectException(AuthenticationException::class); + + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse('invalid', 'application/json; charset=utf-8', 401), + ] + ); + + $resourceOwner->getUserInformation($this->tokenData); + } } diff --git a/Tests/OAuth/ResourceOwner/CleverResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/CleverResourceOwnerTest.php index d2cf88bb0..99dc96d1f 100644 --- a/Tests/OAuth/ResourceOwner/CleverResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/CleverResourceOwnerTest.php @@ -14,17 +14,9 @@ use HWI\Bundle\OAuthBundle\OAuth\ResourceOwner\CleverResourceOwner; /** - * CleverResourceOwnerTest. - * * @author Matt Farmer */ class CleverResourceOwnerTest extends GenericOAuth2ResourceOwnerTest { - protected $resourceOwnerClass = CleverResourceOwner::class; - - protected function setUp(): void - { - $this->resourceOwnerName = 'CleverResourceOwner'; - $this->resourceOwner = $this->createResourceOwner($this->resourceOwnerName); - } + protected string $resourceOwnerClass = CleverResourceOwner::class; } diff --git a/Tests/OAuth/ResourceOwner/DailymotionResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/DailymotionResourceOwnerTest.php index d180dea73..cbbbfd3da 100644 --- a/Tests/OAuth/ResourceOwner/DailymotionResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/DailymotionResourceOwnerTest.php @@ -15,7 +15,7 @@ class DailymotionResourceOwnerTest extends GenericOAuth2ResourceOwnerTest { - protected $resourceOwnerClass = DailymotionResourceOwner::class; + protected string $resourceOwnerClass = DailymotionResourceOwner::class; protected $userResponse = <<createResourceOwner($this->resourceOwnerName, ['display' => 'popup']); + $resourceOwner = $this->createResourceOwner(['display' => 'popup']); $this->assertEquals( $this->options['authorization_url'].'&response_type=code&client_id=clientid&state=eyJzdGF0ZSI6InJhbmRvbSJ9&redirect_uri=http%3A%2F%2Fredirect.to%2F&display=popup', @@ -43,6 +43,6 @@ public function testInvalidDisplayOptionValueThrowsException() { $this->expectException(\Symfony\Component\OptionsResolver\Exception\ExceptionInterface::class); - $this->createResourceOwner($this->resourceOwnerName, ['display' => 'invalid']); + $this->createResourceOwner(['display' => 'invalid']); } } diff --git a/Tests/OAuth/ResourceOwner/DeezerResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/DeezerResourceOwnerTest.php index 3131ba249..773c91601 100644 --- a/Tests/OAuth/ResourceOwner/DeezerResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/DeezerResourceOwnerTest.php @@ -18,7 +18,7 @@ */ class DeezerResourceOwnerTest extends GenericOAuth2ResourceOwnerTest { - protected $resourceOwnerClass = DeezerResourceOwner::class; + protected string $resourceOwnerClass = DeezerResourceOwner::class; protected $userResponse = <<mockHttpClient($this->userResponse); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse($this->userResponse), + ] + ); - $userResponse = $this->resourceOwner->getUserInformation(['access_token' => 'token']); + $userResponse = $resourceOwner->getUserInformation(['access_token' => 'token']); $this->assertEquals('passkey', $userResponse->getNickname()); $this->assertEquals('Kieu', $userResponse->getRealName()); diff --git a/Tests/OAuth/ResourceOwner/DeviantartResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/DeviantartResourceOwnerTest.php index 47fe1e30b..ae9cffc56 100644 --- a/Tests/OAuth/ResourceOwner/DeviantartResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/DeviantartResourceOwnerTest.php @@ -12,10 +12,11 @@ namespace HWI\Bundle\OAuthBundle\Tests\OAuth\ResourceOwner; use HWI\Bundle\OAuthBundle\OAuth\ResourceOwner\DeviantartResourceOwner; +use HWI\Bundle\OAuthBundle\OAuth\Response\AbstractUserResponse; class DeviantartResourceOwnerTest extends GenericOAuth2ResourceOwnerTest { - protected $resourceOwnerClass = DeviantartResourceOwner::class; + protected string $resourceOwnerClass = DeviantartResourceOwner::class; protected $userResponse = <<mockHttpClient($this->userResponse, 'application/json; charset=utf-8'); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse($this->userResponse, 'application/json; charset=utf-8'), + ] + ); /** - * @var \HWI\Bundle\OAuthBundle\OAuth\Response\AbstractUserResponse + * @var AbstractUserResponse */ - $userResponse = $this->resourceOwner->getUserInformation(['access_token' => 'token']); + $userResponse = $resourceOwner->getUserInformation(['access_token' => 'token']); $this->assertEquals('kouiskas', $userResponse->getUsername()); $this->assertEquals('kouiskas', $userResponse->getNickname()); diff --git a/Tests/OAuth/ResourceOwner/DiscogsResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/DiscogsResourceOwnerTest.php index fd4172449..25e3f60b4 100644 --- a/Tests/OAuth/ResourceOwner/DiscogsResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/DiscogsResourceOwnerTest.php @@ -15,7 +15,7 @@ class DiscogsResourceOwnerTest extends GenericOAuth1ResourceOwnerTest { - protected $resourceOwnerClass = DiscogsResourceOwner::class; + protected string $resourceOwnerClass = DiscogsResourceOwner::class; protected $userResponse = << 'account_id', @@ -26,9 +26,11 @@ class DropboxResourceOwnerTest extends GenericOAuth2ResourceOwnerTest public function testGetAuthorizationUrl() { + $resourceOwner = $this->createResourceOwner(); + $this->assertEquals( $this->options['authorization_url'].'&response_type=code&client_id=clientid&state=eyJzdGF0ZSI6InJhbmRvbSJ9&redirect_uri=http%3A%2F%2Fredirect.to%2F', - $this->resourceOwner->getAuthorizationUrl('http://redirect.to/') + $resourceOwner->getAuthorizationUrl('http://redirect.to/') ); } } diff --git a/Tests/OAuth/ResourceOwner/EveOnlineResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/EveOnlineResourceOwnerTest.php index 02c61ca31..9556e3072 100644 --- a/Tests/OAuth/ResourceOwner/EveOnlineResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/EveOnlineResourceOwnerTest.php @@ -15,7 +15,7 @@ class EveOnlineResourceOwnerTest extends GenericOAuth2ResourceOwnerTest { - protected $resourceOwnerClass = EveOnlineResourceOwner::class; + protected string $resourceOwnerClass = EveOnlineResourceOwner::class; protected $userResponse = <<mockHttpClient($this->userResponse, 'application/json; charset=utf-8'); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse($this->userResponse, 'application/json; charset=utf-8'), + ] + ); /** * @var AbstractUserResponse */ - $userResponse = $this->resourceOwner->getUserInformation(['access_token' => 'token']); + $userResponse = $resourceOwner->getUserInformation(['access_token' => 'token']); $this->assertEquals('bar', $userResponse->getFirstName()); $this->assertEquals('foo', $userResponse->getLastName()); diff --git a/Tests/OAuth/ResourceOwner/FacebookResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/FacebookResourceOwnerTest.php index 6d741c5b3..03ef99f20 100644 --- a/Tests/OAuth/ResourceOwner/FacebookResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/FacebookResourceOwnerTest.php @@ -13,11 +13,12 @@ use HWI\Bundle\OAuthBundle\OAuth\ResourceOwner\FacebookResourceOwner; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\OptionsResolver\Exception\ExceptionInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; class FacebookResourceOwnerTest extends GenericOAuth2ResourceOwnerTest { - protected $resourceOwnerClass = FacebookResourceOwner::class; + protected string $resourceOwnerClass = FacebookResourceOwner::class; protected $userResponse = <<expectException(AuthenticationException::class); - $this->mockHttpClient('{"error": {"message": "invalid"}}', 'application/json; charset=utf-8'); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse('{"error": {"message": "invalid"}}', 'application/json; charset=utf-8'), + ] + ); + $request = new Request(['code' => 'code']); - $this->resourceOwner->getAccessToken($request, 'http://redirect.to/'); + $resourceOwner->getAccessToken($request, 'http://redirect.to/'); } public function testAuthTypeRerequest() { - $resourceOwner = $this->createResourceOwner($this->resourceOwnerName, ['auth_type' => 'rerequest']); + $resourceOwner = $this->createResourceOwner(['auth_type' => 'rerequest']); $this->assertEquals( $this->options['authorization_url'].'&response_type=code&client_id=clientid&state=eyJzdGF0ZSI6InJhbmRvbSJ9&redirect_uri=http%3A%2F%2Fredirect.to%2F&auth_type=rerequest', @@ -57,7 +65,7 @@ public function testAuthTypeRerequest() public function testAuthTypeRerequestAndDisplayPopup() { - $resourceOwner = $this->createResourceOwner($this->resourceOwnerName, ['display' => 'popup', 'auth_type' => 'rerequest']); + $resourceOwner = $this->createResourceOwner(['display' => 'popup', 'auth_type' => 'rerequest']); $this->assertEquals( $this->options['authorization_url'].'&response_type=code&client_id=clientid&state=eyJzdGF0ZSI6InJhbmRvbSJ9&redirect_uri=http%3A%2F%2Fredirect.to%2F&display=popup&auth_type=rerequest', @@ -67,7 +75,7 @@ public function testAuthTypeRerequestAndDisplayPopup() public function testDisplayPopup() { - $resourceOwner = $this->createResourceOwner($this->resourceOwnerName, ['display' => 'popup']); + $resourceOwner = $this->createResourceOwner(['display' => 'popup']); $this->assertEquals( $this->options['authorization_url'].'&response_type=code&client_id=clientid&state=eyJzdGF0ZSI6InJhbmRvbSJ9&redirect_uri=http%3A%2F%2Fredirect.to%2F&display=popup', @@ -77,38 +85,47 @@ public function testDisplayPopup() public function testInvalidDisplayOptionValueThrowsException() { - $this->expectException(\Symfony\Component\OptionsResolver\Exception\ExceptionInterface::class); + $this->expectException(ExceptionInterface::class); - $this->createResourceOwner($this->resourceOwnerName, ['display' => 'invalid']); + $this->createResourceOwner(['display' => 'invalid']); } public function testRevokeToken() { - $this->httpResponseHttpCode = 200; - $this->mockHttpClient('{"access_token": "bar"}', 'application/json'); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse('{"access_token": "bar"}', 'application/json'), + ] + ); - $this->assertTrue($this->resourceOwner->revokeToken('token')); + $this->assertTrue($resourceOwner->revokeToken('token')); } public function testRevokeTokenFails() { - $this->httpResponseHttpCode = 401; - $this->mockHttpClient('{"access_token": "bar"}', 'application/json'); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse('{"access_token": "bar"}', 'application/json', 401), + ] + ); - $this->assertFalse($this->resourceOwner->revokeToken('token')); + $this->assertFalse($resourceOwner->revokeToken('token')); } public function testGetAccessTokenErrorResponse() { $this->expectException(AuthenticationException::class); - $this->mockHttpClient(); - $request = new Request([ 'error_code' => 901, 'error_message' => 'This app is in sandbox mode. Edit the app configuration at http://developers.facebook.com/apps to make the app publicly visible.', ]); - $this->resourceOwner->getAccessToken($request, 'http://redirect.to/'); + $resourceOwner = $this->createResourceOwner(); + $resourceOwner->getAccessToken($request, 'http://redirect.to/'); } } diff --git a/Tests/OAuth/ResourceOwner/FlickrResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/FlickrResourceOwnerTest.php index dbc3333e8..b368384ec 100644 --- a/Tests/OAuth/ResourceOwner/FlickrResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/FlickrResourceOwnerTest.php @@ -16,7 +16,7 @@ class FlickrResourceOwnerTest extends GenericOAuth1ResourceOwnerTest { - protected $resourceOwnerClass = FlickrResourceOwner::class; + protected string $resourceOwnerClass = FlickrResourceOwner::class; protected $paths = [ 'identifier' => 'user_nsid', 'nickname' => 'username', @@ -28,6 +28,14 @@ class FlickrResourceOwnerTest extends GenericOAuth1ResourceOwnerTest */ public function testGetUserInformation() { + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse($this->userResponse), + ] + ); + $accessToken = [ 'oauth_token' => 'token', 'oauth_token_secret' => 'secret', @@ -35,7 +43,7 @@ public function testGetUserInformation() 'user_nsid' => '15362483@N08', 'username' => 'lakiboy83', ]; - $userResponse = $this->resourceOwner->getUserInformation($accessToken); + $userResponse = $resourceOwner->getUserInformation($accessToken); $this->assertEquals('15362483@N08', $userResponse->getUsername()); $this->assertEquals('lakiboy83', $userResponse->getNickname()); @@ -50,16 +58,22 @@ public function testGetUserInformation() */ public function testGetAuthorizationUrlContainOAuthTokenAndSecret() { - $this->mockHttpClient('{"oauth_token": "token", "oauth_token_secret": "secret"}', 'application/json; charset=utf-8'); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse('{"oauth_token": "token", "oauth_token_secret": "secret"}', 'application/json; charset=utf-8'), + ] + ); $this->storage->expects($this->once()) ->method('save') - ->with($this->resourceOwner, ['oauth_token' => 'token', 'oauth_token_secret' => 'secret', 'timestamp' => time()]) + ->with($resourceOwner, ['oauth_token' => 'token', 'oauth_token_secret' => 'secret', 'timestamp' => time()]) ; $this->assertEquals( $this->options['authorization_url'].'&oauth_token=token&perms=read&nojsoncallback=1', - $this->resourceOwner->getAuthorizationUrl('http://redirect.to/') + $resourceOwner->getAuthorizationUrl('http://redirect.to/') ); } @@ -69,7 +83,7 @@ public function testGetAuthorizationUrlContainOAuthTokenAndSecret() public function testCustomResponseClass() { $class = CustomUserResponse::class; - $resourceOwner = $this->createResourceOwner($this->resourceOwnerName, ['user_response_class' => $class]); + $resourceOwner = $this->createResourceOwner(['user_response_class' => $class]); /* @var $userResponse CustomUserResponse */ $userResponse = $resourceOwner->getUserInformation(['oauth_token' => 'token', 'oauth_token_secret' => 'secret']); diff --git a/Tests/OAuth/ResourceOwner/FoursquareResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/FoursquareResourceOwnerTest.php index d1815367f..be035e98f 100644 --- a/Tests/OAuth/ResourceOwner/FoursquareResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/FoursquareResourceOwnerTest.php @@ -16,7 +16,7 @@ class FoursquareResourceOwnerTest extends GenericOAuth2ResourceOwnerTest { - protected $resourceOwnerClass = FoursquareResourceOwner::class; + protected string $resourceOwnerClass = FoursquareResourceOwner::class; protected $userResponse = <<mockHttpClient($this->userResponse, 'application/json; charset=utf-8'); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse($this->userResponse, 'application/json; charset=utf-8'), + ] + ); /** * @var AbstractUserResponse */ - $userResponse = $this->resourceOwner->getUserInformation(['access_token' => 'token']); + $userResponse = $resourceOwner->getUserInformation(['access_token' => 'token']); $this->assertEquals('bar', $userResponse->getFirstName()); $this->assertEquals('foo', $userResponse->getLastName()); diff --git a/Tests/OAuth/ResourceOwner/GenericOAuth1ResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/GenericOAuth1ResourceOwnerTest.php index 5703fea7b..534d92674 100644 --- a/Tests/OAuth/ResourceOwner/GenericOAuth1ResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/GenericOAuth1ResourceOwnerTest.php @@ -11,24 +11,18 @@ namespace HWI\Bundle\OAuthBundle\Tests\OAuth\ResourceOwner; -use Http\Client\HttpClient; use HWI\Bundle\OAuthBundle\OAuth\RequestDataStorageInterface; use HWI\Bundle\OAuthBundle\OAuth\ResourceOwner\GenericOAuth1ResourceOwner; use HWI\Bundle\OAuthBundle\Tests\Fixtures\CustomUserResponse; use PHPUnit\Framework\MockObject\MockObject; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\OptionsResolver\Exception\ExceptionInterface; +use Symfony\Component\Security\Core\Exception\AuthenticationException; class GenericOAuth1ResourceOwnerTest extends ResourceOwnerTestCase { - protected $resourceOwnerClass = GenericOAuth1ResourceOwner::class; - /** @var GenericOAuth1ResourceOwner */ - protected $resourceOwner; - protected $resourceOwnerName; - /** @var MockObject&HttpClient */ - protected $httpClient; - protected $httpResponse; - protected $httpResponseContentType; + protected string $resourceOwnerClass = GenericOAuth1ResourceOwner::class; + /** @var MockObject&RequestDataStorageInterface */ protected $storage; @@ -50,47 +44,49 @@ class GenericOAuth1ResourceOwnerTest extends ResourceOwnerTestCase 'realname' => 'foo_disp', ]; - protected function setUp(): void - { - $this->resourceOwnerName = str_replace(['generic', 'resourceownertest'], '', strtolower(__CLASS__)); - $this->resourceOwner = $this->createResourceOwner($this->resourceOwnerName); - } - public function testUndefinedOptionThrowsException() { $this->expectException(ExceptionInterface::class); - $this->createResourceOwner($this->resourceOwnerName, ['non_existing' => null]); + $this->createResourceOwner(['non_existing' => null]); } public function testInvalidOptionValueThrowsException() { $this->expectException(ExceptionInterface::class); - $this->createResourceOwner($this->resourceOwnerName, ['csrf' => 'invalid']); + $this->createResourceOwner(['csrf' => 'invalid']); } public function testHandleRequest() { $request = new Request(['test' => 'test']); - $this->assertFalse($this->resourceOwner->handles($request)); + $resourceOwner = $this->createResourceOwner(); + + $this->assertFalse($resourceOwner->handles($request)); $request = new Request(['oauth_token' => 'test']); - $this->assertTrue($this->resourceOwner->handles($request)); + $this->assertTrue($resourceOwner->handles($request)); $request = new Request(['oauth_token' => 'test', 'test' => 'test']); - $this->assertTrue($this->resourceOwner->handles($request)); + $this->assertTrue($resourceOwner->handles($request)); } public function testGetUserInformation() { - $this->mockHttpClient($this->userResponse, 'application/json; charset=utf-8'); - $accessToken = ['oauth_token' => 'token', 'oauth_token_secret' => 'secret']; - $userResponse = $this->resourceOwner->getUserInformation($accessToken); + + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse($this->userResponse, 'application/json; charset=utf-8'), + ] + ); + $userResponse = $resourceOwner->getUserInformation($accessToken); $this->assertEquals('1', $userResponse->getUsername()); $this->assertEquals('bar', $userResponse->getNickname()); @@ -101,122 +97,176 @@ public function testGetUserInformation() public function testGetAuthorizationUrlContainOAuthTokenAndSecret() { - $this->mockHttpClient('{"oauth_token": "token", "oauth_token_secret": "secret"}', 'application/json; charset=utf-8'); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse('{"oauth_token": "token", "oauth_token_secret": "secret"}', 'application/json; charset=utf-8'), + ] + ); $this->storage->expects($this->once()) ->method('save') - ->with($this->resourceOwner, ['oauth_token' => 'token', 'oauth_token_secret' => 'secret', 'timestamp' => time()]); + ->with($resourceOwner, ['oauth_token' => 'token', 'oauth_token_secret' => 'secret', 'timestamp' => time()]); $this->assertEquals( $this->options['authorization_url'].'&oauth_token=token', - $this->resourceOwner->getAuthorizationUrl('http://redirect.to/') + $resourceOwner->getAuthorizationUrl('http://redirect.to/') ); } public function testGetAuthorizationUrlFailedResponseContainOnlyOAuthToken() { - $this->expectException(\Symfony\Component\Security\Core\Exception\AuthenticationException::class); - - $this->mockHttpClient('{"oauth_token": "token"}', 'application/json; charset=utf-8'); + $this->expectException(AuthenticationException::class); + + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse('{"oauth_token": "token"}', 'application/json; charset=utf-8'), + ] + ); $this->storage->expects($this->never()) ->method('save'); - $this->resourceOwner->getAuthorizationUrl('http://redirect.to/'); + $resourceOwner->getAuthorizationUrl('http://redirect.to/'); } public function testGetAuthorizationUrlFailedResponseContainOAuthProblem() { - $this->expectException(\Symfony\Component\Security\Core\Exception\AuthenticationException::class); - - $this->mockHttpClient('oauth_problem=message'); + $this->expectException(AuthenticationException::class); + + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse('oauth_problem=message', 'text/plain'), + ] + ); $this->storage->expects($this->never()) ->method('save'); - $this->resourceOwner->getAuthorizationUrl('http://redirect.to/'); + $resourceOwner->getAuthorizationUrl('http://redirect.to/'); } public function testGetAuthorizationUrlFailedResponseContainCallbackNotConfirmed() { - $this->expectException(\Symfony\Component\Security\Core\Exception\AuthenticationException::class); - - $this->mockHttpClient('oauth_callback_confirmed=false'); + $this->expectException(AuthenticationException::class); + + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse('oauth_callback_confirmed=false', 'text/plain'), + ] + ); $this->storage->expects($this->never()) ->method('save'); - $this->resourceOwner->getAuthorizationUrl('http://redirect.to/'); + $resourceOwner->getAuthorizationUrl('http://redirect.to/'); } public function testGetAuthorizationUrlFailedResponseNotContainOAuthTokenOrSecret() { - $this->expectException(\Symfony\Component\Security\Core\Exception\AuthenticationException::class); - - $this->mockHttpClient('invalid'); + $this->expectException(AuthenticationException::class); + + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse('invalid', 'text/plain'), + ] + ); $this->storage->expects($this->never()) ->method('save'); - $this->resourceOwner->getAuthorizationUrl('http://redirect.to/'); + $resourceOwner->getAuthorizationUrl('http://redirect.to/'); } public function testGetAccessToken() { - $this->mockHttpClient('oauth_token=token&oauth_token_secret=secret'); - $request = new Request(['oauth_verifier' => 'code', 'oauth_token' => 'token']); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse('oauth_token=token&oauth_token_secret=secret', 'text/plain'), + ] + ); + $this->storage->expects($this->once()) ->method('fetch') - ->with($this->resourceOwner, 'token') + ->with($resourceOwner, 'token') ->willReturn(['oauth_token' => 'token2', 'oauth_token_secret' => 'secret2']); $this->assertEquals( ['oauth_token' => 'token', 'oauth_token_secret' => 'secret'], - $this->resourceOwner->getAccessToken($request, 'http://redirect.to/') + $resourceOwner->getAccessToken($request, 'http://redirect.to/') ); } public function testGetAccessTokenJsonResponse() { - $this->mockHttpClient('{"oauth_token": "token", "oauth_token_secret": "secret"}', 'application/json'); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse('{"oauth_token": "token", "oauth_token_secret": "secret"}', 'application/json'), + ] + ); $request = new Request(['oauth_verifier' => 'code', 'oauth_token' => 'token']); $this->storage->expects($this->once()) ->method('fetch') - ->with($this->resourceOwner, 'token') + ->with($resourceOwner, 'token') ->willReturn(['oauth_token' => 'token2', 'oauth_token_secret' => 'secret2']); $this->assertEquals( ['oauth_token' => 'token', 'oauth_token_secret' => 'secret'], - $this->resourceOwner->getAccessToken($request, 'http://redirect.to/') + $resourceOwner->getAccessToken($request, 'http://redirect.to/') ); } public function testGetAccessTokenJsonCharsetResponse() { - $this->mockHttpClient('{"oauth_token": "token", "oauth_token_secret": "secret"}', 'application/json; charset=utf-8'); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse('{"oauth_token": "token", "oauth_token_secret": "secret"}', 'application/json; charset=utf-8'), + ] + ); $request = new Request(['oauth_verifier' => 'code', 'oauth_token' => 'token']); $this->storage->expects($this->once()) ->method('fetch') - ->with($this->resourceOwner, 'token') + ->with($resourceOwner, 'token') ->willReturn(['oauth_token' => 'token2', 'oauth_token_secret' => 'secret2']); $this->assertEquals( ['oauth_token' => 'token', 'oauth_token_secret' => 'secret'], - $this->resourceOwner->getAccessToken($request, 'http://redirect.to/') + $resourceOwner->getAccessToken($request, 'http://redirect.to/') ); } public function testGetAccessTokenFailedResponse() { - $this->expectException(\Symfony\Component\Security\Core\Exception\AuthenticationException::class); - - $this->mockHttpClient('invalid'); + $this->expectException(AuthenticationException::class); + + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse('invalid', 'text/plain'), + ] + ); $this->storage->expects($this->once()) ->method('fetch') @@ -227,14 +277,20 @@ public function testGetAccessTokenFailedResponse() $request = new Request(['oauth_token' => 'token', 'oauth_verifier' => 'code']); - $this->resourceOwner->getAccessToken($request, 'http://redirect.to/'); + $resourceOwner->getAccessToken($request, 'http://redirect.to/'); } public function testGetAccessTokenErrorResponse() { - $this->expectException(\Symfony\Component\Security\Core\Exception\AuthenticationException::class); - - $this->mockHttpClient('error=foo'); + $this->expectException(AuthenticationException::class); + + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse('error=foo', 'text/plain'), + ] + ); $this->storage->expects($this->once()) ->method('fetch') @@ -245,53 +301,56 @@ public function testGetAccessTokenErrorResponse() $request = new Request(['oauth_token' => 'token', 'oauth_verifier' => 'code']); - $this->resourceOwner->getAccessToken($request, 'http://redirect.to/'); + $resourceOwner->getAccessToken($request, 'http://redirect.to/'); } public function testGetAccessTokenInvalidArgumentException() { - $this->expectException(\Symfony\Component\Security\Core\Exception\AuthenticationException::class); + $this->expectException(AuthenticationException::class); + + $resourceOwner = $this->createResourceOwner(); $this->storage->expects($this->once()) ->method('fetch') - ->will($this->throwException(new \InvalidArgumentException())); - - $this->httpClient->expects($this->never()) - ->method('sendRequest'); + ->willThrowException(new \InvalidArgumentException()); $this->storage->expects($this->never()) ->method('save'); $request = new Request(['oauth_token' => 'token', 'oauth_verifier' => 'code']); - $this->resourceOwner->getAccessToken($request, 'http://redirect.to/'); + $resourceOwner->getAccessToken($request, 'http://redirect.to/'); } public function testRefreshAccessToken() { - $this->expectException(\Symfony\Component\Security\Core\Exception\AuthenticationException::class); + $this->expectException(AuthenticationException::class); - $this->resourceOwner->refreshAccessToken('token'); + $resourceOwner = $this->createResourceOwner(); + $resourceOwner->refreshAccessToken('token'); } public function testRevokeToken() { - $this->expectException(\Symfony\Component\Security\Core\Exception\AuthenticationException::class); + $this->expectException(AuthenticationException::class); - $this->resourceOwner->revokeToken('token'); + $resourceOwner = $this->createResourceOwner(); + $resourceOwner->revokeToken('token'); } public function testCsrfTokenIsAlwaysValidForOAuth1() { + $resourceOwner = $this->createResourceOwner(); + $this->storage->expects($this->never()) ->method('fetch'); - $this->assertTrue($this->resourceOwner->isCsrfTokenValid('valid_token')); + $this->assertTrue($resourceOwner->isCsrfTokenValid('valid_token')); } public function testCsrfTokenValid() { - $resourceOwner = $this->createResourceOwner($this->resourceOwnerName, ['csrf' => true]); + $resourceOwner = $this->createResourceOwner(['csrf' => true]); $this->storage->expects($this->never()) ->method('fetch'); @@ -301,15 +360,20 @@ public function testCsrfTokenValid() public function testGetSetName() { - $this->assertEquals($this->resourceOwnerName, $this->resourceOwner->getName()); + $resourceOwner = $this->createResourceOwner(); + $this->assertEquals($this->prepareResourceOwnerName(), $resourceOwner->getName()); } public function testCustomResponseClass() { $class = CustomUserResponse::class; - $resourceOwner = $this->createResourceOwner($this->resourceOwnerName, ['user_response_class' => $class]); - - $this->mockHttpClient(); + $resourceOwner = $this->createResourceOwner( + ['user_response_class' => $class], + [], + [ + $this->createMockResponse($this->userResponse), + ] + ); /** @var CustomUserResponse $userResponse */ $userResponse = $resourceOwner->getUserInformation(['oauth_token' => 'token', 'oauth_token_secret' => 'secret']); diff --git a/Tests/OAuth/ResourceOwner/GenericOAuth2ResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/GenericOAuth2ResourceOwnerTest.php index 8a574ae41..71cbe40c3 100644 --- a/Tests/OAuth/ResourceOwner/GenericOAuth2ResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/GenericOAuth2ResourceOwnerTest.php @@ -11,7 +11,6 @@ namespace HWI\Bundle\OAuthBundle\Tests\OAuth\ResourceOwner; -use Http\Client\Exception\TransferException; use HWI\Bundle\OAuthBundle\OAuth\Exception\HttpTransportException; use HWI\Bundle\OAuthBundle\OAuth\ResourceOwner\GenericOAuth2ResourceOwner; use HWI\Bundle\OAuthBundle\OAuth\Response\AbstractUserResponse; @@ -22,16 +21,11 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\OptionsResolver\Exception\ExceptionInterface; use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; +use Symfony\Component\Security\Core\Exception\AuthenticationException; class GenericOAuth2ResourceOwnerTest extends ResourceOwnerTestCase { - protected $resourceOwnerClass = GenericOAuth2ResourceOwner::class; - /** - * @var GenericOAuth2ResourceOwner - */ - protected $resourceOwner; - protected $resourceOwnerName; - + protected string $resourceOwnerClass = GenericOAuth2ResourceOwner::class; protected $tokenData = ['access_token' => 'token']; protected $options = [ @@ -62,47 +56,49 @@ class GenericOAuth2ResourceOwnerTest extends ResourceOwnerTestCase protected $redirectUrlPart = '&redirect_uri=http%3A%2F%2Fredirect.to%2F'; protected $authorizationUrlParams = []; - protected function setUp(): void - { - $this->resourceOwnerName = str_replace(['generic', 'resourceownertest'], '', strtolower(__CLASS__)); - $this->resourceOwner = $this->createResourceOwner($this->resourceOwnerName); - } - public function testUndefinedOptionThrowsException() { $this->expectException(ExceptionInterface::class); - $this->createResourceOwner($this->resourceOwnerName, ['non_existing' => null]); + $this->createResourceOwner(['non_existing' => null]); } public function testInvalidOptionValueThrowsException() { $this->expectException(ExceptionInterface::class); - $this->createResourceOwner($this->resourceOwnerName, ['csrf' => 'invalid']); + $this->createResourceOwner(['csrf' => 'invalid']); } public function testHandleRequest() { + $resourceOwner = $this->createResourceOwner(); + $request = new Request(['test' => 'test']); - $this->assertFalse($this->resourceOwner->handles($request)); + $this->assertFalse($resourceOwner->handles($request)); $request = new Request(['code' => 'test']); - $this->assertTrue($this->resourceOwner->handles($request)); + $this->assertTrue($resourceOwner->handles($request)); $request = new Request(['code' => 'test', 'test' => 'test']); - $this->assertTrue($this->resourceOwner->handles($request)); + $this->assertTrue($resourceOwner->handles($request)); } public function testGetUserInformation() { - $this->mockHttpClient($this->userResponse, 'application/json; charset=utf-8'); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse($this->userResponse), + ] + ); /** @var AbstractUserResponse $userResponse */ - $userResponse = $this->resourceOwner->getUserInformation($this->tokenData); + $userResponse = $resourceOwner->getUserInformation($this->tokenData); $this->assertEquals('1', $userResponse->getUsername()); $this->assertEquals('bar', $userResponse->getNickname()); @@ -113,18 +109,16 @@ public function testGetUserInformation() public function testGetUserInformationFailure() { - $exception = new TransferException(); - - $this->httpClient->expects($this->once()) - ->method('sendRequest') - ->will($this->throwException($exception)); - - try { - $this->resourceOwner->getUserInformation($this->tokenData); - $this->fail('An exception should have been raised'); - } catch (HttpTransportException $e) { - $this->assertSame($exception, $e->getPrevious()); - } + $this->expectException(HttpTransportException::class); + + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse('invalid', null, 401), + ] + ); + $resourceOwner->getUserInformation($this->tokenData); } public function testGetAuthorizationUrl() @@ -135,7 +129,7 @@ public function testGetAuthorizationUrl() $state = new State(['csrf_token' => NonceGenerator::generate()]); } - $resourceOwner = $this->createResourceOwner($this->resourceOwnerName, [], [], $state); + $resourceOwner = $this->createResourceOwner([], [], [], $state); if (!$this->csrf) { $this->storage->expects($this->never()) @@ -165,7 +159,7 @@ public function testGetState() $initialState = new State(array_merge($stateParams, ['csrf_token' => NonceGenerator::generate()])); } - $resourceOwner = $this->createResourceOwner($this->resourceOwnerName, [], [], $initialState); + $resourceOwner = $this->createResourceOwner([], [], [], $initialState); $this->storage->expects($this->once()) ->method('fetch') ->with($resourceOwner, State::class, 'state') @@ -178,7 +172,7 @@ public function testGetState() public function testGetStateWithoutStoredValues() { - $resourceOwner = $this->createResourceOwner($this->resourceOwnerName, [], [], new State(null)); + $resourceOwner = $this->createResourceOwner([], [], [], new State(null)); $this->storage->expects($this->once()) ->method('fetch') ->with($resourceOwner, State::class, 'state') @@ -196,7 +190,7 @@ public function testGetAuthorizationUrlWithEnabledCsrf() $nonce = NonceGenerator::generate(); $state = new State(['csrf_token' => $nonce]); - $resourceOwner = $this->createResourceOwner($this->resourceOwnerName, ['csrf' => true], [], $state); + $resourceOwner = $this->createResourceOwner(['csrf' => true], [], [], $state); $this->storage->expects($this->once()) ->method('save') @@ -210,123 +204,156 @@ public function testGetAuthorizationUrlWithEnabledCsrf() $this->state = $state->encode(); } - public function testGetAccessToken() - { - $this->mockHttpClient('access_token=code'); - - $request = new Request(['code' => 'somecode']); - - $this->assertEquals( - ['access_token' => 'code'], - $this->resourceOwner->getAccessToken($request, 'http://redirect.to/') - ); - } - - public function testGetAccessTokenJsonResponse() + /** + * @dataProvider provideAccessTokenData + */ + public function testGetAccessToken(string $response, string $contentType) { - $this->mockHttpClient('{"access_token": "code"}', 'application/json'); - - $request = new Request(['code' => 'somecode']); - - $this->assertEquals( - ['access_token' => 'code'], - $this->resourceOwner->getAccessToken($request, 'http://redirect.to/') + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse($response, $contentType), + ] ); - } - - public function testGetAccessTokenJsonCharsetResponse() - { - $this->mockHttpClient('{"access_token": "code"}', 'application/json; charset=utf-8'); $request = new Request(['code' => 'somecode']); $this->assertEquals( ['access_token' => 'code'], - $this->resourceOwner->getAccessToken($request, 'http://redirect.to/') + $resourceOwner->getAccessToken($request, 'http://redirect.to/') ); } - public function testGetAccessTokenTextJavascriptResponse() + public function provideAccessTokenData(): iterable { - $this->mockHttpClient('{"access_token": "code"}', 'text/javascript'); - - $request = new Request(['code' => 'somecode']); - - $this->assertEquals( - ['access_token' => 'code'], - $this->resourceOwner->getAccessToken($request, 'http://redirect.to/') - ); - } - - public function testGetAccessTokenTextJavascriptCharsetResponse() - { - $this->mockHttpClient('{"access_token": "code"}', 'text/javascript; charset=utf-8'); - - $request = new Request(['code' => 'somecode']); - - $this->assertEquals( - ['access_token' => 'code'], - $this->resourceOwner->getAccessToken($request, 'http://redirect.to/') - ); + yield 'plain text' => [ + 'access_token=code', + 'text/plain', + ]; + + yield 'json' => [ + '{"access_token": "code"}', + 'application/json', + ]; + + yield 'json with charset' => [ + '{"access_token": "code"}', + 'application/json; charset=utf-8', + ]; + + yield 'javascript' => [ + '{"access_token": "code"}', + 'text/javascript', + ]; + + yield 'javascript with charset' => [ + '{"access_token": "code"}', + 'text/javascript; charset=utf-8', + ]; } public function testGetAccessTokenFailedResponse() { - $this->expectException(\Symfony\Component\Security\Core\Exception\AuthenticationException::class); + $this->expectException(AuthenticationException::class); - $this->mockHttpClient('invalid'); $request = new Request(['code' => 'code']); - $this->resourceOwner->getAccessToken($request, 'http://redirect.to/'); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse('invalid'), + ] + ); + $resourceOwner->getAccessToken($request, 'http://redirect.to/'); } public function testGetAccessTokenErrorResponse() { - $this->expectException(\Symfony\Component\Security\Core\Exception\AuthenticationException::class); + $this->expectException(AuthenticationException::class); - $this->mockHttpClient('error=foo'); $request = new Request(['code' => 'code']); - $this->resourceOwner->getAccessToken($request, 'http://redirect.to/'); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse('error=foo'), + ] + ); + $resourceOwner->getAccessToken($request, 'http://redirect.to/'); } - public function testRefreshAccessToken() + /** + * @dataProvider provideRefreshToken + */ + public function testRefreshAccessToken($response, $contentType) { - $this->mockHttpClient('{"access_token": "bar", "expires_in": 3600}', 'application/json'); - $accessToken = $this->resourceOwner->refreshAccessToken('foo'); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse($response, $contentType), + ] + ); + + $accessToken = $resourceOwner->refreshAccessToken('foo'); $this->assertEquals('bar', $accessToken['access_token']); $this->assertEquals(3600, $accessToken['expires_in']); } - public function testRefreshAccessTokenInvalid() + public function provideRefreshToken(): iterable { - $this->expectException(\Symfony\Component\Security\Core\Exception\AuthenticationException::class); - - $this->mockHttpClient('invalid'); - - $this->resourceOwner->refreshAccessToken('foo'); + yield 'correct token' => [ + '{"access_token": "bar", "expires_in": 3600}', + 'application/json', + ]; } - public function testRefreshAccessTokenError() + /** + * @dataProvider provideInvalidRefreshToken + */ + public function testRefreshAccessTokenInvalid(string $response, string $exceptionClass) { - $this->expectException(\Symfony\Component\Security\Core\Exception\AuthenticationException::class); - - $this->mockHttpClient('{"error": "invalid"}', 'application/json'); + $this->expectException($exceptionClass); + + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse($response), + ] + ); + $resourceOwner->refreshAccessToken('foo'); + } - $this->resourceOwner->refreshAccessToken('foo'); + public function provideInvalidRefreshToken(): iterable + { + yield 'invalid' => [ + 'invalid', + AuthenticationException::class, + ]; + + yield 'invalid json' => [ + '{"error": "invalid"}', + AuthenticationException::class, + ]; } public function testRevokeToken() { - $this->expectException(\Symfony\Component\Security\Core\Exception\AuthenticationException::class); + $this->expectException(AuthenticationException::class); - $this->resourceOwner->revokeToken('token'); + $resourceOwner = $this->createResourceOwner(); + $resourceOwner->revokeToken('token'); } public function testGetSetName() { - $this->assertEquals($this->resourceOwnerName, $this->resourceOwner->getName()); + $resourceOwner = $this->createResourceOwner(); + $this->assertEquals($this->prepareResourceOwnerName(), $resourceOwner->getName()); } public function testCsrfTokenIsValidWhenDisabled() @@ -335,15 +362,17 @@ public function testCsrfTokenIsValidWhenDisabled() $this->markTestSkipped('CSRF is enabled for this Resource Owner.'); } + $resourceOwner = $this->createResourceOwner(); + $this->storage->expects($this->never()) ->method('fetch'); - $this->assertTrue($this->resourceOwner->isCsrfTokenValid('whatever you want')); + $this->assertTrue($resourceOwner->isCsrfTokenValid('whatever you want')); } public function testCsrfTokenValid() { - $resourceOwner = $this->createResourceOwner($this->resourceOwnerName, ['csrf' => true]); + $resourceOwner = $this->createResourceOwner(['csrf' => true]); $this->storage->expects($this->once()) ->method('fetch') @@ -355,9 +384,9 @@ public function testCsrfTokenValid() public function testCsrfTokenInvalid() { - $this->expectException(\Symfony\Component\Security\Core\Exception\AuthenticationException::class); + $this->expectException(AuthenticationException::class); - $resourceOwner = $this->createResourceOwner($this->resourceOwnerName, ['csrf' => true]); + $resourceOwner = $this->createResourceOwner(['csrf' => true]); $this->storage->expects($this->once()) ->method('fetch') @@ -369,9 +398,9 @@ public function testCsrfTokenInvalid() public function testCsrfTokenMissing() { - $this->expectException(\Symfony\Component\Security\Core\Exception\AuthenticationException::class); + $this->expectException(AuthenticationException::class); - $resourceOwner = $this->createResourceOwner($this->resourceOwnerName, ['csrf' => true]); + $resourceOwner = $this->createResourceOwner(['csrf' => true]); $resourceOwner->isCsrfTokenValid(null); } @@ -379,11 +408,15 @@ public function testCsrfTokenMissing() public function testCustomResponseClass() { $class = CustomUserResponse::class; - $resourceOwner = $this->createResourceOwner($this->resourceOwnerName, ['user_response_class' => $class]); - $this->mockHttpClient(); + $resourceOwner = $this->createResourceOwner( + ['user_response_class' => $class], + [], + [ + $this->createMockResponse($this->userResponse), + ] + ); - /** @var CustomUserResponse */ $userResponse = $resourceOwner->getUserInformation($this->tokenData); $this->assertInstanceOf($class, $userResponse); @@ -394,34 +427,26 @@ public function testCustomResponseClass() $this->assertNull($userResponse->getExpiresIn()); } - protected function getExpectedAuthorizationUrlWithState($stateParameter) - { - // urlencode state parameter since AbstractResourceOwner::normalizeUrl() http_build_query method encodes them again - return $this->authorizationUrlBasePart.'&state='.urlencode($stateParameter).$this->redirectUrlPart; - } - - /** - * @param StateInterface $state Optional - * - * @throws \ReflectionException - * - * @return GenericOAuth2ResourceOwner - */ - protected function createResourceOwner(string $name, array $options = [], array $paths = [], ?StateInterface $state = null) - { + protected function createResourceOwner( + array $options = [], + array $paths = [], + array $responses = [], + ?StateInterface $state = null + ): GenericOAuth2ResourceOwner { /** @var GenericOAuth2ResourceOwner $resourceOwner */ - $resourceOwner = parent::createResourceOwner($name, $options, $paths); + $resourceOwner = parent::createResourceOwner($options, $paths, $responses); $reflection = new \ReflectionClass(\get_class($resourceOwner)); $stateProperty = $reflection->getProperty('state'); $stateProperty->setAccessible(true); - - $stateProperty->setValue($resourceOwner, $state); - - if (null === $state) { - $stateProperty->setValue($resourceOwner, new State($this->state)); - } + $stateProperty->setValue($resourceOwner, $state ?: new State($this->state)); return $resourceOwner; } + + private function getExpectedAuthorizationUrlWithState($stateParameter): string + { + // urlencode state parameter since AbstractResourceOwner::normalizeUrl() http_build_query method encodes them again + return $this->authorizationUrlBasePart.'&state='.urlencode($stateParameter).$this->redirectUrlPart; + } } diff --git a/Tests/OAuth/ResourceOwner/GeniusResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/GeniusResourceOwnerTest.php index 44d246ae2..a9817ac98 100644 --- a/Tests/OAuth/ResourceOwner/GeniusResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/GeniusResourceOwnerTest.php @@ -15,7 +15,7 @@ class GeniusResourceOwnerTest extends GenericOAuth2ResourceOwnerTest { - protected $resourceOwnerClass = GeniusResourceOwner::class; + protected string $resourceOwnerClass = GeniusResourceOwner::class; protected $userResponse = <<httpResponseHttpCode = 204; - $this->mockHttpClient(null, 'application/json'); - - $this->assertTrue($this->resourceOwner->revokeToken('token')); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse($this->userResponse, 'application/json', 204), + ] + ); + + $this->assertTrue($resourceOwner->revokeToken('token')); } public function testRevokeTokenFails() { - $this->httpResponseHttpCode = 404; - $this->mockHttpClient('{"id": "666"}', 'application/json'); - - $this->assertFalse($this->resourceOwner->revokeToken('token')); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse('{"id": "666"}', 'application/json', 404), + ] + ); + + $this->assertFalse($resourceOwner->revokeToken('token')); } public function testCustomResponseClass() { - $this->httpClientCalls = 2; - - parent::testCustomResponseClass(); - - $this->httpClientCalls = 1; + $class = CustomUserResponse::class; + + $resourceOwner = $this->createResourceOwner( + ['user_response_class' => $class], + [], + [ + $this->createMockResponse($this->userResponse), + $this->createMockResponse($this->userResponse), + ] + ); + + /** @var CustomUserResponse */ + $userResponse = $resourceOwner->getUserInformation($this->tokenData); + + $this->assertInstanceOf($class, $userResponse); + $this->assertEquals('foo666', $userResponse->getUsername()); + $this->assertEquals('foo', $userResponse->getNickname()); + $this->assertEquals('token', $userResponse->getAccessToken()); + $this->assertNull($userResponse->getRefreshToken()); + $this->assertNull($userResponse->getExpiresIn()); } public function testGetUserInformation() { - $this->httpClientCalls = 2; - - parent::testGetUserInformation(); - - $this->httpClientCalls = 1; + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse($this->userResponse), + $this->createMockResponse($this->userResponse), + ] + ); + + /** @var AbstractUserResponse */ + $userResponse = $resourceOwner->getUserInformation($this->tokenData); + + $this->assertEquals('1', $userResponse->getUsername()); + $this->assertEquals('bar', $userResponse->getNickname()); + $this->assertEquals('token', $userResponse->getAccessToken()); + $this->assertNull($userResponse->getRefreshToken()); + $this->assertNull($userResponse->getExpiresIn()); } } diff --git a/Tests/OAuth/ResourceOwner/GitLabResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/GitLabResourceOwnerTest.php index a779bf513..441fb733e 100644 --- a/Tests/OAuth/ResourceOwner/GitLabResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/GitLabResourceOwnerTest.php @@ -15,16 +15,21 @@ class GitLabResourceOwnerTest extends GenericOAuth2ResourceOwnerTest { - protected $resourceOwnerClass = GitLabResourceOwner::class; + protected string $resourceOwnerClass = GitLabResourceOwner::class; protected $httpClientCalls = 1; protected $authorizationUrlBasePart = 'http://user.auth/?test=2&response_type=code&client_id=clientid&scope=read_user'; public function testRevokeToken() { - $this->httpResponseHttpCode = 200; - $this->mockHttpClient(null, 'application/json'); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse($this->userResponse, 'application/json'), + ] + ); - $this->assertTrue($this->resourceOwner->revokeToken('token')); + $this->assertTrue($resourceOwner->revokeToken('token')); } } diff --git a/Tests/OAuth/ResourceOwner/GoogleResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/GoogleResourceOwnerTest.php index b7a2b2b66..b449a2bbb 100644 --- a/Tests/OAuth/ResourceOwner/GoogleResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/GoogleResourceOwnerTest.php @@ -12,11 +12,13 @@ namespace HWI\Bundle\OAuthBundle\Tests\OAuth\ResourceOwner; use HWI\Bundle\OAuthBundle\OAuth\ResourceOwner\GoogleResourceOwner; +use HWI\Bundle\OAuthBundle\OAuth\ResourceOwnerInterface; +use Symfony\Component\OptionsResolver\Exception\ExceptionInterface; use Symfony\Component\Security\Http\HttpUtils; class GoogleResourceOwnerTest extends GenericOAuth2ResourceOwnerTest { - protected $resourceOwnerClass = GoogleResourceOwner::class; + protected string $resourceOwnerClass = GoogleResourceOwner::class; protected $userResponse = <<expectException(\Symfony\Component\OptionsResolver\Exception\ExceptionInterface::class); + $this->expectException(ExceptionInterface::class); - $this->createResourceOwner($this->resourceOwnerName, ['access_type' => 'invalid']); + $this->createResourceOwner(['access_type' => 'invalid']); } public function testInvalidApprovalPromptOptionValueThrowsException() { - $this->expectException(\Symfony\Component\OptionsResolver\Exception\ExceptionInterface::class); + $this->expectException(ExceptionInterface::class); - $this->createResourceOwner($this->resourceOwnerName, ['approval_prompt' => 'invalid']); + $this->createResourceOwner(['approval_prompt' => 'invalid']); } public function testGetAuthorizationUrl() { + $resourceOwner = $this->createResourceOwner(); + $this->assertEquals( $this->options['authorization_url'].'&response_type=code&client_id=clientid&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile&state=eyJzdGF0ZSI6InJhbmRvbSJ9&redirect_uri=http%3A%2F%2Fredirect.to%2F&access_type=offline', - $this->resourceOwner->getAuthorizationUrl('http://redirect.to/') + $resourceOwner->getAuthorizationUrl('http://redirect.to/') ); } public function testRequestVisibleActions() { - $resourceOwner = $this->createResourceOwner($this->resourceOwnerName, ['request_visible_actions' => 'http://schemas.google.com/AddActivity'] + $resourceOwner = $this->createResourceOwner( + ['request_visible_actions' => 'http://schemas.google.com/AddActivity'] ); $this->assertEquals( @@ -72,7 +77,7 @@ public function testRequestVisibleActions() public function testApprovalPromptForce() { - $resourceOwner = $this->createResourceOwner($this->resourceOwnerName, ['approval_prompt' => 'force']); + $resourceOwner = $this->createResourceOwner(['approval_prompt' => 'force']); $this->assertEquals( $this->options['authorization_url'].'&response_type=code&client_id=clientid&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile&state=eyJzdGF0ZSI6InJhbmRvbSJ9&redirect_uri=http%3A%2F%2Fredirect.to%2F&access_type=offline&approval_prompt=force', @@ -82,13 +87,13 @@ public function testApprovalPromptForce() public function testHdParameter() { - $resourceOwner = $this->createResourceOwner($this->resourceOwnerName, ['hd' => 'mycollege.edu']); + $resourceOwner = $this->createResourceOwner(['hd' => 'mycollege.edu']); $this->assertEquals( $this->options['authorization_url'].'&response_type=code&client_id=clientid&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile&state=eyJzdGF0ZSI6InJhbmRvbSJ9&redirect_uri=http%3A%2F%2Fredirect.to%2F&access_type=offline&hd=mycollege.edu', $resourceOwner->getAuthorizationUrl('http://redirect.to/') ); - $resourceOwner = $this->createResourceOwner($this->resourceOwnerName, ['hd' => 'mycollege.edu, mycollege.org']); + $resourceOwner = $this->createResourceOwner(['hd' => 'mycollege.edu, mycollege.org']); $this->assertEquals( $this->options['authorization_url'].'&response_type=code&client_id=clientid&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile&state=eyJzdGF0ZSI6InJhbmRvbSJ9&redirect_uri=http%3A%2F%2Fredirect.to%2F&access_type=offline&hd=mycollege.edu&mycollege.org', $resourceOwner->getAuthorizationUrl('http://redirect.to/') @@ -97,21 +102,31 @@ public function testHdParameter() public function testRevokeToken() { - $this->httpResponseHttpCode = 200; - $this->mockHttpClient('{"access_token": "bar"}', 'application/json'); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse('{"access_token": "bar"}', 'application/json'), + ] + ); - $this->assertTrue($this->resourceOwner->revokeToken('token')); + $this->assertTrue($resourceOwner->revokeToken('token')); } public function testRevokeTokenFails() { - $this->httpResponseHttpCode = 401; - $this->mockHttpClient('{"access_token": "bar"}', 'application/json'); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse('{"access_token": "bar"}', 'application/json', 401), + ] + ); - $this->assertFalse($this->resourceOwner->revokeToken('token')); + $this->assertFalse($resourceOwner->revokeToken('token')); } - protected function setUpResourceOwner($name, HttpUtils $httpUtils, array $options) + protected function setUpResourceOwner(string $name, HttpUtils $httpUtils, array $options, array $responses): ResourceOwnerInterface { return parent::setUpResourceOwner( $name, @@ -121,7 +136,8 @@ protected function setUpResourceOwner($name, HttpUtils $httpUtils, array $option 'access_type' => 'offline', ], $options - ) + ), + $responses ); } } diff --git a/Tests/OAuth/ResourceOwner/HubicResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/HubicResourceOwnerTest.php index 8b9915bc0..50df67017 100644 --- a/Tests/OAuth/ResourceOwner/HubicResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/HubicResourceOwnerTest.php @@ -16,7 +16,7 @@ class HubicResourceOwnerTest extends GenericOAuth2ResourceOwnerTest { - protected $resourceOwnerClass = HubicResourceOwner::class; + protected string $resourceOwnerClass = HubicResourceOwner::class; protected $userResponse = '{ "email": "1", "firstname": "bar", "activated": true , "creationDate": "2013-12-31T19:09:42+01:00", "language": "fr", "status": "ok", "offer": "25g", "lastname": "foo" }'; protected $paths = [ 'identifier' => 'email', @@ -29,12 +29,18 @@ class HubicResourceOwnerTest extends GenericOAuth2ResourceOwnerTest public function testGetUserInformationFirstAndLastName() { - $this->mockHttpClient($this->userResponse, 'application/json; charset=utf-8'); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse($this->userResponse, 'application/json; charset=utf-8'), + ] + ); /** * @var AbstractUserResponse */ - $userResponse = $this->resourceOwner->getUserInformation(['access_token' => 'token']); + $userResponse = $resourceOwner->getUserInformation(['access_token' => 'token']); $this->assertEquals('bar', $userResponse->getFirstName()); $this->assertEquals('foo', $userResponse->getLastName()); @@ -42,9 +48,11 @@ public function testGetUserInformationFirstAndLastName() public function testGetAuthorizationUrl() { + $resourceOwner = $this->createResourceOwner(); + $this->assertEquals( $this->options['authorization_url'].'&response_type=code&client_id=clientid&state=eyJzdGF0ZSI6InJhbmRvbSJ9&redirect_uri=http%3A%2F%2Fredirect.to%2F', - $this->resourceOwner->getAuthorizationUrl('http://redirect.to/') + $resourceOwner->getAuthorizationUrl('http://redirect.to/') ); } } diff --git a/Tests/OAuth/ResourceOwner/InstagramResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/InstagramResourceOwnerTest.php index a74f9f349..2137df8c2 100644 --- a/Tests/OAuth/ResourceOwner/InstagramResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/InstagramResourceOwnerTest.php @@ -16,7 +16,7 @@ class InstagramResourceOwnerTest extends GenericOAuth2ResourceOwnerTest { - protected $resourceOwnerClass = InstagramResourceOwner::class; + protected string $resourceOwnerClass = InstagramResourceOwner::class; protected $userResponse = <<createResourceOwner($this->resourceOwnerName, ['user_response_class' => $class]); + $resourceOwner = $this->createResourceOwner( + ['user_response_class' => $class], + [], + [ + $this->createMockResponse($this->userResponse), + ] + ); /* @var $userResponse CustomUserResponse */ $userResponse = $resourceOwner->getUserInformation(['access_token' => 'token']); diff --git a/Tests/OAuth/ResourceOwner/ItembaseResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/ItembaseResourceOwnerTest.php index ee3ef0498..091cc78eb 100644 --- a/Tests/OAuth/ResourceOwner/ItembaseResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/ItembaseResourceOwnerTest.php @@ -14,13 +14,11 @@ use HWI\Bundle\OAuthBundle\OAuth\ResourceOwner\ItembaseResourceOwner; /** - * Class ItembaseResourceOwnerTest. - * * @author Thomas Bretzke */ class ItembaseResourceOwnerTest extends GenericOAuth2ResourceOwnerTest { - protected $resourceOwnerClass = ItembaseResourceOwner::class; + protected string $resourceOwnerClass = ItembaseResourceOwner::class; protected $userResponse = << 'name', @@ -29,23 +28,17 @@ class JiraResourceOwnerTest extends GenericOAuth1ResourceOwnerTest public function testGetUserInformation() { - $this - ->httpClient->expects($this->exactly(2)) - ->method('sendRequest') - ->willReturnCallback(function (RequestInterface $request) { - $request = $request->withAddedHeader('Content-Type', 'application/json; charset=utf-8'); - - return MessageFactoryDiscovery::find() - ->createResponse( - $this->httpResponseHttpCode, - null, - $request->getHeaders(), - $this->userResponse - ); - }); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse($this->userResponse), + $this->createMockResponse($this->userResponse), + ] + ); $accessToken = ['oauth_token' => 'token', 'oauth_token_secret' => 'secret']; - $userResponse = $this->resourceOwner->getUserInformation($accessToken); + $userResponse = $resourceOwner->getUserInformation($accessToken); $this->assertEquals('asm89', $userResponse->getUsername()); $this->assertEquals('asm89', $userResponse->getNickname()); @@ -57,37 +50,14 @@ public function testGetUserInformation() public function testCustomResponseClass() { $class = CustomUserResponse::class; - $resourceOwner = $this->createResourceOwner($this->resourceOwnerName, ['user_response_class' => $class]); - - $this - ->httpClient->expects($this->atLeastOnce()) - ->method('sendRequest') - ->willReturnCallback(function (RequestInterface $request) { - $request = $request->withAddedHeader('Content-Type', 'application/json; charset=utf-8'); - - return MessageFactoryDiscovery::find() - ->createResponse( - $this->httpResponseHttpCode, - null, - $request->getHeaders(), - $this->userResponse - ); - }); - - $this - ->httpClient->expects($this->atLeastOnce()) - ->method('sendRequest') - ->willReturnCallback(function (RequestInterface $request) { - $request = $request->withAddedHeader('Content-Type', 'text/plain'); - - return MessageFactoryDiscovery::find() - ->createResponse( - $this->httpResponseHttpCode, - null, - $request->getHeaders(), - '' - ); - }); + $resourceOwner = $this->createResourceOwner( + ['user_response_class' => $class], + [], + [ + $this->createMockResponse($this->userResponse, 'application/json; charset=utf-8'), + $this->createMockResponse('', 'text/plain'), + ] + ); /** @var CustomUserResponse $userResponse */ $userResponse = $resourceOwner->getUserInformation(['oauth_token' => 'token', 'oauth_token_secret' => 'secret']); @@ -97,7 +67,7 @@ public function testCustomResponseClass() $this->assertEquals('foo', $userResponse->getNickname()); } - protected function setUpResourceOwner($name, HttpUtils $httpUtils, array $options) + protected function setUpResourceOwner(string $name, HttpUtils $httpUtils, array $options, array $responses): ResourceOwnerInterface { return parent::setUpResourceOwner( $name, @@ -111,7 +81,8 @@ protected function setUpResourceOwner($name, HttpUtils $httpUtils, array $option 'signature_method' => 'PLAINTEXT', ], $options - ) + ), + $responses ); } } diff --git a/Tests/OAuth/ResourceOwner/KeycloakResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/KeycloakResourceOwnerTest.php index bb071220c..2827df1a9 100644 --- a/Tests/OAuth/ResourceOwner/KeycloakResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/KeycloakResourceOwnerTest.php @@ -32,5 +32,5 @@ class KeycloakResourceOwnerTest extends GenericOAuth2ResourceOwnerTest protected $redirectUrlPart = '&redirect_uri=http%3A%2F%2Fredirect.to%2F&approval_prompt=auto'; protected $authorizationUrlParams = ['approval_prompt' => 'auto']; - protected $resourceOwnerClass = KeycloakResourceOwner::class; + protected string $resourceOwnerClass = KeycloakResourceOwner::class; } diff --git a/Tests/OAuth/ResourceOwner/LinkedinResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/LinkedinResourceOwnerTest.php index 66e382232..2f70ff710 100644 --- a/Tests/OAuth/ResourceOwner/LinkedinResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/LinkedinResourceOwnerTest.php @@ -13,10 +13,11 @@ use HWI\Bundle\OAuthBundle\OAuth\ResourceOwner\LinkedinResourceOwner; use HWI\Bundle\OAuthBundle\OAuth\Response\AbstractUserResponse; +use HWI\Bundle\OAuthBundle\Tests\Fixtures\CustomUserResponse; class LinkedinResourceOwnerTest extends GenericOAuth2ResourceOwnerTest { - protected $resourceOwnerClass = LinkedinResourceOwner::class; + protected string $resourceOwnerClass = LinkedinResourceOwner::class; protected $userResponse = <<httpClientCalls = 2; + $class = CustomUserResponse::class; - parent::testCustomResponseClass(); + $resourceOwner = $this->createResourceOwner( + ['user_response_class' => $class], + [], + [ + $this->createMockResponse($this->userResponse, 'application/json; charset=utf-8'), + $this->createMockResponse($this->userResponse, 'application/json; charset=utf-8'), + ] + ); - $this->httpClientCalls = 1; + /** @var CustomUserResponse */ + $userResponse = $resourceOwner->getUserInformation($this->tokenData); + + $this->assertInstanceOf($class, $userResponse); + $this->assertEquals('foo666', $userResponse->getUsername()); + $this->assertEquals('foo', $userResponse->getNickname()); + $this->assertEquals('token', $userResponse->getAccessToken()); + $this->assertNull($userResponse->getRefreshToken()); + $this->assertNull($userResponse->getExpiresIn()); } public function testGetUserInformation() { - $this->httpClientCalls = 2; - - $this->mockHttpClient($this->userResponse, 'application/json; charset=utf-8'); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse($this->userResponse, 'application/json; charset=utf-8'), + $this->createMockResponse($this->userResponse, 'application/json; charset=utf-8'), + ] + ); /** @var AbstractUserResponse $userResponse */ - $userResponse = $this->resourceOwner->getUserInformation($this->tokenData); + $userResponse = $resourceOwner->getUserInformation($this->tokenData); $this->assertEquals('1', $userResponse->getUsername()); $this->assertEquals('example@website.com', $userResponse->getNickname()); @@ -80,7 +101,5 @@ public function testGetUserInformation() $this->assertEquals('token', $userResponse->getAccessToken()); $this->assertNull($userResponse->getRefreshToken()); $this->assertNull($userResponse->getExpiresIn()); - - $this->httpClientCalls = 1; } } diff --git a/Tests/OAuth/ResourceOwner/MailRuResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/MailRuResourceOwnerTest.php index af78177ab..6e57db7f3 100644 --- a/Tests/OAuth/ResourceOwner/MailRuResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/MailRuResourceOwnerTest.php @@ -15,7 +15,7 @@ class MailRuResourceOwnerTest extends GenericOAuth2ResourceOwnerTest { - protected $resourceOwnerClass = MailRuResourceOwner::class; + protected string $resourceOwnerClass = MailRuResourceOwner::class; protected $userResponse = << 'last_name', ]; - protected function setUpResourceOwner($name, HttpUtils $httpUtils, array $options) + protected function setUpResourceOwner(string $name, HttpUtils $httpUtils, array $options, array $responses): ResourceOwnerInterface { return parent::setUpResourceOwner( $name, @@ -43,7 +44,8 @@ protected function setUpResourceOwner($name, HttpUtils $httpUtils, array $option 'application_key' => '123456', ], $options - ) + ), + $responses ); } } diff --git a/Tests/OAuth/ResourceOwner/Office365ResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/Office365ResourceOwnerTest.php index 06638e53b..d8d330da0 100644 --- a/Tests/OAuth/ResourceOwner/Office365ResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/Office365ResourceOwnerTest.php @@ -15,5 +15,5 @@ class Office365ResourceOwnerTest extends GenericOAuth2ResourceOwnerTest { - protected $resourceOwnerClass = Office365ResourceOwner::class; + protected string $resourceOwnerClass = Office365ResourceOwner::class; } diff --git a/Tests/OAuth/ResourceOwner/PaypalResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/PaypalResourceOwnerTest.php index ff17a0cef..294bf271b 100644 --- a/Tests/OAuth/ResourceOwner/PaypalResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/PaypalResourceOwnerTest.php @@ -14,13 +14,11 @@ use HWI\Bundle\OAuthBundle\OAuth\ResourceOwner\PaypalResourceOwner; /** - * Class PaypalResourceOwnerTest. - * * @author Berny Cantos */ class PaypalResourceOwnerTest extends GenericOAuth2ResourceOwnerTest { - protected $resourceOwnerClass = PaypalResourceOwner::class; + protected string $resourceOwnerClass = PaypalResourceOwner::class; protected $userResponse = <<mockHttpClient($this->userResponse); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse($this->userResponse), + ] + ); /** - * @var \HWI\Bundle\OAuthBundle\OAuth\Response\AbstractUserResponse + * @var AbstractUserResponse */ - $userResponse = $this->resourceOwner->getUserInformation(['access_token' => 'token'], ['openid' => '1']); + $userResponse = $resourceOwner->getUserInformation($this->tokenData, ['openid' => '1']); $this->assertEquals('1', $userResponse->getUsername()); $this->assertEquals('bar', $userResponse->getNickname()); @@ -59,12 +68,17 @@ public function testGetUserInformation() public function testCustomResponseClass() { $class = CustomUserResponse::class; - $resourceOwner = $this->createResourceOwner('oauth2', ['user_response_class' => $class]); - $this->mockHttpClient('{"ret": 0}'); + $resourceOwner = $this->createResourceOwner( + ['user_response_class' => $class], + [], + [ + $this->createMockResponse('{"ret": 0}'), + ] + ); /** @var CustomUserResponse $userResponse */ - $userResponse = $resourceOwner->getUserInformation(['access_token' => 'token'], ['openid' => '1']); + $userResponse = $resourceOwner->getUserInformation($this->tokenData, ['openid' => '1']); $this->assertInstanceOf($class, $userResponse); $this->assertEquals('foo666', $userResponse->getUsername()); @@ -74,18 +88,39 @@ public function testCustomResponseClass() $this->assertNull($userResponse->getExpiresIn()); } + public function testGetUserInformationFailure() + { + $this->expectException(AuthenticationException::class); + + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse('invalid', null, 401), + ] + ); + + $resourceOwner->getUserInformation($this->tokenData, ['openid' => '1']); + } + /** * QQ returns access token in jsonp format. */ public function testGetAccessTokenJsonpResponse() { - $this->mockHttpClient('callback({"access_token": "code"});'); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse('callback({"access_token": "code"});'), + ] + ); $request = new Request(['code' => 'somecode']); $this->assertEquals( ['access_token' => 'code'], - $this->resourceOwner->getAccessToken($request, 'http://redirect.to/') + $resourceOwner->getAccessToken($request, 'http://redirect.to/') ); } @@ -94,16 +129,22 @@ public function testGetAccessTokenJsonpResponse() */ public function testGetAccessTokenErrorResponse() { - $this->expectException(\Symfony\Component\Security\Core\Exception\AuthenticationException::class); - - $this->mockHttpClient('callback({"error": 1, "msg": "error"})'); + $this->expectException(AuthenticationException::class); + + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse('callback({"error": 1, "msg": "error"})'), + ] + ); $request = new Request(['code' => 'code']); - $this->resourceOwner->getAccessToken($request, 'http://redirect.to/'); + $resourceOwner->getAccessToken($request, 'http://redirect.to/'); } - protected function setUpResourceOwner($name, HttpUtils $httpUtils, array $options) + protected function setUpResourceOwner(string $name, HttpUtils $httpUtils, array $options, array $responses): ResourceOwnerInterface { return parent::setUpResourceOwner( $name, @@ -116,7 +157,8 @@ protected function setUpResourceOwner($name, HttpUtils $httpUtils, array $option 'me_url' => 'https://graph.qq.com/oauth2.0/me', ], $options - ) + ), + $responses ); } } diff --git a/Tests/OAuth/ResourceOwner/RedditResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/RedditResourceOwnerTest.php index 4aed3d697..191870565 100644 --- a/Tests/OAuth/ResourceOwner/RedditResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/RedditResourceOwnerTest.php @@ -15,7 +15,7 @@ class RedditResourceOwnerTest extends GenericOAuth2ResourceOwnerTest { - protected $resourceOwnerClass = RedditResourceOwner::class; + protected string $resourceOwnerClass = RedditResourceOwner::class; protected $userResponse = <<httpClientCalls) { - $mock = $this->httpClient->expects($this->exactly($this->httpClientCalls)); - } else { - $mock = $this->httpClient->expects($this->once()); - } + return new MockResponse( + $response, + [ + 'http_code' => $httpCode ?: 200, + 'response_headers' => [ + 'Content-Type' => $contentType ?: 'application/json', + ], + ] + ); + } - $mock->method('sendRequest') - ->willReturnCallback(function (RequestInterface $request) use ($response, $contentType) { - $request = $request->withAddedHeader('Content-Type', $contentType ?: $this->httpResponseContentType); - - return MessageFactoryDiscovery::find() - ->createResponse( - $this->httpResponseHttpCode, - null, - $request->getHeaders(), - $response ?: $this->httpResponse - ) - ; - }); + protected function mockHttpClient(string $response = '', string $contentType = 'text/plain') + { + $this->httpClient = new MockHttpClient( + [ + $this->createMockResponse($response, $contentType), + ] + ); } - protected function createResourceOwner(string $name, array $options = [], array $paths = []) + protected function prepareResourceOwnerName(): string { - $this->httpClient = $this->createMock(HttpClient::class); + return str_replace(['generic', 'resourceownertest'], '', strtolower(__CLASS__)); + } + protected function createResourceOwner(array $options = [], array $paths = [], array $responses = []) + { $this->storage = $this->createMock(RequestDataStorageInterface::class); /** @var HttpUtils $httpUtils */ $httpUtils = $this->createMock(HttpUtils::class); - $resourceOwner = $this->setUpResourceOwner($name, $httpUtils, array_merge($this->options, $options)); + $resourceOwner = $this->setUpResourceOwner( + $this->prepareResourceOwnerName(), + $httpUtils, + array_merge($this->options, $options), + $responses + ); $resourceOwner->addPaths(array_merge($this->paths, $paths)); return $resourceOwner; } - /** - * @param string $name - * - * @return \HWI\Bundle\OAuthBundle\OAuth\ResourceOwnerInterface - */ - protected function setUpResourceOwner($name, HttpUtils $httpUtils, array $options) + protected function setUpResourceOwner(string $name, HttpUtils $httpUtils, array $options, array $responses): ResourceOwnerInterface { if (!$this->resourceOwnerClass) { throw new \RuntimeException('Missing resource owner class declaration!'); @@ -94,6 +89,12 @@ protected function setUpResourceOwner($name, HttpUtils $httpUtils, array $option throw new \RuntimeException('Class is not implementing "ResourceOwnerInterface"!'); } - return new $this->resourceOwnerClass(new HttpMethodsClient($this->httpClient, new GuzzleMessageFactory()), $httpUtils, $options, $name, $this->storage); + return new $this->resourceOwnerClass( + $this->httpClient ?: new MockHttpClient($responses), + $httpUtils, + $options, + $name, + $this->storage + ); } } diff --git a/Tests/OAuth/ResourceOwner/RunKeeperResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/RunKeeperResourceOwnerTest.php index 587269cbb..0ed263ffe 100644 --- a/Tests/OAuth/ResourceOwner/RunKeeperResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/RunKeeperResourceOwnerTest.php @@ -14,13 +14,11 @@ use HWI\Bundle\OAuthBundle\OAuth\ResourceOwner\RunKeeperResourceOwner; /** - * RunKeeperResourceOwnerTest. - * * @author Artem Genvald */ class RunKeeperResourceOwnerTest extends GenericOAuth2ResourceOwnerTest { - protected $resourceOwnerClass = RunKeeperResourceOwner::class; + protected string $resourceOwnerClass = RunKeeperResourceOwner::class; /** * {@inheritdoc} */ @@ -41,9 +39,15 @@ class RunKeeperResourceOwnerTest extends GenericOAuth2ResourceOwnerTest public function testGetUserInformation() { - $this->mockHttpClient($this->userResponse, 'application/json; charset=utf-8'); - - $userResponse = $this->resourceOwner->getUserInformation(['access_token' => 'token']); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse($this->userResponse, 'application/json; charset=utf-8'), + ] + ); + + $userResponse = $resourceOwner->getUserInformation(['access_token' => 'token']); $this->assertEquals('Foo Bar', $userResponse->getRealName()); $this->assertEquals('http://www.gravatar.com/avatar/default', $userResponse->getProfilePicture()); diff --git a/Tests/OAuth/ResourceOwner/SalesforceResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/SalesforceResourceOwnerTest.php index 7d49b7a34..c3cfc725d 100644 --- a/Tests/OAuth/ResourceOwner/SalesforceResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/SalesforceResourceOwnerTest.php @@ -11,13 +11,13 @@ namespace HWI\Bundle\OAuthBundle\Tests\OAuth\ResourceOwner; -use Http\Client\Exception\TransferException; use HWI\Bundle\OAuthBundle\OAuth\Exception\HttpTransportException; use HWI\Bundle\OAuthBundle\OAuth\ResourceOwner\SalesforceResourceOwner; +use HWI\Bundle\OAuthBundle\OAuth\Response\AbstractUserResponse; class SalesforceResourceOwnerTest extends GenericOAuth2ResourceOwnerTest { - protected $resourceOwnerClass = SalesforceResourceOwner::class; + protected string $resourceOwnerClass = SalesforceResourceOwner::class; protected $userResponse = <<mockHttpClient($this->userResponse, 'application/json; charset=utf-8'); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse($this->userResponse, 'application/json; charset=utf-8'), + ] + ); /** - * @var \HWI\Bundle\OAuthBundle\OAuth\Response\AbstractUserResponse + * @var AbstractUserResponse */ - $userResponse = $this->resourceOwner->getUserInformation(['access_token' => 'token', 'id' => 'someuser']); + $userResponse = $resourceOwner->getUserInformation( + ['access_token' => 'token', 'id' => 'https://login.salesforce.com/services/oauth2/someuser'] + ); $this->assertEquals('1', $userResponse->getUsername()); $this->assertEquals('bar', $userResponse->getNickname()); @@ -55,18 +63,18 @@ public function testGetUserInformation() public function testGetUserInformationFailure() { - $exception = new TransferException(); + $this->expectException(HttpTransportException::class); - $this->httpClient->expects($this->once()) - ->method('sendRequest') - ->will($this->throwException($exception)); - - try { - $this->resourceOwner->getUserInformation(['access_token' => 'token', 'id' => 'someuser']); - $this->fail('An exception should have been raised'); - } catch (HttpTransportException $e) { - $this->assertSame($exception, $e->getPrevious()); - } + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse('invalid', 'application/json; charset=utf-8', 401), + ] + ); + $resourceOwner->getUserInformation( + ['access_token' => 'token', 'id' => 'https://login.salesforce.com/services/oauth2/someuser'] + ); } public function testCustomResponseClass() diff --git a/Tests/OAuth/ResourceOwner/SensioConnectResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/SensioConnectResourceOwnerTest.php index dd230952a..9009812c1 100644 --- a/Tests/OAuth/ResourceOwner/SensioConnectResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/SensioConnectResourceOwnerTest.php @@ -13,10 +13,11 @@ use HWI\Bundle\OAuthBundle\OAuth\ResourceOwner\SensioConnectResourceOwner; use HWI\Bundle\OAuthBundle\OAuth\Response\SensioConnectUserResponse; +use Symfony\Component\Security\Core\Exception\AuthenticationException; class SensioConnectResourceOwnerTest extends GenericOAuth2ResourceOwnerTest { - protected $resourceOwnerClass = SensioConnectResourceOwner::class; + protected string $resourceOwnerClass = SensioConnectResourceOwner::class; protected $csrf = true; @@ -30,9 +31,13 @@ protected function setUp(): void public function testGetUserInformation() { $class = SensioConnectUserResponse::class; - $resourceOwner = $this->createResourceOwner($this->resourceOwnerName, ['user_response_class' => $class]); - - $this->mockHttpClient($this->userResponse); + $resourceOwner = $this->createResourceOwner( + ['user_response_class' => $class], + [], + [ + $this->createMockResponse($this->userResponse, 'application/xml'), + ] + ); /** * @var SensioConnectUserResponse @@ -46,4 +51,23 @@ public function testGetUserInformation() $this->assertEquals('fake@email.com', $userResponse->getEmail()); $this->assertEquals('token', $userResponse->getAccessToken()); } + + public function testCustomResponseClass() + { + $this->markTestSkipped('SensioConnect already tests this approach'); + } + + public function testGetUserInformationFailure() + { + $this->expectException(AuthenticationException::class); + + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse('invalid', 'application/xml'), + ] + ); + $resourceOwner->getUserInformation(['access_token' => 'token']); + } } diff --git a/Tests/OAuth/ResourceOwner/SinaWeiboResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/SinaWeiboResourceOwnerTest.php index f130a39ee..02556ec3f 100644 --- a/Tests/OAuth/ResourceOwner/SinaWeiboResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/SinaWeiboResourceOwnerTest.php @@ -11,14 +11,14 @@ namespace HWI\Bundle\OAuthBundle\Tests\OAuth\ResourceOwner; -use Http\Client\Exception\TransferException; use HWI\Bundle\OAuthBundle\OAuth\Exception\HttpTransportException; use HWI\Bundle\OAuthBundle\OAuth\ResourceOwner\SinaWeiboResourceOwner; +use HWI\Bundle\OAuthBundle\OAuth\Response\AbstractUserResponse; use HWI\Bundle\OAuthBundle\Tests\Fixtures\CustomUserResponse; class SinaWeiboResourceOwnerTest extends GenericOAuth2ResourceOwnerTest { - protected $resourceOwnerClass = SinaWeiboResourceOwner::class; + protected string $resourceOwnerClass = SinaWeiboResourceOwner::class; protected $userResponse = <<mockHttpClient($this->userResponse); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse($this->userResponse), + ] + ); /** - * @var \HWI\Bundle\OAuthBundle\OAuth\Response\AbstractUserResponse + * @var AbstractUserResponse */ - $userResponse = $this->resourceOwner->getUserInformation(['access_token' => 'token', 'uid' => '1']); + $userResponse = $resourceOwner->getUserInformation(['access_token' => 'token', 'uid' => '1']); $this->assertEquals('1', $userResponse->getUsername()); $this->assertEquals('bar', $userResponse->getNickname()); @@ -51,29 +57,32 @@ public function testGetUserInformation() public function testGetUserInformationFailure() { - $exception = new TransferException(); - - $this->httpClient->expects($this->once()) - ->method('sendRequest') - ->will($this->throwException($exception)); + $this->expectException(HttpTransportException::class); - try { - $this->resourceOwner->getUserInformation(['access_token' => 'token', 'uid' => 'someuser']); - $this->fail('An exception should have been raised'); - } catch (HttpTransportException $e) { - $this->assertSame($exception, $e->getPrevious()); - } + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse('invalid'), + ] + ); + $resourceOwner->getUserInformation(['access_token' => 'token', 'uid' => 'someuser']); } public function testCustomResponseClass() { $class = CustomUserResponse::class; - $resourceOwner = $this->createResourceOwner('oauth2', ['user_response_class' => $class]); - $this->mockHttpClient(); + $resourceOwner = $this->createResourceOwner( + ['user_response_class' => $class], + [], + [ + $this->createMockResponse($this->userResponse), + ] + ); /** - * @var \HWI\Bundle\OAuthBundle\Tests\Fixtures\CustomUserResponse + * @var CustomUserResponse */ $userResponse = $resourceOwner->getUserInformation(['access_token' => 'token', 'uid' => '1']); diff --git a/Tests/OAuth/ResourceOwner/SlackResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/SlackResourceOwnerTest.php index 8a4627146..6ce26b2c4 100644 --- a/Tests/OAuth/ResourceOwner/SlackResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/SlackResourceOwnerTest.php @@ -15,7 +15,7 @@ class SlackResourceOwnerTest extends GenericOAuth2ResourceOwnerTest { - protected $resourceOwnerClass = SlackResourceOwner::class; + protected string $resourceOwnerClass = SlackResourceOwner::class; protected $userResponse = <<mockHttpClient($this->userResponse); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse($this->userResponse), + ] + ); /** - * @var \HWI\Bundle\OAuthBundle\OAuth\Response\AbstractUserResponse + * @var AbstractUserResponse */ - $userResponse = $this->resourceOwner->getUserInformation(['access_token' => 'token']); + $userResponse = $resourceOwner->getUserInformation(['access_token' => 'token']); $this->assertEquals('wizzler', $userResponse->getUsername()); $this->assertEquals('wizzler', $userResponse->getNickname()); @@ -73,9 +80,13 @@ public function testGetUserInformation() public function testCustomResponseClass() { $class = CustomUserResponse::class; - $resourceOwner = $this->createResourceOwner('oauth2', ['user_response_class' => $class]); - - $this->mockHttpClient(); + $resourceOwner = $this->createResourceOwner( + ['user_response_class' => $class], + [], + [ + $this->createMockResponse($this->userResponse), + ] + ); /** * @var CustomUserResponse diff --git a/Tests/OAuth/ResourceOwner/StackExchangeResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/StackExchangeResourceOwnerTest.php index df2c73f46..9f49b63bb 100644 --- a/Tests/OAuth/ResourceOwner/StackExchangeResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/StackExchangeResourceOwnerTest.php @@ -12,11 +12,12 @@ namespace HWI\Bundle\OAuthBundle\Tests\OAuth\ResourceOwner; use HWI\Bundle\OAuthBundle\OAuth\ResourceOwner\StackExchangeResourceOwner; +use HWI\Bundle\OAuthBundle\OAuth\ResourceOwnerInterface; use Symfony\Component\Security\Http\HttpUtils; class StackExchangeResourceOwnerTest extends GenericOAuth2ResourceOwnerTest { - protected $resourceOwnerClass = StackExchangeResourceOwner::class; + protected string $resourceOwnerClass = StackExchangeResourceOwner::class; protected $userResponse = << 'baz']) + array_merge($options, ['key' => 'baz']), + $responses ); } } diff --git a/Tests/OAuth/ResourceOwner/StereomoodResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/StereomoodResourceOwnerTest.php index 0ffb40679..4258eeef8 100644 --- a/Tests/OAuth/ResourceOwner/StereomoodResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/StereomoodResourceOwnerTest.php @@ -16,7 +16,7 @@ class StereomoodResourceOwnerTest extends GenericOAuth1ResourceOwnerTest { - protected $resourceOwnerClass = StereomoodResourceOwner::class; + protected string $resourceOwnerClass = StereomoodResourceOwner::class; protected $userResponse = << 'secret', ]; - $userResponse = $this->resourceOwner->getUserInformation($accessToken); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse($this->userResponse), + ] + ); + $userResponse = $resourceOwner->getUserInformation($accessToken); $this->assertEquals('token', $userResponse->getUsername()); $this->assertEquals('token', $userResponse->getNickname()); @@ -47,7 +54,7 @@ public function testGetUserInformation() public function testCustomResponseClass() { $class = CustomUserResponse::class; - $resourceOwner = $this->createResourceOwner('oauth1', ['user_response_class' => $class]); + $resourceOwner = $this->createResourceOwner(['user_response_class' => $class]); $accessToken = [ 'oauth_token' => 'token', diff --git a/Tests/OAuth/ResourceOwner/StravaResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/StravaResourceOwnerTest.php index b475ffb9b..99110550e 100644 --- a/Tests/OAuth/ResourceOwner/StravaResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/StravaResourceOwnerTest.php @@ -14,13 +14,11 @@ use HWI\Bundle\OAuthBundle\OAuth\ResourceOwner\StravaResourceOwner; /** - * StravaResourceOwnerTest. - * * @author Artem Genvald */ class StravaResourceOwnerTest extends GenericOAuth2ResourceOwnerTest { - protected $resourceOwnerClass = StravaResourceOwner::class; + protected string $resourceOwnerClass = StravaResourceOwner::class; /** * {@inheritdoc} */ @@ -46,9 +44,15 @@ class StravaResourceOwnerTest extends GenericOAuth2ResourceOwnerTest public function testGetUserInformation() { - $this->mockHttpClient($this->userResponse, 'application/json; charset=utf-8'); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse($this->userResponse, 'application/json; charset=utf-8'), + ] + ); - $userResponse = $this->resourceOwner->getUserInformation(['access_token' => 'token']); + $userResponse = $resourceOwner->getUserInformation(['access_token' => 'token']); $this->assertEquals('1', $userResponse->getUsername()); $this->assertEquals('Foo Bar', $userResponse->getRealName()); diff --git a/Tests/OAuth/ResourceOwner/ThirtySevenSignalsResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/ThirtySevenSignalsResourceOwnerTest.php index 9488d1238..31ef0e26e 100644 --- a/Tests/OAuth/ResourceOwner/ThirtySevenSignalsResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/ThirtySevenSignalsResourceOwnerTest.php @@ -15,7 +15,7 @@ class ThirtySevenSignalsResourceOwnerTest extends GenericOAuth2ResourceOwnerTest { - protected $resourceOwnerClass = ThirtySevenSignalsResourceOwner::class; + protected string $resourceOwnerClass = ThirtySevenSignalsResourceOwner::class; protected $userResponse = <<httpResponseHttpCode = 204; - $this->mockHttpClient(null, 'application/json'); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse(null, 'application/json', 204), + ] + ); - $this->assertTrue($this->resourceOwner->revokeToken('token')); + $this->assertTrue($resourceOwner->revokeToken('token')); } public function testRevokeTokenFails() { - $this->httpResponseHttpCode = 404; - $this->mockHttpClient('{"id": "666"}', 'application/json'); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse('{"id": "666"}', 'application/json', 404), + ] + ); - $this->assertFalse($this->resourceOwner->revokeToken('token')); + $this->assertFalse($resourceOwner->revokeToken('token')); } public function testGetUserInformation() { - $this->mockHttpClient($this->userResponse, 'application/json; charset=utf-8'); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse($this->userResponse, 'application/json; charset=utf-8'), + ] + ); /** - * @var \HWI\Bundle\OAuthBundle\OAuth\Response\AbstractUserResponse + * @var AbstractUserResponse */ - $userResponse = $this->resourceOwner->getUserInformation(['access_token' => 'token']); + $userResponse = $resourceOwner->getUserInformation(['access_token' => 'token']); $this->assertEquals('1', $userResponse->getUsername()); $this->assertEquals('example@website.com', $userResponse->getNickname()); diff --git a/Tests/OAuth/ResourceOwner/TraktResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/TraktResourceOwnerTest.php index cbfe56930..abd6a3cf2 100644 --- a/Tests/OAuth/ResourceOwner/TraktResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/TraktResourceOwnerTest.php @@ -15,7 +15,7 @@ class TraktResourceOwnerTest extends GenericOAuth2ResourceOwnerTest { - protected $resourceOwnerClass = TraktResourceOwner::class; + protected string $resourceOwnerClass = TraktResourceOwner::class; protected $userResponse = <<mockHttpClient($this->userResponse, 'application/json; charset=utf-8'); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse($this->userResponse, 'application/json; charset=utf-8'), + ] + ); $accessToken = ['oauth_token' => 'token', 'oauth_token_secret' => 'secret', 'access_token' => 'token']; - $userResponse = $this->resourceOwner->getUserInformation($accessToken); + $userResponse = $resourceOwner->getUserInformation($accessToken); $this->assertEquals('georges', $userResponse->getUsername()); $this->assertEquals('georges', $userResponse->getNickname()); diff --git a/Tests/OAuth/ResourceOwner/TrelloResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/TrelloResourceOwnerTest.php index 49d49e4f4..3a240244e 100644 --- a/Tests/OAuth/ResourceOwner/TrelloResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/TrelloResourceOwnerTest.php @@ -15,7 +15,7 @@ class TrelloResourceOwnerTest extends GenericOAuth1ResourceOwnerTest { - protected $resourceOwnerClass = TrelloResourceOwner::class; + protected string $resourceOwnerClass = TrelloResourceOwner::class; protected $userResponse = <<mockHttpClient('{"oauth_token": "token", "oauth_token_secret": "secret"}', 'application/json; charset=utf-8'); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse('{"oauth_token": "token", "oauth_token_secret": "secret"}', 'application/json; charset=utf-8'), + ] + ); $this->storage->expects($this->once()) ->method('save') - ->with($this->resourceOwner, ['oauth_token' => 'token', 'oauth_token_secret' => 'secret', 'timestamp' => time()]); + ->with($resourceOwner, ['oauth_token' => 'token', 'oauth_token_secret' => 'secret', 'timestamp' => time()]); $this->assertEquals( 'http://user.auth/?test=3&scope=read&oauth_token=token', - $this->resourceOwner->getAuthorizationUrl('http://redirect.to/') + $resourceOwner->getAuthorizationUrl('http://redirect.to/') ); } } diff --git a/Tests/OAuth/ResourceOwner/TwitchResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/TwitchResourceOwnerTest.php index 7fe9fca54..a6de61317 100644 --- a/Tests/OAuth/ResourceOwner/TwitchResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/TwitchResourceOwnerTest.php @@ -15,7 +15,7 @@ class TwitchResourceOwnerTest extends GenericOAuth2ResourceOwnerTest { - protected $resourceOwnerClass = TwitchResourceOwner::class; + protected string $resourceOwnerClass = TwitchResourceOwner::class; protected $userResponse = <<createResourceOwner($this->resourceOwnerName, ['include_email' => true]); + $resourceOwner = $this->createResourceOwner( + ['include_email' => true], + [], + [ + $this->createMockResponse($this->userResponse, 'application/json; charset=utf-8'), + ] + ); + $accessToken = ['oauth_token' => 'token', 'oauth_token_secret' => 'secret', 'user_id' => '1', 'screen_name' => 'bar']; $resourceOwner->getUserInformation($accessToken); @@ -40,10 +47,16 @@ public function testGetUserInformationWithEmail() public function testGetUserInformation() { - $this->mockHttpClient($this->userResponse, 'application/json; charset=utf-8'); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse($this->userResponse, 'application/json; charset=utf-8'), + ] + ); $accessToken = ['oauth_token' => 'token', 'oauth_token_secret' => 'secret', 'user_id' => '1', 'screen_name' => 'bar']; - $userResponse = $this->resourceOwner->getUserInformation($accessToken); + $userResponse = $resourceOwner->getUserInformation($accessToken); $this->assertEquals('1', $userResponse->getUsername()); $this->assertEquals('bar', $userResponse->getNickname()); diff --git a/Tests/OAuth/ResourceOwner/VkontakteResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/VkontakteResourceOwnerTest.php index d34ee8a2e..f27c72ad6 100644 --- a/Tests/OAuth/ResourceOwner/VkontakteResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/VkontakteResourceOwnerTest.php @@ -15,7 +15,7 @@ class VkontakteResourceOwnerTest extends GenericOAuth2ResourceOwnerTest { - protected $resourceOwnerClass = VkontakteResourceOwner::class; + protected string $resourceOwnerClass = VkontakteResourceOwner::class; protected $userResponse = <<mockHttpClient($this->userResponse, 'application/json; charset=utf-8'); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse($this->userResponse, 'application/json; charset=utf-8'), + ] + ); $accessToken = ['oauth_token' => 'token', 'oauth_token_secret' => 'secret']; - $userResponse = $this->resourceOwner->getUserInformation($accessToken); + $userResponse = $resourceOwner->getUserInformation($accessToken); $this->assertEquals('42', $userResponse->getUsername()); $this->assertEquals('foo bar', $userResponse->getNickname()); diff --git a/Tests/OAuth/ResourceOwner/YahooResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/YahooResourceOwnerTest.php index 34be83b99..ff95cddc1 100644 --- a/Tests/OAuth/ResourceOwner/YahooResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/YahooResourceOwnerTest.php @@ -16,7 +16,7 @@ class YahooResourceOwnerTest extends GenericOAuth1ResourceOwnerTest { - protected $resourceOwnerClass = YahooResourceOwner::class; + protected string $resourceOwnerClass = YahooResourceOwner::class; protected $userResponse = <<mockHttpClient($this->userResponse, 'application/json; charset=utf-8'); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse($this->userResponse, 'application/json; charset=utf-8'), + ] + ); $accessToken = ['oauth_token' => 'token', 'oauth_token_secret' => 'secret', 'xoauth_yahoo_guid' => 1]; - $userResponse = $this->resourceOwner->getUserInformation($accessToken); + $userResponse = $resourceOwner->getUserInformation($accessToken); $this->assertEquals('1', $userResponse->getUsername()); $this->assertEquals('bar', $userResponse->getNickname()); @@ -48,9 +54,13 @@ public function testGetUserInformation() public function testCustomResponseClass() { $class = CustomUserResponse::class; - $resourceOwner = $this->createResourceOwner('oauth1', ['user_response_class' => $class]); - - $this->mockHttpClient(); + $resourceOwner = $this->createResourceOwner( + ['user_response_class' => $class], + [], + [ + $this->createMockResponse($this->userResponse), + ] + ); /** * @var CustomUserResponse diff --git a/Tests/OAuth/ResourceOwner/YandexResourceOwnerTest.php b/Tests/OAuth/ResourceOwner/YandexResourceOwnerTest.php index 3e57116e1..b0ff6c14a 100644 --- a/Tests/OAuth/ResourceOwner/YandexResourceOwnerTest.php +++ b/Tests/OAuth/ResourceOwner/YandexResourceOwnerTest.php @@ -15,7 +15,7 @@ class YandexResourceOwnerTest extends GenericOAuth2ResourceOwnerTest { - protected $resourceOwnerClass = YandexResourceOwner::class; + protected string $resourceOwnerClass = YandexResourceOwner::class; protected $userResponse = <<expectException(\Symfony\Component\OptionsResolver\Exception\InvalidOptionsException::class); + $this->expectException(InvalidOptionsException::class); - $this->createResourceOwner($this->resourceOwnerName, ['access_type' => 'invalid']); + $this->createResourceOwner(['access_type' => 'invalid']); } public function testInvalidApprovalPromptOptionValueThrowsException() { - $this->expectException(\Symfony\Component\OptionsResolver\Exception\InvalidOptionsException::class); + $this->expectException(InvalidOptionsException::class); - $this->createResourceOwner($this->resourceOwnerName, ['approval_prompt' => 'invalid']); + $this->createResourceOwner(['approval_prompt' => 'invalid']); } public function testGetAuthorizationUrl() { + $resourceOwner = $this->createResourceOwner(); + $this->assertEquals( $this->options['authorization_url'].'&response_type=code&client_id=clientid&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fyoutube.readonly&state=eyJzdGF0ZSI6InJhbmRvbSJ9&redirect_uri=http%3A%2F%2Fredirect.to%2F&access_type=offline', - $this->resourceOwner->getAuthorizationUrl('http://redirect.to/') + $resourceOwner->getAuthorizationUrl('http://redirect.to/') ); } public function testRequestVisibleActions() { - $resourceOwner = $this->createResourceOwner($this->resourceOwnerName, ['request_visible_actions' => 'http://schemas.google.com/AddActivity'] + $resourceOwner = $this->createResourceOwner( + ['request_visible_actions' => 'http://schemas.google.com/AddActivity'] ); $this->assertEquals( @@ -70,7 +75,7 @@ public function testRequestVisibleActions() public function testApprovalPromptForce() { - $resourceOwner = $this->createResourceOwner($this->resourceOwnerName, ['approval_prompt' => 'force']); + $resourceOwner = $this->createResourceOwner(['approval_prompt' => 'force']); $this->assertEquals( $this->options['authorization_url'].'&response_type=code&client_id=clientid&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fyoutube.readonly&state=eyJzdGF0ZSI6InJhbmRvbSJ9&redirect_uri=http%3A%2F%2Fredirect.to%2F&access_type=offline&approval_prompt=force', @@ -80,7 +85,7 @@ public function testApprovalPromptForce() public function testHdParameter() { - $resourceOwner = $this->createResourceOwner($this->resourceOwnerName, ['hd' => 'mycollege.edu']); + $resourceOwner = $this->createResourceOwner(['hd' => 'mycollege.edu']); $this->assertEquals( $this->options['authorization_url'].'&response_type=code&client_id=clientid&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fyoutube.readonly&state=eyJzdGF0ZSI6InJhbmRvbSJ9&redirect_uri=http%3A%2F%2Fredirect.to%2F&access_type=offline&hd=mycollege.edu', $resourceOwner->getAuthorizationUrl('http://redirect.to/') @@ -89,21 +94,31 @@ public function testHdParameter() public function testRevokeToken() { - $this->httpResponseHttpCode = 200; - $this->mockHttpClient('{"access_token": "bar"}', 'application/json'); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse('{"access_token": "bar"}', 'application/json'), + ] + ); - $this->assertTrue($this->resourceOwner->revokeToken('token')); + $this->assertTrue($resourceOwner->revokeToken('token')); } public function testRevokeTokenFails() { - $this->httpResponseHttpCode = 401; - $this->mockHttpClient('{"access_token": "bar"}', 'application/json'); + $resourceOwner = $this->createResourceOwner( + [], + [], + [ + $this->createMockResponse('{"access_token": "bar"}', 'application/json', 401), + ] + ); - $this->assertFalse($this->resourceOwner->revokeToken('token')); + $this->assertFalse($resourceOwner->revokeToken('token')); } - protected function setUpResourceOwner($name, HttpUtils $httpUtils, array $options) + protected function setUpResourceOwner(string $name, HttpUtils $httpUtils, array $options, array $responses): ResourceOwnerInterface { return parent::setUpResourceOwner( $name, @@ -113,7 +128,8 @@ protected function setUpResourceOwner($name, HttpUtils $httpUtils, array $option 'access_type' => 'offline', ], $options - ) + ), + $responses ); } } diff --git a/composer.json b/composer.json index d18b2f3e3..fd4f9b865 100644 --- a/composer.json +++ b/composer.json @@ -100,13 +100,7 @@ "symfony/form": "^4.4|^5.1", "symfony/yaml": "^4.4|^5.1", "symfony/templating": "^4.4|^5.1", - - "psr/http-message": "^1.0", - "php-http/client-implementation": "^1.0", - "php-http/httplug": "^2.0", - "php-http/client-common": "^2.0", - "php-http/message-factory": "^1.0", - "php-http/discovery": "^1.0" + "symfony/http-client": "^5.3" }, "require-dev": { @@ -119,8 +113,6 @@ "symfony/twig-bundle": "^4.4|^5.1", "symfony/stopwatch": "^5.1", "symfony/translation": "^4.4|^5.1", - "php-http/httplug-bundle": "^1.7", - "php-http/guzzle6-adapter": "^2.0", "phpunit/phpunit": "^9.5", "friendsofphp/php-cs-fixer": "^3.0", "symfony/monolog-bundle": "^3.4", @@ -142,7 +134,6 @@ "suggest": { "doctrine/doctrine-bundle": "to use Doctrine user provider", - "php-http/httplug-bundle": "to provide required HTTP client with ease.", "symfony/property-access": "to use FOSUB integration with this bundle", "symfony/twig-bundle": "to use the Twig hwi_oauth_* functions" },