123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- var AWS = require('../core');
- var STS = require('../../clients/sts');
- /**
- * Represents temporary credentials retrieved from {AWS.STS}. Without any
- * extra parameters, credentials will be fetched from the
- * {AWS.STS.getSessionToken} operation. If an IAM role is provided, the
- * {AWS.STS.assumeRole} operation will be used to fetch credentials for the
- * role instead.
- *
- * AWS.ChainableTemporaryCredentials differs from AWS.TemporaryCredentials in
- * the way masterCredentials and refreshes are handled.
- * AWS.ChainableTemporaryCredentials refreshes expired credentials using the
- * masterCredentials passed by the user to support chaining of STS credentials.
- * However, AWS.TemporaryCredentials recursively collapses the masterCredentials
- * during instantiation, precluding the ability to refresh credentials which
- * require intermediate, temporary credentials.
- *
- * For example, if the application should use RoleA, which must be assumed from
- * RoleB, and the environment provides credentials which can assume RoleB, then
- * AWS.ChainableTemporaryCredentials must be used to support refreshing the
- * temporary credentials for RoleA:
- *
- * ```javascript
- * var roleACreds = new AWS.ChainableTemporaryCredentials({
- * params: {RoleArn: 'RoleA'},
- * masterCredentials: new AWS.ChainableTemporaryCredentials({
- * params: {RoleArn: 'RoleB'},
- * masterCredentials: new AWS.EnvironmentCredentials('AWS')
- * })
- * });
- * ```
- *
- * If AWS.TemporaryCredentials had been used in the previous example,
- * `roleACreds` would fail to refresh because `roleACreds` would
- * use the environment credentials for the AssumeRole request.
- *
- * Another difference is that AWS.ChainableTemporaryCredentials creates the STS
- * service instance during instantiation while AWS.TemporaryCredentials creates
- * the STS service instance during the first refresh. Creating the service
- * instance during instantiation effectively captures the master credentials
- * from the global config, so that subsequent changes to the global config do
- * not affect the master credentials used to refresh the temporary credentials.
- *
- * This allows an instance of AWS.ChainableTemporaryCredentials to be assigned
- * to AWS.config.credentials:
- *
- * ```javascript
- * var envCreds = new AWS.EnvironmentCredentials('AWS');
- * AWS.config.credentials = envCreds;
- * // masterCredentials will be envCreds
- * AWS.config.credentials = new AWS.ChainableTemporaryCredentials({
- * params: {RoleArn: '...'}
- * });
- * ```
- *
- * Similarly, to use the CredentialProviderChain's default providers as the
- * master credentials, simply create a new instance of
- * AWS.ChainableTemporaryCredentials:
- *
- * ```javascript
- * AWS.config.credentials = new ChainableTemporaryCredentials({
- * params: {RoleArn: '...'}
- * });
- * ```
- *
- * @!attribute service
- * @return [AWS.STS] the STS service instance used to
- * get and refresh temporary credentials from AWS STS.
- * @note (see constructor)
- */
- AWS.ChainableTemporaryCredentials = AWS.util.inherit(AWS.Credentials, {
- /**
- * Creates a new temporary credentials object.
- *
- * @param options [map] a set of options
- * @option options params [map] ({}) a map of options that are passed to the
- * {AWS.STS.assumeRole} or {AWS.STS.getSessionToken} operations.
- * If a `RoleArn` parameter is passed in, credentials will be based on the
- * IAM role. If a `SerialNumber` parameter is passed in, {tokenCodeFn} must
- * also be passed in or an error will be thrown.
- * @option options masterCredentials [AWS.Credentials] the master credentials
- * used to get and refresh temporary credentials from AWS STS. By default,
- * AWS.config.credentials or AWS.config.credentialProvider will be used.
- * @option options tokenCodeFn [Function] (null) Function to provide
- * `TokenCode`, if `SerialNumber` is provided for profile in {params}. Function
- * is called with value of `SerialNumber` and `callback`, and should provide
- * the `TokenCode` or an error to the callback in the format
- * `callback(err, token)`.
- * @example Creating a new credentials object for generic temporary credentials
- * AWS.config.credentials = new AWS.ChainableTemporaryCredentials();
- * @example Creating a new credentials object for an IAM role
- * AWS.config.credentials = new AWS.ChainableTemporaryCredentials({
- * params: {
- * RoleArn: 'arn:aws:iam::1234567890:role/TemporaryCredentials'
- * }
- * });
- * @see AWS.STS.assumeRole
- * @see AWS.STS.getSessionToken
- */
- constructor: function ChainableTemporaryCredentials(options) {
- AWS.Credentials.call(this);
- options = options || {};
- this.errorCode = 'ChainableTemporaryCredentialsProviderFailure';
- this.expired = true;
- this.tokenCodeFn = null;
- var params = AWS.util.copy(options.params) || {};
- if (params.RoleArn) {
- params.RoleSessionName = params.RoleSessionName || 'temporary-credentials';
- }
- if (params.SerialNumber) {
- if (!options.tokenCodeFn || (typeof options.tokenCodeFn !== 'function')) {
- throw new AWS.util.error(
- new Error('tokenCodeFn must be a function when params.SerialNumber is given'),
- {code: this.errorCode}
- );
- } else {
- this.tokenCodeFn = options.tokenCodeFn;
- }
- }
- var config = AWS.util.merge(
- {
- params: params,
- credentials: options.masterCredentials || AWS.config.credentials
- },
- options.stsConfig || {}
- );
- this.service = new STS(config);
- },
- /**
- * Refreshes credentials using {AWS.STS.assumeRole} or
- * {AWS.STS.getSessionToken}, depending on whether an IAM role ARN was passed
- * to the credentials {constructor}.
- *
- * @callback callback function(err)
- * Called when the STS service responds (or fails). When
- * this callback is called with no error, it means that the 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
- * @see AWS.Credentials.get
- */
- refresh: function refresh(callback) {
- this.coalesceRefresh(callback || AWS.util.fn.callback);
- },
- /**
- * @api private
- * @param callback
- */
- load: function load(callback) {
- var self = this;
- var operation = self.service.config.params.RoleArn ? 'assumeRole' : 'getSessionToken';
- this.getTokenCode(function (err, tokenCode) {
- var params = {};
- if (err) {
- callback(err);
- return;
- }
- if (tokenCode) {
- params.TokenCode = tokenCode;
- }
- self.service[operation](params, function (err, data) {
- if (!err) {
- self.service.credentialsFrom(data, self);
- }
- callback(err);
- });
- });
- },
- /**
- * @api private
- */
- getTokenCode: function getTokenCode(callback) {
- var self = this;
- if (this.tokenCodeFn) {
- this.tokenCodeFn(this.service.config.params.SerialNumber, function (err, token) {
- if (err) {
- var message = err;
- if (err instanceof Error) {
- message = err.message;
- }
- callback(
- AWS.util.error(
- new Error('Error fetching MFA token: ' + message),
- { code: self.errorCode}
- )
- );
- return;
- }
- callback(null, token);
- });
- } else {
- callback(null);
- }
- }
- });
|