Ticket #689: t689-r7350.diff

File t689-r7350.diff, 9.9 KB (added by Ramiro Morales, 11 years ago)
  • django/contrib/auth/backends.py

    diff -r 983be4e9b98c django/contrib/auth/backends.py
    a b from django.db import connection 
    11from django.db import connection
    22from django.contrib.auth.models import User
    33
    4 try: 
    5     set 
    6 except NameError: 
     4try:
     5    set
     6except NameError:
    77    from sets import Set as set # Python 2.3 fallback
    8        
     8
    99class ModelBackend(object):
    1010    """
    1111    Authenticate against django.contrib.auth.models.User
    class ModelBackend(object): 
    5050            cursor.execute(sql, [user_obj.id])
    5151            user_obj._group_perm_cache = set(["%s.%s" % (row[0], row[1]) for row in cursor.fetchall()])
    5252        return user_obj._group_perm_cache
    53    
     53
    5454    def get_all_permissions(self, user_obj):
    5555        if not hasattr(user_obj, '_perm_cache'):
    5656            user_obj._perm_cache = set([u"%s.%s" % (p.content_type.app_label, p.codename) for p in user_obj.user_permissions.select_related()])
    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
     107        user = User.objects.create_user(username, '')
     108        user.is_staff = False
     109        user.save()
     110        return user
     111
     112    def configure_user(self, user):
     113        """ Configure a user after login.
     114        i.e: to read group membership from LDAP and so on.
     115        """
     116        return user
  • django/contrib/auth/middleware.py

    diff -r 983be4e9b98c 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 983be4e9b98c django/contrib/auth/tests.py
    a b False 
    3535[]
    3636>>> a.user_permissions.all()
    3737[]
    38 """
    39  No newline at end of file
     38"""
     39
     40import os
     41import unittest
     42from doctest import DocTestSuite
     43from django.contrib.auth.models import User
     44from django.contrib.auth.backends import RemoteUserAuthBackend
     45from django.test.client import Client
     46from django.conf import settings
     47
     48class HttpAuthTest(unittest.TestCase):
     49    def setUp(self):
     50        self.extra_headers = {'REMOTE_USER': 'iamnotanuser'}
     51        self.curr_middleware = settings.MIDDLEWARE_CLASSES
     52        self.curr_auth = settings.AUTHENTICATION_BACKENDS
     53
     54        settings.MIDDLEWARE_CLASSES +=\
     55            ('django.contrib.auth.middleware.RemoteUserAuthMiddleware', )
     56        settings.AUTHENTICATION_BACKENDS =\
     57            ('django.contrib.auth.backends.RemoteUserAuthBackend',)
     58
     59    def testRemoteUserIsRespected(self):
     60        c = Client()
     61        extra_headers = {'REMOTE_USER': 'iamnotanuser'}
     62        res = c.get('/', {}, **self.extra_headers)
     63
     64        u = User.objects.get(username='iamnotanuser')
     65        # wow, the user was created! this works.
     66
     67    def tearDown(self):
     68        # Restore settings to avoid breaking other tests.
     69        settings.MIDDLEWARE_CLASSES = self.curr_middleware
     70        settings.AUTHENTICATION_BACKENDS = self.curr_auth
     71
     72
     73def suite():
     74    doctest_suite = DocTestSuite()
     75    http_auth_suite = unittest.TestLoader().loadTestsFromTestCase(HttpAuthTest)
     76    return unittest.TestSuite([doctest_suite, http_auth_suite])
  • new file docs/auth_remote_user.txt

    diff -r 983be4e9b98c docs/auth_remote_user.txt
    - +  
     1======================================================
     2Authenticating against REMOTE_USER from the Web Server
     3======================================================
     4
     5Typically on intranet sites users are already authenticated (i.e. in a Windows
     6domain) by the web server (i.e. using IIS Integrated Authentication).
     7
     8When the web server takes care of authentication it sets the ``REMOTE_USER`` HTTP
     9header for use in the underlying application (i.e. Django). Then it's up to
     10this application take care of the authorization.
     11
     12Django brings all you need to make use of the ``REMOTE_USER`` header bringing you
     13one step furder to single sign-on on enterprise infrastucure!
     14
     15We assume that you have already configured your web server to authenticate
     16users, maybe with mod_auth_sspi in Apache, Integrated Authentication in IIS
     17and so on.
     18
     19Configuring Django
     20==================
     21
     22First of all, you must add the ``RemoteUserAuthMiddleware`` just **after**
     23(never before) ``AuthenticationMiddleware``.
     24
     25After this, you'll have to create you authentication backend that will take
     26care 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
     30create a backend that simply inherits it and you are done. It will simply
     31assume that ``REMOTE_USER`` is always correct and create ``User``objects for
     32it.
     33
     34If you want more control, in you inherited authentication backend you can
     35override 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
     49Examples:
     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            'django.contrib.auth.backends.RemoteUserAuthBackend',
     61        )
  • docs/authentication.txt

    diff -r 983be4e9b98c docs/authentication.txt
    a b database-based scheme, or you can use th 
    10191019database-based scheme, or you can use the default system in tandem with other
    10201020systems.
    10211021
     1022.. admonition:: Handling authentication at the web server
     1023
     1024    There's a very specific situation/scenario in which you want to handle
     1025    authentication at the web server's level (i.e. standard HTTP AUTH) and want
     1026    Django to honour this authentication. This is covered in a separate page:
     1027    `Authenticating against REMOTE_USER from the Web Server`_
     1028
     1029.. _Authenticating against REMOTE_USER from the Web Server: ../auth_remote_user/
     1030
    10221031Specifying authentication backends
    10231032----------------------------------
    10241033
  • docs/request_response.txt

    diff -r 983be4e9b98c docs/request_response.txt
    a b All attributes except ``session`` should 
    109109        * ``QUERY_STRING`` -- The query string, as a single (unparsed) string.
    110110        * ``REMOTE_ADDR`` -- The IP address of the client.
    111111        * ``REMOTE_HOST`` -- The hostname of the client.
     112        * ``REMOTE_USER`` -- The user authenticated by the web server, if any.
    112113        * ``REQUEST_METHOD`` -- A string such as ``"GET"`` or ``"POST"``.
    113114        * ``SERVER_NAME`` -- The hostname of the server.
    114115        * ``SERVER_PORT`` -- The port of the server.
Back to Top