Index: django/contrib/auth/views.py
===================================================================
--- django/contrib/auth/views.py	(revision 9081)
+++ django/contrib/auth/views.py	(working copy)
@@ -14,11 +14,13 @@
 from django.contrib.auth.models import User
 from django.views.decorators.cache import never_cache
 
-def login(request, template_name='registration/login.html', redirect_field_name=REDIRECT_FIELD_NAME):
+def login(request, template_name='registration/login.html',
+          redirect_field_name=REDIRECT_FIELD_NAME,
+          authentication_form=AuthenticationForm):
     "Displays the login form and handles the login action."
     redirect_to = request.REQUEST.get(redirect_field_name, '')
     if request.method == "POST":
-        form = AuthenticationForm(data=request.POST)
+        form = authentication_form(data=request.POST)
         if form.is_valid():
             # Light security check -- make sure redirect_to isn't garbage.
             if not redirect_to or '//' in redirect_to or ' ' in redirect_to:
@@ -29,7 +31,7 @@
                 request.session.delete_test_cookie()
             return HttpResponseRedirect(redirect_to)
     else:
-        form = AuthenticationForm(request)
+        form = authentication_form(request)
     request.session.set_test_cookie()
     if Site._meta.installed:
         current_site = Site.objects.get_current()
@@ -67,7 +69,7 @@
 # 4 views for password reset:
 # - password_reset sends the mail
 # - password_reset_done shows a success message for the above
-# - password_reset_confirm checks the link the user clicked and 
+# - password_reset_confirm checks the link the user clicked and
 #   prompts for a new password
 # - password_reset_complete shows a success message for the above
 
@@ -130,7 +132,7 @@
     else:
         context_instance['validlink'] = False
         form = None
-    context_instance['form'] = form    
+    context_instance['form'] = form
     return render_to_response(template_name, context_instance=context_instance)
 
 def password_reset_complete(request, template_name='registration/password_reset_complete.html'):
@@ -138,16 +140,16 @@
                                                                              {'login_url': settings.LOGIN_URL}))
 
 def password_change(request, template_name='registration/password_change_form.html',
-                    post_change_redirect=None):
+                    post_change_redirect=None, password_change_form=PasswordChangeForm):
     if post_change_redirect is None:
         post_change_redirect = reverse('django.contrib.auth.views.password_change_done')
     if request.method == "POST":
-        form = PasswordChangeForm(request.user, request.POST)
+        form = password_change_form(user=request.user, data=request.POST)
         if form.is_valid():
             form.save()
             return HttpResponseRedirect(post_change_redirect)
     else:
-        form = PasswordChangeForm(request.user)
+        form = password_change_form(user=request.user)
     return render_to_response(template_name, {
         'form': form,
     }, context_instance=RequestContext(request))
Index: docs/topics/auth.txt
===================================================================
--- docs/topics/auth.txt	(revision 9081)
+++ docs/topics/auth.txt	(working copy)
@@ -246,8 +246,8 @@
     .. method:: models.UserManager.create_user(username, email, password=None)
 
         Creates, saves and returns a :class:`~django.contrib.auth.models.User`.
-        The :attr:`~django.contrib.auth.models.User.username`, 
-        :attr:`~django.contrib.auth.models.User.email` and 
+        The :attr:`~django.contrib.auth.models.User.username`,
+        :attr:`~django.contrib.auth.models.User.email` and
         :attr:`~django.contrib.auth.models.User.password` are set as given, and the
         :class:`~django.contrib.auth.models.User` gets ``is_active=True``.
 
@@ -351,11 +351,11 @@
       ``False`` instead of ``True``.
     * :meth:`~django.contrib.auth.models.User.has_perm()` always returns ``False``.
     * :meth:`~django.contrib.auth.models.User.set_password()`,
-      :meth:`~django.contrib.auth.models.User.check_password()`, 
-      :meth:`~django.contrib.auth.models.User.save()`, 
+      :meth:`~django.contrib.auth.models.User.check_password()`,
+      :meth:`~django.contrib.auth.models.User.save()`,
       :meth:`~django.contrib.auth.models.User.delete()`,
-      :meth:`~django.contrib.auth.models.User.set_groups()` and 
-      :meth:`~django.contrib.auth.models.User.set_permissions()` raise 
+      :meth:`~django.contrib.auth.models.User.set_groups()` and
+      :meth:`~django.contrib.auth.models.User.set_permissions()` raise
       :exc:`NotImplementedError`.
 
 In practice, you probably won't need to use
