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

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

Issue 12042069: Scripts to download files from google storage based on sha1 sums (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/depot_tools.git@master
Patch Set: Removed gsutil/tests and gsutil/docs Created 7 years, 10 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
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
192 b64_hmac = self.sign_string(headers['Date'])
193 auth_hdr = self._provider.auth_header
194 headers['Authorization'] = ("%s %s:%s" %
195 (auth_hdr,
196 self._provider.access_key, b64_hmac))
197
198
199 class HmacAuthV3Handler(AuthHandler, HmacKeys):
200 """Implements the new Version 3 HMAC authorization used by Route53."""
201
202 capability = ['hmac-v3', 'route53', 'ses']
203
204 def __init__(self, host, config, provider):
205 AuthHandler.__init__(self, host, config, provider)
206 HmacKeys.__init__(self, host, config, provider)
207
208 def add_auth(self, http_request, **kwargs):
209 headers = http_request.headers
210 if 'Date' not in headers:
211 headers['Date'] = formatdate(usegmt=True)
212
213 if self._provider.security_token:
214 key = self._provider.security_token_header
215 headers[key] = self._provider.security_token
216
217 b64_hmac = self.sign_string(headers['Date'])
218 s = "AWS3-HTTPS AWSAccessKeyId=%s," % self._provider.access_key
219 s += "Algorithm=%s,Signature=%s" % (self.algorithm(), b64_hmac)
220 headers['X-Amzn-Authorization'] = s
221
222
223 class HmacAuthV3HTTPHandler(AuthHandler, HmacKeys):
224 """
225 Implements the new Version 3 HMAC authorization used by DynamoDB.
226 """
227
228 capability = ['hmac-v3-http']
229
230 def __init__(self, host, config, provider):
231 AuthHandler.__init__(self, host, config, provider)
232 HmacKeys.__init__(self, host, config, provider)
233
234 def headers_to_sign(self, http_request):
235 """
236 Select the headers from the request that need to be included
237 in the StringToSign.
238 """
239 headers_to_sign = {}
240 headers_to_sign = {'Host': self.host}
241 for name, value in http_request.headers.items():
242 lname = name.lower()
243 if lname.startswith('x-amz'):
244 headers_to_sign[name] = value
245 return headers_to_sign
246
247 def canonical_headers(self, headers_to_sign):
248 """
249 Return the headers that need to be included in the StringToSign
250 in their canonical form by converting all header keys to lower
251 case, sorting them in alphabetical order and then joining
252 them into a string, separated by newlines.
253 """
254 l = sorted(['%s:%s' % (n.lower().strip(),
255 headers_to_sign[n].strip()) for n in headers_to_sign])
256 return '\n'.join(l)
257
258 def string_to_sign(self, http_request):
259 """
260 Return the canonical StringToSign as well as a dict
261 containing the original version of all headers that
262 were included in the StringToSign.
263 """
264 headers_to_sign = self.headers_to_sign(http_request)
265 canonical_headers = self.canonical_headers(headers_to_sign)
266 string_to_sign = '\n'.join([http_request.method,
267 http_request.auth_path,
268 '',
269 canonical_headers,
270 '',
271 http_request.body])
272 return string_to_sign, headers_to_sign
273
274 def add_auth(self, req, **kwargs):
275 """
276 Add AWS3 authentication to a request.
277
278 :type req: :class`boto.connection.HTTPRequest`
279 :param req: The HTTPRequest object.
280 """
281 # This could be a retry. Make sure the previous
282 # authorization header is removed first.
283 if 'X-Amzn-Authorization' in req.headers:
284 del req.headers['X-Amzn-Authorization']
285 req.headers['X-Amz-Date'] = formatdate(usegmt=True)
286 if self._provider.security_token:
287 req.headers['X-Amz-Security-Token'] = self._provider.security_token
288 string_to_sign, headers_to_sign = self.string_to_sign(req)
289 boto.log.debug('StringToSign:\n%s' % string_to_sign)
290 hash_value = sha256(string_to_sign).digest()
291 b64_hmac = self.sign_string(hash_value)
292 s = "AWS3 AWSAccessKeyId=%s," % self._provider.access_key
293 s += "Algorithm=%s," % self.algorithm()
294 s += "SignedHeaders=%s," % ';'.join(headers_to_sign)
295 s += "Signature=%s" % b64_hmac
296 req.headers['X-Amzn-Authorization'] = s
297
298
299 class HmacAuthV4Handler(AuthHandler, HmacKeys):
300 """
301 Implements the new Version 4 HMAC authorization.
302 """
303
304 capability = ['hmac-v4']
305
306 def __init__(self, host, config, provider,
307 service_name=None, region_name=None):
308 AuthHandler.__init__(self, host, config, provider)
309 HmacKeys.__init__(self, host, config, provider)
310 # You can set the service_name and region_name to override the
311 # values which would otherwise come from the endpoint, e.g.
312 # <service>.<region>.amazonaws.com.
313 self.service_name = service_name
314 self.region_name = region_name
315
316 def _sign(self, key, msg, hex=False):
317 if hex:
318 sig = hmac.new(key, msg.encode('utf-8'), sha256).hexdigest()
319 else:
320 sig = hmac.new(key, msg.encode('utf-8'), sha256).digest()
321 return sig
322
323 def headers_to_sign(self, http_request):
324 """
325 Select the headers from the request that need to be included
326 in the StringToSign.
327 """
328 headers_to_sign = {}
329 headers_to_sign = {'Host': self.host}
330 for name, value in http_request.headers.items():
331 lname = name.lower()
332 if lname.startswith('x-amz'):
333 headers_to_sign[name] = value
334 return headers_to_sign
335
336 def query_string(self, http_request):
337 parameter_names = sorted(http_request.params.keys())
338 pairs = []
339 for pname in parameter_names:
340 pval = str(http_request.params[pname]).encode('utf-8')
341 pairs.append(urllib.quote(pname, safe='') + '=' +
342 urllib.quote(pval, safe='-_~'))
343 return '&'.join(pairs)
344
345 def canonical_query_string(self, http_request):
346 # POST requests pass parameters in through the
347 # http_request.body field.
348 if http_request.method == 'POST':
349 return ""
350 l = []
351 for param in sorted(http_request.params):
352 value = str(http_request.params[param])
353 l.append('%s=%s' % (urllib.quote(param, safe='-_.~'),
354 urllib.quote(value, safe='-_.~')))
355 return '&'.join(l)
356
357 def canonical_headers(self, headers_to_sign):
358 """
359 Return the headers that need to be included in the StringToSign
360 in their canonical form by converting all header keys to lower
361 case, sorting them in alphabetical order and then joining
362 them into a string, separated by newlines.
363 """
364 l = sorted(['%s:%s' % (n.lower().strip(),
365 ' '.join(headers_to_sign[n].strip().split()))
366 for n in headers_to_sign])
367 return '\n'.join(l)
368
369 def signed_headers(self, headers_to_sign):
370 l = ['%s' % n.lower().strip() for n in headers_to_sign]
371 l = sorted(l)
372 return ';'.join(l)
373
374 def canonical_uri(self, http_request):
375 return http_request.auth_path
376
377 def payload(self, http_request):
378 body = http_request.body
379 # If the body is a file like object, we can use
380 # boto.utils.compute_hash, which will avoid reading
381 # the entire body into memory.
382 if hasattr(body, 'seek') and hasattr(body, 'read'):
383 return boto.utils.compute_hash(body, hash_algorithm=sha256)[0]
384 return sha256(http_request.body).hexdigest()
385
386 def canonical_request(self, http_request):
387 cr = [http_request.method.upper()]
388 cr.append(self.canonical_uri(http_request))
389 cr.append(self.canonical_query_string(http_request))
390 headers_to_sign = self.headers_to_sign(http_request)
391 cr.append(self.canonical_headers(headers_to_sign) + '\n')
392 cr.append(self.signed_headers(headers_to_sign))
393 cr.append(self.payload(http_request))
394 return '\n'.join(cr)
395
396 def scope(self, http_request):
397 scope = [self._provider.access_key]
398 scope.append(http_request.timestamp)
399 scope.append(http_request.region_name)
400 scope.append(http_request.service_name)
401 scope.append('aws4_request')
402 return '/'.join(scope)
403
404 def credential_scope(self, http_request):
405 scope = []
406 http_request.timestamp = http_request.headers['X-Amz-Date'][0:8]
407 scope.append(http_request.timestamp)
408 # The service_name and region_name either come from:
409 # * The service_name/region_name attrs or (if these values are None)
410 # * parsed from the endpoint <service>.<region>.amazonaws.com.
411 parts = http_request.host.split('.')
412 if self.region_name is not None:
413 region_name = self.region_name
414 else:
415 if len(parts) == 3:
416 region_name = 'us-east-1'
417 else:
418 region_name = parts[1]
419 if self.service_name is not None:
420 service_name = self.service_name
421 else:
422 service_name = parts[0]
423
424 http_request.service_name = service_name
425 http_request.region_name = region_name
426
427 scope.append(http_request.region_name)
428 scope.append(http_request.service_name)
429 scope.append('aws4_request')
430 return '/'.join(scope)
431
432 def string_to_sign(self, http_request, canonical_request):
433 """
434 Return the canonical StringToSign as well as a dict
435 containing the original version of all headers that
436 were included in the StringToSign.
437 """
438 sts = ['AWS4-HMAC-SHA256']
439 sts.append(http_request.headers['X-Amz-Date'])
440 sts.append(self.credential_scope(http_request))
441 sts.append(sha256(canonical_request).hexdigest())
442 return '\n'.join(sts)
443
444 def signature(self, http_request, string_to_sign):
445 key = self._provider.secret_key
446 k_date = self._sign(('AWS4' + key).encode('utf-8'),
447 http_request.timestamp)
448 k_region = self._sign(k_date, http_request.region_name)
449 k_service = self._sign(k_region, http_request.service_name)
450 k_signing = self._sign(k_service, 'aws4_request')
451 return self._sign(k_signing, string_to_sign, hex=True)
452
453 def add_auth(self, req, **kwargs):
454 """
455 Add AWS4 authentication to a request.
456
457 :type req: :class`boto.connection.HTTPRequest`
458 :param req: The HTTPRequest object.
459 """
460 # This could be a retry. Make sure the previous
461 # authorization header is removed first.
462 if 'X-Amzn-Authorization' in req.headers:
463 del req.headers['X-Amzn-Authorization']
464 now = datetime.datetime.utcnow()
465 req.headers['X-Amz-Date'] = now.strftime('%Y%m%dT%H%M%SZ')
466 if self._provider.security_token:
467 req.headers['X-Amz-Security-Token'] = self._provider.security_token
468 qs = self.query_string(req)
469 if qs and req.method == 'POST':
470 # Stash request parameters into post body
471 # before we generate the signature.
472 req.body = qs
473 req.headers['Content-Type'] = 'application/x-www-form-urlencoded; ch arset=UTF-8'
474 req.headers['Content-Length'] = str(len(req.body))
475 else:
476 # Safe to modify req.path here since
477 # the signature will use req.auth_path.
478 req.path = req.path.split('?')[0]
479 req.path = req.path + '?' + qs
480 canonical_request = self.canonical_request(req)
481 boto.log.debug('CanonicalRequest:\n%s' % canonical_request)
482 string_to_sign = self.string_to_sign(req, canonical_request)
483 boto.log.debug('StringToSign:\n%s' % string_to_sign)
484 signature = self.signature(req, string_to_sign)
485 boto.log.debug('Signature:\n%s' % signature)
486 headers_to_sign = self.headers_to_sign(req)
487 l = ['AWS4-HMAC-SHA256 Credential=%s' % self.scope(req)]
488 l.append('SignedHeaders=%s' % self.signed_headers(headers_to_sign))
489 l.append('Signature=%s' % signature)
490 req.headers['Authorization'] = ','.join(l)
491
492
493 class QuerySignatureHelper(HmacKeys):
494 """
495 Helper for Query signature based Auth handler.
496
497 Concrete sub class need to implement _calc_sigature method.
498 """
499
500 def add_auth(self, http_request, **kwargs):
501 headers = http_request.headers
502 params = http_request.params
503 params['AWSAccessKeyId'] = self._provider.access_key
504 params['SignatureVersion'] = self.SignatureVersion
505 params['Timestamp'] = boto.utils.get_ts()
506 qs, signature = self._calc_signature(
507 http_request.params, http_request.method,
508 http_request.auth_path, http_request.host)
509 boto.log.debug('query_string: %s Signature: %s' % (qs, signature))
510 if http_request.method == 'POST':
511 headers['Content-Type'] = 'application/x-www-form-urlencoded; charse t=UTF-8'
512 http_request.body = qs + '&Signature=' + urllib.quote_plus(signature )
513 http_request.headers['Content-Length'] = str(len(http_request.body))
514 else:
515 http_request.body = ''
516 # if this is a retried request, the qs from the previous try will
517 # already be there, we need to get rid of that and rebuild it
518 http_request.path = http_request.path.split('?')[0]
519 http_request.path = (http_request.path + '?' + qs +
520 '&Signature=' + urllib.quote_plus(signature))
521
522
523 class QuerySignatureV0AuthHandler(QuerySignatureHelper, AuthHandler):
524 """Provides Signature V0 Signing"""
525
526 SignatureVersion = 0
527 capability = ['sign-v0']
528
529 def _calc_signature(self, params, *args):
530 boto.log.debug('using _calc_signature_0')
531 hmac = self._get_hmac()
532 s = params['Action'] + params['Timestamp']
533 hmac.update(s)
534 keys = params.keys()
535 keys.sort(cmp=lambda x, y: cmp(x.lower(), y.lower()))
536 pairs = []
537 for key in keys:
538 val = boto.utils.get_utf8_value(params[key])
539 pairs.append(key + '=' + urllib.quote(val))
540 qs = '&'.join(pairs)
541 return (qs, base64.b64encode(hmac.digest()))
542
543
544 class QuerySignatureV1AuthHandler(QuerySignatureHelper, AuthHandler):
545 """
546 Provides Query Signature V1 Authentication.
547 """
548
549 SignatureVersion = 1
550 capability = ['sign-v1', 'mturk']
551
552 def __init__(self, *args, **kw):
553 QuerySignatureHelper.__init__(self, *args, **kw)
554 AuthHandler.__init__(self, *args, **kw)
555 self._hmac_256 = None
556
557 def _calc_signature(self, params, *args):
558 boto.log.debug('using _calc_signature_1')
559 hmac = self._get_hmac()
560 keys = params.keys()
561 keys.sort(cmp=lambda x, y: cmp(x.lower(), y.lower()))
562 pairs = []
563 for key in keys:
564 hmac.update(key)
565 val = boto.utils.get_utf8_value(params[key])
566 hmac.update(val)
567 pairs.append(key + '=' + urllib.quote(val))
568 qs = '&'.join(pairs)
569 return (qs, base64.b64encode(hmac.digest()))
570
571
572 class QuerySignatureV2AuthHandler(QuerySignatureHelper, AuthHandler):
573 """Provides Query Signature V2 Authentication."""
574
575 SignatureVersion = 2
576 capability = ['sign-v2', 'ec2', 'ec2', 'emr', 'fps', 'ecs',
577 'sdb', 'iam', 'rds', 'sns', 'sqs', 'cloudformation']
578
579 def _calc_signature(self, params, verb, path, server_name):
580 boto.log.debug('using _calc_signature_2')
581 string_to_sign = '%s\n%s\n%s\n' % (verb, server_name.lower(), path)
582 hmac = self._get_hmac()
583 params['SignatureMethod'] = self.algorithm()
584 if self._provider.security_token:
585 params['SecurityToken'] = self._provider.security_token
586 keys = sorted(params.keys())
587 pairs = []
588 for key in keys:
589 val = boto.utils.get_utf8_value(params[key])
590 pairs.append(urllib.quote(key, safe='') + '=' +
591 urllib.quote(val, safe='-_~'))
592 qs = '&'.join(pairs)
593 boto.log.debug('query string: %s' % qs)
594 string_to_sign += qs
595 boto.log.debug('string_to_sign: %s' % string_to_sign)
596 hmac.update(string_to_sign)
597 b64 = base64.b64encode(hmac.digest())
598 boto.log.debug('len(b64)=%d' % len(b64))
599 boto.log.debug('base64 encoded digest: %s' % b64)
600 return (qs, b64)
601
602
603 class POSTPathQSV2AuthHandler(QuerySignatureV2AuthHandler, AuthHandler):
604 """
605 Query Signature V2 Authentication relocating signed query
606 into the path and allowing POST requests with Content-Types.
607 """
608
609 capability = ['mws']
610
611 def add_auth(self, req, **kwargs):
612 req.params['AWSAccessKeyId'] = self._provider.access_key
613 req.params['SignatureVersion'] = self.SignatureVersion
614 req.params['Timestamp'] = boto.utils.get_ts()
615 qs, signature = self._calc_signature(req.params, req.method,
616 req.auth_path, req.host)
617 boto.log.debug('query_string: %s Signature: %s' % (qs, signature))
618 if req.method == 'POST':
619 req.headers['Content-Length'] = str(len(req.body))
620 req.headers['Content-Type'] = req.headers.get('Content-Type',
621 'text/plain')
622 else:
623 req.body = ''
624 # if this is a retried req, the qs from the previous try will
625 # already be there, we need to get rid of that and rebuild it
626 req.path = req.path.split('?')[0]
627 req.path = (req.path + '?' + qs +
628 '&Signature=' + urllib.quote_plus(signature))
629
630
631 def get_auth_handler(host, config, provider, requested_capability=None):
632 """Finds an AuthHandler that is ready to authenticate.
633
634 Lists through all the registered AuthHandlers to find one that is willing
635 to handle for the requested capabilities, config and provider.
636
637 :type host: string
638 :param host: The name of the host
639
640 :type config:
641 :param config:
642
643 :type provider:
644 :param provider:
645
646 Returns:
647 An implementation of AuthHandler.
648
649 Raises:
650 boto.exception.NoAuthHandlerFound:
651 boto.exception.TooManyAuthHandlerReadyToAuthenticate:
652 """
653 ready_handlers = []
654 auth_handlers = boto.plugin.get_plugin(AuthHandler, requested_capability)
655 total_handlers = len(auth_handlers)
656 for handler in auth_handlers:
657 try:
658 ready_handlers.append(handler(host, config, provider))
659 except boto.auth_handler.NotReadyToAuthenticate:
660 pass
661
662 if not ready_handlers:
663 checked_handlers = auth_handlers
664 names = [handler.__name__ for handler in checked_handlers]
665 raise boto.exception.NoAuthHandlerFound(
666 'No handler was ready to authenticate. %d handlers were checked.'
667 ' %s '
668 'Check your credentials' % (len(names), str(names)))
669
670 if len(ready_handlers) > 1:
671 # NOTE: Even though it would be nice to accept more than one handler
672 # by using one of the many ready handlers, we are never sure that each
673 # of them are referring to the same storage account. Since we cannot
674 # easily guarantee that, it is always safe to fail, rather than operate
675 # on the wrong account.
676 names = [handler.__class__.__name__ for handler in ready_handlers]
677 raise boto.exception.TooManyAuthHandlerReadyToAuthenticate(
678 '%d AuthHandlers %s ready to authenticate for requested_capabilit y '
679 '%s, only 1 expected. This happens if you import multiple '
680 'pluging.Plugin implementations that declare support for the '
681 'requested_capability.' % (len(names), str(names),
682 requested_capability))
683
684 return ready_handlers[0]
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698