Skip to content

Commit

Permalink
Allow authorization using queryString when using wss-custom-auth. (#383)
Browse files Browse the repository at this point in the history
Co-authored-by: Stijn De Pestel <stijn.depestel@gmail.com>
  • Loading branch information
bretambrose and stijndepestel authored Jul 9, 2021
1 parent fda92f8 commit 1eaeb85
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 6 deletions.
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,7 @@ follows:
* `customAuthHeaders`: used to specify your custom authorization headers when `protocol` is set to 'wss-custom-auth'. The fields 'X-Amz-CustomAuthorizer-Name', 'X-Amz-CustomAuthorizer-Signature', and the field for your token name are required.
* `servername`: used for SNI. If undefined, a value is derived from `host`.
* `port`: used to specify which port to connect to. If undefined, 443 or 8883 will be chosen depending on `protocol`.
* `customAuthQueryString`: used to specify the token credentials in a query string for custom authorization when `protocol` is set to `wss-custom-auth`. More info can be found [here](https://docs.aws.amazon.com/iot/latest/developerguide/custom-auth.html#custom-auth-websockets).
* `keepalive`: used to specify the time interval for each ping request. Default is set to 300 seconds to connect to AWS IoT.
* `enableMetrics`: used to report SDK version usage metrics. It is set to true by default. To disable metrics collection, set value to false.
* `debug`: set to 'true' for verbose logging (default 'false').
Expand Down Expand Up @@ -746,8 +747,8 @@ set the `protocol` option to `wss-custom-auth`.
### Custom Authorization Configuration

To use custom authorization, you must first set up an authorizer function in Lambda and register it
with IoT. Once you do, you will be able to authenticate using this function. To use custom auth,
set the `customAuthHeaders` option to your headers object when instantiating the [awsIotDevice()](#device)
with IoT. Once you do, you will be able to authenticate using this function. There are two ways to use custom auth:
* set the `customAuthHeaders` option to your headers object when instantiating the [awsIotDevice()](#device)
or [awsIot.thingShadow()](#thingShadow) classes. The headers object is an object containing the header name
and values as key-value pairs:

Expand All @@ -758,6 +759,11 @@ and values as key-value pairs:
'TestAuthorizerToken': 'token'
}
```
* set the `customAuthQueryString` option to your headers object when instantiating the [awsIotDevice()](#device) class. The query string is a string containing the values as key-value pairs:

```js
'?X-Amz-CustomAuthorizer-Name=TestAuthorizer&X-Amz-CustomAuthorizer-Signature=signature&TestAuthorizerToken=token'
```


<a name="programs"></a>
Expand Down
6 changes: 3 additions & 3 deletions device/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ function prepareWebSocketCustomAuthUrl(options) {
hostName = options.host + ':' + options.port;
}

return 'wss://' + hostName + path;
return 'wss://' + hostName + path + (options.customAuthQueryString || '');
}

function arrayEach(array, iterFunction) {
Expand Down Expand Up @@ -505,8 +505,8 @@ function DeviceClient(options) {
throw new Error(exceptions.INVALID_CONNECT_OPTIONS);
}
} else {
if (isUndefined(options.customAuthHeaders)) {
console.log('To authenticate with a custom authorizer, you must provide the required HTTP headers; see README.md');
if (isUndefined(options.customAuthHeaders) && isUndefined(options.customAuthQueryString)) {
console.log('To authenticate with a custom authorizer, you must provide the required HTTP headers or queryString; see README.md');
throw new Error(exceptions.INVALID_CONNECT_OPTIONS);
}
}
Expand Down
35 changes: 34 additions & 1 deletion test/device-unit-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,7 @@ describe( "device class unit tests", function() {
);
});
});
describe("device throws exception if using CustomAuth over websocket without headers", function () {
describe("device throws exception if using CustomAuth over websocket without headers or querystring", function () {
it("throws exception", function () {
assert.throws(function (err) {
var device = deviceModule({
Expand All @@ -557,6 +557,30 @@ describe( "device class unit tests", function() {
);
});
});
describe("device does not throw exception if using CustomAuth over websocket with headers", function () {
it("does not throw an exception", function () {
assert.doesNotThrow(function (err) {
var device = deviceModule({
host: 'XXXX.iot.us-east-1.amazonaws.com',
protocol: 'wss-custom-auth',
customAuthHeaders: {}
});
}, function (err) { console.log('\t[' + err + ']'); return true; }
);
});
});
describe("device does not throw exception if using CustomAuth over websocket with querystring", function () {
it("does not throw an exception", function () {
assert.doesNotThrow(function (err) {
var device = deviceModule({
host: 'XXXX.iot.us-east-1.amazonaws.com',
protocol: 'wss-custom-auth',
customAuthQueryString: ''
});
}, function (err) { console.log('\t[' + err + ']'); return true; }
);
});
});
describe("device does not throw exception if using CustomAuth over websocket with non-standard headers", function () {
it("does not throw an exception", function () {
assert.doesNotThrow(function (err) {
Expand Down Expand Up @@ -1888,6 +1912,15 @@ describe( "device class unit tests", function() {
assert.equal( url, expectedUrl );
});
});
describe("websocket http querystring is correctly set when CustomAuth querystring is specified", function() {
it("generates the correct url", function() {
const queryString = '?X-Amz-CustomAuthorizer-Name=AuthorizerFunctionName&X-Amz-CustomAuthorizer-Signature=Signature&NPAuthorizerToken=Token';
const expectedUrl = 'wss://not-a-real-host.com/mqtt' + queryString;
const url = deviceModule.prepareWebSocketCustomAuthUrl( { host:'not-a-real-host.com', customAuthQueryString: queryString } );
assert.equal( url, expectedUrl );
});

});
describe("websocket headers are correctly set when CustomAuth headers are specified", function() {
it("sets the websocket headers correctly", function() {
var headers = {
Expand Down

2 comments on commit 1eaeb85

@GentileFulvio
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is anyone working to fix the typescript types as well ?

@GentileFulvio
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also noticed the the browserized version does not yet support the wss-custom-auth

Please sign in to comment.