1//go:build go1.7
2// +build go1.7
3
4package session
5
6import (
7	"fmt"
8	"path/filepath"
9	"reflect"
10	"strconv"
11	"strings"
12	"testing"
13
14	"github.com/aws/aws-sdk-go/aws/credentials"
15	"github.com/aws/aws-sdk-go/aws/endpoints"
16	"github.com/aws/aws-sdk-go/internal/ini"
17)
18
19var (
20	testConfigFilename      = filepath.Join("testdata", "shared_config")
21	testConfigOtherFilename = filepath.Join("testdata", "shared_config_other")
22)
23
24func TestLoadSharedConfig(t *testing.T) {
25	cases := []struct {
26		Filenames []string
27		Profile   string
28		Expected  sharedConfig
29		Err       error
30	}{
31		{
32			Filenames: []string{"file_not_exists"},
33			Profile:   "default",
34			Expected: sharedConfig{
35				Profile: "default",
36			},
37		},
38		{
39			Filenames: []string{testConfigFilename},
40			Expected: sharedConfig{
41				Profile: "default",
42				Region:  "default_region",
43			},
44		},
45		{
46			Filenames: []string{testConfigOtherFilename, testConfigFilename},
47			Profile:   "config_file_load_order",
48			Expected: sharedConfig{
49				Profile: "config_file_load_order",
50				Region:  "shared_config_region",
51				Creds: credentials.Value{
52					AccessKeyID:     "shared_config_akid",
53					SecretAccessKey: "shared_config_secret",
54					ProviderName:    fmt.Sprintf("SharedConfigCredentials: %s", testConfigFilename),
55				},
56			},
57		},
58		{
59			Filenames: []string{testConfigFilename, testConfigOtherFilename},
60			Profile:   "config_file_load_order",
61			Expected: sharedConfig{
62				Profile: "config_file_load_order",
63				Region:  "shared_config_other_region",
64				Creds: credentials.Value{
65					AccessKeyID:     "shared_config_other_akid",
66					SecretAccessKey: "shared_config_other_secret",
67					ProviderName:    fmt.Sprintf("SharedConfigCredentials: %s", testConfigOtherFilename),
68				},
69			},
70		},
71		{
72			Filenames: []string{testConfigOtherFilename, testConfigFilename},
73			Profile:   "assume_role",
74			Expected: sharedConfig{
75				Profile:           "assume_role",
76				RoleARN:           "assume_role_role_arn",
77				SourceProfileName: "complete_creds",
78				SourceProfile: &sharedConfig{
79					Profile: "complete_creds",
80					Creds: credentials.Value{
81						AccessKeyID:     "complete_creds_akid",
82						SecretAccessKey: "complete_creds_secret",
83						ProviderName:    fmt.Sprintf("SharedConfigCredentials: %s", testConfigFilename),
84					},
85				},
86			},
87		},
88		{
89			Filenames: []string{testConfigOtherFilename, testConfigFilename},
90			Profile:   "assume_role_invalid_source_profile",
91			Expected: sharedConfig{
92				Profile:           "assume_role_invalid_source_profile",
93				RoleARN:           "assume_role_invalid_source_profile_role_arn",
94				SourceProfileName: "profile_not_exists",
95			},
96			Err: SharedConfigAssumeRoleError{
97				RoleARN:       "assume_role_invalid_source_profile_role_arn",
98				SourceProfile: "profile_not_exists",
99			},
100		},
101		{
102			Filenames: []string{testConfigOtherFilename, testConfigFilename},
103			Profile:   "assume_role_w_creds",
104			Expected: sharedConfig{
105				Profile:           "assume_role_w_creds",
106				RoleARN:           "assume_role_w_creds_role_arn",
107				ExternalID:        "1234",
108				RoleSessionName:   "assume_role_w_creds_session_name",
109				SourceProfileName: "assume_role_w_creds",
110				SourceProfile: &sharedConfig{
111					Profile: "assume_role_w_creds",
112					Creds: credentials.Value{
113						AccessKeyID:     "assume_role_w_creds_akid",
114						SecretAccessKey: "assume_role_w_creds_secret",
115						ProviderName:    fmt.Sprintf("SharedConfigCredentials: %s", testConfigFilename),
116					},
117				},
118			},
119		},
120		{
121			Filenames: []string{testConfigOtherFilename, testConfigFilename},
122			Profile:   "assume_role_wo_creds",
123			Expected: sharedConfig{
124				Profile:           "assume_role_wo_creds",
125				RoleARN:           "assume_role_wo_creds_role_arn",
126				SourceProfileName: "assume_role_wo_creds",
127			},
128			Err: SharedConfigAssumeRoleError{
129				RoleARN:       "assume_role_wo_creds_role_arn",
130				SourceProfile: "assume_role_wo_creds",
131			},
132		},
133		{
134			Filenames: []string{filepath.Join("testdata", "shared_config_invalid_ini")},
135			Profile:   "profile_name",
136			Err:       SharedConfigLoadError{Filename: filepath.Join("testdata", "shared_config_invalid_ini")},
137		},
138		{
139			Filenames: []string{testConfigOtherFilename, testConfigFilename},
140			Profile:   "assume_role_with_credential_source",
141			Expected: sharedConfig{
142				Profile:          "assume_role_with_credential_source",
143				RoleARN:          "assume_role_with_credential_source_role_arn",
144				CredentialSource: credSourceEc2Metadata,
145			},
146		},
147		{
148			Filenames: []string{testConfigOtherFilename, testConfigFilename},
149			Profile:   "multiple_assume_role",
150			Expected: sharedConfig{
151				Profile:           "multiple_assume_role",
152				RoleARN:           "multiple_assume_role_role_arn",
153				SourceProfileName: "assume_role",
154				SourceProfile: &sharedConfig{
155					Profile:           "assume_role",
156					RoleARN:           "assume_role_role_arn",
157					SourceProfileName: "complete_creds",
158					SourceProfile: &sharedConfig{
159						Profile: "complete_creds",
160						Creds: credentials.Value{
161							AccessKeyID:     "complete_creds_akid",
162							SecretAccessKey: "complete_creds_secret",
163							ProviderName:    fmt.Sprintf("SharedConfigCredentials: %s", testConfigFilename),
164						},
165					},
166				},
167			},
168		},
169		{
170			Filenames: []string{testConfigOtherFilename, testConfigFilename},
171			Profile:   "multiple_assume_role_with_credential_source",
172			Expected: sharedConfig{
173				Profile:           "multiple_assume_role_with_credential_source",
174				RoleARN:           "multiple_assume_role_with_credential_source_role_arn",
175				SourceProfileName: "assume_role_with_credential_source",
176				SourceProfile: &sharedConfig{
177					Profile:          "assume_role_with_credential_source",
178					RoleARN:          "assume_role_with_credential_source_role_arn",
179					CredentialSource: credSourceEc2Metadata,
180				},
181			},
182		},
183		{
184			Filenames: []string{testConfigOtherFilename, testConfigFilename},
185			Profile:   "multiple_assume_role_with_credential_source2",
186			Expected: sharedConfig{
187				Profile:           "multiple_assume_role_with_credential_source2",
188				RoleARN:           "multiple_assume_role_with_credential_source2_role_arn",
189				SourceProfileName: "multiple_assume_role_with_credential_source",
190				SourceProfile: &sharedConfig{
191					Profile:           "multiple_assume_role_with_credential_source",
192					RoleARN:           "multiple_assume_role_with_credential_source_role_arn",
193					SourceProfileName: "assume_role_with_credential_source",
194					SourceProfile: &sharedConfig{
195						Profile:          "assume_role_with_credential_source",
196						RoleARN:          "assume_role_with_credential_source_role_arn",
197						CredentialSource: credSourceEc2Metadata,
198					},
199				},
200			},
201		},
202		{
203			Filenames: []string{testConfigFilename},
204			Profile:   "with_sts_regional",
205			Expected: sharedConfig{
206				Profile:             "with_sts_regional",
207				STSRegionalEndpoint: endpoints.RegionalSTSEndpoint,
208			},
209		},
210		{
211			Filenames: []string{testConfigFilename},
212			Profile:   "with_s3_us_east_1_regional",
213			Expected: sharedConfig{
214				Profile:                   "with_s3_us_east_1_regional",
215				S3UsEast1RegionalEndpoint: endpoints.RegionalS3UsEast1Endpoint,
216			},
217		},
218		{
219			Filenames: []string{testConfigFilename},
220			Profile:   "sso_creds",
221			Expected: sharedConfig{
222				Profile:      "sso_creds",
223				SSOAccountID: "012345678901",
224				SSORegion:    "us-west-2",
225				SSORoleName:  "TestRole",
226				SSOStartURL:  "https://127.0.0.1/start",
227			},
228		},
229		{
230			Filenames: []string{testConfigFilename},
231			Profile:   "source_sso_creds",
232			Expected: sharedConfig{
233				Profile:           "source_sso_creds",
234				RoleARN:           "source_sso_creds_arn",
235				SourceProfileName: "sso_creds",
236				SourceProfile: &sharedConfig{
237					Profile:      "sso_creds",
238					SSOAccountID: "012345678901",
239					SSORegion:    "us-west-2",
240					SSORoleName:  "TestRole",
241					SSOStartURL:  "https://127.0.0.1/start",
242				},
243			},
244		},
245		{
246			Filenames: []string{testConfigFilename},
247			Profile:   "sso_and_static",
248			Expected: sharedConfig{
249				Profile: "sso_and_static",
250				Creds: credentials.Value{
251					AccessKeyID:     "sso_and_static_akid",
252					SecretAccessKey: "sso_and_static_secret",
253					SessionToken:    "sso_and_static_token",
254					ProviderName:    fmt.Sprintf("SharedConfigCredentials: %s", testConfigFilename),
255				},
256				SSOAccountID: "012345678901",
257				SSORegion:    "us-west-2",
258				SSORoleName:  "TestRole",
259				SSOStartURL:  "https://THIS_SHOULD_NOT_BE_IN_TESTDATA_CACHE/start",
260			},
261		},
262		{
263			Filenames: []string{testConfigFilename},
264			Profile:   "source_sso_and_assume",
265			Expected: sharedConfig{
266				Profile:           "source_sso_and_assume",
267				RoleARN:           "source_sso_and_assume_arn",
268				SourceProfileName: "sso_and_assume",
269				SourceProfile: &sharedConfig{
270					Profile:           "sso_and_assume",
271					RoleARN:           "sso_with_assume_role_arn",
272					SourceProfileName: "multiple_assume_role_with_credential_source",
273					SourceProfile: &sharedConfig{
274						Profile:           "multiple_assume_role_with_credential_source",
275						RoleARN:           "multiple_assume_role_with_credential_source_role_arn",
276						SourceProfileName: "assume_role_with_credential_source",
277						SourceProfile: &sharedConfig{
278							Profile:          "assume_role_with_credential_source",
279							RoleARN:          "assume_role_with_credential_source_role_arn",
280							CredentialSource: credSourceEc2Metadata,
281						},
282					},
283				},
284			},
285		},
286		{
287			Filenames: []string{testConfigFilename},
288			Profile:   "sso_mixed_credproc",
289			Expected: sharedConfig{
290				Profile:           "sso_mixed_credproc",
291				SSOAccountID:      "012345678901",
292				SSORegion:         "us-west-2",
293				SSORoleName:       "TestRole",
294				SSOStartURL:       "https://127.0.0.1/start",
295				CredentialProcess: "/path/to/process",
296			},
297		},
298		{
299			Filenames: []string{testConfigFilename},
300			Profile:   "EC2MetadataServiceEndpoint",
301			Expected: sharedConfig{
302				Profile:         "EC2MetadataServiceEndpoint",
303				EC2IMDSEndpoint: "http://endpoint.localhost",
304			},
305		},
306		{
307			Filenames: []string{testConfigFilename},
308			Profile:   "EC2MetadataServiceEndpointModeIPv6",
309			Expected: sharedConfig{
310				Profile:             "EC2MetadataServiceEndpointModeIPv6",
311				EC2IMDSEndpointMode: endpoints.EC2IMDSEndpointModeStateIPv6,
312			},
313		},
314		{
315			Filenames: []string{testConfigFilename},
316			Profile:   "EC2MetadataServiceEndpointModeIPv4",
317			Expected: sharedConfig{
318				Profile:             "EC2MetadataServiceEndpointModeIPv4",
319				EC2IMDSEndpointMode: endpoints.EC2IMDSEndpointModeStateIPv4,
320			},
321		},
322		{
323			Filenames: []string{testConfigFilename},
324			Profile:   "EC2MetadataServiceEndpointModeUnknown",
325			Expected: sharedConfig{
326				Profile: "EC2MetadataServiceEndpointModeUnknown",
327			},
328			Err: fmt.Errorf("failed to load ec2_metadata_service_endpoint_mode from shared config"),
329		},
330		{
331			Filenames: []string{testConfigFilename},
332			Profile:   "EC2MetadataServiceEndpointAndModeMixed",
333			Expected: sharedConfig{
334				Profile:             "EC2MetadataServiceEndpointAndModeMixed",
335				EC2IMDSEndpoint:     "http://endpoint.localhost",
336				EC2IMDSEndpointMode: endpoints.EC2IMDSEndpointModeStateIPv6,
337			},
338		},
339	}
340
341	for i, c := range cases {
342		t.Run(strconv.Itoa(i)+"_"+c.Profile, func(t *testing.T) {
343			cfg, err := loadSharedConfig(c.Profile, c.Filenames, true)
344			if c.Err != nil {
345				if err == nil {
346					t.Fatalf("expect error, got none")
347				}
348				if e, a := c.Err.Error(), err.Error(); !strings.Contains(a, e) {
349					t.Errorf("expect %v, to be in %v", e, a)
350				}
351				return
352			}
353
354			if err != nil {
355				t.Fatalf("expect no error, got %v", err)
356			}
357			if e, a := c.Expected, cfg; !reflect.DeepEqual(e, a) {
358				t.Errorf("expect %v, got %v", e, a)
359			}
360		})
361	}
362}
363
364func TestLoadSharedConfigFromFile(t *testing.T) {
365	filename := testConfigFilename
366	f, err := ini.OpenFile(filename)
367	if err != nil {
368		t.Fatalf("failed to load test config file, %s, %v", filename, err)
369	}
370	iniFile := sharedConfigFile{IniData: f, Filename: filename}
371
372	cases := []struct {
373		Profile  string
374		Expected sharedConfig
375		Err      error
376	}{
377		{
378			Profile:  "default",
379			Expected: sharedConfig{Region: "default_region"},
380		},
381		{
382			Profile:  "alt_profile_name",
383			Expected: sharedConfig{Region: "alt_profile_name_region"},
384		},
385		{
386			Profile:  "short_profile_name_first",
387			Expected: sharedConfig{Region: "short_profile_name_first_short"},
388		},
389		{
390			Profile:  "partial_creds",
391			Expected: sharedConfig{},
392		},
393		{
394			Profile: "complete_creds",
395			Expected: sharedConfig{
396				Creds: credentials.Value{
397					AccessKeyID:     "complete_creds_akid",
398					SecretAccessKey: "complete_creds_secret",
399					ProviderName:    fmt.Sprintf("SharedConfigCredentials: %s", testConfigFilename),
400				},
401			},
402		},
403		{
404			Profile: "complete_creds_with_token",
405			Expected: sharedConfig{
406				Creds: credentials.Value{
407					AccessKeyID:     "complete_creds_with_token_akid",
408					SecretAccessKey: "complete_creds_with_token_secret",
409					SessionToken:    "complete_creds_with_token_token",
410					ProviderName:    fmt.Sprintf("SharedConfigCredentials: %s", testConfigFilename),
411				},
412			},
413		},
414		{
415			Profile: "full_profile",
416			Expected: sharedConfig{
417				Creds: credentials.Value{
418					AccessKeyID:     "full_profile_akid",
419					SecretAccessKey: "full_profile_secret",
420					ProviderName:    fmt.Sprintf("SharedConfigCredentials: %s", testConfigFilename),
421				},
422				Region: "full_profile_region",
423			},
424		},
425		{
426			Profile: "partial_assume_role",
427			Expected: sharedConfig{
428				RoleARN: "partial_assume_role_role_arn",
429			},
430		},
431		{
432			Profile: "assume_role",
433			Expected: sharedConfig{
434				RoleARN:           "assume_role_role_arn",
435				SourceProfileName: "complete_creds",
436			},
437		},
438		{
439			Profile: "assume_role_w_mfa",
440			Expected: sharedConfig{
441				RoleARN:           "assume_role_role_arn",
442				SourceProfileName: "complete_creds",
443				MFASerial:         "0123456789",
444			},
445		},
446		{
447			Profile: "does_not_exists",
448			Err:     SharedConfigProfileNotExistsError{Profile: "does_not_exists"},
449		},
450		{
451			Profile: "valid_arn_region",
452			Expected: sharedConfig{
453				S3UseARNRegion: true,
454			},
455		},
456	}
457
458	for i, c := range cases {
459		t.Run(strconv.Itoa(i)+"_"+c.Profile, func(t *testing.T) {
460			cfg := sharedConfig{}
461
462			err := cfg.setFromIniFile(c.Profile, iniFile, true)
463			if c.Err != nil {
464				if err == nil {
465					t.Fatalf("expect error, got none")
466				}
467				if e, a := c.Err.Error(), err.Error(); !strings.Contains(a, e) {
468					t.Errorf("expect %v, to be in %v", e, a)
469				}
470				return
471			}
472
473			if err != nil {
474				t.Errorf("expect no error, got %v", err)
475			}
476			if e, a := c.Expected, cfg; !reflect.DeepEqual(e, a) {
477				t.Errorf("expect %v, got %v", e, a)
478			}
479		})
480	}
481}
482
483func TestLoadSharedConfigIniFiles(t *testing.T) {
484	cases := []struct {
485		Filenames []string
486		Expected  []sharedConfigFile
487	}{
488		{
489			Filenames: []string{"not_exists", testConfigFilename},
490			Expected: []sharedConfigFile{
491				{Filename: testConfigFilename},
492			},
493		},
494		{
495			Filenames: []string{testConfigFilename, testConfigOtherFilename},
496			Expected: []sharedConfigFile{
497				{Filename: testConfigFilename},
498				{Filename: testConfigOtherFilename},
499			},
500		},
501	}
502
503	for i, c := range cases {
504		t.Run(strconv.Itoa(i), func(t *testing.T) {
505			files, err := loadSharedConfigIniFiles(c.Filenames)
506			if err != nil {
507				t.Fatalf("expect no error, got %v", err)
508			}
509			if e, a := len(c.Expected), len(files); e != a {
510				t.Errorf("expect %v, got %v", e, a)
511			}
512
513			for i, expectedFile := range c.Expected {
514				if e, a := expectedFile.Filename, files[i].Filename; e != a {
515					t.Errorf("expect %v, got %v", e, a)
516				}
517			}
518		})
519	}
520}
521