Ticket #689: t689-r7823.diff

File t689-r7823.diff, 8.1 KB (added by Ramiro Morales, 16 years ago)
  • django/contrib/auth/backends.py

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

    diff -r ff26bafd50e1 django/contrib/auth/middleware.py
    a b  
    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 ff26bafd50e1 django/contrib/auth/tests.py
    a b  
    7373        response = self.client.post('/password_reset/', {'email': 'staffmember@example.com'})
    7474        self.assertEquals(response.status_code, 302)
    7575        self.assertEquals(len(mail.outbox), 1)
     76
     77from django.contrib.auth.models import User
     78from django.conf import settings
     79
     80class HttpAuthTest(TestCase):
     81    def setUp(self):
     82        self.curr_middleware = settings.MIDDLEWARE_CLASSES
     83        self.curr_auth = settings.AUTHENTICATION_BACKENDS
     84
     85        settings.MIDDLEWARE_CLASSES +=\
     86            ('django.contrib.auth.middleware.RemoteUserAuthMiddleware', )
     87        settings.AUTHENTICATION_BACKENDS =\
     88            ('django.contrib.auth.backends.RemoteUserAuthBackend',)
     89
     90    def test_remote_user(self):
     91        "REMOTE_USER variable set by Web server is respected"
     92        extra_headers = {'REMOTE_USER': 'iamnotanuser'}
     93        response = self.client.get('/', **extra_headers)
     94
     95        u = User.objects.get(username='iamnotanuser')
     96        # if no exception ws raises above it means this works.
     97
     98    def tearDown(self):
     99        # Restore settings to avoid breaking other tests.
     100        settings.MIDDLEWARE_CLASSES = self.curr_middleware
     101        settings.AUTHENTICATION_BACKENDS = self.curr_auth
  • new file docs/auth_remote_user.txt

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

    diff -r ff26bafd50e1 docs/authentication.txt
    a b  
    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