Skip to content

Commit

Permalink
V1.1.0 (#8)
Browse files Browse the repository at this point in the history
support SignatureVersion 2
  • Loading branch information
devinstewart authored Sep 29, 2022
1 parent 4010119 commit 0d8c398
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 11 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
**v1.1.0**
- upated sns-payload-validator to v1.1.0 to support SignatureVersion 2
- add SignatureVersion 2 tests
- Updated README.md

**v1.0.1**
- fix reposizitory in package.json
- better wording in README.md
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Plugin for [hapi](https://hapi.dev) to easily setup an [auth strategy](https://h
```bash
npm install --save hapi-auth-sns
```
**Please note:** While `SignatureVersion` 1 is the default, on 2022-09-19 [AWS announced](https://aws.amazon.com/blogs/security/sign-amazon-sns-messages-with-sha256-hashing-for-http-subscriptions/) the ability to set topics with `SignatureVersion` 2. Starting with version `1.1.0` of this plugin, `SignatureVersion` 1 and 2 are supported.

## Getting Started
```js
Expand Down Expand Up @@ -105,7 +106,7 @@ The `request.payload` will have the following properties:
- `Subject` - The subject of the message when the message type is `Notification`. This is not present if a Subject was not provided when the message was published.
- `Message` - The message body when the message type is `Notification`.
- `Timestamp` - The time the message was sent.
- `SignatureVersion` - The version of the signature algorithm used to sign the message. Always `'1'`.
- `SignatureVersion` - The version of the signature algorithm used to sign the message. Defaults to `1`, can also be `2`.
- `Signature` - The signature of the message used to verify the message integrity.
- `SigningCertURL` - The URL of the certificate used to sign the message.
- `SubscribeURL` - The URL used to subscribe the route when the message type is `SubscriptionConfirmation` or `UnsubscribeConfirmation`.
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "hapi-auth-sns",
"description": "AWS SNS Authentication",
"version": "1.0.1",
"version": "1.1.0",
"repository": "git://github.com/devinstewart/hapi-auth-sns",
"main": "lib/index.js",
"files": [
Expand All @@ -23,7 +23,7 @@
"@hapi/boom": "^10.0.0",
"@hapi/hoek": "^10.0.1",
"joi": "^17.6.0",
"sns-payload-validator": "^1.0.4"
"sns-payload-validator": "^1.1.0"
},
"devDependencies": {
"@hapi/code": "^9.0.1",
Expand Down
22 changes: 18 additions & 4 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ describe('Plugin', () => {

beforeEach(() => setupCertNock());

it('returns 200 on valid payload', async () => {
it('returns 200 on valid payload, SignatureVersion 1', async () => {

const server = Hapi.server();
await server.register(Sns);
Expand All @@ -52,7 +52,21 @@ describe('Plugin', () => {
server.auth.default('sns');
server.route({ path: '/', method: 'POST', handler: (request) => request.auth.credentials.sns });

const res = await server.inject({ method: 'POST', url: '/', payload: Mock.validNotification });
const res = await server.inject({ method: 'POST', url: '/', payload: Mock.validNotificationSigV1 });
expect(res.statusCode).to.equal(200);
expect(res.result).to.equal(true);
});

it('returns 200 on valid payload, SignatureVersion 2', async () => {

const server = Hapi.server();
await server.register(Sns);
server.auth.strategy('sns', 'sns', { autoSubscribe: false, autoResubscribe: false });

server.auth.default('sns');
server.route({ path: '/', method: 'POST', handler: (request) => request.auth.credentials.sns });

const res = await server.inject({ method: 'POST', url: '/', payload: Mock.validNotificationSigV2 });
expect(res.statusCode).to.equal(200);
expect(res.result).to.equal(true);
});
Expand Down Expand Up @@ -124,7 +138,7 @@ describe('Plugin', () => {
server.auth.default('sns');
server.route({ path: '/', method: 'POST', handler: successHandler, options: { auth: { scope: 'test' } } });

const res = await server.inject({ method: 'POST', url: '/', payload: Mock.validNotification });
const res = await server.inject({ method: 'POST', url: '/', payload: Mock.validNotificationSigV1 });
expect(res.statusCode).to.equal(200);
});

Expand All @@ -137,7 +151,7 @@ describe('Plugin', () => {
server.auth.default('sns');
server.route({ path: '/', method: 'POST', handler: successHandler, config: { auth: { scope: 'wrongScope' } } });

const res = await server.inject({ method: 'POST', url: '/', payload: Mock.validNotification });
const res = await server.inject({ method: 'POST', url: '/', payload: Mock.validNotificationSigV1 });
expect(res.statusCode).to.equal(403);
expect(res.result.message).to.equal('Insufficient scope');
});
Expand Down
20 changes: 16 additions & 4 deletions test/mock.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ internals.getKeys = (type) => {

};

internals.addSignature = (payload) => {
internals.addSignature = (payload, signatureVersion = '1') => {

const sign = Crypto.createSign('sha1WithRSAEncryption');
const sign = signatureVersion === '1' ? Crypto.createSign('sha1WithRSAEncryption') : Crypto.createSign('sha256WithRSAEncryption');
const keys = internals.getKeys(payload.Type);
for (const key of keys) {
if (key in payload) {
Expand All @@ -58,7 +58,7 @@ internals.SubscribePath = '/';
internals.SubscribeParams = { Action: 'ConfirmSubscription', MoreStuff: 'MoreStuff' };
internals.SubscribeURL = internals.SubscribeHost + internals.SubscribePath + '?Action' + '=' + internals.SubscribeParams.Action + '&MoreStuff' + '=' + internals.SubscribeParams.MoreStuff;

internals.validNotification = {
internals.validNotificationSigV1 = {
Type: 'Notification',
MessageId: internals.MessageId,
TopicArn: internals.TopicArn,
Expand All @@ -69,6 +69,17 @@ internals.validNotification = {
SigningCertURL: internals.SigningCertURL
};

internals.validNotificationSigV2 = {
Type: 'Notification',
MessageId: internals.MessageId,
TopicArn: internals.TopicArn,
Subject: 'Regarding SNS',
Message: 'Hello SNS!',
Timestamp: (new Date()).toISOString(),
SignatureVersion: '2',
SigningCertURL: internals.SigningCertURL
};

internals.validSubscriptionConfirmation = {
Type: 'SubscriptionConfirmation',
MessageId: internals.MessageId,
Expand Down Expand Up @@ -101,7 +112,8 @@ internals.Mock = class {
SubscribeHost = internals.SubscribeHost;
SubscribeParams = internals.SubscribeParams;
SubscribePath = internals.SubscribePath;
validNotification = internals.addSignature(internals.validNotification);
validNotificationSigV1 = internals.addSignature(internals.validNotificationSigV1);
validNotificationSigV2 = internals.addSignature(internals.validNotificationSigV2, '2');
validSubscriptionConfirmation = internals.addSignature(internals.validSubscriptionConfirmation);
validUnsubscribeConfirmation = internals.addSignature(internals.validUnsubscribeConfirmation);
};
Expand Down

0 comments on commit 0d8c398

Please sign in to comment.