Advertisement
Guest User

Untitled

a guest
Aug 29th, 2017
141
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.09 KB | None | 0 0
  1. # File: a (Python 3.4)
  2.  
  3. '''
  4. requests.auth
  5. ~~~~~~~~~~~~~
  6.  
  7. This module contains the authentication handlers for Requests.
  8. '''
  9. import os
  10. import re
  11. import time
  12. import hashlib
  13. from base64 import b64encode
  14. from compat import urlparse, str
  15. from cookies import extract_cookies_to_jar
  16. from utils import parse_dict_header, to_native_string
  17. from status_codes import codes
  18.  
  19. CONTENT_TYPE_FORM_URLENCODED = 'application/x-www-form-urlencoded'
  20. CONTENT_TYPE_MULTI_PART = 'multipart/form-data'
  21.  
  22.  
  23. def _basic_auth_str(username, password):
  24.     '''Returns a Basic Auth string.'''
  25.     authstr = 'Basic ' + to_native_string(b64encode(('%s:%s' % (username, password)).encode('latin1')).strip())
  26.     return authstr
  27.  
  28.  
  29. class AuthBase(object):
  30.     __qualname__ = 'AuthBase'
  31.     __doc__ = 'Base class that all auth implementations derive from'
  32.  
  33.     def __call__(self, r):
  34.         raise NotImplementedError('Auth hooks must be callable.')
  35.  
  36.  
  37. class HTTPBasicAuth(AuthBase):
  38.     __qualname__ = 'HTTPBasicAuth'
  39.     __doc__ = 'Attaches HTTP Basic Authentication to the given Request object.'
  40.  
  41.     def __init__(self, username, password):
  42.         self.username = username
  43.         self.password = password
  44.  
  45.     def __call__(self, r):
  46.         r.headers['Authorization'] = _basic_auth_str(self.username, self.password)
  47.         return r
  48.  
  49.  
  50. class HTTPProxyAuth(HTTPBasicAuth):
  51.     __qualname__ = 'HTTPProxyAuth'
  52.     __doc__ = 'Attaches HTTP Proxy Authentication to a given Request object.'
  53.  
  54.     def __call__(self, r):
  55.         r.headers['Proxy-Authorization'] = _basic_auth_str(self.username, self.password)
  56.         return r
  57.  
  58.  
  59. class HTTPDigestAuth(AuthBase):
  60.     __qualname__ = 'HTTPDigestAuth'
  61.     __doc__ = 'Attaches HTTP Digest Authentication to the given Request object.'
  62.  
  63.     def __init__(self, username, password):
  64.         self.username = username
  65.         self.password = password
  66.         self.last_nonce = ''
  67.         self.nonce_count = 0
  68.         self.chal = {}
  69.         self.pos = None
  70.  
  71.     def build_digest_header(self, method, url):
  72.         realm = self.chal['realm']
  73.         nonce = self.chal['nonce']
  74.         qop = self.chal.get('qop')
  75.         algorithm = self.chal.get('algorithm')
  76.         opaque = self.chal.get('opaque')
  77.         if algorithm is None:
  78.             _algorithm = 'MD5'
  79.         else:
  80.             _algorithm = algorithm.upper()
  81.         if _algorithm == 'MD5' or _algorithm == 'MD5-SESS':
  82.  
  83.             def md5_utf8(x):
  84.                 if isinstance(x, str):
  85.                     x = x.encode('utf-8')
  86.                 return hashlib.md5(x).hexdigest()
  87.  
  88.             hash_utf8 = md5_utf8
  89.         elif _algorithm == 'SHA':
  90.  
  91.             def sha_utf8(x):
  92.                 if isinstance(x, str):
  93.                     x = x.encode('utf-8')
  94.                 return hashlib.sha1(x).hexdigest()
  95.  
  96.             hash_utf8 = sha_utf8
  97.  
  98.         KD = lambda s, d: hash_utf8('%s:%s' % (s, d))
  99.         if hash_utf8 is None:
  100.             return None
  101.         entdig = (None,)
  102.         p_parsed = urlparse(url)
  103.         path = p_parsed.path
  104.         if p_parsed.query:
  105.             path += '?' + p_parsed.query
  106.         A1 = '%s:%s:%s' % (self.username, realm, self.password)
  107.         A2 = '%s:%s' % (method, path)
  108.         HA1 = hash_utf8(A1)
  109.         HA2 = hash_utf8(A2)
  110.         if nonce == self.last_nonce:
  111.             self.nonce_count += 1
  112.         else:
  113.             self.nonce_count = 1
  114.         ncvalue = '%08x' % self.nonce_count
  115.         s = str(self.nonce_count).encode('utf-8')
  116.         s += nonce.encode('utf-8')
  117.         s += time.ctime().encode('utf-8')
  118.         s += os.urandom(8)
  119.         cnonce = hashlib.sha1(s).hexdigest()[:16]
  120.         noncebit = '%s:%s:%s:%s:%s' % (nonce, ncvalue, cnonce, qop, HA2)
  121.         if _algorithm == 'MD5-SESS':
  122.             HA1 = hash_utf8('%s:%s:%s' % (HA1, nonce, cnonce))
  123.         if qop is None:
  124.             respdig = KD(HA1, '%s:%s' % (nonce, HA2))
  125.         elif qop == 'auth' or 'auth' in qop.split(','):
  126.             respdig = KD(HA1, noncebit)
  127.         else:
  128.             return None
  129.         self.last_nonce = None
  130.         base = 'username="%s", realm="%s", nonce="%s", uri="%s", response="%s"' % (
  131.         self.username, realm, nonce, path, respdig)
  132.         if opaque:
  133.             base += ', opaque="%s"' % opaque
  134.         if algorithm:
  135.             base += ', algorithm="%s"' % algorithm
  136.         if entdig:
  137.             base += ', digest="%s"' % entdig
  138.         if qop:
  139.             base += ', qop="auth", nc=%s, cnonce="%s"' % (ncvalue, cnonce)
  140.         return 'Digest %s' % base
  141.  
  142.     def handle_redirect(self, r, **kwargs):
  143.         '''Reset num_401_calls counter on redirects.'''
  144.         if r.is_redirect:
  145.             setattr(self, 'num_401_calls', 1)
  146.  
  147.     def handle_401(self, r, **kwargs):
  148.         '''Takes the given response and tries digest-auth, if needed.'''
  149.         if self.pos is not None:
  150.             r.request.body.seek(self.pos)
  151.         num_401_calls = getattr(self, 'num_401_calls', 1)
  152.         s_auth = r.headers.get('www-authenticate', '')
  153.         if 'digest' in s_auth.lower() and num_401_calls < 2:
  154.             setattr(self, 'num_401_calls', num_401_calls + 1)
  155.             pat = re.compile('digest ', flags=re.IGNORECASE)
  156.             self.chal = parse_dict_header(pat.sub('', s_auth, count=1))
  157.             r.raw.release_conn()
  158.             prep = r.request.copy()
  159.             extract_cookies_to_jar(prep._cookies, r.request, r.raw)
  160.             prep.prepare_cookies(prep._cookies)
  161.             prep.headers['Authorization'] = self.build_digest_header(prep.method, prep.url)
  162.             _r = r.connection.send(prep, **None)
  163.             _r.history.append(r)
  164.             _r.request = prep
  165.             return _r
  166.         None(self, 'num_401_calls', num_401_calls + 1)
  167.         return r
  168.  
  169.     def __call__(self, r):
  170.         if self.last_nonce:
  171.             r.headers['Authorization'] = self.build_digest_header(r.method, r.url)
  172.  
  173.         try:
  174.             self.pos = r.body.tell()
  175.         except AttributeError:
  176.             self.pos = None
  177.  
  178.         r.register_hook('response', self.handle_401)
  179.         r.register_hook('response', self.handle_redirect)
  180.         return r
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement