mirror of
https://github.com/alchemy-fr/Phraseanet.git
synced 2025-10-09 02:54:26 +00:00
implements oauth2.0 v9.0 Resource Owner Basic Credentials
This commit is contained in:
@@ -14,6 +14,8 @@ namespace Alchemy\Phrasea\Application;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -102,10 +104,20 @@ return call_user_func(function()
|
||||
|
||||
|
||||
$template = "api/auth/end_user_authorization.twig";
|
||||
$custom_template = $app['appbox']->get_registry()->get('GV_RootPath') . 'config/templates/web/api/auth/end_user_authorization/' . $client->get_id() . '.twig';
|
||||
|
||||
$custom_template = sprintf(
|
||||
"%sconfig/templates/web/api/auth/end_user_authorization/%s.twig"
|
||||
, $app['appbox']->get_registry()->get('GV_RootPath')
|
||||
, $client->get_id()
|
||||
);
|
||||
|
||||
|
||||
if (file_exists($custom_template))
|
||||
{
|
||||
$template = 'api/auth/end_user_authorization/' . $client->get_id() . '.twig';
|
||||
$template = sprintf(
|
||||
'api/auth/end_user_authorization/%s.twig'
|
||||
, $client->get_id()
|
||||
);
|
||||
}
|
||||
|
||||
if ( ! $authenticated)
|
||||
@@ -146,8 +158,11 @@ return call_user_func(function()
|
||||
}
|
||||
}
|
||||
|
||||
//check if current client is alreadu authorized by current user
|
||||
$user_auth_clients = \API_OAuth2_Application::load_authorized_app_by_user($app['appbox'], $app['Core']->getAuthenticatedUser());
|
||||
//check if current client is already authorized by current user
|
||||
$user_auth_clients = \API_OAuth2_Application::load_authorized_app_by_user(
|
||||
$app['appbox']
|
||||
, $app['Core']->getAuthenticatedUser()
|
||||
);
|
||||
|
||||
foreach ($user_auth_clients as $auth_client)
|
||||
{
|
||||
@@ -156,6 +171,7 @@ return call_user_func(function()
|
||||
}
|
||||
|
||||
$account = $oauth2_adapter->updateAccount($session->get_usr_id());
|
||||
|
||||
$params['account_id'] = $account->get_id();
|
||||
|
||||
if ( ! $app_authorized && $action_accept === null)
|
||||
@@ -203,8 +219,13 @@ return call_user_func(function()
|
||||
* Token endpoint - used to exchange an authorization grant for an access token.
|
||||
*/
|
||||
$route = '/token';
|
||||
$app->post($route, function() use ($app)
|
||||
$app->post($route, function(\Silex\Application $app, Request $request)
|
||||
{
|
||||
if(!$request->isSecure())
|
||||
{
|
||||
throw new HttpException(400, 'require the use of the https', null, array('content-type'=> 'application/json'));
|
||||
}
|
||||
|
||||
$app['oauth']->grantAccessToken();
|
||||
ob_flush();
|
||||
flush();
|
||||
@@ -431,9 +452,26 @@ return call_user_func(function()
|
||||
return new Response('The requested page could not be found.', 404);
|
||||
}
|
||||
|
||||
$code = $e instanceof HttpExceptionInterface ? $e->getStatusCode() : 500;
|
||||
$code = 500;
|
||||
$msg = 'We are sorry, but something went wrong';
|
||||
$headers = array();
|
||||
|
||||
return new Response('We are sorry, but something went wrong.<br />' . $e->getMessage(), $code);
|
||||
if($e instanceof HttpExceptionInterface)
|
||||
{
|
||||
$headers = $e->getHeaders();
|
||||
$msg = $e->getMessage();
|
||||
$code = $e->getStatusCode();
|
||||
|
||||
if(isset($headers['content-type']) && $headers['content-type'] == 'application/json')
|
||||
{
|
||||
$obj = new \stdClass();
|
||||
$obj->msg = $msg;
|
||||
$obj->code = $code;
|
||||
$msg = json_encode($obj);
|
||||
}
|
||||
}
|
||||
|
||||
return new Response($msg, $code, $headers);
|
||||
});
|
||||
|
||||
|
||||
|
@@ -195,7 +195,6 @@ class API_OAuth2_Adapter extends OAuth2
|
||||
$application = API_OAuth2_Application::load_from_client_id($this->appbox, $client_id);
|
||||
|
||||
if ($client_secret === NULL)
|
||||
|
||||
return true;
|
||||
|
||||
$crypted = $this->crypt_secret($client_secret, $application->get_nonce());
|
||||
@@ -285,7 +284,8 @@ class API_OAuth2_Adapter extends OAuth2
|
||||
protected function getSupportedGrantTypes()
|
||||
{
|
||||
return array(
|
||||
OAUTH2_GRANT_TYPE_AUTH_CODE
|
||||
OAUTH2_GRANT_TYPE_AUTH_CODE,
|
||||
OAUTH2_GRANT_TYPE_USER_CREDENTIALS
|
||||
);
|
||||
}
|
||||
|
||||
@@ -640,13 +640,11 @@ class API_OAuth2_Adapter extends OAuth2
|
||||
|
||||
|
||||
if ($token_param === FALSE) // Access token was not provided
|
||||
|
||||
return $exit_not_present ? $this->errorWWWAuthenticateResponseHeader(OAUTH2_HTTP_BAD_REQUEST, $realm, OAUTH2_ERROR_INVALID_REQUEST, 'The request is missing a required parameter, includes an unsupported parameter or parameter value, repeats the same parameter, uses more than one method for including an access token, or is otherwise malformed.', NULL, $scope) : FALSE;
|
||||
// Get the stored token data (from the implementing subclass)
|
||||
$token = $this->getAccessToken($token_param);
|
||||
|
||||
if ($token === NULL)
|
||||
|
||||
return $exit_invalid ? $this->errorWWWAuthenticateResponseHeader(OAUTH2_HTTP_UNAUTHORIZED, $realm, OAUTH2_ERROR_INVALID_TOKEN, 'The access token provided is invalid.', NULL, $scope) : FALSE;
|
||||
|
||||
if (isset($token['revoked']) && $token['revoked'])
|
||||
@@ -658,13 +656,11 @@ class API_OAuth2_Adapter extends OAuth2
|
||||
{
|
||||
// Check token expiration (I'm leaving this check separated, later we'll fill in better error messages)
|
||||
if (isset($token["expires"]) && time() > $token["expires"])
|
||||
|
||||
return $exit_expired ? $this->errorWWWAuthenticateResponseHeader(OAUTH2_HTTP_UNAUTHORIZED, $realm, OAUTH2_ERROR_EXPIRED_TOKEN, 'The access token provided has expired.', NULL, $scope) : FALSE;
|
||||
}
|
||||
// Check scope, if provided
|
||||
// If token doesn't have a scope, it's NULL/empty, or it's insufficient, then throw an error
|
||||
if ($scope && ( ! isset($token["scope"]) || ! $token["scope"] || ! $this->checkScope($scope, $token["scope"])))
|
||||
|
||||
return $exit_scope ? $this->errorWWWAuthenticateResponseHeader(OAUTH2_HTTP_FORBIDDEN, $realm, OAUTH2_ERROR_INSUFFICIENT_SCOPE, 'The request requires higher privileges than provided by the access token.', NULL, $scope) : FALSE;
|
||||
|
||||
//save token's linked ses_id
|
||||
@@ -740,17 +736,14 @@ class API_OAuth2_Adapter extends OAuth2
|
||||
case OAUTH2_GRANT_TYPE_AUTH_CODE:
|
||||
if ( ! $input["code"] || ! $input["redirect_uri"])
|
||||
$this->errorJsonResponse(OAUTH2_HTTP_BAD_REQUEST, OAUTH2_ERROR_INVALID_REQUEST);
|
||||
|
||||
$stored = $this->getAuthCode($input["code"]);
|
||||
|
||||
// Ensure that the input uri starts with the stored uri
|
||||
if ($stored === NULL || (strcasecmp(substr($input["redirect_uri"], 0, strlen($stored["redirect_uri"])), $stored["redirect_uri"]) !== 0) || $client[0] != $stored["client_id"])
|
||||
$this->errorJsonResponse(OAUTH2_HTTP_BAD_REQUEST, OAUTH2_ERROR_INVALID_GRANT);
|
||||
|
||||
|
||||
if ($stored["expires"] < time())
|
||||
$this->errorJsonResponse(OAUTH2_HTTP_BAD_REQUEST, OAUTH2_ERROR_EXPIRED_TOKEN);
|
||||
|
||||
break;
|
||||
case OAUTH2_GRANT_TYPE_USER_CREDENTIALS:
|
||||
if ( ! $input["username"] || ! $input["password"])
|
||||
@@ -759,7 +752,7 @@ class API_OAuth2_Adapter extends OAuth2
|
||||
$stored = $this->checkUserCredentials($client[0], $input["username"], $input["password"]);
|
||||
|
||||
if ($stored === FALSE)
|
||||
$this->errorJsonResponse(OAUTH2_HTTP_BAD_REQUEST, OAUTH2_ERROR_INVALID_GRANT);
|
||||
$this->errorJsonResponse(OAUTH2_HTTP_BAD_REQUEST, OAUTH2_ERROR_INVALID_GRANT, 'Unknow user');
|
||||
|
||||
break;
|
||||
case OAUTH2_GRANT_TYPE_ASSERTION:
|
||||
@@ -835,4 +828,30 @@ class API_OAuth2_Adapter extends OAuth2
|
||||
return $token;
|
||||
}
|
||||
|
||||
protected function checkUserCredentials($client_id, $username, $password)
|
||||
{
|
||||
try
|
||||
{
|
||||
$appbox = appbox::get_instance(\bootstrap::getCore());
|
||||
|
||||
$application = API_OAuth2_Application::load_from_client_id($appbox, $client_id);
|
||||
|
||||
$auth = new \Session_Authentication_Native($appbox, $username, $password);
|
||||
|
||||
$auth->challenge_password();
|
||||
|
||||
$account = API_OAuth2_Account::load_with_user($appbox, $application, $auth->get_user());
|
||||
|
||||
return array(
|
||||
'redirect_uri' => $application->get_redirect_uri()
|
||||
, 'client_id' => $application->get_client_id()
|
||||
, 'account_id' => $account->get_id()
|
||||
);
|
||||
}
|
||||
catch (\Exception $e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -15,14 +15,8 @@
|
||||
* @license http://opensource.org/licenses/gpl-3.0 GPLv3
|
||||
* @link www.phraseanet.com
|
||||
*/
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
require_once __DIR__ . "/../../../lib/bootstrap.php";
|
||||
|
||||
try
|
||||
{
|
||||
$app = require __DIR__ . '/../../../lib/Alchemy/Phrasea/Application/OAuth2.php';
|
||||
|
||||
$app->run();
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
return new Response('Internal Server Error', 500);
|
||||
}
|
||||
|
Reference in New Issue
Block a user