Version 5.0.0 beta 1
This commit is contained in:
1 parent
25ddeb65d6
commit
15c7beabc5
6736 files changed
+627902
-497943
No files matched your search
+112
-94
@@ -7,7 +7,26 @@
|
||||
* @package Invision Community
|
||||
* @since 29 Apr 2017
|
||||
*/
|
||||
\define('REPORT_EXCEPTIONS', TRUE);
|
||||
|
||||
use IPS\Api\OAuthClient;
|
||||
use IPS\Db;
|
||||
use IPS\Dispatcher;
|
||||
use IPS\Dispatcher\External;
|
||||
use IPS\Http\Url;
|
||||
use IPS\Login;
|
||||
use IPS\Login\Handler\OAuth2\InitException;
|
||||
use IPS\Member;
|
||||
use IPS\Member\Device;
|
||||
use IPS\Output;
|
||||
use IPS\Request;
|
||||
use IPS\Session;
|
||||
use IPS\Session\Front;
|
||||
use IPS\Settings;
|
||||
use IPS\Theme;
|
||||
use const IPS\DEBUG_OAUTH_REDIRECTS;
|
||||
use const IPS\OAUTH_REQUIRES_HTTPS;
|
||||
|
||||
define('REPORT_EXCEPTIONS', TRUE);
|
||||
require '../../init.php';
|
||||
|
||||
class oAuthServerAuthorizationRequest
|
||||
@@ -69,43 +88,43 @@ class oAuthServerAuthorizationRequest
|
||||
/* Get the client */
|
||||
try
|
||||
{
|
||||
$obj->client = \IPS\Api\OAuthClient::load( $clientId );
|
||||
$obj->client = OAuthClient::load( $clientId );
|
||||
if ( !$obj->client->enabled )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
throw new OutOfRangeException;
|
||||
}
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
catch (OutOfRangeException $e )
|
||||
{
|
||||
throw new \IPS\Login\Handler\OAuth2\InitException('oauth_err_invalid_client');
|
||||
throw new InitException('oauth_err_invalid_client');
|
||||
}
|
||||
|
||||
/* Set the Redirect URI */
|
||||
$allowedRedirectUris = json_decode( $obj->client->redirect_uris );
|
||||
|
||||
if( \defined('\IPS\DEBUG_OAUTH_REDIRECTS') )
|
||||
if( defined('\IPS\DEBUG_OAUTH_REDIRECTS') )
|
||||
{
|
||||
$allowedRedirectUris = array_merge( $allowedRedirectUris, \IPS\DEBUG_OAUTH_REDIRECTS );
|
||||
$allowedRedirectUris = array_merge( $allowedRedirectUris, 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');
|
||||
throw new InitException('oauth_err_invalid_redirect_uri');
|
||||
}
|
||||
else
|
||||
{
|
||||
$obj->redirectUri = \IPS\Http\Url::external( $redirectUri );
|
||||
$obj->redirectUri = Url::external( $redirectUri );
|
||||
}
|
||||
}
|
||||
elseif ( \count( $allowedRedirectUris ) === 1 )
|
||||
elseif ( count( $allowedRedirectUris ) === 1 )
|
||||
{
|
||||
$obj->redirectUri = \IPS\Http\Url::external( array_shift( $allowedRedirectUris ) );
|
||||
$obj->redirectUri = Url::external( array_shift( $allowedRedirectUris ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new \IPS\Login\Handler\OAuth2\InitException('oauth_err_invalid_redirect_uri');
|
||||
throw new InitException('oauth_err_invalid_redirect_uri');
|
||||
}
|
||||
$obj->providedRedirectUri = $redirectUri;
|
||||
|
||||
@@ -149,14 +168,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');
|
||||
}
|
||||
@@ -192,24 +211,24 @@ class oAuthServerAuthorizationRequest
|
||||
/**
|
||||
* Get URL to redirect the user back to the client after successful authorization
|
||||
*
|
||||
* @param \IPS\Member $member The member
|
||||
* @param Member $member The member
|
||||
* @param array $scopes The authorized scopes
|
||||
* @return void
|
||||
*/
|
||||
public function authorized( \IPS\Member $member, $scopes )
|
||||
public function authorized( Member $member, $scopes )
|
||||
{
|
||||
$scopes = $this->client->choose_scopes ? $scopes : $this->scope;
|
||||
$device = \IPS\Member\Device::loadOrCreate( $member );
|
||||
$device = Device::loadOrCreate( $member );
|
||||
|
||||
if ( $this->responseType === 'code' )
|
||||
{
|
||||
do
|
||||
{
|
||||
$authorizationCode = \IPS\Login::generateRandomString( 64 );
|
||||
$authorizationCode = Login::generateRandomString( 64 );
|
||||
}
|
||||
while ( \IPS\Db::i()->select( 'COUNT(*)', 'core_oauth_server_authorization_codes', array( 'client_id=? AND code=?', $this->client->client_id, $authorizationCode ) )->first() );
|
||||
while ( 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(
|
||||
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,
|
||||
@@ -270,27 +289,27 @@ class oAuthServerAuthorizationRequest
|
||||
public function promptRequired( $requestedPromptType )
|
||||
{
|
||||
/* If we're not logged in, we definitely do, unless we cancelled */
|
||||
if ( !\IPS\Member::loggedIn()->member_id and ( !isset( \IPS\Request::i()->allow ) or \IPS\Request::i()->allow ) )
|
||||
if ( !Member::loggedIn()->member_id and ( !isset( Request::i()->allow ) or Request::i()->allow ) )
|
||||
{
|
||||
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'] )
|
||||
if ( Member::loggedIn()->isBanned() or Member::loggedIn()->members_bitoptions['validating'] )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* If our account is incomplete (e.g. no name or no email), show that screen instead */
|
||||
if( \IPS\Member::loggedIn()->member_id and !( \IPS\Member::loggedIn()->real_name and \IPS\Member::loggedIn()->email ) )
|
||||
if( Member::loggedIn()->member_id and !( Member::loggedIn()->real_name and Member::loggedIn()->email ) )
|
||||
{
|
||||
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 ) )
|
||||
if ( isset( Request::i()->allow ) and Login::compareHashes( (string) Session::i()->csrfKey, (string) Request::i()->csrfKey ) )
|
||||
{
|
||||
if ( !\IPS\Request::i()->allow )
|
||||
if ( !Request::i()->allow )
|
||||
{
|
||||
throw new \IPS\Login\Handler\OAuth2\Exception('access_denied');
|
||||
}
|
||||
@@ -298,7 +317,7 @@ class oAuthServerAuthorizationRequest
|
||||
}
|
||||
|
||||
/* Does the client require it? */
|
||||
if ( !\in_array( $this->client->prompt, array( 'none', 'automatic' ) ) )
|
||||
if ( !in_array( $this->client->prompt, array( 'none', 'automatic' ) ) )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
@@ -316,10 +335,10 @@ class oAuthServerAuthorizationRequest
|
||||
}
|
||||
|
||||
/* Do we already have an access token with these scopes? */
|
||||
$accessToken = $this->client->getAccessToken( \IPS\Member::loggedIn(), $this->scope );
|
||||
$accessToken = $this->client->getAccessToken( Member::loggedIn(), $this->scope );
|
||||
if ( $accessToken )
|
||||
{
|
||||
\IPS\Request::i()->grantedScope = $accessToken['scope'] ? array_combine( json_decode( $accessToken['scope'], TRUE ), array_fill( 0, \count( json_decode( $accessToken['scope'], TRUE ) ), TRUE ) ) : array();
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -337,26 +356,26 @@ class oAuthServerAuthorizationRequest
|
||||
public function prompt( $requestedPromptType, $loggedIn )
|
||||
{
|
||||
/* If we're banned or validating, we'll show those screens instead */
|
||||
if ( \IPS\Member::loggedIn()->member_id and \IPS\Member::loggedIn()->isBanned() )
|
||||
if ( Member::loggedIn()->member_id and Member::loggedIn()->isBanned() )
|
||||
{
|
||||
\IPS\Output::i()->showBanned();
|
||||
Output::i()->showBanned();
|
||||
exit;
|
||||
}
|
||||
elseif ( \IPS\Member::loggedIn()->members_bitoptions['validating'] )
|
||||
elseif ( Member::loggedIn()->members_bitoptions['validating'] )
|
||||
{
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=register&do=validating', 'front', 'register' ) );
|
||||
Output::i()->redirect( 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
|
||||
a bit cleaner */
|
||||
if ( isset( \IPS\Request::i()->client_id ) )
|
||||
if ( isset( Request::i()->client_id ) )
|
||||
{
|
||||
$key = md5( uniqid() );
|
||||
\IPS\Request::i()->setCookie( 'oauth_authorize', $key );
|
||||
Request::i()->setCookie( 'oauth_authorize', $key );
|
||||
|
||||
\IPS\Db::i()->insert( 'core_oauth_authorize_prompts', array(
|
||||
Db::i()->insert( 'core_oauth_authorize_prompts', array(
|
||||
'session_id' => $key,
|
||||
'client_id' => $this->client->client_id,
|
||||
'response_type' => $this->responseType,
|
||||
@@ -365,24 +384,24 @@ class oAuthServerAuthorizationRequest
|
||||
'state' => $this->state,
|
||||
'timestamp' => time(),
|
||||
'logged_in' => FALSE,
|
||||
'prompt' => \in_array( $requestedPromptType, array( 'login', 'reauthorize' ) ) ? $requestedPromptType : NULL,
|
||||
'prompt' => in_array( $requestedPromptType, array( 'login', 'reauthorize' ) ) ? $requestedPromptType : NULL,
|
||||
'code_challenge' => $this->codeChallenge,
|
||||
'code_challenge_method' => $this->codeChallengeMethod
|
||||
), TRUE );
|
||||
|
||||
$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::internal( 'oauth/authorize/', 'interface' );
|
||||
if ( isset( 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,
|
||||
'_processLogin' => Request::i()->_processLogin,
|
||||
'csrfKey' => Request::i()->csrfKey,
|
||||
) );
|
||||
}
|
||||
\IPS\Output::i()->redirect( $url );
|
||||
Output::i()->redirect( $url );
|
||||
}
|
||||
|
||||
/* Construct the URL for this page */
|
||||
$url = \IPS\Http\Url::internal( 'oauth/authorize/', 'interface' );
|
||||
$url = Url::internal( 'oauth/authorize/', 'interface' );
|
||||
|
||||
/* Get the scope definitions */
|
||||
$scopes = array();
|
||||
@@ -393,9 +412,9 @@ class oAuthServerAuthorizationRequest
|
||||
}
|
||||
|
||||
/* Do we need them to login? */
|
||||
if ( !\IPS\Member::loggedIn()->member_id or ( ( $this->client->prompt === 'login' or $requestedPromptType === 'login' ) and !$loggedIn ) )
|
||||
if ( !Member::loggedIn()->member_id or ( ( $this->client->prompt === 'login' or $requestedPromptType === 'login' ) and !$loggedIn ) )
|
||||
{
|
||||
$login = new \IPS\Login( $url );
|
||||
$login = new Login( $url );
|
||||
|
||||
$member = NULL;
|
||||
$error = NULL;
|
||||
@@ -403,16 +422,16 @@ class oAuthServerAuthorizationRequest
|
||||
{
|
||||
if ( $success = $login->authenticate() )
|
||||
{
|
||||
\IPS\Db::i()->update( 'core_oauth_authorize_prompts', array( 'logged_in' => TRUE, 'prompt' => NULL ), array( 'session_id=?', \IPS\Request::i()->cookie['oauth_authorize'] ) );
|
||||
Db::i()->update( 'core_oauth_authorize_prompts', array( 'logged_in' => TRUE, 'prompt' => NULL ), array( 'session_id=?', Request::i()->cookie['oauth_authorize'] ) );
|
||||
|
||||
if ( $success->mfa() )
|
||||
{
|
||||
$_SESSION['processing2FA'] = array( 'memberId' => $success->member->member_id, 'anonymous' => $success->anonymous, 'remember' => $success->rememberMe, 'destination' => (string) $url, 'handler' => $success->handler->id );
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=system&controller=login", 'front', 'login' )->setQueryString( '_mfaLogin', 1 ) );
|
||||
Output::i()->redirect( Url::internal( "app=core&module=system&controller=login", 'front', 'login' )->setQueryString( '_mfaLogin', 1 ) );
|
||||
}
|
||||
$success->process();
|
||||
|
||||
\IPS\Output::i()->redirect( $url );
|
||||
Output::i()->redirect( $url );
|
||||
}
|
||||
}
|
||||
catch ( \IPS\Login\Exception $e )
|
||||
@@ -423,7 +442,7 @@ class oAuthServerAuthorizationRequest
|
||||
$e->handler = $e->handler->id;
|
||||
$_SESSION['linkAccounts'] = json_encode( $e );
|
||||
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=login&do=link', 'front', 'login' )->setQueryString( 'ref', base64_encode( $url ) ) );
|
||||
Output::i()->redirect( Url::internal( 'app=core&module=system&controller=login&do=link', 'front', 'login' )->setQueryString( 'ref', base64_encode( $url ) ) );
|
||||
}
|
||||
|
||||
$error = $e->getMessage();
|
||||
@@ -431,37 +450,36 @@ class oAuthServerAuthorizationRequest
|
||||
|
||||
if ( $member === NULL )
|
||||
{
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'login', 'core', 'global' )->oauthLogin( $url, $this->client, $scopes, $login, $error );
|
||||
\IPS\Dispatcher::i()->finish();
|
||||
Output::i()->output = Theme::i()->getTemplate( 'login', 'core', 'global' )->oauthLogin( $url, $this->client, $scopes, $login, $error );
|
||||
Dispatcher::i()->finish();
|
||||
}
|
||||
}
|
||||
/* If we're logged in but the account is incomplete (e.g. social registration with hitherto unset name/email), redirect to complete registration first */
|
||||
elseif ( \IPS\Member::loggedIn()->member_id and !( \IPS\Member::loggedIn()->real_name and \IPS\Member::loggedIn()->email ) )
|
||||
elseif ( Member::loggedIn()->member_id and !( Member::loggedIn()->real_name and Member::loggedIn()->email ) )
|
||||
{
|
||||
$url = \IPS\Http\Url::internal( 'oauth/authorize/', 'interface' );
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=register&do=complete', 'front', 'register' )->addRef( $url )->setQueryString( 'oauth', 1 ) );
|
||||
$url = Url::internal( 'oauth/authorize/', 'interface' );
|
||||
Output::i()->redirect( Url::internal( 'app=core&module=system&controller=register&do=complete', 'front', 'register' )->addRef( $url )->setQueryString( 'oauth', 1 ) );
|
||||
}
|
||||
|
||||
/* Still here? Show an authorization screen */
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'login', 'core', 'global' )->oauthAuthorize( $url, $this->client, $scopes );
|
||||
\IPS\Dispatcher::i()->finish();
|
||||
Output::i()->output = Theme::i()->getTemplate( 'login', 'core', 'global' )->oauthAuthorize( $url, $this->client, $scopes );
|
||||
Dispatcher::i()->finish();
|
||||
}
|
||||
}
|
||||
|
||||
/* Init */
|
||||
\IPS\Session\Front::i();
|
||||
\IPS\Dispatcher\External::i();
|
||||
\IPS\Output::i()->bodyClasses[] = 'ipsLayout_minimal';
|
||||
\IPS\Output::i()->bodyClasses[] = 'ipsLayout_minimalNoHome';
|
||||
\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';
|
||||
\IPS\Output::i()->httpHeaders['Cross-Origin-Opener-Policy'] = 'same-origin';
|
||||
\IPS\Output::setCacheTime( false );
|
||||
Front::i();
|
||||
External::i();
|
||||
Output::i()->bodyClasses[] = 'ipsLayout_minimal';
|
||||
Output::i()->bodyClasses[] = 'ipsLayout_minimalNoHome';
|
||||
Output::i()->title = Member::loggedIn()->language()->addToStack( 'oauth_authorize', FALSE, array( 'sprintf' => array( Settings::i()->board_name ) ) );
|
||||
Output::i()->httpHeaders['X-Frame-Options'] = 'DENY';
|
||||
Output::i()->pageCaching = FALSE;
|
||||
|
||||
/* Check we are not banned */
|
||||
if ( \IPS\Request::i()->ipAddressIsBanned() or ( \IPS\Member::loggedIn()->member_id and \IPS\Member::loggedIn()->isBanned() ) )
|
||||
if ( Request::i()->ipAddressIsBanned() or ( Member::loggedIn()->member_id and Member::loggedIn()->isBanned() ) )
|
||||
{
|
||||
\IPS\Output::i()->showBanned();
|
||||
Output::i()->showBanned();
|
||||
}
|
||||
|
||||
/* Handle the OAuth request */
|
||||
@@ -469,11 +487,11 @@ try
|
||||
{
|
||||
/* Get our params */
|
||||
$loggedIn = FALSE;
|
||||
if ( !isset( \IPS\Request::i()->client_id ) and isset( \IPS\Request::i()->cookie['oauth_authorize'] ) )
|
||||
if ( !isset( Request::i()->client_id ) and isset( Request::i()->cookie['oauth_authorize'] ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
$row = \IPS\Db::i()->select( '*', 'core_oauth_authorize_prompts', array( 'session_id=?', \IPS\Request::i()->cookie['oauth_authorize'] ) )->first();
|
||||
$row = Db::i()->select( '*', 'core_oauth_authorize_prompts', array( 'session_id=?', Request::i()->cookie['oauth_authorize'] ) )->first();
|
||||
$clientId = $row['client_id'];
|
||||
$responseType = $row['response_type'];
|
||||
$redirectUri = $row['redirect_uri'];
|
||||
@@ -484,35 +502,35 @@ try
|
||||
$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' ) ) )
|
||||
if ( isset( Request::i()->prompt ) and in_array( 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;
|
||||
Db::i()->update( 'core_oauth_authorize_prompts', array( 'prompt' => Request::i()->prompt ), array( 'session_id=?', Request::i()->cookie['oauth_authorize'] ) );
|
||||
$prompt = Request::i()->prompt;
|
||||
}
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
catch (UnderflowException $e )
|
||||
{
|
||||
throw new \IPS\Login\Handler\OAuth2\InitException('oauth_err_invalid_client');
|
||||
throw new InitException('oauth_err_invalid_client');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$clientId = \IPS\Request::i()->client_id;
|
||||
$responseType = \IPS\Request::i()->response_type;
|
||||
$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;
|
||||
$clientId = Request::i()->client_id;
|
||||
$responseType = Request::i()->response_type;
|
||||
$redirectUri = Request::i()->redirect_uri;
|
||||
$scope = Request::i()->scope;
|
||||
$state = Request::i()->state;
|
||||
$prompt = Request::i()->prompt;
|
||||
$codeChallenge = isset( Request::i()->code_challenge ) ? Request::i()->code_challenge : NULL;
|
||||
$codeChallengeMethod = ( isset( Request::i()->code_challenge_method ) and in_array( Request::i()->code_challenge_method, array( 'plain', 'S256' ) ) ) ? Request::i()->code_challenge_method : NULL;
|
||||
}
|
||||
|
||||
/* Have we asked to register? */
|
||||
if ( isset( \IPS\Request::i()->register ) )
|
||||
if ( isset( 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(
|
||||
$url = Url::internal( 'oauth/authorize/', 'interface' )->setQueryString( array(
|
||||
'client_id' => $clientId,
|
||||
'response_type' => $responseType,
|
||||
'redirect_uri' => $redirectUri,
|
||||
@@ -520,7 +538,7 @@ try
|
||||
'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 ) );
|
||||
Output::i()->redirect( Url::internal( 'app=core&module=system&controller=register', 'front', 'register' )->addRef( (string) $url )->setQueryString( 'oauth', 1 ) );
|
||||
exit;
|
||||
}
|
||||
|
||||
@@ -529,13 +547,13 @@ try
|
||||
$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 )
|
||||
if ( ( isset( Settings::i()->setup_in_progress ) AND Settings::i()->setup_in_progress ) or !Settings::i()->site_online )
|
||||
{
|
||||
throw new \IPS\Login\Handler\OAuth2\Exception('temporarily_unavailable');
|
||||
}
|
||||
|
||||
/* HTTPs only */
|
||||
if ( \IPS\OAUTH_REQUIRES_HTTPS and !\IPS\Request::i()->isSecure() )
|
||||
if ( OAUTH_REQUIRES_HTTPS and !Request::i()->isSecure() )
|
||||
{
|
||||
throw new \IPS\Login\Handler\OAuth2\Exception( 'invalid_request', "request must be made with https" );
|
||||
}
|
||||
@@ -555,16 +573,16 @@ try
|
||||
}
|
||||
|
||||
/* Still here? Go ahead */
|
||||
if ( isset( \IPS\Request::i()->cookie['oauth_authorize'] ) )
|
||||
if ( isset( 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 );
|
||||
Db::i()->delete( 'core_oauth_authorize_prompts', array( 'session_id=?', Request::i()->cookie['oauth_authorize'] ) );
|
||||
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 );
|
||||
Output::i()->redirect( $request->authorized( Member::loggedIn(), isset( Request::i()->grantedScope ) ? array_keys( Request::i()->grantedScope ) : array() ), NULL, 302 );
|
||||
}
|
||||
catch ( \IPS\Login\Handler\OAuth2\InitException $e )
|
||||
catch ( InitException $e )
|
||||
{
|
||||
\IPS\Output::i()->error( $e->getMessage(), '2S361/2', 403 );
|
||||
Output::i()->error( $e->getMessage(), '2S361/2', 403 );
|
||||
}
|
||||
catch ( \IPS\Login\Handler\OAuth2\Exception $e )
|
||||
{
|
||||
@@ -573,9 +591,9 @@ catch ( \IPS\Login\Handler\OAuth2\Exception $e )
|
||||
{
|
||||
$response['error_description'] = $e->description;
|
||||
}
|
||||
\IPS\Output::i()->redirect( $request->redirect( $response ), NULL, 302 );
|
||||
Output::i()->redirect( $request->redirect( $response ), NULL, 302 );
|
||||
}
|
||||
catch ( Exception $e )
|
||||
{
|
||||
\IPS\Output::i()->redirect( $request->redirect( array( 'error' => 'server_error', 'error_description' => $e->getMessage() ) ), NULL, 302 );
|
||||
Output::i()->redirect( $request->redirect( array( 'error' => 'server_error', 'error_description' => $e->getMessage() ) ), NULL, 302 );
|
||||
}
|
||||
+87
-45
@@ -7,103 +7,145 @@
|
||||
* @package Invision Community
|
||||
* @since 31 May 2017
|
||||
*/
|
||||
\define('REPORT_EXCEPTIONS', TRUE);
|
||||
require '../../init.php';
|
||||
\IPS\Session\Front::i();
|
||||
use IPS\Http\Url;
|
||||
use IPS\Http\Url\Internal;
|
||||
use IPS\Member;
|
||||
use IPS\Output;
|
||||
use IPS\Request;
|
||||
use IPS\Session\Front;
|
||||
|
||||
if ( isset( \IPS\Request::i()->state ) and $explodedData = explode( '-', \IPS\Request::i()->state ) and \count( $explodedData ) === 4 and $destination = @base64_decode( $explodedData[1] ) )
|
||||
define('REPORT_EXCEPTIONS', TRUE);
|
||||
require '../../init.php';
|
||||
Front::i();
|
||||
|
||||
if ( isset( Request::i()->state ) and $explodedData = explode( '-', Request::i()->state ) and count( $explodedData ) === 4 and $destination = @base64_decode( $explodedData[1] ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
$destination = \IPS\Http\Url::createFromString( $destination )->setQueryString( array(
|
||||
'_processLogin' => $explodedData[0],
|
||||
'csrfKey' => $explodedData[2],
|
||||
'ref' => $explodedData[3],
|
||||
$destination = Url::createFromString( $destination )->setQueryString( array(
|
||||
'_processLogin' => $explodedData[0],
|
||||
'csrfKey' => $explodedData[2],
|
||||
'ref' => $explodedData[3],
|
||||
) );
|
||||
if ( !( $destination instanceof \IPS\Http\Url\Internal ) )
|
||||
if ( !( $destination instanceof Internal ) )
|
||||
{
|
||||
throw new \Exception;
|
||||
throw new Exception;
|
||||
}
|
||||
|
||||
if ( isset( \IPS\Request::i()->error ) )
|
||||
if ( isset( Request::i()->error ) )
|
||||
{
|
||||
foreach ( array( 'error', 'error_description', 'error_uri' ) as $k )
|
||||
{
|
||||
if ( isset( \IPS\Request::i()->$k ) )
|
||||
if ( isset( Request::i()->$k ) )
|
||||
{
|
||||
$destination = $destination->setQueryString( $k, \IPS\Request::i()->$k );
|
||||
$destination = $destination->setQueryString( $k, Request::i()->$k );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* OAuth 2 */
|
||||
if ( isset( \IPS\Request::i()->access_token ) )
|
||||
if ( isset( Request::i()->access_token ) )
|
||||
{
|
||||
foreach ( array( 'access_token', 'token_type', 'expires_in', 'scope', 'state' ) as $k )
|
||||
{
|
||||
if ( isset( \IPS\Request::i()->$k ) )
|
||||
if ( isset( Request::i()->$k ) )
|
||||
{
|
||||
$destination = $destination->setQueryString( $k, \IPS\Request::i()->$k );
|
||||
$destination = $destination->setQueryString( $k, Request::i()->$k );
|
||||
}
|
||||
}
|
||||
}
|
||||
/* OAuth 1 */
|
||||
elseif ( isset( \IPS\Request::i()->oauth_token ) )
|
||||
elseif ( isset( Request::i()->oauth_token ) )
|
||||
{
|
||||
foreach ( array( 'oauth_token', 'oauth_verifier', 'state' ) as $k )
|
||||
{
|
||||
if ( isset( \IPS\Request::i()->$k ) )
|
||||
if ( isset( Request::i()->$k ) )
|
||||
{
|
||||
$destination = $destination->setQueryString( $k, \IPS\Request::i()->$k );
|
||||
$destination = $destination->setQueryString( $k, Request::i()->$k );
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif ( isset( \IPS\Request::i()->code ) )
|
||||
elseif ( isset( Request::i()->code ) )
|
||||
{
|
||||
/* Sign in with Apple does not make name available any later in the process */
|
||||
if ( isset( \IPS\Request::i()->user ) )
|
||||
if ( isset( Request::i()->user ) )
|
||||
{
|
||||
$_SESSION['oauth_user'] = \IPS\Request::i()->user;
|
||||
$_SESSION['oauth_user'] = Request::i()->user;
|
||||
}
|
||||
|
||||
$destination = $destination->setQueryString( 'code', \IPS\Request::i()->code );
|
||||
$destination = $destination->setQueryString( 'code', Request::i()->code );
|
||||
}
|
||||
|
||||
/* If it's a POST request and the URL is quite long, we need to redirect via POST */
|
||||
if ( \IPS\Request::i()->requestMethod() === 'POST')
|
||||
if ( Request::i()->requestMethod() === 'POST')
|
||||
{
|
||||
if( empty( $destination->queryString['ref'] ) )
|
||||
{
|
||||
$destination = $destination->setQueryString( 'ref', base64_encode( (string) \IPS\Http\Url::baseUrl() ) );
|
||||
}
|
||||
|
||||
\IPS\Output::i()->redirect( $destination, httpStatusCode: 307 );
|
||||
@header( "Cache-control: no-cache, no-store, must-revalidate, max-age=0, s-maxage=0" );
|
||||
@header( "Expires: 0" );
|
||||
|
||||
$queryStringComponents = $destination->queryString;
|
||||
$destination = \IPS\Http\Url::createFromString( @base64_decode( $explodedData[1] ) );
|
||||
$output = <<<HTML
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>{$loading}</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>{$message}</noscript>
|
||||
<form style="display: none" action="{$destination}" method="POST">
|
||||
HTML;
|
||||
foreach ( $queryStringComponents as $k => $v )
|
||||
{
|
||||
if ( $k === 'ref' )
|
||||
{
|
||||
if ( !$v )
|
||||
{
|
||||
$v = base64_encode( (string) \IPS\Http\Url::baseUrl() );
|
||||
}
|
||||
}
|
||||
$output .= <<<HTML
|
||||
<input name="{$k}" value="{$v}" >
|
||||
HTML;
|
||||
|
||||
}
|
||||
$output .= <<<HTML
|
||||
<input type="submit" value="{$message}" />
|
||||
</form>
|
||||
<script>
|
||||
const form = document.querySelector('form');
|
||||
form.submit();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
HTML;
|
||||
echo $output;
|
||||
exit;
|
||||
}
|
||||
|
||||
\IPS\Output::i()->redirect( $destination );
|
||||
Output::i()->redirect( $destination );
|
||||
exit;
|
||||
}
|
||||
catch ( \Exception $e ) {}
|
||||
catch (Exception $e ) {}
|
||||
}
|
||||
|
||||
$url = (string) \IPS\Http\Url::internal( 'oauth/callback/', 'none' );
|
||||
$url = (string) Url::internal( 'oauth/callback/', 'none' );
|
||||
|
||||
/* Force no caching */
|
||||
@header( 'Cross-Origin-Opener-Policy: same-origin' );
|
||||
@header( "Cache-control: no-cache, no-store, must-revalidate, max-age=0, s-maxage=0" );
|
||||
@header( "Expires: 0" );
|
||||
?><!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title><?php echo \IPS\Member::loggedIn()->language()->get( 'loading' ); ?></title>
|
||||
<script>
|
||||
if ( window.location.hash ) {
|
||||
var hash = window.location.hash.substr( 0, 1 ) == '#' ? window.location.hash.substr( 1 ) : window.location.hash;
|
||||
window.location = "<?php echo $url; ?>?" + hash;
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<noscript><?php echo \IPS\Member::loggedIn()->language()->get( 'oauth_implicit_no_js' ); ?></noscript>
|
||||
</body>
|
||||
<head>
|
||||
<title><?php echo Member::loggedIn()->language()->get( 'loading' ); ?></title>
|
||||
<script>
|
||||
if ( window.location.hash ) {
|
||||
var hash = window.location.hash.substr( 0, 1 ) == '#' ? window.location.hash.substr( 1 ) : window.location.hash;
|
||||
window.location = "<?php echo $url; ?>?" + hash;
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<noscript><?php echo Member::loggedIn()->language()->get( 'oauth_implicit_no_js' ); ?></noscript>
|
||||
</body>
|
||||
</html>
|
||||
+60
-51
@@ -7,7 +7,17 @@
|
||||
* @package Invision Community
|
||||
* @since 29 Apr 2017
|
||||
*/
|
||||
\define('REPORT_EXCEPTIONS', TRUE);
|
||||
|
||||
use IPS\Api\OAuthClient;
|
||||
use IPS\Db;
|
||||
use IPS\Login;
|
||||
use IPS\Member;
|
||||
use IPS\Member\Device;
|
||||
use IPS\Output;
|
||||
use IPS\Request;
|
||||
use const IPS\OAUTH_REQUIRES_HTTPS;
|
||||
|
||||
define('REPORT_EXCEPTIONS', TRUE);
|
||||
require '../../init.php';
|
||||
|
||||
class oAuthServerTokenRequest
|
||||
@@ -31,13 +41,13 @@ class oAuthServerTokenRequest
|
||||
/* Get the client */
|
||||
try
|
||||
{
|
||||
$obj->client = \IPS\Api\OAuthClient::load( $clientId );
|
||||
$obj->client = OAuthClient::load( $clientId );
|
||||
if ( !$obj->client->enabled )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
throw new OutOfRangeException;
|
||||
}
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
catch (OutOfRangeException $e )
|
||||
{
|
||||
throw new \IPS\Login\Handler\OAuth2\Exception( 'invalid_client' );
|
||||
}
|
||||
@@ -47,27 +57,27 @@ class oAuthServerTokenRequest
|
||||
{
|
||||
$bruteForce = $obj->client->brute_force ? json_decode( $obj->client->brute_force, TRUE ) : array();
|
||||
|
||||
if ( isset( $bruteForce[ \IPS\Request::i()->ipAddress() ] ) and $bruteForce[ \IPS\Request::i()->ipAddress() ] >= 3 )
|
||||
if ( isset( $bruteForce[ Request::i()->ipAddress() ] ) and $bruteForce[ Request::i()->ipAddress() ] >= 3 )
|
||||
{
|
||||
throw new \IPS\Login\Handler\OAuth2\Exception( 'invalid_client', "blocked for too many authentication failures" );
|
||||
}
|
||||
|
||||
if ( password_verify( $clientSecret, $obj->client->client_secret ) )
|
||||
{
|
||||
if ( isset( $bruteForce[ \IPS\Request::i()->ipAddress() ] ) )
|
||||
if ( isset( $bruteForce[ Request::i()->ipAddress() ] ) )
|
||||
{
|
||||
unset( $bruteForce[ \IPS\Request::i()->ipAddress() ] );
|
||||
unset( $bruteForce[ Request::i()->ipAddress() ] );
|
||||
$obj->client->brute_force = json_encode( $bruteForce );
|
||||
$obj->client->save();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !isset( $bruteForce[ \IPS\Request::i()->ipAddress() ] ) )
|
||||
if ( !isset( $bruteForce[ Request::i()->ipAddress() ] ) )
|
||||
{
|
||||
$bruteForce[ \IPS\Request::i()->ipAddress() ] = 0;
|
||||
$bruteForce[ Request::i()->ipAddress() ] = 0;
|
||||
}
|
||||
$bruteForce[ \IPS\Request::i()->ipAddress() ]++;
|
||||
$bruteForce[ Request::i()->ipAddress() ]++;
|
||||
$obj->client->brute_force = json_encode( $bruteForce );
|
||||
$obj->client->save();
|
||||
|
||||
@@ -86,7 +96,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' );
|
||||
}
|
||||
@@ -98,7 +108,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' );
|
||||
}
|
||||
@@ -119,19 +129,19 @@ class oAuthServerTokenRequest
|
||||
{
|
||||
try
|
||||
{
|
||||
$authorizationCode = \IPS\Db::i()->select( '*', 'core_oauth_server_authorization_codes', array( 'client_id=? AND code=?', $this->client->client_id, $authorizationCode ) )->first();
|
||||
$authorizationCode = Db::i()->select( '*', 'core_oauth_server_authorization_codes', array( 'client_id=? AND code=?', $this->client->client_id, $authorizationCode ) )->first();
|
||||
|
||||
/* If it's expired, delete it and do not validate */
|
||||
if ( $authorizationCode['expires'] < time() )
|
||||
{
|
||||
\IPS\Db::i()->delete( 'core_oauth_server_authorization_codes', array( 'client_id=? AND code=?', $authorizationCode['client_id'], $authorizationCode['code'] ) );
|
||||
Db::i()->delete( 'core_oauth_server_authorization_codes', array( 'client_id=? AND code=?', $authorizationCode['client_id'], $authorizationCode['code'] ) );
|
||||
return;
|
||||
}
|
||||
|
||||
/* If it's already been used, this should be treated as an attack: revoke any access tokens already generated and do not validate */
|
||||
if ( $authorizationCode['used'] )
|
||||
{
|
||||
\IPS\Db::i()->update( 'core_oauth_server_access_tokens', array( 'status' => 'revoked' ), array( 'client_id=? AND authorization_code=?', $this->client->client_id, $authorizationCode['code'] ) );
|
||||
Db::i()->update( 'core_oauth_server_access_tokens', array( 'status' => 'revoked' ), array( 'client_id=? AND authorization_code=?', $this->client->client_id, $authorizationCode['code'] ) );
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -154,34 +164,34 @@ class oAuthServerTokenRequest
|
||||
$codeVerifier = rtrim( strtr( base64_encode( pack( 'H*', hash( 'sha256', $codeVerifier ) ) ), '+/', '-_' ), '=' );
|
||||
}
|
||||
|
||||
if ( !\IPS\Login::compareHashes( $authorizationCode['code_challenge'], $codeVerifier ) )
|
||||
if ( !Login::compareHashes( $authorizationCode['code_challenge'], $codeVerifier ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check we're not banned and not validating */
|
||||
$member = \IPS\Member::load( $authorizationCode['member_id'] );
|
||||
$member = 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'] ) );
|
||||
Db::i()->update( 'core_oauth_server_authorization_codes', array( 'used' => 1 ), array( 'client_id=? AND code=?', $authorizationCode['client_id'], $authorizationCode['code'] ) );
|
||||
|
||||
/* Return access token */
|
||||
try
|
||||
{
|
||||
$device = $authorizationCode['device_key'] ? \IPS\Member\Device::load( $authorizationCode['device_key'] ) : NULL;
|
||||
$device = $authorizationCode['device_key'] ? Device::load( $authorizationCode['device_key'] ) : NULL;
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
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 )
|
||||
catch (UnderflowException $e )
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -197,21 +207,18 @@ class oAuthServerTokenRequest
|
||||
*/
|
||||
public function validatePassword( $username, $password, $scope )
|
||||
{
|
||||
$member = NULL;
|
||||
$accessToken = NULL;
|
||||
$fails = [];
|
||||
$success = FALSE;
|
||||
$fails = array();
|
||||
|
||||
$login = new \IPS\Login();
|
||||
$login = new Login();
|
||||
|
||||
foreach ( $login->usernamePasswordMethods() as $method )
|
||||
{
|
||||
try
|
||||
{
|
||||
if( $member = $method->authenticateUsernamePassword( $login, $username, $password ) )
|
||||
{
|
||||
$success = TRUE;
|
||||
}
|
||||
\IPS\Login::checkIfAccountIsLocked( $member, TRUE );
|
||||
$member = $method->authenticateUsernamePassword( $login, $username, $password );
|
||||
Login::checkIfAccountIsLocked( $member, TRUE );
|
||||
|
||||
if ( !$member->isBanned() and !$member->members_bitoptions['validating'] )
|
||||
{
|
||||
@@ -223,21 +230,23 @@ class oAuthServerTokenRequest
|
||||
{
|
||||
if ( $e->getCode() === \IPS\Login\Exception::BAD_PASSWORD and $e->member )
|
||||
{
|
||||
$fails[ $e->member->member_id ] = $e->member;
|
||||
$e->member->failedLogin();
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e ) { }
|
||||
catch (Exception $e ) { }
|
||||
}
|
||||
|
||||
/* Record any fails if none of the sign-ins were successful */
|
||||
if( $success === TRUE )
|
||||
|
||||
foreach ( $fails as $failedMember )
|
||||
{
|
||||
foreach ( $fails as $failedMember )
|
||||
if ( !$member or $failedMember->member_id != $failedMember->member_id )
|
||||
{
|
||||
$failedMember->failedLogin();
|
||||
$failedLogins = is_array( $failedMember->failed_logins ) ? $failedMember->failed_logins : array();
|
||||
$failedLogins[ Request::i()->ipAddress() ][] = time();
|
||||
$failedMember->failed_logins = $failedLogins;
|
||||
$failedMember->save();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return $accessToken;
|
||||
}
|
||||
|
||||
@@ -270,7 +279,7 @@ class oAuthServerTokenRequest
|
||||
$member = NULL;
|
||||
if ( $accessToken['member_id'] )
|
||||
{
|
||||
$member = \IPS\Member::load( $accessToken['member_id'] );
|
||||
$member = Member::load( $accessToken['member_id'] );
|
||||
if ( !$member->member_id or $member->isBanned() or $member->members_bitoptions['validating'] )
|
||||
{
|
||||
return;
|
||||
@@ -282,9 +291,9 @@ class oAuthServerTokenRequest
|
||||
|
||||
try
|
||||
{
|
||||
$device = $accessToken['device_key'] ? \IPS\Member\Device::load( $accessToken['device_key'] ) : NULL;
|
||||
$device = $accessToken['device_key'] ? Device::load( $accessToken['device_key'] ) : NULL;
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
catch (UnderflowException $e )
|
||||
{
|
||||
$device = NULL;
|
||||
}
|
||||
@@ -298,19 +307,19 @@ class oAuthServerTokenRequest
|
||||
try
|
||||
{
|
||||
/* TLS only */
|
||||
if ( \IPS\OAUTH_REQUIRES_HTTPS and !\IPS\Request::i()->isSecure() )
|
||||
if ( OAUTH_REQUIRES_HTTPS and !Request::i()->isSecure() )
|
||||
{
|
||||
throw new \IPS\Login\Handler\OAuth2\Exception( 'invalid_request', "request must be made with https" );
|
||||
}
|
||||
|
||||
/* POST only */
|
||||
if ( \IPS\Request::i()->requestMethod() !== 'POST' )
|
||||
if ( Request::i()->requestMethod() !== 'POST' )
|
||||
{
|
||||
throw new \IPS\Login\Handler\OAuth2\Exception( 'invalid_request', "request must be a POST request" );
|
||||
}
|
||||
|
||||
/* Check we are not IP banned */
|
||||
$ipBanned = \IPS\Request::i()->ipAddressIsBanned();
|
||||
$ipBanned = Request::i()->ipAddressIsBanned();
|
||||
if ( $ipBanned )
|
||||
{
|
||||
throw new \IPS\Login\Handler\OAuth2\Exception( 'invalid_client', "IP Address banned" );
|
||||
@@ -350,19 +359,19 @@ try
|
||||
|
||||
/* Validate grant */
|
||||
$accessToken = NULL;
|
||||
switch ( $request->grantType( \IPS\Request::i()->grant_type ) )
|
||||
switch ( $request->grantType( Request::i()->grant_type ) )
|
||||
{
|
||||
case 'authorization_code':
|
||||
$accessToken = $request->validateAuthorizationCode( \IPS\Request::i()->code, \IPS\Request::i()->redirect_uri, isset( \IPS\Request::i()->code_verifier ) ? \IPS\Request::i()->code_verifier : NULL );
|
||||
$accessToken = $request->validateAuthorizationCode( Request::i()->code, Request::i()->redirect_uri, isset( Request::i()->code_verifier ) ? Request::i()->code_verifier : NULL );
|
||||
break;
|
||||
case 'password':
|
||||
$accessToken = $request->validatePassword( \IPS\Request::i()->username, \IPS\Request::i()->protect('password'), isset( \IPS\Request::i()->scope ) ? explode( ' ', \IPS\Request::i()->scope ) : NULL );
|
||||
$accessToken = $request->validatePassword( Request::i()->username, Request::i()->protect('password'), isset( Request::i()->scope ) ? explode( ' ', Request::i()->scope ) : NULL );
|
||||
break;
|
||||
case 'client_credentials':
|
||||
$accessToken = $request->validateClientCredentials( isset( \IPS\Request::i()->scope ) ? explode( ' ', \IPS\Request::i()->scope ) : NULL );
|
||||
$accessToken = $request->validateClientCredentials( isset( Request::i()->scope ) ? explode( ' ', Request::i()->scope ) : NULL );
|
||||
break;
|
||||
case 'refresh_token':
|
||||
$accessToken = $request->validateRefreshToken( \IPS\Request::i()->refresh_token, isset( \IPS\Request::i()->scope ) ? explode( ' ', \IPS\Request::i()->scope ) : NULL );
|
||||
$accessToken = $request->validateRefreshToken( Request::i()->refresh_token, isset( Request::i()->scope ) ? explode( ' ', Request::i()->scope ) : NULL );
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -383,7 +392,7 @@ try
|
||||
$response['scope'] = implode( ' ', json_decode( $accessToken['scope'], TRUE ) );
|
||||
}
|
||||
|
||||
\IPS\Output::i()->sendOutput( json_encode( $response ), 200, 'application/json', array( 'Cache-Control' => 'no-cache, no-store, must-revalidate, max-age=0, s-maxage=0', 'Pragma' => 'no-cache' ), FALSE, FALSE, FALSE );
|
||||
Output::i()->sendOutput( json_encode( $response ), 200, 'application/json', array( 'Cache-Control' => 'no-cache, no-store, must-revalidate, max-age=0, s-maxage=0', 'Pragma' => 'no-cache' ), FALSE, FALSE, FALSE );
|
||||
|
||||
}
|
||||
else
|
||||
@@ -398,9 +407,9 @@ catch ( \IPS\Login\Handler\OAuth2\Exception $e )
|
||||
{
|
||||
$response['error_description'] = $e->description;
|
||||
}
|
||||
\IPS\Output::i()->sendOutput( json_encode( $response ), $e->getMessage() === 'invalid_client' ? 401 : 400, 'application/json', array( 'Cache-Control' => 'no-cache, no-store, must-revalidate, max-age=0, s-maxage=0' ), FALSE, FALSE, FALSE );
|
||||
Output::i()->sendOutput( json_encode( $response ), $e->getMessage() === 'invalid_client' ? 401 : 400, 'application/json', array( 'Cache-Control' => 'no-cache, no-store, must-revalidate, max-age=0, s-maxage=0' ), FALSE, FALSE, FALSE );
|
||||
}
|
||||
catch ( Exception $e )
|
||||
{
|
||||
\IPS\Output::i()->sendOutput( json_encode( array( 'error' => 'server_error', 'error_description' => $e->getMessage() ) ), 500, 'application/json', array( 'Cache-Control' => 'no-cache, no-store, must-revalidate, max-age=0, s-maxage=0' ), FALSE, FALSE, FALSE );
|
||||
Output::i()->sendOutput( json_encode( array( 'error' => 'server_error', 'error_description' => $e->getMessage() ) ), 500, 'application/json', array( 'Cache-Control' => 'no-cache, no-store, must-revalidate, max-age=0, s-maxage=0' ), FALSE, FALSE, FALSE );
|
||||
}
|
||||
Reference in new issue
Block a user