Enable Discovery debug logging for production troubleshooting
- Add DISCOVERY_LOG_LEVEL=debug - Add DISCOVERY_SHOW_PROGRESS=true - Temporary changes for debugging InitializerProcessor fixes on production
This commit is contained in:
191
tests/Framework/Security/RequestSigning/RequestVerifierTest.php
Normal file
191
tests/Framework/Security/RequestSigning/RequestVerifierTest.php
Normal file
@@ -0,0 +1,191 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Framework\Security\RequestSigning;
|
||||
|
||||
use App\Framework\Http\Headers;
|
||||
use App\Framework\Http\HttpRequest;
|
||||
use App\Framework\Http\Method;
|
||||
use App\Framework\Security\RequestSigning\InMemorySigningKeyRepository;
|
||||
use App\Framework\Security\RequestSigning\RequestVerifier;
|
||||
use App\Framework\Security\RequestSigning\SigningKey;
|
||||
use PHPUnit\Framework\Attributes\Test;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class RequestVerifierTest extends TestCase
|
||||
{
|
||||
private RequestVerifier $verifier;
|
||||
|
||||
private InMemorySigningKeyRepository $keyRepository;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->keyRepository = new InMemorySigningKeyRepository();
|
||||
$this->verifier = new RequestVerifier($this->keyRepository);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function it_can_verify_valid_hmac_signature(): void
|
||||
{
|
||||
$key = SigningKey::createHmac('test-key', 'my-secret-key-that-is-long-enough-for-security');
|
||||
$this->keyRepository->store($key);
|
||||
|
||||
// Manually create a valid signature for testing
|
||||
$request = new HttpRequest(
|
||||
method: Method::GET,
|
||||
path: '/api/test',
|
||||
headers: new Headers([
|
||||
'Host' => 'example.com',
|
||||
'Date' => 'Thu, 05 Jan 2023 21:31:40 GMT',
|
||||
'Signature' => 'keyId="test-key",algorithm="hmac-sha256",headers="(request-target) host date",signature="mock-signature"',
|
||||
])
|
||||
);
|
||||
|
||||
// We need to mock the signature creation to match what would be generated
|
||||
$signingString = "(request-target): get /api/test\nhost: example.com\ndate: Thu, 05 Jan 2023 21:31:40 GMT";
|
||||
$expectedSignature = base64_encode(hash_hmac('sha256', $signingString, 'my-secret-key-that-is-long-enough-for-security', true));
|
||||
|
||||
$validRequest = new HttpRequest(
|
||||
method: Method::GET,
|
||||
path: '/api/test',
|
||||
headers: new Headers([
|
||||
'Host' => 'example.com',
|
||||
'Date' => 'Thu, 05 Jan 2023 21:31:40 GMT',
|
||||
'Signature' => "keyId=\"test-key\",algorithm=\"hmac-sha256\",headers=\"(request-target) host date\",signature=\"{$expectedSignature}\"",
|
||||
])
|
||||
);
|
||||
|
||||
$result = $this->verifier->verify($validRequest);
|
||||
|
||||
$this->assertTrue($result->isSuccess());
|
||||
$this->assertEquals('test-key', $result->signature->keyId);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function it_fails_verification_for_missing_signature(): void
|
||||
{
|
||||
$request = new HttpRequest(
|
||||
method: Method::GET,
|
||||
path: '/api/test',
|
||||
headers: new Headers(['Host' => 'example.com'])
|
||||
);
|
||||
|
||||
$result = $this->verifier->verify($request);
|
||||
|
||||
$this->assertTrue($result->isFailure());
|
||||
$this->assertEquals('Missing Signature header', $result->errorMessage);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function it_fails_verification_for_unknown_key(): void
|
||||
{
|
||||
$request = new HttpRequest(
|
||||
method: Method::GET,
|
||||
path: '/api/test',
|
||||
headers: new Headers([
|
||||
'Host' => 'example.com',
|
||||
'Date' => 'Thu, 05 Jan 2023 21:31:40 GMT',
|
||||
'Signature' => 'keyId="unknown-key",algorithm="hmac-sha256",headers="(request-target) host date",signature="test-signature"',
|
||||
])
|
||||
);
|
||||
|
||||
$result = $this->verifier->verify($request);
|
||||
|
||||
$this->assertTrue($result->isFailure());
|
||||
$this->assertEquals('Unknown key ID: unknown-key', $result->errorMessage);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function it_fails_verification_for_invalid_signature(): void
|
||||
{
|
||||
$key = SigningKey::createHmac('test-key', 'my-secret-key-that-is-long-enough-for-security');
|
||||
$this->keyRepository->store($key);
|
||||
|
||||
$request = new HttpRequest(
|
||||
method: Method::GET,
|
||||
path: '/api/test',
|
||||
headers: new Headers([
|
||||
'Host' => 'example.com',
|
||||
'Date' => 'Thu, 05 Jan 2023 21:31:40 GMT',
|
||||
'Signature' => 'keyId="test-key",algorithm="hmac-sha256",headers="(request-target) host date",signature="invalid-signature"',
|
||||
])
|
||||
);
|
||||
|
||||
$result = $this->verifier->verify($request);
|
||||
|
||||
$this->assertTrue($result->isFailure());
|
||||
$this->assertEquals('Invalid signature', $result->errorMessage);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function it_can_verify_digest_header(): void
|
||||
{
|
||||
$body = '{"test": "data"}';
|
||||
$expectedHash = base64_encode(hash('sha256', $body, true));
|
||||
|
||||
$request = new HttpRequest(
|
||||
method: Method::POST,
|
||||
path: '/api/test',
|
||||
headers: new Headers([
|
||||
'Digest' => "SHA256={$expectedHash}",
|
||||
]),
|
||||
body: $body
|
||||
);
|
||||
|
||||
$this->assertTrue($this->verifier->verifyDigest($request));
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function it_fails_digest_verification_for_wrong_hash(): void
|
||||
{
|
||||
$request = new HttpRequest(
|
||||
method: Method::POST,
|
||||
path: '/api/test',
|
||||
headers: new Headers([
|
||||
'Digest' => 'SHA256=wrong-hash',
|
||||
]),
|
||||
body: '{"test": "data"}'
|
||||
);
|
||||
|
||||
$this->assertFalse($this->verifier->verifyDigest($request));
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function it_passes_digest_verification_when_no_digest_header(): void
|
||||
{
|
||||
$request = new HttpRequest(
|
||||
method: Method::POST,
|
||||
path: '/api/test',
|
||||
body: '{"test": "data"}'
|
||||
);
|
||||
|
||||
$this->assertTrue($this->verifier->verifyDigest($request));
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function it_fails_verification_for_expired_key(): void
|
||||
{
|
||||
$expiredKey = SigningKey::createHmac(
|
||||
'expired-key',
|
||||
'secret-that-is-long-enough-for-security',
|
||||
expiresAt: new \DateTimeImmutable('2020-01-01')
|
||||
);
|
||||
$this->keyRepository->store($expiredKey);
|
||||
|
||||
$request = new HttpRequest(
|
||||
method: Method::GET,
|
||||
path: '/api/test',
|
||||
headers: new Headers([
|
||||
'Host' => 'example.com',
|
||||
'Date' => 'Thu, 05 Jan 2023 21:31:40 GMT',
|
||||
'Signature' => 'keyId="expired-key",algorithm="hmac-sha256",headers="(request-target) host date",signature="test-signature"',
|
||||
])
|
||||
);
|
||||
|
||||
$result = $this->verifier->verify($request);
|
||||
|
||||
$this->assertTrue($result->isFailure());
|
||||
$this->assertEquals('Signing key is not valid', $result->errorMessage);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user