123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- var fs = require('fs');
- var AWS = require('../core'),
- ENV_RELATIVE_URI = 'AWS_CONTAINER_CREDENTIALS_RELATIVE_URI',
- ENV_FULL_URI = 'AWS_CONTAINER_CREDENTIALS_FULL_URI',
- ENV_AUTH_TOKEN = 'AWS_CONTAINER_AUTHORIZATION_TOKEN',
- ENV_AUTH_TOKEN_FILE = 'AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE',
- FULL_URI_UNRESTRICTED_PROTOCOLS = ['https:'],
- FULL_URI_ALLOWED_PROTOCOLS = ['http:', 'https:'],
- FULL_URI_ALLOWED_HOSTNAMES = ['localhost', '127.0.0.1', '169.254.170.23'],
- RELATIVE_URI_HOST = '169.254.170.2';
- /**
- * Represents credentials received from specified URI.
- *
- * This class will request refreshable credentials from the relative URI
- * specified by the AWS_CONTAINER_CREDENTIALS_RELATIVE_URI or the
- * AWS_CONTAINER_CREDENTIALS_FULL_URI environment variable. If valid credentials
- * are returned in the response, these will be used with zero configuration.
- *
- * This credentials class will by default timeout after 1 second of inactivity
- * and retry 3 times.
- * If your requests to the relative URI are timing out, you can increase
- * the value by configuring them directly:
- *
- * ```javascript
- * AWS.config.credentials = new AWS.RemoteCredentials({
- * httpOptions: { timeout: 5000 }, // 5 second timeout
- * maxRetries: 10, // retry 10 times
- * retryDelayOptions: { base: 200 } // see AWS.Config for information
- * });
- * ```
- *
- * @see AWS.Config.retryDelayOptions
- *
- * @!macro nobrowser
- */
- AWS.RemoteCredentials = AWS.util.inherit(AWS.Credentials, {
- constructor: function RemoteCredentials(options) {
- AWS.Credentials.call(this);
- options = options ? AWS.util.copy(options) : {};
- if (!options.httpOptions) options.httpOptions = {};
- options.httpOptions = AWS.util.merge(
- this.httpOptions, options.httpOptions);
- AWS.util.update(this, options);
- },
- /**
- * @api private
- */
- httpOptions: { timeout: 1000 },
- /**
- * @api private
- */
- maxRetries: 3,
- /**
- * @api private
- */
- isConfiguredForEcsCredentials: function isConfiguredForEcsCredentials() {
- return Boolean(
- process &&
- process.env &&
- (process.env[ENV_RELATIVE_URI] || process.env[ENV_FULL_URI])
- );
- },
- /**
- * @api private
- */
- getECSFullUri: function getECSFullUri() {
- if (process && process.env) {
- var relative = process.env[ENV_RELATIVE_URI],
- full = process.env[ENV_FULL_URI];
- if (relative) {
- return 'http://' + RELATIVE_URI_HOST + relative;
- } else if (full) {
- var parsed = AWS.util.urlParse(full);
- if (FULL_URI_ALLOWED_PROTOCOLS.indexOf(parsed.protocol) < 0) {
- throw AWS.util.error(
- new Error('Unsupported protocol: AWS.RemoteCredentials supports '
- + FULL_URI_ALLOWED_PROTOCOLS.join(',') + ' only; '
- + parsed.protocol + ' requested.'),
- { code: 'ECSCredentialsProviderFailure' }
- );
- }
- if (FULL_URI_UNRESTRICTED_PROTOCOLS.indexOf(parsed.protocol) < 0 &&
- FULL_URI_ALLOWED_HOSTNAMES.indexOf(parsed.hostname) < 0) {
- throw AWS.util.error(
- new Error('Unsupported hostname: AWS.RemoteCredentials only supports '
- + FULL_URI_ALLOWED_HOSTNAMES.join(',') + ' for ' + parsed.protocol + '; '
- + parsed.protocol + '//' + parsed.hostname + ' requested.'),
- { code: 'ECSCredentialsProviderFailure' }
- );
- }
- return full;
- } else {
- throw AWS.util.error(
- new Error('Variable ' + ENV_RELATIVE_URI + ' or ' + ENV_FULL_URI +
- ' must be set to use AWS.RemoteCredentials.'),
- { code: 'ECSCredentialsProviderFailure' }
- );
- }
- } else {
- throw AWS.util.error(
- new Error('No process info available'),
- { code: 'ECSCredentialsProviderFailure' }
- );
- }
- },
- /**
- * @api private
- */
- getECSAuthToken: function getECSAuthToken() {
- if (process && process.env && (process.env[ENV_FULL_URI] || process.env[ENV_AUTH_TOKEN_FILE])) {
- if (!process.env[ENV_AUTH_TOKEN] && process.env[ENV_AUTH_TOKEN_FILE]) {
- try {
- var data = fs.readFileSync(process.env[ENV_AUTH_TOKEN_FILE]).toString();
- return data;
- } catch (error) {
- console.error('Error reading token file:', error);
- throw error; // Re-throw the error to propagate it
- }
- }
- return process.env[ENV_AUTH_TOKEN];
- }
- },
- /**
- * @api private
- */
- credsFormatIsValid: function credsFormatIsValid(credData) {
- return (!!credData.accessKeyId && !!credData.secretAccessKey &&
- !!credData.sessionToken && !!credData.expireTime);
- },
- /**
- * @api private
- */
- formatCreds: function formatCreds(credData) {
- if (!!credData.credentials) {
- credData = credData.credentials;
- }
- return {
- expired: false,
- accessKeyId: credData.accessKeyId || credData.AccessKeyId,
- secretAccessKey: credData.secretAccessKey || credData.SecretAccessKey,
- sessionToken: credData.sessionToken || credData.Token,
- expireTime: new Date(credData.expiration || credData.Expiration)
- };
- },
- /**
- * @api private
- */
- request: function request(url, callback) {
- var httpRequest = new AWS.HttpRequest(url);
- httpRequest.method = 'GET';
- httpRequest.headers.Accept = 'application/json';
- var token = this.getECSAuthToken();
- if (token) {
- httpRequest.headers.Authorization = token;
- }
- AWS.util.handleRequestWithRetries(httpRequest, this, callback);
- },
- /**
- * Loads the credentials from the relative URI specified by container
- *
- * @callback callback function(err)
- * Called when the request to the relative URI 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`, `sessionToken`, and `expireTime` 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);
- },
- /**
- * @api private
- */
- load: function load(callback) {
- var self = this;
- var fullUri;
- try {
- fullUri = this.getECSFullUri();
- } catch (err) {
- callback(err);
- return;
- }
- this.request(fullUri, function(err, data) {
- if (!err) {
- try {
- data = JSON.parse(data);
- var creds = self.formatCreds(data);
- if (!self.credsFormatIsValid(creds)) {
- throw AWS.util.error(
- new Error('Response data is not in valid format'),
- { code: 'ECSCredentialsProviderFailure' }
- );
- }
- AWS.util.update(self, creds);
- } catch (dataError) {
- err = dataError;
- }
- }
- callback(err, creds);
- });
- }
- });
|