1 | var AWS = require('./core');
|
2 |
|
3 | /**
|
4 | * Represents your AWS security credentials, specifically the
|
5 | * {accessKeyId}, {secretAccessKey}, and optional {sessionToken}.
|
6 | * Creating a `Credentials` object allows you to pass around your
|
7 | * security information to configuration and service objects.
|
8 | *
|
9 | * Note that this class typically does not need to be constructed manually,
|
10 | * as the {AWS.Config} and {AWS.Service} classes both accept simple
|
11 | * options hashes with the three keys. These structures will be converted
|
12 | * into Credentials objects automatically.
|
13 | *
|
14 | * ## Expiring and Refreshing Credentials
|
15 | *
|
16 | * Occasionally credentials can expire in the middle of a long-running
|
17 | * application. In this case, the SDK will automatically attempt to
|
18 | * refresh the credentials from the storage location if the Credentials
|
19 | * class implements the {refresh} method.
|
20 | *
|
21 | * If you are implementing a credential storage location, you
|
22 | * will want to create a subclass of the `Credentials` class and
|
23 | * override the {refresh} method. This method allows credentials to be
|
24 | * retrieved from the backing store, be it a file system, database, or
|
25 | * some network storage. The method should reset the credential attributes
|
26 | * on the object.
|
27 | *
|
28 | * @!attribute expired
|
29 | * @return [Boolean] whether the credentials have been expired and
|
30 | * require a refresh. Used in conjunction with {expireTime}.
|
31 | * @!attribute expireTime
|
32 | * @return [Date] a time when credentials should be considered expired. Used
|
33 | * in conjunction with {expired}.
|
34 | * @!attribute accessKeyId
|
35 | * @return [String] the AWS access key ID
|
36 | * @!attribute secretAccessKey
|
37 | * @return [String] the AWS secret access key
|
38 | * @!attribute sessionToken
|
39 | * @return [String] an optional AWS session token
|
40 | */
|
41 | AWS.Credentials = AWS.util.inherit({
|
42 | /**
|
43 | * A credentials object can be created using positional arguments or an options
|
44 | * hash.
|
45 | *
|
46 | * @overload AWS.Credentials(accessKeyId, secretAccessKey, sessionToken=null)
|
47 | * Creates a Credentials object with a given set of credential information
|
48 | * as positional arguments.
|
49 | * @param accessKeyId [String] the AWS access key ID
|
50 | * @param secretAccessKey [String] the AWS secret access key
|
51 | * @param sessionToken [String] the optional AWS session token
|
52 | * @example Create a credentials object with AWS credentials
|
53 | * var creds = new AWS.Credentials('akid', 'secret', 'session');
|
54 | * @overload AWS.Credentials(options)
|
55 | * Creates a Credentials object with a given set of credential information
|
56 | * as an options hash.
|
57 | * @option options accessKeyId [String] the AWS access key ID
|
58 | * @option options secretAccessKey [String] the AWS secret access key
|
59 | * @option options sessionToken [String] the optional AWS session token
|
60 | * @example Create a credentials object with AWS credentials
|
61 | * var creds = new AWS.Credentials({
|
62 | * accessKeyId: 'akid', secretAccessKey: 'secret', sessionToken: 'session'
|
63 | * });
|
64 | */
|
65 | constructor: function Credentials() {
|
66 | // hide secretAccessKey from being displayed with util.inspect
|
67 | AWS.util.hideProperties(this, ['secretAccessKey']);
|
68 |
|
69 | this.expired = false;
|
70 | this.expireTime = null;
|
71 | this.refreshCallbacks = [];
|
72 | if (arguments.length === 1 && typeof arguments[0] === 'object') {
|
73 | var creds = arguments[0].credentials || arguments[0];
|
74 | this.accessKeyId = creds.accessKeyId;
|
75 | this.secretAccessKey = creds.secretAccessKey;
|
76 | this.sessionToken = creds.sessionToken;
|
77 | } else {
|
78 | this.accessKeyId = arguments[0];
|
79 | this.secretAccessKey = arguments[1];
|
80 | this.sessionToken = arguments[2];
|
81 | }
|
82 | },
|
83 |
|
84 | /**
|
85 | * @return [Integer] the number of seconds before {expireTime} during which
|
86 | * the credentials will be considered expired.
|
87 | */
|
88 | expiryWindow: 15,
|
89 |
|
90 | /**
|
91 | * @return [Boolean] whether the credentials object should call {refresh}
|
92 | * @note Subclasses should override this method to provide custom refresh
|
93 | * logic.
|
94 | */
|
95 | needsRefresh: function needsRefresh() {
|
96 | var currentTime = AWS.util.date.getDate().getTime();
|
97 | var adjustedTime = new Date(currentTime + this.expiryWindow * 1000);
|
98 |
|
99 | if (this.expireTime && adjustedTime > this.expireTime) {
|
100 | return true;
|
101 | } else {
|
102 | return this.expired || !this.accessKeyId || !this.secretAccessKey;
|
103 | }
|
104 | },
|
105 |
|
106 | /**
|
107 | * Gets the existing credentials, refreshing them if they are not yet loaded
|
108 | * or have expired. Users should call this method before using {refresh},
|
109 | * as this will not attempt to reload credentials when they are already
|
110 | * loaded into the object.
|
111 | *
|
112 | * @callback callback function(err)
|
113 | * When this callback is called with no error, it means either credentials
|
114 | * do not need to be refreshed or refreshed credentials information has
|
115 | * been loaded into the object (as the `accessKeyId`, `secretAccessKey`,
|
116 | * and `sessionToken` properties).
|
117 | * @param err [Error] if an error occurred, this value will be filled
|
118 | */
|
119 | get: function get(callback) {
|
120 | var self = this;
|
121 | if (this.needsRefresh()) {
|
122 | this.refresh(function(err) {
|
123 | if (!err) self.expired = false; // reset expired flag
|
124 | if (callback) callback(err);
|
125 | });
|
126 | } else if (callback) {
|
127 | callback();
|
128 | }
|
129 | },
|
130 |
|
131 | /**
|
132 | * @!method getPromise()
|
133 | * Returns a 'thenable' promise.
|
134 | * Gets the existing credentials, refreshing them if they are not yet loaded
|
135 | * or have expired. Users should call this method before using {refresh},
|
136 | * as this will not attempt to reload credentials when they are already
|
137 | * loaded into the object.
|
138 | *
|
139 | * Two callbacks can be provided to the `then` method on the returned promise.
|
140 | * The first callback will be called if the promise is fulfilled, and the second
|
141 | * callback will be called if the promise is rejected.
|
142 | * @callback fulfilledCallback function()
|
143 | * Called if the promise is fulfilled. When this callback is called, it
|
144 | * means either credentials do not need to be refreshed or refreshed
|
145 | * credentials information has been loaded into the object (as the
|
146 | * `accessKeyId`, `secretAccessKey`, and `sessionToken` properties).
|
147 | * @callback rejectedCallback function(err)
|
148 | * Called if the promise is rejected.
|
149 | * @param err [Error] if an error occurred, this value will be filled
|
150 | * @return [Promise] A promise that represents the state of the `get` call.
|
151 | * @example Calling the `getPromise` method.
|
152 | * var promise = credProvider.getPromise();
|
153 | * promise.then(function() { ... }, function(err) { ... });
|
154 | */
|
155 |
|
156 | /**
|
157 | * @!method refreshPromise()
|
158 | * Returns a 'thenable' promise.
|
159 | * Refreshes the credentials. Users should call {get} before attempting
|
160 | * to forcibly refresh credentials.
|
161 | *
|
162 | * Two callbacks can be provided to the `then` method on the returned promise.
|
163 | * The first callback will be called if the promise is fulfilled, and the second
|
164 | * callback will be called if the promise is rejected.
|
165 | * @callback fulfilledCallback function()
|
166 | * Called if the promise is fulfilled. When this callback is called, it
|
167 | * means refreshed credentials information has been loaded into the object
|
168 | * (as the `accessKeyId`, `secretAccessKey`, and `sessionToken` properties).
|
169 | * @callback rejectedCallback function(err)
|
170 | * Called if the promise is rejected.
|
171 | * @param err [Error] if an error occurred, this value will be filled
|
172 | * @return [Promise] A promise that represents the state of the `refresh` call.
|
173 | * @example Calling the `refreshPromise` method.
|
174 | * var promise = credProvider.refreshPromise();
|
175 | * promise.then(function() { ... }, function(err) { ... });
|
176 | */
|
177 |
|
178 | /**
|
179 | * Refreshes the credentials. Users should call {get} before attempting
|
180 | * to forcibly refresh credentials.
|
181 | *
|
182 | * @callback callback function(err)
|
183 | * When this callback is called with no error, it means refreshed
|
184 | * credentials information has been loaded into the object (as the
|
185 | * `accessKeyId`, `secretAccessKey`, and `sessionToken` properties).
|
186 | * @param err [Error] if an error occurred, this value will be filled
|
187 | * @note Subclasses should override this class to reset the
|
188 | * {accessKeyId}, {secretAccessKey} and optional {sessionToken}
|
189 | * on the credentials object and then call the callback with
|
190 | * any error information.
|
191 | * @see get
|
192 | */
|
193 | refresh: function refresh(callback) {
|
194 | this.expired = false;
|
195 | callback();
|
196 | },
|
197 |
|
198 | /**
|
199 | * @api private
|
200 | * @param callback
|
201 | */
|
202 | coalesceRefresh: function coalesceRefresh(callback, sync) {
|
203 | var self = this;
|
204 | if (self.refreshCallbacks.push(callback) === 1) {
|
205 | self.load(function onLoad(err) {
|
206 | AWS.util.arrayEach(self.refreshCallbacks, function(callback) {
|
207 | if (sync) {
|
208 | callback(err);
|
209 | } else {
|
210 | // callback could throw, so defer to ensure all callbacks are notified
|
211 | AWS.util.defer(function () {
|
212 | callback(err);
|
213 | });
|
214 | }
|
215 | });
|
216 | self.refreshCallbacks.length = 0;
|
217 | });
|
218 | }
|
219 | },
|
220 |
|
221 | /**
|
222 | * @api private
|
223 | * @param callback
|
224 | */
|
225 | load: function load(callback) {
|
226 | callback();
|
227 | }
|
228 | });
|
229 |
|
230 | /**
|
231 | * @api private
|
232 | */
|
233 | AWS.Credentials.addPromisesToClass = function addPromisesToClass(PromiseDependency) {
|
234 | this.prototype.getPromise = AWS.util.promisifyMethod('get', PromiseDependency);
|
235 | this.prototype.refreshPromise = AWS.util.promisifyMethod('refresh', PromiseDependency);
|
236 | };
|
237 |
|
238 | /**
|
239 | * @api private
|
240 | */
|
241 | AWS.Credentials.deletePromisesFromClass = function deletePromisesFromClass() {
|
242 | delete this.prototype.getPromise;
|
243 | delete this.prototype.refreshPromise;
|
244 | };
|
245 |
|
246 | AWS.util.addPromises(AWS.Credentials);
|