Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Hacky challenge returning

  • Loading branch information...
commit de279b0a8056c3ccf673884920d3387c8c9c1283 1 parent 4d49787
almad authored
View
4 djangohttpdigest/authentication.py
@@ -0,0 +1,4 @@
+
+"""
+Various authentication cases, used by decorators.
+"""
View
6 djangohttpdigest/client.py
@@ -20,12 +20,6 @@ def http_authenticate(self, response, method, queryargs=None):
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 {}
View
16 djangohttpdigest/decorators.py
@@ -1,8 +1,18 @@
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
View
38 djangohttpdigest/digest.py
@@ -0,0 +1,38 @@
+"""
+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
+
+
View
3  djangohttpdigest/tests/__init__.py
@@ -1 +1,2 @@
-from test_simple_digest import *
+from test_digest import *
View
0  djangohttpdigest/tests/test_authentication.py
No changes.
View
35 djangohttpdigest/tests/test_digest.py
@@ -0,0 +1,35 @@
+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(''))
View
14 djangohttpdigest/tests/test_simple_digest.py
@@ -1,5 +1,5 @@
import urllib2
-
+import logging
from django.test import TestCase
from djangohttpdigest.client import HttpDigestClient
@@ -18,6 +18,10 @@ def test_simple_autentization(self):
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)
@@ -29,14 +33,18 @@ def test_autentization_compatible(self):
""" 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()
View
2  testproject/testapi/views.py
@@ -9,5 +9,5 @@ def simpleprotected(request):
view returns 401 on failure or for challenge, 200 with empty body
on successfull authorization.
"""
-
+ raise ValueError()
return HttpResponse('')
Please sign in to comment.
Something went wrong with that request. Please try again.