Commit 7a6469f5 by Anthony Lenton

Added a settings, OPENID_USE_EMAIL_FOR_USERNAME to use a stripped version of the…

Added a settings, OPENID_USE_EMAIL_FOR_USERNAME to use a stripped version of the user's email for generating the username, if no nick is provided by the OpenID server.
parent 691ecea9
...@@ -146,6 +146,16 @@ class OpenIDBackend: ...@@ -146,6 +146,16 @@ class OpenIDBackend:
return dict(email=email, nickname=nickname, return dict(email=email, nickname=nickname,
first_name=first_name, last_name=last_name) first_name=first_name, last_name=last_name)
def _get_preferred_username(self, nickname, email):
if nickname:
return nickname
if email and getattr(settings, 'OPENID_USE_EMAIL_FOR_USERNAME',
False):
suggestion = ''.join([x for x in email if x.isalnum()])
if suggestion:
return suggestion
return 'openiduser'
def _get_available_username(self, nickname, identity_url): def _get_available_username(self, nickname, identity_url):
# If we're being strict about usernames, throw an error if we didn't # If we're being strict about usernames, throw an error if we didn't
# get one back from the provider # get one back from the provider
...@@ -225,10 +235,12 @@ class OpenIDBackend: ...@@ -225,10 +235,12 @@ class OpenIDBackend:
"An attribute required for logging in was not " "An attribute required for logging in was not "
"returned ({0}).".format(required_attr)) "returned ({0}).".format(required_attr))
nickname = details['nickname'] or 'openiduser' nickname = self._get_preferred_username(details['nickname'],
details['email'])
email = details['email'] or '' email = details['email'] or ''
username = self._get_available_username(details['nickname'], openid_response.identity_url) username = self._get_available_username(nickname,
openid_response.identity_url)
user = User.objects.create_user(username, email, password=None) user = User.objects.create_user(username, email, password=None)
self.associate_openid(user, openid_response) self.associate_openid(user, openid_response)
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
import unittest import unittest
from django.conf import settings
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.test import TestCase from django.test import TestCase
...@@ -45,6 +46,12 @@ class OpenIDBackendTests(TestCase): ...@@ -45,6 +46,12 @@ class OpenIDBackendTests(TestCase):
def setUp(self): def setUp(self):
super(OpenIDBackendTests, self).setUp() super(OpenIDBackendTests, self).setUp()
self.backend = OpenIDBackend() self.backend = OpenIDBackend()
self.old_openid_use_email_for_username = getattr(settings,
'OPENID_USE_EMAIL_FOR_USERNAME', False)
def tearDown(self):
settings.OPENID_USE_EMAIL_FOR_USERNAME = \
self.old_openid_use_email_for_username
def test_extract_user_details_sreg(self): def test_extract_user_details_sreg(self):
endpoint = OpenIDServiceEndpoint() endpoint = OpenIDServiceEndpoint()
...@@ -150,6 +157,29 @@ class OpenIDBackendTests(TestCase): ...@@ -150,6 +157,29 @@ class OpenIDBackendTests(TestCase):
self.assertEqual("Some", data['first_name']) self.assertEqual("Some", data['first_name'])
self.assertEqual("User", data['last_name']) self.assertEqual("User", data['last_name'])
def test_preferred_username_email_munging(self):
settings.OPENID_USE_EMAIL_FOR_USERNAME = True
for nick, email, expected in [
('nickcomesfirst', 'foo@example.com', 'nickcomesfirst'),
('', 'foo@example.com', 'fooexamplecom'),
('noemail', '', 'noemail'),
('', '@%.-', 'openiduser'),
('', '', 'openiduser'),
(None, None, 'openiduser')]:
self.assertEqual(expected,
self.backend._get_preferred_username(nick, email))
def test_preferred_username_no_email_munging(self):
for nick, email, expected in [
('nickcomesfirst', 'foo@example.com', 'nickcomesfirst'),
('', 'foo@example.com', 'openiduser'),
('noemail', '', 'noemail'),
('', '@%.-', 'openiduser'),
('', '', 'openiduser'),
(None, None, 'openiduser')]:
self.assertEqual(expected,
self.backend._get_preferred_username(nick, email))
def suite(): def suite():
return unittest.TestLoader().loadTestsFromName(__name__) return unittest.TestLoader().loadTestsFromName(__name__)
...@@ -42,7 +42,7 @@ from openid.fetchers import ( ...@@ -42,7 +42,7 @@ from openid.fetchers import (
from openid.oidutil import importElementTree from openid.oidutil import importElementTree
from openid.server.server import BROWSER_REQUEST_MODES, ENCODE_URL, Server from openid.server.server import BROWSER_REQUEST_MODES, ENCODE_URL, Server
from openid.store.memstore import MemoryStore from openid.store.memstore import MemoryStore
from openid.message import OPENID1_URL_LIMIT, IDENTIFIER_SELECT from openid.message import IDENTIFIER_SELECT
from django_openid_auth import teams from django_openid_auth import teams
from django_openid_auth.models import UserOpenID from django_openid_auth.models import UserOpenID
...@@ -50,7 +50,6 @@ from django_openid_auth.views import ( ...@@ -50,7 +50,6 @@ from django_openid_auth.views import (
sanitise_redirect_url, sanitise_redirect_url,
make_consumer, make_consumer,
) )
from django_openid_auth.auth import OpenIDBackend
from django_openid_auth.signals import openid_login_complete from django_openid_auth.signals import openid_login_complete
from django_openid_auth.store import DjangoOpenIDStore from django_openid_auth.store import DjangoOpenIDStore
from django_openid_auth.exceptions import ( from django_openid_auth.exceptions import (
...@@ -185,6 +184,8 @@ class RelyingPartyTests(TestCase): ...@@ -185,6 +184,8 @@ class RelyingPartyTests(TestCase):
self.old_physical_multifactor = getattr(settings, 'OPENID_PHYSICAL_MULTIFACTOR_REQUIRED', False) self.old_physical_multifactor = getattr(settings, 'OPENID_PHYSICAL_MULTIFACTOR_REQUIRED', False)
self.old_login_render_failure = getattr(settings, 'OPENID_RENDER_FAILURE', None) self.old_login_render_failure = getattr(settings, 'OPENID_RENDER_FAILURE', None)
self.old_consumer_complete = Consumer.complete self.old_consumer_complete = Consumer.complete
self.old_openid_use_email_for_username = getattr(settings,
'OPENID_USE_EMAIL_FOR_USERNAME', False)
self.old_required_fields = getattr( self.old_required_fields = getattr(
settings, 'OPENID_SREG_REQUIRED_FIELDS', []) settings, 'OPENID_SREG_REQUIRED_FIELDS', [])
...@@ -198,6 +199,7 @@ class RelyingPartyTests(TestCase): ...@@ -198,6 +199,7 @@ class RelyingPartyTests(TestCase):
settings.OPENID_FOLLOW_RENAMES = False settings.OPENID_FOLLOW_RENAMES = False
settings.OPENID_PHYSICAL_MULTIFACTOR_REQUIRED = False settings.OPENID_PHYSICAL_MULTIFACTOR_REQUIRED = False
settings.OPENID_SREG_REQUIRED_FIELDS = [] settings.OPENID_SREG_REQUIRED_FIELDS = []
settings.OPENID_USE_EMAIL_FOR_USERNAME = False
def tearDown(self): def tearDown(self):
settings.LOGIN_REDIRECT_URL = self.old_login_redirect_url settings.LOGIN_REDIRECT_URL = self.old_login_redirect_url
...@@ -212,6 +214,7 @@ class RelyingPartyTests(TestCase): ...@@ -212,6 +214,7 @@ class RelyingPartyTests(TestCase):
settings.OPENID_RENDER_FAILURE = self.old_login_render_failure settings.OPENID_RENDER_FAILURE = self.old_login_render_failure
Consumer.complete = self.old_consumer_complete Consumer.complete = self.old_consumer_complete
settings.OPENID_SREG_REQUIRED_FIELDS = self.old_required_fields settings.OPENID_SREG_REQUIRED_FIELDS = self.old_required_fields
settings.OPENID_USE_EMAIL_FOR_USERNAME = self.old_openid_use_email_for_username
setDefaultFetcher(None) setDefaultFetcher(None)
super(RelyingPartyTests, self).tearDown() super(RelyingPartyTests, self).tearDown()
...@@ -569,6 +572,20 @@ class RelyingPartyTests(TestCase): ...@@ -569,6 +572,20 @@ class RelyingPartyTests(TestCase):
self.assertEquals(user.last_name, 'User') self.assertEquals(user.last_name, 'User')
self.assertEquals(user.email, 'foo@example.com') self.assertEquals(user.email, 'foo@example.com')
def test_login_without_nickname_with_email_suggestion(self):
settings.OPENID_CREATE_USERS = True
settings.OPENID_USE_EMAIL_FOR_USERNAME = True
openid_req = {'openid_identifier': 'http://example.com/identity',
'next': '/getuser/'}
openid_resp = {'nickname': '', 'fullname': 'Openid User',
'email': 'foo@example.com'}
self._do_user_login(openid_req, openid_resp)
response = self.client.get('/getuser/')
# username defaults to a munged version of the email
self.assertEquals(response.content, 'fooexamplecom')
def test_login_duplicate_username_numbering(self): def test_login_duplicate_username_numbering(self):
settings.OPENID_FOLLOW_RENAMES = False settings.OPENID_FOLLOW_RENAMES = False
settings.OPENID_CREATE_USERS = True settings.OPENID_CREATE_USERS = True
......
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