247 lines
9.6 KiB
JavaScript
247 lines
9.6 KiB
JavaScript
|
var AWS = require('./core');
|
||
|
|
||
|
/**
|
||
|
* Represents your AWS security credentials, specifically the
|
||
|
* {accessKeyId}, {secretAccessKey}, and optional {sessionToken}.
|
||
|
* Creating a `Credentials` object allows you to pass around your
|
||
|
* security information to configuration and service objects.
|
||
|
*
|
||
|
* Note that this class typically does not need to be constructed manually,
|
||
|
* as the {AWS.Config} and {AWS.Service} classes both accept simple
|
||
|
* options hashes with the three keys. These structures will be converted
|
||
|
* into Credentials objects automatically.
|
||
|
*
|
||
|
* ## Expiring and Refreshing Credentials
|
||
|
*
|
||
|
* Occasionally credentials can expire in the middle of a long-running
|
||
|
* application. In this case, the SDK will automatically attempt to
|
||
|
* refresh the credentials from the storage location if the Credentials
|
||
|
* class implements the {refresh} method.
|
||
|
*
|
||
|
* If you are implementing a credential storage location, you
|
||
|
* will want to create a subclass of the `Credentials` class and
|
||
|
* override the {refresh} method. This method allows credentials to be
|
||
|
* retrieved from the backing store, be it a file system, database, or
|
||
|
* some network storage. The method should reset the credential attributes
|
||
|
* on the object.
|
||
|
*
|
||
|
* @!attribute expired
|
||
|
* @return [Boolean] whether the credentials have been expired and
|
||
|
* require a refresh. Used in conjunction with {expireTime}.
|
||
|
* @!attribute expireTime
|
||
|
* @return [Date] a time when credentials should be considered expired. Used
|
||
|
* in conjunction with {expired}.
|
||
|
* @!attribute accessKeyId
|
||
|
* @return [String] the AWS access key ID
|
||
|
* @!attribute secretAccessKey
|
||
|
* @return [String] the AWS secret access key
|
||
|
* @!attribute sessionToken
|
||
|
* @return [String] an optional AWS session token
|
||
|
*/
|
||
|
AWS.Credentials = AWS.util.inherit({
|
||
|
/**
|
||
|
* A credentials object can be created using positional arguments or an options
|
||
|
* hash.
|
||
|
*
|
||
|
* @overload AWS.Credentials(accessKeyId, secretAccessKey, sessionToken=null)
|
||
|
* Creates a Credentials object with a given set of credential information
|
||
|
* as positional arguments.
|
||
|
* @param accessKeyId [String] the AWS access key ID
|
||
|
* @param secretAccessKey [String] the AWS secret access key
|
||
|
* @param sessionToken [String] the optional AWS session token
|
||
|
* @example Create a credentials object with AWS credentials
|
||
|
* var creds = new AWS.Credentials('akid', 'secret', 'session');
|
||
|
* @overload AWS.Credentials(options)
|
||
|
* Creates a Credentials object with a given set of credential information
|
||
|
* as an options hash.
|
||
|
* @option options accessKeyId [String] the AWS access key ID
|
||
|
* @option options secretAccessKey [String] the AWS secret access key
|
||
|
* @option options sessionToken [String] the optional AWS session token
|
||
|
* @example Create a credentials object with AWS credentials
|
||
|
* var creds = new AWS.Credentials({
|
||
|
* accessKeyId: 'akid', secretAccessKey: 'secret', sessionToken: 'session'
|
||
|
* });
|
||
|
*/
|
||
|
constructor: function Credentials() {
|
||
|
// hide secretAccessKey from being displayed with util.inspect
|
||
|
AWS.util.hideProperties(this, ['secretAccessKey']);
|
||
|
|
||
|
this.expired = false;
|
||
|
this.expireTime = null;
|
||
|
this.refreshCallbacks = [];
|
||
|
if (arguments.length === 1 && typeof arguments[0] === 'object') {
|
||
|
var creds = arguments[0].credentials || arguments[0];
|
||
|
this.accessKeyId = creds.accessKeyId;
|
||
|
this.secretAccessKey = creds.secretAccessKey;
|
||
|
this.sessionToken = creds.sessionToken;
|
||
|
} else {
|
||
|
this.accessKeyId = arguments[0];
|
||
|
this.secretAccessKey = arguments[1];
|
||
|
this.sessionToken = arguments[2];
|
||
|
}
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* @return [Integer] the number of seconds before {expireTime} during which
|
||
|
* the credentials will be considered expired.
|
||
|
*/
|
||
|
expiryWindow: 15,
|
||
|
|
||
|
/**
|
||
|
* @return [Boolean] whether the credentials object should call {refresh}
|
||
|
* @note Subclasses should override this method to provide custom refresh
|
||
|
* logic.
|
||
|
*/
|
||
|
needsRefresh: function needsRefresh() {
|
||
|
var currentTime = AWS.util.date.getDate().getTime();
|
||
|
var adjustedTime = new Date(currentTime + this.expiryWindow * 1000);
|
||
|
|
||
|
if (this.expireTime && adjustedTime > this.expireTime) {
|
||
|
return true;
|
||
|
} else {
|
||
|
return this.expired || !this.accessKeyId || !this.secretAccessKey;
|
||
|
}
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Gets the existing credentials, refreshing them if they are not yet loaded
|
||
|
* or have expired. Users should call this method before using {refresh},
|
||
|
* as this will not attempt to reload credentials when they are already
|
||
|
* loaded into the object.
|
||
|
*
|
||
|
* @callback callback function(err)
|
||
|
* When this callback is called with no error, it means either credentials
|
||
|
* do not need to be refreshed or refreshed credentials information has
|
||
|
* been loaded into the object (as the `accessKeyId`, `secretAccessKey`,
|
||
|
* and `sessionToken` properties).
|
||
|
* @param err [Error] if an error occurred, this value will be filled
|
||
|
*/
|
||
|
get: function get(callback) {
|
||
|
var self = this;
|
||
|
if (this.needsRefresh()) {
|
||
|
this.refresh(function(err) {
|
||
|
if (!err) self.expired = false; // reset expired flag
|
||
|
if (callback) callback(err);
|
||
|
});
|
||
|
} else if (callback) {
|
||
|
callback();
|
||
|
}
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* @!method getPromise()
|
||
|
* Returns a 'thenable' promise.
|
||
|
* Gets the existing credentials, refreshing them if they are not yet loaded
|
||
|
* or have expired. Users should call this method before using {refresh},
|
||
|
* as this will not attempt to reload credentials when they are already
|
||
|
* loaded into the object.
|
||
|
*
|
||
|
* Two callbacks can be provided to the `then` method on the returned promise.
|
||
|
* The first callback will be called if the promise is fulfilled, and the second
|
||
|
* callback will be called if the promise is rejected.
|
||
|
* @callback fulfilledCallback function()
|
||
|
* Called if the promise is fulfilled. When this callback is called, it
|
||
|
* means either credentials do not need to be refreshed or refreshed
|
||
|
* credentials information has been loaded into the object (as the
|
||
|
* `accessKeyId`, `secretAccessKey`, and `sessionToken` properties).
|
||
|
* @callback rejectedCallback function(err)
|
||
|
* Called if the promise is rejected.
|
||
|
* @param err [Error] if an error occurred, this value will be filled
|
||
|
* @return [Promise] A promise that represents the state of the `get` call.
|
||
|
* @example Calling the `getPromise` method.
|
||
|
* var promise = credProvider.getPromise();
|
||
|
* promise.then(function() { ... }, function(err) { ... });
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @!method refreshPromise()
|
||
|
* Returns a 'thenable' promise.
|
||
|
* Refreshes the credentials. Users should call {get} before attempting
|
||
|
* to forcibly refresh credentials.
|
||
|
*
|
||
|
* Two callbacks can be provided to the `then` method on the returned promise.
|
||
|
* The first callback will be called if the promise is fulfilled, and the second
|
||
|
* callback will be called if the promise is rejected.
|
||
|
* @callback fulfilledCallback function()
|
||
|
* Called if the promise is fulfilled. When this callback is called, it
|
||
|
* means refreshed credentials information has been loaded into the object
|
||
|
* (as the `accessKeyId`, `secretAccessKey`, and `sessionToken` properties).
|
||
|
* @callback rejectedCallback function(err)
|
||
|
* Called if the promise is rejected.
|
||
|
* @param err [Error] if an error occurred, this value will be filled
|
||
|
* @return [Promise] A promise that represents the state of the `refresh` call.
|
||
|
* @example Calling the `refreshPromise` method.
|
||
|
* var promise = credProvider.refreshPromise();
|
||
|
* promise.then(function() { ... }, function(err) { ... });
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* Refreshes the credentials. Users should call {get} before attempting
|
||
|
* to forcibly refresh credentials.
|
||
|
*
|
||
|
* @callback callback function(err)
|
||
|
* When this callback is called with no error, it means refreshed
|
||
|
* credentials information has been loaded into the object (as the
|
||
|
* `accessKeyId`, `secretAccessKey`, and `sessionToken` properties).
|
||
|
* @param err [Error] if an error occurred, this value will be filled
|
||
|
* @note Subclasses should override this class to reset the
|
||
|
* {accessKeyId}, {secretAccessKey} and optional {sessionToken}
|
||
|
* on the credentials object and then call the callback with
|
||
|
* any error information.
|
||
|
* @see get
|
||
|
*/
|
||
|
refresh: function refresh(callback) {
|
||
|
this.expired = false;
|
||
|
callback();
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* @api private
|
||
|
* @param callback
|
||
|
*/
|
||
|
coalesceRefresh: function coalesceRefresh(callback, sync) {
|
||
|
var self = this;
|
||
|
if (self.refreshCallbacks.push(callback) === 1) {
|
||
|
self.load(function onLoad(err) {
|
||
|
AWS.util.arrayEach(self.refreshCallbacks, function(callback) {
|
||
|
if (sync) {
|
||
|
callback(err);
|
||
|
} else {
|
||
|
// callback could throw, so defer to ensure all callbacks are notified
|
||
|
AWS.util.defer(function () {
|
||
|
callback(err);
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
self.refreshCallbacks.length = 0;
|
||
|
});
|
||
|
}
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* @api private
|
||
|
* @param callback
|
||
|
*/
|
||
|
load: function load(callback) {
|
||
|
callback();
|
||
|
}
|
||
|
});
|
||
|
|
||
|
/**
|
||
|
* @api private
|
||
|
*/
|
||
|
AWS.Credentials.addPromisesToClass = function addPromisesToClass(PromiseDependency) {
|
||
|
this.prototype.getPromise = AWS.util.promisifyMethod('get', PromiseDependency);
|
||
|
this.prototype.refreshPromise = AWS.util.promisifyMethod('refresh', PromiseDependency);
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* @api private
|
||
|
*/
|
||
|
AWS.Credentials.deletePromisesFromClass = function deletePromisesFromClass() {
|
||
|
delete this.prototype.getPromise;
|
||
|
delete this.prototype.refreshPromise;
|
||
|
};
|
||
|
|
||
|
AWS.util.addPromises(AWS.Credentials);
|