2013-01-05 01:14:02 +05:30
< ? php
2013-02-13 02:03:23 +05:30
/**
2013-02-20 18:10:42 +05:30
* OAuth 2.0 Authorization Server
2013-02-13 02:03:23 +05:30
*
2013-05-08 23:59:24 +05:30
* @ package php - loep / oauth2 - server
2013-02-13 02:03:23 +05:30
* @ author Alex Bilbie < hello @ alexbilbie . com >
2013-05-08 23:59:24 +05:30
* @ copyright Copyright ( c ) 2013 PHP League of Extraordinary Packages
2013-02-13 02:03:23 +05:30
* @ license http :// mit - license . org /
2013-05-09 00:00:53 +05:30
* @ link http :// github . com / php - loep / oauth2 - server
2013-02-13 02:03:23 +05:30
*/
2013-01-05 01:14:02 +05:30
2013-05-09 00:12:23 +05:30
namespace League\OAuth2\Server ;
2013-01-05 01:14:02 +05:30
2013-05-09 00:12:23 +05:30
use League\OAuth2\Server\Util\SecureKey ;
2013-12-24 22:32:58 +05:30
use League\OAuth2\Server\Grant\GrantTypeInterface ;
use League\OAuth2\Server\Exception\ClientException ;
use League\OAuth2\Server\Exception\ServerException ;
use League\OAuth2\Server\Exception\InvalidGrantTypeException ;
2013-05-09 00:12:23 +05:30
use League\OAuth2\Server\Storage\ClientInterface ;
2013-12-24 22:32:58 +05:30
use League\OAuth2\Server\Storage\AccessTokenInterface ;
use League\OAuth2\Server\Storage\AuthCodeInterface ;
use League\OAuth2\Server\Storage\RefreshTokenInterface ;
use League\OAuth2\Server\Storage\SessionInterface ;
2013-05-09 00:12:23 +05:30
use League\OAuth2\Server\Storage\ScopeInterface ;
2013-12-24 22:32:58 +05:30
use Symfony\Component\HttpFoundation\Request ;
2013-01-29 19:46:47 +05:30
2013-02-13 02:03:23 +05:30
/**
2013-02-20 18:10:42 +05:30
* OAuth 2.0 authorization server class
2013-02-13 02:03:23 +05:30
*/
2013-05-09 00:12:23 +05:30
class Authorization
2013-01-05 01:14:02 +05:30
{
2013-01-29 19:48:13 +05:30
/**
* The delimeter between scopes specified in the scope query string parameter
2013-05-09 06:12:15 +05:30
* The OAuth 2 specification states it should be a space but most use a comma
2013-01-29 19:48:13 +05:30
* @ var string
*/
2013-05-09 06:12:15 +05:30
protected $scopeDelimeter = ' ' ;
2013-01-05 01:14:02 +05:30
2013-02-13 02:03:23 +05:30
/**
* The TTL ( time to live ) of an access token in seconds ( default : 3600 )
* @ var integer
*/
2013-05-08 23:05:13 +05:30
protected $accessTokenTTL = 3600 ;
2013-01-05 01:14:02 +05:30
2013-02-13 02:03:23 +05:30
/**
* The registered grant response types
* @ var array
*/
2013-12-27 01:52:31 +05:30
protected $responseTypes = [];
2013-01-05 01:14:02 +05:30
2013-02-13 02:03:23 +05:30
/**
* The client , scope and session storage classes
* @ var array
*/
2013-12-27 01:52:31 +05:30
protected $storages = [];
2013-01-05 01:14:02 +05:30
2013-02-13 02:03:23 +05:30
/**
* The registered grant types
* @ var array
*/
2013-12-27 01:52:31 +05:30
protected $grantTypes = [];
2013-01-05 01:14:02 +05:30
2013-03-04 18:40:00 +05:30
/**
* Require the " scope " parameter to be in checkAuthoriseParams ()
* @ var boolean
*/
2013-05-09 22:32:41 +05:30
protected $requireScopeParam = false ;
2013-03-04 18:45:12 +05:30
2013-03-04 21:16:02 +05:30
/**
2013-05-09 22:45:36 +05:30
* Default scope ( s ) to be used if none is provided
* @ var string | array
2013-03-04 21:16:02 +05:30
*/
protected $defaultScope = null ;
2013-03-04 18:45:12 +05:30
/**
* Require the " state " parameter to be in checkAuthoriseParams ()
* @ var boolean
*/
protected $requireStateParam = false ;
2013-03-04 18:40:00 +05:30
2013-02-13 02:03:23 +05:30
/**
* The request object
* @ var Util\RequestInterface
*/
2013-03-06 22:29:18 +05:30
protected $request = null ;
2013-01-22 21:55:51 +05:30
2013-01-29 19:49:23 +05:30
/**
* Exception error codes
* @ var array
*/
2013-12-27 01:52:31 +05:30
protected static $exceptionCodes = [
2013-01-29 19:49:23 +05:30
0 => 'invalid_request' ,
1 => 'unauthorized_client' ,
2 => 'access_denied' ,
3 => 'unsupported_response_type' ,
4 => 'invalid_scope' ,
5 => 'server_error' ,
6 => 'temporarily_unavailable' ,
7 => 'unsupported_grant_type' ,
8 => 'invalid_client' ,
9 => 'invalid_grant'
2013-12-27 01:52:31 +05:30
];
2013-01-29 19:49:23 +05:30
/**
* Exception error messages
* @ var array
*/
2013-12-27 01:52:31 +05:30
protected static $exceptionMessages = [
2013-01-29 19:49:23 +05:30
'invalid_request' => 'The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the "%s" parameter.' ,
'unauthorized_client' => 'The client is not authorized to request an access token using this method.' ,
'access_denied' => 'The resource owner or authorization server denied the request.' ,
'unsupported_response_type' => 'The authorization server does not support obtaining an access token using this method.' ,
'invalid_scope' => 'The requested scope is invalid, unknown, or malformed. Check the "%s" scope.' ,
'server_error' => 'The authorization server encountered an unexpected condition which prevented it from fulfilling the request.' ,
'temporarily_unavailable' => 'The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server.' ,
'unsupported_grant_type' => 'The authorization grant type "%s" is not supported by the authorization server' ,
'invalid_client' => 'Client authentication failed' ,
'invalid_grant' => 'The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client. Check the "%s" parameter.' ,
'invalid_credentials' => 'The user credentials were incorrect.' ,
'invalid_refresh' => 'The refresh token is invalid.' ,
2013-12-27 01:52:31 +05:30
];
2013-01-05 01:14:02 +05:30
2013-03-26 21:47:01 +05:30
/**
* Exception error HTTP status codes
* @ var array
* RFC 6749 , section 4.1 . 2.1 .:
2013-03-27 19:56:46 +05:30
* No 503 status code for 'temporarily_unavailable' , because
2013-03-26 21:47:01 +05:30
* " a 503 Service Unavailable HTTP status code cannot be
* returned to the client via an HTTP redirect "
*/
2013-12-27 01:52:31 +05:30
protected static $exceptionHttpStatusCodes = [
2013-03-26 21:47:01 +05:30
'invalid_request' => 400 ,
'unauthorized_client' => 400 ,
'access_denied' => 401 ,
'unsupported_response_type' => 400 ,
'invalid_scope' => 400 ,
'server_error' => 500 ,
'temporarily_unavailable' => 400 ,
2013-03-27 19:56:46 +05:30
'unsupported_grant_type' => 501 ,
2013-03-26 21:47:01 +05:30
'invalid_client' => 401 ,
'invalid_grant' => 400 ,
'invalid_credentials' => 400 ,
'invalid_refresh' => 400 ,
2013-12-31 21:05:13 +05:30
];
2013-03-27 19:56:46 +05:30
2013-03-26 21:47:01 +05:30
/**
* Get all headers that have to be send with the error response
* @ param string $error The error message key
* @ return array Array with header values
*/
public static function getExceptionHttpHeaders ( $error )
{
2013-12-27 01:52:31 +05:30
$headers = [];
2013-03-26 21:47:01 +05:30
switch ( self :: $exceptionHttpStatusCodes [ $error ]) {
case 401 :
$headers [] = 'HTTP/1.1 401 Unauthorized' ;
break ;
case 500 :
$headers [] = 'HTTP/1.1 500 Internal Server Error' ;
break ;
case 501 :
$headers [] = 'HTTP/1.1 501 Not Implemented' ;
break ;
case 400 :
default :
$headers [] = 'HTTP/1.1 400 Bad Request' ;
}
2013-03-27 19:56:46 +05:30
2013-03-26 21:47:01 +05:30
// Add "WWW-Authenticate" header
//
2013-03-27 19:56:46 +05:30
// RFC 6749, section 5.2.:
2013-03-26 21:47:01 +05:30
// "If the client attempted to authenticate via the 'Authorization'
// request header field, the authorization server MUST
// respond with an HTTP 401 (Unauthorized) status code and
// include the "WWW-Authenticate" response header field
// matching the authentication scheme used by the client.
2013-03-27 19:56:46 +05:30
// @codeCoverageIgnoreStart
2013-03-26 21:47:01 +05:30
if ( $error === 'invalid_client' ) {
2013-03-27 19:56:46 +05:30
$authScheme = null ;
2013-03-26 21:47:01 +05:30
$request = new Request ();
if ( $request -> server ( 'PHP_AUTH_USER' ) !== null ) {
2013-03-27 19:56:46 +05:30
$authScheme = 'Basic' ;
2013-03-26 21:47:01 +05:30
} else {
2013-03-27 19:56:46 +05:30
$authHeader = $request -> header ( 'Authorization' );
if ( $authHeader !== null ) {
if ( strpos ( $authHeader , 'Bearer' ) === 0 ) {
$authScheme = 'Bearer' ;
} elseif ( strpos ( $authHeader , 'Basic' ) === 0 ) {
$authScheme = 'Basic' ;
2013-03-26 21:47:01 +05:30
}
}
}
2013-03-27 19:56:46 +05:30
if ( $authScheme !== null ) {
$headers [] = 'WWW-Authenticate: ' . $authScheme . ' realm=""' ;
2013-03-26 21:47:01 +05:30
}
}
2013-03-27 19:56:46 +05:30
// @codeCoverageIgnoreEnd
2013-03-26 21:47:01 +05:30
return $headers ;
}
2013-02-13 02:03:23 +05:30
/**
* Get an exception message
* @ param string $error The error message key
* @ return string The error message
*/
2013-02-01 20:11:10 +05:30
public static function getExceptionMessage ( $error = '' )
{
return self :: $exceptionMessages [ $error ];
}
2013-02-15 21:59:00 +05:30
/**
* Get an exception code
* @ param integer $code The exception code
* @ return string The exception code type
*/
public static function getExceptionType ( $code = 0 )
{
return self :: $exceptionCodes [ $code ];
}
2013-02-13 02:03:23 +05:30
/**
2013-02-20 18:10:42 +05:30
* Create a new OAuth2 authorization server
2013-12-27 01:52:31 +05:30
* @ return self
2013-02-13 02:03:23 +05:30
*/
2013-12-24 22:32:58 +05:30
public function __construct ()
{
$this -> storages = [];
2013-12-27 01:52:31 +05:30
return $this ;
2013-12-24 22:32:58 +05:30
}
2013-12-27 01:52:31 +05:30
/**
* Set the client storage
* @ param ClientInterface $client
* @ return self
*/
2013-12-24 22:32:58 +05:30
public function setClientStorage ( ClientInterface $client )
{
$this -> storages [ 'client' ] = $client ;
2013-12-27 01:52:31 +05:30
return $this ;
2013-12-24 22:32:58 +05:30
}
2013-12-27 01:52:31 +05:30
/**
* Set the session storage
* @ param SessionInterface $session
* @ return self
*/
2013-12-24 22:32:58 +05:30
public function setSessionStorage ( SessionInterface $session )
2013-01-29 19:46:47 +05:30
{
2013-12-24 22:32:58 +05:30
$this -> storages [ 'session' ] = $session ;
2013-12-27 01:52:31 +05:30
return $this ;
2013-12-24 22:32:58 +05:30
}
2013-12-27 01:52:31 +05:30
/**
* Set the access token storage
* @ param AccessTokenInterface $accessToken
* @ return self
*/
2013-12-24 22:32:58 +05:30
public function setAccessTokenStorage ( AccessTokenInterface $accessToken )
{
$this -> storages [ 'access_token' ] = $accessToken ;
2013-12-27 01:52:31 +05:30
return $this ;
2013-12-24 22:32:58 +05:30
}
2013-12-27 01:52:31 +05:30
/**
* Set the refresh token storage
* @ param RefreshTokenInteface $refreshToken
* @ return self
*/
2013-12-24 22:32:58 +05:30
public function setRefreshTokenStorage ( RefreshTokenInterface $refreshToken )
{
$this -> storages [ 'refresh_token' ] = $refreshToken ;
2013-12-27 01:52:31 +05:30
return $this ;
2013-12-24 22:32:58 +05:30
}
2013-12-27 01:52:31 +05:30
/**
* Set the auth code storage
* @ param AuthCodeInterface $authCode
* @ return self
*/
2013-12-24 22:32:58 +05:30
public function setAuthCodeStorage ( AuthCodeInterface $authCode )
{
$this -> storages [ 'auth_code' ] = $authCode ;
2013-12-27 01:52:31 +05:30
return $this ;
2013-12-24 22:32:58 +05:30
}
2013-12-27 01:52:31 +05:30
/**
* Set the scope storage
* @ param ScopeInterface $scope
* @ return self
*/
2013-12-24 22:32:58 +05:30
public function setScopeStorage ( ScopeInterface $scope )
{
$this -> storages [ 'scope' ] = $scope ;
2013-12-27 01:52:31 +05:30
return $this ;
2013-01-05 01:14:02 +05:30
}
2013-02-13 02:03:23 +05:30
/**
* Enable support for a grant
* @ param GrantTypeInterface $grantType A grant class which conforms to Interface / GrantTypeInterface
* @ param null | string $identifier An identifier for the grant ( autodetected if not passed )
2013-12-24 22:32:58 +05:30
* @ return self
2013-02-13 02:03:23 +05:30
*/
2013-01-29 19:47:56 +05:30
public function addGrantType ( GrantTypeInterface $grantType , $identifier = null )
2013-01-05 01:14:02 +05:30
{
if ( is_null ( $identifier )) {
2013-01-29 19:47:56 +05:30
$identifier = $grantType -> getIdentifier ();
}
2013-12-06 01:55:50 +05:30
// Inject server into grant
$grantType -> setAuthorizationServer ( $this );
2013-03-06 22:29:18 +05:30
$this -> grantTypes [ $identifier ] = $grantType ;
2013-01-29 19:47:56 +05:30
2013-01-29 21:51:53 +05:30
if ( ! is_null ( $grantType -> getResponseType ())) {
2013-01-29 19:47:56 +05:30
$this -> responseTypes [] = $grantType -> getResponseType ();
2013-01-05 01:14:02 +05:30
}
2013-12-24 22:32:58 +05:30
return $this ;
2013-01-05 01:14:02 +05:30
}
2013-02-13 02:03:23 +05:30
/**
* Check if a grant type has been enabled
* @ param string $identifier The grant type identifier
2013-12-24 22:32:58 +05:30
* @ return boolean Returns " true " if enabled , " false " if not
2013-02-13 02:03:23 +05:30
*/
2013-03-06 22:29:18 +05:30
public function hasGrantType ( $identifier )
2013-02-01 20:11:10 +05:30
{
2013-03-06 22:29:18 +05:30
return ( array_key_exists ( $identifier , $this -> grantTypes ));
2013-02-01 20:11:10 +05:30
}
2013-11-26 05:28:42 +05:30
/**
* Returns response types
* @ return array
*/
2013-03-31 18:07:12 +05:30
public function getResponseTypes ()
{
return $this -> responseTypes ;
}
2013-03-04 18:40:00 +05:30
/**
* Require the " scope " paremter in checkAuthoriseParams ()
* @ param boolean $require
2013-12-24 22:32:58 +05:30
* @ return self
2013-03-04 18:40:00 +05:30
*/
2013-05-11 11:31:54 +05:30
public function requireScopeParam ( $require = true )
2013-03-04 18:45:12 +05:30
{
$this -> requireScopeParam = $require ;
2013-12-24 22:32:58 +05:30
return $this ;
2013-03-04 18:45:12 +05:30
}
2013-03-21 21:52:29 +05:30
/**
* Is the scope parameter required ?
* @ return bool
*/
public function scopeParamRequired ()
{
return $this -> requireScopeParam ;
}
2013-03-04 21:16:02 +05:30
/**
* Default scope to be used if none is provided and requireScopeParam is false
2013-12-24 22:32:58 +05:30
* @ param self
2013-03-04 21:16:02 +05:30
*/
2013-03-21 21:52:16 +05:30
public function setDefaultScope ( $default = null )
2013-03-04 21:16:02 +05:30
{
$this -> defaultScope = $default ;
2013-11-26 05:28:42 +05:30
return $this ;
2013-03-04 21:16:02 +05:30
}
2013-03-21 21:52:44 +05:30
/**
* Default scope to be used if none is provided and requireScopeParam is false
* @ return string | null
*/
public function getDefaultScope ()
{
return $this -> defaultScope ;
}
2013-03-31 18:27:24 +05:30
/**
* Require the " state " paremter in checkAuthoriseParams ()
* @ param boolean $require
* @ return void
*/
public function stateParamRequired ()
{
return $this -> requireStateParam ;
}
2013-03-04 18:45:12 +05:30
/**
* Require the " state " paremter in checkAuthoriseParams ()
* @ param boolean $require
* @ return void
*/
2013-05-11 11:31:54 +05:30
public function requireStateParam ( $require = true )
2013-03-04 18:40:00 +05:30
{
2013-03-04 18:45:12 +05:30
$this -> requireStateParam = $require ;
2013-11-26 05:28:42 +05:30
return $this ;
2013-03-04 18:40:00 +05:30
}
2013-02-13 02:03:23 +05:30
/**
* Get the scope delimeter
* @ return string The scope delimiter ( default : " , " )
*/
2013-01-22 21:55:51 +05:30
public function getScopeDelimeter ()
{
return $this -> scopeDelimeter ;
}
2013-02-13 02:03:23 +05:30
/**
* Set the scope delimiter
* @ param string $scopeDelimeter
*/
2013-05-09 06:36:09 +05:30
public function setScopeDelimeter ( $scopeDelimeter = ' ' )
2013-01-05 01:14:02 +05:30
{
2013-02-13 02:03:23 +05:30
$this -> scopeDelimeter = $scopeDelimeter ;
2013-11-26 05:28:42 +05:30
return $this ;
2013-01-05 01:14:02 +05:30
}
2013-02-13 02:03:23 +05:30
/**
* Get the TTL for an access token
* @ return int The TTL
*/
2013-05-08 23:05:13 +05:30
public function getAccessTokenTTL ()
2013-01-22 21:55:51 +05:30
{
2013-05-08 23:05:13 +05:30
return $this -> accessTokenTTL ;
2013-01-22 21:55:51 +05:30
}
2013-02-13 02:03:23 +05:30
/**
* Set the TTL for an access token
2013-05-08 03:46:30 +05:30
* @ param int $accessTokenTTL The new TTL
2013-02-13 02:03:23 +05:30
*/
2013-05-09 06:36:09 +05:30
public function setAccessTokenTTL ( $accessTokenTTL = 3600 )
2013-01-05 01:14:02 +05:30
{
2013-05-08 03:46:30 +05:30
$this -> accessTokenTTL = $accessTokenTTL ;
2013-11-26 05:28:42 +05:30
return $this ;
2013-01-05 01:14:02 +05:30
}
2013-01-22 21:55:51 +05:30
/**
* Sets the Request Object
2013-12-24 22:32:58 +05:30
* @ param \Symfony\Component\HttpFoundation\Request The Request Object
* @ return self
2013-01-22 21:55:51 +05:30
*/
2013-12-24 22:32:58 +05:30
public function setRequest ( Request $request )
2013-01-22 21:55:51 +05:30
{
2013-03-06 22:29:18 +05:30
$this -> request = $request ;
2013-11-26 05:28:42 +05:30
return $this ;
2013-01-22 21:55:51 +05:30
}
/**
2013-12-24 22:32:58 +05:30
* Gets the Request object . It will create one from the globals if one is not set .
* @ return \Symfony\Component\HttpFoundation\Request
2013-01-22 21:55:51 +05:30
*/
2013-03-06 22:29:18 +05:30
public function getRequest ()
2013-01-22 21:55:51 +05:30
{
2013-03-06 22:29:18 +05:30
if ( $this -> request === null ) {
2013-12-24 22:32:58 +05:30
$this -> request = \Symfony\Component\HttpFoundation\Request :: createFromGlobals ();
2013-01-22 21:55:51 +05:30
}
2013-03-06 22:29:18 +05:30
return $this -> request ;
2013-01-22 21:55:51 +05:30
}
2013-02-13 02:03:23 +05:30
/**
* Return a storage class
* @ param string $obj The class required
* @ return Storage\ClientInterface | Storage\ScopeInterface | Storage\SessionInterface
*/
2013-03-06 22:29:18 +05:30
public function getStorage ( $obj )
2013-01-29 19:46:47 +05:30
{
2013-12-24 22:32:58 +05:30
if ( ! isset ( $this -> storages [ $obj ])) {
throw new ServerException ( 'The `' . $obj . ' ` storage interface has not been registered with the authorization
server ' );
}
2013-03-06 22:29:18 +05:30
return $this -> storages [ $obj ];
2013-01-29 19:46:47 +05:30
}
2013-01-22 21:55:51 +05:30
/**
* Issue an access token
2013-02-01 20:11:10 +05:30
* @ param array $inputParams Optional array of parsed $_POST keys
2013-12-24 22:32:58 +05:30
* @ return array Authorise request parameters
2013-01-22 21:55:51 +05:30
*/
2013-12-27 01:52:31 +05:30
public function issueAccessToken ( $inputParams = [])
2013-01-22 21:55:51 +05:30
{
2013-12-24 22:32:58 +05:30
$grantType = $this -> getRequest () -> request -> get ( 'grant_type' );
2013-02-14 01:06:10 +05:30
if ( is_null ( $grantType )) {
2013-12-24 22:32:58 +05:30
throw new ClientException ( sprintf ( self :: $exceptionMessages [ 'invalid_request' ], 'grant_type' ), 0 );
2013-01-29 21:54:28 +05:30
}
2013-01-22 21:55:51 +05:30
2013-01-29 21:54:28 +05:30
// Ensure grant type is one that is recognised and is enabled
2013-03-06 22:29:18 +05:30
if ( ! in_array ( $grantType , array_keys ( $this -> grantTypes ))) {
2013-12-24 22:32:58 +05:30
throw new ClientException ( sprintf ( self :: $exceptionMessages [ 'unsupported_grant_type' ], $grantType ), 7 );
2013-01-29 21:54:28 +05:30
}
2013-01-22 21:55:51 +05:30
2013-01-29 21:54:48 +05:30
// Complete the flow
2013-02-14 01:06:10 +05:30
return $this -> getGrantType ( $grantType ) -> completeFlow ( $inputParams );
2013-01-29 21:54:48 +05:30
}
2013-01-22 21:55:51 +05:30
2013-02-13 02:03:23 +05:30
/**
* Return a grant type class
* @ param string $grantType The grant type identifer
2013-05-09 02:40:58 +05:30
* @ return Grant\AuthCode | Grant\ClientCredentials | Grant\Implict | Grant\Password | Grant\RefreshToken
2013-02-13 02:03:23 +05:30
*/
2013-03-06 23:31:34 +05:30
public function getGrantType ( $grantType )
2013-01-29 21:54:48 +05:30
{
2013-05-07 02:27:46 +05:30
if ( isset ( $this -> grantTypes [ $grantType ])) {
return $this -> grantTypes [ $grantType ];
}
2013-12-24 22:32:58 +05:30
throw new InvalidGrantTypeException ( sprintf ( self :: $exceptionMessages [ 'unsupported_grant_type' ], $grantType ), 9 );
2013-02-13 23:55:10 +05:30
}
2013-01-05 01:14:02 +05:30
}