diff --git a/src/OAuth2/ClientAssertionType/HttpBasic.php b/src/OAuth2/ClientAssertionType/HttpBasic.php index eef5a2ef6..0811edb9b 100644 --- a/src/OAuth2/ClientAssertionType/HttpBasic.php +++ b/src/OAuth2/ClientAssertionType/HttpBasic.php @@ -117,6 +117,18 @@ public function getClientCredentials(RequestInterface $request, &$errors = null) ); } + if ($authorizationHeader = $request->getServerParams()["HTTP_AUTHORIZATION"]) { + $exploded = explode(':', base64_decode(substr($authorizationHeader, 6))); + if (count($exploded) != 2) { + return null; + } + + $result = []; + list($result['client_id'], $result['client_secret']) = $exploded; + return $result; + + } + if ($this->config['allow_credentials_in_request_body']) { $body = json_decode((string) $request->getBody(), true); // Using POST for HttpBasic authorization is not recommended, but is supported by specification diff --git a/src/OAuth2/Controller/ResourceController.php b/src/OAuth2/Controller/ResourceController.php index 14f75317d..ab58b7eb2 100644 --- a/src/OAuth2/Controller/ResourceController.php +++ b/src/OAuth2/Controller/ResourceController.php @@ -2,12 +2,12 @@ namespace OAuth2\Controller; -use OAuth2\ResponseException; use OAuth2\TokenType\TokenTypeInterface; use OAuth2\Storage\AccessTokenInterface; use OAuth2\ScopeInterface; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\StreamInterface; use OAuth2\Scope; /** @@ -37,7 +37,7 @@ public function __construct(TokenTypeInterface $tokenType, AccessTokenInterface $this->scopeUtil = $scopeUtil; } - public function verifyResourceRequest(RequestInterface $request, ResponseInterface $response, $scope = null) + public function verifyResourceRequest(RequestInterface $request, ResponseInterface $response, StreamInterface $stream, $scope = null) { try { $token = $this->getAccessTokenData($request, $response); @@ -70,15 +70,19 @@ public function verifyResourceRequest(RequestInterface $request, ResponseInterfa } } + $stream->write($e->getMessage()); + return $response - ->withStatusCode($e->getStatusCode() ?: 401) - ->withHeader('WWW-Authenticate' => $authHeader); + ->withStatus($e->getStatusCode() ?: 401) + ->withHeader('WWW-Authenticate', $authHeader) + ->withHeader('Content-Type', 'application/json') + ->withBody($stream); } // allow retrieval of the token $this->token = $token; - return (bool) $token; + return $response; } public function getAccessTokenData(RequestInterface $request, ResponseInterface $response) @@ -110,3 +114,27 @@ public function getToken() return $this->token; } } + +class ResponseException extends \LogicException { + + public function __construct($short_code, $description){ + $this->shortCode = $short_code; + $this->description = $description; + $this->statusCode = 401; + parent::__construct(json_encode(['code'=>$short_code, 'error_description' => $description]), $this->statusCode); + + } + + public function getDescription(){ + return $this->description; + } + + public function getShortCode(){ + return $this->shortCode; + } + + public function getStatusCode(){ + return $this->statusCode; + } + +} diff --git a/src/OAuth2/Controller/ResourceControllerInterface.php b/src/OAuth2/Controller/ResourceControllerInterface.php index 91988b240..29bf78e58 100644 --- a/src/OAuth2/Controller/ResourceControllerInterface.php +++ b/src/OAuth2/Controller/ResourceControllerInterface.php @@ -4,6 +4,7 @@ use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\StreamInterface; /** * This controller is called when a "resource" is requested. @@ -20,7 +21,7 @@ */ interface ResourceControllerInterface { - public function verifyResourceRequest(RequestInterface $request, ResponseInterface $response, $scope = null); + public function verifyResourceRequest(RequestInterface $request, ResponseInterface $response, StreamInterface $stream, $scope = null); public function getAccessTokenData(RequestInterface $request, ResponseInterface $response); } diff --git a/src/OAuth2/Controller/TokenController.php b/src/OAuth2/Controller/TokenController.php index a7e6b0e58..1db896e37 100644 --- a/src/OAuth2/Controller/TokenController.php +++ b/src/OAuth2/Controller/TokenController.php @@ -10,7 +10,7 @@ use OAuth2\Storage\ClientInterface; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; -use Zend\Diactoros\Stream; +use Psr\Http\Message\StreamInterface; /** * @see OAuth2\Controller\TokenControllerInterface @@ -45,29 +45,33 @@ public function __construct(AccessTokenInterface $accessToken, ClientInterface $ $this->scopeUtil = $scopeUtil; } - public function handleTokenRequest(RequestInterface $request, ResponseInterface $response) + public function handleTokenRequest(RequestInterface $request, ResponseInterface $response, StreamInterface $stream) { $errors = null; - $body = new Stream('php://temp', 'rw'); + if($stream->getContents()!="") { + throw new \LogicException("Stream has to be empty"); + } if ($token = $this->grantAccessToken($request, $errors)) { // @see http://tools.ietf.org/html/rfc6749#section-5.1 // server MUST disable caching in headers when tokens are involved - $body->write(json_encode($token)); + $stream->write(json_encode($token)); return $response ->withStatus(200) ->withHeader('Cache-Control', 'no-store') + ->withHeader('Content-Type', 'application/json') ->withHeader('Pragma', 'no-cache') - ->withBody($body); + ->withBody($stream); } - $body->write(json_encode(array_filter(array( - 'error' => $error['code'], - 'error_description' => $error['description'], - 'error_uri' => $error['uri'], + $stream->write(json_encode(array_filter(array( + 'error' => $errors['code'], + 'error_description' => $errors['description'], + 'error_uri' => $errors['uri'] ?? null, )))); return $response ->withStatus($errors['code'] == 'invalid_method' ? 405 : 400) - ->withBody($body); + ->withHeader('Content-Type', 'application/json') + ->withBody($stream); } /** @@ -99,6 +103,7 @@ public function grantAccessToken(RequestInterface $request, &$errors = null) return false; } + $body = json_decode((string) $request->getBody(), true); /** @@ -128,6 +133,7 @@ public function grantAccessToken(RequestInterface $request, &$errors = null) $grantType = $this->grantTypes[$grantTypeIdentifier]; + /** * Retrieve the client information from the request * ClientAssertionTypes allow for grant types which also assert the client data @@ -149,8 +155,17 @@ public function grantAccessToken(RequestInterface $request, &$errors = null) */ $grantType->validateRequest($request, $response); + if ($grantType instanceof ClientAssertionTypeInterface) { $clientId = $grantType->getClientId(); + if(empty($clientId)) { + $errors = array( + 'code' => 'invalid_client', + 'description' => 'client ID doesn\'t exists', + ); + + return false; + } } else { // validate the Client ID (if applicable) if (!is_null($storedClientId = $grantType->getClientId()) && $storedClientId != $clientId) { @@ -163,6 +178,8 @@ public function grantAccessToken(RequestInterface $request, &$errors = null) } } + + /** * Validate the client can use the requested grant type */ diff --git a/src/OAuth2/Controller/TokenControllerInterface.php b/src/OAuth2/Controller/TokenControllerInterface.php index 1aa720299..bb33b1c1f 100644 --- a/src/OAuth2/Controller/TokenControllerInterface.php +++ b/src/OAuth2/Controller/TokenControllerInterface.php @@ -4,6 +4,8 @@ use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\StreamInterface; + /** * This controller is called when a token is being requested. @@ -26,7 +28,7 @@ interface TokenControllerInterface * OAuth2\ResponseInterface - An instance of OAuth2\ResponseInterface to contain the response data * */ - public function handleTokenRequest(RequestInterface $request, ResponseInterface $response); + public function handleTokenRequest(RequestInterface $request, ResponseInterface $response, StreamInterface $stream); public function grantAccessToken(RequestInterface $request, &$errors = null); } diff --git a/src/OAuth2/Server.php b/src/OAuth2/Server.php index d90286f99..8eb1b8353 100644 --- a/src/OAuth2/Server.php +++ b/src/OAuth2/Server.php @@ -34,8 +34,7 @@ use OAuth2\Storage\JwtAccessTokenInterface; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; -use Zend\Diactoros\Response; -use Zend\Diactoros\ServerRequestFactory; +use Psr\Http\Message\StreamInterface; /** * Server class for OAuth2 @@ -254,9 +253,9 @@ public function handleUserInfoRequest(RequestInterface $request, ResponseInterfa * * @ingroup oauth2_section_4 */ - public function handleTokenRequest(RequestInterface $request, ResponseInterface $response = null) + public function handleTokenRequest(RequestInterface $request, ResponseInterface $response, StreamInterface $stream) { - return $this->getTokenController()->handleTokenRequest($request, $response ?: new Response()); + return $this->getTokenController()->handleTokenRequest($request, $response, $stream); } public function grantAccessToken(RequestInterface $request, &$errors = null) @@ -336,12 +335,9 @@ public function validateAuthorizeRequest(RequestInterface $request, &$errors = n return $this->getAuthorizeController()->validateAuthorizeRequest($request, $errors); } - public function verifyResourceRequest(RequestInterface $request, ResponseInterface $response = null, $scope = null) + public function verifyResourceRequest(RequestInterface $request, ResponseInterface $response, StreamInterface $stream, $scope = null) : ResponseInterface { - $this->response = is_null($response) ? new Response() : $response; - $value = $this->getResourceController()->verifyResourceRequest($request, $this->response, $scope); - - return $value; + return $this->getResourceController()->verifyResourceRequest($request, $response, $stream, $scope); } public function getAccessTokenData(RequestInterface $request, ResponseInterface $response = null) diff --git a/src/OAuth2/TokenType/Bearer.php b/src/OAuth2/TokenType/Bearer.php index afa148ee4..f18756061 100644 --- a/src/OAuth2/TokenType/Bearer.php +++ b/src/OAuth2/TokenType/Bearer.php @@ -3,6 +3,7 @@ namespace OAuth2\TokenType; use Psr\Http\Message\RequestInterface; +use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; /** @@ -30,12 +31,12 @@ public function getTokenType() * * @see https://github.com/bshaffer/oauth2-server-php/issues/349#issuecomment-37993588 */ - public function requestHasToken(RequestInterface $request) + public function requestHasToken(ServerRequestInterface $request) { - $headers = $request->headers('AUTHORIZATION'); + $header = $request->getHeader('AUTHORIZATION'); // check the header, then the querystring, then the request body - return !empty($headers) || (bool) ($request->request($this->config['token_param_name'])) || (bool) ($request->query($this->config['token_param_name'])); + return !empty($header) || (bool) ($request->getAttribute($this->config['token_param_name'])) || (bool) ($request->getQueryParams()[$this->config['token_param_name']]); } /** @@ -60,9 +61,9 @@ public function requestHasToken(RequestInterface $request) * @see http://code.google.com/p/android/issues/detail?id=6684 * */ - public function getAccessTokenParameter(RequestInterface $request, ResponseInterface $response) + public function getAccessTokenParameter(ServerRequestInterface $request, ResponseInterface $response) { - $headers = $request->headers('AUTHORIZATION'); + $headers = $request->getHeader('AUTHORIZATION'); /** * Ensure more than one method is not used for including an @@ -70,7 +71,7 @@ public function getAccessTokenParameter(RequestInterface $request, ResponseInter * * @see http://tools.ietf.org/html/rfc6750#section-3.1 */ - $methodsUsed = !empty($headers) + (bool) ($request->query($this->config['token_param_name'])) + (bool) ($request->request($this->config['token_param_name'])); + $methodsUsed = !empty($headers) + (bool) ($request->getQueryParams()[$this->config['token_param_name']]) + (bool) ($request->getAttribute($this->config['token_param_name'])); if ($methodsUsed > 1) { $response->setError(400, 'invalid_request', 'Only one method may be used to authenticate at a time (Auth header, GET or POST)'); @@ -100,7 +101,7 @@ public function getAccessTokenParameter(RequestInterface $request, ResponseInter return $matches[1]; } - if ($request->request($this->config['token_param_name'])) { + if ($request->getAttribute($this->config['token_param_name'])) { // // POST: Get the token from POST data if (!in_array(strtolower($request->server('REQUEST_METHOD')), array('post', 'put'))) { $response->setError(400, 'invalid_request', 'When putting the token in the body, the method must be POST or PUT', '#section-2.2'); @@ -125,6 +126,6 @@ public function getAccessTokenParameter(RequestInterface $request, ResponseInter } // GET method - return $request->query($this->config['token_param_name']); + return $request->getQueryParams()[$this->config['token_param_name']]; } } diff --git a/src/OAuth2/TokenType/TokenTypeInterface.php b/src/OAuth2/TokenType/TokenTypeInterface.php index ffff778f1..edc6a30d9 100644 --- a/src/OAuth2/TokenType/TokenTypeInterface.php +++ b/src/OAuth2/TokenType/TokenTypeInterface.php @@ -2,7 +2,7 @@ namespace OAuth2\TokenType; -use Psr\Http\Message\RequestInterface; +use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; interface TokenTypeInterface @@ -17,5 +17,5 @@ public function getTokenType(); /** * Retrieves the token string from the request object */ - public function getAccessTokenParameter(RequestInterface $request, ResponseInterface $response); + public function getAccessTokenParameter(ServerRequestInterface $request, ResponseInterface $response); }