Ticket #689: 689_full.diff
File 689_full.diff, 9.9 KB (added by , 17 years ago) |
---|
-
django/contrib/auth/backends.py
diff --git a/django/contrib/auth/backends.py b/django/contrib/auth/backends.py index f79929e..74d87f4 100644
a b class ModelBackend: 68 68 return User.objects.get(pk=user_id) 69 69 except User.DoesNotExist: 70 70 return None 71 72 class RemoteUserAuthBackend(ModelBackend): 73 74 def __init__(self): 75 if self.__class__ == RemoteUserAuthBackend: 76 raise TypeError, "You must create your own class derived\ 77 from Remote UserAuthBackend in order to use it." 78 79 def authenticate(self, username, password=None): 80 """ 81 Authenticate user - RemoteUserAuth middleware passes REMOTE_USER 82 as username. password param is not used, just added in case :) 83 """ 84 user = None 85 if username: 86 username = self.parse_user(username) 87 try: 88 user = User.objects.get(username=username) 89 except User.DoesNotExist: 90 user = self.unknown_user(username) 91 user = self.configure_user(user) 92 return user 93 94 def parse_user(self, username): 95 """ Parse the provided username. 96 Override this method if you need to do special things with the 97 username, like stripping @realm or cleaning something like 98 cn=x,dc=sas,etc. 99 """ 100 return username 101 102 def unknown_user(self, username): 103 # Auto-create user 104 password = User.objects.make_random_password() 105 user = User.objects.create_user(username, '', password) 106 user.is_staff = False 107 user.save() 108 return user 109 110 def configure_user(self, user): 111 """ Configure a user after login. 112 i.e: to read group membership from LDAP and so on. 113 """ 114 return user 115 -
django/contrib/auth/middleware.py
diff --git a/django/contrib/auth/middleware.py b/django/contrib/auth/middleware.py index 42dc15a..cc8a9d8 100644
a b class AuthenticationMiddleware(object): 10 10 assert hasattr(request, 'session'), "The Django authentication middleware requires session middleware to be installed. Edit your MIDDLEWARE_CLASSES setting to insert 'django.contrib.sessions.middleware.SessionMiddleware'." 11 11 request.__class__.user = LazyUser() 12 12 return None 13 14 class RemoteUserAuthMiddleware(object): 15 def process_request(self, request): 16 from django.contrib.auth import authenticate, login 17 # AuthenticationMiddleware is required to create request.user 18 error = """The Django RemoteUserAuth middleware requires authentication middleware to be installed. Edit your MIDDLEWARE_CLASSES 19 setting to insert 'django.contrib.auth.middleware.AuthenticationMiddleware' *before* the RemoteUserMiddleware class.""" 20 assert hasattr(request, 'user'), error 21 if request.user.is_anonymous(): 22 user = None 23 try: 24 user = authenticate(username=request.META['REMOTE_USER']) 25 except KeyError: 26 pass # No remote user available 27 if user is not None: 28 request.user = user # set request.user to the authenticated user 29 login(request, user) # auto-login the user to Django 30 return None -
django/contrib/auth/tests.py
diff --git a/django/contrib/auth/tests.py b/django/contrib/auth/tests.py index 329049c..30ed042 100644
a b 1 import os 2 import unittest 3 from django.contrib.auth.models import User 4 from django.contrib.auth.backends import RemoteUserAuthBackend 5 from django.test.client import Client 6 from django.conf import settings 7 8 class SimpleDerivedBackend(RemoteUserAuthBackend): 9 pass 10 11 class HttpAuthTest(unittest.TestCase): 12 def setUp(self): 13 self.extra_headers = {'REMOTE_USER': 'iamnotanuser'} 14 self.curr_middleware = settings.MIDDLEWARE_CLASSES 15 self.curr_auth = settings.AUTHENTICATION_BACKENDS 16 17 settings.MIDDLEWARE_CLASSES +=\ 18 ('django.contrib.auth.middleware.RemoteUserAuthMiddleware', ) 19 settings.AUTHENTICATION_BACKENDS =\ 20 ('django.contrib.auth.tests.SimpleDerivedBackend',) 21 22 def testBackendMustBeDerived(self): 23 """ 24 HttpAuthTest.testBackendMustBeDerived: RemoteUserAuthBackend cannot be 25 used without being inherited by another class. 26 """ 27 # RemoteUserAuthBackend cannot be instantiated! 28 self.assertRaises(TypeError, RemoteUserAuthBackend) 29 30 # Check that it won't work on a request. 31 settings.AUTHENTICATION_BACKENDS =\ 32 ('django.contrib.auth.backends.RemoteUserAuthBackend',) 33 c = Client() 34 self.assertRaises(TypeError, c.get ,'/', {}, **self.extra_headers) 35 36 def testRemoteUserIsRespected(self): 37 c = Client() 38 extra_headers = {'REMOTE_USER': 'iamnotanuser'} 39 res = c.get('/', {}, **self.extra_headers) 40 41 u = User.objects.get(username='iamnotanuser') 42 # wow, the user was created! this works. 43 44 def tearDown(self): 45 # Restore settings to avoid breaking other tests. 46 settings.MIDDLEWARE_CLASSES = self.curr_middleware 47 settings.AUTHENTICATION_BACKENDS = self.curr_auth 48 1 49 """ 2 50 >>> from models import User, AnonymousUser 3 51 >>> u = User.objects.create_user('testuser', 'test@example.com', 'testpw') … … False 23 71 [] 24 72 >>> a.user_permissions.all() 25 73 [] 26 """ 27 No newline at end of file 74 """ -
new file docs/auth_remote_user.txt
diff --git a/docs/auth_remote_user.txt b/docs/auth_remote_user.txt new file mode 100644 index 0000000..57945e1
- + 1 ====================================================== 2 Authenticating against REMOTE_USER from the Web Server 3 ====================================================== 4 5 Typically on intranet sites users are already authenticated (i.e. in a Windows 6 domain) by the web server (i.e. using IIS Integrated Authentication). 7 8 When the web server takes care of authentication it sets the ``REMOTE_USER`` HTTP 9 header for use in the underlying application (i.e. Django). Then it's up to 10 this application take care of the authorization. 11 12 Django brings all you need to make use of the ``REMOTE_USER`` header bringing you 13 one step furder to single sign-on on enterprise infrastucure! 14 15 We assume that you have already configured your web server to authenticate 16 users, maybe with mod_auth_sspi in Apache, Integrated Authentication in IIS 17 and so on. 18 19 Configuring Django 20 ================== 21 22 First of all, you must add the ``RemoteUserAuthMiddleware`` just **after** 23 (never before) ``AuthenticationMiddleware``. 24 25 After this, you'll have to create you authentication backend that will take 26 care of checking that ``REMOTE_USER`` is valid. But don't be scared, 27 ``RemoteUserAuthBackend`` is here to help you. 28 29 ``RemoteUserAuthBackend`` provides a "template" of what you need, you could 30 create a backend that simply inherits it and you are done. It will simply 31 assume that ``REMOTE_USER`` is always correct and create ``User``objects for 32 it. 33 34 If you want more control, in you inherited authentication backend you can 35 override a few methods: 36 37 * ``parse_user``: Should cleanup ``REMOTE_USER`` (i.e. strip @realm from 38 it). It takes the ``username`` as argument, and must return the cleaned 39 ``username``. 40 * ``unkown_user``: Should create and return a ``User`` object, will be 41 called when a ``User`` object does not exist for ``REMOTE_USER``. Takes 42 ``username`` as it's only argument. 43 * ``configure_user``: Will be called after ``unkown_user`` so you can 44 configure the recently created ``User`` object (in case you did not want 45 to override ``unkown_user``. Takes the ``User`` instance as an argument. 46 Should also return the ``User`` instance that represents the User. 47 48 49 Examples: 50 51 settings.py:: 52 53 MIDDLEWARE_CLASSES = ( 54 'django.contrib.auth.middleware.AuthenticationMiddleware', 55 'django.contrib.auth.middleware.RemoteUserAuthMiddleware', 56 ... 57 ) 58 59 AUTHENTICATION_BACKENDS = ( 60 'myproject.backends.MyDerivedBackend', 61 ) 62 63 myproject/backends.py:: 64 65 from django.contrib.auth.backends import RemoteUserAuthBackend 66 67 class MyDerivedBackend(RemoteUserAuthBackend): 68 # We don't really do anything, we are fine with the default 69 # behaviour. 70 pass -
docs/authentication.txt
diff --git a/docs/authentication.txt b/docs/authentication.txt index 2c34c66..dd77ee1 100644
a b plug in another authentication sources. You can override Django's default 966 966 database-based scheme, or you can use the default system in tandem with other 967 967 systems. 968 968 969 There's a very specific situation/scenario in which you want to handle 970 authentication at the web server's level (i.e. standard HTTP AUTH) and want 971 Django to honour this authentication. This is covered in a separate page: 972 `Authenticating against REMOTE_USER from the Web Server`_ 973 974 .. _Authenticating against REMOTE_USER from the Web Server: ../auth_remote_user/ 975 969 976 Specifying authentication backends 970 977 ---------------------------------- 971 978 -
docs/request_response.txt
diff --git a/docs/request_response.txt b/docs/request_response.txt index 8da00cd..e12f1f5 100644
a b All attributes except ``session`` should be considered read-only. 109 109 * ``QUERY_STRING`` -- The query string, as a single (unparsed) string. 110 110 * ``REMOTE_ADDR`` -- The IP address of the client. 111 111 * ``REMOTE_HOST`` -- The hostname of the client. 112 * ``REMOTE_USER`` -- The user authenticated by the web server, if any. 112 113 * ``REQUEST_METHOD`` -- A string such as ``"GET"`` or ``"POST"``. 113 114 * ``SERVER_NAME`` -- The hostname of the server. 114 115 * ``SERVER_PORT`` -- The port of the server.