Merge pull request #604 from iansltx/http-basic-from-header

Look at Authorization header directly for HTTP Basic auth checks
This commit is contained in:
Alex Bilbie 2016-06-22 08:42:30 +01:00 committed by GitHub
commit 8b865cc523
2 changed files with 106 additions and 10 deletions

View File

@ -137,21 +137,15 @@ abstract class AbstractGrant implements GrantTypeInterface
*/ */
protected function validateClient(ServerRequestInterface $request) protected function validateClient(ServerRequestInterface $request)
{ {
$clientId = $this->getRequestParameter( list($basicAuthUser, $basicAuthPassword) = $this->getBasicAuthCredentials($request);
'client_id',
$request, $clientId = $this->getRequestParameter('client_id', $request, $basicAuthUser);
$this->getServerParameter('PHP_AUTH_USER', $request)
);
if (is_null($clientId)) { if (is_null($clientId)) {
throw OAuthServerException::invalidRequest('client_id'); throw OAuthServerException::invalidRequest('client_id');
} }
// If the client is confidential require the client secret // If the client is confidential require the client secret
$clientSecret = $this->getRequestParameter( $clientSecret = $this->getRequestParameter('client_secret', $request, $basicAuthPassword);
'client_secret',
$request,
$this->getServerParameter('PHP_AUTH_PW', $request)
);
$client = $this->clientRepository->getClientEntity( $client = $this->clientRepository->getClientEntity(
$clientId, $clientId,
@ -237,6 +231,38 @@ abstract class AbstractGrant implements GrantTypeInterface
return isset($requestParameters[$parameter]) ? $requestParameters[$parameter] : $default; return isset($requestParameters[$parameter]) ? $requestParameters[$parameter] : $default;
} }
/**
* Retrieve HTTP Basic Auth credentials with the Authorization header
* of a request. First index of the returned array is the username,
* second is the password (so list() will work). If the header does
* not exist, or is otherwise an invalid HTTP Basic header, return
* [null, null].
*
* @param \Psr\Http\Message\ServerRequestInterface $request
* @return string[]|null[]
*/
protected function getBasicAuthCredentials(ServerRequestInterface $request)
{
if (!$request->hasHeader('Authorization')) {
return [null, null];
}
$header = $request->getHeader('Authorization')[0];
if (strpos($header, 'Basic ') !== 0) {
return [null, null];
}
if (!($decoded = base64_decode(substr($header, 6)))) {
return [null, null];
}
if (strpos($decoded, ':') === false) {
return [null, null]; // HTTP Basic header without colon isn't valid
}
return explode(':', $decoded, 2);
}
/** /**
* Retrieve query string parameter. * Retrieve query string parameter.
* *

View File

@ -32,6 +32,76 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase
$grantMock->setEmitter(new Emitter()); $grantMock->setEmitter(new Emitter());
} }
public function testHttpBasicWithPassword()
{
/** @var AbstractGrant $grantMock */
$grantMock = $this->getMockForAbstractClass(AbstractGrant::class);
$abstractGrantReflection = new \ReflectionClass($grantMock);
$serverRequest = new ServerRequest();
$serverRequest = $serverRequest->withHeader('Authorization', 'Basic ' . base64_encode('Open:Sesame'));
$basicAuthMethod = $abstractGrantReflection->getMethod('getBasicAuthCredentials');
$basicAuthMethod->setAccessible(true);
$this->assertSame(['Open', 'Sesame'], $basicAuthMethod->invoke($grantMock, $serverRequest));
}
public function testHttpBasicNoPassword()
{
/** @var AbstractGrant $grantMock */
$grantMock = $this->getMockForAbstractClass(AbstractGrant::class);
$abstractGrantReflection = new \ReflectionClass($grantMock);
$serverRequest = new ServerRequest();
$serverRequest = $serverRequest->withHeader('Authorization', 'Basic ' . base64_encode('Open:'));
$basicAuthMethod = $abstractGrantReflection->getMethod('getBasicAuthCredentials');
$basicAuthMethod->setAccessible(true);
$this->assertSame(['Open', ''], $basicAuthMethod->invoke($grantMock, $serverRequest));
}
public function testHttpBasicNotBasic()
{
/** @var AbstractGrant $grantMock */
$grantMock = $this->getMockForAbstractClass(AbstractGrant::class);
$abstractGrantReflection = new \ReflectionClass($grantMock);
$serverRequest = new ServerRequest();
$serverRequest = $serverRequest->withHeader('Authorization', 'Foo ' . base64_encode('Open:Sesame'));
$basicAuthMethod = $abstractGrantReflection->getMethod('getBasicAuthCredentials');
$basicAuthMethod->setAccessible(true);
$this->assertSame([null, null], $basicAuthMethod->invoke($grantMock, $serverRequest));
}
public function testHttpBasicNotBase64()
{
/** @var AbstractGrant $grantMock */
$grantMock = $this->getMockForAbstractClass(AbstractGrant::class);
$abstractGrantReflection = new \ReflectionClass($grantMock);
$serverRequest = new ServerRequest();
$serverRequest = $serverRequest->withHeader('Authorization', 'Basic ||');
$basicAuthMethod = $abstractGrantReflection->getMethod('getBasicAuthCredentials');
$basicAuthMethod->setAccessible(true);
$this->assertSame([null, null], $basicAuthMethod->invoke($grantMock, $serverRequest));
}
public function testHttpBasicNoColon()
{
/** @var AbstractGrant $grantMock */
$grantMock = $this->getMockForAbstractClass(AbstractGrant::class);
$abstractGrantReflection = new \ReflectionClass($grantMock);
$serverRequest = new ServerRequest();
$serverRequest = $serverRequest->withHeader('Authorization', 'Basic ' . base64_encode('OpenSesame'));
$basicAuthMethod = $abstractGrantReflection->getMethod('getBasicAuthCredentials');
$basicAuthMethod->setAccessible(true);
$this->assertSame([null, null], $basicAuthMethod->invoke($grantMock, $serverRequest));
}
public function testValidateClientPublic() public function testValidateClientPublic()
{ {
$client = new ClientEntity(); $client = new ClientEntity();