Commits

Anonymous committed 025ad38

Support for model-protected views with realm.

Comments (0)

Files changed (6)

djangohttpdigest/authentication.py

 Various authentication cases, used by decorators.
 """
 
-__all__ = ("SimpleHardcodedAuthenticator")
+__all__ = ("SimpleHardcodedAuthenticator", "ModelAuthenticator")
 
 class Authenticator(object):
     """ Authenticator """
         Return bool whether it matches.
         """
         if not self.a1:
-            self.get_a1(digestor=digestor)
+            try:
+                self.get_a1(digestor=digestor)
+            except ValueError:
+                return False
         
         assert self.a1 is not None
         
 
 class ModelAuthenticator(Authenticator):
     def __init__(self, model, realm, realm_field, username_field, secret_field):
-         self.model = model
-         self.realm = realm
-         self.realm_field = realm_field
-         self.username_field = username_field
-         self.secret_field = secret_field
+        Authenticator.__init__(self)
+        
+        self.model = model
+        self.realm = realm
+        self.realm_field = realm_field
+        self.username_field = username_field
+        self.secret_field = secret_field
     
     
     def get_a1(self, digestor):
         try:
-            inst = model.objects.get(**{
+            inst = self.model.objects.get(**{
                 self.realm_field : self.realm,
                 self.username_field : digestor.get_client_username()
             })
             self.a1 = getattr(inst, self.secret_field)
             return self.a1
         
-        except model.DoesNotExist:
+        except self.model.DoesNotExist:
             raise ValueError()
     

djangohttpdigest/decorators.py

 
 from http import HttpResponseNotAuthorized
 from digest import Digestor, parse_authorization_header
-from authentication import SimpleHardcodedAuthenticator
+from authentication import SimpleHardcodedAuthenticator, ModelAuthenticator
 
 __all__ = ("protect_digest", "protect_digest_model")
 
         return _wrapper
     return _innerDecorator
 
-def protect_digest_model(model, realm_field='realm', username_field='username', secret_field='secret_field'):
+def protect_digest_model(model, realm, realm_field='realm', username_field='username', secret_field='secret_field'):
     def _innerDecorator(function):
         def _wrapper(request, *args, **kwargs):
             
-            digestor = Digestor(realm=realm)
+            digestor = Digestor(method=request.method, path=request.path, realm=realm)
             
             if request.META.has_key('HTTP_AUTHORIZATION'):
                 # successfull auth
                 except ValueError, err:
                     return HttpResponseBadRequest(err)
 
-                authenticator = SimpleHardcodedAuthenticator(realm=realm, username=username, password=password)
-                
-                if authenticator.secret_passed():
+                authenticator = ModelAuthenticator(model=model, realm=realm, realm_field=realm_field, username_field=username_field, secret_field=secret_field)
+
+                if authenticator.secret_passed(digestor):
                     return function(request, *args, **kwargs)
                 
             # nothing received, return challenge

djangohttpdigest/digest.py

         self.parsed_header = parse_authorization_header(header)
         return self.parsed_header
     
-    def get_client_username(self, username):
+    def get_client_username(self):
         return self.parsed_header['username']
     
     

djangohttpdigest/tests/test_simple_digest.py

 import urllib2
 import logging
+from md5 import md5
 from django.test import TestCase
 
 from djangohttpdigest.client import HttpDigestClient
 #        self.assertEquals(200, response.status_code)
         
     
-    def _check_authentication_compatibility(self, uri):
+    def _check_authentication_compatibility(self, path):
+        
+        # first handle bad path
+        
+        auth_handler = urllib2.HTTPDigestAuthHandler()
+        auth_handler.add_password('simple', self.url, 'username', 'badpassword')
+        opener = urllib2.build_opener(auth_handler)
+        
+        request = urllib2.Request(self.url+path)
+        try:
+            response = opener.open(request)
+            self.fail("Exception expected to be raised")
+        except urllib2.HTTPError, err:
+            self.assertEquals(401, err.code)
+            if err.fp:
+                err.fp.close()
+
+        # then happy path
+        
         auth_handler = urllib2.HTTPDigestAuthHandler()
         auth_handler.add_password('simple', self.url, 'username', 'password')
         opener = urllib2.build_opener(auth_handler)
         
-        request = urllib2.Request(self.url+self.path)
+        request = urllib2.Request(self.url+path)
         try:
             response = opener.open(request)
         except urllib2.HTTPError, err:
         self.assertEquals(200, response.code)
         response.close()
     
-    def test_autentization_compatible(self):
+    def test_autentization_compatible_simple(self):
         """ Check our server-side autentizations is compatible with standard (urllib2) one """
-        self._check_authentication_compatibility(uri='/testapi/simpleprotected/')
-        self._check_authentication_compatibility(uri='/testapi/modelprotected/')
+        self._check_authentication_compatibility(path='/testapi/simpleprotected/')
+        
+    def test_autentization_compatible_model(self):
+        # add something to test agains
+        from testapi.models import ModelWithRealmSet
+        
+        ModelWithRealmSet.objects.create(realm='simple', username='username', secret=md5("%s:%s:%s" % ("username", "simple", "password")).hexdigest()) 
+        
+        self._check_authentication_compatibility(path='/testapi/modelprotected/')
 

testproject/testapi/models.py

     realm = models.CharField(max_length=30)
     username = models.CharField(max_length=30)
     secret = models.CharField(max_length=50)
+    
+    def __unicode__(self):
+        return u"<ModelWithRealmSet realm=%s, username=%s>" % (self.realm, self.username)

testproject/testapi/views.py

     """
     return HttpResponse('')
 
-@protect_digest_model(model=ModelWithRealmSet,
+@protect_digest_model(realm='simple',
+      model=ModelWithRealmSet,
       realm_field='realm',
       username_field='username',
-      secret_field='secret_field'
+      secret_field='secret'
 )
 def modelprotected(request):
     """