Commits

almad  committed eafd7f3

Hacky challenge returning

  • Participants
  • Parent commits 5b5127c

Comments (0)

Files changed (9)

File djangohttpdigest/authentication.py

+
+"""
+Various authentication cases, used by decorators.
+"""

File djangohttpdigest/client.py

         Authenticate using HTTP digest and return our second request.
         If problem occurs and we cannot repeat our request, return original one.
         """
-        if not response.has_key('WWW-Authenticate'):
-            # server has not send needed authentication information
-            return response
-        (authentication_method, auth) = response['WWW-Authenticate'].split(" ", 1)
-        if authmeth.lower() != 'digest':
-            raise ValueError("Unsupported authentication method %s" % authmeth)
     
     def get(self, url, data=None, *args, **kwargs):
         data = data or {}

File djangohttpdigest/decorators.py

 from http import HttpResponseNotAuthorized
+
+from digest import get_digest_challenge
+
 def protect_digest(realm, username, password):
-    def _innerDecorator(f):
-        def _wrapper(*args, **kwargs):
-            return HttpResponseNotAuthorized("Not Authorized")
+    def _innerDecorator(function):
+        def _wrapper(request, *args, **kwargs):
+            if request.META.has_key('HTTP_AUTHORIZATION'):
+                # successfull auth
+                if request.META['AUTH_TYPE'].lower() != 'digest':
+                    raise NotImplementedError("Only digest supported")
+                #return function(request, *args, **kwargs)
+            response = HttpResponseNotAuthorized("Not Authorized")
+            response['www-authenticate'] = get_digest_challenge(realm)
+            return response
         return _wrapper
     return _innerDecorator
 

File djangohttpdigest/digest.py

+"""
+Helper functions and algorithms for computing HTTP digest thingies.
+"""
+import time
+from md5 import md5
+from django.http import HttpResponseBadRequest
+
+def parse_authorization_header(header):
+    #auth_scheme, auth_params  = credentials.split(" ", 1)
+    pass
+
+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.
+    Raise HttpResponseBadRequest if malformed header was send.
+    """
+    if request.META.has_key('AUTHORIZATION'):
+        header = parse_authorization_header(request.meta['AUTHORIZATION'])
+    else:
+        return False
+    
+    

File djangohttpdigest/tests/__init__.py

-from test_simple_digest import *
+from test_simple_digest import *
+from test_digest import *

File djangohttpdigest/tests/test_authentication.py

Empty file added.

File djangohttpdigest/tests/test_digest.py

+import urllib2
+
+from django.test import TestCase
+from django.http import HttpRequest, HttpResponseBadRequest
+from django.core.handlers.wsgi import WSGIRequest
+
+from djangohttpdigest.digest import check_credentials, parse_authorization_header
+
+class TestSimpleDigest(TestCase):
+    
+    environment = {
+        'HTTP_COOKIE':       '',
+        'PATH_INFO':         '/',
+        'QUERY_STRING':      '',
+        'REQUEST_METHOD':    'GET',
+        'SCRIPT_NAME':       '',
+        'SERVER_NAME':       'testserver',
+        'SERVER_PORT':       '80',
+        'SERVER_PROTOCOL':   'HTTP/1.1',
+    }
+    
+    def test_check_credentials(self):
+        """ Manually construct requests and check parse function behave correctly """
+        request = WSGIRequest(self.__class__.environment)
+        self.assertEquals(False, check_credentials(request))
+        
+        # bad authentication content
+        request.META['AUTHENTICATION'] = ''
+        
+        self.assertEquals(False, check_credentials(request))
+    
+    def test_parse_authorization_header(self):
+        """ Authorization header parsing, for various inputs """
+        
+        self.assertRaises(HttpResponseBadRequest, lambda:parse_authorization_header(''))

File djangohttpdigest/tests/test_simple_digest.py

 import urllib2
-
+import logging
 from django.test import TestCase
 
 from djangohttpdigest.client import HttpDigestClient
         response = self.client.get(self.path)
         self.assertEquals(401, response.status_code)
         
+        # and that challenge is returned
+        assert len(response['www-authenticate']) > 0
+        assert 'nonce' in response['www-authenticate']
+        
         #Now use our client ant autentize
 #        client = HttpDigestClient()
 #        client.set_http_authentication(username='username', password='password', path=self.path)
         """ Check our server-side autentization is compatible with standard (urllib2) one """
         
         auth_handler = urllib2.HTTPDigestAuthHandler()
-        auth_handler.add_password('localhost', self.url, 'username', 'password')
+        auth_handler.add_password('simple', self.url, 'username', 'password')
         opener = urllib2.build_opener(auth_handler)
         
         request = urllib2.Request(self.url+self.path)
         try:
             response = opener.open(request)
         except urllib2.HTTPError, err:
-            print err.fp.read()
+            if err.fp:
+                error = ": %s" % err.fp.read()
+            else:
+                error = ''
+            logging.error("Error occured while opening HTTP %s" % error)
             raise
         self.assertEquals(200, response.code)
         response.close()

File testproject/testapi/views.py

     view returns 401 on failure or for challenge, 200 with empty body
     on successfull authorization. 
     """
-    
+    raise ValueError()
     return HttpResponse('')