Skip to content
Merged
63 changes: 59 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ $options = [
],
];

// A key consists of your UUID and a MIME base64 encoded shared secret.
// A key consists of your UUID and a Base64-encoded shared secret.
// Note: the API provider may have already encoded the secret. In this case, it should not be re-encoded.
$key = new Key('e7fe97fa-a0c8-4a42-ab8e-2c26d52df059', base64_encode('secret'));

// Provide your key, realm and optional signed headers.
Expand Down Expand Up @@ -130,7 +131,7 @@ In order to use the provided Symfony integration, you will need to include the f
}
```

Sammple implementation:
Sample implementation:

```yaml
# app/config/parameters.yml
Expand All @@ -149,7 +150,12 @@ services:
arguments:
- '@hmac.keyloader'
public: false


hmac.response.signer:
class: Acquia\Hmac\Symfony\HmacResponseListener
tags:
- { name: kernel.event_listener, event: kernel.response, method: onKernelResponse }

hmac.entry-point:
class: Acquia\Hmac\Symfony\HmacAuthenticationEntryPoint

Expand All @@ -172,7 +178,7 @@ security:
hmac_auth:
pattern: ^/api/
stateless: true
wsse: true
hmac_auth: true
```

```php
Expand All @@ -194,6 +200,55 @@ class AppBundle extends Bundle
}
```

PHPUnit testing a controller using HMAC HTTP authentication in Symfony:

1. Add the service declaration:

```yaml
# app/config/parameters_test.yml

services:
test.client.hmac:
class: Acquia\Hmac\Test\Mocks\Symfony\HmacClientlient
arguments: ['@kernel', '%test.client.parameters%', '@test.client.history', '@test.client.cookiejar']

```

```php
// src/AppBundle/Tests/HmacTestCase.php

namespace MyApp\Bundle\AppBundle\Tests;

use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Bundle\FrameworkBundle\Client;
use Acquia\Hmac\Key;

class HmacTestCase extends WebTestCase
{
/**
* @var Client
*/
private $client;

protected static function createClient(array $options = array(), array $server = array())
{
$kernel = static::bootKernel($options);

$client = $kernel->getContainer()->get('test.client.hmac');
$client->setServerParameters($server);

return $client;
}

protected function setUp()
{
$this->client = static::createClient();

$this->client->setKey(new Key('my-key', 'my-not-really-secret'));
}
```

## Contributing and Development

Submit changes using GitHub's standard [pull request](https://help.github.com/articles/using-pull-requests) workflow.
Expand Down
74 changes: 74 additions & 0 deletions test/Mocks/Symfony/HmacClient.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<?php

namespace Acquia\Hmac\Test\Mocks\Symfony;

use Acquia\Hmac\KeyInterface;
use Acquia\Hmac\RequestSigner;
use Acquia\Hmac\ResponseAuthenticator;
use Symfony\Bundle\FrameworkBundle\Client;
use Symfony\Bridge\PsrHttpMessage\Factory\DiactorosFactory;
use Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory;
use Symfony\Component\HttpFoundation\Response;

/**
* A mock Symfony client for testing HTTP HMAC request signing and response authentication.
*/
class HmacClient extends Client
{
/**
* @var \Acquia\Hmac\KeyInterface $key
* The key to sign requests with.
*/
protected $key;

/**
* Set the private key for HTTP HMAC authentication.
*
* @param \Acquia\Hmac\KeyInterface $key
* The key to sign requests with.
*
* @return static
*/
public function setKey(KeyInterface $key)
{
$this->key = $key;

return $this;
}

/**
* Sign the request with HTTP HMAC and authenticate the response signature.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* The Symfony request.
*
* @return \Symfony\Component\HttpFoundation\Response
* An Symfony response indicating the result of making the signed request.
*/
protected function doRequest($request)
{
if (!$this->key instanceof Key) {
return new Response('The HTTP HMAC key has not been provided.', 400);
}

$psr7Factory = new DiactorosFactory();
$httpFoundationFactory = new HttpFoundationFactory();

$psrRequest = $psr7Factory->createRequest($request);

$hmacSigner = new RequestSigner($this->key);
$signedRequest = $hmacSigner->signRequest($psrRequest);
$symfonyRequest = $httpFoundationFactory->createRequest($signedRequest);

$response = parent::doRequest($symfonyRequest);
$psrResponse = $psr7Factory->createResponse($response);

$authenticator = new ResponseAuthenticator($signedRequest, $this->key);

if (!$authenticator->isAuthentic($psrResponse)) {
return new Response('The response cannot be authenticated.', 400);
}

return $response;
}
}