Ticket #689: t689-r7609.diff

File t689-r7609.diff, 8.4 KB (added by Ramiro Morales, 11 years ago)

Patch updated to apply cleanly to r7609 incorporating fixes and suggestions by Thomas Guettler plus additional fixes and docs content

  • django/contrib/auth/backends.py

    diff -r b7788e7bd0a8 django/contrib/auth/backends.py
    a b class ModelBackend(object): 
    6868            return User.objects.get(pk=user_id)
    6969        except User.DoesNotExist:
    7070            return None
     71
     72class RemoteUserAuthBackend:
     73
     74    def authenticate(self, username, password=None):
     75        """
     76        Authenticate user - RemoteUserAuth middleware passes REMOTE_USER
     77        as username.
     78        """
     79        if password is not None:
     80            return None
     81        user = None
     82        if username:
     83            username = self.parse_user(username)
     84            try:
     85                user = User.objects.get(username=username)
     86            except User.DoesNotExist:
     87                user = self.unknown_user(username)
     88                user = self.configure_user(user)
     89        return user
     90
     91    def parse_user(self, username):
     92        """ Parse the provided username.
     93        Override this method if you need to do special things with the
     94        username, like stripping @realm or cleaning something like
     95        cn=x,dc=sas,etc.
     96        """
     97        return username
     98
     99    def get_user(self, user_id):
     100        try:
     101            return User.objects.get(pk=user_id)
     102        except User.DoesNotExist:
     103            return None
     104
     105    def unknown_user(self, username):
     106        """Auto-create user. Called only if User object doesn't already exist
     107        for username.
     108        """
     109        user = User.objects.create_user(username, '')
     110        user.is_staff = False
     111        user.save()
     112        return user
     113
     114    def configure_user(self, user):
     115        """ Configure a user after login.
     116        i.e: to read group membership from LDAP and so on.
     117        Called only if user User object has just benn created."
     118        """
     119        return user
  • django/contrib/auth/middleware.py

    diff -r b7788e7bd0a8 django/contrib/auth/middleware.py
    a b class AuthenticationMiddleware(object): 
    1010        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'."
    1111        request.__class__.user = LazyUser()
    1212        return None
     13
     14class 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
     19setting 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 -r b7788e7bd0a8 django/contrib/auth/tests.py
    a b u'joe@somewhere.org' 
    5252u'joe@somewhere.org'
    5353>>> u.password
    5454u'!'
    55 """
    56  No newline at end of file
     55"""
     56
     57import os
     58import unittest
     59from doctest import DocTestSuite
     60from django.contrib.auth.models import User
     61from django.contrib.auth.backends import RemoteUserAuthBackend
     62from django.test.client import Client
     63from django.conf import settings
     64
     65class HttpAuthTest(unittest.TestCase):
     66    def setUp(self):
     67        self.extra_headers = {'REMOTE_USER': 'iamnotanuser'}
     68        self.curr_middleware = settings.MIDDLEWARE_CLASSES
     69        self.curr_auth = settings.AUTHENTICATION_BACKENDS
     70
     71        settings.MIDDLEWARE_CLASSES +=\
     72            ('django.contrib.auth.middleware.RemoteUserAuthMiddleware', )
     73        settings.AUTHENTICATION_BACKENDS =\
     74            ('django.contrib.auth.backends.RemoteUserAuthBackend',)
     75
     76    def testRemoteUserIsRespected(self):
     77        c = Client()
     78        extra_headers = {'REMOTE_USER': 'iamnotanuser'}
     79        res = c.get('/', {}, **self.extra_headers)
     80
     81        u = User.objects.get(username='iamnotanuser')
     82        # wow, the user was created! this works.
     83
     84    def tearDown(self):
     85        # Restore settings to avoid breaking other tests.
     86        settings.MIDDLEWARE_CLASSES = self.curr_middleware
     87        settings.AUTHENTICATION_BACKENDS = self.curr_auth
     88
     89
     90def suite():
     91    doctest_suite = DocTestSuite()
     92    http_auth_suite = unittest.TestLoader().loadTestsFromTestCase(HttpAuthTest)
     93    return unittest.TestSuite([doctest_suite, http_auth_suite])
  • new file docs/auth_remote_user.txt

    diff -r b7788e7bd0a8 docs/auth_remote_user.txt
    - +  
     1======================================================
     2Authenticating against REMOTE_USER from the Web Server
     3======================================================
     4
     5Typically on intranet sites users are already authenticated by the web server
     6(e.g. a Windows domain using IIS Integrated Authentication, Apache
     7`mod_authnz_ldap`_, `CAS`_, `Cosign`_, `WebAuth`_, etc.)
     8
     9.. _mod_authnz_ldap: http://httpd.apache.org/docs/2.2/mod/mod_authnz_ldap.html
     10.. _CAS: http://www.ja-sig.org/products/cas/
     11.. _Cosign: http://weblogin.org
     12.. _WebAuth: http://www.stanford.edu/services/webauth/
     13
     14When the web server takes care of authentication it sets the ``REMOTE_USER`` HTTP
     15header for use in the underlying application (i.e. Django). Then it's up to
     16this application take care of the authorization.
     17
     18Django brings all you need to make use of the ``REMOTE_USER`` header bringing you
     19one step further to single sign-on on enterprise infrastucure!
     20
     21We assume that you have already configured your web server to authenticate
     22users, maybe with mod_auth_sspi in Apache, Integrated Authentication in IIS
     23and so on.
     24
     25Configuring Django
     26==================
     27
     28First of all, you must add the ``RemoteUserAuthMiddleware`` just **after**
     29(never before) ``AuthenticationMiddleware``.
     30
     31If you want more control, you can inherit from ``RemoteUserAuthBackend`` and
     32override a few methods:
     33
     34   * ``parse_user``: Should cleanup ``REMOTE_USER`` (i.e. strip @realm from
     35     it). It takes the ``username`` as argument, and must return the cleaned
     36     ``username``.
     37   * ``unkown_user``: Will be called when no ``User`` object exist for
     38     ``REMOTE_USER``. Takes ``username`` as it's only argument. Should create
     39     and return a ``User`` object.
     40   * ``configure_user``: Will be called after ``unknown_user`` only when a new
     41     ``User`` object has been created so you can configure it. Takes the
     42     newly created ``User`` instance as it's only argument. Should also return
     43     the ``User`` instance that represents the User.
     44
     45Examples:
     46
     47    settings.py::
     48
     49        MIDDLEWARE_CLASSES = (
     50            'django.contrib.auth.middleware.AuthenticationMiddleware',
     51            'django.contrib.auth.middleware.RemoteUserAuthMiddleware',
     52            ...
     53            )
     54
     55        AUTHENTICATION_BACKENDS = (
     56            'django.contrib.auth.backends.RemoteUserAuthBackend',
     57        )
  • docs/authentication.txt

    diff -r b7788e7bd0a8 docs/authentication.txt
    a b database-based scheme, or you can use th 
    10311031database-based scheme, or you can use the default system in tandem with other
    10321032systems.
    10331033
     1034**New in Django development version**
     1035
     1036.. admonition:: Handling authentication at the web server
     1037
     1038    There's a very specific situation/scenario in which you want to handle
     1039    authentication at the web server's level (i.e. standard HTTP AUTH) and want
     1040    Django to honour this authentication. This is covered in a separate page:
     1041    `Authenticating against REMOTE_USER from the Web Server`_
     1042
     1043.. _Authenticating against REMOTE_USER from the Web Server: ../auth_remote_user/
     1044
    10341045Specifying authentication backends
    10351046----------------------------------
    10361047
Back to Top