Commit 7f7c6f49 by James Henstridge

Add code to integrate the OpenID code with django.contrib.auth.

parent ace34c30
"""Glue between OpenID and django.contrib.auth."""
from django.conf import settings
from django.contrib.auth.models import User
from openid.extensions import sreg
from models import UserOpenID
class IdentityAlreadyClaimed(Exception):
pass
def get_user(openid_response):
try:
user_openid = UserOpenID.objects.get(
claimed_id__exact=openid_response.identity_url)
except UserOpenID.DoesNotExist:
return None
return user_openid.user
def find_unused_username(preferred_username):
"""Return an unused username, based on preferred_username."""
i = 0
while True:
username = preferred_username
if i > 0:
username += str(i)
try:
User.objects.get(username__exact=username)
except User.DoesNotExist:
return username
i += 1
def fill_user_details_from_sreg(user, sreg_response):
fullname = sreg_response.get('fullname')
if fullname:
# Do our best here ...
if ' ' in fullname:
user.first_name, user.last_name = fullname.rsplit(None, 1)
else:
user.first_name = u''
user.last_name = fullname
email = sreg_response.get('email')
if email:
user.email = email
user.save()
def create_user(openid_response):
"""Create a new user from an OpenID response."""
sreg_response = sreg.SRegResponse.fromSuccessResponse(openid_response)
if sreg_response:
nickname = sreg_response.get('nickname', 'openiduser')
email = sreg_response.get('email', '')
else:
nickname = 'openiduser'
email = ''
username = find_unused_username(nickname)
user = User.objects.create_user(username, email)
if sreg_response:
fill_user_details_from_sreg(user, sreg_response)
add_openid(user, openid_response)
return user
def add_openid(user, openid_response):
existing_user = get_user(openid_response)
if existing_user is not None:
if existing_user != user:
raise IdentityAlreadyClaimed(
"The identity %s has already been claimed"
% openid_response.identity_url)
return
user_openid = UserOpenID(
user=user,
claimed_id=openid_response.identity_url,
display_id=openid_response.endpoint.getDisplayIdentifier())
user_openid.save()
def openid_authenticate(openid_response):
user = get_user(openid_response)
if user is not None:
if getattr(settings, 'OPENID_UPDATE_DETAILS_FROM_SREG', False):
sreg_response = sreg.SRegResponse.fromSuccessResponse(
openid_response)
if sreg_response:
fill_user_details_from_sreg(user, sreg_response)
else:
if getattr(settings, 'OPENID_CREATE_USERS', False):
user = create_user(openid_response)
# As we aren't using authenticate() here, we need to annotate the
# user with the backend used. We don't currently have one though,
# so fake it.
if user is not None:
user.backend = 'django.contrib.auth.backends.ModelBackend'
return user
...@@ -6,7 +6,9 @@ from openid.yadis import xri ...@@ -6,7 +6,9 @@ from openid.yadis import xri
class OpenIDLoginForm(forms.Form): class OpenIDLoginForm(forms.Form):
openid_url = forms.CharField(max_length=255, widget=forms.widgets.TextInput(attrs={'class': 'required openid'})) openid_url = forms.CharField(
max_length=255,
widget=forms.TextInput(attrs={'class': 'required openid'}))
def clean_openid_url(self): def clean_openid_url(self):
if 'openid_url' in self.cleaned_data: if 'openid_url' in self.cleaned_data:
......
...@@ -25,4 +25,5 @@ class Association(models.Model): ...@@ -25,4 +25,5 @@ class Association(models.Model):
class UserOpenID(models.Model): class UserOpenID(models.Model):
user = models.ForeignKey(User) user = models.ForeignKey(User)
claimed_id = models.TextField(max_length=2047) claimed_id = models.TextField(max_length=2047, unique=True)
display_id = models.TextField(max_length=2047)
...@@ -2,7 +2,7 @@ import re ...@@ -2,7 +2,7 @@ import re
import urllib import urllib
from django.conf import settings from django.conf import settings
from django.contrib.auth import REDIRECT_FIELD_NAME from django.contrib.auth import REDIRECT_FIELD_NAME, login as auth_login
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.http import HttpResponse, HttpResponseRedirect from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render_to_response from django.shortcuts import render_to_response
...@@ -15,6 +15,7 @@ from openid.consumer.discover import DiscoveryFailure ...@@ -15,6 +15,7 @@ from openid.consumer.discover import DiscoveryFailure
from openid.extensions import sreg from openid.extensions import sreg
from auth import openid_authenticate
from util import DjangoOpenIDStore from util import DjangoOpenIDStore
from forms import OpenIDLoginForm from forms import OpenIDLoginForm
...@@ -130,10 +131,18 @@ def login_complete(request, redirect_field_name=REDIRECT_FIELD_NAME): ...@@ -130,10 +131,18 @@ def login_complete(request, redirect_field_name=REDIRECT_FIELD_NAME):
openid_response = parse_openid_response(request) openid_response = parse_openid_response(request)
if not openid_response: if not openid_response:
return HttpResponseRedirect(sanitise_redirect_url(redirect_to)) return HttpResponse('No OpenID response')
if openid_response.status == SUCCESS: if openid_response.status == SUCCESS:
return HttpResponse("Success: %s") user = openid_authenticate(openid_response)
if user is not None:
if user.is_active:
auth_login(request, user)
return HttpResponseRedirect(sanitise_redirect_url(redirect_to))
else:
return HttpResponse('Disabled account')
else:
return HttpResponse('invalid user')
elif openid_response.status == FAILURE: elif openid_response.status == FAILURE:
return HttpResponse("Failure: %s" % openid_response.message) return HttpResponse("Failure: %s" % openid_response.message)
elif openid_response.status == CANCEL: elif openid_response.status == CANCEL:
......
...@@ -60,7 +60,7 @@ TEMPLATE_LOADERS = ( ...@@ -60,7 +60,7 @@ TEMPLATE_LOADERS = (
MIDDLEWARE_CLASSES = ( MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',
'django_openidconsumer.middleware.OpenIDMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware',
) )
ROOT_URLCONF = 'example_consumer.urls' ROOT_URLCONF = 'example_consumer.urls'
...@@ -72,6 +72,14 @@ TEMPLATE_DIRS = ( ...@@ -72,6 +72,14 @@ TEMPLATE_DIRS = (
) )
INSTALLED_APPS = ( INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions', 'django.contrib.sessions',
'django_openidconsumer', 'django_openidconsumer',
) )
OPENID_CREATE_USERS = True
OPENID_UPDATE_DETAILS_FROM_SREG = True
OPENID_SSO_SERVER_URL = 'https://login.launchpad.net/'
LOGIN_REDIRECT_URL = '/'
...@@ -3,12 +3,8 @@ import views ...@@ -3,12 +3,8 @@ import views
urlpatterns = patterns('', urlpatterns = patterns('',
(r'^$', views.index), (r'^$', views.index),
(r'^openid/$', 'django_openidconsumer.views.login_begin'), (r'^openid/login$', 'django_openidconsumer.views.login_begin'),
#(r'^openid/with-sreg/$', 'django_openidconsumer.views.begin', { (r'^openid/login/complete$', 'django_openidconsumer.views.login_complete'),
# 'sreg': 'email,nickname', (r'^openid/logout$', 'django.contrib.auth.views.logout'),
# 'redirect_to': '/openid/complete/',
#}),
(r'^openid/complete/$', 'django_openidconsumer.views.login_complete'),
#(r'^openid/signout/$', 'django_openidconsumer.views.signout'),
(r'^next-works/$', views.next_works), (r'^next-works/$', views.next_works),
) )
from django.http import HttpResponse from django.http import HttpResponse
from pprint import pformat
from django.utils.html import escape from django.utils.html import escape
def index(request): def index(request):
s = [] s = ['<p>']
if request.openid: if request.user.is_authenticated():
s.append('<p>You are signed in as <strong>%s</strong>' % escape( s.append('You are signed in as <strong>%s</strong> (%s)' % (
str(request.openid) escape(request.user.username),
)) escape(request.user.get_full_name())))
s.append(' | <a href="/openid/logout">Sign out</a>')
if request.openid.is_iname: else:
s.append(' (an i-name)') s.append('<a href="/openid/login">Sign in with OpenID</a>')
s.append('</p>')
if request.openid.sreg:
s.append('<p>sreg data: %s</p>' % escape(str(request.openid.sreg)))
if len(request.openids) > 1:
s.append('<p>Also signed in as %s</p>' % ', '.join([
escape(str(o)) for o in request.openids[:-1]
]))
s.append('<a href="/openid/">Sign in with OpenID</a>')
s.append(' | <a href="/openid/with-sreg/">')
s.append('Sign in with OpenID using simple registration</a>')
s.append(' | <a href="/openid/?next=/next-works/">')
s.append('Sign in with OpenID, testing ?next= param</a>')
if request.openid:
s.append(' | <a href="/openid/signout/">Sign out</a>')
s.append('</p>') s.append('</p>')
return HttpResponse('\n'.join(s)) return HttpResponse('\n'.join(s))
def next_works(request): def next_works(request):
return HttpResponse('?next= bit works. <a href="/">Home</a>') return HttpResponse('?next= bit works. <a href="/">Home</a>')
\ No newline at end of file
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