Commit 030e869d by Michael Nelson

GREEN: Failing to provide required attributes results in a forbidden message.

parent 00090272
...@@ -45,6 +45,9 @@ class IdentityAlreadyClaimed(Exception): ...@@ -45,6 +45,9 @@ class IdentityAlreadyClaimed(Exception):
class StrictUsernameViolation(Exception): class StrictUsernameViolation(Exception):
pass pass
class RequiredAttributeNotReturned(Exception):
pass
class OpenIDBackend: class OpenIDBackend:
"""A django.contrib.auth backend that authenticates the user based on """A django.contrib.auth backend that authenticates the user based on
an OpenID response.""" an OpenID response."""
...@@ -76,7 +79,7 @@ class OpenIDBackend: ...@@ -76,7 +79,7 @@ class OpenIDBackend:
if getattr(settings, 'OPENID_CREATE_USERS', False): if getattr(settings, 'OPENID_CREATE_USERS', False):
try: try:
user = self.create_user_from_openid(openid_response) user = self.create_user_from_openid(openid_response)
except StrictUsernameViolation: except (StrictUsernameViolation, RequiredAttributeNotReturned):
return None return None
else: else:
user = user_openid.user user = user_openid.user
...@@ -202,6 +205,13 @@ class OpenIDBackend: ...@@ -202,6 +205,13 @@ class OpenIDBackend:
def create_user_from_openid(self, openid_response): def create_user_from_openid(self, openid_response):
details = self._extract_user_details(openid_response) details = self._extract_user_details(openid_response)
required_attrs = getattr(settings, 'OPENID_SREG_REQUIRED_FIELDS', [])
for required_attr in required_attrs:
if required_attr not in details:
raise RequiredAttributeNotReturned(
"The required attribute '{0}' was not returned.".format(
required_attr))
nickname = details['nickname'] or 'openiduser' nickname = details['nickname'] or 'openiduser'
email = details['email'] or '' email = details['email'] or ''
......
...@@ -555,6 +555,34 @@ class RelyingPartyTests(TestCase): ...@@ -555,6 +555,34 @@ class RelyingPartyTests(TestCase):
# Status code should be 403: Forbidden # Status code should be 403: Forbidden
self.assertEquals(403, response.status_code) self.assertEquals(403, response.status_code)
def test_login_requires_sreg_required_fields(self):
# If any required attributes are not included in the response,
# we fail with a forbidden.
settings.OPENID_CREATE_USERS = True
settings.OPENID_SREG_REQUIRED_FIELDS = ('email', 'language')
# Posting in an identity URL begins the authentication request:
response = self.client.post('/openid/login/',
{'openid_identifier': 'http://example.com/identity',
'next': '/getuser/'})
self.assertContains(response, 'OpenID transaction in progress')
# Complete the request, passing back some simple registration
# data. The user is redirected to the next URL.
openid_request = self.provider.parseFormPost(response.content)
sreg_request = sreg.SRegRequest.fromOpenIDRequest(openid_request)
openid_response = openid_request.answer(True)
sreg_response = sreg.SRegResponse.extractResponse(
sreg_request, {'nickname': 'foo',
'fullname': 'Some User',
'email': 'foo@example.com'})
openid_response.addExtension(sreg_response)
response = self.complete(openid_response)
# Status code should be 403: Forbidden as we didn't include
# a required field - language.
self.assertEquals(403, response.status_code)
def test_login_update_details(self): def test_login_update_details(self):
settings.OPENID_UPDATE_DETAILS_FROM_SREG = True settings.OPENID_UPDATE_DETAILS_FROM_SREG = True
user = User.objects.create_user('testuser', 'someone@example.com') user = User.objects.create_user('testuser', 'someone@example.com')
...@@ -620,37 +648,6 @@ class RelyingPartyTests(TestCase): ...@@ -620,37 +648,6 @@ class RelyingPartyTests(TestCase):
self.assertEqual(['email', 'language'], sreg_request.required) self.assertEqual(['email', 'language'], sreg_request.required)
self.assertEqual(['fullname', 'nickname'], sreg_request.optional) self.assertEqual(['fullname', 'nickname'], sreg_request.optional)
def test_login_requires_sreg_required_fields(self):
# If any required attributes are not included in the response,
# we fail with a forbidden.
settings.OPENID_SREG_REQUIRED_FIELDS = ('email', 'language')
user = User.objects.create_user('testuser', 'someone@example.com')
useropenid = UserOpenID(
user=user,
claimed_id='http://example.com/identity',
display_id='http://example.com/identity')
useropenid.save()
# Posting in an identity URL begins the authentication request:
response = self.client.post('/openid/login/',
{'openid_identifier': 'http://example.com/identity',
'next': '/getuser/'})
# Complete the request, passing back some simple registration
# data. The user is redirected to the next URL.
openid_request = self.provider.parseFormPost(response.content)
sreg_request = sreg.SRegRequest.fromOpenIDRequest(openid_request)
openid_response = openid_request.answer(True)
sreg_response = sreg.SRegResponse.extractResponse(
sreg_request, {'nickname': 'foo',
'fullname': 'Some User',
'email': 'foo@example.com'})
openid_response.addExtension(sreg_response)
response = self.complete(openid_response)
# Status code should be 403: Forbidden, as the required
# language was not included.
self.assertEquals(403, response.status_code)
def test_login_attribute_exchange(self): def test_login_attribute_exchange(self):
settings.OPENID_UPDATE_DETAILS_FROM_SREG = True settings.OPENID_UPDATE_DETAILS_FROM_SREG = True
user = User.objects.create_user('testuser', 'someone@example.com') user = User.objects.create_user('testuser', 'someone@example.com')
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment