Skip to content

Instantly share code, notes, and snippets.

@AlmogBaku
Created December 6, 2015 00:29
Show Gist options
  • Save AlmogBaku/3164020daee67ec800dd to your computer and use it in GitHub Desktop.
Save AlmogBaku/3164020daee67ec800dd to your computer and use it in GitHub Desktop.
Patched OAuth Server to allow `password` grant without secret
<?php
/**
* Created by PhpStorm.
* User: AlmogBaku
* Date: 04/12/2015
* Time: 3:13 PM
*/
namespace Rimoto\ApiBundle\Security;
use OAuth2\OAuth2;
use OAuth2\OAuth2ServerException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class PatchedOAuth2 extends OAuth2
{
/**
* Grant or deny a requested access token.
*
* This would be called from the "/token" endpoint as defined in the spec.
* Obviously, you can call your endpoint whatever you want.
* Draft specifies that the authorization parameters should be retrieved from POST, but you can override to whatever method you like.
*
* @param Request $request (optional) The request
*
* @return Response
* @throws OAuth2ServerException
*
* @see http://tools.ietf.org/html/draft-ietf-oauth-v2-20#section-4
* @see http://tools.ietf.org/html/draft-ietf-oauth-v2-21#section-10.6
* @see http://tools.ietf.org/html/draft-ietf-oauth-v2-21#section-4.1.3
*
* @ingroup oauth2_section_4
*/
public function grantAccessToken(Request $request = null)
{
$filters = array(
"grant_type" => array(
"filter" => FILTER_VALIDATE_REGEXP,
"options" => array("regexp" => self::GRANT_TYPE_REGEXP),
"flags" => FILTER_REQUIRE_SCALAR
),
"scope" => array("flags" => FILTER_REQUIRE_SCALAR),
"code" => array("flags" => FILTER_REQUIRE_SCALAR),
"redirect_uri" => array("filter" => FILTER_SANITIZE_URL),
"username" => array("flags" => FILTER_REQUIRE_SCALAR),
"password" => array("flags" => FILTER_REQUIRE_SCALAR),
"refresh_token" => array("flags" => FILTER_REQUIRE_SCALAR),
);
if ($request === null) {
$request = Request::createFromGlobals();
}
// Input data by default can be either POST or GET
if ($request->getMethod() === 'POST') {
$inputData = $request->request->all();
} else {
$inputData = $request->query->all();
}
// Basic authorization header
$authHeaders = $this->getAuthorizationHeader($request);
// Filter input data
$input = filter_var_array($inputData, $filters);
// Grant Type must be specified.
if (!$input["grant_type"]) {
throw new OAuth2ServerException(self::HTTP_BAD_REQUEST, self::ERROR_INVALID_REQUEST, 'Invalid grant_type parameter or parameter missing');
}
// Authorize the client
$clientCredentials = $this->getClientCredentials($inputData, $authHeaders);
$client = $this->storage->getClient($clientCredentials[0]);
if (!$client) {
throw new OAuth2ServerException(self::HTTP_BAD_REQUEST, self::ERROR_INVALID_CLIENT, 'The client credentials are invalid');
}
if (($this->storage->checkClientCredentials($client, $clientCredentials[1]) === false) && ($input["grant_type"]!=self::GRANT_TYPE_USER_CREDENTIALS)) {
throw new OAuth2ServerException(self::HTTP_BAD_REQUEST, self::ERROR_INVALID_CLIENT, 'The client credentials are invalid');
}
if (!$this->storage->checkRestrictedGrantType($client, $input["grant_type"])) {
throw new OAuth2ServerException(self::HTTP_BAD_REQUEST, self::ERROR_UNAUTHORIZED_CLIENT, 'The grant type is unauthorized for this client_id');
}
// Do the granting
switch ($input["grant_type"]) {
case self::GRANT_TYPE_AUTH_CODE:
// returns array('data' => data, 'scope' => scope)
$stored = $this->grantAccessTokenAuthCode($client, $input);
break;
case self::GRANT_TYPE_USER_CREDENTIALS:
// returns: true || array('scope' => scope)
$stored = $this->grantAccessTokenUserCredentials($client, $input);
break;
case self::GRANT_TYPE_CLIENT_CREDENTIALS:
// returns: true || array('scope' => scope)
$stored = $this->grantAccessTokenClientCredentials($client, $input, $clientCredentials);
break;
case self::GRANT_TYPE_REFRESH_TOKEN:
// returns array('data' => data, 'scope' => scope)
$stored = $this->grantAccessTokenRefreshToken($client, $input);
break;
default:
if (filter_var($input["grant_type"], FILTER_VALIDATE_URL)) {
// returns: true || array('scope' => scope)
$stored = $this->grantAccessTokenExtension($client, $inputData, $authHeaders);
} else {
throw new OAuth2ServerException(self::HTTP_BAD_REQUEST, self::ERROR_INVALID_REQUEST, 'Invalid grant_type parameter or parameter missing');
}
}
if (!is_array($stored)) {
$stored = array();
}
// if no scope provided to check against $input['scope'] then application defaults are set
// if no data is provided than null is set
$stored += array('scope' => $this->getVariable(self::CONFIG_SUPPORTED_SCOPES, null), 'data' => null,
'access_token_lifetime' => $this->getVariable(self::CONFIG_ACCESS_LIFETIME),
'issue_refresh_token' => true, 'refresh_token_lifetime' => $this->getVariable(self::CONFIG_REFRESH_LIFETIME));
$scope = $stored['scope'];
if ($input["scope"]) {
// Check scope, if provided
if (!isset($stored["scope"]) || !$this->checkScope($input["scope"], $stored["scope"])) {
throw new OAuth2ServerException(self::HTTP_BAD_REQUEST, self::ERROR_INVALID_SCOPE, 'An unsupported scope was requested.');
}
$scope = $input["scope"];
}
$token = $this->createAccessToken($client, $stored['data'], $scope, $stored['access_token_lifetime'], $stored['issue_refresh_token'], $stored['refresh_token_lifetime']);
return new Response(json_encode($token), 200, $this->getJsonHeaders());
}
/**
* Returns HTTP headers for JSON.
*
* @see http://tools.ietf.org/html/draft-ietf-oauth-v2-20#section-5.1
* @see http://tools.ietf.org/html/draft-ietf-oauth-v2-20#section-5.2
*
* @return array
*
* @ingroup oauth2_section_5
*/
protected function getJsonHeaders()
{
return array(
'Content-Type' => 'application/json',
'Cache-Control' => 'no-store',
'Pragma' => 'no-cache',
);
}
}
parameters:
fos_oauth_server.server.class: Rimoto\ApiBundle\Security\PatchedOAuth2
@wadjeroudi
Copy link

Why rewrite getJsonHeaders ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment