mirror of
https://github.com/cderche/greenlock-storage-s3
synced 2025-05-13 16:16:32 +00:00
183 lines
6.3 KiB
JavaScript
183 lines
6.3 KiB
JavaScript
var AWS = require('../core');
|
|
var proc = require('child_process');
|
|
var iniLoader = AWS.util.iniLoader;
|
|
|
|
/**
|
|
* Represents credentials loaded from shared credentials file
|
|
* (defaulting to ~/.aws/credentials or defined by the
|
|
* `AWS_SHARED_CREDENTIALS_FILE` environment variable).
|
|
*
|
|
* ## Using process credentials
|
|
*
|
|
* The credentials file can specify a credential provider that executes
|
|
* a given process and attempts to read its stdout to recieve a JSON payload
|
|
* containing the credentials:
|
|
*
|
|
* [default]
|
|
* credential_process = /usr/bin/credential_proc
|
|
*
|
|
* Automatically handles refreshing credentials if an Expiration time is
|
|
* provided in the credentials payload. Credentials supplied in the same profile
|
|
* will take precedence over the credential_process.
|
|
*
|
|
* Sourcing credentials from an external process can potentially be dangerous,
|
|
* so proceed with caution. Other credential providers should be preferred if
|
|
* at all possible. If using this option, you should make sure that the shared
|
|
* credentials file is as locked down as possible using security best practices
|
|
* for your operating system.
|
|
*
|
|
* ## Using custom profiles
|
|
*
|
|
* The SDK supports loading credentials for separate profiles. This can be done
|
|
* in two ways:
|
|
*
|
|
* 1. Set the `AWS_PROFILE` environment variable in your process prior to
|
|
* loading the SDK.
|
|
* 2. Directly load the AWS.ProcessCredentials provider:
|
|
*
|
|
* ```javascript
|
|
* var creds = new AWS.ProcessCredentials({profile: 'myprofile'});
|
|
* AWS.config.credentials = creds;
|
|
* ```
|
|
*
|
|
* @!macro nobrowser
|
|
*/
|
|
AWS.ProcessCredentials = AWS.util.inherit(AWS.Credentials, {
|
|
/**
|
|
* Creates a new ProcessCredentials object.
|
|
*
|
|
* @param options [map] a set of options
|
|
* @option options profile [String] (AWS_PROFILE env var or 'default')
|
|
* the name of the profile to load.
|
|
* @option options filename [String] ('~/.aws/credentials' or defined by
|
|
* AWS_SHARED_CREDENTIALS_FILE process env var)
|
|
* the filename to use when loading credentials.
|
|
* @option options callback [Function] (err) Credentials are eagerly loaded
|
|
* by the constructor. When the callback is called with no error, the
|
|
* credentials have been loaded successfully.
|
|
*/
|
|
constructor: function ProcessCredentials(options) {
|
|
AWS.Credentials.call(this);
|
|
|
|
options = options || {};
|
|
|
|
this.filename = options.filename;
|
|
this.profile = options.profile || process.env.AWS_PROFILE || AWS.util.defaultProfile;
|
|
this.get(options.callback || AWS.util.fn.noop);
|
|
},
|
|
|
|
/**
|
|
* @api private
|
|
*/
|
|
load: function load(callback) {
|
|
var self = this;
|
|
try {
|
|
var profiles = {};
|
|
var profilesFromConfig = {};
|
|
if (process.env[AWS.util.configOptInEnv]) {
|
|
var profilesFromConfig = iniLoader.loadFrom({
|
|
isConfig: true,
|
|
filename: process.env[AWS.util.sharedConfigFileEnv]
|
|
});
|
|
}
|
|
var profilesFromCreds = iniLoader.loadFrom({
|
|
filename: this.filename ||
|
|
(process.env[AWS.util.configOptInEnv] && process.env[AWS.util.sharedCredentialsFileEnv])
|
|
});
|
|
for (var i = 0, profileNames = Object.keys(profilesFromCreds); i < profileNames.length; i++) {
|
|
profiles[profileNames[i]] = profilesFromCreds[profileNames[i]];
|
|
}
|
|
// load after profilesFromCreds to prefer profilesFromConfig
|
|
for (var i = 0, profileNames = Object.keys(profilesFromConfig); i < profileNames.length; i++) {
|
|
profiles[profileNames[i]] = profilesFromConfig[profileNames[i]];
|
|
}
|
|
var profile = profiles[this.profile] || {};
|
|
|
|
if (Object.keys(profile).length === 0) {
|
|
throw AWS.util.error(
|
|
new Error('Profile ' + this.profile + ' not found'),
|
|
{ code: 'ProcessCredentialsProviderFailure' }
|
|
);
|
|
}
|
|
|
|
if (profile['credential_process']) {
|
|
this.loadViaCredentialProcess(profile, function(err, data) {
|
|
if (err) {
|
|
callback(err, null);
|
|
} else {
|
|
self.expired = false;
|
|
self.accessKeyId = data.AccessKeyId;
|
|
self.secretAccessKey = data.SecretAccessKey;
|
|
self.sessionToken = data.SessionToken;
|
|
if (data.Expiration) {
|
|
self.expireTime = new Date(data.Expiration);
|
|
}
|
|
callback(null);
|
|
}
|
|
});
|
|
} else {
|
|
throw AWS.util.error(
|
|
new Error('Profile ' + this.profile + ' did not include credential process'),
|
|
{ code: 'ProcessCredentialsProviderFailure' }
|
|
);
|
|
}
|
|
} catch (err) {
|
|
callback(err);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Executes the credential_process and retrieves
|
|
* credentials from the output
|
|
* @api private
|
|
* @param profile [map] credentials profile
|
|
* @throws ProcessCredentialsProviderFailure
|
|
*/
|
|
loadViaCredentialProcess: function loadViaCredentialProcess(profile, callback) {
|
|
proc.exec(profile['credential_process'], function(err, stdOut, stdErr) {
|
|
if (err) {
|
|
callback(AWS.util.error(
|
|
new Error('credential_process returned error'),
|
|
{ code: 'ProcessCredentialsProviderFailure'}
|
|
), null);
|
|
} else {
|
|
try {
|
|
var credData = JSON.parse(stdOut);
|
|
if (credData.Expiration) {
|
|
var currentTime = AWS.util.date.getDate();
|
|
var expireTime = new Date(credData.Expiration);
|
|
if (expireTime < currentTime) {
|
|
throw Error('credential_process returned expired credentials');
|
|
}
|
|
}
|
|
|
|
if (credData.Version !== 1) {
|
|
throw Error('credential_process does not return Version == 1');
|
|
}
|
|
callback(null, credData);
|
|
} catch (err) {
|
|
callback(AWS.util.error(
|
|
new Error(err.message),
|
|
{ code: 'ProcessCredentialsProviderFailure'}
|
|
), null);
|
|
}
|
|
}
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Loads the credentials from the credential process
|
|
*
|
|
* @callback callback function(err)
|
|
* Called after the credential process has been executed. 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 get
|
|
*/
|
|
refresh: function refresh(callback) {
|
|
this.coalesceRefresh(callback || AWS.util.fn.callback);
|
|
}
|
|
});
|