From 2aa318cfd732ada3cf5623a5918e75203a033764 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 6 Apr 2014 19:14:46 +0100 Subject: [PATCH] AuthCode grant --- src/League/OAuth2/Server/Entity/AuthCode.php | 42 ++ src/League/OAuth2/Server/Grant/AuthCode.php | 191 +++--- tests/Entities/AuthCodeTest.php | 21 +- tests/Grant/AuthCodeTest.php | 615 +++++++++++++++++++ 4 files changed, 786 insertions(+), 83 deletions(-) create mode 100644 tests/Grant/AuthCodeTest.php diff --git a/src/League/OAuth2/Server/Entity/AuthCode.php b/src/League/OAuth2/Server/Entity/AuthCode.php index 7bfcae10..ea0ec9de 100644 --- a/src/League/OAuth2/Server/Entity/AuthCode.php +++ b/src/League/OAuth2/Server/Entity/AuthCode.php @@ -22,6 +22,48 @@ use Symfony\Component\HttpFoundation\ParameterBag; */ class AuthCode extends AbstractToken { + /** + * Redirect URI + * @var string + */ + protected $redirectUri = ''; + + /** + * Set the redirect URI for the authorization request + * @param string $redirectUri + * @return self + */ + public function setRedirectUri($redirectUri) + { + $this->redirectUri = $redirectUri; + return $this; + } + + /** + * Get the redirect URI + * @return string + */ + public function getRedirectUri() + { + return $this->redirectUri; + } + + /** + * [generateRedirectUri description] + * @param string $state The state parameter if set by the client + * @param string $queryDelimeter The query delimiter ('?' for auth code grant, '#' for implicit grant) + * @return string + */ + public function generateRedirectUri($state = null, $queryDelimeter = '?') + { + $uri = $this->getRedirectUri(); + $uri .= (strstr($this->getRedirectUri(), $queryDelimeter) === false) ? $queryDelimeter : '&'; + return $uri.http_build_query([ + 'code' => $this->getToken(), + 'state' => $state + ]); + } + /** * {@inheritdoc} */ diff --git a/src/League/OAuth2/Server/Grant/AuthCode.php b/src/League/OAuth2/Server/Grant/AuthCode.php index 9d6549a9..39271433 100644 --- a/src/League/OAuth2/Server/Grant/AuthCode.php +++ b/src/League/OAuth2/Server/Grant/AuthCode.php @@ -11,21 +11,26 @@ namespace League\OAuth2\Server\Grant; +use League\OAuth2\Server\AuthorizationServer; use League\OAuth2\Server\Request; -use League\OAuth2\Server\Authorization; use League\OAuth2\Server\Exception; +use League\OAuth2\Server\Entity\Client; +use League\OAuth2\Server\Entity\RefreshToken; +use League\OAuth2\Server\Entity\Session; +use League\OAuth2\Server\Entity\AccessToken; +use League\OAuth2\Server\Entity\Scope; +use League\OAuth2\Server\Entity\AuthCode as AC; use League\OAuth2\Server\Util\SecureKey; use League\OAuth2\Server\Storage\SessionInterface; use League\OAuth2\Server\Storage\ClientInterface; use League\OAuth2\Server\Storage\ScopeInterface; +use League\OAuth2\Server\Exception\ClientException; /** * Auth code grant class */ -class AuthCode implements GrantTypeInterface { - - use GrantTrait; - +class AuthCode extends AbstractGrant +{ /** * Grant identifier * @var string @@ -74,9 +79,7 @@ class AuthCode implements GrantTypeInterface { */ public function checkAuthoriseParams() { - // Auth params - $authParams = $this->server->getParam(array('client_id', 'redirect_uri', 'response_type', 'scope', 'state'), 'get', $inputParams); - + // Get required params $clientId = $this->server->getRequest()->request->get('client_id', null); if (is_null($clientId)) { throw new ClientException( @@ -150,28 +153,27 @@ class AuthCode implements GrantTypeInterface { * @param array $authParams The authorise request $_GET parameters * @return string An authorisation code */ - public function newAuthoriseRequest($type =, $typeId, $authParams = []) + public function newAuthoriseRequest($type, $typeId, $authParams = []) { - // Generate an auth code - $authCode = SecureKey::make(); - // Create a new session $session = new Session($this->server); $session->setOwner($type, $typeId); $session->associateClient($authParams['client']); + $session->save(); - // Associate a redirect URI - $this->server->getStorage('session')->associateRedirectUri($sessionId, $authParams['redirect_uri']); + // Create a new auth code + $authCode = new AC($this->server); + $authCode->setToken(SecureKey::make()); + $authCode->setRedirectUri($authParams['redirect_uri']); - // Associate the auth code - $authCodeId = $this->server->getStorage('session')->associateAuthCode($sessionId, $authCode, time() + $this->authTokenTTL); - - // Associate the scopes to the auth code foreach ($authParams['scopes'] as $scope) { - $this->server->getStorage('session')->associateAuthCodeScope($authCodeId, $scope['id']); + $authCode->associateScope($scope); } - return $authCode; + $authCode->setSession($session); + $authCode->save(); + + return $authCode->generateRedirectUri($authParams['state']); } /** @@ -182,78 +184,107 @@ class AuthCode implements GrantTypeInterface { public function completeFlow($inputParams = null) { // Get the required params - $authParams = $this->server->getParam(array('client_id', 'client_secret', 'redirect_uri', 'code'), 'post', $inputParams); - - if (is_null($authParams['client_id'])) { - throw new Exception\ClientException(sprintf($this->server->getExceptionMessage('invalid_request'), 'client_id'), 0); + $clientId = $this->server->getRequest()->request->get('client_id', null); + if (is_null($clientId)) { + throw new ClientException( + sprintf(AuthorizationServer::getExceptionMessage('invalid_request'), 'client_id'), + 0 + ); } - if (is_null($authParams['client_secret'])) { - throw new Exception\ClientException(sprintf($this->server->getExceptionMessage('invalid_request'), 'client_secret'), 0); + $clientSecret = $this->server->getRequest()->request->get('client_secret', null); + if (is_null($clientSecret)) { + throw new ClientException( + sprintf(AuthorizationServer::getExceptionMessage('invalid_request'), 'client_secret'), + 0 + ); } - if (is_null($authParams['redirect_uri'])) { - throw new Exception\ClientException(sprintf($this->server->getExceptionMessage('invalid_request'), 'redirect_uri'), 0); + $redirectUri = $this->server->getRequest()->request->get('redirect_uri', null); + if (is_null($redirectUri)) { + throw new ClientException( + sprintf(AuthorizationServer::getExceptionMessage('invalid_request'), 'redirect_uri'), + 0 + ); } - // Validate client ID and redirect URI - $clientDetails = $this->server->getStorage('client')->getClient($authParams['client_id'], $authParams['client_secret'], $authParams['redirect_uri'], $this->identifier); - - if ($clientDetails === false) { - throw new Exception\ClientException($this->server->getExceptionMessage('invalid_client'), 8); - } - - $authParams['client_details'] = $clientDetails; - - // Validate the authorization code - if (is_null($authParams['code'])) { - throw new Exception\ClientException(sprintf($this->server->getExceptionMessage('invalid_request'), 'code'), 0); - } - - // Verify the authorization code matches the client_id and the request_uri - $authCodeDetails = $this->server->getStorage('session')->validateAuthCode($authParams['client_id'], $authParams['redirect_uri'], $authParams['code']); - - if ( ! $authCodeDetails) { - throw new Exception\ClientException(sprintf($this->server->getExceptionMessage('invalid_grant'), 'code'), 9); - } - - // Get any associated scopes - $scopes = $this->server->getStorage('session')->getAuthCodeScopes($authCodeDetails['authcode_id']); - - // A session ID was returned so update it with an access token and remove the authorisation code - $accessToken = SecureKey::make(); - $accessTokenExpiresIn = ($this->accessTokenTTL !== null) ? $this->accessTokenTTL : $this->server->getAccessTokenTTL(); - $accessTokenExpires = time() + $accessTokenExpiresIn; - - // Remove the auth code - $this->server->getStorage('session')->removeAuthCode($authCodeDetails['session_id']); - - // Create an access token - $accessTokenId = $this->server->getStorage('session')->associateAccessToken($authCodeDetails['session_id'], $accessToken, $accessTokenExpires); - - // Associate scopes with the access token - if (count($scopes) > 0) { - foreach ($scopes as $scope) { - $this->server->getStorage('session')->associateScope($accessTokenId, $scope['scope_id']); - } - } - - $response = array( - 'access_token' => $accessToken, - 'token_type' => 'Bearer', - 'expires' => $accessTokenExpires, - 'expires_in' => $accessTokenExpiresIn + // Validate client ID and client secret + $client = $this->server->getStorage('client')->get( + $clientId, + $clientSecret, + $redirectUri, + $this->getIdentifier() ); + if (($client instanceof Client) === false) { + throw new ClientException(AuthorizationServer::getExceptionMessage('invalid_client'), 8); + } + + // Validate the auth code + $authCode = $this->server->getRequest()->request->get('code', null); + if (is_null($authCode)) { + throw new ClientException( + sprintf(AuthorizationServer::getExceptionMessage('invalid_request'), 'code'), + 0 + ); + } + + $code = $this->server->getStorage('auth_code')->get($authCode); + if (($code instanceof AC) === false) { + throw new ClientException( + sprintf(AuthorizationServer::getExceptionMessage('invalid_request'), 'code'), + 9 + ); + } + + // Check redirect URI presented matches redirect URI originally used in authorise request + if ($code->getRedirectUri() !== $redirectUri) { + throw new ClientException( + sprintf(AuthorizationServer::getExceptionMessage('invalid_request'), 'redirect_uri'), + 9 + ); + } + + $session = $code->getSession(); + $authCodeScopes = $code->getScopes(); + + // Generate the access token + $accessToken = new AccessToken($this->server); + $accessToken->setToken(SecureKey::make()); + $accessToken->setExpireTime($this->server->getAccessTokenTTL() + time()); + + foreach ($authCodeScopes as $authCodeScope) { + $session->associateScope($authCodeScope); + } + + $response = [ + 'access_token' => $accessToken->getToken(), + 'token_type' => 'Bearer', + 'expires' => $accessToken->getExpireTime(), + 'expires_in' => $this->server->getAccessTokenTTL() + ]; + // Associate a refresh token if set if ($this->server->hasGrantType('refresh_token')) { - $refreshToken = SecureKey::make(); - $refreshTokenTTL = time() + $this->server->getGrantType('refresh_token')->getRefreshTokenTTL(); - $this->server->getStorage('session')->associateRefreshToken($accessTokenId, $refreshToken, $refreshTokenTTL, $authParams['client_id']); - $response['refresh_token'] = $refreshToken; + $refreshToken = new RefreshToken($this->server); + $refreshToken->setToken(SecureKey::make()); + $refreshToken->setExpireTime($this->server->getGrantType('refresh_token')->getRefreshTokenTTL() + time()); + $response['refresh_token'] = $refreshToken->getToken(); + } + + // Expire the auth code + $code->expire(); + + // Save all the things + $session->save(); + $accessToken->setSession($session); + $accessToken->save(); + + if ($this->server->hasGrantType('refresh_token')) { + $refreshToken->setAccessToken($accessToken); + $refreshToken->save(); } return $response; } - } diff --git a/tests/Entities/AuthCodeTest.php b/tests/Entities/AuthCodeTest.php index 0d325ea6..6499f76f 100644 --- a/tests/Entities/AuthCodeTest.php +++ b/tests/Entities/AuthCodeTest.php @@ -5,14 +5,29 @@ namespace LeagueTests\Entities; use League\OAuth2\Server\Entity\Scope; use League\OAuth2\Server\Entity\Session; use League\OAuth2\Server\Entity\AuthCode; -use League\OAuth2\Server\AuthorizationServer as Authorization; +use League\OAuth2\Server\AuthorizationServer; use \Mockery as M; class AuthCodeTest extends \PHPUnit_Framework_TestCase { + function testSetGet() + { + $server = new AuthorizationServer; + $session = M::mock('League\OAuth2\Server\Entity\Session'); + + $code = new AuthCode($server); + $code->setRedirectUri('http://foo/bar'); + $code->setToken('foobar'); + $code->setSession($session); + + $this->assertEquals('http://foo/bar', $code->getRedirectUri()); + $this->assertEquals('http://foo/bar?code=foobar', $code->generateRedirectUri()); + $this->assertTrue($code->getSession() instanceof \League\OAuth2\Server\Entity\Session); + } + function testSave() { - $server = new Authorization(); + $server = new AuthorizationServer(); $authCodeStorage = M::mock('League\OAuth2\Server\Storage\AuthCodeInterface'); $authCodeStorage->shouldReceive('create'); @@ -37,7 +52,7 @@ class AuthCodeTest extends \PHPUnit_Framework_TestCase function testExpire() { - $server = new Authorization(); + $server = new AuthorizationServer(); $authCodeStorage = M::mock('League\OAuth2\Server\Storage\AuthCodeInterface'); $authCodeStorage->shouldReceive('delete'); diff --git a/tests/Grant/AuthCodeTest.php b/tests/Grant/AuthCodeTest.php new file mode 100644 index 00000000..ecd04309 --- /dev/null +++ b/tests/Grant/AuthCodeTest.php @@ -0,0 +1,615 @@ +setAuthTokenTTL(100); + + $class = new \ReflectionClass($grant); + $property = $class->getProperty('authTokenTTL'); + $property->setAccessible(true); + $this->assertEquals(100, $property->getValue($grant)); + } + + public function testCheckAuthoriseParamsMissingClientId() + { + $this->setExpectedException('League\OAuth2\Server\Exception\ClientException', 'The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the "client_id" parameter.'); + + $_POST = []; + + $server = new Authorization; + $grant = new AuthCode; + + $server->addGrantType($grant); + $grant->checkAuthoriseParams(); + + } + + public function testCheckAuthoriseParamsMissingRedirectUri() + { + $this->setExpectedException('League\OAuth2\Server\Exception\ClientException', 'The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the "redirect_uri" parameter.'); + + $_POST = [ + 'client_id' => 'testapp' + ]; + + $server = new Authorization; + $grant = new AuthCode; + + $server->addGrantType($grant); + $grant->checkAuthoriseParams(); + } + + public function testCheckAuthoriseParamsMissingStateParam() + { + $this->setExpectedException('League\OAuth2\Server\Exception\ClientException', 'The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the "state" parameter.'); + + $_POST = [ + 'client_id' => 'testapp', + 'redirect_uri' => 'http://foo/bar' + ]; + + $server = new Authorization; + $server->requireStateParam(true); + $grant = new AuthCode; + + $server->addGrantType($grant); + $grant->checkAuthoriseParams(); + } + + public function testCheckAuthoriseParamsMissingResponseType() + { + $this->setExpectedException('League\OAuth2\Server\Exception\ClientException', 'The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the "response_type" parameter.'); + + $_POST = [ + 'client_id' => 'testapp', + 'redirect_uri' => 'http://foo/bar' + ]; + + $server = new Authorization; + $grant = new AuthCode; + + $server->addGrantType($grant); + $grant->checkAuthoriseParams(); + } + + public function testCheckAuthoriseParamsInvalidResponseType() + { + $this->setExpectedException('League\OAuth2\Server\Exception\ClientException', 'The authorization server does not support obtaining an access token using this method.'); + + $_POST = [ + 'client_id' => 'testapp', + 'redirect_uri' => 'http://foo/bar', + 'response_type' => 'foobar' + ]; + + $server = new Authorization; + $grant = new AuthCode; + + $server->addGrantType($grant); + $grant->checkAuthoriseParams(); + } + + public function testCheckAuthoriseParamsInvalidClient() + { + $this->setExpectedException('League\OAuth2\Server\Exception\ClientException', 'Client authentication failed'); + + $_POST = [ + 'client_id' => 'testapp', + 'redirect_uri' => 'http://foo/bar', + 'response_type' => 'code' + ]; + + $server = new Authorization; + $grant = new AuthCode; + + $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); + $clientStorage->shouldReceive('setServer'); + $clientStorage->shouldReceive('get')->andReturn(null); + + $server->setClientStorage($clientStorage); + + $server->addGrantType($grant); + $grant->checkAuthoriseParams(); + } + + public function testCheckAuthoriseParamsInvalidScope() + { + $this->setExpectedException('League\OAuth2\Server\Exception\ClientException', 'The requested scope is invalid, unknown, or malformed. Check the "foo" scope.'); + + $_POST = [ + 'response_type' => 'code', + 'client_id' => 'testapp', + 'redirect_uri' => 'http://foo/bar', + 'scope' => 'foo' + ]; + + $server = new Authorization; + $grant = new AuthCode; + + $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); + $clientStorage->shouldReceive('setServer'); + $clientStorage->shouldReceive('get')->andReturn( + (new Client($server))->setId('testapp') + ); + + $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); + $sessionStorage->shouldReceive('setServer'); + $sessionStorage->shouldReceive('create'); + $sessionStorage->shouldReceive('getScopes')->andReturn([]); + + $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); + $accessTokenStorage->shouldReceive('setServer'); + $accessTokenStorage->shouldReceive('create'); + $accessTokenStorage->shouldReceive('getScopes')->andReturn([]); + + $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); + $scopeStorage->shouldReceive('setServer'); + $scopeStorage->shouldReceive('get')->andReturn(null); + + $server->setClientStorage($clientStorage); + $server->setScopeStorage($scopeStorage); + $server->setSessionStorage($sessionStorage); + $server->setAccessTokenStorage($accessTokenStorage); + + $server->addGrantType($grant); + $grant->checkAuthoriseParams(); + } + + public function testCheckAuthoriseParams() + { + $_POST = [ + 'response_type' => 'code', + 'client_id' => 'testapp', + 'redirect_uri' => 'http://foo/bar', + 'scope' => 'foo' + ]; + + $server = new Authorization; + $grant = new AuthCode; + + $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); + $clientStorage->shouldReceive('setServer'); + $clientStorage->shouldReceive('get')->andReturn( + (new Client($server))->setId('testapp') + ); + + $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); + $sessionStorage->shouldReceive('setServer'); + $sessionStorage->shouldReceive('create')->andreturn(123); + $sessionStorage->shouldReceive('getScopes')->shouldReceive('getScopes')->andReturn([ + (new Scope($server))->setId('foo') + ]); + $sessionStorage->shouldReceive('associateScope'); + + $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); + $accessTokenStorage->shouldReceive('setServer'); + $accessTokenStorage->shouldReceive('create'); + $accessTokenStorage->shouldReceive('getScopes')->andReturn([ + (new Scope($server))->setId('foo') + ]); + $accessTokenStorage->shouldReceive('associateScope'); + + $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); + $scopeStorage->shouldReceive('setServer'); + $scopeStorage->shouldReceive('get')->andReturn( + (new Scope($server))->setId('foo') + ); + + $server->setClientStorage($clientStorage); + $server->setScopeStorage($scopeStorage); + $server->setSessionStorage($sessionStorage); + $server->setAccessTokenStorage($accessTokenStorage); + + $server->addGrantType($grant); + + $result = $grant->checkAuthoriseParams(); + + $this->assertTrue($result['client'] instanceof Client); + $this->assertTrue($result['redirect_uri'] === $_POST['redirect_uri']); + $this->assertTrue($result['state'] === null); + $this->assertTrue($result['response_type'] === 'code'); + $this->assertTrue($result['scopes']['foo'] instanceof Scope); + } + + public function testNewAuthoriseRequest() + { + $server = new Authorization; + + $client = (new Client($server))->setId('testapp'); + $scope = (new Scope($server))->setId('foo'); + + $grant = new AuthCode; + $server->addGrantType($grant); + + $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); + $sessionStorage->shouldReceive('setServer'); + $sessionStorage->shouldReceive('create')->andreturn(123); + $sessionStorage->shouldReceive('getScopes')->shouldReceive('getScopes')->andReturn([$scope]); + $sessionStorage->shouldReceive('associateScope'); + $server->setSessionStorage($sessionStorage); + + $authCodeStorage = M::mock('League\OAuth2\Server\Storage\AuthCodeInterface'); + $authCodeStorage->shouldReceive('setServer'); + $authCodeStorage->shouldReceive('get'); + $authCodeStorage->shouldReceive('create'); + $authCodeStorage->shouldReceive('associateScope'); + $server->setAuthCodeStorage($authCodeStorage); + + $grant->newAuthoriseRequest('user', 123, [ + 'client' => $client, + 'redirect_uri' => 'http://foo/bar', + 'scopes' => [$scope], + 'state' => 'foobar' + ]); + } + + public function testCompleteFlowMissingClientId() + { + $this->setExpectedException('League\OAuth2\Server\Exception\ClientException', 'The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the "client_id" parameter.'); + + $_POST['grant_type'] = 'authorization_code'; + + $server = new Authorization; + $grant = new AuthCode; + + $server->addGrantType($grant); + $server->issueAccessToken(); + + } + + public function testCompleteFlowMissingClientSecret() + { + $this->setExpectedException('League\OAuth2\Server\Exception\ClientException', 'The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the "client_secret" parameter.'); + + $_POST = [ + 'grant_type' => 'authorization_code', + 'client_id' => 'testapp' + ]; + + $server = new Authorization; + $grant = new AuthCode; + + $server->addGrantType($grant); + $server->issueAccessToken(); + } + + public function testCompleteFlowMissingRedirectUri() + { + $this->setExpectedException('League\OAuth2\Server\Exception\ClientException', 'The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the "redirect_uri" parameter.'); + + $_POST = [ + 'grant_type' => 'authorization_code', + 'client_id' => 'testapp', + 'client_secret' => 'foobar' + ]; + + $server = new Authorization; + $grant = new AuthCode; + + $server->addGrantType($grant); + $server->issueAccessToken(); + } + + public function testCompleteFlowInvalidClient() + { + $this->setExpectedException('League\OAuth2\Server\Exception\ClientException', 'Client authentication failed'); + + $_POST = [ + 'grant_type' => 'authorization_code', + 'client_id' => 'testapp', + 'client_secret' => 'foobar', + 'redirect_uri' => 'http://foo/bar' + ]; + + $server = new Authorization; + $grant = new AuthCode; + + $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); + $clientStorage->shouldReceive('setServer'); + $clientStorage->shouldReceive('get')->andReturn(null); + + $server->setClientStorage($clientStorage); + + $server->addGrantType($grant); + $server->issueAccessToken(); + } + + public function testCompleteFlowMissingCode() + { + $this->setExpectedException('League\OAuth2\Server\Exception\ClientException', 'The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the "code" parameter.'); + + $_POST = [ + 'grant_type' => 'authorization_code', + 'client_id' => 'testapp', + 'client_secret' => 'foobar', + 'redirect_uri' => 'http://foo/bar' + ]; + + $server = new Authorization; + $grant = new AuthCode; + + $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); + $clientStorage->shouldReceive('setServer'); + $clientStorage->shouldReceive('get')->andReturn( + (new Client($server))->setId('testapp') + ); + + $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); + $sessionStorage->shouldReceive('setServer'); + $sessionStorage->shouldReceive('create'); + $sessionStorage->shouldReceive('getScopes')->andReturn([]); + + $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); + $accessTokenStorage->shouldReceive('setServer'); + $accessTokenStorage->shouldReceive('create'); + $accessTokenStorage->shouldReceive('getScopes')->andReturn([]); + + $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); + $scopeStorage->shouldReceive('setServer'); + $scopeStorage->shouldReceive('get')->andReturn(null); + + $authCodeStorage = M::mock('League\OAuth2\Server\Storage\AuthCodeInterface'); + $authCodeStorage->shouldReceive('setServer'); + $authCodeStorage->shouldReceive('get'); + + $server->setClientStorage($clientStorage); + $server->setScopeStorage($scopeStorage); + $server->setSessionStorage($sessionStorage); + $server->setAccessTokenStorage($accessTokenStorage); + $server->setAuthCodeStorage($authCodeStorage); + + $server->addGrantType($grant); + $server->issueAccessToken(); + } + + public function testCompleteFlowInvalidCode() + { + $this->setExpectedException('League\OAuth2\Server\Exception\ClientException', 'The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the "code" parameter.'); + + $_POST = [ + 'grant_type' => 'authorization_code', + 'client_id' => 'testapp', + 'client_secret' => 'foobar', + 'redirect_uri' => 'http://foo/bar', + 'code' => 'foobar' + ]; + + $server = new Authorization; + $grant = new AuthCode; + + $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); + $clientStorage->shouldReceive('setServer'); + $clientStorage->shouldReceive('get')->andReturn( + (new Client($server))->setId('testapp') + ); + + $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); + $sessionStorage->shouldReceive('setServer'); + $sessionStorage->shouldReceive('create'); + $sessionStorage->shouldReceive('getScopes')->andReturn([]); + + $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); + $accessTokenStorage->shouldReceive('setServer'); + $accessTokenStorage->shouldReceive('create'); + $accessTokenStorage->shouldReceive('getScopes')->andReturn([]); + + $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); + $scopeStorage->shouldReceive('setServer'); + $scopeStorage->shouldReceive('get')->andReturn(null); + + $authCodeStorage = M::mock('League\OAuth2\Server\Storage\AuthCodeInterface'); + $authCodeStorage->shouldReceive('setServer'); + $authCodeStorage->shouldReceive('get'); + + $server->setClientStorage($clientStorage); + $server->setScopeStorage($scopeStorage); + $server->setSessionStorage($sessionStorage); + $server->setAccessTokenStorage($accessTokenStorage); + $server->setAuthCodeStorage($authCodeStorage); + + $server->addGrantType($grant); + $server->issueAccessToken(); + } + + public function testCompleteFlowRedirectUriMismatch() + { + $this->setExpectedException('League\OAuth2\Server\Exception\ClientException', 'The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the "redirect_uri" parameter.'); + + $_POST = [ + 'grant_type' => 'authorization_code', + 'client_id' => 'testapp', + 'client_secret' => 'foobar', + 'redirect_uri' => 'http://foo/bar', + 'code' => 'foobar' + ]; + + $server = new Authorization; + $grant = new AuthCode; + + $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); + $clientStorage->shouldReceive('setServer'); + $clientStorage->shouldReceive('get')->andReturn( + (new Client($server))->setId('testapp') + ); + + $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); + $sessionStorage->shouldReceive('setServer'); + $sessionStorage->shouldReceive('create'); + $sessionStorage->shouldReceive('getScopes')->andReturn([]); + + $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); + $accessTokenStorage->shouldReceive('setServer'); + $accessTokenStorage->shouldReceive('create'); + $accessTokenStorage->shouldReceive('getScopes')->andReturn([]); + + $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); + $scopeStorage->shouldReceive('setServer'); + $scopeStorage->shouldReceive('get')->andReturn(null); + + $authCodeStorage = M::mock('League\OAuth2\Server\Storage\AuthCodeInterface'); + $authCodeStorage->shouldReceive('setServer'); + $authCodeStorage->shouldReceive('get')->andReturn( + (new AC($server))->setToken('foobar')->setRedirectUri('http://fail/face') + ); + + $server->setClientStorage($clientStorage); + $server->setScopeStorage($scopeStorage); + $server->setSessionStorage($sessionStorage); + $server->setAccessTokenStorage($accessTokenStorage); + $server->setAuthCodeStorage($authCodeStorage); + + $server->addGrantType($grant); + $server->issueAccessToken(); + } + + public function testCompleteFlow() + { + $_POST = [ + 'grant_type' => 'authorization_code', + 'client_id' => 'testapp', + 'client_secret' => 'foobar', + 'redirect_uri' => 'http://foo/bar', + 'code' => 'foo' + ]; + + $server = new Authorization; + $grant = new AuthCode; + + $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); + $clientStorage->shouldReceive('setServer'); + $clientStorage->shouldReceive('getBySession')->andReturn( + (new Client($server))->setId('testapp') + ); + $clientStorage->shouldReceive('get')->andReturn( + (new Client($server))->setId('testapp') + ); + + $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); + $sessionStorage->shouldReceive('setServer'); + $sessionStorage->shouldReceive('create')->andreturn(123); + $sessionStorage->shouldReceive('associateScope'); + $sessionStorage->shouldReceive('getByAuthCode')->andReturn( + (new Session($server))->setId('foobar') + ); + + $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); + $accessTokenStorage->shouldReceive('setServer'); + $accessTokenStorage->shouldReceive('create'); + $accessTokenStorage->shouldReceive('associateScope'); + $accessTokenStorage->shouldReceive('getScopes')->andReturn([ + (new Scope($server))->setId('foo') + ]); + + $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); + $scopeStorage->shouldReceive('setServer'); + $scopeStorage->shouldReceive('get')->andReturn( + (new Scope($server))->setId('foo') + ); + + $authCodeStorage = M::mock('League\OAuth2\Server\Storage\AuthCodeInterface'); + $authCodeStorage->shouldReceive('setServer'); + $authCodeStorage->shouldReceive('delete'); + $authCodeStorage->shouldReceive('get')->andReturn( + (new AC($server))->setToken('foobar')->setRedirectUri('http://foo/bar') + ); + $authCodeStorage->shouldReceive('getScopes')->andReturn([ + (new Scope($server))->setId('foo') + ]); + + $server->setClientStorage($clientStorage); + $server->setScopeStorage($scopeStorage); + $server->setSessionStorage($sessionStorage); + $server->setAccessTokenStorage($accessTokenStorage); + $server->setAuthCodeStorage($authCodeStorage); + + $server->addGrantType($grant); + $server->issueAccessToken(); + } + + public function testCompleteFlowWithRefreshToken() + { + $_POST = [ + 'grant_type' => 'authorization_code', + 'client_id' => 'testapp', + 'client_secret' => 'foobar', + 'redirect_uri' => 'http://foo/bar', + 'code' => 'foo' + ]; + + $server = new Authorization; + $grant = new AuthCode; + $rtgrant = new RefreshToken; + + $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); + $clientStorage->shouldReceive('setServer'); + $clientStorage->shouldReceive('getBySession')->andReturn( + (new Client($server))->setId('testapp') + ); + $clientStorage->shouldReceive('get')->andReturn( + (new Client($server))->setId('testapp') + ); + + $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); + $sessionStorage->shouldReceive('setServer'); + $sessionStorage->shouldReceive('create')->andreturn(123); + $sessionStorage->shouldReceive('associateScope'); + $sessionStorage->shouldReceive('getByAuthCode')->andReturn( + (new Session($server))->setId('foobar') + ); + + $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); + $accessTokenStorage->shouldReceive('setServer'); + $accessTokenStorage->shouldReceive('create'); + $accessTokenStorage->shouldReceive('associateScope'); + $accessTokenStorage->shouldReceive('getScopes')->andReturn([ + (new Scope($server))->setId('foo') + ]); + + $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); + $scopeStorage->shouldReceive('setServer'); + $scopeStorage->shouldReceive('get')->andReturn( + (new Scope($server))->setId('foo') + ); + + $authCodeStorage = M::mock('League\OAuth2\Server\Storage\AuthCodeInterface'); + $authCodeStorage->shouldReceive('setServer'); + $authCodeStorage->shouldReceive('delete'); + $authCodeStorage->shouldReceive('get')->andReturn( + (new AC($server))->setToken('foobar')->setRedirectUri('http://foo/bar') + ); + $authCodeStorage->shouldReceive('getScopes')->andReturn([ + (new Scope($server))->setId('foo') + ]); + + $refreshTokenStorage = M::mock('League\OAuth2\Server\Storage\RefreshTokenInterface'); + $refreshTokenStorage->shouldReceive('setServer'); + $refreshTokenStorage->shouldReceive('create'); + $refreshTokenStorage->shouldReceive('associateScope'); + + $server->setClientStorage($clientStorage); + $server->setScopeStorage($scopeStorage); + $server->setSessionStorage($sessionStorage); + $server->setAccessTokenStorage($accessTokenStorage); + $server->setAuthCodeStorage($authCodeStorage); + $server->setRefreshTokenStorage($refreshTokenStorage); + + $server->addGrantType($grant); + $server->addGrantType($rtgrant); + $server->issueAccessToken(); + } +}