Fix http signatures signing of psr7 requests
This commit is contained in:
parent
634db57684
commit
4c5b667175
@ -28,7 +28,8 @@
|
||||
"phpseclib/phpseclib": "^2.0",
|
||||
"psr/http-message": "^1.0",
|
||||
"symfony/http-kernel": "^4.2",
|
||||
"symfony/psr-http-message-bridge": "^1.1"
|
||||
"symfony/psr-http-message-bridge": "^1.1",
|
||||
"zendframework/zend-diactoros": "^1.8"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/dbunit": "^4.0",
|
||||
|
118
composer.lock
generated
118
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "fa1affc2b91bce0c5e025b09069a9fc6",
|
||||
"content-hash": "4fdd0e94241c59ddd2c9763881167989",
|
||||
"packages": [
|
||||
{
|
||||
"name": "doctrine/annotations",
|
||||
@ -1900,6 +1900,70 @@
|
||||
"psr-7"
|
||||
],
|
||||
"time": "2018-08-30T16:28:28+00:00"
|
||||
},
|
||||
{
|
||||
"name": "zendframework/zend-diactoros",
|
||||
"version": "1.8.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/zendframework/zend-diactoros.git",
|
||||
"reference": "20da13beba0dde8fb648be3cc19765732790f46e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/zendframework/zend-diactoros/zipball/20da13beba0dde8fb648be3cc19765732790f46e",
|
||||
"reference": "20da13beba0dde8fb648be3cc19765732790f46e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^5.6 || ^7.0",
|
||||
"psr/http-message": "^1.0"
|
||||
},
|
||||
"provide": {
|
||||
"psr/http-message-implementation": "1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-dom": "*",
|
||||
"ext-libxml": "*",
|
||||
"php-http/psr7-integration-tests": "dev-master",
|
||||
"phpunit/phpunit": "^5.7.16 || ^6.0.8 || ^7.2.7",
|
||||
"zendframework/zend-coding-standard": "~1.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.8.x-dev",
|
||||
"dev-develop": "1.9.x-dev",
|
||||
"dev-release-2.0": "2.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/functions/create_uploaded_file.php",
|
||||
"src/functions/marshal_headers_from_sapi.php",
|
||||
"src/functions/marshal_method_from_sapi.php",
|
||||
"src/functions/marshal_protocol_version_from_sapi.php",
|
||||
"src/functions/marshal_uri_from_sapi.php",
|
||||
"src/functions/normalize_server.php",
|
||||
"src/functions/normalize_uploaded_files.php",
|
||||
"src/functions/parse_cookie_header.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Zend\\Diactoros\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-2-Clause"
|
||||
],
|
||||
"description": "PSR HTTP Message implementations",
|
||||
"homepage": "https://github.com/zendframework/zend-diactoros",
|
||||
"keywords": [
|
||||
"http",
|
||||
"psr",
|
||||
"psr-7"
|
||||
],
|
||||
"time": "2018-09-05T19:29:37+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
@ -2657,6 +2721,58 @@
|
||||
],
|
||||
"time": "2018-12-12T07:20:32+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/http-factory",
|
||||
"version": "1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/http-factory.git",
|
||||
"reference": "378bfe27931ecc54ff824a20d6f6bfc303bbd04c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/http-factory/zipball/378bfe27931ecc54ff824a20d6f6bfc303bbd04c",
|
||||
"reference": "378bfe27931ecc54ff824a20d6f6bfc303bbd04c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.0.0",
|
||||
"psr/http-message": "^1.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Psr\\Http\\Message\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "PHP-FIG",
|
||||
"homepage": "http://www.php-fig.org/"
|
||||
}
|
||||
],
|
||||
"description": "Common interfaces for PSR-7 HTTP message factories",
|
||||
"keywords": [
|
||||
"factory",
|
||||
"http",
|
||||
"message",
|
||||
"psr",
|
||||
"psr-17",
|
||||
"psr-7",
|
||||
"request",
|
||||
"response"
|
||||
],
|
||||
"time": "2018-07-30T21:54:04+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/code-unit-reverse-lookup",
|
||||
"version": "1.0.1",
|
||||
|
@ -5,7 +5,7 @@ use DateTime;
|
||||
use ActivityPub\Utils\DateTimeProvider;
|
||||
use ActivityPub\Utils\SimpleDateTimeProvider;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory;
|
||||
use Symfony\Bridge\PsrHttpMessage\Factory\DiactorosFactory;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\HeaderUtils;
|
||||
|
||||
@ -29,9 +29,9 @@ class HttpSignatureService
|
||||
private $dateTimeProvider;
|
||||
|
||||
/**
|
||||
* @var HttpFoundationFactory
|
||||
* @var DiactorosFactory
|
||||
*/
|
||||
private $httpFoundationFactory;
|
||||
private $psr7Factory;
|
||||
|
||||
/**
|
||||
* Constructs a new HttpSignatureService
|
||||
@ -45,7 +45,7 @@ class HttpSignatureService
|
||||
$dateTimeProvider = new SimpleDateTimeProvider();
|
||||
}
|
||||
$this->dateTimeProvider = $dateTimeProvider;
|
||||
$this->httpFoundationFactory = new HttpFoundationFactory();
|
||||
$this->psr7Factory = new DiactorosFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -58,10 +58,9 @@ class HttpSignatureService
|
||||
* (default ['(request-target)', 'host', 'date'])
|
||||
* @return string The Signature header value
|
||||
*/
|
||||
public function sign( RequestInterface $psrRequest, string $privateKey,
|
||||
public function sign( RequestInterface $request, string $privateKey,
|
||||
string $keyId, $headers = self::DEFAULT_HEADERS )
|
||||
{
|
||||
$request = $this->httpFoundationFactory->createRequest( $psrRequest );
|
||||
$headers = array_map( 'strtolower', $headers );
|
||||
$signingString = $this->getSigningString( $request, $headers );
|
||||
$keypair = RsaKeypair::fromPrivateKey( $privateKey );
|
||||
@ -111,7 +110,8 @@ class HttpSignatureService
|
||||
$targetHeaders = $params['headers'];
|
||||
}
|
||||
|
||||
$signingString = $this->getSigningString( $request, $targetHeaders );
|
||||
$psrRequest = $this->psr7Factory->createRequest( $request );
|
||||
$signingString = $this->getSigningString( $psrRequest, $targetHeaders );
|
||||
$signature = base64_decode( $params['signature'] );
|
||||
// TODO handle different algorithms here, checking the 'algorithm' param and the key headers
|
||||
$keypair = RsaKeypair::fromPublicKey( $publicKey );
|
||||
@ -125,18 +125,22 @@ class HttpSignatureService
|
||||
* @param array $headers The headers to use to generate the signing string
|
||||
* @return string The signing string
|
||||
*/
|
||||
private function getSigningString( Request $request, $headers )
|
||||
private function getSigningString( RequestInterface $request, $headers )
|
||||
{
|
||||
$signingComponents = array();
|
||||
foreach ( $headers as $header ) {
|
||||
$component = "${header}: ";
|
||||
if ( $header == '(request-target)' ) {
|
||||
$method = strtolower( $request->getMethod());
|
||||
$path = $request->getRequestUri();
|
||||
$path = $request->getUri()->getPath();
|
||||
$query = $request->getUri()->getQuery();
|
||||
if ( ! empty( $query ) ) {
|
||||
$path = "$path?$query";
|
||||
}
|
||||
$component = $component . $method . ' ' . $path;
|
||||
} else {
|
||||
// TODO handle 'digest' specially here too
|
||||
$values = $request->headers->get( $header, null, false );
|
||||
$values = $request->getHeader( $header );
|
||||
$component = $component . implode( ', ', $values );
|
||||
}
|
||||
$signingComponents[] = $component;
|
||||
|
@ -4,6 +4,7 @@ namespace ActivityPub\Test\Crypto;
|
||||
use DateTime;
|
||||
use ActivityPub\Crypto\HttpSignatureService;
|
||||
use ActivityPub\Test\TestUtils\TestDateTimeProvider;
|
||||
use GuzzleHttp\Psr7\Request as PsrRequest;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
@ -44,7 +45,7 @@ G6aFKaqQfOXKCyWoUiVknQJAXrlgySFci/2ueKlIE1QqIiLSZ8V8OlpFLRnb1pzI
|
||||
$this->httpSignatureService = new HttpSignatureService( $dateTimeProvider );
|
||||
}
|
||||
|
||||
private static function getRequest()
|
||||
private static function getSymfonyRequest()
|
||||
{
|
||||
$request = Request::create(
|
||||
'https://example.com/foo?param=value&pet=dog',
|
||||
@ -65,6 +66,21 @@ G6aFKaqQfOXKCyWoUiVknQJAXrlgySFci/2ueKlIE1QqIiLSZ8V8OlpFLRnb1pzI
|
||||
return $request;
|
||||
}
|
||||
|
||||
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
|
||||
);
|
||||
}
|
||||
|
||||
public function testItVerifies()
|
||||
{
|
||||
$testCases = array(
|
||||
@ -164,7 +180,7 @@ G6aFKaqQfOXKCyWoUiVknQJAXrlgySFci/2ueKlIE1QqIiLSZ8V8OlpFLRnb1pzI
|
||||
) );
|
||||
$this->httpSignatureService = new HttpSignatureService( $dateTimeProvider );
|
||||
}
|
||||
$request = self::getRequest();
|
||||
$request = self::getSymfonyRequest();
|
||||
foreach ( $testCase['headers'] as $header => $value ) {
|
||||
$request->headers->set( $header, $value );
|
||||
}
|
||||
@ -198,7 +214,7 @@ G6aFKaqQfOXKCyWoUiVknQJAXrlgySFci/2ueKlIE1QqIiLSZ8V8OlpFLRnb1pzI
|
||||
),
|
||||
);
|
||||
foreach ( $testCases as $testCase ) {
|
||||
$request = self::getRequest();
|
||||
$request = self::getPsrRequest();
|
||||
if ( array_key_exists( 'headers', $testCase ) ) {
|
||||
$actual = $this->httpSignatureService->sign(
|
||||
$request, self::PRIVATE_KEY, $testCase['keyId'], $testCase['headers']
|
||||
|
Loading…
Reference in New Issue
Block a user