1// +build go1.7
2
3package session
4
5import (
6	"fmt"
7	"path/filepath"
8	"reflect"
9	"strconv"
10	"strings"
11	"testing"
12
13	"github.com/aws/aws-sdk-go/aws/credentials"
14	"github.com/aws/aws-sdk-go/aws/endpoints"
15	"github.com/aws/aws-sdk-go/internal/ini"
16)
17
18var (
19	testConfigFilename      = filepath.Join("testdata", "shared_config")
20	testConfigOtherFilename = filepath.Join("testdata", "shared_config_other")
21)
22
23func TestLoadSharedConfig(t *testing.T) {
24	cases := []struct {
25		Filenames []string
26		Profile   string
27		Expected  sharedConfig
28		Err       error
29	}{
30		{
31			Filenames: []string{"file_not_exists"},
32			Profile:   "default",
33			Expected:  sharedConfig{},
34		},
35		{
36			Filenames: []string{testConfigFilename},
37			Expected: sharedConfig{
38				Region: "default_region",
39			},
40		},
41		{
42			Filenames: []string{testConfigOtherFilename, testConfigFilename},
43			Profile:   "config_file_load_order",
44			Expected: sharedConfig{
45				Region: "shared_config_region",
46				Creds: credentials.Value{
47					AccessKeyID:     "shared_config_akid",
48					SecretAccessKey: "shared_config_secret",
49					ProviderName:    fmt.Sprintf("SharedConfigCredentials: %s", testConfigFilename),
50				},
51			},
52		},
53		{
54			Filenames: []string{testConfigFilename, testConfigOtherFilename},
55			Profile:   "config_file_load_order",
56			Expected: sharedConfig{
57				Region: "shared_config_other_region",
58				Creds: credentials.Value{
59					AccessKeyID:     "shared_config_other_akid",
60					SecretAccessKey: "shared_config_other_secret",
61					ProviderName:    fmt.Sprintf("SharedConfigCredentials: %s", testConfigOtherFilename),
62				},
63			},
64		},
65		{
66			Filenames: []string{testConfigOtherFilename, testConfigFilename},
67			Profile:   "assume_role",
68			Expected: sharedConfig{
69				RoleARN:           "assume_role_role_arn",
70				SourceProfileName: "complete_creds",
71				SourceProfile: &sharedConfig{
72					Creds: credentials.Value{
73						AccessKeyID:     "complete_creds_akid",
74						SecretAccessKey: "complete_creds_secret",
75						ProviderName:    fmt.Sprintf("SharedConfigCredentials: %s", testConfigFilename),
76					},
77				},
78			},
79		},
80		{
81			Filenames: []string{testConfigOtherFilename, testConfigFilename},
82			Profile:   "assume_role_invalid_source_profile",
83			Expected: sharedConfig{
84				RoleARN:           "assume_role_invalid_source_profile_role_arn",
85				SourceProfileName: "profile_not_exists",
86			},
87			Err: SharedConfigAssumeRoleError{
88				RoleARN:       "assume_role_invalid_source_profile_role_arn",
89				SourceProfile: "profile_not_exists",
90			},
91		},
92		{
93			Filenames: []string{testConfigOtherFilename, testConfigFilename},
94			Profile:   "assume_role_w_creds",
95			Expected: sharedConfig{
96				RoleARN:           "assume_role_w_creds_role_arn",
97				ExternalID:        "1234",
98				RoleSessionName:   "assume_role_w_creds_session_name",
99				SourceProfileName: "assume_role_w_creds",
100				SourceProfile: &sharedConfig{
101					Creds: credentials.Value{
102						AccessKeyID:     "assume_role_w_creds_akid",
103						SecretAccessKey: "assume_role_w_creds_secret",
104						ProviderName:    fmt.Sprintf("SharedConfigCredentials: %s", testConfigFilename),
105					},
106				},
107			},
108		},
109		{
110			Filenames: []string{testConfigOtherFilename, testConfigFilename},
111			Profile:   "assume_role_wo_creds",
112			Expected: sharedConfig{
113				RoleARN:           "assume_role_wo_creds_role_arn",
114				SourceProfileName: "assume_role_wo_creds",
115			},
116			Err: SharedConfigAssumeRoleError{
117				RoleARN:       "assume_role_wo_creds_role_arn",
118				SourceProfile: "assume_role_wo_creds",
119			},
120		},
121		{
122			Filenames: []string{filepath.Join("testdata", "shared_config_invalid_ini")},
123			Profile:   "profile_name",
124			Err:       SharedConfigLoadError{Filename: filepath.Join("testdata", "shared_config_invalid_ini")},
125		},
126		{
127			Filenames: []string{testConfigOtherFilename, testConfigFilename},
128			Profile:   "assume_role_with_credential_source",
129			Expected: sharedConfig{
130				RoleARN:          "assume_role_with_credential_source_role_arn",
131				CredentialSource: credSourceEc2Metadata,
132			},
133		},
134		{
135			Filenames: []string{testConfigOtherFilename, testConfigFilename},
136			Profile:   "multiple_assume_role",
137			Expected: sharedConfig{
138				RoleARN:           "multiple_assume_role_role_arn",
139				SourceProfileName: "assume_role",
140				SourceProfile: &sharedConfig{
141					RoleARN:           "assume_role_role_arn",
142					SourceProfileName: "complete_creds",
143					SourceProfile: &sharedConfig{
144						Creds: credentials.Value{
145							AccessKeyID:     "complete_creds_akid",
146							SecretAccessKey: "complete_creds_secret",
147							ProviderName:    fmt.Sprintf("SharedConfigCredentials: %s", testConfigFilename),
148						},
149					},
150				},
151			},
152		},
153		{
154			Filenames: []string{testConfigOtherFilename, testConfigFilename},
155			Profile:   "multiple_assume_role_with_credential_source",
156			Expected: sharedConfig{
157				RoleARN:           "multiple_assume_role_with_credential_source_role_arn",
158				SourceProfileName: "assume_role_with_credential_source",
159				SourceProfile: &sharedConfig{
160					RoleARN:          "assume_role_with_credential_source_role_arn",
161					CredentialSource: credSourceEc2Metadata,
162				},
163			},
164		},
165		{
166			Filenames: []string{testConfigOtherFilename, testConfigFilename},
167			Profile:   "multiple_assume_role_with_credential_source2",
168			Expected: sharedConfig{
169				RoleARN:           "multiple_assume_role_with_credential_source2_role_arn",
170				SourceProfileName: "multiple_assume_role_with_credential_source",
171				SourceProfile: &sharedConfig{
172					RoleARN:           "multiple_assume_role_with_credential_source_role_arn",
173					SourceProfileName: "assume_role_with_credential_source",
174					SourceProfile: &sharedConfig{
175						RoleARN:          "assume_role_with_credential_source_role_arn",
176						CredentialSource: credSourceEc2Metadata,
177					},
178				},
179			},
180		},
181		{
182			Filenames: []string{testConfigFilename},
183			Profile:   "with_sts_regional",
184			Expected: sharedConfig{
185				STSRegionalEndpoint: endpoints.RegionalSTSEndpoint,
186			},
187		},
188		{
189			Filenames: []string{testConfigFilename},
190			Profile:   "with_s3_us_east_1_regional",
191			Expected: sharedConfig{
192				S3UsEast1RegionalEndpoint: endpoints.RegionalS3UsEast1Endpoint,
193			},
194		},
195	}
196
197	for i, c := range cases {
198		t.Run(strconv.Itoa(i)+"_"+c.Profile, func(t *testing.T) {
199			cfg, err := loadSharedConfig(c.Profile, c.Filenames, true)
200			if c.Err != nil {
201				if err == nil {
202					t.Fatalf("expect error, got none")
203				}
204				if e, a := c.Err.Error(), err.Error(); !strings.Contains(a, e) {
205					t.Errorf("expect %v, to be in %v", e, a)
206				}
207				return
208			}
209
210			if err != nil {
211				t.Fatalf("expect no error, got %v", err)
212			}
213			if e, a := c.Expected, cfg; !reflect.DeepEqual(e, a) {
214				t.Errorf("expect %v, got %v", e, a)
215			}
216		})
217	}
218}
219
220func TestLoadSharedConfigFromFile(t *testing.T) {
221	filename := testConfigFilename
222	f, err := ini.OpenFile(filename)
223	if err != nil {
224		t.Fatalf("failed to load test config file, %s, %v", filename, err)
225	}
226	iniFile := sharedConfigFile{IniData: f, Filename: filename}
227
228	cases := []struct {
229		Profile  string
230		Expected sharedConfig
231		Err      error
232	}{
233		{
234			Profile:  "default",
235			Expected: sharedConfig{Region: "default_region"},
236		},
237		{
238			Profile:  "alt_profile_name",
239			Expected: sharedConfig{Region: "alt_profile_name_region"},
240		},
241		{
242			Profile:  "short_profile_name_first",
243			Expected: sharedConfig{Region: "short_profile_name_first_short"},
244		},
245		{
246			Profile:  "partial_creds",
247			Expected: sharedConfig{},
248		},
249		{
250			Profile: "complete_creds",
251			Expected: sharedConfig{
252				Creds: credentials.Value{
253					AccessKeyID:     "complete_creds_akid",
254					SecretAccessKey: "complete_creds_secret",
255					ProviderName:    fmt.Sprintf("SharedConfigCredentials: %s", testConfigFilename),
256				},
257			},
258		},
259		{
260			Profile: "complete_creds_with_token",
261			Expected: sharedConfig{
262				Creds: credentials.Value{
263					AccessKeyID:     "complete_creds_with_token_akid",
264					SecretAccessKey: "complete_creds_with_token_secret",
265					SessionToken:    "complete_creds_with_token_token",
266					ProviderName:    fmt.Sprintf("SharedConfigCredentials: %s", testConfigFilename),
267				},
268			},
269		},
270		{
271			Profile: "full_profile",
272			Expected: sharedConfig{
273				Creds: credentials.Value{
274					AccessKeyID:     "full_profile_akid",
275					SecretAccessKey: "full_profile_secret",
276					ProviderName:    fmt.Sprintf("SharedConfigCredentials: %s", testConfigFilename),
277				},
278				Region: "full_profile_region",
279			},
280		},
281		{
282			Profile: "partial_assume_role",
283			Expected: sharedConfig{
284				RoleARN: "partial_assume_role_role_arn",
285			},
286		},
287		{
288			Profile: "assume_role",
289			Expected: sharedConfig{
290				RoleARN:           "assume_role_role_arn",
291				SourceProfileName: "complete_creds",
292			},
293		},
294		{
295			Profile: "assume_role_w_mfa",
296			Expected: sharedConfig{
297				RoleARN:           "assume_role_role_arn",
298				SourceProfileName: "complete_creds",
299				MFASerial:         "0123456789",
300			},
301		},
302		{
303			Profile: "does_not_exists",
304			Err:     SharedConfigProfileNotExistsError{Profile: "does_not_exists"},
305		},
306		{
307			Profile: "valid_arn_region",
308			Expected: sharedConfig{
309				S3UseARNRegion: true,
310			},
311		},
312	}
313
314	for i, c := range cases {
315		t.Run(strconv.Itoa(i)+"_"+c.Profile, func(t *testing.T) {
316			cfg := sharedConfig{}
317
318			err := cfg.setFromIniFile(c.Profile, iniFile, true)
319			if c.Err != nil {
320				if err == nil {
321					t.Fatalf("expect error, got none")
322				}
323				if e, a := c.Err.Error(), err.Error(); !strings.Contains(a, e) {
324					t.Errorf("expect %v, to be in %v", e, a)
325				}
326				return
327			}
328
329			if err != nil {
330				t.Errorf("expect no error, got %v", err)
331			}
332			if e, a := c.Expected, cfg; !reflect.DeepEqual(e, a) {
333				t.Errorf("expect %v, got %v", e, a)
334			}
335		})
336	}
337}
338
339func TestLoadSharedConfigIniFiles(t *testing.T) {
340	cases := []struct {
341		Filenames []string
342		Expected  []sharedConfigFile
343	}{
344		{
345			Filenames: []string{"not_exists", testConfigFilename},
346			Expected: []sharedConfigFile{
347				{Filename: testConfigFilename},
348			},
349		},
350		{
351			Filenames: []string{testConfigFilename, testConfigOtherFilename},
352			Expected: []sharedConfigFile{
353				{Filename: testConfigFilename},
354				{Filename: testConfigOtherFilename},
355			},
356		},
357	}
358
359	for i, c := range cases {
360		t.Run(strconv.Itoa(i), func(t *testing.T) {
361			files, err := loadSharedConfigIniFiles(c.Filenames)
362			if err != nil {
363				t.Fatalf("expect no error, got %v", err)
364			}
365			if e, a := len(c.Expected), len(files); e != a {
366				t.Errorf("expect %v, got %v", e, a)
367			}
368
369			for i, expectedFile := range c.Expected {
370				if e, a := expectedFile.Filename, files[i].Filename; e != a {
371					t.Errorf("expect %v, got %v", e, a)
372				}
373			}
374		})
375	}
376}
377