Repository: aws/aws-sdk-js
Pull request #2323 (2018-10-25 16:18:28)

httpOptions on STS assume role in SharedIniFileCredentials
<!--
Thank you for your pull request. Please provide a description below.
-->

##### Checklist
<!-- Remove items that do not apply. For completed items, change [ ] to [x]. -->

- [x] `npm run test` passes
- [x] `.d.ts` file is updated
- [x] changelog is added
- [x] run `bundle exec rake docs:api` and inspect `doc/latest/index.html` if documentation is changed


srchase: For Feature Request: https://github.com/aws/aws-sdk-js/issues/2298
AllanFly120: Looks good! Can you also add a unit test for the change? You can refer to the test [here](https://github.com/aws/aws-sdk-js/blob/master/test/credentials.spec.js#L567). Instead of spy on `STS.assumeRole()`, you can spy on the node `httpClient` to confirm if the `httpOptions` is supplied to the client. like this:

```javascript
var spy = helpers.spyOn(httpClient, 'handleRequest').andCallThrough();
expect(spy.calls.length).to.eql(1);
expect(spy.calls[0].arguments[1]).to.eql(/**httpOptions you set*/)
```
The code change works but usually we need a unit test to make sure we don't accidentally break the feature in the future.
AllanFly120: Looks good to me. Can you rebase your commit and force update this PR? And then :shipit: 

Patch:
diff --git a/.changes/next-release/feature-Credentials-5e168daf.json b/.changes/next-release/feature-Credentials-5e168daf.json
new file mode 100644
index 000000000..717b30c67
--- /dev/null
+++ b/.changes/next-release/feature-Credentials-5e168daf.json
@@ -0,0 +1,5 @@
+{
+  "type": "feature",
+  "category": "Credentials",
+  "description": "httpsOptions for STS in SharedIniFileCredentials"
+}
\ No newline at end of file
diff --git a/lib/credentials/shared_ini_file_credentials.d.ts b/lib/credentials/shared_ini_file_credentials.d.ts
index 4234be38a..99e45fedf 100644
--- a/lib/credentials/shared_ini_file_credentials.d.ts
+++ b/lib/credentials/shared_ini_file_credentials.d.ts
@@ -1,4 +1,5 @@
 import {Credentials} from '../credentials';
+import {HTTPOptions} from '../config';
 export class SharedIniFileCredentials extends Credentials {
     /**
      * Creates a new SharedIniFileCredentials object.
@@ -11,4 +12,5 @@ interface SharedIniFileCredentialsOptions {
     filename?: string
     disableAssumeRole?: boolean
     tokenCodeFn?: (mfaSerial: string, callback: (err?: Error, token?: string) => void) => void
+    httpOptions?: HTTPOptions
 }
diff --git a/lib/credentials/shared_ini_file_credentials.js b/lib/credentials/shared_ini_file_credentials.js
index 1758499c2..f7a75bbfe 100644
--- a/lib/credentials/shared_ini_file_credentials.js
+++ b/lib/credentials/shared_ini_file_credentials.js
@@ -53,6 +53,28 @@ AWS.SharedIniFileCredentials = AWS.util.inherit(AWS.Credentials, {
    *   file. Function is called with value of mfa_serial and callback, and
    *   should provide the TokenCode or an error to the callback in the format
    *   callback(err, token)
+   * @option options httpOptions [map] A set of options to pass to the low-level
+   *   HTTP request. Currently supported options are:
+   *   * **proxy** [String] &mdash; the URL to proxy requests through
+   *   * **agent** [http.Agent, https.Agent] &mdash; the Agent object to perform
+   *     HTTP requests with. Used for connection pooling. Defaults to the global
+   *     agent (`http.globalAgent`) for non-SSL connections. Note that for
+   *     SSL connections, a special Agent object is used in order to enable
+   *     peer certificate verification. This feature is only available in the
+   *     Node.js environment.
+   *   * **connectTimeout** [Integer] &mdash; Sets the socket to timeout after
+   *     failing to establish a connection with the server after
+   *     `connectTimeout` milliseconds. This timeout has no effect once a socket
+   *     connection has been established.
+   *   * **timeout** [Integer] &mdash; Sets the socket to timeout after timeout
+   *     milliseconds of inactivity on the socket. Defaults to two minutes
+   *     (120000).
+   *   * **xhrAsync** [Boolean] &mdash; Whether the SDK will send asynchronous
+   *     HTTP requests. Used in the browser environment only. Set to false to
+   *     send requests synchronously. Defaults to true (async on).
+   *   * **xhrWithCredentials** [Boolean] &mdash; Sets the "withCredentials"
+   *     property of an XMLHttpRequest object. Used in the browser environment
+   *     only. Defaults to false.
    */
   constructor: function SharedIniFileCredentials(options) {
     AWS.Credentials.call(this);
@@ -65,6 +87,7 @@ AWS.SharedIniFileCredentials = AWS.util.inherit(AWS.Credentials, {
     this.disableAssumeRole = Boolean(options.disableAssumeRole);
     this.preferStaticCredentials = Boolean(options.preferStaticCredentials);
     this.tokenCodeFn = options.tokenCodeFn || null;
+    this.httpOptions = options.httpOptions || null;
     this.get(function() {});
   },
 
@@ -206,7 +229,8 @@ AWS.SharedIniFileCredentials = AWS.util.inherit(AWS.Credentials, {
 
     this.roleArn = roleArn;
     var sts = new STS({
-      credentials: sourceCredentials
+      credentials: sourceCredentials,
+      httpOptions: this.httpOptions
     });
 
     var roleParams = {


Test patch:
diff --git a/test/credentials.spec.js b/test/credentials.spec.js
index abdacac28..e28452c9c 100644
--- a/test/credentials.spec.js
+++ b/test/credentials.spec.js
@@ -598,6 +598,29 @@
           return done();
         });
       });
+      it('will use httpOptions for assume role when provided', function(done) {
+        var creds, mock;
+        var httpClient, spy;
+        mock = '[default]\nrole_arn = arn\nsource_profile = foo_base\n[foo_base]\naws_access_key_id = baseKey\naws_secret_access_key = baseSecret\n';
+        helpers.spyOn(AWS.util, 'readFileSync').andReturn(mock);
+        helpers.mockHttpResponse(200, {}, '<AssumeRoleResponse xmlns="https://sts.amazonaws.com/doc/2011-06-15/">\n  <AssumeRoleResult>\n    <Credentials>\n      <AccessKeyId>KEY</AccessKeyId>\n      <SecretAccessKey>SECRET</SecretAccessKey>\n      <SessionToken>TOKEN</SessionToken>\n      <Expiration>1970-01-01T00:00:00.000Z</Expiration>\n    </Credentials>\n  </AssumeRoleResult>\n</AssumeRoleResponse>');
+        creds = new AWS.SharedIniFileCredentials({
+          httpOptions: {
+            connectTimeout: 2000,
+            proxy: 'https://foo.bar',
+            timeout: 2000,
+          }
+        });
+        httpClient = AWS.HttpClient.getInstance();
+        spy = helpers.spyOn(httpClient, 'handleRequest').andCallThrough();
+        return creds.refresh(function(err) {
+          expect(spy.calls.length).to.equal(1);
+          expect(spy.calls[0].arguments[1].connectTimeout).to.equal(2000);
+          expect(spy.calls[0].arguments[1].proxy).to.equal('https://foo.bar');
+          expect(spy.calls[0].arguments[1].timeout).to.equal(2000);
+          return done();
+        });
+      });
 
       describe('mfa serial callback', function() {