Ticket #689: 689.2.diff

File 689.2.diff, 10.0 KB (added by Marc Fargas, 15 years ago)

New patch with Gary's comments

  • django/contrib/auth/backends.py

    diff --git a/django/contrib/auth/backends.py b/django/contrib/auth/backends.py
    index bba883b..fdc0df9 100644
    a b class ModelBackend(object):  
    7878            return User.objects.get(pk=user_id)
    7979        except User.DoesNotExist:
    8080            return None
     81
     82class RemoteUserAuthBackend(ModelBackend):
     83    create_unknown_user = True
     84
     85    def authenticate(self, username, password=None):
     86        """
     87        Authenticate user - RemoteUserAuth middleware passes REMOTE_USER
     88        as username.
     89        """
     90        if password is not None:
     91            return None
     92        user = None
     93        if username:
     94            username = self.parse_user(username)
     95            if self.create_unknown_user:
     96                user, created = User.objects.get_or_create(username=username)
     97                if created:
     98                    user = self.configure_user(user)
     99            else:
     100                try:
     101                    user = User.objects.get(username=username)
     102                except User.DoesNotExist:
     103                    return None
     104        return user
     105
     106    def parse_user(self, username):
     107        """ Parse the provided username.
     108        Override this method if you need to do special things with the
     109        username, like stripping @realm or cleaning something like
     110        cn=x,dc=sas,etc.
     111        """
     112        return username
     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 been created."
     118        """
     119        return user
  • django/contrib/auth/middleware.py

    diff --git a/django/contrib/auth/middleware.py b/django/contrib/auth/middleware.py
    index 42dc15a..7deb0fe 100644
    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
     31
  • django/contrib/auth/tests/__init__.py

    diff --git a/django/contrib/auth/tests/__init__.py b/django/contrib/auth/tests/__init__.py
    index 23cfbaf..b40a9c2 100644
    a b  
    1 from django.contrib.auth.tests.basic import BASIC_TESTS
     1from django.contrib.auth.tests.basic import BASIC_TESTS, HttpAuthTest
    22from django.contrib.auth.tests.views import PasswordResetTest, ChangePasswordTest
    33from django.contrib.auth.tests.forms import FORM_TESTS
    44from django.contrib.auth.tests.tokens import TOKEN_GENERATOR_TESTS
    __test__ = {  
    1111    'FORM_TESTS': FORM_TESTS,
    1212    'TOKEN_GENERATOR_TESTS': TOKEN_GENERATOR_TESTS,
    1313    'CHANGEPASSWORD_TESTS': ChangePasswordTest,
     14    'HTTPAUTH_TESTS': HttpAuthTest,
    1415}
  • django/contrib/auth/tests/basic.py

    diff --git a/django/contrib/auth/tests/basic.py b/django/contrib/auth/tests/basic.py
    index 2071710..be2b8ca 100644
    a b u'joe@somewhere.org'  
    5454>>> u.password
    5555u'!'
    5656"""
     57
     58from django.test import TestCase
     59from django.contrib.auth.models import User
     60from django.conf import settings
     61
     62class HttpAuthTest(TestCase):
     63    def setUp(self):
     64        self.curr_middleware = settings.MIDDLEWARE_CLASSES
     65        self.curr_auth = settings.AUTHENTICATION_BACKENDS
     66
     67        settings.MIDDLEWARE_CLASSES +=\
     68            ('django.contrib.auth.middleware.RemoteUserAuthMiddleware', )
     69        settings.AUTHENTICATION_BACKENDS =\
     70            ('django.contrib.auth.backends.RemoteUserAuthBackend',)
     71
     72    def test_remote_user(self):
     73        "REMOTE_USER variable set by Web server is respected"
     74        extra_headers = {'REMOTE_USER': 'iamnotanuser'}
     75        response = self.client.get('/', **extra_headers)
     76
     77        u = User.objects.get(username='iamnotanuser')
     78        # if no exception ws raises above it means this works.
     79
     80    def tearDown(self):
     81        # Restore settings to avoid breaking other tests.
     82        settings.MIDDLEWARE_CLASSES = self.curr_middleware
     83        settings.AUTHENTICATION_BACKENDS = self.curr_auth
  • new file docs/topics/auth-remote-user.txt

    diff --git a/docs/topics/auth-remote-user.txt b/docs/topics/auth-remote-user.txt
    new file mode 100644
    index 0000000..71a2782
    - +  
     1.. _topics-auth-remote-user:
     2
     3======================================================
     4Authenticating against REMOTE_USER from the Web Server
     5======================================================
     6
     7Typically on intranet sites users are already authenticated by the web server
     8(e.g. a Windows domain using IIS Integrated Authentication, or an environment
     9using solutions like Apache `mod_authnz_ldap`_, `CAS`_, `Cosign`_, `WebAuth`_,
     10etc.)
     11
     12.. _mod_authnz_ldap: http://httpd.apache.org/docs/2.2/mod/mod_authnz_ldap.html
     13.. _CAS: http://www.ja-sig.org/products/cas/
     14.. _Cosign: http://weblogin.org
     15.. _WebAuth: http://www.stanford.edu/services/webauth/
     16
     17When the web server takes care of authentication it sets the ``REMOTE_USER``
     18header for use in the underlying application. Then it's up to this
     19application to take care of the authorization.
     20
     21Django can be configured to make use of the ``REMOTE_USER`` header making it
     22possible to integrate your Django applications with a pre-existing single
     23sign-on enterprise infrastructure.
     24
     25We assume that you have already configured your web server to authenticate
     26users (i.e. by using ``mod_auth_sspi`` in Apache, Integrated Authentication in
     27IIS or one of the solutions listed above).
     28
     29Configuring Django
     30==================
     31
     32First of all, you must add the ``RemoteUserAuthMiddleware`` to the
     33``MIDDLEWARE_CLASSES`` setting just **after** (never before)
     34``AuthenticationMiddleware``.
     35
     36With this setup, ``RemoteUserAuthMiddleware`` will detect the ``REMOTE_USER``
     37variable in the requests and will auto-login the user by using the username
     38contained in such variable. The user must already exist in the authentication
     39backend being used by Django.
     40
     41Additionally, you need to add an authentication backend to Django. This backend
     42is responsible of doing extra authorization and user setup when it's logged in
     43by the ``RemoteUserAuthMiddleware``. A fully-working sample backend is provided
     44which you can use by adding ``RemoteUserAuthBackend`` in the
     45``AUTHENTICATION_BACKENDS`` setting.
     46
     47If you want even more control, you can create your own authentication backend
     48that inherits from ``RemoteUserAuthBackend``, override a few methods and attributes:
     49
     50   * ``create_unknown_user``: Attribute, tell if the user specified in ``REMOTE_USER``
     51     should be created when it does not exist in the Django database. Defaults to ``True``.
     52   * ``parse_user``: Should cleanup ``REMOTE_USER`` (i.e. strip @realm from
     53     it). It takes the ``username`` as argument, and must return the cleaned
     54     ``username``.
     55   * ``configure_user``: Will be called after ``unknown_user`` only when a new
     56     ``User`` object has been created so you can configure it. Takes the
     57     newly created ``User`` instance as it's only argument. Should also return
     58     the ``User`` instance that represents the user.
     59
     60and use it in the ``AUTHENTICATION_BACKENDS`` setting.
     61
     62Examples:
     63
     64    settings.py::
     65
     66        MIDDLEWARE_CLASSES = (
     67            'django.contrib.auth.middleware.AuthenticationMiddleware',
     68            'django.contrib.auth.middleware.RemoteUserAuthMiddleware',
     69            ...
     70            )
     71
     72        AUTHENTICATION_BACKENDS = (
     73            'django.contrib.auth.backends.RemoteUserAuthBackend',
     74        )
  • docs/topics/auth.txt

    diff --git a/docs/topics/auth.txt b/docs/topics/auth.txt
    index 6de6a3b..4717b3d 100644
    a b plug in another authentication sources. You can override Django's default  
    12241224database-based scheme, or you can use the default system in tandem with other
    12251225systems.
    12261226
     1227.. versionadded:: 1.1
     1228    Handling authentication at the web server was added in Django 1.1
     1229
     1230Handling authentication at the web server
     1231-----------------------------------------
     1232
     1233There's a very specific situation/scenario in which you want to handle
     1234authentication at the web server's level (i.e. standard HTTP AUTH) and want
     1235Django to honour this authentication. This is covered in
     1236:ref:`Authenticating against REMOTE_USER<topics-auth-remote-user>`
     1237
    12271238Specifying authentication backends
    12281239----------------------------------
    12291240
    A full authorization implementation can be found in  
    13601371the ``auth_permission`` table most of the time.
    13611372
    13621373.. _django/contrib/auth/backends.py: http://code.djangoproject.com/browser/django/trunk/django/contrib/auth/backends.py
     1374
  • docs/topics/index.txt

    diff --git a/docs/topics/index.txt b/docs/topics/index.txt
    index 5d83980..710cfc0 100644
    a b Introductions to all the key parts of Django you'll need to know:  
    1717   files
    1818   testing
    1919   auth
     20   auth-remote-user
    2021   cache
    2122   email
    2223   i18n
Back to Top