Skip to content

Commit b5ddefd

Browse files
authored
Merge branch 'master' into bugfix/respect-tolerance-values
2 parents 1d116bb + 400e7f4 commit b5ddefd

File tree

3 files changed

+86
-8
lines changed

3 files changed

+86
-8
lines changed

readme.md

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,24 @@ php artisan vendor:publish
3333
You will need to set the following details in your environment:
3434

3535
```sh
36+
SIGNED_REQUEST_ALGORITHM=
37+
SIGNED_REQUEST_CACHE_PREFIX=
3638
SIGNED_REQUEST_SIGNATURE_HEADER=
3739
SIGNED_REQUEST_ALGORITHM_HEADER=
3840
SIGNED_REQUEST_KEY=
41+
SIGNED_REQUEST_ALLOW_REPLAYS=
42+
SIGNED_REQUEST_TOLERANCE_SECONDS=
3943
```
4044

41-
The `SIGNED_REQUEST_SIGNATURE_HEADER` should be the request header that the signature will be included on, something like `X-SIGNATURE`. Similarly the `SIGNED_REQUEST_ALGORITHM_HEADER` should be the request header that the includes the algorithm used to sign the request. Finally the `SIGNED_REQUEST_KEY` should hold the key used to verify the signed requests.
45+
Each of the settings above allows for a different level of configuration.
46+
47+
- `SIGNED_REQUEST_ALGORITHM` is the algorithm that will be used to generate / verify the signature. This is defaulted to use `sha256` feel free to change this to anything that `hash_hmac` accepts.
48+
- `SIGNED_REQUEST_CACHE_PREFIX` is the prefix to use for all the cache keys that will be generated. Here you can use the default if you're not planning on sharing a cache between multiple applications.
49+
- `SIGNED_REQUEST_SIGNATURE_HEADER` should be the request header that the signature will be included on, `X-Signature` will be used by default.
50+
- `SIGNED_REQUEST_ALGORITHM_HEADER` should be the request header that the includes the algorithm used to sign the request.
51+
- `SIGNED_REQUEST_KEY` is the shared secret key between the application generating the requests, and the application consuming them. This value should not be publically available.
52+
- `SIGNED_REQUEST_ALLOW_REPLAYS` allows you to enable or disable replay attacks. By default replays are disabled.
53+
- `SIGNED_REQUEST_TOLERANCE_SECONDS` is the number of seconds that a request will be considered for. This setting allows for some time drift between servers and is only used when replays are disabled.
4254

4355
### Setup the Middleware
4456

