...

Source file src/golang.org/x/oauth2/google/externalaccount/aws_test.go

Documentation: golang.org/x/oauth2/google/externalaccount

     1  // Copyright 2021 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package externalaccount
     6  
     7  import (
     8  	"context"
     9  	"encoding/json"
    10  	"errors"
    11  	"fmt"
    12  	"net/http"
    13  	"net/http/httptest"
    14  	neturl "net/url"
    15  	"reflect"
    16  	"strings"
    17  	"testing"
    18  	"time"
    19  )
    20  
    21  var defaultTime = time.Date(2011, 9, 9, 23, 36, 0, 0, time.UTC)
    22  var secondDefaultTime = time.Date(2020, 8, 11, 6, 55, 22, 0, time.UTC)
    23  
    24  type validateHeaders func(r *http.Request)
    25  
    26  func setTime(testTime time.Time) func() time.Time {
    27  	return func() time.Time {
    28  		return testTime
    29  	}
    30  }
    31  
    32  func setEnvironment(env map[string]string) func(string) string {
    33  	return func(key string) string {
    34  		return env[key]
    35  	}
    36  }
    37  
    38  var defaultRequestSigner = &awsRequestSigner{
    39  	RegionName: "us-east-1",
    40  	AwsSecurityCredentials: &AwsSecurityCredentials{
    41  		AccessKeyID:     "AKIDEXAMPLE",
    42  		SecretAccessKey: "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY",
    43  	},
    44  }
    45  
    46  const (
    47  	accessKeyID     = "ASIARD4OQDT6A77FR3CL"
    48  	secretAccessKey = "Y8AfSaucF37G4PpvfguKZ3/l7Id4uocLXxX0+VTx"
    49  	securityToken   = "IQoJb3JpZ2luX2VjEIz//////////wEaCXVzLWVhc3QtMiJGMEQCIH7MHX/Oy/OB8OlLQa9GrqU1B914+iMikqWQW7vPCKlgAiA/Lsv8Jcafn14owfxXn95FURZNKaaphj0ykpmS+Ki+CSq0AwhlEAAaDDA3NzA3MTM5MTk5NiIMx9sAeP1ovlMTMKLjKpEDwuJQg41/QUKx0laTZYjPlQvjwSqS3OB9P1KAXPWSLkliVMMqaHqelvMF/WO/glv3KwuTfQsavRNs3v5pcSEm4SPO3l7mCs7KrQUHwGP0neZhIKxEXy+Ls//1C/Bqt53NL+LSbaGv6RPHaX82laz2qElphg95aVLdYgIFY6JWV5fzyjgnhz0DQmy62/Vi8pNcM2/VnxeCQ8CC8dRDSt52ry2v+nc77vstuI9xV5k8mPtnaPoJDRANh0bjwY5Sdwkbp+mGRUJBAQRlNgHUJusefXQgVKBCiyJY4w3Csd8Bgj9IyDV+Azuy1jQqfFZWgP68LSz5bURyIjlWDQunO82stZ0BgplKKAa/KJHBPCp8Qi6i99uy7qh76FQAqgVTsnDuU6fGpHDcsDSGoCls2HgZjZFPeOj8mmRhFk1Xqvkbjuz8V1cJk54d3gIJvQt8gD2D6yJQZecnuGWd5K2e2HohvCc8Fc9kBl1300nUJPV+k4tr/A5R/0QfEKOZL1/k5lf1g9CREnrM8LVkGxCgdYMxLQow1uTL+QU67AHRRSp5PhhGX4Rek+01vdYSnJCMaPhSEgcLqDlQkhk6MPsyT91QMXcWmyO+cAZwUPwnRamFepuP4K8k2KVXs/LIJHLELwAZ0ekyaS7CptgOqS7uaSTFG3U+vzFZLEnGvWQ7y9IPNQZ+Dffgh4p3vF4J68y9049sI6Sr5d5wbKkcbm8hdCDHZcv4lnqohquPirLiFQ3q7B17V9krMPu3mz1cg4Ekgcrn/E09NTsxAqD8NcZ7C7ECom9r+X3zkDOxaajW6hu3Az8hGlyylDaMiFfRbBJpTIlxp7jfa7CxikNgNtEKLH9iCzvuSg2vhA=="
    50  )
    51  
    52  var requestSignerWithToken = &awsRequestSigner{
    53  	RegionName: "us-east-2",
    54  	AwsSecurityCredentials: &AwsSecurityCredentials{
    55  		AccessKeyID:     accessKeyID,
    56  		SecretAccessKey: secretAccessKey,
    57  		SessionToken:    securityToken,
    58  	},
    59  }
    60  
    61  func setDefaultTime(req *http.Request) {
    62  	// Don't use time.Format for this
    63  	// Our output signature expects this to be a Monday, even though Sept 9, 2011 is a Friday
    64  	req.Header.Add("date", "Mon, 09 Sep 2011 23:36:00 GMT")
    65  }
    66  
    67  func testRequestSigner(t *testing.T, rs *awsRequestSigner, input, expectedOutput *http.Request) {
    68  	t.Helper()
    69  
    70  	err := rs.SignRequest(input)
    71  	if err != nil {
    72  		t.Errorf("unexpected error: %q", err.Error())
    73  	}
    74  
    75  	if got, want := input.URL.String(), expectedOutput.URL.String(); !reflect.DeepEqual(got, want) {
    76  		t.Errorf("url = %q, want %q", got, want)
    77  	}
    78  	if got, want := input.Method, expectedOutput.Method; !reflect.DeepEqual(got, want) {
    79  		t.Errorf("method = %q, want %q", got, want)
    80  	}
    81  	for header := range expectedOutput.Header {
    82  		if got, want := input.Header[header], expectedOutput.Header[header]; !reflect.DeepEqual(got, want) {
    83  			t.Errorf("header[%q] = %q, want %q", header, got, want)
    84  		}
    85  	}
    86  }
    87  
    88  func TestAWSv4Signature_GetRequest(t *testing.T) {
    89  	input, _ := http.NewRequest("GET", "https://host.foo.com", nil)
    90  	setDefaultTime(input)
    91  
    92  	output, _ := http.NewRequest("GET", "https://host.foo.com", nil)
    93  	output.Header = http.Header{
    94  		"Host":          []string{"host.foo.com"},
    95  		"Date":          []string{"Mon, 09 Sep 2011 23:36:00 GMT"},
    96  		"Authorization": []string{"AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470"},
    97  	}
    98  
    99  	oldNow := now
   100  	defer func() { now = oldNow }()
   101  	now = setTime(defaultTime)
   102  
   103  	testRequestSigner(t, defaultRequestSigner, input, output)
   104  }
   105  
   106  func TestAWSv4Signature_GetRequestWithRelativePath(t *testing.T) {
   107  	input, _ := http.NewRequest("GET", "https://host.foo.com/foo/bar/../..", nil)
   108  	setDefaultTime(input)
   109  
   110  	output, _ := http.NewRequest("GET", "https://host.foo.com/foo/bar/../..", nil)
   111  	output.Header = http.Header{
   112  		"Host":          []string{"host.foo.com"},
   113  		"Date":          []string{"Mon, 09 Sep 2011 23:36:00 GMT"},
   114  		"Authorization": []string{"AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470"},
   115  	}
   116  
   117  	oldNow := now
   118  	defer func() { now = oldNow }()
   119  	now = setTime(defaultTime)
   120  
   121  	testRequestSigner(t, defaultRequestSigner, input, output)
   122  }
   123  
   124  func TestAWSv4Signature_GetRequestWithDotPath(t *testing.T) {
   125  	input, _ := http.NewRequest("GET", "https://host.foo.com/./", nil)
   126  	setDefaultTime(input)
   127  
   128  	output, _ := http.NewRequest("GET", "https://host.foo.com/./", nil)
   129  	output.Header = http.Header{
   130  		"Host":          []string{"host.foo.com"},
   131  		"Date":          []string{"Mon, 09 Sep 2011 23:36:00 GMT"},
   132  		"Authorization": []string{"AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470"},
   133  	}
   134  
   135  	oldNow := now
   136  	defer func() { now = oldNow }()
   137  	now = setTime(defaultTime)
   138  
   139  	testRequestSigner(t, defaultRequestSigner, input, output)
   140  }
   141  
   142  func TestAWSv4Signature_GetRequestWithPointlessDotPath(t *testing.T) {
   143  	input, _ := http.NewRequest("GET", "https://host.foo.com/./foo", nil)
   144  	setDefaultTime(input)
   145  
   146  	output, _ := http.NewRequest("GET", "https://host.foo.com/./foo", nil)
   147  	output.Header = http.Header{
   148  		"Host":          []string{"host.foo.com"},
   149  		"Date":          []string{"Mon, 09 Sep 2011 23:36:00 GMT"},
   150  		"Authorization": []string{"AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=910e4d6c9abafaf87898e1eb4c929135782ea25bb0279703146455745391e63a"},
   151  	}
   152  
   153  	oldNow := now
   154  	defer func() { now = oldNow }()
   155  	now = setTime(defaultTime)
   156  
   157  	testRequestSigner(t, defaultRequestSigner, input, output)
   158  }
   159  
   160  func TestAWSv4Signature_GetRequestWithUtf8Path(t *testing.T) {
   161  	input, _ := http.NewRequest("GET", "https://host.foo.com/%E1%88%B4", nil)
   162  	setDefaultTime(input)
   163  
   164  	output, _ := http.NewRequest("GET", "https://host.foo.com/%E1%88%B4", nil)
   165  	output.Header = http.Header{
   166  		"Host":          []string{"host.foo.com"},
   167  		"Date":          []string{"Mon, 09 Sep 2011 23:36:00 GMT"},
   168  		"Authorization": []string{"AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=8d6634c189aa8c75c2e51e106b6b5121bed103fdb351f7d7d4381c738823af74"},
   169  	}
   170  
   171  	oldNow := now
   172  	defer func() { now = oldNow }()
   173  	now = setTime(defaultTime)
   174  
   175  	testRequestSigner(t, defaultRequestSigner, input, output)
   176  }
   177  
   178  func TestAWSv4Signature_GetRequestWithDuplicateQuery(t *testing.T) {
   179  	input, _ := http.NewRequest("GET", "https://host.foo.com/?foo=Zoo&foo=aha", nil)
   180  	setDefaultTime(input)
   181  
   182  	output, _ := http.NewRequest("GET", "https://host.foo.com/?foo=Zoo&foo=aha", nil)
   183  	output.Header = http.Header{
   184  		"Host":          []string{"host.foo.com"},
   185  		"Date":          []string{"Mon, 09 Sep 2011 23:36:00 GMT"},
   186  		"Authorization": []string{"AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=be7148d34ebccdc6423b19085378aa0bee970bdc61d144bd1a8c48c33079ab09"},
   187  	}
   188  
   189  	oldNow := now
   190  	defer func() { now = oldNow }()
   191  	now = setTime(defaultTime)
   192  
   193  	testRequestSigner(t, defaultRequestSigner, input, output)
   194  }
   195  
   196  func TestAWSv4Signature_GetRequestWithMisorderedQuery(t *testing.T) {
   197  	input, _ := http.NewRequest("GET", "https://host.foo.com/?foo=b&foo=a", nil)
   198  	setDefaultTime(input)
   199  
   200  	output, _ := http.NewRequest("GET", "https://host.foo.com/?foo=b&foo=a", nil)
   201  	output.Header = http.Header{
   202  		"Host":          []string{"host.foo.com"},
   203  		"Date":          []string{"Mon, 09 Sep 2011 23:36:00 GMT"},
   204  		"Authorization": []string{"AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=feb926e49e382bec75c9d7dcb2a1b6dc8aa50ca43c25d2bc51143768c0875acc"},
   205  	}
   206  
   207  	oldNow := now
   208  	defer func() { now = oldNow }()
   209  	now = setTime(defaultTime)
   210  
   211  	testRequestSigner(t, defaultRequestSigner, input, output)
   212  }
   213  
   214  func TestAWSv4Signature_GetRequestWithUtf8Query(t *testing.T) {
   215  	input, _ := http.NewRequest("GET", "https://host.foo.com/?ሴ=bar", nil)
   216  	setDefaultTime(input)
   217  
   218  	output, _ := http.NewRequest("GET", "https://host.foo.com/?ሴ=bar", nil)
   219  	output.Header = http.Header{
   220  		"Host":          []string{"host.foo.com"},
   221  		"Date":          []string{"Mon, 09 Sep 2011 23:36:00 GMT"},
   222  		"Authorization": []string{"AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=6fb359e9a05394cc7074e0feb42573a2601abc0c869a953e8c5c12e4e01f1a8c"},
   223  	}
   224  
   225  	oldNow := now
   226  	defer func() { now = oldNow }()
   227  	now = setTime(defaultTime)
   228  
   229  	testRequestSigner(t, defaultRequestSigner, input, output)
   230  }
   231  
   232  func TestAWSv4Signature_PostRequest(t *testing.T) {
   233  	input, _ := http.NewRequest("POST", "https://host.foo.com/", nil)
   234  	setDefaultTime(input)
   235  	input.Header.Add("ZOO", "zoobar")
   236  
   237  	output, _ := http.NewRequest("POST", "https://host.foo.com/", nil)
   238  	output.Header = http.Header{
   239  		"Host":          []string{"host.foo.com"},
   240  		"Date":          []string{"Mon, 09 Sep 2011 23:36:00 GMT"},
   241  		"Authorization": []string{"AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host;zoo, Signature=b7a95a52518abbca0964a999a880429ab734f35ebbf1235bd79a5de87756dc4a"},
   242  		"Zoo":           []string{"zoobar"},
   243  	}
   244  
   245  	oldNow := now
   246  	defer func() { now = oldNow }()
   247  	now = setTime(defaultTime)
   248  
   249  	testRequestSigner(t, defaultRequestSigner, input, output)
   250  }
   251  
   252  func TestAWSv4Signature_PostRequestWithCapitalizedHeaderValue(t *testing.T) {
   253  	input, _ := http.NewRequest("POST", "https://host.foo.com/", nil)
   254  	setDefaultTime(input)
   255  	input.Header.Add("zoo", "ZOOBAR")
   256  
   257  	output, _ := http.NewRequest("POST", "https://host.foo.com/", nil)
   258  	output.Header = http.Header{
   259  		"Host":          []string{"host.foo.com"},
   260  		"Date":          []string{"Mon, 09 Sep 2011 23:36:00 GMT"},
   261  		"Authorization": []string{"AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host;zoo, Signature=273313af9d0c265c531e11db70bbd653f3ba074c1009239e8559d3987039cad7"},
   262  		"Zoo":           []string{"ZOOBAR"},
   263  	}
   264  
   265  	oldNow := now
   266  	defer func() { now = oldNow }()
   267  	now = setTime(defaultTime)
   268  
   269  	testRequestSigner(t, defaultRequestSigner, input, output)
   270  }
   271  
   272  func TestAWSv4Signature_PostRequestPhfft(t *testing.T) {
   273  	input, _ := http.NewRequest("POST", "https://host.foo.com/", nil)
   274  	setDefaultTime(input)
   275  	input.Header.Add("p", "phfft")
   276  
   277  	output, _ := http.NewRequest("POST", "https://host.foo.com/", nil)
   278  	output.Header = http.Header{
   279  		"Host":          []string{"host.foo.com"},
   280  		"Date":          []string{"Mon, 09 Sep 2011 23:36:00 GMT"},
   281  		"Authorization": []string{"AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host;p, Signature=debf546796015d6f6ded8626f5ce98597c33b47b9164cf6b17b4642036fcb592"},
   282  		"P":             []string{"phfft"},
   283  	}
   284  
   285  	oldNow := now
   286  	defer func() { now = oldNow }()
   287  	now = setTime(defaultTime)
   288  
   289  	testRequestSigner(t, defaultRequestSigner, input, output)
   290  }
   291  
   292  func TestAWSv4Signature_PostRequestWithBody(t *testing.T) {
   293  	input, _ := http.NewRequest("POST", "https://host.foo.com/", strings.NewReader("foo=bar"))
   294  	setDefaultTime(input)
   295  	input.Header.Add("Content-Type", "application/x-www-form-urlencoded")
   296  
   297  	output, _ := http.NewRequest("POST", "https://host.foo.com/", nil)
   298  	output.Header = http.Header{
   299  		"Host":          []string{"host.foo.com"},
   300  		"Date":          []string{"Mon, 09 Sep 2011 23:36:00 GMT"},
   301  		"Content-Type":  []string{"application/x-www-form-urlencoded"},
   302  		"Authorization": []string{"AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=content-type;date;host, Signature=5a15b22cf462f047318703b92e6f4f38884e4a7ab7b1d6426ca46a8bd1c26cbc"},
   303  	}
   304  
   305  	oldNow := now
   306  	defer func() { now = oldNow }()
   307  	now = setTime(defaultTime)
   308  
   309  	testRequestSigner(t, defaultRequestSigner, input, output)
   310  }
   311  
   312  func TestAWSv4Signature_PostRequestWithQueryString(t *testing.T) {
   313  	input, _ := http.NewRequest("POST", "https://host.foo.com/?foo=bar", nil)
   314  	setDefaultTime(input)
   315  
   316  	output, _ := http.NewRequest("POST", "https://host.foo.com/?foo=bar", nil)
   317  	output.Header = http.Header{
   318  		"Host":          []string{"host.foo.com"},
   319  		"Date":          []string{"Mon, 09 Sep 2011 23:36:00 GMT"},
   320  		"Authorization": []string{"AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b6e3b79003ce0743a491606ba1035a804593b0efb1e20a11cba83f8c25a57a92"},
   321  	}
   322  
   323  	oldNow := now
   324  	defer func() { now = oldNow }()
   325  	now = setTime(defaultTime)
   326  
   327  	testRequestSigner(t, defaultRequestSigner, input, output)
   328  }
   329  
   330  func TestAWSv4Signature_GetRequestWithSecurityToken(t *testing.T) {
   331  	input, _ := http.NewRequest("GET", "https://ec2.us-east-2.amazonaws.com?Action=DescribeRegions&Version=2013-10-15", nil)
   332  
   333  	output, _ := http.NewRequest("GET", "https://ec2.us-east-2.amazonaws.com?Action=DescribeRegions&Version=2013-10-15", nil)
   334  	output.Header = http.Header{
   335  		"Host":                 []string{"ec2.us-east-2.amazonaws.com"},
   336  		"Authorization":        []string{"AWS4-HMAC-SHA256 Credential=" + accessKeyID + "/20200811/us-east-2/ec2/aws4_request, SignedHeaders=host;x-amz-date;x-amz-security-token, Signature=631ea80cddfaa545fdadb120dc92c9f18166e38a5c47b50fab9fce476e022855"},
   337  		"X-Amz-Date":           []string{"20200811T065522Z"},
   338  		"X-Amz-Security-Token": []string{securityToken},
   339  	}
   340  
   341  	oldNow := now
   342  	defer func() { now = oldNow }()
   343  	now = setTime(secondDefaultTime)
   344  
   345  	testRequestSigner(t, requestSignerWithToken, input, output)
   346  }
   347  
   348  func TestAWSv4Signature_PostRequestWithSecurityToken(t *testing.T) {
   349  	input, _ := http.NewRequest("POST", "https://sts.us-east-2.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15", nil)
   350  
   351  	output, _ := http.NewRequest("POST", "https://sts.us-east-2.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15", nil)
   352  	output.Header = http.Header{
   353  		"Authorization":        []string{"AWS4-HMAC-SHA256 Credential=" + accessKeyID + "/20200811/us-east-2/sts/aws4_request, SignedHeaders=host;x-amz-date;x-amz-security-token, Signature=73452984e4a880ffdc5c392355733ec3f5ba310d5e0609a89244440cadfe7a7a"},
   354  		"Host":                 []string{"sts.us-east-2.amazonaws.com"},
   355  		"X-Amz-Date":           []string{"20200811T065522Z"},
   356  		"X-Amz-Security-Token": []string{securityToken},
   357  	}
   358  
   359  	oldNow := now
   360  	defer func() { now = oldNow }()
   361  	now = setTime(secondDefaultTime)
   362  
   363  	testRequestSigner(t, requestSignerWithToken, input, output)
   364  }
   365  
   366  func TestAWSv4Signature_PostRequestWithSecurityTokenAndAdditionalHeaders(t *testing.T) {
   367  	requestParams := "{\"KeySchema\":[{\"KeyType\":\"HASH\",\"AttributeName\":\"Id\"}],\"TableName\":\"TestTable\",\"AttributeDefinitions\":[{\"AttributeName\":\"Id\",\"AttributeType\":\"S\"}],\"ProvisionedThroughput\":{\"WriteCapacityUnits\":5,\"ReadCapacityUnits\":5}}"
   368  	input, _ := http.NewRequest("POST", "https://dynamodb.us-east-2.amazonaws.com/", strings.NewReader(requestParams))
   369  	input.Header.Add("Content-Type", "application/x-amz-json-1.0")
   370  	input.Header.Add("x-amz-target", "DynamoDB_20120810.CreateTable")
   371  
   372  	output, _ := http.NewRequest("POST", "https://dynamodb.us-east-2.amazonaws.com/", strings.NewReader(requestParams))
   373  	output.Header = http.Header{
   374  		"Authorization":        []string{"AWS4-HMAC-SHA256 Credential=" + accessKeyID + "/20200811/us-east-2/dynamodb/aws4_request, SignedHeaders=content-type;host;x-amz-date;x-amz-security-token;x-amz-target, Signature=fdaa5b9cc9c86b80fe61eaf504141c0b3523780349120f2bd8145448456e0385"},
   375  		"Host":                 []string{"dynamodb.us-east-2.amazonaws.com"},
   376  		"X-Amz-Date":           []string{"20200811T065522Z"},
   377  		"Content-Type":         []string{"application/x-amz-json-1.0"},
   378  		"X-Amz-Target":         []string{"DynamoDB_20120810.CreateTable"},
   379  		"X-Amz-Security-Token": []string{securityToken},
   380  	}
   381  
   382  	oldNow := now
   383  	defer func() { now = oldNow }()
   384  	now = setTime(secondDefaultTime)
   385  
   386  	testRequestSigner(t, requestSignerWithToken, input, output)
   387  }
   388  
   389  func TestAWSv4Signature_PostRequestWithAmzDateButNoSecurityToken(t *testing.T) {
   390  	var requestSigner = &awsRequestSigner{
   391  		RegionName: "us-east-2",
   392  		AwsSecurityCredentials: &AwsSecurityCredentials{
   393  			AccessKeyID:     accessKeyID,
   394  			SecretAccessKey: secretAccessKey,
   395  		},
   396  	}
   397  
   398  	input, _ := http.NewRequest("POST", "https://sts.us-east-2.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15", nil)
   399  
   400  	output, _ := http.NewRequest("POST", "https://sts.us-east-2.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15", nil)
   401  	output.Header = http.Header{
   402  		"Authorization": []string{"AWS4-HMAC-SHA256 Credential=" + accessKeyID + "/20200811/us-east-2/sts/aws4_request, SignedHeaders=host;x-amz-date, Signature=d095ba304919cd0d5570ba8a3787884ee78b860f268ed040ba23831d55536d56"},
   403  		"Host":          []string{"sts.us-east-2.amazonaws.com"},
   404  		"X-Amz-Date":    []string{"20200811T065522Z"},
   405  	}
   406  
   407  	oldNow := now
   408  	defer func() { now = oldNow }()
   409  	now = setTime(secondDefaultTime)
   410  
   411  	testRequestSigner(t, requestSigner, input, output)
   412  }
   413  
   414  type testAwsServer struct {
   415  	url                         string
   416  	securityCredentialURL       string
   417  	regionURL                   string
   418  	regionalCredVerificationURL string
   419  	imdsv2SessionTokenUrl       string
   420  
   421  	Credentials map[string]string
   422  
   423  	WriteRolename            func(http.ResponseWriter, *http.Request)
   424  	WriteSecurityCredentials func(http.ResponseWriter, *http.Request)
   425  	WriteRegion              func(http.ResponseWriter, *http.Request)
   426  	WriteIMDSv2SessionToken  func(http.ResponseWriter, *http.Request)
   427  }
   428  
   429  func createAwsTestServer(url, regionURL, regionalCredVerificationURL, imdsv2SessionTokenUrl string, rolename, region string, credentials map[string]string, imdsv2SessionToken string, validateHeaders validateHeaders) *testAwsServer {
   430  	server := &testAwsServer{
   431  		url:                         url,
   432  		securityCredentialURL:       fmt.Sprintf("%s/%s", url, rolename),
   433  		regionURL:                   regionURL,
   434  		regionalCredVerificationURL: regionalCredVerificationURL,
   435  		imdsv2SessionTokenUrl:       imdsv2SessionTokenUrl,
   436  		Credentials:                 credentials,
   437  		WriteRolename: func(w http.ResponseWriter, r *http.Request) {
   438  			validateHeaders(r)
   439  			w.Write([]byte(rolename))
   440  		},
   441  		WriteRegion: func(w http.ResponseWriter, r *http.Request) {
   442  			validateHeaders(r)
   443  			w.Write([]byte(region))
   444  		},
   445  		WriteIMDSv2SessionToken: func(w http.ResponseWriter, r *http.Request) {
   446  			validateHeaders(r)
   447  			w.Write([]byte(imdsv2SessionToken))
   448  		},
   449  	}
   450  
   451  	server.WriteSecurityCredentials = func(w http.ResponseWriter, r *http.Request) {
   452  		validateHeaders(r)
   453  		jsonCredentials, _ := json.Marshal(server.Credentials)
   454  		w.Write(jsonCredentials)
   455  	}
   456  
   457  	return server
   458  }
   459  
   460  func createDefaultAwsTestServer() *testAwsServer {
   461  	return createAwsTestServer(
   462  		"/latest/meta-data/iam/security-credentials",
   463  		"/latest/meta-data/placement/availability-zone",
   464  		"https://sts.{region}.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15",
   465  		"",
   466  		"gcp-aws-role",
   467  		"us-east-2b",
   468  		map[string]string{
   469  			"SecretAccessKey": secretAccessKey,
   470  			"AccessKeyId":     accessKeyID,
   471  			"Token":           securityToken,
   472  		},
   473  		"",
   474  		noHeaderValidation,
   475  	)
   476  }
   477  
   478  func createDefaultAwsTestServerWithImdsv2(t *testing.T) *testAwsServer {
   479  	validateSessionTokenHeaders := func(r *http.Request) {
   480  		if r.URL.Path == "/latest/api/token" {
   481  			headerValue := r.Header.Get(awsIMDSv2SessionTtlHeader)
   482  			if headerValue != awsIMDSv2SessionTtl {
   483  				t.Errorf("%q = \n%q\n want \n%q", awsIMDSv2SessionTtlHeader, headerValue, awsIMDSv2SessionTtl)
   484  			}
   485  		} else {
   486  			headerValue := r.Header.Get(awsIMDSv2SessionTokenHeader)
   487  			if headerValue != "sessiontoken" {
   488  				t.Errorf("%q = \n%q\n want \n%q", awsIMDSv2SessionTokenHeader, headerValue, "sessiontoken")
   489  			}
   490  		}
   491  	}
   492  
   493  	return createAwsTestServer(
   494  		"/latest/meta-data/iam/security-credentials",
   495  		"/latest/meta-data/placement/availability-zone",
   496  		"https://sts.{region}.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15",
   497  		"/latest/api/token",
   498  		"gcp-aws-role",
   499  		"us-east-2b",
   500  		map[string]string{
   501  			"SecretAccessKey": secretAccessKey,
   502  			"AccessKeyId":     accessKeyID,
   503  			"Token":           securityToken,
   504  		},
   505  		"sessiontoken",
   506  		validateSessionTokenHeaders,
   507  	)
   508  }
   509  
   510  func (server *testAwsServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
   511  	switch p := r.URL.Path; p {
   512  	case server.url:
   513  		server.WriteRolename(w, r)
   514  	case server.securityCredentialURL:
   515  		server.WriteSecurityCredentials(w, r)
   516  	case server.regionURL:
   517  		server.WriteRegion(w, r)
   518  	case server.imdsv2SessionTokenUrl:
   519  		server.WriteIMDSv2SessionToken(w, r)
   520  	}
   521  }
   522  
   523  func notFound(w http.ResponseWriter, r *http.Request) {
   524  	w.WriteHeader(404)
   525  	w.Write([]byte("Not Found"))
   526  }
   527  
   528  func noHeaderValidation(r *http.Request) {}
   529  
   530  func (server *testAwsServer) getCredentialSource(url string) *CredentialSource {
   531  	return &CredentialSource{
   532  		EnvironmentID:               "aws1",
   533  		URL:                         url + server.url,
   534  		RegionURL:                   url + server.regionURL,
   535  		RegionalCredVerificationURL: server.regionalCredVerificationURL,
   536  		IMDSv2SessionTokenURL:       url + server.imdsv2SessionTokenUrl,
   537  	}
   538  }
   539  
   540  func getExpectedSubjectToken(url, region, accessKeyID, secretAccessKey, securityToken string) string {
   541  	req, _ := http.NewRequest("POST", url, nil)
   542  	req.Header.Add("x-goog-cloud-target-resource", testFileConfig.Audience)
   543  	signer := &awsRequestSigner{
   544  		RegionName: region,
   545  		AwsSecurityCredentials: &AwsSecurityCredentials{
   546  			AccessKeyID:     accessKeyID,
   547  			SecretAccessKey: secretAccessKey,
   548  			SessionToken:    securityToken,
   549  		},
   550  	}
   551  	signer.SignRequest(req)
   552  
   553  	result := awsRequest{
   554  		URL:    url,
   555  		Method: "POST",
   556  		Headers: []awsRequestHeader{
   557  			{
   558  				Key:   "Authorization",
   559  				Value: req.Header.Get("Authorization"),
   560  			}, {
   561  				Key:   "Host",
   562  				Value: req.Header.Get("Host"),
   563  			}, {
   564  				Key:   "X-Amz-Date",
   565  				Value: req.Header.Get("X-Amz-Date"),
   566  			},
   567  		},
   568  	}
   569  
   570  	if securityToken != "" {
   571  		result.Headers = append(result.Headers, awsRequestHeader{
   572  			Key:   "X-Amz-Security-Token",
   573  			Value: securityToken,
   574  		})
   575  	}
   576  
   577  	result.Headers = append(result.Headers, awsRequestHeader{
   578  		Key:   "X-Goog-Cloud-Target-Resource",
   579  		Value: testFileConfig.Audience,
   580  	})
   581  
   582  	str, _ := json.Marshal(result)
   583  	return neturl.QueryEscape(string(str))
   584  }
   585  
   586  func TestAWSCredential_BasicRequest(t *testing.T) {
   587  	server := createDefaultAwsTestServer()
   588  	ts := httptest.NewServer(server)
   589  
   590  	tfc := testFileConfig
   591  	tfc.CredentialSource = server.getCredentialSource(ts.URL)
   592  	oldGetenv := getenv
   593  	oldNow := now
   594  	defer func() {
   595  		getenv = oldGetenv
   596  		now = oldNow
   597  	}()
   598  	getenv = setEnvironment(map[string]string{})
   599  	now = setTime(defaultTime)
   600  
   601  	base, err := tfc.parse(context.Background())
   602  	if err != nil {
   603  		t.Fatalf("parse() failed %v", err)
   604  	}
   605  
   606  	out, err := base.subjectToken()
   607  	if err != nil {
   608  		t.Fatalf("retrieveSubjectToken() failed: %v", err)
   609  	}
   610  
   611  	expected := getExpectedSubjectToken(
   612  		"https://sts.us-east-2.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15",
   613  		"us-east-2",
   614  		accessKeyID,
   615  		secretAccessKey,
   616  		securityToken,
   617  	)
   618  
   619  	if got, want := out, expected; !reflect.DeepEqual(got, want) {
   620  		t.Errorf("subjectToken = \n%q\n want \n%q", got, want)
   621  	}
   622  }
   623  
   624  func TestAWSCredential_IMDSv2(t *testing.T) {
   625  	server := createDefaultAwsTestServerWithImdsv2(t)
   626  	ts := httptest.NewServer(server)
   627  
   628  	tfc := testFileConfig
   629  	tfc.CredentialSource = server.getCredentialSource(ts.URL)
   630  
   631  	oldGetenv := getenv
   632  	oldNow := now
   633  	defer func() {
   634  		getenv = oldGetenv
   635  		now = oldNow
   636  	}()
   637  	getenv = setEnvironment(map[string]string{})
   638  	now = setTime(defaultTime)
   639  
   640  	base, err := tfc.parse(context.Background())
   641  	if err != nil {
   642  		t.Fatalf("parse() failed %v", err)
   643  	}
   644  
   645  	out, err := base.subjectToken()
   646  	if err != nil {
   647  		t.Fatalf("retrieveSubjectToken() failed: %v", err)
   648  	}
   649  
   650  	expected := getExpectedSubjectToken(
   651  		"https://sts.us-east-2.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15",
   652  		"us-east-2",
   653  		accessKeyID,
   654  		secretAccessKey,
   655  		securityToken,
   656  	)
   657  
   658  	if got, want := out, expected; !reflect.DeepEqual(got, want) {
   659  		t.Errorf("subjectToken = \n%q\n want \n%q", got, want)
   660  	}
   661  }
   662  
   663  func TestAWSCredential_BasicRequestWithoutSecurityToken(t *testing.T) {
   664  	server := createDefaultAwsTestServer()
   665  	ts := httptest.NewServer(server)
   666  	delete(server.Credentials, "Token")
   667  
   668  	tfc := testFileConfig
   669  	tfc.CredentialSource = server.getCredentialSource(ts.URL)
   670  
   671  	oldGetenv := getenv
   672  	oldNow := now
   673  	defer func() {
   674  		getenv = oldGetenv
   675  		now = oldNow
   676  	}()
   677  	getenv = setEnvironment(map[string]string{})
   678  	now = setTime(defaultTime)
   679  
   680  	base, err := tfc.parse(context.Background())
   681  	if err != nil {
   682  		t.Fatalf("parse() failed %v", err)
   683  	}
   684  
   685  	out, err := base.subjectToken()
   686  	if err != nil {
   687  		t.Fatalf("retrieveSubjectToken() failed: %v", err)
   688  	}
   689  
   690  	expected := getExpectedSubjectToken(
   691  		"https://sts.us-east-2.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15",
   692  		"us-east-2",
   693  		accessKeyID,
   694  		secretAccessKey,
   695  		"",
   696  	)
   697  
   698  	if got, want := out, expected; !reflect.DeepEqual(got, want) {
   699  		t.Errorf("subjectToken = \n%q\n want \n%q", got, want)
   700  	}
   701  }
   702  
   703  func TestAWSCredential_BasicRequestWithEnv(t *testing.T) {
   704  	server := createDefaultAwsTestServer()
   705  	ts := httptest.NewServer(server)
   706  
   707  	tfc := testFileConfig
   708  	tfc.CredentialSource = server.getCredentialSource(ts.URL)
   709  
   710  	oldGetenv := getenv
   711  	oldNow := now
   712  	defer func() {
   713  		getenv = oldGetenv
   714  		now = oldNow
   715  	}()
   716  	getenv = setEnvironment(map[string]string{
   717  		"AWS_ACCESS_KEY_ID":     "AKIDEXAMPLE",
   718  		"AWS_SECRET_ACCESS_KEY": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY",
   719  		"AWS_REGION":            "us-west-1",
   720  	})
   721  	now = setTime(defaultTime)
   722  
   723  	base, err := tfc.parse(context.Background())
   724  	if err != nil {
   725  		t.Fatalf("parse() failed %v", err)
   726  	}
   727  
   728  	out, err := base.subjectToken()
   729  	if err != nil {
   730  		t.Fatalf("retrieveSubjectToken() failed: %v", err)
   731  	}
   732  
   733  	expected := getExpectedSubjectToken(
   734  		"https://sts.us-west-1.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15",
   735  		"us-west-1",
   736  		"AKIDEXAMPLE",
   737  		"wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY",
   738  		"",
   739  	)
   740  
   741  	if got, want := out, expected; !reflect.DeepEqual(got, want) {
   742  		t.Errorf("subjectToken = \n%q\n want \n%q", got, want)
   743  	}
   744  }
   745  
   746  func TestAWSCredential_BasicRequestWithDefaultEnv(t *testing.T) {
   747  	server := createDefaultAwsTestServer()
   748  	ts := httptest.NewServer(server)
   749  
   750  	tfc := testFileConfig
   751  	tfc.CredentialSource = server.getCredentialSource(ts.URL)
   752  
   753  	oldGetenv := getenv
   754  	oldNow := now
   755  	defer func() {
   756  		getenv = oldGetenv
   757  		now = oldNow
   758  	}()
   759  	getenv = setEnvironment(map[string]string{
   760  		"AWS_ACCESS_KEY_ID":     "AKIDEXAMPLE",
   761  		"AWS_SECRET_ACCESS_KEY": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY",
   762  		"AWS_REGION":            "us-west-1",
   763  	})
   764  	now = setTime(defaultTime)
   765  
   766  	base, err := tfc.parse(context.Background())
   767  	if err != nil {
   768  		t.Fatalf("parse() failed %v", err)
   769  	}
   770  
   771  	out, err := base.subjectToken()
   772  	if err != nil {
   773  		t.Fatalf("retrieveSubjectToken() failed: %v", err)
   774  	}
   775  	expected := getExpectedSubjectToken(
   776  		"https://sts.us-west-1.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15",
   777  		"us-west-1",
   778  		"AKIDEXAMPLE",
   779  		"wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY",
   780  		"",
   781  	)
   782  
   783  	if got, want := out, expected; !reflect.DeepEqual(got, want) {
   784  		t.Errorf("subjectToken = \n%q\n want \n%q", got, want)
   785  	}
   786  }
   787  
   788  func TestAWSCredential_BasicRequestWithTwoRegions(t *testing.T) {
   789  	server := createDefaultAwsTestServer()
   790  	ts := httptest.NewServer(server)
   791  
   792  	tfc := testFileConfig
   793  	tfc.CredentialSource = server.getCredentialSource(ts.URL)
   794  
   795  	oldGetenv := getenv
   796  	oldNow := now
   797  	defer func() {
   798  		getenv = oldGetenv
   799  		now = oldNow
   800  	}()
   801  	getenv = setEnvironment(map[string]string{
   802  		"AWS_ACCESS_KEY_ID":     "AKIDEXAMPLE",
   803  		"AWS_SECRET_ACCESS_KEY": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY",
   804  		"AWS_REGION":            "us-west-1",
   805  		"AWS_DEFAULT_REGION":    "us-east-1",
   806  	})
   807  	now = setTime(defaultTime)
   808  
   809  	base, err := tfc.parse(context.Background())
   810  	if err != nil {
   811  		t.Fatalf("parse() failed %v", err)
   812  	}
   813  
   814  	out, err := base.subjectToken()
   815  	if err != nil {
   816  		t.Fatalf("retrieveSubjectToken() failed: %v", err)
   817  	}
   818  	expected := getExpectedSubjectToken(
   819  		"https://sts.us-west-1.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15",
   820  		"us-west-1",
   821  		"AKIDEXAMPLE",
   822  		"wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY",
   823  		"",
   824  	)
   825  
   826  	if got, want := out, expected; !reflect.DeepEqual(got, want) {
   827  		t.Errorf("subjectToken = \n%q\n want \n%q", got, want)
   828  	}
   829  }
   830  
   831  func TestAWSCredential_RequestWithBadVersion(t *testing.T) {
   832  	server := createDefaultAwsTestServer()
   833  	ts := httptest.NewServer(server)
   834  
   835  	tfc := testFileConfig
   836  	tfc.CredentialSource = server.getCredentialSource(ts.URL)
   837  	tfc.CredentialSource.EnvironmentID = "aws3"
   838  
   839  	oldGetenv := getenv
   840  	defer func() {
   841  		getenv = oldGetenv
   842  	}()
   843  	getenv = setEnvironment(map[string]string{})
   844  
   845  	_, err := tfc.parse(context.Background())
   846  	if err == nil {
   847  		t.Fatalf("parse() should have failed")
   848  	}
   849  	if got, want := err.Error(), "oauth2/google/externalaccount: aws version '3' is not supported in the current build"; !reflect.DeepEqual(got, want) {
   850  		t.Errorf("subjectToken = %q, want %q", got, want)
   851  	}
   852  }
   853  
   854  func TestAWSCredential_RequestWithNoRegionURL(t *testing.T) {
   855  	server := createDefaultAwsTestServer()
   856  	ts := httptest.NewServer(server)
   857  
   858  	tfc := testFileConfig
   859  	tfc.CredentialSource = server.getCredentialSource(ts.URL)
   860  	tfc.CredentialSource.RegionURL = ""
   861  
   862  	oldGetenv := getenv
   863  	defer func() {
   864  		getenv = oldGetenv
   865  	}()
   866  	getenv = setEnvironment(map[string]string{})
   867  
   868  	base, err := tfc.parse(context.Background())
   869  	if err != nil {
   870  		t.Fatalf("parse() failed %v", err)
   871  	}
   872  
   873  	_, err = base.subjectToken()
   874  	if err == nil {
   875  		t.Fatalf("retrieveSubjectToken() should have failed")
   876  	}
   877  
   878  	if got, want := err.Error(), "oauth2/google/externalaccount: unable to determine AWS region"; !reflect.DeepEqual(got, want) {
   879  		t.Errorf("subjectToken = %q, want %q", got, want)
   880  	}
   881  }
   882  
   883  func TestAWSCredential_RequestWithBadRegionURL(t *testing.T) {
   884  	server := createDefaultAwsTestServer()
   885  	ts := httptest.NewServer(server)
   886  
   887  	server.WriteRegion = notFound
   888  
   889  	tfc := testFileConfig
   890  	tfc.CredentialSource = server.getCredentialSource(ts.URL)
   891  
   892  	oldGetenv := getenv
   893  	defer func() {
   894  		getenv = oldGetenv
   895  	}()
   896  	getenv = setEnvironment(map[string]string{})
   897  
   898  	base, err := tfc.parse(context.Background())
   899  	if err != nil {
   900  		t.Fatalf("parse() failed %v", err)
   901  	}
   902  
   903  	_, err = base.subjectToken()
   904  	if err == nil {
   905  		t.Fatalf("retrieveSubjectToken() should have failed")
   906  	}
   907  
   908  	if got, want := err.Error(), "oauth2/google/externalaccount: unable to retrieve AWS region - Not Found"; !reflect.DeepEqual(got, want) {
   909  		t.Errorf("subjectToken = %q, want %q", got, want)
   910  	}
   911  }
   912  
   913  func TestAWSCredential_RequestWithMissingCredential(t *testing.T) {
   914  	server := createDefaultAwsTestServer()
   915  	ts := httptest.NewServer(server)
   916  
   917  	server.WriteSecurityCredentials = func(w http.ResponseWriter, r *http.Request) {
   918  		w.Write([]byte("{}"))
   919  	}
   920  
   921  	tfc := testFileConfig
   922  	tfc.CredentialSource = server.getCredentialSource(ts.URL)
   923  
   924  	oldGetenv := getenv
   925  	defer func() {
   926  		getenv = oldGetenv
   927  	}()
   928  	getenv = setEnvironment(map[string]string{})
   929  
   930  	base, err := tfc.parse(context.Background())
   931  	if err != nil {
   932  		t.Fatalf("parse() failed %v", err)
   933  	}
   934  
   935  	_, err = base.subjectToken()
   936  	if err == nil {
   937  		t.Fatalf("retrieveSubjectToken() should have failed")
   938  	}
   939  
   940  	if got, want := err.Error(), "oauth2/google/externalaccount: missing AccessKeyId credential"; !reflect.DeepEqual(got, want) {
   941  		t.Errorf("subjectToken = %q, want %q", got, want)
   942  	}
   943  }
   944  
   945  func TestAWSCredential_RequestWithIncompleteCredential(t *testing.T) {
   946  	server := createDefaultAwsTestServer()
   947  	ts := httptest.NewServer(server)
   948  
   949  	server.WriteSecurityCredentials = func(w http.ResponseWriter, r *http.Request) {
   950  		w.Write([]byte(`{"AccessKeyId":"FOOBARBAS"}`))
   951  	}
   952  
   953  	tfc := testFileConfig
   954  	tfc.CredentialSource = server.getCredentialSource(ts.URL)
   955  
   956  	oldGetenv := getenv
   957  	defer func() {
   958  		getenv = oldGetenv
   959  	}()
   960  	getenv = setEnvironment(map[string]string{})
   961  
   962  	base, err := tfc.parse(context.Background())
   963  	if err != nil {
   964  		t.Fatalf("parse() failed %v", err)
   965  	}
   966  
   967  	_, err = base.subjectToken()
   968  	if err == nil {
   969  		t.Fatalf("retrieveSubjectToken() should have failed")
   970  	}
   971  
   972  	if got, want := err.Error(), "oauth2/google/externalaccount: missing SecretAccessKey credential"; !reflect.DeepEqual(got, want) {
   973  		t.Errorf("subjectToken = %q, want %q", got, want)
   974  	}
   975  }
   976  
   977  func TestAWSCredential_RequestWithNoCredentialURL(t *testing.T) {
   978  	server := createDefaultAwsTestServer()
   979  	ts := httptest.NewServer(server)
   980  
   981  	tfc := testFileConfig
   982  	tfc.CredentialSource = server.getCredentialSource(ts.URL)
   983  	tfc.CredentialSource.URL = ""
   984  
   985  	oldGetenv := getenv
   986  	defer func() {
   987  		getenv = oldGetenv
   988  	}()
   989  	getenv = setEnvironment(map[string]string{})
   990  
   991  	base, err := tfc.parse(context.Background())
   992  	if err != nil {
   993  		t.Fatalf("parse() failed %v", err)
   994  	}
   995  
   996  	_, err = base.subjectToken()
   997  	if err == nil {
   998  		t.Fatalf("retrieveSubjectToken() should have failed")
   999  	}
  1000  
  1001  	if got, want := err.Error(), "oauth2/google/externalaccount: unable to determine the AWS metadata server security credentials endpoint"; !reflect.DeepEqual(got, want) {
  1002  		t.Errorf("subjectToken = %q, want %q", got, want)
  1003  	}
  1004  }
  1005  
  1006  func TestAWSCredential_RequestWithBadCredentialURL(t *testing.T) {
  1007  	server := createDefaultAwsTestServer()
  1008  	ts := httptest.NewServer(server)
  1009  	server.WriteRolename = notFound
  1010  
  1011  	tfc := testFileConfig
  1012  	tfc.CredentialSource = server.getCredentialSource(ts.URL)
  1013  
  1014  	oldGetenv := getenv
  1015  	defer func() {
  1016  		getenv = oldGetenv
  1017  	}()
  1018  	getenv = setEnvironment(map[string]string{})
  1019  
  1020  	base, err := tfc.parse(context.Background())
  1021  	if err != nil {
  1022  		t.Fatalf("parse() failed %v", err)
  1023  	}
  1024  
  1025  	_, err = base.subjectToken()
  1026  	if err == nil {
  1027  		t.Fatalf("retrieveSubjectToken() should have failed")
  1028  	}
  1029  
  1030  	if got, want := err.Error(), "oauth2/google/externalaccount: unable to retrieve AWS role name - Not Found"; !reflect.DeepEqual(got, want) {
  1031  		t.Errorf("subjectToken = %q, want %q", got, want)
  1032  	}
  1033  }
  1034  
  1035  func TestAWSCredential_RequestWithBadFinalCredentialURL(t *testing.T) {
  1036  	server := createDefaultAwsTestServer()
  1037  	ts := httptest.NewServer(server)
  1038  	server.WriteSecurityCredentials = notFound
  1039  
  1040  	tfc := testFileConfig
  1041  	tfc.CredentialSource = server.getCredentialSource(ts.URL)
  1042  
  1043  	oldGetenv := getenv
  1044  	defer func() {
  1045  		getenv = oldGetenv
  1046  	}()
  1047  	getenv = setEnvironment(map[string]string{})
  1048  
  1049  	base, err := tfc.parse(context.Background())
  1050  	if err != nil {
  1051  		t.Fatalf("parse() failed %v", err)
  1052  	}
  1053  
  1054  	_, err = base.subjectToken()
  1055  	if err == nil {
  1056  		t.Fatalf("retrieveSubjectToken() should have failed")
  1057  	}
  1058  
  1059  	if got, want := err.Error(), "oauth2/google/externalaccount: unable to retrieve AWS security credentials - Not Found"; !reflect.DeepEqual(got, want) {
  1060  		t.Errorf("subjectToken = %q, want %q", got, want)
  1061  	}
  1062  }
  1063  
  1064  func TestAWSCredential_ShouldNotCallMetadataEndpointWhenCredsAreInEnv(t *testing.T) {
  1065  	server := createDefaultAwsTestServer()
  1066  	ts := httptest.NewServer(server)
  1067  
  1068  	metadataTs := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  1069  		t.Error("Metadata server should not have been called.")
  1070  	}))
  1071  
  1072  	tfc := testFileConfig
  1073  	tfc.CredentialSource = server.getCredentialSource(ts.URL)
  1074  	tfc.CredentialSource.IMDSv2SessionTokenURL = metadataTs.URL
  1075  
  1076  	oldGetenv := getenv
  1077  	oldNow := now
  1078  	defer func() {
  1079  		getenv = oldGetenv
  1080  		now = oldNow
  1081  	}()
  1082  	getenv = setEnvironment(map[string]string{
  1083  		"AWS_ACCESS_KEY_ID":     "AKIDEXAMPLE",
  1084  		"AWS_SECRET_ACCESS_KEY": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY",
  1085  		"AWS_REGION":            "us-west-1",
  1086  	})
  1087  	now = setTime(defaultTime)
  1088  
  1089  	base, err := tfc.parse(context.Background())
  1090  	if err != nil {
  1091  		t.Fatalf("parse() failed %v", err)
  1092  	}
  1093  
  1094  	out, err := base.subjectToken()
  1095  	if err != nil {
  1096  		t.Fatalf("retrieveSubjectToken() failed: %v", err)
  1097  	}
  1098  
  1099  	expected := getExpectedSubjectToken(
  1100  		"https://sts.us-west-1.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15",
  1101  		"us-west-1",
  1102  		"AKIDEXAMPLE",
  1103  		"wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY",
  1104  		"",
  1105  	)
  1106  
  1107  	if got, want := out, expected; !reflect.DeepEqual(got, want) {
  1108  		t.Errorf("subjectToken = \n%q\n want \n%q", got, want)
  1109  	}
  1110  }
  1111  
  1112  func TestAWSCredential_ShouldCallMetadataEndpointWhenNoRegion(t *testing.T) {
  1113  	server := createDefaultAwsTestServerWithImdsv2(t)
  1114  	ts := httptest.NewServer(server)
  1115  
  1116  	tfc := testFileConfig
  1117  	tfc.CredentialSource = server.getCredentialSource(ts.URL)
  1118  
  1119  	oldGetenv := getenv
  1120  	oldNow := now
  1121  	defer func() {
  1122  		getenv = oldGetenv
  1123  		now = oldNow
  1124  	}()
  1125  	getenv = setEnvironment(map[string]string{
  1126  		"AWS_ACCESS_KEY_ID":     accessKeyID,
  1127  		"AWS_SECRET_ACCESS_KEY": secretAccessKey,
  1128  	})
  1129  	now = setTime(defaultTime)
  1130  
  1131  	base, err := tfc.parse(context.Background())
  1132  	if err != nil {
  1133  		t.Fatalf("parse() failed %v", err)
  1134  	}
  1135  
  1136  	out, err := base.subjectToken()
  1137  	if err != nil {
  1138  		t.Fatalf("retrieveSubjectToken() failed: %v", err)
  1139  	}
  1140  
  1141  	expected := getExpectedSubjectToken(
  1142  		"https://sts.us-east-2.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15",
  1143  		"us-east-2",
  1144  		accessKeyID,
  1145  		secretAccessKey,
  1146  		"",
  1147  	)
  1148  
  1149  	if got, want := out, expected; !reflect.DeepEqual(got, want) {
  1150  		t.Errorf("subjectToken = \n%q\n want \n%q", got, want)
  1151  	}
  1152  }
  1153  
  1154  func TestAWSCredential_ShouldCallMetadataEndpointWhenNoAccessKey(t *testing.T) {
  1155  	server := createDefaultAwsTestServerWithImdsv2(t)
  1156  	ts := httptest.NewServer(server)
  1157  
  1158  	tfc := testFileConfig
  1159  	tfc.CredentialSource = server.getCredentialSource(ts.URL)
  1160  
  1161  	oldGetenv := getenv
  1162  	oldNow := now
  1163  	defer func() {
  1164  		getenv = oldGetenv
  1165  		now = oldNow
  1166  	}()
  1167  	getenv = setEnvironment(map[string]string{
  1168  		"AWS_SECRET_ACCESS_KEY": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY",
  1169  		"AWS_REGION":            "us-west-1",
  1170  	})
  1171  	now = setTime(defaultTime)
  1172  
  1173  	base, err := tfc.parse(context.Background())
  1174  	if err != nil {
  1175  		t.Fatalf("parse() failed %v", err)
  1176  	}
  1177  
  1178  	out, err := base.subjectToken()
  1179  	if err != nil {
  1180  		t.Fatalf("retrieveSubjectToken() failed: %v", err)
  1181  	}
  1182  
  1183  	expected := getExpectedSubjectToken(
  1184  		"https://sts.us-west-1.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15",
  1185  		"us-west-1",
  1186  		accessKeyID,
  1187  		secretAccessKey,
  1188  		securityToken,
  1189  	)
  1190  
  1191  	if got, want := out, expected; !reflect.DeepEqual(got, want) {
  1192  		t.Errorf("subjectToken = \n%q\n want \n%q", got, want)
  1193  	}
  1194  }
  1195  
  1196  func TestAWSCredential_ShouldCallMetadataEndpointWhenNoSecretAccessKey(t *testing.T) {
  1197  	server := createDefaultAwsTestServerWithImdsv2(t)
  1198  	ts := httptest.NewServer(server)
  1199  
  1200  	tfc := testFileConfig
  1201  	tfc.CredentialSource = server.getCredentialSource(ts.URL)
  1202  
  1203  	oldGetenv := getenv
  1204  	oldNow := now
  1205  	defer func() {
  1206  		getenv = oldGetenv
  1207  		now = oldNow
  1208  	}()
  1209  	getenv = setEnvironment(map[string]string{
  1210  		"AWS_ACCESS_KEY_ID": "AKIDEXAMPLE",
  1211  		"AWS_REGION":        "us-west-1",
  1212  	})
  1213  	now = setTime(defaultTime)
  1214  
  1215  	base, err := tfc.parse(context.Background())
  1216  	if err != nil {
  1217  		t.Fatalf("parse() failed %v", err)
  1218  	}
  1219  
  1220  	out, err := base.subjectToken()
  1221  	if err != nil {
  1222  		t.Fatalf("retrieveSubjectToken() failed: %v", err)
  1223  	}
  1224  
  1225  	expected := getExpectedSubjectToken(
  1226  		"https://sts.us-west-1.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15",
  1227  		"us-west-1",
  1228  		accessKeyID,
  1229  		secretAccessKey,
  1230  		securityToken,
  1231  	)
  1232  
  1233  	if got, want := out, expected; !reflect.DeepEqual(got, want) {
  1234  		t.Errorf("subjectToken = \n%q\n want \n%q", got, want)
  1235  	}
  1236  }
  1237  
  1238  func TestAWSCredential_ProgrammaticAuth(t *testing.T) {
  1239  	tfc := testFileConfig
  1240  	securityCredentials := AwsSecurityCredentials{
  1241  		AccessKeyID:     accessKeyID,
  1242  		SecretAccessKey: secretAccessKey,
  1243  		SessionToken:    securityToken,
  1244  	}
  1245  
  1246  	tfc.AwsSecurityCredentialsSupplier = testAwsSupplier{
  1247  		awsRegion:   "us-east-2",
  1248  		err:         nil,
  1249  		credentials: &securityCredentials,
  1250  	}
  1251  
  1252  	oldNow := now
  1253  	defer func() {
  1254  		now = oldNow
  1255  	}()
  1256  	now = setTime(defaultTime)
  1257  
  1258  	base, err := tfc.parse(context.Background())
  1259  	if err != nil {
  1260  		t.Fatalf("parse() failed %v", err)
  1261  	}
  1262  
  1263  	out, err := base.subjectToken()
  1264  	if err != nil {
  1265  		t.Fatalf("retrieveSubjectToken() failed: %v", err)
  1266  	}
  1267  
  1268  	expected := getExpectedSubjectToken(
  1269  		"https://sts.us-east-2.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15",
  1270  		"us-east-2",
  1271  		accessKeyID,
  1272  		secretAccessKey,
  1273  		securityToken,
  1274  	)
  1275  
  1276  	if got, want := out, expected; !reflect.DeepEqual(got, want) {
  1277  		t.Errorf("subjectToken = \n%q\n want \n%q", got, want)
  1278  	}
  1279  }
  1280  
  1281  func TestAWSCredential_ProgrammaticAuthNoSessionToken(t *testing.T) {
  1282  	tfc := testFileConfig
  1283  	securityCredentials := AwsSecurityCredentials{
  1284  		AccessKeyID:     accessKeyID,
  1285  		SecretAccessKey: secretAccessKey,
  1286  	}
  1287  
  1288  	tfc.AwsSecurityCredentialsSupplier = testAwsSupplier{
  1289  		awsRegion:   "us-east-2",
  1290  		err:         nil,
  1291  		credentials: &securityCredentials,
  1292  	}
  1293  
  1294  	oldNow := now
  1295  	defer func() {
  1296  		now = oldNow
  1297  	}()
  1298  	now = setTime(defaultTime)
  1299  
  1300  	base, err := tfc.parse(context.Background())
  1301  	if err != nil {
  1302  		t.Fatalf("parse() failed %v", err)
  1303  	}
  1304  
  1305  	out, err := base.subjectToken()
  1306  	if err != nil {
  1307  		t.Fatalf("retrieveSubjectToken() failed: %v", err)
  1308  	}
  1309  
  1310  	expected := getExpectedSubjectToken(
  1311  		"https://sts.us-east-2.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15",
  1312  		"us-east-2",
  1313  		accessKeyID,
  1314  		secretAccessKey,
  1315  		"",
  1316  	)
  1317  
  1318  	if got, want := out, expected; !reflect.DeepEqual(got, want) {
  1319  		t.Errorf("subjectToken = \n%q\n want \n%q", got, want)
  1320  	}
  1321  }
  1322  
  1323  func TestAWSCredential_ProgrammaticAuthError(t *testing.T) {
  1324  	tfc := testFileConfig
  1325  	testErr := errors.New("test error")
  1326  	tfc.AwsSecurityCredentialsSupplier = testAwsSupplier{
  1327  		awsRegion:   "us-east-2",
  1328  		err:         testErr,
  1329  		credentials: nil,
  1330  	}
  1331  
  1332  	base, err := tfc.parse(context.Background())
  1333  	if err != nil {
  1334  		t.Fatalf("parse() failed %v", err)
  1335  	}
  1336  
  1337  	_, err = base.subjectToken()
  1338  	if err == nil {
  1339  		t.Fatalf("subjectToken() should have failed")
  1340  	}
  1341  	if err != testErr {
  1342  		t.Errorf("error = %e, want %e", err, testErr)
  1343  	}
  1344  }
  1345  
  1346  func TestAWSCredential_ProgrammaticAuthRegionError(t *testing.T) {
  1347  	tfc := testFileConfig
  1348  	securityCredentials := AwsSecurityCredentials{
  1349  		AccessKeyID:     accessKeyID,
  1350  		SecretAccessKey: secretAccessKey,
  1351  	}
  1352  
  1353  	testErr := errors.New("test")
  1354  	tfc.AwsSecurityCredentialsSupplier = testAwsSupplier{
  1355  		awsRegion:   "",
  1356  		regionErr:   testErr,
  1357  		credentials: &securityCredentials,
  1358  	}
  1359  
  1360  	base, err := tfc.parse(context.Background())
  1361  	if err != nil {
  1362  		t.Fatalf("parse() failed %v", err)
  1363  	}
  1364  
  1365  	_, err = base.subjectToken()
  1366  	if err == nil {
  1367  		t.Fatalf("subjectToken() should have failed")
  1368  	}
  1369  	if err != testErr {
  1370  		t.Errorf("error = %e, want %e", err, testErr)
  1371  	}
  1372  }
  1373  
  1374  func TestAWSCredential_ProgrammaticAuthOptions(t *testing.T) {
  1375  	tfc := testFileConfig
  1376  	securityCredentials := AwsSecurityCredentials{
  1377  		AccessKeyID:     accessKeyID,
  1378  		SecretAccessKey: secretAccessKey,
  1379  	}
  1380  	expectedOptions := SupplierOptions{Audience: tfc.Audience, SubjectTokenType: tfc.SubjectTokenType}
  1381  
  1382  	tfc.AwsSecurityCredentialsSupplier = testAwsSupplier{
  1383  		awsRegion:       "us-east-2",
  1384  		credentials:     &securityCredentials,
  1385  		expectedOptions: &expectedOptions,
  1386  	}
  1387  
  1388  	base, err := tfc.parse(context.Background())
  1389  	if err != nil {
  1390  		t.Fatalf("parse() failed %v", err)
  1391  	}
  1392  
  1393  	_, err = base.subjectToken()
  1394  	if err != nil {
  1395  		t.Fatalf("subjectToken() failed %v", err)
  1396  	}
  1397  }
  1398  
  1399  func TestAWSCredential_ProgrammaticAuthContext(t *testing.T) {
  1400  	tfc := testFileConfig
  1401  	securityCredentials := AwsSecurityCredentials{
  1402  		AccessKeyID:     accessKeyID,
  1403  		SecretAccessKey: secretAccessKey,
  1404  	}
  1405  	ctx := context.Background()
  1406  
  1407  	tfc.AwsSecurityCredentialsSupplier = testAwsSupplier{
  1408  		awsRegion:       "us-east-2",
  1409  		credentials:     &securityCredentials,
  1410  		expectedContext: ctx,
  1411  	}
  1412  
  1413  	base, err := tfc.parse(ctx)
  1414  	if err != nil {
  1415  		t.Fatalf("parse() failed %v", err)
  1416  	}
  1417  
  1418  	_, err = base.subjectToken()
  1419  	if err != nil {
  1420  		t.Fatalf("subjectToken() failed %v", err)
  1421  	}
  1422  }
  1423  
  1424  func TestAwsCredential_CredentialSourceType(t *testing.T) {
  1425  	server := createDefaultAwsTestServer()
  1426  	ts := httptest.NewServer(server)
  1427  
  1428  	tfc := testFileConfig
  1429  	tfc.CredentialSource = server.getCredentialSource(ts.URL)
  1430  
  1431  	base, err := tfc.parse(context.Background())
  1432  	if err != nil {
  1433  		t.Fatalf("parse() failed %v", err)
  1434  	}
  1435  
  1436  	if got, want := base.credentialSourceType(), "aws"; got != want {
  1437  		t.Errorf("got %v but want %v", got, want)
  1438  	}
  1439  }
  1440  
  1441  type testAwsSupplier struct {
  1442  	err             error
  1443  	regionErr       error
  1444  	awsRegion       string
  1445  	credentials     *AwsSecurityCredentials
  1446  	expectedOptions *SupplierOptions
  1447  	expectedContext context.Context
  1448  }
  1449  
  1450  func (supp testAwsSupplier) AwsRegion(ctx context.Context, options SupplierOptions) (string, error) {
  1451  	if supp.regionErr != nil {
  1452  		return "", supp.regionErr
  1453  	}
  1454  	if supp.expectedOptions != nil {
  1455  		if supp.expectedOptions.Audience != options.Audience {
  1456  			return "", errors.New("Audience does not match")
  1457  		}
  1458  		if supp.expectedOptions.SubjectTokenType != options.SubjectTokenType {
  1459  			return "", errors.New("Audience does not match")
  1460  		}
  1461  	}
  1462  	if supp.expectedContext != nil {
  1463  		if supp.expectedContext != ctx {
  1464  			return "", errors.New("Context does not match")
  1465  		}
  1466  	}
  1467  	return supp.awsRegion, nil
  1468  }
  1469  
  1470  func (supp testAwsSupplier) AwsSecurityCredentials(ctx context.Context, options SupplierOptions) (*AwsSecurityCredentials, error) {
  1471  	if supp.err != nil {
  1472  		return nil, supp.err
  1473  	}
  1474  	if supp.expectedOptions != nil {
  1475  		if supp.expectedOptions.Audience != options.Audience {
  1476  			return nil, errors.New("Audience does not match")
  1477  		}
  1478  		if supp.expectedOptions.SubjectTokenType != options.SubjectTokenType {
  1479  			return nil, errors.New("Audience does not match")
  1480  		}
  1481  	}
  1482  	if supp.expectedContext != nil {
  1483  		if supp.expectedContext != ctx {
  1484  			return nil, errors.New("Context does not match")
  1485  		}
  1486  	}
  1487  	return supp.credentials, nil
  1488  }
  1489  

View as plain text