18
18
module Mongo
19
19
module Auth
20
20
class Aws
21
-
22
21
# Raised when trying to authorize with an invalid configuration
23
22
#
24
23
# @api private
@@ -51,15 +50,17 @@ def initialize
51
50
#
52
51
# @api private
53
52
class CredentialsRetriever
54
-
55
53
# Timeout for metadata operations, in seconds.
56
54
#
57
55
# The auth spec suggests a 10 second timeout but this seems
58
56
# excessively long given that the endpoint is essentially local.
59
57
METADATA_TIMEOUT = 5
60
58
61
- def initialize ( user = nil )
59
+ # @param [ Auth::User | nil ] user The user object, if one was provided.
60
+ # @param [ Auth::Aws::CredentialsCache ] credentials_cache The credentials cache.
61
+ def initialize ( user = nil , credentials_cache : CredentialsCache . instance )
62
62
@user = user
63
+ @credentials_cache = credentials_cache
63
64
end
64
65
65
66
# @return [ Auth::User | nil ] The user object, if one was provided.
@@ -70,55 +71,77 @@ def initialize(user = nil)
70
71
#
71
72
# @return [ Auth::Aws::Credentials ] A valid set of credentials.
72
73
#
73
- # @raise Auth::InvalidConfiguration if credentials could not be
74
- # retrieved for any reason, or if a source contains an invalid set
74
+ # @raise Auth::InvalidConfiguration if a source contains an invalid set
75
75
# of credentials.
76
+ # @raise Auth::Aws::CredentialsNotFound if credentials could not be
77
+ # retrieved from any source.
76
78
def credentials
77
- if user
78
- credentials = Credentials . new (
79
- user . name ,
80
- user . password ,
81
- user . auth_mech_properties [ 'aws_session_token' ] ,
82
- )
83
-
84
- if credentials_valid? ( credentials , 'Mongo::Client URI or Ruby options' )
85
- return credentials
86
- end
87
- end
79
+ credentials = credentials_from_user ( user )
80
+ return credentials unless credentials . nil?
88
81
89
- credentials = Credentials . new (
90
- ENV [ 'AWS_ACCESS_KEY_ID' ] ,
91
- ENV [ 'AWS_SECRET_ACCESS_KEY' ] ,
92
- ENV [ 'AWS_SESSION_TOKEN' ] ,
93
- )
82
+ credentials = credentials_from_environment
83
+ return credentials unless credentials . nil?
94
84
95
- if credentials_valid? ( credentials , 'environment variables' )
96
- return credentials
97
- end
85
+ credentials = @credentials_cache . fetch { obtain_credentials_from_endpoints }
86
+ return credentials unless credentials . nil?
98
87
99
- credentials = web_identity_credentials
88
+ raise Auth ::Aws ::CredentialsNotFound
89
+ end
100
90
101
- if credentials && credentials_valid? ( credentials , 'Web identity token' )
102
- return credentials
103
- end
91
+ private
104
92
105
- credentials = ecs_metadata_credentials
93
+ # Returns credentials from the user object.
94
+ #
95
+ # @param [ Auth::User | nil ] user The user object, if one was provided.
96
+ #
97
+ # @return [ Auth::Aws::Credentials | nil ] A set of credentials, or nil
98
+ #
99
+ # @raise Auth::InvalidConfiguration if a source contains an invalid set
100
+ # of credentials.
101
+ def credentials_from_user ( user )
102
+ return nil unless user
106
103
107
- if credentials && credentials_valid? ( credentials , 'ECS task metadata' )
108
- return credentials
109
- end
104
+ credentials = Credentials . new (
105
+ user . name ,
106
+ user . password ,
107
+ user . auth_mech_properties [ 'aws_session_token' ]
108
+ )
109
+ return credentials if credentials_valid? ( credentials , 'Mongo::Client URI or Ruby options' )
110
+ end
110
111
111
- credentials = ec2_metadata_credentials
112
+ # Returns credentials from environment variables.
113
+ #
114
+ # @return [ Auth::Aws::Credentials | nil ] A set of credentials, or nil
115
+ # if retrieval failed or the obtained credentials are invalid.
116
+ #
117
+ # @raise Auth::InvalidConfiguration if a source contains an invalid set
118
+ # of credentials.
119
+ def credentials_from_environment
120
+ credentials = Credentials . new (
121
+ ENV [ 'AWS_ACCESS_KEY_ID' ] ,
122
+ ENV [ 'AWS_SECRET_ACCESS_KEY' ] ,
123
+ ENV [ 'AWS_SESSION_TOKEN' ]
124
+ )
125
+ credentials if credentials && credentials_valid? ( credentials , 'environment variables' )
126
+ end
112
127
113
- if credentials && credentials_valid? ( credentials , 'EC2 instance metadata' )
114
- return credentials
128
+ # Returns credentials from the AWS metadata endpoints.
129
+ #
130
+ # @return [ Auth::Aws::Credentials | nil ] A set of credentials, or nil
131
+ # if retrieval failed or the obtained credentials are invalid.
132
+ #
133
+ # @raise Auth::InvalidConfiguration if a source contains an invalid set
134
+ # of credentials.
135
+ def obtain_credentials_from_endpoints
136
+ if ( credentials = web_identity_credentials ) && credentials_valid? ( credentials , 'Web identity token' )
137
+ credentials
138
+ elsif ( credentials = ecs_metadata_credentials ) && credentials_valid? ( credentials , 'ECS task metadata' )
139
+ credentials
140
+ elsif ( credentials = ec2_metadata_credentials ) && credentials_valid? ( credentials , 'EC2 instance metadata' )
141
+ credentials
115
142
end
116
-
117
- raise Auth ::Aws ::CredentialsNotFound
118
143
end
119
144
120
- private
121
-
122
145
# Returns credentials from the EC2 metadata endpoint. The credentials
123
146
# could be empty, partial or invalid.
124
147
#
@@ -158,10 +181,11 @@ def ec2_metadata_credentials
158
181
payload [ 'AccessKeyId' ] ,
159
182
payload [ 'SecretAccessKey' ] ,
160
183
payload [ 'Token' ] ,
184
+ DateTime . parse ( payload [ 'Expiration' ] ) . to_time
161
185
)
162
186
# When trying to use the EC2 metadata endpoint on ECS:
163
187
# Errno::EINVAL: Failed to open TCP connection to 169.254.169.254:80 (Invalid argument - connect(2) for "169.254.169.254" port 80)
164
- rescue ::Timeout ::Error , IOError , SystemCallError
188
+ rescue ::Timeout ::Error , IOError , SystemCallError , TypeError
165
189
return nil
166
190
end
167
191
@@ -190,8 +214,9 @@ def ecs_metadata_credentials
190
214
payload [ 'AccessKeyId' ] ,
191
215
payload [ 'SecretAccessKey' ] ,
192
216
payload [ 'Token' ] ,
217
+ DateTime . parse ( payload [ 'Expiration' ] ) . to_time
193
218
)
194
- rescue ::Timeout ::Error , IOError , SystemCallError
219
+ rescue ::Timeout ::Error , IOError , SystemCallError , TypeError
195
220
return nil
196
221
end
197
222
@@ -284,8 +309,9 @@ def credentials_from_web_identity_response(response)
284
309
payload [ 'AccessKeyId' ] ,
285
310
payload [ 'SecretAccessKey' ] ,
286
311
payload [ 'SessionToken' ] ,
312
+ Time . at ( payload [ 'Expiration' ] )
287
313
)
288
- rescue JSON ::ParserError
314
+ rescue JSON ::ParserError , TypeError
289
315
nil
290
316
end
291
317
0 commit comments