]>
Commit | Line | Data |
---|---|---|
bae9f6d2 JC |
1 | package credentials |
2 | ||
3 | import ( | |
4 | "fmt" | |
5 | "os" | |
bae9f6d2 | 6 | |
bae9f6d2 | 7 | "github.com/aws/aws-sdk-go/aws/awserr" |
107c1cdb | 8 | "github.com/aws/aws-sdk-go/internal/ini" |
9b12e4fe | 9 | "github.com/aws/aws-sdk-go/internal/shareddefaults" |
bae9f6d2 JC |
10 | ) |
11 | ||
12 | // SharedCredsProviderName provides a name of SharedCreds provider | |
13 | const SharedCredsProviderName = "SharedCredentialsProvider" | |
14 | ||
15 | var ( | |
16 | // ErrSharedCredentialsHomeNotFound is emitted when the user directory cannot be found. | |
bae9f6d2 JC |
17 | ErrSharedCredentialsHomeNotFound = awserr.New("UserHomeNotFound", "user home directory not found.", nil) |
18 | ) | |
19 | ||
20 | // A SharedCredentialsProvider retrieves credentials from the current user's home | |
21 | // directory, and keeps track if those credentials are expired. | |
22 | // | |
23 | // Profile ini file example: $HOME/.aws/credentials | |
24 | type SharedCredentialsProvider struct { | |
25 | // Path to the shared credentials file. | |
26 | // | |
27 | // If empty will look for "AWS_SHARED_CREDENTIALS_FILE" env variable. If the | |
28 | // env value is empty will default to current user's home directory. | |
29 | // Linux/OSX: "$HOME/.aws/credentials" | |
30 | // Windows: "%USERPROFILE%\.aws\credentials" | |
31 | Filename string | |
32 | ||
33 | // AWS Profile to extract credentials from the shared credentials file. If empty | |
34 | // will default to environment variable "AWS_PROFILE" or "default" if | |
35 | // environment variable is also not set. | |
36 | Profile string | |
37 | ||
38 | // retrieved states if the credentials have been successfully retrieved. | |
39 | retrieved bool | |
40 | } | |
41 | ||
42 | // NewSharedCredentials returns a pointer to a new Credentials object | |
43 | // wrapping the Profile file provider. | |
44 | func NewSharedCredentials(filename, profile string) *Credentials { | |
45 | return NewCredentials(&SharedCredentialsProvider{ | |
46 | Filename: filename, | |
47 | Profile: profile, | |
48 | }) | |
49 | } | |
50 | ||
51 | // Retrieve reads and extracts the shared credentials from the current | |
52 | // users home directory. | |
53 | func (p *SharedCredentialsProvider) Retrieve() (Value, error) { | |
54 | p.retrieved = false | |
55 | ||
56 | filename, err := p.filename() | |
57 | if err != nil { | |
58 | return Value{ProviderName: SharedCredsProviderName}, err | |
59 | } | |
60 | ||
61 | creds, err := loadProfile(filename, p.profile()) | |
62 | if err != nil { | |
63 | return Value{ProviderName: SharedCredsProviderName}, err | |
64 | } | |
65 | ||
66 | p.retrieved = true | |
67 | return creds, nil | |
68 | } | |
69 | ||
70 | // IsExpired returns if the shared credentials have expired. | |
71 | func (p *SharedCredentialsProvider) IsExpired() bool { | |
72 | return !p.retrieved | |
73 | } | |
74 | ||
75 | // loadProfiles loads from the file pointed to by shared credentials filename for profile. | |
76 | // The credentials retrieved from the profile will be returned or error. Error will be | |
77 | // returned if it fails to read from the file, or the data is invalid. | |
78 | func loadProfile(filename, profile string) (Value, error) { | |
107c1cdb | 79 | config, err := ini.OpenFile(filename) |
bae9f6d2 JC |
80 | if err != nil { |
81 | return Value{ProviderName: SharedCredsProviderName}, awserr.New("SharedCredsLoad", "failed to load shared credentials file", err) | |
82 | } | |
107c1cdb ND |
83 | |
84 | iniProfile, ok := config.GetSection(profile) | |
85 | if !ok { | |
86 | return Value{ProviderName: SharedCredsProviderName}, awserr.New("SharedCredsLoad", "failed to get profile", nil) | |
bae9f6d2 JC |
87 | } |
88 | ||
107c1cdb ND |
89 | id := iniProfile.String("aws_access_key_id") |
90 | if len(id) == 0 { | |
bae9f6d2 JC |
91 | return Value{ProviderName: SharedCredsProviderName}, awserr.New("SharedCredsAccessKey", |
92 | fmt.Sprintf("shared credentials %s in %s did not contain aws_access_key_id", profile, filename), | |
107c1cdb | 93 | nil) |
bae9f6d2 JC |
94 | } |
95 | ||
107c1cdb ND |
96 | secret := iniProfile.String("aws_secret_access_key") |
97 | if len(secret) == 0 { | |
bae9f6d2 JC |
98 | return Value{ProviderName: SharedCredsProviderName}, awserr.New("SharedCredsSecret", |
99 | fmt.Sprintf("shared credentials %s in %s did not contain aws_secret_access_key", profile, filename), | |
100 | nil) | |
101 | } | |
102 | ||
103 | // Default to empty string if not found | |
107c1cdb | 104 | token := iniProfile.String("aws_session_token") |
bae9f6d2 JC |
105 | |
106 | return Value{ | |
107c1cdb ND |
107 | AccessKeyID: id, |
108 | SecretAccessKey: secret, | |
109 | SessionToken: token, | |
bae9f6d2 JC |
110 | ProviderName: SharedCredsProviderName, |
111 | }, nil | |
112 | } | |
113 | ||
114 | // filename returns the filename to use to read AWS shared credentials. | |
115 | // | |
116 | // Will return an error if the user's home directory path cannot be found. | |
117 | func (p *SharedCredentialsProvider) filename() (string, error) { | |
9b12e4fe JC |
118 | if len(p.Filename) != 0 { |
119 | return p.Filename, nil | |
120 | } | |
121 | ||
122 | if p.Filename = os.Getenv("AWS_SHARED_CREDENTIALS_FILE"); len(p.Filename) != 0 { | |
123 | return p.Filename, nil | |
bae9f6d2 JC |
124 | } |
125 | ||
9b12e4fe JC |
126 | if home := shareddefaults.UserHomeDir(); len(home) == 0 { |
127 | // Backwards compatibility of home directly not found error being returned. | |
128 | // This error is too verbose, failure when opening the file would of been | |
129 | // a better error to return. | |
130 | return "", ErrSharedCredentialsHomeNotFound | |
131 | } | |
132 | ||
133 | p.Filename = shareddefaults.SharedCredentialsFilename() | |
134 | ||
bae9f6d2 JC |
135 | return p.Filename, nil |
136 | } | |
137 | ||
138 | // profile returns the AWS shared credentials profile. If empty will read | |
139 | // environment variable "AWS_PROFILE". If that is not set profile will | |
140 | // return "default". | |
141 | func (p *SharedCredentialsProvider) profile() string { | |
142 | if p.Profile == "" { | |
143 | p.Profile = os.Getenv("AWS_PROFILE") | |
144 | } | |
145 | if p.Profile == "" { | |
146 | p.Profile = "default" | |
147 | } | |
148 | ||
149 | return p.Profile | |
150 | } |