Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(766)

Side by Side Diff: third_party/boto/auth.py

Issue 12633019: Added boto/ to depot_tools/third_party (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: Moved boto down by one Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « third_party/boto/__init__.py ('k') | third_party/boto/auth_handler.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # Copyright 2010 Google Inc.
2 # Copyright (c) 2011 Mitch Garnaat http://garnaat.org/
3 # Copyright (c) 2011, Eucalyptus Systems, Inc.
4 #
5 # Permission is hereby granted, free of charge, to any person obtaining a
6 # copy of this software and associated documentation files (the
7 # "Software"), to deal in the Software without restriction, including
8 # without limitation the rights to use, copy, modify, merge, publish, dis-
9 # tribute, sublicense, and/or sell copies of the Software, and to permit
10 # persons to whom the Software is furnished to do so, subject to the fol-
11 # lowing conditions:
12 #
13 # The above copyright notice and this permission notice shall be included
14 # in all copies or substantial portions of the Software.
15 #
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
18 # ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
19 # SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 # IN THE SOFTWARE.
23
24
25 """
26 Handles authentication required to AWS and GS
27 """
28
29 import base64
30 import boto
31 import boto.auth_handler
32 import boto.exception
33 import boto.plugin
34 import boto.utils
35 import hmac
36 import sys
37 import urllib
38 import time
39 import datetime
40 import copy
41 from email.utils import formatdate
42
43 from boto.auth_handler import AuthHandler
44 from boto.exception import BotoClientError
45 #
46 # the following is necessary because of the incompatibilities
47 # between Python 2.4, 2.5, and 2.6 as well as the fact that some
48 # people running 2.4 have installed hashlib as a separate module
49 # this fix was provided by boto user mccormix.
50 # see: http://code.google.com/p/boto/issues/detail?id=172
51 # for more details.
52 #
53 try:
54 from hashlib import sha1 as sha
55 from hashlib import sha256 as sha256
56
57 if sys.version[:3] == "2.4":
58 # we are using an hmac that expects a .new() method.
59 class Faker:
60 def __init__(self, which):
61 self.which = which
62 self.digest_size = self.which().digest_size
63
64 def new(self, *args, **kwargs):
65 return self.which(*args, **kwargs)
66
67 sha = Faker(sha)
68 sha256 = Faker(sha256)
69
70 except ImportError:
71 import sha
72 sha256 = None
73
74
75 class HmacKeys(object):
76 """Key based Auth handler helper."""
77
78 def __init__(self, host, config, provider):
79 if provider.access_key is None or provider.secret_key is None:
80 raise boto.auth_handler.NotReadyToAuthenticate()
81 self.host = host
82 self.update_provider(provider)
83
84 def update_provider(self, provider):
85 self._provider = provider
86 self._hmac = hmac.new(self._provider.secret_key, digestmod=sha)
87 if sha256:
88 self._hmac_256 = hmac.new(self._provider.secret_key,
89 digestmod=sha256)
90 else:
91 self._hmac_256 = None
92
93 def algorithm(self):
94 if self._hmac_256:
95 return 'HmacSHA256'
96 else:
97 return 'HmacSHA1'
98
99 def _get_hmac(self):
100 if self._hmac_256:
101 digestmod = sha256
102 else:
103 digestmod = sha
104 return hmac.new(self._provider.secret_key,
105 digestmod=digestmod)
106
107 def sign_string(self, string_to_sign):
108 new_hmac = self._get_hmac()
109 new_hmac.update(string_to_sign)
110 return base64.encodestring(new_hmac.digest()).strip()
111
112 def __getstate__(self):
113 pickled_dict = copy.copy(self.__dict__)
114 del pickled_dict['_hmac']
115 del pickled_dict['_hmac_256']
116 return pickled_dict
117
118 def __setstate__(self, dct):
119 self.__dict__ = dct
120 self.update_provider(self._provider)
121
122
123 class AnonAuthHandler(AuthHandler, HmacKeys):
124 """
125 Implements Anonymous requests.
126 """
127
128 capability = ['anon']
129
130 def __init__(self, host, config, provider):
131 AuthHandler.__init__(self, host, config, provider)
132
133 def add_auth(self, http_request, **kwargs):
134 pass
135
136
137 class HmacAuthV1Handler(AuthHandler, HmacKeys):
138 """ Implements the HMAC request signing used by S3 and GS."""
139
140 capability = ['hmac-v1', 's3']
141
142 def __init__(self, host, config, provider):
143 AuthHandler.__init__(self, host, config, provider)
144 HmacKeys.__init__(self, host, config, provider)
145 self._hmac_256 = None
146
147 def update_provider(self, provider):
148 super(HmacAuthV1Handler, self).update_provider(provider)
149 self._hmac_256 = None
150
151 def add_auth(self, http_request, **kwargs):
152 headers = http_request.headers
153 method = http_request.method
154 auth_path = http_request.auth_path
155 if 'Date' not in headers:
156 headers['Date'] = formatdate(usegmt=True)
157
158 if self._provider.security_token:
159 key = self._provider.security_token_header
160 headers[key] = self._provider.security_token
161 string_to_sign = boto.utils.canonical_string(method, auth_path,
162 headers, None,
163 self._provider)
164 boto.log.debug('StringToSign:\n%s' % string_to_sign)
165 b64_hmac = self.sign_string(string_to_sign)
166 auth_hdr = self._provider.auth_header
167 headers['Authorization'] = ("%s %s:%s" %
168 (auth_hdr,
169 self._provider.access_key, b64_hmac))
170
171
172 class HmacAuthV2Handler(AuthHandler, HmacKeys):
173 """
174 Implements the simplified HMAC authorization used by CloudFront.
175 """
176 capability = ['hmac-v2', 'cloudfront']
177
178 def __init__(self, host, config, provider):
179 AuthHandler.__init__(self, host, config, provider)
180 HmacKeys.__init__(self, host, config, provider)
181 self._hmac_256 = None
182
183 def update_provider(self, provider):
184 super(HmacAuthV2Handler, self).update_provider(provider)
185 self._hmac_256 = None
186
187 def add_auth(self, http_request, **kwargs):
188 headers = http_request.headers
189 if 'Date' not in headers:
190 headers['Date'] = formatdate(usegmt=True)
191 if self._provider.security_token:
192 key = self._provider.security_token_header
193 headers[key] = self._provider.security_token
194
195 b64_hmac = self.sign_string(headers['Date'])
196 auth_hdr = self._provider.auth_header
197 headers['Authorization'] = ("%s %s:%s" %
198 (auth_hdr,
199 self._provider.access_key, b64_hmac))
200
201
202 class HmacAuthV3Handler(AuthHandler, HmacKeys):
203 """Implements the new Version 3 HMAC authorization used by Route53."""
204
205 capability = ['hmac-v3', 'route53', 'ses']
206
207 def __init__(self, host, config, provider):
208 AuthHandler.__init__(self, host, config, provider)
209 HmacKeys.__init__(self, host, config, provider)
210
211 def add_auth(self, http_request, **kwargs):
212 headers = http_request.headers
213 if 'Date' not in headers:
214 headers['Date'] = formatdate(usegmt=True)
215
216 if self._provider.security_token:
217 key = self._provider.security_token_header
218 headers[key] = self._provider.security_token
219
220 b64_hmac = self.sign_string(headers['Date'])
221 s = "AWS3-HTTPS AWSAccessKeyId=%s," % self._provider.access_key
222 s += "Algorithm=%s,Signature=%s" % (self.algorithm(), b64_hmac)
223 headers['X-Amzn-Authorization'] = s
224
225
226 class HmacAuthV3HTTPHandler(AuthHandler, HmacKeys):
227 """
228 Implements the new Version 3 HMAC authorization used by DynamoDB.
229 """
230
231 capability = ['hmac-v3-http']
232
233 def __init__(self, host, config, provider):
234 AuthHandler.__init__(self, host, config, provider)
235 HmacKeys.__init__(self, host, config, provider)
236
237 def headers_to_sign(self, http_request):
238 """
239 Select the headers from the request that need to be included
240 in the StringToSign.
241 """
242 headers_to_sign = {}
243 headers_to_sign = {'Host': self.host}
244 for name, value in http_request.headers.items():
245 lname = name.lower()
246 if lname.startswith('x-amz'):
247 headers_to_sign[name] = value
248 return headers_to_sign
249
250 def canonical_headers(self, headers_to_sign):
251 """
252 Return the headers that need to be included in the StringToSign
253 in their canonical form by converting all header keys to lower
254 case, sorting them in alphabetical order and then joining
255 them into a string, separated by newlines.
256 """
257 l = sorted(['%s:%s' % (n.lower().strip(),
258 headers_to_sign[n].strip()) for n in headers_to_sign])
259 return '\n'.join(l)
260
261 def string_to_sign(self, http_request):
262 """
263 Return the canonical StringToSign as well as a dict
264 containing the original version of all headers that
265 were included in the StringToSign.
266 """
267 headers_to_sign = self.headers_to_sign(http_request)
268 canonical_headers = self.canonical_headers(headers_to_sign)
269 string_to_sign = '\n'.join([http_request.method,
270 http_request.auth_path,
271 '',
272 canonical_headers,
273 '',
274 http_request.body])
275 return string_to_sign, headers_to_sign
276
277 def add_auth(self, req, **kwargs):
278 """
279 Add AWS3 authentication to a request.
280
281 :type req: :class`boto.connection.HTTPRequest`
282 :param req: The HTTPRequest object.
283 """
284 # This could be a retry. Make sure the previous
285 # authorization header is removed first.
286 if 'X-Amzn-Authorization' in req.headers:
287 del req.headers['X-Amzn-Authorization']
288 req.headers['X-Amz-Date'] = formatdate(usegmt=True)
289 if self._provider.security_token:
290 req.headers['X-Amz-Security-Token'] = self._provider.security_token
291 string_to_sign, headers_to_sign = self.string_to_sign(req)
292 boto.log.debug('StringToSign:\n%s' % string_to_sign)
293 hash_value = sha256(string_to_sign).digest()
294 b64_hmac = self.sign_string(hash_value)
295 s = "AWS3 AWSAccessKeyId=%s," % self._provider.access_key
296 s += "Algorithm=%s," % self.algorithm()
297 s += "SignedHeaders=%s," % ';'.join(headers_to_sign)
298 s += "Signature=%s" % b64_hmac
299 req.headers['X-Amzn-Authorization'] = s
300
301
302 class HmacAuthV4Handler(AuthHandler, HmacKeys):
303 """
304 Implements the new Version 4 HMAC authorization.
305 """
306
307 capability = ['hmac-v4']
308
309 def __init__(self, host, config, provider,
310 service_name=None, region_name=None):
311 AuthHandler.__init__(self, host, config, provider)
312 HmacKeys.__init__(self, host, config, provider)
313 # You can set the service_name and region_name to override the
314 # values which would otherwise come from the endpoint, e.g.
315 # <service>.<region>.amazonaws.com.
316 self.service_name = service_name
317 self.region_name = region_name
318
319 def _sign(self, key, msg, hex=False):
320 if hex:
321 sig = hmac.new(key, msg.encode('utf-8'), sha256).hexdigest()
322 else:
323 sig = hmac.new(key, msg.encode('utf-8'), sha256).digest()
324 return sig
325
326 def headers_to_sign(self, http_request):
327 """
328 Select the headers from the request that need to be included
329 in the StringToSign.
330 """
331 headers_to_sign = {}
332 headers_to_sign = {'Host': self.host}
333 for name, value in http_request.headers.items():
334 lname = name.lower()
335 if lname.startswith('x-amz'):
336 headers_to_sign[name] = value
337 return headers_to_sign
338
339 def query_string(self, http_request):
340 parameter_names = sorted(http_request.params.keys())
341 pairs = []
342 for pname in parameter_names:
343 pval = str(http_request.params[pname]).encode('utf-8')
344 pairs.append(urllib.quote(pname, safe='') + '=' +
345 urllib.quote(pval, safe='-_~'))
346 return '&'.join(pairs)
347
348 def canonical_query_string(self, http_request):
349 # POST requests pass parameters in through the
350 # http_request.body field.
351 if http_request.method == 'POST':
352 return ""
353 l = []
354 for param in sorted(http_request.params):
355 value = str(http_request.params[param])
356 l.append('%s=%s' % (urllib.quote(param, safe='-_.~'),
357 urllib.quote(value, safe='-_.~')))
358 return '&'.join(l)
359
360 def canonical_headers(self, headers_to_sign):
361 """
362 Return the headers that need to be included in the StringToSign
363 in their canonical form by converting all header keys to lower
364 case, sorting them in alphabetical order and then joining
365 them into a string, separated by newlines.
366 """
367 l = sorted(['%s:%s' % (n.lower().strip(),
368 ' '.join(headers_to_sign[n].strip().split()))
369 for n in headers_to_sign])
370 return '\n'.join(l)
371
372 def signed_headers(self, headers_to_sign):
373 l = ['%s' % n.lower().strip() for n in headers_to_sign]
374 l = sorted(l)
375 return ';'.join(l)
376
377 def canonical_uri(self, http_request):
378 return http_request.auth_path
379
380 def payload(self, http_request):
381 body = http_request.body
382 # If the body is a file like object, we can use
383 # boto.utils.compute_hash, which will avoid reading
384 # the entire body into memory.
385 if hasattr(body, 'seek') and hasattr(body, 'read'):
386 return boto.utils.compute_hash(body, hash_algorithm=sha256)[0]
387 return sha256(http_request.body).hexdigest()
388
389 def canonical_request(self, http_request):
390 cr = [http_request.method.upper()]
391 cr.append(self.canonical_uri(http_request))
392 cr.append(self.canonical_query_string(http_request))
393 headers_to_sign = self.headers_to_sign(http_request)
394 cr.append(self.canonical_headers(headers_to_sign) + '\n')
395 cr.append(self.signed_headers(headers_to_sign))
396 cr.append(self.payload(http_request))
397 return '\n'.join(cr)
398
399 def scope(self, http_request):
400 scope = [self._provider.access_key]
401 scope.append(http_request.timestamp)
402 scope.append(http_request.region_name)
403 scope.append(http_request.service_name)
404 scope.append('aws4_request')
405 return '/'.join(scope)
406
407 def credential_scope(self, http_request):
408 scope = []
409 http_request.timestamp = http_request.headers['X-Amz-Date'][0:8]
410 scope.append(http_request.timestamp)
411 # The service_name and region_name either come from:
412 # * The service_name/region_name attrs or (if these values are None)
413 # * parsed from the endpoint <service>.<region>.amazonaws.com.
414 parts = http_request.host.split('.')
415 if self.region_name is not None:
416 region_name = self.region_name
417 else:
418 if len(parts) == 3:
419 region_name = 'us-east-1'
420 else:
421 region_name = parts[1]
422 if self.service_name is not None:
423 service_name = self.service_name
424 else:
425 service_name = parts[0]
426
427 http_request.service_name = service_name
428 http_request.region_name = region_name
429
430 scope.append(http_request.region_name)
431 scope.append(http_request.service_name)
432 scope.append('aws4_request')
433 return '/'.join(scope)
434
435 def string_to_sign(self, http_request, canonical_request):
436 """
437 Return the canonical StringToSign as well as a dict
438 containing the original version of all headers that
439 were included in the StringToSign.
440 """
441 sts = ['AWS4-HMAC-SHA256']
442 sts.append(http_request.headers['X-Amz-Date'])
443 sts.append(self.credential_scope(http_request))
444 sts.append(sha256(canonical_request).hexdigest())
445 return '\n'.join(sts)
446
447 def signature(self, http_request, string_to_sign):
448 key = self._provider.secret_key
449 k_date = self._sign(('AWS4' + key).encode('utf-8'),
450 http_request.timestamp)
451 k_region = self._sign(k_date, http_request.region_name)
452 k_service = self._sign(k_region, http_request.service_name)
453 k_signing = self._sign(k_service, 'aws4_request')
454 return self._sign(k_signing, string_to_sign, hex=True)
455
456 def add_auth(self, req, **kwargs):
457 """
458 Add AWS4 authentication to a request.
459
460 :type req: :class`boto.connection.HTTPRequest`
461 :param req: The HTTPRequest object.
462 """
463 # This could be a retry. Make sure the previous
464 # authorization header is removed first.
465 if 'X-Amzn-Authorization' in req.headers:
466 del req.headers['X-Amzn-Authorization']
467 now = datetime.datetime.utcnow()
468 req.headers['X-Amz-Date'] = now.strftime('%Y%m%dT%H%M%SZ')
469 if self._provider.security_token:
470 req.headers['X-Amz-Security-Token'] = self._provider.security_token
471 qs = self.query_string(req)
472 if qs and req.method == 'POST':
473 # Stash request parameters into post body
474 # before we generate the signature.
475 req.body = qs
476 req.headers['Content-Type'] = 'application/x-www-form-urlencoded; ch arset=UTF-8'
477 req.headers['Content-Length'] = str(len(req.body))
478 else:
479 # Safe to modify req.path here since
480 # the signature will use req.auth_path.
481 req.path = req.path.split('?')[0]
482 req.path = req.path + '?' + qs
483 canonical_request = self.canonical_request(req)
484 boto.log.debug('CanonicalRequest:\n%s' % canonical_request)
485 string_to_sign = self.string_to_sign(req, canonical_request)
486 boto.log.debug('StringToSign:\n%s' % string_to_sign)
487 signature = self.signature(req, string_to_sign)
488 boto.log.debug('Signature:\n%s' % signature)
489 headers_to_sign = self.headers_to_sign(req)
490 l = ['AWS4-HMAC-SHA256 Credential=%s' % self.scope(req)]
491 l.append('SignedHeaders=%s' % self.signed_headers(headers_to_sign))
492 l.append('Signature=%s' % signature)
493 req.headers['Authorization'] = ','.join(l)
494
495
496 class QuerySignatureHelper(HmacKeys):
497 """
498 Helper for Query signature based Auth handler.
499
500 Concrete sub class need to implement _calc_sigature method.
501 """
502
503 def add_auth(self, http_request, **kwargs):
504 headers = http_request.headers
505 params = http_request.params
506 params['AWSAccessKeyId'] = self._provider.access_key
507 params['SignatureVersion'] = self.SignatureVersion
508 params['Timestamp'] = boto.utils.get_ts()
509 qs, signature = self._calc_signature(
510 http_request.params, http_request.method,
511 http_request.auth_path, http_request.host)
512 boto.log.debug('query_string: %s Signature: %s' % (qs, signature))
513 if http_request.method == 'POST':
514 headers['Content-Type'] = 'application/x-www-form-urlencoded; charse t=UTF-8'
515 http_request.body = qs + '&Signature=' + urllib.quote_plus(signature )
516 http_request.headers['Content-Length'] = str(len(http_request.body))
517 else:
518 http_request.body = ''
519 # if this is a retried request, the qs from the previous try will
520 # already be there, we need to get rid of that and rebuild it
521 http_request.path = http_request.path.split('?')[0]
522 http_request.path = (http_request.path + '?' + qs +
523 '&Signature=' + urllib.quote_plus(signature))
524
525
526 class QuerySignatureV0AuthHandler(QuerySignatureHelper, AuthHandler):
527 """Provides Signature V0 Signing"""
528
529 SignatureVersion = 0
530 capability = ['sign-v0']
531
532 def _calc_signature(self, params, *args):
533 boto.log.debug('using _calc_signature_0')
534 hmac = self._get_hmac()
535 s = params['Action'] + params['Timestamp']
536 hmac.update(s)
537 keys = params.keys()
538 keys.sort(cmp=lambda x, y: cmp(x.lower(), y.lower()))
539 pairs = []
540 for key in keys:
541 val = boto.utils.get_utf8_value(params[key])
542 pairs.append(key + '=' + urllib.quote(val))
543 qs = '&'.join(pairs)
544 return (qs, base64.b64encode(hmac.digest()))
545
546
547 class QuerySignatureV1AuthHandler(QuerySignatureHelper, AuthHandler):
548 """
549 Provides Query Signature V1 Authentication.
550 """
551
552 SignatureVersion = 1
553 capability = ['sign-v1', 'mturk']
554
555 def __init__(self, *args, **kw):
556 QuerySignatureHelper.__init__(self, *args, **kw)
557 AuthHandler.__init__(self, *args, **kw)
558 self._hmac_256 = None
559
560 def _calc_signature(self, params, *args):
561 boto.log.debug('using _calc_signature_1')
562 hmac = self._get_hmac()
563 keys = params.keys()
564 keys.sort(cmp=lambda x, y: cmp(x.lower(), y.lower()))
565 pairs = []
566 for key in keys:
567 hmac.update(key)
568 val = boto.utils.get_utf8_value(params[key])
569 hmac.update(val)
570 pairs.append(key + '=' + urllib.quote(val))
571 qs = '&'.join(pairs)
572 return (qs, base64.b64encode(hmac.digest()))
573
574
575 class QuerySignatureV2AuthHandler(QuerySignatureHelper, AuthHandler):
576 """Provides Query Signature V2 Authentication."""
577
578 SignatureVersion = 2
579 capability = ['sign-v2', 'ec2', 'ec2', 'emr', 'fps', 'ecs',
580 'sdb', 'iam', 'rds', 'sns', 'sqs', 'cloudformation']
581
582 def _calc_signature(self, params, verb, path, server_name):
583 boto.log.debug('using _calc_signature_2')
584 string_to_sign = '%s\n%s\n%s\n' % (verb, server_name.lower(), path)
585 hmac = self._get_hmac()
586 params['SignatureMethod'] = self.algorithm()
587 if self._provider.security_token:
588 params['SecurityToken'] = self._provider.security_token
589 keys = sorted(params.keys())
590 pairs = []
591 for key in keys:
592 val = boto.utils.get_utf8_value(params[key])
593 pairs.append(urllib.quote(key, safe='') + '=' +
594 urllib.quote(val, safe='-_~'))
595 qs = '&'.join(pairs)
596 boto.log.debug('query string: %s' % qs)
597 string_to_sign += qs
598 boto.log.debug('string_to_sign: %s' % string_to_sign)
599 hmac.update(string_to_sign)
600 b64 = base64.b64encode(hmac.digest())
601 boto.log.debug('len(b64)=%d' % len(b64))
602 boto.log.debug('base64 encoded digest: %s' % b64)
603 return (qs, b64)
604
605
606 class POSTPathQSV2AuthHandler(QuerySignatureV2AuthHandler, AuthHandler):
607 """
608 Query Signature V2 Authentication relocating signed query
609 into the path and allowing POST requests with Content-Types.
610 """
611
612 capability = ['mws']
613
614 def add_auth(self, req, **kwargs):
615 req.params['AWSAccessKeyId'] = self._provider.access_key
616 req.params['SignatureVersion'] = self.SignatureVersion
617 req.params['Timestamp'] = boto.utils.get_ts()
618 qs, signature = self._calc_signature(req.params, req.method,
619 req.auth_path, req.host)
620 boto.log.debug('query_string: %s Signature: %s' % (qs, signature))
621 if req.method == 'POST':
622 req.headers['Content-Length'] = str(len(req.body))
623 req.headers['Content-Type'] = req.headers.get('Content-Type',
624 'text/plain')
625 else:
626 req.body = ''
627 # if this is a retried req, the qs from the previous try will
628 # already be there, we need to get rid of that and rebuild it
629 req.path = req.path.split('?')[0]
630 req.path = (req.path + '?' + qs +
631 '&Signature=' + urllib.quote_plus(signature))
632
633
634 def get_auth_handler(host, config, provider, requested_capability=None):
635 """Finds an AuthHandler that is ready to authenticate.
636
637 Lists through all the registered AuthHandlers to find one that is willing
638 to handle for the requested capabilities, config and provider.
639
640 :type host: string
641 :param host: The name of the host
642
643 :type config:
644 :param config:
645
646 :type provider:
647 :param provider:
648
649 Returns:
650 An implementation of AuthHandler.
651
652 Raises:
653 boto.exception.NoAuthHandlerFound
654 """
655 ready_handlers = []
656 auth_handlers = boto.plugin.get_plugin(AuthHandler, requested_capability)
657 total_handlers = len(auth_handlers)
658 for handler in auth_handlers:
659 try:
660 ready_handlers.append(handler(host, config, provider))
661 except boto.auth_handler.NotReadyToAuthenticate:
662 pass
663
664 if not ready_handlers:
665 checked_handlers = auth_handlers
666 names = [handler.__name__ for handler in checked_handlers]
667 raise boto.exception.NoAuthHandlerFound(
668 'No handler was ready to authenticate. %d handlers were checked.'
669 ' %s '
670 'Check your credentials' % (len(names), str(names)))
671
672 # We select the last ready auth handler that was loaded, to allow users to
673 # customize how auth works in environments where there are shared boto
674 # config files (e.g., /etc/boto.cfg and ~/.boto): The more general,
675 # system-wide shared configs should be loaded first, and the user's
676 # customizations loaded last. That way, for example, the system-wide
677 # config might include a plugin_directory that includes a service account
678 # auth plugin shared by all users of a Google Compute Engine instance
679 # (allowing sharing of non-user data between various services), and the
680 # user could override this with a .boto config that includes user-specific
681 # credentials (for access to user data).
682 return ready_handlers[-1]
OLDNEW
« no previous file with comments | « third_party/boto/__init__.py ('k') | third_party/boto/auth_handler.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698