Version 4.5.0
This commit is contained in:
1 parent
1a0c7fd3c2
commit
f79dcf067a
3791 files changed
+248032
-76372
No files matched your search
+155
-46
@@ -7,8 +7,7 @@
|
||||
* @package Invision Community
|
||||
* @since 29 Apr 2017
|
||||
*/
|
||||
|
||||
define('REPORT_EXCEPTIONS', TRUE);
|
||||
\define('REPORT_EXCEPTIONS', TRUE);
|
||||
require '../../init.php';
|
||||
|
||||
class oAuthServerAuthorizationRequest
|
||||
@@ -43,15 +42,27 @@ class oAuthServerAuthorizationRequest
|
||||
*/
|
||||
protected $scope = array();
|
||||
|
||||
/**
|
||||
* @brief Code Challenge
|
||||
*/
|
||||
protected $codeChallenge;
|
||||
|
||||
/**
|
||||
* @brief Code Challenge Method
|
||||
*/
|
||||
protected $codeChallengeMethod;
|
||||
|
||||
/**
|
||||
* Init
|
||||
*
|
||||
* @param string $clientId Client ID
|
||||
* @param string $redirectUri Redirect URI, if provided
|
||||
* @param string|NULL $state The state, if provided
|
||||
* @param string $clientId Client ID
|
||||
* @param string $redirectUri Redirect URI, if provided
|
||||
* @param string|NULL $state The state, if provided
|
||||
* @param string|NULL $codeChallenge The code challenge, if provided
|
||||
* @param string|NULL $codeChallengeMethod The code challenge method, if provided
|
||||
* @return void
|
||||
*/
|
||||
public static function init( $clientId, $redirectUri = NULL, $state = NULL )
|
||||
public static function init( $clientId, $redirectUri = NULL, $state = NULL, $codeChallenge = NULL, $codeChallengeMethod = NULL )
|
||||
{
|
||||
$obj = new static;
|
||||
|
||||
@@ -71,9 +82,15 @@ class oAuthServerAuthorizationRequest
|
||||
|
||||
/* Set the Redirect URI */
|
||||
$allowedRedirectUris = json_decode( $obj->client->redirect_uris );
|
||||
|
||||
if( \defined('\IPS\DEBUG_OAUTH_REDIRECTS') )
|
||||
{
|
||||
$allowedRedirectUris = array_merge( $allowedRedirectUris, \IPS\DEBUG_OAUTH_REDIRECTS );
|
||||
}
|
||||
|
||||
if ( $redirectUri )
|
||||
{
|
||||
if ( !in_array( $redirectUri, $allowedRedirectUris ) )
|
||||
if ( !\in_array( $redirectUri, $allowedRedirectUris ) )
|
||||
{
|
||||
throw new \IPS\Login\Handler\OAuth2\InitException('oauth_err_invalid_redirect_uri');
|
||||
}
|
||||
@@ -82,7 +99,7 @@ class oAuthServerAuthorizationRequest
|
||||
$obj->redirectUri = \IPS\Http\Url::external( $redirectUri );
|
||||
}
|
||||
}
|
||||
elseif ( count( $allowedRedirectUris ) === 1 )
|
||||
elseif ( \count( $allowedRedirectUris ) === 1 )
|
||||
{
|
||||
$obj->redirectUri = \IPS\Http\Url::external( array_shift( $allowedRedirectUris ) );
|
||||
}
|
||||
@@ -98,9 +115,30 @@ class oAuthServerAuthorizationRequest
|
||||
$obj->state = $state;
|
||||
}
|
||||
|
||||
/* Set code challenge and method if applicable */
|
||||
if ( $codeChallenge )
|
||||
{
|
||||
$obj->codeChallenge = $codeChallenge;
|
||||
$obj->codeChallengeMethod = $codeChallengeMethod;
|
||||
}
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the request is valid
|
||||
*
|
||||
* @return void
|
||||
* @throws \IPS\Login\Handler\OAuth2\Exception
|
||||
*/
|
||||
public function validate()
|
||||
{
|
||||
if ( ( $this->client->pkce !== 'none' and !$this->codeChallenge ) or ( $this->client->pkce === 'S256' and $this->codeChallengeMethod !== 'S256' ) )
|
||||
{
|
||||
throw new \IPS\Login\Handler\OAuth2\Exception( 'invalid_request', $this->codeChallenge ? "transform algorithm not supported" : "code challenge required" );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the response type
|
||||
*
|
||||
@@ -111,14 +149,14 @@ class oAuthServerAuthorizationRequest
|
||||
{
|
||||
if ( $responseType === 'code' )
|
||||
{
|
||||
if ( !in_array( 'authorization_code', explode( ',', $this->client->grant_types ) ) )
|
||||
if ( !\in_array( 'authorization_code', explode( ',', $this->client->grant_types ) ) )
|
||||
{
|
||||
throw new \IPS\Login\Handler\OAuth2\Exception('unsupported_response_type');
|
||||
}
|
||||
}
|
||||
elseif ( $responseType === 'token' )
|
||||
{
|
||||
if ( !in_array( 'implicit', explode( ',', $this->client->grant_types ) ) )
|
||||
if ( !\in_array( 'implicit', explode( ',', $this->client->grant_types ) ) )
|
||||
{
|
||||
throw new \IPS\Login\Handler\OAuth2\Exception('unsupported_response_type');
|
||||
}
|
||||
@@ -154,13 +192,14 @@ class oAuthServerAuthorizationRequest
|
||||
/**
|
||||
* Get URL to redirect the user back to the client after successful authorization
|
||||
*
|
||||
* @param \IPS\Member $member The member
|
||||
* @param array $scopes The authorized scopes
|
||||
* @param \IPS\Member $member The member
|
||||
* @param array $scopes The authorized scopes
|
||||
* @return void
|
||||
*/
|
||||
public function authorized( \IPS\Member $member, $scopes )
|
||||
{
|
||||
$scopes = $this->client->choose_scopes ? $scopes : $this->scope;
|
||||
$device = \IPS\Member\Device::loadOrCreate( $member );
|
||||
|
||||
if ( $this->responseType === 'code' )
|
||||
{
|
||||
@@ -171,19 +210,23 @@ class oAuthServerAuthorizationRequest
|
||||
while ( \IPS\Db::i()->select( 'COUNT(*)', 'core_oauth_server_authorization_codes', array( 'client_id=? AND code=?', $this->client->client_id, $authorizationCode ) )->first() );
|
||||
|
||||
\IPS\Db::i()->insert( 'core_oauth_server_authorization_codes', array(
|
||||
'client_id' => $this->client->client_id,
|
||||
'redirect_uri' => $this->providedRedirectUri ?: NULL,
|
||||
'member_id' => $member->member_id,
|
||||
'expires' => time() + 60,
|
||||
'code' => $authorizationCode,
|
||||
'scope' => $scopes ? json_encode( $scopes ) : NULL
|
||||
'client_id' => $this->client->client_id,
|
||||
'redirect_uri' => $this->providedRedirectUri ?: NULL,
|
||||
'member_id' => $member->member_id,
|
||||
'expires' => time() + 60,
|
||||
'code' => $authorizationCode,
|
||||
'scope' => $scopes ? json_encode( $scopes ) : NULL,
|
||||
'code_challenge' => $this->codeChallenge,
|
||||
'code_challenge_method' => $this->codeChallengeMethod,
|
||||
'user_agent' => isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : NULL,
|
||||
'device_key' => $device ? $device->device_key : NULL
|
||||
) );
|
||||
|
||||
return $this->redirect( array( 'code' => $authorizationCode ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
$accessToken = $this->client->generateAccessToken( $member, $scopes, 'implicit', TRUE );
|
||||
$accessToken = $this->client->generateAccessToken( $member, $scopes, 'implicit', TRUE, NULL, isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : NULL, isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : NULL, $device );
|
||||
|
||||
$response = array( 'access_token' => $accessToken['access_token'], 'token_type' => 'bearer' );
|
||||
if ( $accessToken['access_token_expires'] )
|
||||
@@ -232,6 +275,12 @@ class oAuthServerAuthorizationRequest
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* If we're banned or validating, we'll show those screens instead */
|
||||
if ( \IPS\Member::loggedIn()->isBanned() or \IPS\Member::loggedIn()->members_bitoptions['validating'] )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Have we gone through it already? */
|
||||
if ( isset( \IPS\Request::i()->allow ) and \IPS\Login::compareHashes( (string) \IPS\Session::i()->csrfKey, (string) \IPS\Request::i()->csrfKey ) )
|
||||
{
|
||||
@@ -243,7 +292,7 @@ class oAuthServerAuthorizationRequest
|
||||
}
|
||||
|
||||
/* Does the client require it? */
|
||||
if ( $this->client->prompt !== 'automatic' )
|
||||
if ( !\in_array( $this->client->prompt, array( 'none', 'automatic' ) ) )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
@@ -253,15 +302,21 @@ class oAuthServerAuthorizationRequest
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Are we always bypassing? */
|
||||
if ( $this->client->prompt === 'none' )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Do we already have an access token with these scopes? */
|
||||
$accessToken = $this->client->getAccessToken( \IPS\Member::loggedIn(), $this->scope );
|
||||
if ( $accessToken )
|
||||
{
|
||||
\IPS\Request::i()->grantedScope = array_combine( json_decode( $accessToken['scope'], TRUE ), array_fill( 0, count( json_decode( $accessToken['scope'], TRUE ) ), TRUE ) );
|
||||
\IPS\Request::i()->grantedScope = $accessToken['scope'] ? array_combine( json_decode( $accessToken['scope'], TRUE ), array_fill( 0, \count( json_decode( $accessToken['scope'], TRUE ) ), TRUE ) ) : array();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/* No? We need a new token */
|
||||
return TRUE;
|
||||
}
|
||||
@@ -269,12 +324,23 @@ class oAuthServerAuthorizationRequest
|
||||
/**
|
||||
* Show authorization form
|
||||
*
|
||||
* @param string $requestedPromptType Requested prompt type, if provided
|
||||
* @param bool $loggedIn Has the user logged in?
|
||||
* @param string $requestedPromptType Requested prompt type, if provided
|
||||
* @param bool $loggedIn Has the user logged in?
|
||||
* @return void
|
||||
*/
|
||||
public function prompt( $requestedPromptType, $loggedIn )
|
||||
{
|
||||
/* If we're banned or validating, we'll show those screens instead */
|
||||
if ( \IPS\Member::loggedIn()->isBanned() )
|
||||
{
|
||||
\IPS\Output::i()->showBanned();
|
||||
exit;
|
||||
}
|
||||
elseif ( \IPS\Member::loggedIn()->members_bitoptions['validating'] )
|
||||
{
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=register&do=validating', 'front', 'register' ) );
|
||||
}
|
||||
|
||||
/* We mustn't have the redirect_uri in the URL when displaying the page as this needs to be handled securely (it will
|
||||
probably include a client-issued CSRF key) and if we use it in the URL, any third party scripts that may be being
|
||||
used on the community (tracking or advertisements, for example) will have access to it - this also makes the URI
|
||||
@@ -285,17 +351,28 @@ class oAuthServerAuthorizationRequest
|
||||
\IPS\Request::i()->setCookie( 'oauth_authorize', $key );
|
||||
|
||||
\IPS\Db::i()->insert( 'core_oauth_authorize_prompts', array(
|
||||
'session_id' => $key,
|
||||
'client_id' => $this->client->client_id,
|
||||
'response_type' => $this->responseType,
|
||||
'redirect_uri' => $this->providedRedirectUri ?: NULL,
|
||||
'scope' => implode( ' ', $this->scope ),
|
||||
'state' => $this->state,
|
||||
'timestamp' => time(),
|
||||
'logged_in' => FALSE
|
||||
'session_id' => $key,
|
||||
'client_id' => $this->client->client_id,
|
||||
'response_type' => $this->responseType,
|
||||
'redirect_uri' => $this->providedRedirectUri ?: NULL,
|
||||
'scope' => implode( ' ', $this->scope ),
|
||||
'state' => $this->state,
|
||||
'timestamp' => time(),
|
||||
'logged_in' => FALSE,
|
||||
'prompt' => \in_array( $requestedPromptType, array( 'login', 'reauthorize' ) ) ? $requestedPromptType : NULL,
|
||||
'code_challenge' => $this->codeChallenge,
|
||||
'code_challenge_method' => $this->codeChallengeMethod
|
||||
), TRUE );
|
||||
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'oauth/authorize/', 'interface' ) );
|
||||
|
||||
$url = \IPS\Http\Url::internal( 'oauth/authorize/', 'interface' );
|
||||
if ( isset( \IPS\Request::i()->_processLogin ) ) // This is if they clicked a social sign in button on the registration form throwing them back to here
|
||||
{
|
||||
$url = $url->setQueryString( array(
|
||||
'_processLogin' => \IPS\Request::i()->_processLogin,
|
||||
'csrfKey' => \IPS\Request::i()->csrfKey,
|
||||
) );
|
||||
}
|
||||
\IPS\Output::i()->redirect( $url );
|
||||
}
|
||||
|
||||
/* Construct the URL for this page */
|
||||
@@ -320,7 +397,7 @@ class oAuthServerAuthorizationRequest
|
||||
{
|
||||
if ( $success = $login->authenticate() )
|
||||
{
|
||||
\IPS\Db::i()->update( 'core_oauth_authorize_prompts', array( 'logged_in' => TRUE ), array( 'session_id=?', \IPS\Request::i()->cookie['oauth_authorize'] ) );
|
||||
\IPS\Db::i()->update( 'core_oauth_authorize_prompts', array( 'logged_in' => TRUE, 'prompt' => NULL ), array( 'session_id=?', \IPS\Request::i()->cookie['oauth_authorize'] ) );
|
||||
|
||||
if ( $success->mfa() )
|
||||
{
|
||||
@@ -367,9 +444,8 @@ class oAuthServerAuthorizationRequest
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'oauth_authorize', FALSE, array( 'sprintf' => array( \IPS\Settings::i()->board_name ) ) );
|
||||
\IPS\Output::i()->httpHeaders['X-Frame-Options'] = 'DENY';
|
||||
|
||||
/* Check we are not IP banned */
|
||||
$ipBanned = \IPS\Request::i()->ipAddressIsBanned();
|
||||
if ( $ipBanned )
|
||||
/* Check we are not banned */
|
||||
if ( \IPS\Request::i()->ipAddressIsBanned() or \IPS\Member::loggedIn()->isBanned() )
|
||||
{
|
||||
\IPS\Output::i()->showBanned();
|
||||
}
|
||||
@@ -379,7 +455,7 @@ try
|
||||
{
|
||||
/* Get our params */
|
||||
$loggedIn = FALSE;
|
||||
if ( !isset( \IPS\Request::i()->client_id ) )
|
||||
if ( !isset( \IPS\Request::i()->client_id ) and isset( \IPS\Request::i()->cookie['oauth_authorize'] ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -390,6 +466,15 @@ try
|
||||
$scope = $row['scope'];
|
||||
$state = $row['state'];
|
||||
$loggedIn = $row['logged_in'];
|
||||
$prompt = $row['prompt'];
|
||||
$codeChallenge = $row['code_challenge'];
|
||||
$codeChallengeMethod = $row['code_challenge_method'];
|
||||
|
||||
if ( isset( \IPS\Request::i()->prompt ) and \in_array( \IPS\Request::i()->prompt, array( 'login', 'reauthorize' ) ) )
|
||||
{
|
||||
\IPS\Db::i()->update( 'core_oauth_authorize_prompts', array( 'prompt' => \IPS\Request::i()->prompt ), array( 'session_id=?', \IPS\Request::i()->cookie['oauth_authorize'] ) );
|
||||
$prompt = \IPS\Request::i()->prompt;
|
||||
}
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
{
|
||||
@@ -403,10 +488,31 @@ try
|
||||
$redirectUri = \IPS\Request::i()->redirect_uri;
|
||||
$scope = \IPS\Request::i()->scope;
|
||||
$state = \IPS\Request::i()->state;
|
||||
$prompt = \IPS\Request::i()->prompt;
|
||||
$codeChallenge = isset( \IPS\Request::i()->code_challenge ) ? \IPS\Request::i()->code_challenge : NULL;
|
||||
$codeChallengeMethod = ( isset( \IPS\Request::i()->code_challenge_method ) and \in_array( \IPS\Request::i()->code_challenge_method, array( 'plain', 'S256' ) ) ) ? \IPS\Request::i()->code_challenge_method : NULL;
|
||||
}
|
||||
|
||||
/* Have we asked to register? */
|
||||
if ( isset( \IPS\Request::i()->register ) )
|
||||
{
|
||||
/* The authorize prompt data will probably expire before we're done, so put the referal URL (for after registration)
|
||||
to the full URL which will initiate a new prompt. But don't delete the current prompt data in case the user hits back */
|
||||
$url = \IPS\Http\Url::internal( 'oauth/authorize/', 'interface' )->setQueryString( array(
|
||||
'client_id' => $clientId,
|
||||
'response_type' => $responseType,
|
||||
'redirect_uri' => $redirectUri,
|
||||
'scope' => $scope,
|
||||
'state' => $state,
|
||||
'prompt' => ( $prompt === 'login' ) ? 'reauthorize' : $prompt, // We never need to log in immediately after registering, that's confusing
|
||||
) );
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=register', 'front', 'register' )->addRef( (string) $url )->setQueryString( 'oauth', 1 ) );
|
||||
exit;
|
||||
}
|
||||
|
||||
/* Init, validating client_id and redirect_uri */
|
||||
$request = oAuthServerAuthorizationRequest::init( $clientId, $redirectUri, $state );
|
||||
$request = oAuthServerAuthorizationRequest::init( $clientId, $redirectUri, $state, $codeChallenge, $codeChallengeMethod );
|
||||
$request->validate();
|
||||
|
||||
/* If site is offline, return temporarily_unavailable */
|
||||
if ( ( isset( \IPS\Settings::i()->setup_in_progress ) AND \IPS\Settings::i()->setup_in_progress ) or !\IPS\Settings::i()->site_online )
|
||||
@@ -426,17 +532,20 @@ try
|
||||
{
|
||||
$request->setScope( $scope );
|
||||
}
|
||||
|
||||
|
||||
/* Do we need them to be prompted? */
|
||||
$authorizedUrl = NULL;
|
||||
if ( $request->promptRequired( \IPS\Request::i()->prompt ) )
|
||||
if ( $request->promptRequired( $prompt ) )
|
||||
{
|
||||
$request->prompt( \IPS\Request::i()->prompt, $loggedIn );
|
||||
$request->prompt( $prompt, $loggedIn );
|
||||
}
|
||||
|
||||
|
||||
/* Still here? Go ahead */
|
||||
\IPS\Db::i()->delete( 'core_oauth_authorize_prompts', array( 'session_id=?', \IPS\Request::i()->cookie['oauth_authorize'] ) );
|
||||
\IPS\Request::i()->setCookie( 'oauth_authorize', NULL );
|
||||
if ( isset( \IPS\Request::i()->cookie['oauth_authorize'] ) )
|
||||
{
|
||||
\IPS\Db::i()->delete( 'core_oauth_authorize_prompts', array( 'session_id=?', \IPS\Request::i()->cookie['oauth_authorize'] ) );
|
||||
\IPS\Request::i()->setCookie( 'oauth_authorize', NULL );
|
||||
}
|
||||
\IPS\Output::i()->redirect( $request->authorized( \IPS\Member::loggedIn(), isset( \IPS\Request::i()->grantedScope ) ? array_keys( \IPS\Request::i()->grantedScope ) : array() ), NULL, 302 );
|
||||
}
|
||||
catch ( \IPS\Login\Handler\OAuth2\InitException $e )
|
||||
|
||||
@@ -7,12 +7,11 @@
|
||||
* @package Invision Community
|
||||
* @since 31 May 2017
|
||||
*/
|
||||
|
||||
define('REPORT_EXCEPTIONS', TRUE);
|
||||
\define('REPORT_EXCEPTIONS', TRUE);
|
||||
require '../../init.php';
|
||||
\IPS\Session\Front::i();
|
||||
|
||||
if ( isset( \IPS\Request::i()->state ) and $explodedData = explode( '-', \IPS\Request::i()->state ) and count( $explodedData ) === 4 and $destination = @base64_decode( $explodedData[1] ) )
|
||||
if ( isset( \IPS\Request::i()->state ) and $explodedData = explode( '-', \IPS\Request::i()->state ) and \count( $explodedData ) === 4 and $destination = @base64_decode( $explodedData[1] ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -61,6 +60,12 @@ if ( isset( \IPS\Request::i()->state ) and $explodedData = explode( '-', \IPS\Re
|
||||
}
|
||||
elseif ( isset( \IPS\Request::i()->code ) )
|
||||
{
|
||||
/* Sign in with Apple does not make name available any later in the process */
|
||||
if ( isset( \IPS\Request::i()->user ) )
|
||||
{
|
||||
$_SESSION['oauth_user'] = \IPS\Request::i()->user;
|
||||
}
|
||||
|
||||
$destination = $destination->setQueryString( 'code', \IPS\Request::i()->code );
|
||||
}
|
||||
|
||||
|
||||
Whitespace-only changes.
+62
-15
@@ -7,8 +7,7 @@
|
||||
* @package Invision Community
|
||||
* @since 29 Apr 2017
|
||||
*/
|
||||
|
||||
define('REPORT_EXCEPTIONS', TRUE);
|
||||
\define('REPORT_EXCEPTIONS', TRUE);
|
||||
require '../../init.php';
|
||||
|
||||
class oAuthServerTokenRequest
|
||||
@@ -87,7 +86,7 @@ class oAuthServerTokenRequest
|
||||
*/
|
||||
public function grantType( $grantType )
|
||||
{
|
||||
if ( !in_array( $grantType, array( 'authorization_code', 'implicit', 'client_credentials', 'password', 'refresh_token' ) ) )
|
||||
if ( !\in_array( $grantType, array( 'authorization_code', 'implicit', 'client_credentials', 'password', 'refresh_token' ) ) )
|
||||
{
|
||||
throw new \IPS\Login\Handler\OAuth2\Exception( 'unsupported_grant_type' );
|
||||
}
|
||||
@@ -99,7 +98,7 @@ class oAuthServerTokenRequest
|
||||
throw new \IPS\Login\Handler\OAuth2\Exception( 'unsupported_grant_type' );
|
||||
}
|
||||
}
|
||||
elseif ( !in_array( $grantType, explode( ',', $this->client->grant_types ) ) )
|
||||
elseif ( !\in_array( $grantType, explode( ',', $this->client->grant_types ) ) )
|
||||
{
|
||||
throw new \IPS\Login\Handler\OAuth2\Exception( 'unauthorized_client' );
|
||||
}
|
||||
@@ -111,10 +110,12 @@ class oAuthServerTokenRequest
|
||||
/**
|
||||
* Validate Authorization Code
|
||||
*
|
||||
* @param string $authorizationCode The Authorization Code
|
||||
* @param string $authorizationCode The Authorization Code
|
||||
* @param string|NULL $redirectUri The redirect URI, if provided
|
||||
* @param string|NULL $codeVerifier The code verifier, if provided
|
||||
* @return array|NULL
|
||||
*/
|
||||
public function validateAuthorizationCode( $authorizationCode, $redirectUri = NULL )
|
||||
public function validateAuthorizationCode( $authorizationCode, $redirectUri = NULL, $codeVerifier = NULL )
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -140,11 +141,45 @@ class oAuthServerTokenRequest
|
||||
return;
|
||||
}
|
||||
|
||||
/* If it has a code verifier, validate that */
|
||||
if ( $authorizationCode['code_challenge'] or $this->client->pkce !== 'none' )
|
||||
{
|
||||
if ( !$codeVerifier or !$authorizationCode['code_challenge'] )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $authorizationCode['code_challenge_method'] === 'S256' or $this->client->pkce === 'S256' )
|
||||
{
|
||||
$codeVerifier = rtrim( strtr( base64_encode( pack( 'H*', hash( 'sha256', $codeVerifier ) ) ), '+/', '-_' ), '=' );
|
||||
}
|
||||
|
||||
if ( !\IPS\Login::compareHashes( $authorizationCode['code_challenge'], $codeVerifier ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check we're not banned and not validating */
|
||||
$member = \IPS\Member::load( $authorizationCode['member_id'] );
|
||||
if ( $member->isBanned() or $member->members_bitoptions['validating'] )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Mark it used */
|
||||
\IPS\Db::i()->update( 'core_oauth_server_authorization_codes', array( 'used' => 1 ), array( 'client_id=? AND code=?', $authorizationCode['client_id'], $authorizationCode['code'] ) );
|
||||
|
||||
/* Return access token */
|
||||
return $this->client->generateAccessToken( \IPS\Member::load( $authorizationCode['member_id'] ), $authorizationCode['scope'] ? json_decode( $authorizationCode['scope'] ) : NULL, 'authorization_code', FALSE, $authorizationCode['code'] );
|
||||
try
|
||||
{
|
||||
$device = $authorizationCode['device_key'] ? \IPS\Member\Device::load( $authorizationCode['device_key'] ) : NULL;
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
{
|
||||
$device = NULL;
|
||||
}
|
||||
return $this->client->generateAccessToken( $member, $authorizationCode['scope'] ? json_decode( $authorizationCode['scope'] ) : NULL, 'authorization_code', FALSE, $authorizationCode['code'], $authorizationCode['user_agent'], isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : NULL, $device );
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
{
|
||||
@@ -156,7 +191,7 @@ class oAuthServerTokenRequest
|
||||
* Validate Password
|
||||
*
|
||||
* @param string $username Username
|
||||
* @param string $password Password
|
||||
* @param object $password The plaintext password provided by the user, wrapped in an object that can be cast to a string so it doesn't show in any logs
|
||||
* @param array|null $scope Scopes
|
||||
* @return array|NULL
|
||||
*/
|
||||
@@ -175,7 +210,10 @@ class oAuthServerTokenRequest
|
||||
$member = $method->authenticateUsernamePassword( $login, $username, $password );
|
||||
\IPS\Login::checkIfAccountIsLocked( $member, TRUE );
|
||||
|
||||
$accessToken = $this->client->generateAccessToken( $member, $scope, 'password' );
|
||||
if ( !$member->isBanned() and !$member->members_bitoptions['validating'] )
|
||||
{
|
||||
$accessToken = $this->client->generateAccessToken( $member, $scope, 'password', FALSE, NULL, isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : NULL, isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : NULL, NULL );
|
||||
}
|
||||
break;
|
||||
}
|
||||
catch ( \IPS\Login\Exception $e )
|
||||
@@ -192,7 +230,7 @@ class oAuthServerTokenRequest
|
||||
{
|
||||
if ( !$member or $failedMember->member_id != $failedMember->member_id )
|
||||
{
|
||||
$failedLogins = is_array( $failedMember->failed_logins ) ? $failedMember->failed_logins : array();
|
||||
$failedLogins = \is_array( $failedMember->failed_logins ) ? $failedMember->failed_logins : array();
|
||||
$failedLogins[ \IPS\Request::i()->ipAddress() ][] = time();
|
||||
$failedMember->failed_logins = $failedLogins;
|
||||
$failedMember->save();
|
||||
@@ -212,7 +250,7 @@ class oAuthServerTokenRequest
|
||||
{
|
||||
if ( $this->client->client_secret )
|
||||
{
|
||||
return $this->client->generateAccessToken( NULL, $scope, 'client_credentials', TRUE );
|
||||
return $this->client->generateAccessToken( NULL, $scope, 'client_credentials', TRUE, NULL, NULL, isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : NULL );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,7 +270,7 @@ class oAuthServerTokenRequest
|
||||
if ( $accessToken['member_id'] )
|
||||
{
|
||||
$member = \IPS\Member::load( $accessToken['member_id'] );
|
||||
if ( !$member->member_id )
|
||||
if ( !$member->member_id or $member->isBanned() or $member->members_bitoptions['validating'] )
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -241,7 +279,16 @@ class oAuthServerTokenRequest
|
||||
$originalScope = $accessToken['scope'] ? json_decode( $accessToken['scope'], TRUE ) : array();
|
||||
$scope = $newScope ? array_intersect( $originalScope, $newScope ) : $originalScope;
|
||||
|
||||
return $this->client->generateAccessToken( $member, $scope, 'refresh_token', TRUE );
|
||||
try
|
||||
{
|
||||
$device = $accessToken['device_key'] ? \IPS\Member\Device::load( $accessToken['device_key'] ) : NULL;
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
{
|
||||
$device = NULL;
|
||||
}
|
||||
|
||||
return $this->client->generateAccessToken( $member, $scope, 'refresh_token', TRUE, NULL, $accessToken['auth_user_agent'], isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : NULL, $device, $accessToken );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -305,10 +352,10 @@ try
|
||||
switch ( $request->grantType( \IPS\Request::i()->grant_type ) )
|
||||
{
|
||||
case 'authorization_code':
|
||||
$accessToken = $request->validateAuthorizationCode( \IPS\Request::i()->code, \IPS\Request::i()->redirect_uri );
|
||||
$accessToken = $request->validateAuthorizationCode( \IPS\Request::i()->code, \IPS\Request::i()->redirect_uri, isset( \IPS\Request::i()->code_verifier ) ? \IPS\Request::i()->code_verifier : NULL );
|
||||
break;
|
||||
case 'password':
|
||||
$accessToken = $request->validatePassword( \IPS\Request::i()->username, \IPS\Request::i()->password, isset( \IPS\Request::i()->scope ) ? explode( ' ', \IPS\Request::i()->scope ) : NULL );
|
||||
$accessToken = $request->validatePassword( \IPS\Request::i()->username, \IPS\Request::i()->protect('password'), isset( \IPS\Request::i()->scope ) ? explode( ' ', \IPS\Request::i()->scope ) : NULL );
|
||||
break;
|
||||
case 'client_credentials':
|
||||
$accessToken = $request->validateClientCredentials( isset( \IPS\Request::i()->scope ) ? explode( ' ', \IPS\Request::i()->scope ) : NULL );
|
||||
|
||||
Reference in new issue
Block a user