@@ -523,11 +523,9 @@
     :func:`~django.contrib.auth.authenticate()`
     sets an attribute on the :class:`~django.contrib.auth.models.User` noting
     which authentication backend successfully authenticated that user (see
-    the `backends documentation`_ for details), and this information is
-    needed later during the login process.
+    :ref:`authentication-backends` for details), and this information is needed
+    later during the login process.
 
-.. _backends documentation: #other-authentication-sources
-
 Manually checking a user's password
 -----------------------------------
 
@@ -683,7 +681,7 @@
           :class:`~django.contrib.sites.models.Site``, according to the
           :setting:`SITE_ID` setting. If you're using the Django development version
           and you don't have the site framework installed, this will be set to the
-          value of ``request.META['SERVER_NAME']``. For more on sites, see 
+          value of ``request.META['SERVER_NAME']``. For more on sites, see
           :ref:`ref-contrib-sites`.
 
     If you'd prefer not to call the template :file:`registration/login.html`,
@@ -717,6 +715,15 @@
 
         {% endblock %}
 
+    **New in Django development version**
+
+    If you are using alternate authentication (see
+    :ref:`authentication-backends`) you can pass a custom authentication form
+    to the login view via the ``authentication_form`` parameter. This form must
+    accept a ``request`` keyword argument in its ``__init__`` method, and
+    provide a ``get_user`` argument which returns the authenticated user object
+    (this method is only ever called after successful form validation).
+
     .. _forms documentation: ../forms/
     .. _site framework docs: ../sites/
 
@@ -760,6 +767,15 @@
           displaying the password change form. This will default to
           :file:`registration/password_change_form.html` if not supplied.
 
+        * ``post_change_redirect``: The URL which the user will be redirected
+          to after a successful password change (defaults to the reverse of the
+          :func:`django.contrib.auth.views.password_change_done` view).
+
+        * ``password_change_form``: A custom "change password" form which must
+          accept a ``user`` keyword argument. The form is responsible for
+          actually changing the user's password.
+          (**New in Django development version**)
+
     **Template context:**
 
         * ``form``: The password change form.
@@ -1029,7 +1045,7 @@
 fields:
 
 .. attribute:: models.Permission.name
-    
+
     Required. 50 characters or fewer. Example: ``'Can vote'``.
 
 .. attribute:: models.Permission.content_type
@@ -1038,7 +1054,7 @@
     which contains a record for each installed Django model.
 
 .. attribute:: models.Permission.codename
-    
+
     Required. 100 characters or fewer. Example: ``'can_vote'``.
 
 Methods
@@ -1061,7 +1077,7 @@
    :setting:`TEMPLATE_CONTEXT_PROCESSORS` setting contains
    ``"django.core.context_processors.auth"``, which is default. For more, see
    the :ref:`RequestContext docs <subclassing-context-requestcontext>`.
-   
+
 Users
 -----
 
@@ -1091,7 +1107,7 @@
 
     {{ perms.foo }}
 
-Two-level-attribute lookup is a proxy to 
+Two-level-attribute lookup is a proxy to
 :meth:`User.has_perm <django.contrib.auth.models.User.has_perm>`. This example
 would display ``True`` if the logged-in user had the permission
 ``foo.can_vote``::
@@ -1145,7 +1161,7 @@
 
     To create a new message, use
     ``user_obj.message_set.create(message='message_text')``.
-    
+
     To retrieve/delete messages, use
     :meth:`user_obj.get_and_delete_messages() <django.contrib.auth.models.User.get_and_delete_messages>`,
     which returns a list of ``Message`` objects in the user's queue (if any)
@@ -1305,7 +1321,7 @@
 
 The user model will delegate permission lookup functions
 (:meth:`~django.contrib.auth.models.User.get_group_permissions()`,
-:meth:`~django.contrib.auth.models.User.get_all_permissions()`, 
+:meth:`~django.contrib.auth.models.User.get_all_permissions()`,
 :meth:`~django.contrib.auth.models.User.has_perm()`, and
 :meth:`~django.contrib.auth.models.User.has_module_perms()`) to any
 authentication backend that implements these functions.
