Package httxlib :: Module httxauth
[hide private]
[frames] | no frames]

Source Code for Module httxlib.httxauth

  1  #!/usr/bin/env python 
  2  # -*- coding: latin-1; py-indent-offset:4 -*- 
  3  ################################################################################ 
  4  #  
  5  # This file is part of HttxLib 
  6  # 
  7  # HttxLib is an HTTP(s) Python library suited multithreaded/multidomain 
  8  # applications 
  9  # 
 10  # Copyright (C) 2010-2011 Daniel Rodriguez (aka Daniel Rodriksson) 
 11  # Copyright (C) 2011 Sensible Odds Ltd 
 12  # 
 13  # You can learn more and contact the author at: 
 14  # 
 15  #    http://code.google.com/p/httxlib/ 
 16  # 
 17  # HttxLib is free software: you can redistribute it and/or modify 
 18  # it under the terms of the GNU General Public License as published by 
 19  # the Free Software Foundation, either version 3 of the License, or 
 20  # (at your option) any later version. 
 21  # 
 22  # HttxLib is distributed in the hope that it will be useful, 
 23  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 24  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 25  # GNU General Public License for more details. 
 26  # 
 27  # You should have received a copy of the GNU General Public License 
 28  # along with HttxLib. If not, see <http://www.gnu.org/licenses/>. 
 29  # 
 30  ################################################################################ 
 31  # 
 32  # NOTES: 
 33  # 
 34  #   The authdigest code has been adapted from Python 2.6.5 httplib code 
 35  #   making it apt for 1st authentication and 2nd-nth authentication 
 36  #   and cleaning other dependencies like parsing of the header fields 
 37  #   get_cnonce and get_algorithm_impls are also part of the httplib 
 38  #   implementation 
 39  # 
 40  ############################################################################### 
 41   
 42  ''' 
 43  Authentication functions to answer to Basic and Digest HTTP authentication 
 44  challenges 
 45  ''' 
 46   
 47  from base64 import b64encode 
 48   
 49  from httxutil import * 
 50   
51 -def authbasic(username, password, authchallenge):
52 ''' 53 Given a username and a password return an HTTP Basic Authentication 54 challenge. 55 56 The authchallenge parameter is just for harmony with authdigest 57 and for potentially defining a plug-in interface for other 58 authentications 59 60 @param username: The username to reply to the challenge 61 @type username: str 62 @param password: The password to reply to the challenge 63 @type password: str 64 @return: A tuple containing a base64 encoded challenge and 65 a string with a cache-able challenge for future responses 66 The second value can be None 67 @rtype: tuple (str, str|None) 68 ''' 69 # Remove the trailing end of line 70 # base64auth = base64encode('%s:%s' % (username, password))[:-1] 71 base64auth = b64encode('%s:%s' % (username, password)).rstrip() 72 73 return ('basic', base64auth, None)
74 75
76 -def authdigest(username, password, challenge, request, nonce_count):
77 ''' 78 Given a username, password, a list of challenge fields, a request 79 a sequence number (nonce_count) return a Diget Auth challenge 80 answer 81 82 If username is None, then challenge will contain a username key with 83 the username and the password parameter will be the cached value of 84 the HA1 (see the function below) to be used 85 86 @param username: The username to reply to the challenge or None to 87 indicate that the password contains a HA1 cache 88 @type username: str|None 89 @param password: The password to reply to the challenge or a HA1 cache 90 @type password: str 91 @param challenge: Dictionary with the parameters in the challenge 92 @type challenge: dict 93 @param request: The request that has generated the auth challenge 94 @type request: L{HttxRequest} 95 @param nonce_count: Sequence value if this not the first time such 96 a request has been seen. Used by Digest auth to 97 prevent replay attacks 98 @type nonce_count: int 99 @return: A tuple containing a digest answer and 100 a string with a cache-able challenge for future responses 101 Both values can be None if a specific non-supported variant 102 of the Digest Auth is used 103 @rtype: tuple (str|None, str|None) 104 ''' 105 try: 106 realm = challenge['realm'] 107 nonce = challenge['nonce'] 108 except KeyError: 109 return (None, None, None) 110 111 qop = challenge.get('qop') 112 algorithm = challenge.get('algorithm', 'MD5') 113 # mod_digest doesn't send an opaque, even though it isn't supposed to be optional 114 opaque = challenge.get('opaque', None) 115 116 H, KD = get_algorithm_impls(algorithm) 117 if H is None: 118 return (None, None, None) 119 120 entdig = None 121 122 if not username: 123 username = challenge['username'] 124 HA1 = password 125 else: 126 A1 = "%s:%s:%s" % (username, realm, password) 127 HA1 = H(A1) 128 129 # XXX selector: what about proxies and full urls 130 A2 = "%s:%s" % (request.get_method(), request.get_selector()) 131 if qop == 'auth': 132 133 # client nonce - cnonce 134 cnonce = get_cnonce(nonce_count, nonce) 135 136 ncvalue = '%08x' % nonce_count 137 noncebit = "%s:%s:%s:%s:%s" % (nonce, ncvalue, cnonce, qop, H(A2)) 138 139 respdig = KD(HA1, noncebit) 140 elif qop is None: 141 respdig = KD(HA1, "%s:%s" % (nonce, H(A2))) 142 else: 143 # XXX handle auth-int. 144 # raise URLError("qop '%s' is not supported." % qop) 145 return (None, None, None) 146 147 # XXX should the partial digests be encoded too? 148 149 base = 'username="%s", realm="%s", nonce="%s", uri="%s", response="%s"' \ 150 % (username, realm, nonce, request.get_selector(), respdig) 151 if opaque: 152 base += ', opaque="%s"' % opaque 153 if entdig: 154 base += ', digest="%s"' % entdig 155 base += ', algorithm="%s"' % algorithm 156 if qop: 157 base += ', qop=auth, nc=%s, cnonce="%s"' % (ncvalue, cnonce) 158 159 return ('digest', base, HA1)
160