From e563230f1086cfc765a030a405729f55d0d53a69 Mon Sep 17 00:00:00 2001 From: ziege Date: Tue, 26 Mar 2013 17:17:01 +0100 Subject: [PATCH 1/3] Method to get all headers for the error response Method added to get all required headers for the error response, according to the RFC - the correct HTTP status code and the "WWW-Authenticate" header in special cases. --- src/OAuth2/AuthServer.php | 79 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/src/OAuth2/AuthServer.php b/src/OAuth2/AuthServer.php index 54fb7811..c31f3bde 100644 --- a/src/OAuth2/AuthServer.php +++ b/src/OAuth2/AuthServer.php @@ -117,6 +117,85 @@ class AuthServer 'invalid_refresh' => 'The refresh token is invalid.', ); + /** + * Exception error HTTP status codes + * @var array + * + * RFC 6749, section 4.1.2.1.: + * No 503 status code for 'temporarily_unavailable', because + * "a 503 Service Unavailable HTTP status code cannot be + * returned to the client via an HTTP redirect" + */ + protected static $exceptionHttpStatusCodes = array( + 'invalid_request' => 400, + 'unauthorized_client' => 400, + 'access_denied' => 401, + 'unsupported_response_type' => 400, + 'invalid_scope' => 400, + 'server_error' => 500, + 'temporarily_unavailable' => 400, + 'unsupported_grant_type' => 400, + 'invalid_client' => 401, + 'invalid_grant' => 400, + 'invalid_credentials' => 400, + 'invalid_refresh' => 400, + ); + + /** + * Get all headers that have to be send with the error response + * + * @param string $error The error message key + * @return array Array with header values + */ + public static function getExceptionHttpHeaders($error) + { + $headers = array(); + switch (self::$exceptionHttpStatusCodes[$error]) { + case 401: + $headers[] = 'HTTP/1.1 401 Unauthorized'; + break; + case 500: + $headers[] = 'HTTP/1.1 500 Internal Server Error'; + break; + case 501: + $headers[] = 'HTTP/1.1 501 Not Implemented'; + break; + case 400: + default: + $headers[] = 'HTTP/1.1 400 Bad Request'; + } + + // Add "WWW-Authenticate" header + // + // RFC 6749, section 5.2.: + // "If the client attempted to authenticate via the 'Authorization' + // request header field, the authorization server MUST + // respond with an HTTP 401 (Unauthorized) status code and + // include the "WWW-Authenticate" response header field + // matching the authentication scheme used by the client. + if ($error === 'invalid_client') { + $auth_scheme = null; + $request = new Request(); + if ($request->server('PHP_AUTH_USER') !== null) { + $auth_scheme = 'Basic'; + } else { + $auth_header = $request->header('Authorization'); + if ($auth_header !== null) { + if (strpos($auth_header, 'Bearer') === 0) { + $auth_scheme = 'Bearer'; + } elseif (strpos($auth_header, 'Basic') === 0) { + $auth_scheme = 'Basic'; + } + } + } + if ($auth_scheme !== null) { + $headers[] = "WWW-Authenticate: $auth_scheme realm=\"\""; + } + } + + return $headers; + } + /** * Get an exception message * From 3481ec8aa2fbf7bba8ec07b422dd461a5e3dc7fe Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Wed, 27 Mar 2013 14:26:46 +0000 Subject: [PATCH 2/3] Variable name fixes + little changes to support unit tests --- src/OAuth2/AuthServer.php | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/OAuth2/AuthServer.php b/src/OAuth2/AuthServer.php index c31f3bde..1e45f363 100644 --- a/src/OAuth2/AuthServer.php +++ b/src/OAuth2/AuthServer.php @@ -120,9 +120,9 @@ class AuthServer /** * Exception error HTTP status codes * @var array - * + * * RFC 6749, section 4.1.2.1.: - * No 503 status code for 'temporarily_unavailable', because + * No 503 status code for 'temporarily_unavailable', because * "a 503 Service Unavailable HTTP status code cannot be * returned to the client via an HTTP redirect" */ @@ -134,13 +134,13 @@ class AuthServer 'invalid_scope' => 400, 'server_error' => 500, 'temporarily_unavailable' => 400, - 'unsupported_grant_type' => 400, + 'unsupported_grant_type' => 501, 'invalid_client' => 401, 'invalid_grant' => 400, 'invalid_credentials' => 400, 'invalid_refresh' => 400, ); - + /** * Get all headers that have to be send with the error response * @@ -164,35 +164,37 @@ class AuthServer default: $headers[] = 'HTTP/1.1 400 Bad Request'; } - + // Add "WWW-Authenticate" header // - // RFC 6749, section 5.2.: + // RFC 6749, section 5.2.: // "If the client attempted to authenticate via the 'Authorization' // request header field, the authorization server MUST // respond with an HTTP 401 (Unauthorized) status code and // include the "WWW-Authenticate" response header field // matching the authentication scheme used by the client. + // @codeCoverageIgnoreStart if ($error === 'invalid_client') { - $auth_scheme = null; + $authScheme = null; $request = new Request(); if ($request->server('PHP_AUTH_USER') !== null) { - $auth_scheme = 'Basic'; + $authScheme = 'Basic'; } else { - $auth_header = $request->header('Authorization'); - if ($auth_header !== null) { - if (strpos($auth_header, 'Bearer') === 0) { - $auth_scheme = 'Bearer'; - } elseif (strpos($auth_header, 'Basic') === 0) { - $auth_scheme = 'Basic'; + $authHeader = $request->header('Authorization'); + if ($authHeader !== null) { + if (strpos($authHeader, 'Bearer') === 0) { + $authScheme = 'Bearer'; + } elseif (strpos($authHeader, 'Basic') === 0) { + $authScheme = 'Basic'; } } } - if ($auth_scheme !== null) { - $headers[] = "WWW-Authenticate: $auth_scheme realm=\"\""; + if ($authScheme !== null) { + $headers[] = 'WWW-Authenticate: '.$authScheme.' realm=""'; } } - + // @codeCoverageIgnoreEnd + return $headers; } From d53abc661c525b3785c5516df6e6f9f2a21b8203 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Wed, 27 Mar 2013 14:27:06 +0000 Subject: [PATCH 3/3] getExceptionHttpHeaders() unit tests --- tests/authorization/AuthServerTest.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/authorization/AuthServerTest.php b/tests/authorization/AuthServerTest.php index 0158b887..8b4c7bbe 100644 --- a/tests/authorization/AuthServerTest.php +++ b/tests/authorization/AuthServerTest.php @@ -50,6 +50,14 @@ class Authorization_Server_test extends PHPUnit_Framework_TestCase $this->assertEquals('access_denied', OAuth2\AuthServer::getExceptionType(2)); } + public function test_getExceptionHttpHeaders() + { + $this->assertEquals(array('HTTP/1.1 401 Unauthorized'), OAuth2\AuthServer::getExceptionHttpHeaders('access_denied')); + $this->assertEquals(array('HTTP/1.1 500 Internal Server Error'), OAuth2\AuthServer::getExceptionHttpHeaders('server_error')); + $this->assertEquals(array('HTTP/1.1 501 Not Implemented'), OAuth2\AuthServer::getExceptionHttpHeaders('unsupported_grant_type')); + $this->assertEquals(array('HTTP/1.1 400 Bad Request'), OAuth2\AuthServer::getExceptionHttpHeaders('invalid_refresh')); + } + public function test_hasGrantType() { $a = $this->returnDefault();