Merge lp:~mhall119/django-openid-auth/provides-784239 into lp:~django-openid-auth/django-openid-auth/trunk

Proposed by Michael Hall
Status: Merged
Merged at revision: 85
Proposed branch: lp:~mhall119/django-openid-auth/provides-784239
Merge into: lp:~django-openid-auth/django-openid-auth/trunk
Prerequisite: lp:~mhall119/django-openid-auth/django-yubikey-auth
Diff against target: 462 lines (+261/-28)
5 files modified
README.txt (+12/-0)
django_openid_auth/auth.py (+15/-12)
django_openid_auth/exceptions.py (+68/-0)
django_openid_auth/tests/test_views.py (+150/-4)
django_openid_auth/views.py (+16/-12)
To merge this branch: bzr merge lp:~mhall119/django-openid-auth/provides-784239
Reviewer Review Type Date Requested Status
Anthony Lenton Approve
Software Center Agent (community) Approve
Review via email: mp+61497@code.launchpad.net

Commit message

Allow authentication exceptions to bubble up and get passed along to the failure view.

Description of the change

Overview
========
Allow exceptions thrown during authentication to be used to inform the user of the cause of a login failure.

Details
=======
Previously we silently swallowed exceptions during calls to authenticate. Instead we will catch them and pass them along to the failure view so the user can be told explicitly what the problem was with their login attempt.

To post a comment you must log in.
Revision history for this message
Anthony Lenton (elachuni) wrote :

Hi Michael,

I like the approach in general. A few comments/suggestions,
 - you import all defined exceptions on lines 145/151 of the diff, but then you don't seem to use them.
 - does StrictUsernameViolation make sense now? you only use it to inherit from it from two other classes that you raise separately and catch together with all other DjangoOpenIDException. If you think eventually people will want to catch all StrictUsernameViolations together then it's fine as is, otherwise removing it will flatten exception class tree and make it clearer I think.
 - and ideally it would have a test or two I think (to ensure that the messages do indeed reach the user, for example?)
Thanks!

85. By Michael Hall

Cleanup exception class heirarchy and imports, make overriding the login failure handler a settings option, add additional test cases to veryfiy that overriding the handler works and that the proper exceptions are being passed

86. By Michael Hall

Merge from prerequisite branch

87. By Michael Hall

Merge from trunk

88. By Michael Hall

Merge from prerequisite branch

89. By Michael Hall

Fix syntax error from merge

Revision history for this message
Software Center Agent (software-center-agent) wrote :

Thanks Michael!

