-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
0a54ed2
commit 35a8f57
Showing
10 changed files
with
491 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"type": "feature", | ||
"category": "RDS", | ||
"description": "Adds AWS.RDS.Signer class to generate auth tokens for connecting to a database." | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import {Credentials, CredentialsOptions} from '../credentials'; | ||
import {AWSError} from '../error'; | ||
export class Signer { | ||
/** | ||
* A signer object can be used to generate an auth token to a database. | ||
*/ | ||
constructor(options?:Signer.SignerOptions); | ||
/** | ||
* Generate an auth token to a database. | ||
*/ | ||
getAuthToken(options: Signer.SignerOptions, callback: (err: AWSError, token: string) => void): void; | ||
/** | ||
* Generate an auth token to a database. | ||
*/ | ||
getAuthToken(options: Signer.SignerOptions): string; | ||
} | ||
|
||
declare namespace Signer { | ||
export interface SignerOptions { | ||
credentials?: Credentials | CredentialsOptions; | ||
region?: string; | ||
hostname?: string; | ||
port?: number; | ||
username?: string; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,214 @@ | ||
var AWS = require('../core'); | ||
|
||
/** | ||
* @api private | ||
*/ | ||
var service = null; | ||
|
||
/** | ||
* @api private | ||
*/ | ||
var api = { | ||
signatureVersion: 'v4', | ||
signingName: 'rds-db' | ||
}; | ||
|
||
/** | ||
* @api private | ||
*/ | ||
var requiredAuthTokenOptions = { | ||
region: 'string', | ||
hostname: 'string', | ||
port: 'number', | ||
username: 'string' | ||
}; | ||
|
||
/** | ||
* A signer object can be used to generate an auth token to a database. | ||
*/ | ||
AWS.RDS.Signer = AWS.util.inherit({ | ||
/** | ||
* Creates a signer object can be used to generate an auth token. | ||
* | ||
* @option options credentials [AWS.Credentials] the AWS credentials | ||
* to sign requests with. Uses the default credential provider chain | ||
* if not specified. | ||
* @option options hostname [String] the hostname of the database to connect to. | ||
* @option options port [Number] the port number the database is listening on. | ||
* @option options region [String] the region the database is located in. | ||
* @option options username [String] the username to login as. | ||
* @example Passing in options to constructor | ||
* var signer = new AWS.RDS.Signer({ | ||
* credentials: new AWS.SharedIniFileCredentials({profile: 'default'}), | ||
* region: 'us-east-1', | ||
* hostname: 'db.us-east-1.rds.amazonaws.com', | ||
* port: 8000, | ||
* username: 'name' | ||
* }); | ||
*/ | ||
constructor: function Signer(options) { | ||
this.options = options || {}; | ||
}, | ||
|
||
/** | ||
* @api private | ||
* Strips the protocol from a url. | ||
*/ | ||
convertUrlToAuthToken: function convertUrlToAuthToken(url) { | ||
// we are always using https as the protocol | ||
var protocol = 'https://'; | ||
if (url.indexOf(protocol) === 0) { | ||
return url.substring(protocol.length); | ||
} | ||
}, | ||
|
||
/** | ||
* @overload getAuthToken(options = {}, [callback]) | ||
* Generate an auth token to a database. | ||
* @note You must ensure that you have static or previously resolved | ||
* credentials if you call this method synchronously (with no callback), | ||
* otherwise it may not properly sign the request. If you cannot guarantee | ||
* this (you are using an asynchronous credential provider, i.e., EC2 | ||
* IAM roles), you should always call this method with an asynchronous | ||
* callback. | ||
* | ||
* @param options [map] The fields to use when generating an auth token. | ||
* Any options specified here will be merged on top of any options passed | ||
* to AWS.RDS.Signer: | ||
* | ||
* * **credentials** (AWS.Credentials) — the AWS credentials | ||
* to sign requests with. Uses the default credential provider chain | ||
* if not specified. | ||
* * **hostname** (String) — the hostname of the database to connect to. | ||
* * **port** (Number) — the port number the database is listening on. | ||
* * **region** (String) — the region the database is located in. | ||
* * **username** (String) — the username to login as. | ||
* @return [String] if called synchronously (with no callback), returns the | ||
* auth token. | ||
* @return [null] nothing is returned if a callback is provided. | ||
* @callback callback function (err, token) | ||
* If a callback is supplied, it is called when an auth token has been generated. | ||
* @param err [Error] the error object returned from the signer. | ||
* @param token [String] the auth token. | ||
* | ||
* @example Generating an auth token synchronously | ||
* var signer = new AWS.RDS.Signer({ | ||
* // configure options | ||
* region: 'us-east-1', | ||
* username: 'default', | ||
* hostname: 'db.us-east-1.amazonaws.com', | ||
* port: 8000 | ||
* }); | ||
* var token = signer.getAuthToken({ | ||
* // these options are merged with those defined when creating the signer, overriding in the case of a duplicate option | ||
* // credentials are not specified here or when creating the signer, so default credential provider will be used | ||
* username: 'test' // overriding username | ||
* }); | ||
* @example Generating an auth token asynchronously | ||
* var signer = new AWS.RDS.Signer({ | ||
* // configure options | ||
* region: 'us-east-1', | ||
* username: 'default', | ||
* hostname: 'db.us-east-1.amazonaws.com', | ||
* port: 8000 | ||
* }); | ||
* signer.getAuthToken({ | ||
* // these options are merged with those defined when creating the signer, overriding in the case of a duplicate option | ||
* // credentials are not specified here or when creating the signer, so default credential provider will be used | ||
* username: 'test' // overriding username | ||
* }, function(err, token) { | ||
* if (err) { | ||
* // handle error | ||
* } else { | ||
* // use token | ||
* } | ||
* }); | ||
* | ||
*/ | ||
getAuthToken: function getAuthToken(options, callback) { | ||
if (typeof options === 'function' && callback === undefined) { | ||
callback = options; | ||
options = {}; | ||
} | ||
var self = this; | ||
var hasCallback = typeof callback === 'function'; | ||
// merge options with existing options | ||
options = AWS.util.merge(this.options, options); | ||
// validate options | ||
var optionsValidation = this.validateAuthTokenOptions(options); | ||
if (optionsValidation !== true) { | ||
if (hasCallback) { | ||
return callback(optionsValidation, null); | ||
} | ||
throw optionsValidation; | ||
} | ||
|
||
// 15 minutes | ||
var expires = 900; | ||
// create service to generate a request from | ||
service = new AWS.Service({ | ||
region: options.region, | ||
credentials: options.credentials, | ||
endpoint: new AWS.Endpoint(options.hostname + ':' + options.port), | ||
paramValidation: false, | ||
signatureVersion: 'v4' | ||
}); | ||
// ensure the SDK is using sigv4 signing (config is not enough) | ||
service.api = api; | ||
|
||
var request = service.makeRequest(); | ||
// add listeners to request to properly build auth token | ||
this.modifyRequestForAuthToken(request, options); | ||
|
||
if (hasCallback) { | ||
request.presign(expires, function(err, url) { | ||
if (url) { | ||
url = self.convertUrlToAuthToken(url); | ||
} | ||
callback(err, url); | ||
}); | ||
} else { | ||
var url = request.presign(expires); | ||
return this.convertUrlToAuthToken(url); | ||
} | ||
}, | ||
|
||
/** | ||
* @api private | ||
* Modifies a request to allow the presigner to generate an auth token. | ||
*/ | ||
modifyRequestForAuthToken: function modifyRequestForAuthToken(request, options) { | ||
request.on('build', request.buildAsGet); | ||
var httpRequest = request.httpRequest; | ||
httpRequest.body = AWS.util.queryParamsToString({ | ||
Action: 'connect', | ||
DBUser: options.username | ||
}); | ||
}, | ||
|
||
/** | ||
* @api private | ||
* Validates that the options passed in contain all the keys with values of the correct type that | ||
* are needed to generate an auth token. | ||
*/ | ||
validateAuthTokenOptions: function validateAuthTokenOptions(options) { | ||
// iterate over all keys in options | ||
var message = ''; | ||
options = options || {}; | ||
for (var key in requiredAuthTokenOptions) { | ||
if (!Object.prototype.hasOwnProperty.call(requiredAuthTokenOptions, key)) { | ||
continue; | ||
} | ||
if (typeof options[key] !== requiredAuthTokenOptions[key]) { | ||
message += 'option \'' + key + '\' should have been type \'' + requiredAuthTokenOptions[key] + '\', was \'' + typeof options[key] + '\'.\n'; | ||
} | ||
} | ||
if (message.length) { | ||
return AWS.util.error(new Error(), { | ||
code: 'InvalidParameter', | ||
message: message | ||
}); | ||
} | ||
return true; | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
var AWS = require('../core'); | ||
|
||
require('../rds/signer'); | ||
/** | ||
* @api private | ||
*/ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.