def __init__(self, app, user_dict, required = False, json=True): self.app = app self.user_dict = user_dict self.nonces_by_time = Fifo() self.nonces_set = set() self.required = required self.json = json
class WSSEAuthMiddleware: def __init__(self, app, user_dict, required = False, json=True): self.app = app self.user_dict = user_dict self.nonces_by_time = Fifo() self.nonces_set = set() self.required = required self.json = json def _fail(self, start_response): status = "401 Authorization Required" headers = [('Content-type', 'text/plain'), ('WWW-Authenticate', 'WSSE realm="wsse", profile="UsernameToken"')] start_response(status, headers) if self.json: return [dumps({'status' : 'rejected', 'reason' : 'Bad WSSE Auth'})] else: return ['Bad WSSE Auth'] def __call__(self, environ, start_response): #parse nonce, created, username out of ... #check validity of wsse info if environ.get('HTTP_AUTHORIZATION', None) != 'WSSE profile="UsernameToken"': if self.required: #print "no http_auth", environ return self._fail(start_response) else: return self.app(environ, start_response) header = environ.get('HTTP_X_WSSE', None) if not header: #print "no header" return self._fail(start_response) wsse_re = re.compile('UsernameToken Username="******"]+)", PasswordDigest="([^"]+)", Nonce="([^"]+)", Created="([^"]+)"') match = wsse_re.match(header) if not match: #print "Bad format" return self._fail(start_response) #bad format username = match.group(1) password = self.user_dict.get(username.lower()) if not password: #print "no user %s password" % username return self._fail(start_response) digest = match.group(2) nonce = match.group(3) created = match.group(4) if nonce in self.nonces_set: #print "already used this nonce" return self._fail(start_response) created_date = parse_w3dtf(created) five_minutes_ago = datetime.now() - timedelta(0, 300, 0) if created_date < five_minutes_ago: #print "too old" return self._fail(start_response) #too old self.nonces_set.add(nonce) self.nonces_by_time.append((created_date, nonce)) #remove old nonces while not self.nonces_by_time.empty() and self.nonces_by_time.top()[0] < five_minutes_ago: created_date, nonce = self.nonces_by_time.pop() self.nonces_set.remove(nonce) key = "%s%s%s" % (nonce, created, password) if not digest == sha(key).digest().encode("base64").strip(): #print "did not match" return self._fail(start_response) environ['REMOTE_USER'] = username environ['AUTHENTICATION_METHOD'] = 'WSSE' return self.app(environ, start_response)
def test_fifo(): fifo = Fifo() assert fifo.empty() fifo.append('morx') assert not fifo.empty() assert fifo.top() == 'morx' assert fifo.pop() == 'morx' assert fifo.empty() #--- fifo.append('foo') fifo.append('bar') assert fifo.top() == 'foo' assert fifo.pop() == 'foo' assert not fifo.empty() assert fifo.pop() == 'bar' assert fifo.empty() #--- fifo.append('foo') fifo.append('bar') assert fifo.top() == 'foo' assert fifo.pop() == 'foo' assert not fifo.empty() fifo.append('baz') assert fifo.pop() == 'bar' assert not fifo.empty() assert fifo.pop() == 'baz' assert fifo.empty()