process_credentials.js
5.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
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 = AWS.util.getProfilesFromSharedConfig(iniLoader, this.filename);
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) {
iniLoader.clearCachedFiles();
this.coalesceRefresh(callback || AWS.util.fn.callback);
}
});