activitypub-php/test/Crypto/HttpSignatureServiceTest.php

248 lines
11 KiB
PHP

<?php
namespace ActivityPub\Test\Crypto;
use ActivityPub\Crypto\HttpSignatureService;
use ActivityPub\Test\TestConfig\APTestCase;
use ActivityPub\Test\TestUtils\TestDateTimeProvider;
use DateTime;
use GuzzleHttp\Psr7\Request as PsrRequest;
use Symfony\Component\HttpFoundation\Request;
class HttpSignatureServiceTest extends APTestCase
{
const PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCFENGw33yGihy92pDjZQhl0C3
6rPJj+CvfSC8+q28hxA161QFNUd13wuCTUcq0Qd2qsBe/2hFyc2DCJJg0h1L78+6
Z4UMR7EOcpfdUE9Hf3m/hs+FUR45uBJeDK1HSFHD8bHKD6kv8FPGfJTotc+2xjJw
oYi+1hqp1fIekaxsyQIDAQAB
-----END PUBLIC KEY-----";
const PRIVATE_KEY = "-----BEGIN RSA PRIVATE KEY-----
MIICXgIBAAKBgQDCFENGw33yGihy92pDjZQhl0C36rPJj+CvfSC8+q28hxA161QF
NUd13wuCTUcq0Qd2qsBe/2hFyc2DCJJg0h1L78+6Z4UMR7EOcpfdUE9Hf3m/hs+F
UR45uBJeDK1HSFHD8bHKD6kv8FPGfJTotc+2xjJwoYi+1hqp1fIekaxsyQIDAQAB
AoGBAJR8ZkCUvx5kzv+utdl7T5MnordT1TvoXXJGXK7ZZ+UuvMNUCdN2QPc4sBiA
QWvLw1cSKt5DsKZ8UETpYPy8pPYnnDEz2dDYiaew9+xEpubyeW2oH4Zx71wqBtOK
kqwrXa/pzdpiucRRjk6vE6YY7EBBs/g7uanVpGibOVAEsqH1AkEA7DkjVH28WDUg
f1nqvfn2Kj6CT7nIcE3jGJsZZ7zlZmBmHFDONMLUrXR/Zm3pR5m0tCmBqa5RK95u
412jt1dPIwJBANJT3v8pnkth48bQo/fKel6uEYyboRtA5/uHuHkZ6FQF7OUkGogc
mSJluOdc5t6hI1VsLn0QZEjQZMEOWr+wKSMCQQCC4kXJEsHAve77oP6HtG/IiEn7
kpyUXRNvFsDE0czpJJBvL/aRFUJxuRK91jhjC68sA7NsKMGg5OXb5I5Jj36xAkEA
gIT7aFOYBFwGgQAQkWNKLvySgKbAZRTeLBacpHMuQdl1DfdntvAyqpAZ0lY0RKmW
G6aFKaqQfOXKCyWoUiVknQJAXrlgySFci/2ueKlIE1QqIiLSZ8V8OlpFLRnb1pzI
7U1yQXnTAEFYM560yJlzUpOb1V4cScGd365tiSMvxLOvTA==
-----END RSA PRIVATE KEY-----";
/**
* @var HttpSignatureService
*/
private $httpSignatureService;
public function setUp()
{
$dateTimeProvider = new TestDateTimeProvider( array(
'http-signature.verify' => DateTime::createFromFormat(
DateTime::RFC2822, 'Sun, 05 Jan 2014 21:31:40 GMT'
),
) );
$this->httpSignatureService = new HttpSignatureService( $dateTimeProvider );
}
public function provideTestItVerifies()
{
return array(
array( array(
'id' => 'defaultTest',
'headers' => array(
'Authorization' => 'Signature keyId="Test",algorithm="rsa-sha256",signature="SjWJWbWN7i0wzBvtPl8rbASWz5xQW6mcJmn+ibttBqtifLN7Sazz6m79cNfwwb8DMJ5cou1s7uEGKKCs+FLEEaDV5lp7q25WqS+lavg7T8hc0GppauB6hbgEKTwblDHYGEtbGmtdHgVCk9SuS13F0hZ8FD0k/5OxEPXe5WozsbM="',
),
'expectedResult' => true,
) ),
array( array(
'id' => 'basicTest',
'headers' => array(
'Authorization' => 'Signature keyId="Test",algorithm="rsa-sha256",headers="(request-target) host date", signature="qdx+H7PHHDZgy4y/Ahn9Tny9V3GP6YgBPyUXMmoxWtLbHpUnXS2mg2+SbrQDMCJypxBLSPQR2aAjn7ndmw2iicw3HMbe8VfEdKFYRqzic+efkb3nndiv/x1xSHDJWeSWkx3ButlYSuBskLu6kd9Fswtemr3lgdDEmn04swr2Os0="',
),
'expectedResult' => true,
) ),
array( array(
'id' => 'allHeadersTest',
'headers' => array(
'Authorization' => 'Signature keyId="Test",algorithm="rsa-sha256",headers="(request-target) host date content-type digest content-length",signature="vSdrb+dS3EceC9bcwHSo4MlyKS59iFIrhgYkz8+oVLEEzmYZZvRs8rgOp+63LEM3v+MFHB32NfpB2bEKBIvB1q52LaEUHFv120V01IL+TAD48XaERZFukWgHoBTLMhYS2Gb51gWxpeIq8knRmPnYePbF5MOkR0Zkly4zKH7s1dE="',
),
'expectedResult' => true,
) ),
array( array(
'id' => 'defaultTestSigHeader',
'headers' => array(
'Signature' => 'keyId="Test",algorithm="rsa-sha256",signature="SjWJWbWN7i0wzBvtPl8rbASWz5xQW6mcJmn+ibttBqtifLN7Sazz6m79cNfwwb8DMJ5cou1s7uEGKKCs+FLEEaDV5lp7q25WqS+lavg7T8hc0GppauB6hbgEKTwblDHYGEtbGmtdHgVCk9SuS13F0hZ8FD0k/5OxEPXe5WozsbM="',
),
'expectedResult' => true,
) ),
array( array(
'id' => 'basicTestSigHeader',
'headers' => array(
'Signature' => 'keyId="Test",algorithm="rsa-sha256",headers="(request-target) host date", signature="qdx+H7PHHDZgy4y/Ahn9Tny9V3GP6YgBPyUXMmoxWtLbHpUnXS2mg2+SbrQDMCJypxBLSPQR2aAjn7ndmw2iicw3HMbe8VfEdKFYRqzic+efkb3nndiv/x1xSHDJWeSWkx3ButlYSuBskLu6kd9Fswtemr3lgdDEmn04swr2Os0="',
),
'expectedResult' => true,
) ),
array( array(
'id' => 'allHeadersTestSigHeader',
'headers' => array(
'Signature' => 'keyId="Test",algorithm="rsa-sha256",headers="(request-target) host date content-type digest content-length",signature="vSdrb+dS3EceC9bcwHSo4MlyKS59iFIrhgYkz8+oVLEEzmYZZvRs8rgOp+63LEM3v+MFHB32NfpB2bEKBIvB1q52LaEUHFv120V01IL+TAD48XaERZFukWgHoBTLMhYS2Gb51gWxpeIq8knRmPnYePbF5MOkR0Zkly4zKH7s1dE="',
),
'expectedResult' => true,
) ),
array( array(
'id' => 'noHeaders',
'headers' => array(),
'expectedResult' => false,
) ),
array( array(
'id' => 'headerMissing',
'headers' => array(
'Authorization' => 'Signature keyId="Test",algorithm="rsa-sha256",headers="(request-target) host date content-type digest content-length x-foo-header",signature="vSdrb+dS3EceC9bcwHSo4MlyKS59iFIrhgYkz8+oVLEEzmYZZvRs8rgOp+63LEM3v+MFHB32NfpB2bEKBIvB1q52LaEUHFv120V01IL+TAD48XaERZFukWgHoBTLMhYS2Gb51gWxpeIq8knRmPnYePbF5MOkR0Zkly4zKH7s1dE="',
),
'expectedResult' => false,
) ),
array( array(
'id' => 'malformedHeader',
'headers' => array(
'Authorization' => 'not a real auth header',
),
'expectedResult' => false,
) ),
array( array(
'id' => 'partlyMalformedHeader',
'headers' => array(
'Authorization' => 'Signature keyId="Test",algorithm="rsa-sha256",headers-malformed="(request-target) host date content-type digest content-length",signature="vSdrb+dS3EceC9bcwHSo4MlyKS59iFIrhgYkz8+oVLEEzmYZZvRs8rgOp+63LEM3v+MFHB32NfpB2bEKBIvB1q52LaEUHFv120V01IL+TAD48XaERZFukWgHoBTLMhYS2Gb51gWxpeIq8knRmPnYePbF5MOkR0Zkly4zKH7s1dE="',
),
'expectedResult' => false,
) ),
array( array(
'id' => 'dateTooFarInPast',
'headers' => array(
'Authorization' => 'Signature keyId="Test",algorithm="rsa-sha256",headers="(request-target) host date", signature="qdx+H7PHHDZgy4y/Ahn9Tny9V3GP6YgBPyUXMmoxWtLbHpUnXS2mg2+SbrQDMCJypxBLSPQR2aAjn7ndmw2iicw3HMbe8VfEdKFYRqzic+efkb3nndiv/x1xSHDJWeSWkx3ButlYSuBskLu6kd9Fswtemr3lgdDEmn04swr2Os0="',
),
'expectedResult' => false,
'currentDatetime' => DateTime::createFromFormat(
DateTime::RFC2822, 'Sun, 05 Jan 2014 21:36:41 GMT'
),
) ),
array( array(
'id' => 'dateTooFarInFuture',
'headers' => array(
'Authorization' => 'Signature keyId="Test",algorithm="rsa-sha256",headers="(request-target) host date", signature="qdx+H7PHHDZgy4y/Ahn9Tny9V3GP6YgBPyUXMmoxWtLbHpUnXS2mg2+SbrQDMCJypxBLSPQR2aAjn7ndmw2iicw3HMbe8VfEdKFYRqzic+efkb3nndiv/x1xSHDJWeSWkx3ButlYSuBskLu6kd9Fswtemr3lgdDEmn04swr2Os0="',
),
'expectedResult' => false,
'currentDatetime' => DateTime::createFromFormat(
DateTime::RFC2822, 'Sun, 05 Jan 2014 21:26:39 GMT'
),
) ),
);
}
/**
* @dataProvider provideTestItVerifies
*/
public function testItVerifies( $testCase )
{
if ( array_key_exists( 'currentDatetime', $testCase ) ) {
$dateTimeProvider = new TestDateTimeProvider( array(
'http-signature.verify' => $testCase['currentDatetime'],
) );
$this->httpSignatureService = new HttpSignatureService( $dateTimeProvider );
}
$request = self::getSymfonyRequest();
foreach ( $testCase['headers'] as $header => $value ) {
$request->headers->set( $header, $value );
}
$actual = $this->httpSignatureService->verify( $request, self::PUBLIC_KEY );
$this->assertEquals(
$testCase['expectedResult'], $actual, "Error on test $testCase[id]"
);
}
private static function getSymfonyRequest()
{
$request = Request::create(
'https://example.com/foo?param=value&pet=dog',
Request::METHOD_POST,
array(),
array(),
array(),
array(),
'{"hello": "world"}'
);
$request->headers->set( 'host', 'example.com' );
$request->headers->set( 'content-type', 'application/json' );
$request->headers->set(
'digest', 'SHA-256=X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE='
);
$request->headers->set( 'content-length', 18 );
$request->headers->set( 'date', 'Sun, 05 Jan 2014 21:31:40 GMT' );
return $request;
}
public function provideTestItSigns()
{
return array(
array( array(
'id' => 'basicTest',
'keyId' => 'Test',
'expected' => 'keyId="Test",algorithm="rsa-sha256",headers="(request-target) host date",signature="qdx+H7PHHDZgy4y/Ahn9Tny9V3GP6YgBPyUXMmoxWtLbHpUnXS2mg2+SbrQDMCJypxBLSPQR2aAjn7ndmw2iicw3HMbe8VfEdKFYRqzic+efkb3nndiv/x1xSHDJWeSWkx3ButlYSuBskLu6kd9Fswtemr3lgdDEmn04swr2Os0="',
) ),
array( array(
'id' => 'allHeadersTest',
'keyId' => 'Test',
'headers' => array(
'(request-target)',
'host',
'date',
'content-type',
'digest',
'content-length',
),
'expected' => 'keyId="Test",algorithm="rsa-sha256",headers="(request-target) host date content-type digest content-length",signature="vSdrb+dS3EceC9bcwHSo4MlyKS59iFIrhgYkz8+oVLEEzmYZZvRs8rgOp+63LEM3v+MFHB32NfpB2bEKBIvB1q52LaEUHFv120V01IL+TAD48XaERZFukWgHoBTLMhYS2Gb51gWxpeIq8knRmPnYePbF5MOkR0Zkly4zKH7s1dE="',
) ),
);
}
/**
* @dataProvider provideTestItSigns
*/
public function testItSigns( $testCase )
{
$request = self::getPsrRequest();
if ( array_key_exists( 'headers', $testCase ) ) {
$actual = $this->httpSignatureService->sign(
$request, self::PRIVATE_KEY, $testCase['keyId'], $testCase['headers']
);
} else {
$actual = $this->httpSignatureService->sign(
$request, self::PRIVATE_KEY, $testCase['keyId']
);
}
$this->assertEquals(
$testCase['expected'], $actual, "Error on test $testCase[id]"
);
}
private static function getPsrRequest()
{
$headers = array(
'Host' => 'example.com',
'Content-Type' => 'application/json',
'Digest' => 'SHA-256=X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=',
'Content-Length' => 18,
'Date' => 'Sun, 05 Jan 2014 21:31:40 GMT'
);
$body = '{"hello": "world"}';
return new PsrRequest(
'POST', 'https://example.com/foo?param=value&pet=dog', $headers, $body
);
}
}