@@ -57,3 +69,43 @@ Route::get('/fire', function () {
5769
return "You'll only see this if the signature of the request is valid!";
5870
})->middleware('verify-signature');
5971
```
72+
73+
### Signing Postman Requests
74+
75+
If you, like us, like to use [postman](https://www.getpostman.com/) to share your api internally you can use the following pre-request script to automatically sign your postman requests:
76+
77+
```js
78+
function guid() {
79+
function s4() {
80+
return Math.floor((1 + Math.random()) * 0x10000)
81+
.toString(16)
82+
.substring(1);
83+
}
84+
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
85+
s4() + '-' + s4() + s4() + s4();
86+
}
87+
88+
postman.setEnvironmentVariable("x-signed-id", guid());
89+
postman.setEnvironmentVariable("x-signed-timestamp", (new Date()).toUTCString());
90+
postman.setEnvironmentVariable("x-algorithm", "sha256");
91+
92+
var payload = {
93+
"id": postman.getEnvironmentVariable("x-signed-id"),
94+
"method": request.method,
95+
"timestamp": postman.getEnvironmentVariable("x-signed-timestamp"),
96+
"uri": request.url.replace("{{url}}", postman.getEnvironmentVariable("url")),
97+
"content": (Object.keys(request.data).length === 0) ? "" : request.data
98+
};
99+
100+
var hash = CryptoJS.HmacSHA256(JSON.stringify(payload), postman.getEnvironmentVariable("key"));
101+
var signature = hash.toString();
102+
103+
postman.setEnvironmentVariable("x-signature", signature);
104+
```
105+
106+
Note for this to work you'll have to setup your environment to have the following variables:
107+
108+
- `{{url}}` this is the base url to the api you'll be hitting.
109+
- `{{key}}` this is the shared secret key you'll be using in your environment.
110+
111+
All other environment variables that will be needed will be automatically generated by the above script.

src/Requests/Payload.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
namespace SoapBox\SignedRequests\Requests;
44

5-
use GuzzleHttp\Psr7\Request as GuzzleRequest;
65
use Illuminate\Http\Request as IlluminateRequest;
6+
use Psr\Http\Message\RequestInterface as Psr7Request;
77

88
class Payload
99
{
@@ -31,13 +31,13 @@ public function __construct($request)
3131
/**
3232
* Returns the payload from a guzzle request.
3333
*
34-
* @param \GuzzleHttp\Psr7\Request $request
34+
* @param \Psr\Http\Message\RequestInterface $request
3535
* An instance of the guzzle request to extract a payload from.
3636
*
3737
* @return string
3838
* The payload.
3939
*/
40-
protected function generateFromGuzzleRequest(GuzzleRequest $request) : string
40+
protected function generateFromPsr7Request(Psr7Request $request) : string
4141
{
4242
$id = isset($this->request->getHeader('X-SIGNED-ID')[0]) ?
4343
$this->request->getHeader('X-SIGNED-ID')[0] : '';
@@ -49,7 +49,7 @@ protected function generateFromGuzzleRequest(GuzzleRequest $request) : string
4949
'method' => $this->request->getMethod(),
5050
'timestamp' => $timestamp,
5151
'uri' => (string) $this->request->getUri(),
52-
'content' => $this->request->getBody()
52+
'content' => $this->request->getBody()->getContents()
5353
], JSON_UNESCAPED_SLASHES);
5454
}
5555

@@ -84,8 +84,8 @@ protected function generateFromIlluminateRequest(IlluminateRequest $request) : s
8484
*/
8585
public function __toString() : string
8686
{
87-
if ($this->request instanceof GuzzleRequest) {
88-
return $this->generateFromGuzzleRequest($this->request);
87+
if ($this->request instanceof Psr7Request) {
88+
return $this->generateFromPsr7Request($this->request);
8989
}
9090

9191
if ($this->request instanceof IlluminateRequest) {

tests/Requests/PayloadTest.php

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,33 @@ public function it_translates_a_guzzle_request_to_a_json_encoded_string()
3131
'method' => $method,
3232
'timestamp' => $now,
3333
'uri' => $uri,
34-
'content' => $request->getBody()
34+
'content' => $request->getBody()->getContents()
35+
], JSON_UNESCAPED_SLASHES);
36+
37+
$this->assertEquals($expected, (string) new Payload($request));
38+
}
39+
40+
/**
41+
* @test
42+
*/
43+
public function it_translates_a_guzzle_request_with_content_to_a_json_encoded_string()
44+
{
45+
$now = (string) Carbon::now();
46+
47+
$method = 'GET';
48+
$uri = 'https://localhost';
49+
$id = Uuid::uuid4();
50+
51+
$request = (new GuzzleRequest('GET', 'https://localhost', [], 'content'))
52+
->withHeader('X-SIGNED-ID', $id)
53+
->withHeader('X-SIGNED-TIMESTAMP', $now);
54+
55+
$expected = json_encode([
56+
'id' => $id,
57+
'method' => $method,
58+
'timestamp' => $now,
59+
'uri' => $uri,
60+
'content' => 'content'
3561
], JSON_UNESCAPED_SLASHES);
3662

3763
$this->assertEquals($expected, (string) new Payload($request));

0 commit comments

Comments
 (0)