github.com/mohanarpit/terraform@v0.6.16-0.20160909104007-291f29853544/builtin/providers/aws/auth_helpers_test.go (about)

     1  package aws
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io/ioutil"
     8  	"log"
     9  	"net/http"
    10  	"net/http/httptest"
    11  	"os"
    12  	"testing"
    13  	"time"
    14  
    15  	"github.com/aws/aws-sdk-go/aws"
    16  	"github.com/aws/aws-sdk-go/aws/awserr"
    17  	awsCredentials "github.com/aws/aws-sdk-go/aws/credentials"
    18  	"github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds"
    19  	"github.com/aws/aws-sdk-go/aws/session"
    20  	"github.com/aws/aws-sdk-go/service/iam"
    21  	"github.com/aws/aws-sdk-go/service/sts"
    22  )
    23  
    24  func TestAWSGetAccountId_shouldBeValid_fromEC2Role(t *testing.T) {
    25  	resetEnv := unsetEnv(t)
    26  	defer resetEnv()
    27  	// capture the test server's close method, to call after the test returns
    28  	awsTs := awsEnv(t)
    29  	defer awsTs()
    30  
    31  	iamEndpoints := []*iamEndpoint{}
    32  	ts, iamConn, stsConn := getMockedAwsIamStsApi(iamEndpoints)
    33  	defer ts()
    34  
    35  	id, err := GetAccountId(iamConn, stsConn, ec2rolecreds.ProviderName)
    36  	if err != nil {
    37  		t.Fatalf("Getting account ID from EC2 metadata API failed: %s", err)
    38  	}
    39  
    40  	expectedAccountId := "123456789013"
    41  	if id != expectedAccountId {
    42  		t.Fatalf("Expected account ID: %s, given: %s", expectedAccountId, id)
    43  	}
    44  }
    45  
    46  func TestAWSGetAccountId_shouldBeValid_EC2RoleHasPriority(t *testing.T) {
    47  	resetEnv := unsetEnv(t)
    48  	defer resetEnv()
    49  	// capture the test server's close method, to call after the test returns
    50  	awsTs := awsEnv(t)
    51  	defer awsTs()
    52  
    53  	iamEndpoints := []*iamEndpoint{
    54  		{
    55  			Request:  &iamRequest{"POST", "/", "Action=GetUser&Version=2010-05-08"},
    56  			Response: &iamResponse{200, iamResponse_GetUser_valid, "text/xml"},
    57  		},
    58  	}
    59  	ts, iamConn, stsConn := getMockedAwsIamStsApi(iamEndpoints)
    60  	defer ts()
    61  
    62  	id, err := GetAccountId(iamConn, stsConn, ec2rolecreds.ProviderName)
    63  	if err != nil {
    64  		t.Fatalf("Getting account ID from EC2 metadata API failed: %s", err)
    65  	}
    66  
    67  	expectedAccountId := "123456789013"
    68  	if id != expectedAccountId {
    69  		t.Fatalf("Expected account ID: %s, given: %s", expectedAccountId, id)
    70  	}
    71  }
    72  
    73  func TestAWSGetAccountId_shouldBeValid_fromIamUser(t *testing.T) {
    74  	iamEndpoints := []*iamEndpoint{
    75  		{
    76  			Request:  &iamRequest{"POST", "/", "Action=GetUser&Version=2010-05-08"},
    77  			Response: &iamResponse{200, iamResponse_GetUser_valid, "text/xml"},
    78  		},
    79  	}
    80  
    81  	ts, iamConn, stsConn := getMockedAwsIamStsApi(iamEndpoints)
    82  	defer ts()
    83  
    84  	id, err := GetAccountId(iamConn, stsConn, "")
    85  	if err != nil {
    86  		t.Fatalf("Getting account ID via GetUser failed: %s", err)
    87  	}
    88  
    89  	expectedAccountId := "123456789012"
    90  	if id != expectedAccountId {
    91  		t.Fatalf("Expected account ID: %s, given: %s", expectedAccountId, id)
    92  	}
    93  }
    94  
    95  func TestAWSGetAccountId_shouldBeValid_fromGetCallerIdentity(t *testing.T) {
    96  	iamEndpoints := []*iamEndpoint{
    97  		{
    98  			Request:  &iamRequest{"POST", "/", "Action=GetUser&Version=2010-05-08"},
    99  			Response: &iamResponse{403, iamResponse_GetUser_unauthorized, "text/xml"},
   100  		},
   101  		{
   102  			Request:  &iamRequest{"POST", "/", "Action=GetCallerIdentity&Version=2011-06-15"},
   103  			Response: &iamResponse{200, stsResponse_GetCallerIdentity_valid, "text/xml"},
   104  		},
   105  	}
   106  	ts, iamConn, stsConn := getMockedAwsIamStsApi(iamEndpoints)
   107  	defer ts()
   108  
   109  	id, err := GetAccountId(iamConn, stsConn, "")
   110  	if err != nil {
   111  		t.Fatalf("Getting account ID via GetUser failed: %s", err)
   112  	}
   113  
   114  	expectedAccountId := "123456789012"
   115  	if id != expectedAccountId {
   116  		t.Fatalf("Expected account ID: %s, given: %s", expectedAccountId, id)
   117  	}
   118  }
   119  
   120  func TestAWSGetAccountId_shouldBeValid_fromIamListRoles(t *testing.T) {
   121  	iamEndpoints := []*iamEndpoint{
   122  		{
   123  			Request:  &iamRequest{"POST", "/", "Action=GetUser&Version=2010-05-08"},
   124  			Response: &iamResponse{403, iamResponse_GetUser_unauthorized, "text/xml"},
   125  		},
   126  		{
   127  			Request:  &iamRequest{"POST", "/", "Action=GetCallerIdentity&Version=2011-06-15"},
   128  			Response: &iamResponse{403, stsResponse_GetCallerIdentity_unauthorized, "text/xml"},
   129  		},
   130  		{
   131  			Request:  &iamRequest{"POST", "/", "Action=ListRoles&MaxItems=1&Version=2010-05-08"},
   132  			Response: &iamResponse{200, iamResponse_ListRoles_valid, "text/xml"},
   133  		},
   134  	}
   135  	ts, iamConn, stsConn := getMockedAwsIamStsApi(iamEndpoints)
   136  	defer ts()
   137  
   138  	id, err := GetAccountId(iamConn, stsConn, "")
   139  	if err != nil {
   140  		t.Fatalf("Getting account ID via ListRoles failed: %s", err)
   141  	}
   142  
   143  	expectedAccountId := "123456789012"
   144  	if id != expectedAccountId {
   145  		t.Fatalf("Expected account ID: %s, given: %s", expectedAccountId, id)
   146  	}
   147  }
   148  
   149  func TestAWSGetAccountId_shouldBeValid_federatedRole(t *testing.T) {
   150  	iamEndpoints := []*iamEndpoint{
   151  		{
   152  			Request:  &iamRequest{"POST", "/", "Action=GetUser&Version=2010-05-08"},
   153  			Response: &iamResponse{400, iamResponse_GetUser_federatedFailure, "text/xml"},
   154  		},
   155  		{
   156  			Request:  &iamRequest{"POST", "/", "Action=ListRoles&MaxItems=1&Version=2010-05-08"},
   157  			Response: &iamResponse{200, iamResponse_ListRoles_valid, "text/xml"},
   158  		},
   159  	}
   160  	ts, iamConn, stsConn := getMockedAwsIamStsApi(iamEndpoints)
   161  	defer ts()
   162  
   163  	id, err := GetAccountId(iamConn, stsConn, "")
   164  	if err != nil {
   165  		t.Fatalf("Getting account ID via ListRoles failed: %s", err)
   166  	}
   167  
   168  	expectedAccountId := "123456789012"
   169  	if id != expectedAccountId {
   170  		t.Fatalf("Expected account ID: %s, given: %s", expectedAccountId, id)
   171  	}
   172  }
   173  
   174  func TestAWSGetAccountId_shouldError_unauthorizedFromIam(t *testing.T) {
   175  	iamEndpoints := []*iamEndpoint{
   176  		{
   177  			Request:  &iamRequest{"POST", "/", "Action=GetUser&Version=2010-05-08"},
   178  			Response: &iamResponse{403, iamResponse_GetUser_unauthorized, "text/xml"},
   179  		},
   180  		{
   181  			Request:  &iamRequest{"POST", "/", "Action=ListRoles&MaxItems=1&Version=2010-05-08"},
   182  			Response: &iamResponse{403, iamResponse_ListRoles_unauthorized, "text/xml"},
   183  		},
   184  	}
   185  	ts, iamConn, stsConn := getMockedAwsIamStsApi(iamEndpoints)
   186  	defer ts()
   187  
   188  	id, err := GetAccountId(iamConn, stsConn, "")
   189  	if err == nil {
   190  		t.Fatal("Expected error when getting account ID")
   191  	}
   192  
   193  	if id != "" {
   194  		t.Fatalf("Expected no account ID, given: %s", id)
   195  	}
   196  }
   197  
   198  func TestAWSParseAccountIdFromArn(t *testing.T) {
   199  	validArn := "arn:aws:iam::101636750127:instance-profile/aws-elasticbeanstalk-ec2-role"
   200  	expectedId := "101636750127"
   201  	id, err := parseAccountIdFromArn(validArn)
   202  	if err != nil {
   203  		t.Fatalf("Expected no error when parsing valid ARN: %s", err)
   204  	}
   205  	if id != expectedId {
   206  		t.Fatalf("Parsed id doesn't match with expected (%q != %q)", id, expectedId)
   207  	}
   208  
   209  	invalidArn := "blablah"
   210  	id, err = parseAccountIdFromArn(invalidArn)
   211  	if err == nil {
   212  		t.Fatalf("Expected error when parsing invalid ARN (%q)", invalidArn)
   213  	}
   214  }
   215  
   216  func TestAWSGetCredentials_shouldError(t *testing.T) {
   217  	resetEnv := unsetEnv(t)
   218  	defer resetEnv()
   219  	cfg := Config{}
   220  
   221  	c, err := GetCredentials(&cfg)
   222  	if awsErr, ok := err.(awserr.Error); ok {
   223  		if awsErr.Code() != "NoCredentialProviders" {
   224  			t.Fatal("Expected NoCredentialProviders error")
   225  		}
   226  	}
   227  	_, err = c.Get()
   228  	if awsErr, ok := err.(awserr.Error); ok {
   229  		if awsErr.Code() != "NoCredentialProviders" {
   230  			t.Fatal("Expected NoCredentialProviders error")
   231  		}
   232  	}
   233  	if err == nil {
   234  		t.Fatal("Expected an error with empty env, keys, and IAM in AWS Config")
   235  	}
   236  }
   237  
   238  func TestAWSGetCredentials_shouldBeStatic(t *testing.T) {
   239  	simple := []struct {
   240  		Key, Secret, Token string
   241  	}{
   242  		{
   243  			Key:    "test",
   244  			Secret: "secret",
   245  		}, {
   246  			Key:    "test",
   247  			Secret: "test",
   248  			Token:  "test",
   249  		},
   250  	}
   251  
   252  	for _, c := range simple {
   253  		cfg := Config{
   254  			AccessKey: c.Key,
   255  			SecretKey: c.Secret,
   256  			Token:     c.Token,
   257  		}
   258  
   259  		creds, err := GetCredentials(&cfg)
   260  		if err != nil {
   261  			t.Fatalf("Error gettings creds: %s", err)
   262  		}
   263  		if creds == nil {
   264  			t.Fatal("Expected a static creds provider to be returned")
   265  		}
   266  
   267  		v, err := creds.Get()
   268  		if err != nil {
   269  			t.Fatalf("Error gettings creds: %s", err)
   270  		}
   271  
   272  		if v.AccessKeyID != c.Key {
   273  			t.Fatalf("AccessKeyID mismatch, expected: (%s), got (%s)", c.Key, v.AccessKeyID)
   274  		}
   275  		if v.SecretAccessKey != c.Secret {
   276  			t.Fatalf("SecretAccessKey mismatch, expected: (%s), got (%s)", c.Secret, v.SecretAccessKey)
   277  		}
   278  		if v.SessionToken != c.Token {
   279  			t.Fatalf("SessionToken mismatch, expected: (%s), got (%s)", c.Token, v.SessionToken)
   280  		}
   281  	}
   282  }
   283  
   284  // TestAWSGetCredentials_shouldIAM is designed to test the scenario of running Terraform
   285  // from an EC2 instance, without environment variables or manually supplied
   286  // credentials.
   287  func TestAWSGetCredentials_shouldIAM(t *testing.T) {
   288  	// clear AWS_* environment variables
   289  	resetEnv := unsetEnv(t)
   290  	defer resetEnv()
   291  
   292  	// capture the test server's close method, to call after the test returns
   293  	ts := awsEnv(t)
   294  	defer ts()
   295  
   296  	// An empty config, no key supplied
   297  	cfg := Config{}
   298  
   299  	creds, err := GetCredentials(&cfg)
   300  	if err != nil {
   301  		t.Fatalf("Error gettings creds: %s", err)
   302  	}
   303  	if creds == nil {
   304  		t.Fatal("Expected a static creds provider to be returned")
   305  	}
   306  
   307  	v, err := creds.Get()
   308  	if err != nil {
   309  		t.Fatalf("Error gettings creds: %s", err)
   310  	}
   311  	if v.AccessKeyID != "somekey" {
   312  		t.Fatalf("AccessKeyID mismatch, expected: (somekey), got (%s)", v.AccessKeyID)
   313  	}
   314  	if v.SecretAccessKey != "somesecret" {
   315  		t.Fatalf("SecretAccessKey mismatch, expected: (somesecret), got (%s)", v.SecretAccessKey)
   316  	}
   317  	if v.SessionToken != "sometoken" {
   318  		t.Fatalf("SessionToken mismatch, expected: (sometoken), got (%s)", v.SessionToken)
   319  	}
   320  }
   321  
   322  // TestAWSGetCredentials_shouldIAM is designed to test the scenario of running Terraform
   323  // from an EC2 instance, without environment variables or manually supplied
   324  // credentials.
   325  func TestAWSGetCredentials_shouldIgnoreIAM(t *testing.T) {
   326  	resetEnv := unsetEnv(t)
   327  	defer resetEnv()
   328  	// capture the test server's close method, to call after the test returns
   329  	ts := awsEnv(t)
   330  	defer ts()
   331  	simple := []struct {
   332  		Key, Secret, Token string
   333  	}{
   334  		{
   335  			Key:    "test",
   336  			Secret: "secret",
   337  		}, {
   338  			Key:    "test",
   339  			Secret: "test",
   340  			Token:  "test",
   341  		},
   342  	}
   343  
   344  	for _, c := range simple {
   345  		cfg := Config{
   346  			AccessKey: c.Key,
   347  			SecretKey: c.Secret,
   348  			Token:     c.Token,
   349  		}
   350  
   351  		creds, err := GetCredentials(&cfg)
   352  		if err != nil {
   353  			t.Fatalf("Error gettings creds: %s", err)
   354  		}
   355  		if creds == nil {
   356  			t.Fatal("Expected a static creds provider to be returned")
   357  		}
   358  
   359  		v, err := creds.Get()
   360  		if err != nil {
   361  			t.Fatalf("Error gettings creds: %s", err)
   362  		}
   363  		if v.AccessKeyID != c.Key {
   364  			t.Fatalf("AccessKeyID mismatch, expected: (%s), got (%s)", c.Key, v.AccessKeyID)
   365  		}
   366  		if v.SecretAccessKey != c.Secret {
   367  			t.Fatalf("SecretAccessKey mismatch, expected: (%s), got (%s)", c.Secret, v.SecretAccessKey)
   368  		}
   369  		if v.SessionToken != c.Token {
   370  			t.Fatalf("SessionToken mismatch, expected: (%s), got (%s)", c.Token, v.SessionToken)
   371  		}
   372  	}
   373  }
   374  
   375  func TestAWSGetCredentials_shouldErrorWithInvalidEndpoint(t *testing.T) {
   376  	resetEnv := unsetEnv(t)
   377  	defer resetEnv()
   378  	// capture the test server's close method, to call after the test returns
   379  	ts := invalidAwsEnv(t)
   380  	defer ts()
   381  
   382  	creds, err := GetCredentials(&Config{})
   383  	if err != nil {
   384  		t.Fatalf("Error gettings creds: %s", err)
   385  	}
   386  	if creds == nil {
   387  		t.Fatal("Expected a static creds provider to be returned")
   388  	}
   389  
   390  	v, err := creds.Get()
   391  	if err == nil {
   392  		t.Fatal("Expected error returned when getting creds w/ invalid EC2 endpoint")
   393  	}
   394  
   395  	if v.ProviderName != "" {
   396  		t.Fatalf("Expected provider name to be empty, %q given", v.ProviderName)
   397  	}
   398  }
   399  
   400  func TestAWSGetCredentials_shouldIgnoreInvalidEndpoint(t *testing.T) {
   401  	resetEnv := unsetEnv(t)
   402  	defer resetEnv()
   403  	// capture the test server's close method, to call after the test returns
   404  	ts := invalidAwsEnv(t)
   405  	defer ts()
   406  
   407  	creds, err := GetCredentials(&Config{AccessKey: "accessKey", SecretKey: "secretKey"})
   408  	if err != nil {
   409  		t.Fatalf("Error gettings creds: %s", err)
   410  	}
   411  	v, err := creds.Get()
   412  	if err != nil {
   413  		t.Fatalf("Getting static credentials w/ invalid EC2 endpoint failed: %s", err)
   414  	}
   415  	if creds == nil {
   416  		t.Fatal("Expected a static creds provider to be returned")
   417  	}
   418  
   419  	if v.ProviderName != "StaticProvider" {
   420  		t.Fatalf("Expected provider name to be %q, %q given", "StaticProvider", v.ProviderName)
   421  	}
   422  
   423  	if v.AccessKeyID != "accessKey" {
   424  		t.Fatalf("Static Access Key %q doesn't match: %s", "accessKey", v.AccessKeyID)
   425  	}
   426  
   427  	if v.SecretAccessKey != "secretKey" {
   428  		t.Fatalf("Static Secret Key %q doesn't match: %s", "secretKey", v.SecretAccessKey)
   429  	}
   430  }
   431  
   432  func TestAWSGetCredentials_shouldCatchEC2RoleProvider(t *testing.T) {
   433  	resetEnv := unsetEnv(t)
   434  	defer resetEnv()
   435  	// capture the test server's close method, to call after the test returns
   436  	ts := awsEnv(t)
   437  	defer ts()
   438  
   439  	creds, err := GetCredentials(&Config{})
   440  	if err != nil {
   441  		t.Fatalf("Error gettings creds: %s", err)
   442  	}
   443  	if creds == nil {
   444  		t.Fatal("Expected an EC2Role creds provider to be returned")
   445  	}
   446  
   447  	v, err := creds.Get()
   448  	if err != nil {
   449  		t.Fatalf("Expected no error when getting creds: %s", err)
   450  	}
   451  	expectedProvider := "EC2RoleProvider"
   452  	if v.ProviderName != expectedProvider {
   453  		t.Fatalf("Expected provider name to be %q, %q given",
   454  			expectedProvider, v.ProviderName)
   455  	}
   456  }
   457  
   458  var credentialsFileContents = `[myprofile]
   459  aws_access_key_id = accesskey
   460  aws_secret_access_key = secretkey
   461  `
   462  
   463  func TestAWSGetCredentials_shouldBeShared(t *testing.T) {
   464  	file, err := ioutil.TempFile(os.TempDir(), "terraform_aws_cred")
   465  	if err != nil {
   466  		t.Fatalf("Error writing temporary credentials file: %s", err)
   467  	}
   468  	_, err = file.WriteString(credentialsFileContents)
   469  	if err != nil {
   470  		t.Fatalf("Error writing temporary credentials to file: %s", err)
   471  	}
   472  	err = file.Close()
   473  	if err != nil {
   474  		t.Fatalf("Error closing temporary credentials file: %s", err)
   475  	}
   476  
   477  	defer os.Remove(file.Name())
   478  
   479  	resetEnv := unsetEnv(t)
   480  	defer resetEnv()
   481  
   482  	if err := os.Setenv("AWS_PROFILE", "myprofile"); err != nil {
   483  		t.Fatalf("Error resetting env var AWS_PROFILE: %s", err)
   484  	}
   485  	if err := os.Setenv("AWS_SHARED_CREDENTIALS_FILE", file.Name()); err != nil {
   486  		t.Fatalf("Error resetting env var AWS_SHARED_CREDENTIALS_FILE: %s", err)
   487  	}
   488  
   489  	creds, err := GetCredentials(&Config{Profile: "myprofile", CredsFilename: file.Name()})
   490  	if err != nil {
   491  		t.Fatalf("Error gettings creds: %s", err)
   492  	}
   493  	if creds == nil {
   494  		t.Fatal("Expected a provider chain to be returned")
   495  	}
   496  
   497  	v, err := creds.Get()
   498  	if err != nil {
   499  		t.Fatalf("Error gettings creds: %s", err)
   500  	}
   501  
   502  	if v.AccessKeyID != "accesskey" {
   503  		t.Fatalf("AccessKeyID mismatch, expected (%s), got (%s)", "accesskey", v.AccessKeyID)
   504  	}
   505  
   506  	if v.SecretAccessKey != "secretkey" {
   507  		t.Fatalf("SecretAccessKey mismatch, expected (%s), got (%s)", "accesskey", v.AccessKeyID)
   508  	}
   509  }
   510  
   511  func TestAWSGetCredentials_shouldBeENV(t *testing.T) {
   512  	// need to set the environment variables to a dummy string, as we don't know
   513  	// what they may be at runtime without hardcoding here
   514  	s := "some_env"
   515  	resetEnv := setEnv(s, t)
   516  
   517  	defer resetEnv()
   518  
   519  	cfg := Config{}
   520  	creds, err := GetCredentials(&cfg)
   521  	if err != nil {
   522  		t.Fatalf("Error gettings creds: %s", err)
   523  	}
   524  	if creds == nil {
   525  		t.Fatalf("Expected a static creds provider to be returned")
   526  	}
   527  
   528  	v, err := creds.Get()
   529  	if err != nil {
   530  		t.Fatalf("Error gettings creds: %s", err)
   531  	}
   532  	if v.AccessKeyID != s {
   533  		t.Fatalf("AccessKeyID mismatch, expected: (%s), got (%s)", s, v.AccessKeyID)
   534  	}
   535  	if v.SecretAccessKey != s {
   536  		t.Fatalf("SecretAccessKey mismatch, expected: (%s), got (%s)", s, v.SecretAccessKey)
   537  	}
   538  	if v.SessionToken != s {
   539  		t.Fatalf("SessionToken mismatch, expected: (%s), got (%s)", s, v.SessionToken)
   540  	}
   541  }
   542  
   543  // unsetEnv unsets enviornment variables for testing a "clean slate" with no
   544  // credentials in the environment
   545  func unsetEnv(t *testing.T) func() {
   546  	// Grab any existing AWS keys and preserve. In some tests we'll unset these, so
   547  	// we need to have them and restore them after
   548  	e := getEnv()
   549  	if err := os.Unsetenv("AWS_ACCESS_KEY_ID"); err != nil {
   550  		t.Fatalf("Error unsetting env var AWS_ACCESS_KEY_ID: %s", err)
   551  	}
   552  	if err := os.Unsetenv("AWS_SECRET_ACCESS_KEY"); err != nil {
   553  		t.Fatalf("Error unsetting env var AWS_SECRET_ACCESS_KEY: %s", err)
   554  	}
   555  	if err := os.Unsetenv("AWS_SESSION_TOKEN"); err != nil {
   556  		t.Fatalf("Error unsetting env var AWS_SESSION_TOKEN: %s", err)
   557  	}
   558  	if err := os.Unsetenv("AWS_PROFILE"); err != nil {
   559  		t.Fatalf("Error unsetting env var AWS_PROFILE: %s", err)
   560  	}
   561  	if err := os.Unsetenv("AWS_SHARED_CREDENTIALS_FILE"); err != nil {
   562  		t.Fatalf("Error unsetting env var AWS_SHARED_CREDENTIALS_FILE: %s", err)
   563  	}
   564  
   565  	return func() {
   566  		// re-set all the envs we unset above
   567  		if err := os.Setenv("AWS_ACCESS_KEY_ID", e.Key); err != nil {
   568  			t.Fatalf("Error resetting env var AWS_ACCESS_KEY_ID: %s", err)
   569  		}
   570  		if err := os.Setenv("AWS_SECRET_ACCESS_KEY", e.Secret); err != nil {
   571  			t.Fatalf("Error resetting env var AWS_SECRET_ACCESS_KEY: %s", err)
   572  		}
   573  		if err := os.Setenv("AWS_SESSION_TOKEN", e.Token); err != nil {
   574  			t.Fatalf("Error resetting env var AWS_SESSION_TOKEN: %s", err)
   575  		}
   576  		if err := os.Setenv("AWS_PROFILE", e.Profile); err != nil {
   577  			t.Fatalf("Error resetting env var AWS_PROFILE: %s", err)
   578  		}
   579  		if err := os.Setenv("AWS_SHARED_CREDENTIALS_FILE", e.CredsFilename); err != nil {
   580  			t.Fatalf("Error resetting env var AWS_SHARED_CREDENTIALS_FILE: %s", err)
   581  		}
   582  	}
   583  }
   584  
   585  func setEnv(s string, t *testing.T) func() {
   586  	e := getEnv()
   587  	// Set all the envs to a dummy value
   588  	if err := os.Setenv("AWS_ACCESS_KEY_ID", s); err != nil {
   589  		t.Fatalf("Error setting env var AWS_ACCESS_KEY_ID: %s", err)
   590  	}
   591  	if err := os.Setenv("AWS_SECRET_ACCESS_KEY", s); err != nil {
   592  		t.Fatalf("Error setting env var AWS_SECRET_ACCESS_KEY: %s", err)
   593  	}
   594  	if err := os.Setenv("AWS_SESSION_TOKEN", s); err != nil {
   595  		t.Fatalf("Error setting env var AWS_SESSION_TOKEN: %s", err)
   596  	}
   597  	if err := os.Setenv("AWS_PROFILE", s); err != nil {
   598  		t.Fatalf("Error setting env var AWS_PROFILE: %s", err)
   599  	}
   600  	if err := os.Setenv("AWS_SHARED_CREDENTIALS_FILE", s); err != nil {
   601  		t.Fatalf("Error setting env var AWS_SHARED_CREDENTIALS_FLE: %s", err)
   602  	}
   603  
   604  	return func() {
   605  		// re-set all the envs we unset above
   606  		if err := os.Setenv("AWS_ACCESS_KEY_ID", e.Key); err != nil {
   607  			t.Fatalf("Error resetting env var AWS_ACCESS_KEY_ID: %s", err)
   608  		}
   609  		if err := os.Setenv("AWS_SECRET_ACCESS_KEY", e.Secret); err != nil {
   610  			t.Fatalf("Error resetting env var AWS_SECRET_ACCESS_KEY: %s", err)
   611  		}
   612  		if err := os.Setenv("AWS_SESSION_TOKEN", e.Token); err != nil {
   613  			t.Fatalf("Error resetting env var AWS_SESSION_TOKEN: %s", err)
   614  		}
   615  		if err := os.Setenv("AWS_PROFILE", e.Profile); err != nil {
   616  			t.Fatalf("Error setting env var AWS_PROFILE: %s", err)
   617  		}
   618  		if err := os.Setenv("AWS_SHARED_CREDENTIALS_FILE", s); err != nil {
   619  			t.Fatalf("Error setting env var AWS_SHARED_CREDENTIALS_FLE: %s", err)
   620  		}
   621  	}
   622  }
   623  
   624  // awsEnv establishes a httptest server to mock out the internal AWS Metadata
   625  // service. IAM Credentials are retrieved by the EC2RoleProvider, which makes
   626  // API calls to this internal URL. By replacing the server with a test server,
   627  // we can simulate an AWS environment
   628  func awsEnv(t *testing.T) func() {
   629  	routes := routes{}
   630  	if err := json.Unmarshal([]byte(metadataApiRoutes), &routes); err != nil {
   631  		t.Fatalf("Failed to unmarshal JSON in AWS ENV test: %s", err)
   632  	}
   633  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   634  		w.Header().Set("Content-Type", "text/plain")
   635  		w.Header().Add("Server", "MockEC2")
   636  		log.Printf("[DEBUG] Mocker server received request to %q", r.RequestURI)
   637  		for _, e := range routes.Endpoints {
   638  			if r.RequestURI == e.Uri {
   639  				fmt.Fprintln(w, e.Body)
   640  				w.WriteHeader(200)
   641  				return
   642  			}
   643  		}
   644  		w.WriteHeader(400)
   645  	}))
   646  
   647  	os.Setenv("AWS_METADATA_URL", ts.URL+"/latest")
   648  	return ts.Close
   649  }
   650  
   651  // invalidAwsEnv establishes a httptest server to simulate behaviour
   652  // when endpoint doesn't respond as expected
   653  func invalidAwsEnv(t *testing.T) func() {
   654  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   655  		w.WriteHeader(400)
   656  	}))
   657  
   658  	os.Setenv("AWS_METADATA_URL", ts.URL+"/latest")
   659  	return ts.Close
   660  }
   661  
   662  // getMockedAwsIamStsApi establishes a httptest server to simulate behaviour
   663  // of a real AWS' IAM & STS server
   664  func getMockedAwsIamStsApi(endpoints []*iamEndpoint) (func(), *iam.IAM, *sts.STS) {
   665  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   666  		buf := new(bytes.Buffer)
   667  		buf.ReadFrom(r.Body)
   668  		requestBody := buf.String()
   669  
   670  		log.Printf("[DEBUG] Received API %q request to %q: %s",
   671  			r.Method, r.RequestURI, requestBody)
   672  
   673  		for _, e := range endpoints {
   674  			if r.Method == e.Request.Method && r.RequestURI == e.Request.Uri && requestBody == e.Request.Body {
   675  				log.Printf("[DEBUG] Mock API responding with %d: %s", e.Response.StatusCode, e.Response.Body)
   676  
   677  				w.WriteHeader(e.Response.StatusCode)
   678  				w.Header().Set("Content-Type", e.Response.ContentType)
   679  				w.Header().Set("X-Amzn-Requestid", "1b206dd1-f9a8-11e5-becf-051c60f11c4a")
   680  				w.Header().Set("Date", time.Now().Format(time.RFC1123))
   681  
   682  				fmt.Fprintln(w, e.Response.Body)
   683  				return
   684  			}
   685  		}
   686  
   687  		w.WriteHeader(400)
   688  		return
   689  	}))
   690  
   691  	sc := awsCredentials.NewStaticCredentials("accessKey", "secretKey", "")
   692  
   693  	sess, err := session.NewSession(&aws.Config{
   694  		Credentials:                   sc,
   695  		Region:                        aws.String("us-east-1"),
   696  		Endpoint:                      aws.String(ts.URL),
   697  		CredentialsChainVerboseErrors: aws.Bool(true),
   698  	})
   699  	if err != nil {
   700  		panic(fmt.Sprintf("Error creating AWS Session: %s", err))
   701  	}
   702  	iamConn := iam.New(sess)
   703  	stsConn := sts.New(sess)
   704  	return ts.Close, iamConn, stsConn
   705  }
   706  
   707  func getEnv() *currentEnv {
   708  	// Grab any existing AWS keys and preserve. In some tests we'll unset these, so
   709  	// we need to have them and restore them after
   710  	return &currentEnv{
   711  		Key:           os.Getenv("AWS_ACCESS_KEY_ID"),
   712  		Secret:        os.Getenv("AWS_SECRET_ACCESS_KEY"),
   713  		Token:         os.Getenv("AWS_SESSION_TOKEN"),
   714  		Profile:       os.Getenv("AWS_PROFILE"),
   715  		CredsFilename: os.Getenv("AWS_SHARED_CREDENTIALS_FILE"),
   716  	}
   717  }
   718  
   719  // struct to preserve the current environment
   720  type currentEnv struct {
   721  	Key, Secret, Token, Profile, CredsFilename string
   722  }
   723  
   724  type routes struct {
   725  	Endpoints []*endpoint `json:"endpoints"`
   726  }
   727  type endpoint struct {
   728  	Uri  string `json:"uri"`
   729  	Body string `json:"body"`
   730  }
   731  
   732  const metadataApiRoutes = `
   733  {
   734    "endpoints": [
   735      {
   736        "uri": "/latest/meta-data/instance-id",
   737        "body": "mock-instance-id"
   738      },
   739      {
   740        "uri": "/latest/meta-data/iam/info",
   741        "body": "{\"Code\": \"Success\",\"LastUpdated\": \"2016-03-17T12:27:32Z\",\"InstanceProfileArn\": \"arn:aws:iam::123456789013:instance-profile/my-instance-profile\",\"InstanceProfileId\": \"AIPAABCDEFGHIJKLMN123\"}"
   742      },
   743      {
   744        "uri": "/latest/meta-data/iam/security-credentials",
   745        "body": "test_role"
   746      },
   747      {
   748        "uri": "/latest/meta-data/iam/security-credentials/test_role",
   749        "body": "{\"Code\":\"Success\",\"LastUpdated\":\"2015-12-11T17:17:25Z\",\"Type\":\"AWS-HMAC\",\"AccessKeyId\":\"somekey\",\"SecretAccessKey\":\"somesecret\",\"Token\":\"sometoken\"}"
   750      }
   751    ]
   752  }
   753  `
   754  
   755  type iamEndpoint struct {
   756  	Request  *iamRequest
   757  	Response *iamResponse
   758  }
   759  
   760  type iamRequest struct {
   761  	Method string
   762  	Uri    string
   763  	Body   string
   764  }
   765  
   766  type iamResponse struct {
   767  	StatusCode  int
   768  	Body        string
   769  	ContentType string
   770  }
   771  
   772  const iamResponse_GetUser_valid = `<GetUserResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/">
   773    <GetUserResult>
   774      <User>
   775        <UserId>AIDACKCEVSQ6C2EXAMPLE</UserId>
   776        <Path>/division_abc/subdivision_xyz/</Path>
   777        <UserName>Bob</UserName>
   778        <Arn>arn:aws:iam::123456789012:user/division_abc/subdivision_xyz/Bob</Arn>
   779        <CreateDate>2013-10-02T17:01:44Z</CreateDate>
   780        <PasswordLastUsed>2014-10-10T14:37:51Z</PasswordLastUsed>
   781      </User>
   782    </GetUserResult>
   783    <ResponseMetadata>
   784      <RequestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestId>
   785    </ResponseMetadata>
   786  </GetUserResponse>`
   787  
   788  const iamResponse_GetUser_unauthorized = `<ErrorResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/">
   789    <Error>
   790      <Type>Sender</Type>
   791      <Code>AccessDenied</Code>
   792      <Message>User: arn:aws:iam::123456789012:user/Bob is not authorized to perform: iam:GetUser on resource: arn:aws:iam::123456789012:user/Bob</Message>
   793    </Error>
   794    <RequestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestId>
   795  </ErrorResponse>`
   796  
   797  const stsResponse_GetCallerIdentity_valid = `<GetCallerIdentityResponse xmlns="https://sts.amazonaws.com/doc/2011-06-15/">
   798    <GetCallerIdentityResult>
   799     <Arn>arn:aws:iam::123456789012:user/Alice</Arn>
   800      <UserId>AKIAI44QH8DHBEXAMPLE</UserId>
   801      <Account>123456789012</Account>
   802    </GetCallerIdentityResult>
   803    <ResponseMetadata>
   804      <RequestId>01234567-89ab-cdef-0123-456789abcdef</RequestId>
   805    </ResponseMetadata>
   806  </GetCallerIdentityResponse>`
   807  
   808  const stsResponse_GetCallerIdentity_unauthorized = `<ErrorResponse xmlns="https://sts.amazonaws.com/doc/2011-06-15/">
   809    <Error>
   810      <Type>Sender</Type>
   811      <Code>AccessDenied</Code>
   812      <Message>User: arn:aws:iam::123456789012:user/Bob is not authorized to perform: sts:GetCallerIdentity</Message>
   813    </Error>
   814    <RequestId>01234567-89ab-cdef-0123-456789abcdef</RequestId>
   815  </ErrorResponse>`
   816  
   817  const iamResponse_GetUser_federatedFailure = `<ErrorResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/">
   818    <Error>
   819      <Type>Sender</Type>
   820      <Code>ValidationError</Code>
   821      <Message>Must specify userName when calling with non-User credentials</Message>
   822    </Error>
   823    <RequestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestId>
   824  </ErrorResponse>`
   825  
   826  const iamResponse_ListRoles_valid = `<ListRolesResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/">
   827    <ListRolesResult>
   828      <IsTruncated>true</IsTruncated>
   829      <Marker>AWceSSsKsazQ4IEplT9o4hURCzBs00iavlEvEXAMPLE</Marker>
   830      <Roles>
   831        <member>
   832          <Path>/</Path>
   833          <AssumeRolePolicyDocument>%7B%22Version%22%3A%222008-10-17%22%2C%22Statement%22%3A%5B%7B%22Sid%22%3A%22%22%2C%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22Service%22%3A%22ec2.amazonaws.com%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D</AssumeRolePolicyDocument>
   834          <RoleId>AROACKCEVSQ6C2EXAMPLE</RoleId>
   835          <RoleName>elasticbeanstalk-role</RoleName>
   836          <Arn>arn:aws:iam::123456789012:role/elasticbeanstalk-role</Arn>
   837          <CreateDate>2013-10-02T17:01:44Z</CreateDate>
   838        </member>
   839      </Roles>
   840    </ListRolesResult>
   841    <ResponseMetadata>
   842      <RequestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestId>
   843    </ResponseMetadata>
   844  </ListRolesResponse>`
   845  
   846  const iamResponse_ListRoles_unauthorized = `<ErrorResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/">
   847    <Error>
   848      <Type>Sender</Type>
   849      <Code>AccessDenied</Code>
   850      <Message>User: arn:aws:iam::123456789012:user/Bob is not authorized to perform: iam:ListRoles on resource: arn:aws:iam::123456789012:role/</Message>
   851    </Error>
   852    <RequestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestId>
   853  </ErrorResponse>`