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

Source Code for Module httxlib.httxauthcache

  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  HttxLib authcache object to enable cached (or partially cached) authentication 
 33  answer to authentication requests 
 34   
 35  A namedtuple I{AuthCache} is defined for storage in the cache with the 
 36  following fields: 
 37   
 38    - {headername} if WWW-Authenticate or Proxy-Authenticate was sent 
 39    - {scheme} if Basic, Digest or other 
 40    - {answer} Previous answer 
 41    - {cachedata} Specific data cached to be used if a new auth request is seen 
 42  ''' 
 43   
 44  from collections import defaultdict, namedtuple 
 45  from copy import deepcopy 
 46   
 47  from httxobject import HttxObject 
 48   
 49  # Authorization cache type 
 50  AuthCache = namedtuple('AuthCache', 'headername, scheme, answer, cachedata') 
 51   
 52   
53 -class HttxAuthCache(HttxObject):
54 ''' 55 An object that caches data from and for authentication requests 56 57 @ivar cache: holds the cache entries 58 @type cache: dict 59 @ivar noncecache: holds specifically sequestial nonce values for 60 digest authentication 61 @type noncecache: defaultdict(int) 62 ''' 63
64 - def __init__(self):
65 ''' 66 Constructor. It delegates construction to the base class 67 L{HttxObject} and initializes the member variables 68 ''' 69 HttxObject.__init__(self) 70 self.cache = dict() 71 self.noncecache = defaultdict(int)
72 73
74 - def __deepcopy__(self, memo):
75 ''' 76 Deepcopy support. 77 78 @param memo: standard __deepcopy__ parameter to avoid circular references 79 @type memo: dict 80 @return: a cloned object 81 @rtype: L{HttxAuthCache} 82 ''' 83 clone = self.__class__() 84 with self.lock: 85 clone.cache = deepcopy(self.cache, memo) 86 clone.noncecache = deepcopy(self.noncecache, memo) 87 88 return clone
89 90
91 - def getnoncecount(self, nonce):
92 ''' 93 Get a new nonce_count value for nonce 94 95 This will increment the cached value and return and cache the 96 incremented value 97 98 @param nonce: nonce value in digest auth requests 99 @type nonce: str 100 @return: a sequentally incremented nonce_count 101 @rtype: int 102 ''' 103 with self.lock: 104 self.noncecache[nonce] += 1 105 return self.noncecache[nonce]
106 107
108 - def set(self, url, headername, scheme, answer, cachedata):
109 ''' 110 Set a new entry in the cache 111 112 @param headername: WWW-Authenticate or Proxy-Authenticate as sent 113 @type headername: str 114 @param scheme: Basic, Digest or other types of auth 115 @type scheme: str 116 @param answer: Answer sent to the server 117 @type answer: str 118 @param cachedata: Specific data cached to be used if a new auth request is seen 119 @type cachedata: str 120 ''' 121 with self.lock: 122 self.cache[url] = AuthCache(headername, scheme, answer, cachedata)
123 124
125 - def get(self, url, opaque=False):
126 ''' 127 Get a cache entry for a url 128 129 The search is done hierarchically, because once authorized in an url 130 all sub-urls (same domain and same initial) path will likely send 131 the same authorization request 132 133 @param url: url for the http request 134 @type url: str 135 @param opaque: if no assumption has to be made about the stored data 136 and just cachedata has to be returned 137 @type opaque: bool (Default: False) 138 @return: A tuple with the headername to be sent and the header content 139 Both values can be None to indicate that no entry was found 140 @rtype: tuple 141 ''' 142 urllen = len(url) 143 authcache = None 144 145 with self.lock: 146 cachekeys = self.cache.keys() 147 cachekeys.sort(reverse=True) 148 149 for cachekey in cachekeys: 150 if len(cachekey) > urllen or not url.startswith(cachekey): 151 continue 152 153 with self.lock: 154 authcache = self.cache[cachekey] 155 break 156 157 headername = None 158 headerval = None 159 160 if authcache: 161 if opaque: 162 # for external handlers 163 return authcache.cachedata 164 165 elif authcache.scheme == 'basic': 166 authanswer = authcache.answer 167 168 elif authcache.scheme == 'digest': 169 authchallenge = parse_keqv_list(parse_http_list(authcache.answer)) 170 171 nonce = authchallenge['nonce'] 172 nonce_count = self.getnoncecount(nonce) 173 authanswer = authdigest(None, authcache.cachedata, authchallenge, httxreq, nonce_count) 174 175 headerval = '%s %s' % (authcache.scheme, authanswer) 176 headername = authcache.headername 177 178 if opaque: 179 return None 180 181 return (headername, headerval)
182