Commits

Anonymous committed 5b5127c

Set up proper live server environment and urllib2 tests

Comments (0)

Files changed (9)

djangohttpdigest/__init__.py

 
 __version__ = (0, 1, 0, 'pre')
-__versionstr__ = '0.1.0-pre'
+__versionstr__ = '0.1.0-pre'
+
+from decorators import (
+    protect_digest
+)

djangohttpdigest/client.py

 
 class HttpDigestClient(Client):
     """ Extend Django's client for HTTP digest support """
+    
+    def set_http_authentication(self, username, password, path):
+        self.http_username = username
+        self.http_password = password
+        self.http_path = path
+    
+    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 {}
+        response = Client.get(self, url, data, *args, **kwargs)
+        if response.status_code == 401:
+            return self.http_authenticate(response=response, method='get', queryargs=data)
+
+    def post(self, url, *args, **kwargs):
+        response = Client.post(self, url, *args, **kwargs)
+
+    def put(self, url, *args, **kwargs):
+        response = Client.put(self, url, *args, **kwargs)
+        
+    def delete(self, url, *args, **kwargs):
+        response = Client.delete(self, url, *args, **kwargs)
+        
+    def options(self, url, *args, **kwargs):
+        response = Client.options(self, url, *args, **kwargs)
+
+    def head(self, url, *args, **kwargs):
+        response = Client.head(self, url, *args, **kwargs)
+

djangohttpdigest/decorators.py

+from http import HttpResponseNotAuthorized
+def protect_digest(realm, username, password):
+    def _innerDecorator(f):
+        def _wrapper(*args, **kwargs):
+            return HttpResponseNotAuthorized("Not Authorized")
+        return _wrapper
+    return _innerDecorator
+

djangohttpdigest/http.py

+"""
+Fixes around django.http
+"""
+
+from django.http import HttpResponse
+
+class HttpResponseNotAuthorized(HttpResponse):
+    status_code = 401

djangohttpdigest/tests/test_simple_digest.py

+import urllib2
+
 from django.test import TestCase
+
 from djangohttpdigest.client import HttpDigestClient
 
-class TestSimpleDigest(TestCase):
+from module_test import LiveServerTestCase
+
+class TestSimpleDigest(LiveServerTestCase):
+    path = '/testapi/simpleprotected/'
+    url = 'http://localhost:8000'
     
-    def test_simple_authorization(self):
+    def test_simple_autentization(self):
         """ Test view protected by simple realm-username-password decorator """
-        path = '/testapi/simpleprotected/'
+        
         
         # first test that using normal client, path is protected and returns 401
-        response = self.client.get(path)
-        self.assertEquals(401, response.status_code)
+        response = self.client.get(self.path)
+        self.assertEquals(401, response.status_code)
+        
+        #Now use our client ant autentize
+#        client = HttpDigestClient()
+#        client.set_http_authentication(username='username', password='password', path=self.path)
+#        response = client.get(self.path)
+#        self.assertEquals(200, response.status_code)
+        
+
+    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')
+        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()
+            raise
+        self.assertEquals(200, response.code)
+        response.close()
+
 #!/bin/sh
 cd testproject
-./manage.py test $1
+#./manage.py test $1
+./livetests.py
 exit $?;

testproject/livetests.py

+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+""" Run webtests """
+
+import sys
+import os, os.path
+
+from django.core.management import setup_environ
+import nose
+from nose.config import Config, all_config_files
+from nose.plugins.manager import DefaultPluginManager
+
+import settings
+setup_environ(settings)
+
+from server_runner import ServerRunner
+
+def run_selenium_tests():
+    
+        # nose config
+        config = Config(files=all_config_files(), plugins=DefaultPluginManager())
+        config.workingDir = os.path.join(os.path.dirname(__file__)) 
+        server_runner = ServerRunner()
+        server_runner.run_server()
+        success = nose.run(config=config)
+        server_runner.stop_server()
+        
+        return success
+
+def main():
+    success = run_selenium_tests()
+    
+    sys.exit(not success)
+    
+if __name__ == '__main__':
+    main()

testproject/server_runner.py

+# -*- coding: utf-8 -*-
+__license__ = """
+   Copyright (c) 2007 Mikeal Rogers
+   Modified for RPGPedia project (c) 2008 by Almad
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+"""
+
+
+import sys, os
+from time import sleep
+from threading import Thread
+
+import cherrypy
+
+__all__ = ["ServerRunner"]
+
+class ServerRunner(object):
+    
+    def __init__(self, port=8000):
+        self.port = port
+        self.httpd = None
+        self.http_thread = None
+    
+    def run_server(self):
+    
+         import django.core.handlers.wsgi
+         _application = django.core.handlers.wsgi.WSGIHandler()
+    
+         def application(environ, start_response):
+             environ['PATH_INFO'] = environ['SCRIPT_NAME'] + environ['PATH_INFO']
+             return _application(environ, start_response)
+    
+         import cherrypy
+         httpd = cherrypy.wsgiserver.CherryPyWSGIServer(('', self.port), application, server_name='django-test-http')
+         httpd_thread = Thread(target=httpd.start)
+         httpd_thread.start()
+         sleep(.5)
+    
+         self.httpd_thread = httpd_thread
+         self.httpd = httpd
+    
+    def stop_server(self):
+         self.httpd.stop()

testproject/testapi/views.py

 from django.http import HttpResponse
+from djangohttpdigest import protect_digest
 
+@protect_digest(realm='simple', username='username', password='password')
 def simpleprotected(request):
     """
     This is example of far too simply protected value