Skip to content

Commit

Permalink
Created digestor, moved challenge retrieving to it
Browse files Browse the repository at this point in the history
  • Loading branch information
almad committed Oct 26, 2008
1 parent 3501217 commit 1764f7a
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 21 deletions.
7 changes: 5 additions & 2 deletions djangohttpdigest/decorators.py
@@ -1,11 +1,14 @@
from django.http import HttpResponseBadRequest

from http import HttpResponseNotAuthorized
from digest import get_digest_challenge, parse_authorization_header, check_hardcoded_authentication
from digest import Digestor, parse_authorization_header, check_hardcoded_authentication

def protect_digest(realm, username, password):
def _innerDecorator(function):
def _wrapper(request, *args, **kwargs):

digestor = Digestor(realm=realm)

if request.META.has_key('HTTP_AUTHORIZATION'):
# successfull auth
if request.META['AUTH_TYPE'].lower() != 'digest':
Expand All @@ -20,7 +23,7 @@ def _wrapper(request, *args, **kwargs):

# nothing received, return challenge
response = HttpResponseNotAuthorized("Not Authorized")
response['www-authenticate'] = get_digest_challenge(realm)
response['www-authenticate'] = digestor.get_digest_challenge()
return response
return _wrapper
return _innerDecorator
Expand Down
50 changes: 33 additions & 17 deletions djangohttpdigest/digest.py
@@ -1,9 +1,41 @@
"""
Helper functions and algorithms for computing HTTP digest thingies.
"""
import time
from time import time
import urllib2
from md5 import md5
#from sha import sha

class Digestor(object):
""" Main class for handling digest algorithms as described in RFC 2617 """

# map string representation of algorithm to hash function
algorithm_implementation_map = {
'md5' : md5,
# 'sha' : sha,
}

def __init__(self, realm=None, qop=None, opaque=None, algorithm=None):
object.__init__(self)

self.algorithm = algorithm or 'md5'
self.opaque = opaque or 'ToDoMoveThisToSettings'
self.qop = qop or 'auth'
self.realm = realm or None

assert self.algorithm in self.algorithm_implementation_map

def get_digest_challenge(self):
""" Return HTTP digest challenge, which has to be placed into www-authenticate header"""

nonce = self.algorithm_implementation_map[self.algorithm]("%s:%s" % (time(), self.realm)).hexdigest()

return 'Digest realm="%(realm)s", qop="%(qop)s", nonce="%(nonce)s", opaque="%(opaque)s"' % {
'realm' : self.realm,
'qop' : self.qop,
'nonce' : nonce,
'opaque' : self.opaque
}

def parse_authorization_header(header):
""" Parse requests authorization header into list.
Expand Down Expand Up @@ -31,22 +63,6 @@ def parse_authorization_header(header):

return params

def get_digest_challenge(realm):
""" Return HTTP digest challenge, which has to be placed into www-authenticate header"""

algorithm = 'md5'
qop = 'auth'
opaque = 'ToDoMoveThisToSettings'

nonce = md5("%s:%s" % (time.time(), realm)).hexdigest()

return 'Digest realm="%(realm)s", qop="%(qop)s", nonce="%(nonce)s", opaque="%(opaque)s"' % {
'realm' : realm,
'qop' : qop,
'nonce' : nonce,
'opaque' : opaque
}

def check_credentials(request):
"""
Check if request contains credentials.
Expand Down
19 changes: 17 additions & 2 deletions djangohttpdigest/tests/test_digest.py
@@ -1,11 +1,27 @@
import re
import urllib2

from django.test import TestCase
from django.http import HttpRequest
from django.core.handlers.wsgi import WSGIRequest

from djangohttpdigest.digest import check_credentials, parse_authorization_header
from djangohttpdigest.digest import Digestor, check_credentials, parse_authorization_header

class TestDigestor(TestCase):
""" Test digestor, our wrapping class for handling digests """

def setUp(self):
self.digestor = Digestor(realm='testrealm')

def test_get_digest_challenge(self):
challenge = self.digestor.get_digest_challenge()

# check our challenge is compatible with urllib2's resolving
if re.compile('(?:.*,)*[ \t]*([^ \t]+)[ \t]+realm="([^"]*)"', re.I).match(challenge):
pass
else:
self.fail("Challenge %s does not match urllib2's regexp" % challenge)

class TestSimpleDigest(TestCase):

environment = {
Expand All @@ -31,5 +47,4 @@ def test_check_credentials(self):

def test_parse_authorization_header(self):
""" Authorization header parsing, for various inputs """

self.assertRaises(ValueError, lambda:parse_authorization_header(''))

0 comments on commit 1764f7a

Please sign in to comment.