Added auth request parameter validation, tests. Started work on exchange methods
This commit is contained in:
parent
e3c3d124bb
commit
9fc7299232
@ -179,10 +179,21 @@ class Server {
|
|||||||
|
|
||||||
if (is_null($token)) {
|
if (is_null($token)) {
|
||||||
$this->logger->error('Attempting to exchange an auth code for a token resulted in null.', $bodyParams);
|
$this->logger->error('Attempting to exchange an auth code for a token resulted in null.', $bodyParams);
|
||||||
|
return new Response(400, ['content-type' => 'application/json'], json_encode([
|
||||||
|
'error' => 'invalid_grant',
|
||||||
|
'error_description' => 'The provided credentials were not valid.'
|
||||||
|
]));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify that it was issued for the same client_id and redirect_uri
|
// Verify that it was issued for the same client_id and redirect_uri
|
||||||
|
if ($token->getData()['client_id'] !== $bodyParams['client_id']
|
||||||
|
|| $token->getData()['redirect_uri'] !== $bodyParams['redirect_uri']) {
|
||||||
|
$this->logger->error("The provided client_id and/or redirect_uri did not match those stored in the token.");
|
||||||
|
return new Response(400, ['content-type' => 'application/json'], json_encode([
|
||||||
|
'error' => 'invalid_grant',
|
||||||
|
'error_description' => 'The provided credentials were not valid.'
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
// Check that the supplied code_verifier hashes to the stored code_challenge
|
// Check that the supplied code_verifier hashes to the stored code_challenge
|
||||||
|
|
||||||
@ -435,7 +446,7 @@ class Server {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Response(400, ['contet-type' => 'application/json'], json_encode([
|
return new Response(400, ['content-type' => 'application/json'], json_encode([
|
||||||
'error' => 'invalid_request',
|
'error' => 'invalid_request',
|
||||||
'error_description' => 'Request to token endpoint was not a valid code exchange request.'
|
'error_description' => 'Request to token endpoint was not a valid code exchange request.'
|
||||||
]));
|
]));
|
||||||
|
@ -56,6 +56,10 @@ class FilesystemJsonStorage implements TokenStorageInterface, LoggerAwareInterfa
|
|||||||
$authCode = generateRandomString(self::TOKEN_LENGTH);
|
$authCode = generateRandomString(self::TOKEN_LENGTH);
|
||||||
$accessToken = $this->hash($authCode);
|
$accessToken = $this->hash($authCode);
|
||||||
|
|
||||||
|
if (!array_key_exists('valid_until', $data)) {
|
||||||
|
$data['valid_until'] = time() + $this->authCodeTtl;
|
||||||
|
}
|
||||||
|
|
||||||
if (!$this->put($accessToken, $data)) {
|
if (!$this->put($accessToken, $data)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -82,7 +86,7 @@ class FilesystemJsonStorage implements TokenStorageInterface, LoggerAwareInterfa
|
|||||||
if ($data['exchanged_at'] ?? false) { return null; }
|
if ($data['exchanged_at'] ?? false) { return null; }
|
||||||
|
|
||||||
// Make sure the auth code isn’t expired.
|
// Make sure the auth code isn’t expired.
|
||||||
if ($data['valid_until'] ?? 0 < time()) { return null; }
|
if (($data['valid_until'] ?? 0) < time()) { return null; }echo 'h';
|
||||||
|
|
||||||
// If the access token is valid, mark it as redeemed and set a new expiry time.
|
// If the access token is valid, mark it as redeemed and set a new expiry time.
|
||||||
$data['exchanged_at'] = time();
|
$data['exchanged_at'] = time();
|
||||||
|
@ -8,6 +8,7 @@ use Nyholm\Psr7\Response;
|
|||||||
use Nyholm\Psr7\ServerRequest;
|
use Nyholm\Psr7\ServerRequest;
|
||||||
use Nyholm\Psr7\Request;
|
use Nyholm\Psr7\Request;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use PHPUnit\TextUI\XmlConfiguration\File;
|
||||||
use Psr\Http\Message\ServerRequestInterface;
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
use Taproot\IndieAuth\Callback\DefaultAuthorizationForm;
|
use Taproot\IndieAuth\Callback\DefaultAuthorizationForm;
|
||||||
use Taproot\IndieAuth\Callback\SingleUserPasswordAuthenticationCallback;
|
use Taproot\IndieAuth\Callback\SingleUserPasswordAuthenticationCallback;
|
||||||
@ -16,6 +17,8 @@ use Taproot\IndieAuth\Server;
|
|||||||
use Taproot\IndieAuth\Storage\FilesystemJsonStorage;
|
use Taproot\IndieAuth\Storage\FilesystemJsonStorage;
|
||||||
use Taproot\IndieAuth\Storage\TokenStorageInterface;
|
use Taproot\IndieAuth\Storage\TokenStorageInterface;
|
||||||
|
|
||||||
|
use function Taproot\IndieAuth\generatePKCECodeChallenge;
|
||||||
|
use function Taproot\IndieAuth\generateRandomString;
|
||||||
use function Taproot\IndieAuth\hashAuthorizationRequestParameters;
|
use function Taproot\IndieAuth\hashAuthorizationRequestParameters;
|
||||||
use function Taproot\IndieAuth\urlComponentsMatch;
|
use function Taproot\IndieAuth\urlComponentsMatch;
|
||||||
|
|
||||||
@ -505,7 +508,7 @@ EOT
|
|||||||
* Test Authorization Token Exchange Requests
|
* Test Authorization Token Exchange Requests
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public function testBothExchangePathsReturnErrorsIfParametersAreMissing() {
|
public function testExchangePathsReturnErrorsIfParametersAreMissing() {
|
||||||
$s = $this->getDefaultServer();
|
$s = $this->getDefaultServer();
|
||||||
|
|
||||||
$req = (new ServerRequest('POST', 'https://example.com'))->withParsedBody([
|
$req = (new ServerRequest('POST', 'https://example.com'))->withParsedBody([
|
||||||
@ -523,6 +526,47 @@ EOT
|
|||||||
$this->assertEquals('invalid_request', $tokenEndpointJson['error']);
|
$this->assertEquals('invalid_request', $tokenEndpointJson['error']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testExchangePathsReturnErrorOnInvalidParameters() {
|
||||||
|
$s = $this->getDefaultServer();
|
||||||
|
$storage = new FilesystemJsonStorage(TOKEN_STORAGE_PATH, SERVER_SECRET);
|
||||||
|
|
||||||
|
$testCases = [
|
||||||
|
'Mismatched client_id' => ['client_id' => 'https://invalid-client.example.com/'],
|
||||||
|
'Mismatched redirect_uri' => ['redirect_uri' => 'https://invalid-client.example.com/auth'],
|
||||||
|
'Invalid code_verifier' => ['code_verifier' => 'definitely_not_the_randomly_generated_string'],
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($testCases as $name => $params) {
|
||||||
|
// Create an auth code.
|
||||||
|
$codeVerifier = generateRandomString(32);
|
||||||
|
$authCode = $storage->createAuthCode([
|
||||||
|
'client_id' => 'https://client.example.com/',
|
||||||
|
'redirect_uri' => 'https://client.example.com/auth',
|
||||||
|
'code_challenge' => generatePKCECodeChallenge($codeVerifier),
|
||||||
|
'state' => '12345',
|
||||||
|
'code_challenge_method' => 'S256'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$req = (new ServerRequest('POST', 'https://example.com'))->withParsedBody(array_merge([
|
||||||
|
'grant_type' => 'authorization_code',
|
||||||
|
'code' => $authCode->getKey(),
|
||||||
|
'client_id' => $authCode->getData()['client_id'],
|
||||||
|
'redirect_uri' => $authCode->getData()['redirect_uri'],
|
||||||
|
'code_verifier' => $codeVerifier
|
||||||
|
], $params));
|
||||||
|
|
||||||
|
$authEndpointResponse = $s->handleAuthorizationEndpointRequest($req);
|
||||||
|
$this->assertEquals(400, $authEndpointResponse->getStatusCode());
|
||||||
|
$authEndpointJson = json_decode((string) $authEndpointResponse->getBody(), true);
|
||||||
|
$this->assertEquals('invalid_grant', $authEndpointJson['error']);
|
||||||
|
|
||||||
|
$tokenEndpointResponse = $s->handleAuthorizationEndpointRequest($req);
|
||||||
|
$this->assertEquals(400, $tokenEndpointResponse->getStatusCode());
|
||||||
|
$tokenEndpointJson = json_decode((string) $tokenEndpointResponse->getBody(), true);
|
||||||
|
$this->assertEquals('invalid_grant', $tokenEndpointJson['error']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test Non-Indieauth Requests.
|
* Test Non-Indieauth Requests.
|
||||||
*/
|
*/
|
||||||
|
Reference in New Issue
Block a user