review: Approve
Revision history for this message
Anthony Lenton (elachuni) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'README.txt'
--- README.txt 2011-08-23 18:55:24 +0000
+++ README.txt 2011-08-23 18:55:24 +0000
@@ -154,3 +154,15 @@
154If the user's OpenID provider supports the PAPE extension and provides the Physical Multifactor authentication policy, this will154If the user's OpenID provider supports the PAPE extension and provides the Physical Multifactor authentication policy, this will
155cause the OpenID login to fail if the user does not provide valid physical authentication to the provider.155cause the OpenID login to fail if the user does not provide valid physical authentication to the provider.
156156
157== Override Login Failure Handling ==
158
159You can optionally provide your own handler for login failures by adding the following setting:
160
161 OPENID_RENDER_FAILURE = failure_handler_function
162
163Where failure_handler_function is a function reference that will take the following parameters:
164
165 def failure_handler_function(request, message, status=None, template_name=None, exception=None)
166
167This function must return a Django.http.HttpResponse instance.
168
157169
=== modified file 'django_openid_auth/auth.py'
--- django_openid_auth/auth.py 2011-08-23 18:55:24 +0000
+++ django_openid_auth/auth.py 2011-08-23 18:55:24 +0000
@@ -37,16 +37,13 @@
3737
38from django_openid_auth import teams38from django_openid_auth import teams
39from django_openid_auth.models import UserOpenID39from django_openid_auth.models import UserOpenID
4040from django_openid_auth.exceptions import (
4141 IdentityAlreadyClaimed,
42class IdentityAlreadyClaimed(Exception):42 DuplicateUsernameViolation,
43 pass43 MissingUsernameViolation,
4444 MissingPhysicalMultiFactor,
45class StrictUsernameViolation(Exception):45 RequiredAttributeNotReturned,
46 pass46)
47
48class RequiredAttributeNotReturned(Exception):
49 pass
5047
51class OpenIDBackend:48class OpenIDBackend:
52 """A django.contrib.auth backend that authenticates the user based on49 """A django.contrib.auth backend that authenticates the user based on
@@ -92,7 +89,7 @@
92 pape_response = pape.Response.fromSuccessResponse(openid_response)89 pape_response = pape.Response.fromSuccessResponse(openid_response)
93 if pape_response is None or \90 if pape_response is None or \
94 pape.AUTH_MULTI_FACTOR_PHYSICAL not in pape_response.auth_policies:91 pape.AUTH_MULTI_FACTOR_PHYSICAL not in pape_response.auth_policies:
95 return None92 raise MissingPhysicalMultiFactor()
9693
97 teams_response = teams.TeamsResponse.fromSuccessResponse(94 teams_response = teams.TeamsResponse.fromSuccessResponse(
98 openid_response)95 openid_response)
@@ -150,6 +147,12 @@
150 first_name=first_name, last_name=last_name)147 first_name=first_name, last_name=last_name)
151148
152 def _get_available_username(self, nickname, identity_url):149 def _get_available_username(self, nickname, identity_url):
150 # If we're being strict about usernames, throw an error if we didn't
151 # get one back from the provider
152 if getattr(settings, 'OPENID_STRICT_USERNAMES', False):
153 if nickname is None or nickname == '':
154 raise MissingUsernameViolation()
155
153 # If we don't have a nickname, and we're not being strict, use a default156 # If we don't have a nickname, and we're not being strict, use a default
154 nickname = nickname or 'openiduser'157 nickname = nickname or 'openiduser'
155158
@@ -184,7 +187,7 @@
184187
185 if getattr(settings, 'OPENID_STRICT_USERNAMES', False):188 if getattr(settings, 'OPENID_STRICT_USERNAMES', False):
186 if User.objects.filter(username__exact=nickname).count() > 0:189 if User.objects.filter(username__exact=nickname).count() > 0:
187 raise StrictUsernameViolation(190 raise DuplicateUsernameViolation(
188 "The username (%s) with which you tried to log in is "191 "The username (%s) with which you tried to log in is "
189 "already in use for a different account." % nickname)192 "already in use for a different account." % nickname)
190193
191194
=== added file 'django_openid_auth/exceptions.py'
--- django_openid_auth/exceptions.py 1970-01-01 00:00:00 +0000
+++ django_openid_auth/exceptions.py 2011-08-23 18:55:24 +0000
@@ -0,0 +1,68 @@
1# django-openid-auth - OpenID integration for django.contrib.auth
2#
3# Copyright (C) 2008-2010 Canonical Ltd.
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions
7# are met:
8#
9# * Redistributions of source code must retain the above copyright
10# notice, this list of conditions and the following disclaimer.
11#
12# * Redistributions in binary form must reproduce the above copyright
13# notice, this list of conditions and the following disclaimer in the
14# documentation and/or other materials provided with the distribution.
15#
16# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
20# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27# POSSIBILITY OF SUCH DAMAGE.
28
29"""Exception classes thrown by OpenID Authentication and Validation."""
30
31class DjangoOpenIDException(Exception):
32 pass
33
34class RequiredAttributeNotReturned(DjangoOpenIDException):
35 pass
36
37class IdentityAlreadyClaimed(DjangoOpenIDException):
38
39 def __init__(self, message=None):
40 if message is None:
41 self.message = "Another user already exists for your selected OpenID"
42 else:
43 self.message = message
44
45class DuplicateUsernameViolation(DjangoOpenIDException):
46
47 def __init__(self, message=None):
48 if message is None:
49 self.message = "Your desired username is already being used."
50 else:
51 self.message = message
52
53class MissingUsernameViolation(DjangoOpenIDException):
54
55 def __init__(self, message=None):
56 if message is None:
57 self.message = "No nickname given for your account."
58 else:
59 self.message = message
60
61class MissingPhysicalMultiFactor(DjangoOpenIDException):
62
63 def __init__(self, message=None):
64 if message is None:
65 self.message = "Login requires physical multi-factor authentication."
66 else:
67 self.message = message
68
069
=== modified file 'django_openid_auth/tests/test_views.py'
--- django_openid_auth/tests/test_views.py 2011-08-23 18:55:24 +0000
+++ django_openid_auth/tests/test_views.py 2011-08-23 18:55:24 +0000
@@ -32,7 +32,7 @@
3232
33from django.conf import settings33from django.conf import settings
34from django.contrib.auth.models import User, Group34from django.contrib.auth.models import User, Group
35from django.http import HttpRequest35from django.http import HttpRequest, HttpResponse
36from django.test import TestCase36from django.test import TestCase
37from openid.consumer.consumer import Consumer, SuccessResponse37from openid.consumer.consumer import Consumer, SuccessResponse
38from openid.consumer.discover import OpenIDServiceEndpoint38from openid.consumer.discover import OpenIDServiceEndpoint
@@ -53,11 +53,15 @@
53from django_openid_auth.auth import OpenIDBackend53from django_openid_auth.auth import OpenIDBackend
54from django_openid_auth.signals import openid_login_complete54from django_openid_auth.signals import openid_login_complete
55from django_openid_auth.store import DjangoOpenIDStore55from django_openid_auth.store import DjangoOpenIDStore
5656from django_openid_auth.exceptions import (
57 MissingUsernameViolation,
58 DuplicateUsernameViolation,
59 MissingPhysicalMultiFactor,
60 RequiredAttributeNotReturned,
61)
5762
58ET = importElementTree()63ET = importElementTree()
5964
60
61class StubOpenIDProvider(HTTPFetcher):65class StubOpenIDProvider(HTTPFetcher):
6266
63 def __init__(self, base_url):67 def __init__(self, base_url):
@@ -179,7 +183,9 @@
179 self.old_use_as_admin_login = getattr(settings, 'OPENID_USE_AS_ADMIN_LOGIN', False)183 self.old_use_as_admin_login = getattr(settings, 'OPENID_USE_AS_ADMIN_LOGIN', False)
180 self.old_follow_renames = getattr(settings, 'OPENID_FOLLOW_RENAMES', False)184 self.old_follow_renames = getattr(settings, 'OPENID_FOLLOW_RENAMES', False)
181 self.old_physical_multifactor = getattr(settings, 'OPENID_PHYSICAL_MULTIFACTOR_REQUIRED', False)185 self.old_physical_multifactor = getattr(settings, 'OPENID_PHYSICAL_MULTIFACTOR_REQUIRED', False)
186 self.old_login_render_failure = getattr(settings, 'OPENID_RENDER_FAILURE', None)
182 self.old_consumer_complete = Consumer.complete187 self.old_consumer_complete = Consumer.complete
188
183 self.old_required_fields = getattr(189 self.old_required_fields = getattr(
184 settings, 'OPENID_SREG_REQUIRED_FIELDS', [])190 settings, 'OPENID_SREG_REQUIRED_FIELDS', [])
185191
@@ -203,6 +209,7 @@
203 settings.OPENID_USE_AS_ADMIN_LOGIN = self.old_use_as_admin_login209 settings.OPENID_USE_AS_ADMIN_LOGIN = self.old_use_as_admin_login
204 settings.OPENID_FOLLOW_RENAMES = self.old_follow_renames210 settings.OPENID_FOLLOW_RENAMES = self.old_follow_renames
205 settings.OPENID_PHYSICAL_MULTIFACTOR_REQUIRED = self.old_physical_multifactor211 settings.OPENID_PHYSICAL_MULTIFACTOR_REQUIRED = self.old_physical_multifactor
212 settings.OPENID_RENDER_FAILURE = self.old_login_render_failure
206 Consumer.complete = self.old_consumer_complete213 Consumer.complete = self.old_consumer_complete
207 settings.OPENID_SREG_REQUIRED_FIELDS = self.old_required_fields214 settings.OPENID_SREG_REQUIRED_FIELDS = self.old_required_fields
208215
@@ -485,6 +492,63 @@
485492
486 response = self.complete(openid_response)493 response = self.complete(openid_response)
487 self.assertEquals(403, response.status_code)494 self.assertEquals(403, response.status_code)
495 self.assertContains(response, '<h1>OpenID failed</h1>', status_code=403)
496 self.assertContains(response, '<p>Login requires physical multi-factor authentication.</p>', status_code=403)
497
498 def test_login_physical_multifactor_not_provided_override(self):
499 settings.OPENID_PHYSICAL_MULTIFACTOR_REQUIRED = True
500 preferred_auth = pape.AUTH_MULTI_FACTOR_PHYSICAL
501 self.provider.type_uris.append(pape.ns_uri)
502
503 # Override the login_failure handler
504 def mock_login_failure_handler(request, message, status=403,
505 template_name=None,
506 exception=None):
507 self.assertTrue(isinstance(exception, MissingPhysicalMultiFactor))
508 return HttpResponse('Test Failure Override', status=200)
509 settings.OPENID_RENDER_FAILURE = mock_login_failure_handler
510
511 def mock_complete(this, request_args, return_to):
512 request = {'openid.mode': 'checkid_setup',
513 'openid.trust_root': 'http://localhost/',
514 'openid.return_to': 'http://localhost/',
515 'openid.identity': IDENTIFIER_SELECT,
516 'openid.ns.pape' : pape.ns_uri,
517 'openid.pape.auth_policies': request_args.get('openid.pape.auth_policies', pape.AUTH_NONE),
518 }
519 openid_server = self.provider.server
520 orequest = openid_server.decodeRequest(request)
521 response = SuccessResponse(
522 self.endpoint, orequest.message,
523 signed_fields=['openid.pape.auth_policies',])
524 return response
525 Consumer.complete = mock_complete
526
527 user = User.objects.create_user('testuser', 'test@example.com')
528 useropenid = UserOpenID(
529 user=user,
530 claimed_id='http://example.com/identity',
531 display_id='http://example.com/identity')
532 useropenid.save()
533
534 openid_req = {'openid_identifier': 'http://example.com/identity',
535 'next': '/getuser/'}
536 openid_resp = {'nickname': 'testuser', 'fullname': 'Openid User',
537 'email': 'test@example.com'}
538
539 openid_request = self._get_login_request(openid_req)
540 openid_response = self._get_login_response(openid_request, openid_req, openid_resp, use_pape=pape.AUTH_NONE)
541
542 response_auth = openid_request.message.getArg(
543 'http://specs.openid.net/extensions/pape/1.0',
544 'auth_policies',
545 )
546 self.assertNotEqual(response_auth, preferred_auth)
547
548 # Status code should be 200, since we over-rode the login_failure handler
549 response = self.complete(openid_response)
550 self.assertEquals(200, response.status_code)
551 self.assertContains(response, 'Test Failure Override')
488552
489 def test_login_without_nickname(self):553 def test_login_without_nickname(self):
490 settings.OPENID_CREATE_USERS = True554 settings.OPENID_CREATE_USERS = True
@@ -680,6 +744,7 @@
680 def test_strict_username_no_nickname(self):744 def test_strict_username_no_nickname(self):
681 settings.OPENID_CREATE_USERS = True745 settings.OPENID_CREATE_USERS = True
682 settings.OPENID_STRICT_USERNAMES = True746 settings.OPENID_STRICT_USERNAMES = True
747 settings.OPENID_SREG_REQUIRED_FIELDS = []
683748
684 # Posting in an identity URL begins the authentication request:749 # Posting in an identity URL begins the authentication request:
685 response = self.client.post('/openid/login/',750 response = self.client.post('/openid/login/',
@@ -701,6 +766,44 @@
701766
702 # Status code should be 403: Forbidden767 # Status code should be 403: Forbidden
703 self.assertEquals(403, response.status_code)768 self.assertEquals(403, response.status_code)
769 self.assertContains(response, '<h1>OpenID failed</h1>', status_code=403)
770 self.assertContains(response, "An attribute required for logging in was not returned "
771 "(nickname)", status_code=403)
772
773 def test_strict_username_no_nickname_override(self):
774 settings.OPENID_CREATE_USERS = True
775 settings.OPENID_STRICT_USERNAMES = True
776 settings.OPENID_SREG_REQUIRED_FIELDS = []
777
778 # Override the login_failure handler
779 def mock_login_failure_handler(request, message, status=403,
780 template_name=None,
781 exception=None):
782 self.assertTrue(isinstance(exception, (RequiredAttributeNotReturned, MissingUsernameViolation)))
783 return HttpResponse('Test Failure Override', status=200)
784 settings.OPENID_RENDER_FAILURE = mock_login_failure_handler
785
786 # Posting in an identity URL begins the authentication request:
787 response = self.client.post('/openid/login/',
788 {'openid_identifier': 'http://example.com/identity',
789 'next': '/getuser/'})
790 self.assertContains(response, 'OpenID transaction in progress')
791
792 # Complete the request, passing back some simple registration
793 # data. The user is redirected to the next URL.
794 openid_request = self.provider.parseFormPost(response.content)
795 sreg_request = sreg.SRegRequest.fromOpenIDRequest(openid_request)
796 openid_response = openid_request.answer(True)
797 sreg_response = sreg.SRegResponse.extractResponse(
798 sreg_request, {'nickname': '', # No nickname
799 'fullname': 'Some User',
800 'email': 'foo@example.com'})
801 openid_response.addExtension(sreg_response)
802 response = self.complete(openid_response)
803
804 # Status code should be 200, since we over-rode the login_failure handler
805 self.assertEquals(200, response.status_code)
806 self.assertContains(response, 'Test Failure Override')
704807
705 def test_strict_username_duplicate_user(self):808 def test_strict_username_duplicate_user(self):
706 settings.OPENID_CREATE_USERS = True809 settings.OPENID_CREATE_USERS = True
@@ -731,11 +834,54 @@
731 response = self.complete(openid_response)834 response = self.complete(openid_response)
732835
733 # Status code should be 403: Forbidden836 # Status code should be 403: Forbidden
837 self.assertEquals(403, response.status_code)
838 self.assertContains(response, '<h1>OpenID failed</h1>', status_code=403)
734 self.assertContains(response,839 self.assertContains(response,
735 "The username (someuser) with which you tried to log in is "840 "The username (someuser) with which you tried to log in is "
736 "already in use for a different account.",841 "already in use for a different account.",
737 status_code=403)842 status_code=403)
738843
844 def test_strict_username_duplicate_user_override(self):
845 settings.OPENID_CREATE_USERS = True
846 settings.OPENID_STRICT_USERNAMES = True
847
848 # Override the login_failure handler
849 def mock_login_failure_handler(request, message, status=403,
850 template_name=None,
851 exception=None):
852 self.assertTrue(isinstance(exception, DuplicateUsernameViolation))
853 return HttpResponse('Test Failure Override', status=200)
854 settings.OPENID_RENDER_FAILURE = mock_login_failure_handler
855
856 # Create a user with the same name as we'll pass back via sreg.
857 user = User.objects.create_user('someuser', 'someone@example.com')
858 useropenid = UserOpenID(
859 user=user,
860 claimed_id='http://example.com/different_identity',
861 display_id='http://example.com/different_identity')
862 useropenid.save()
863
864 # Posting in an identity URL begins the authentication request:
865 response = self.client.post('/openid/login/',
866 {'openid_identifier': 'http://example.com/identity',
867 'next': '/getuser/'})
868 self.assertContains(response, 'OpenID transaction in progress')
869
870 # Complete the request, passing back some simple registration
871 # data. The user is redirected to the next URL.
872 openid_request = self.provider.parseFormPost(response.content)
873 sreg_request = sreg.SRegRequest.fromOpenIDRequest(openid_request)
874 openid_response = openid_request.answer(True)
875 sreg_response = sreg.SRegResponse.extractResponse(
876 sreg_request, {'nickname': 'someuser', 'fullname': 'Some User',
877 'email': 'foo@example.com'})
878 openid_response.addExtension(sreg_response)
879 response = self.complete(openid_response)
880
881 # Status code should be 200, since we over-rode the login_failure handler
882 self.assertEquals(200, response.status_code)
883 self.assertContains(response, 'Test Failure Override')
884
739 def test_login_requires_sreg_required_fields(self):885 def test_login_requires_sreg_required_fields(self):
740 # If any required attributes are not included in the response,886 # If any required attributes are not included in the response,
741 # we fail with a forbidden.887 # we fail with a forbidden.
@@ -1054,7 +1200,7 @@
1054 self.assertTrue(self.signal_handler_called)1200 self.assertTrue(self.signal_handler_called)
1055 openid_login_complete.disconnect(login_callback)1201 openid_login_complete.disconnect(login_callback)
10561202
10571203
1058class HelperFunctionsTest(TestCase):1204class HelperFunctionsTest(TestCase):
1059 def test_sanitise_redirect_url(self):1205 def test_sanitise_redirect_url(self):
1060 settings.ALLOWED_EXTERNAL_OPENID_REDIRECT_DOMAINS = [1206 settings.ALLOWED_EXTERNAL_OPENID_REDIRECT_DOMAINS = [
10611207
=== modified file 'django_openid_auth/views.py'
--- django_openid_auth/views.py 2011-08-23 18:55:24 +0000
+++ django_openid_auth/views.py 2011-08-23 18:55:24 +0000
@@ -51,14 +51,14 @@
51from openid.extensions import sreg, ax, pape51from openid.extensions import sreg, ax, pape
5252
53from django_openid_auth import teams53from django_openid_auth import teams
54from django_openid_auth.auth import (
55 RequiredAttributeNotReturned,
56 StrictUsernameViolation,
57 )
58from django_openid_auth.forms import OpenIDLoginForm54from django_openid_auth.forms import OpenIDLoginForm
59from django_openid_auth.models import UserOpenID55from django_openid_auth.models import UserOpenID
60from django_openid_auth.signals import openid_login_complete56from django_openid_auth.signals import openid_login_complete
61from django_openid_auth.store import DjangoOpenIDStore57from django_openid_auth.store import DjangoOpenIDStore
58from django_openid_auth.exceptions import (
59 RequiredAttributeNotReturned,
60 DjangoOpenIDException,
61)
6262
6363
64next_url_re = re.compile('^/[-\w/]+$')64next_url_re = re.compile('^/[-\w/]+$')
@@ -122,10 +122,11 @@
122122
123123
124def default_render_failure(request, message, status=403,124def default_render_failure(request, message, status=403,
125 template_name='openid/failure.html'):125 template_name='openid/failure.html',
126 exception=None):
126 """Render an error page to the user."""127 """Render an error page to the user."""
127 data = render_to_string(128 data = render_to_string(
128 template_name, dict(message=message),129 template_name, dict(message=message, exception=exception),
129 context_instance=RequestContext(request))130 context_instance=RequestContext(request))
130 return HttpResponse(data, status=status)131 return HttpResponse(data, status=status)
131132
@@ -175,7 +176,8 @@
175 openid_request = consumer.begin(openid_url)176 openid_request = consumer.begin(openid_url)
176 except DiscoveryFailure, exc:177 except DiscoveryFailure, exc:
177 return render_failure(178 return render_failure(
178 request, "OpenID discovery error: %s" % (str(exc),), status=500)179 request, "OpenID discovery error: %s" % (str(exc),), status=500,
180 exception=exc)
179181
180 # Request some user details. If the provider advertises support182 # Request some user details. If the provider advertises support
181 # for attribute exchange, use that.183 # for attribute exchange, use that.
@@ -220,7 +222,6 @@
220 pape_request = pape.Request(preferred_auth_policies=preferred_auth)222 pape_request = pape.Request(preferred_auth_policies=preferred_auth)
221 openid_request.addExtension(pape_request)223 openid_request.addExtension(pape_request)
222224
223
224 # Request team info225 # Request team info
225 teams_mapping_auto = getattr(settings, 'OPENID_LAUNCHPAD_TEAMS_MAPPING_AUTO', False)226 teams_mapping_auto = getattr(settings, 'OPENID_LAUNCHPAD_TEAMS_MAPPING_AUTO', False)
226 teams_mapping_auto_blacklist = getattr(settings, 'OPENID_LAUNCHPAD_TEAMS_MAPPING_AUTO_BLACKLIST', [])227 teams_mapping_auto_blacklist = getattr(settings, 'OPENID_LAUNCHPAD_TEAMS_MAPPING_AUTO_BLACKLIST', [])
@@ -250,8 +251,11 @@
250251
251@csrf_exempt252@csrf_exempt
252def login_complete(request, redirect_field_name=REDIRECT_FIELD_NAME,253def login_complete(request, redirect_field_name=REDIRECT_FIELD_NAME,
253 render_failure=default_render_failure):254 render_failure=None):
254 redirect_to = request.REQUEST.get(redirect_field_name, '')255 redirect_to = request.REQUEST.get(redirect_field_name, '')
256 render_failure = render_failure or \
257 getattr(settings, 'OPENID_RENDER_FAILURE', None) or \
258 default_render_failure
255259
256 openid_response = parse_openid_response(request)260 openid_response = parse_openid_response(request)
257 if not openid_response:261 if not openid_response:
@@ -261,9 +265,9 @@
261 if openid_response.status == SUCCESS:265 if openid_response.status == SUCCESS:
262 try:266 try:
263 user = authenticate(openid_response=openid_response)267 user = authenticate(openid_response=openid_response)
264 except (StrictUsernameViolation, RequiredAttributeNotReturned), e:268 except DjangoOpenIDException, e:
265 return render_failure(request, e)269 return render_failure(request, e.message, exception=e)
266270
267 if user is not None:271 if user is not None:
268 if user.is_active:272 if user.is_active:
269 auth_login(request, user)273 auth_login(request, user)

Subscribers

People subscribed via source and target branches