jasny/http-digest

PSR-7 client and server middleware for HTTP Digest header creation and validation as described in RFC 3230

v1.2.1 2019-06-03 17:31 UTC

This package is auto-updated.

Last update: 2024-10-16 08:51:48 UTC


README

Build Status Scrutinizer Code Quality Code Coverage Packagist Stable Version Packagist License

PSR-7 client and server middleware for HTTP Digest header creation and validation as described in RFC 3230. Supports MD5, SHA, SHA-256 and SHA-512 (RFC 5843).

The Digest header contains a hash of the body.

Digest: SHA=thvDyvhfIqlvFe+A9MYgxAfm1q5=

The Want-Digest message header field indicates the sender's desire to receive an instance digest on messages associated with the Request-URI.

Want-Digest: MD5;q=0.3, SHA;q=1

Installation

composer require jasny/http-digest

Usage

Create the HttpDigest service to create and verify digests. Give the server priorities for supported algorithms. This value should be similar to those in the Want-Digest header.

use Jasny\HttpDigest\HttpDigest;

$service = new HttpDigest(["MD5;q=0.3", "SHA;q=1"]);

The priorities may also be specified as string.

$service = new HttpDigest("MD5;q=0.3, SHA;q=1");

The service for content negotiating may be created and passes in the constructor for proper DI.

use Jasny\HttpDigest\HttpDigest;

$negotiator = new DigestNegotiator();
$service = new HttpDigest(["MD5;q=0.3", "SHA;q=1"], $negotiator);

Creating a digest

You can use the service to create a digest for content.

$digest = $service->create($body);

Verifying a digest

You can use the service to verify the digest.

$service->verify($body, $digest);

If the digest doesn't match or if the algorithm is unsupported, a HttpDigestException is thrown.

Priorities and the Want-Digest header

You can change the priorities using withPriorities(). This will create a new copy of the service.

$newService = $service->withPriorities(["MD5;q=0.3", "SHA;q=0.5", "SHA-256;q=1"]);

To get the configured priorities use getPriorities(). The getWantDigest() function returns the priorities in as a string in the format expected for Wanted-Digest.

$priorities = $service->getPriorities();
$header = $service->getWantDigest();

Server middleware

Server middleware can be used to verify the digest of PSR-7 requests.

When the middleware is used, requests with a body (like POST or GET requests) must contain a Digest header. If the Digest header is missing, invalid or doesn't meet the requirements, the middleware will return a 400 Bad Request response with a With-Digest header and the handler will not be called.

Single pass middleware (PSR-15)

The middleware implements the PSR-15 MiddlewareInterface. As PSR standard many new libraries support this type of middleware, for example Zend Stratigility.

You're required to supply a PSR-17 response factory, to create a 400 Bad Request response for requests with invalid signatures.

use Jasny\HttpDigest\HttpDigest;
use Jasny\HttpDigest\ServerMiddleware;
use Zend\Stratigility\MiddlewarePipe;
use Zend\Diactoros\ResponseFactory;

$service = new HttpDigest(["MD5;q=0.3", "SHA;q=1"]);
$responseFactory = new ResponseFactory();
$middleware = new ServerMiddleware($service, $responseFactory);

$app = new MiddlewarePipe();
$app->pipe($middleware);

Double pass middleware

Many PHP libraries support double pass middleware. These are callables with the following signature;

fn(ServerRequestInterface $request, ResponseInterface $response, callable $next): ResponseInterface

To get a callback to be used by libraries as Jasny Router and Relay, use the asDoublePass() method.

use Jasny\HttpDigest\HttpDigest;
use Jasny\HttpDigest\ServerMiddleware;
use Relay\RelayBuilder;

$service = new HttpDigest(["MD5;q=0.3", "SHA;q=1"]);
$middleware = new ServerMiddleware($service);

$relayBuilder = new RelayBuilder($resolver);
$relay = $relayBuilder->newInstance([
    $middleware->asDoublePass(),
]);

$response = $relay($request, $baseResponse);

Client middleware

Client middleware can be used to sign requests send by PSR-7 compatible HTTP clients like Guzzle and HTTPlug.

use Jasny\HttpDigest\HttpDigest;
use Jasny\HttpDigest\ClientMiddleware;

$service = new HttpDigest(["MD5;q=0.3", "SHA;q=1"]);
$middleware = new ClientMiddleware($service);

Double pass middleware

The client middleware can be used by any client that does support double pass middleware. Such middleware are callables with the following signature;

fn(RequestInterface $request, ResponseInterface $response, callable $next): ResponseInterface

Most HTTP clients do not support double pass middleware, but a type of single pass instead. However more general purpose PSR-7 middleware libraries, like Relay, do support double pass.

use Relay\RelayBuilder;

$relayBuilder = new RelayBuilder($resolver);
$relay = $relayBuilder->newInstance([
    $middleware->asDoublePass(),
]);

$response = $relay($request, $baseResponse);

The client middleware does not conform to PSR-15 (single pass) as that is intended for server requests only.

Guzzle

Guzzle is the most popular HTTP Client for PHP. The middleware has a forGuzzle() method that creates a callback which can be used as Guzzle middleware.

use GuzzleHttp\HandlerStack;
use GuzzleHttp\Client;
use Jasny\HttpDigest\HttpDigest;
use Jasny\HttpDigest\ClientMiddleware;

$service = new HttpDigest(["MD5;q=0.3", "SHA;q=1"]);
$middleware = new ClientMiddleware($service);

$stack = new HandlerStack();
$stack->push($middleware->forGuzzle());

$client = new Client(['handler' => $stack]);

HTTPlug

HTTPlug is the HTTP client of PHP-HTTP. It allows you to write reusable libraries and applications that need an HTTP client without binding to a specific implementation.

The forHttplug() method for the middleware creates an object that can be used as HTTPlug plugin.

use Http\Discovery\HttpClientDiscovery;
use Http\Client\Common\PluginClient;
use Jasny\HttpDigest\HttpDigest;
use Jasny\HttpDigest\ClientMiddleware;

$service = new HttpDigest(["MD5;q=0.3", "SHA;q=1"]);
$middleware = new ClientMiddleware($service);

$pluginClient = new PluginClient(
    HttpClientDiscovery::find(),
    [
        $middleware->forHttplug(),
    ]
);