Commit 57955026 by Michael Hall

Let exceptions bubble up and pass them on to render_failure so we can give users…

Let exceptions bubble up and pass them on to render_failure so we can give users helpful information when their login fails
parent 1cdfd743
......@@ -37,13 +37,13 @@ from openid.extensions import ax, sreg, pape
from django_openid_auth import teams
from django_openid_auth.models import UserOpenID
class IdentityAlreadyClaimed(Exception):
pass
class StrictUsernameViolation(Exception):
pass
from django_openid_auth.exceptions import (
DjangoOpenIDException,
IdentityAlreadyClaimed,
DuplicateUsernameViolation,
MissingUsernameViolation,
MissingPhysicalMultiFactor,
)
class OpenIDBackend:
"""A django.contrib.auth backend that authenticates the user based on
......@@ -74,10 +74,7 @@ class OpenIDBackend:
claimed_id__exact=openid_response.identity_url)
except UserOpenID.DoesNotExist:
if getattr(settings, 'OPENID_CREATE_USERS', False):
try:
user = self.create_user_from_openid(openid_response)
except StrictUsernameViolation:
return None
user = self.create_user_from_openid(openid_response)
else:
user = user_openid.user
......@@ -92,7 +89,7 @@ class OpenIDBackend:
pape_response = pape.Response.fromSuccessResponse(openid_response)
if pape_response is None or \
pape.AUTH_MULTI_FACTOR_PHYSICAL not in pape_response.auth_policies:
return None
raise MissingPhysicalMultiFactor()
teams_response = teams.TeamsResponse.fromSuccessResponse(
openid_response)
......@@ -152,7 +149,7 @@ class OpenIDBackend:
# get one back from the provider
if getattr(settings, 'OPENID_STRICT_USERNAMES', False):
if nickname is None or nickname == '':
raise StrictUsernameViolation("No username")
raise MissingUsernameViolation()
# If we don't have a nickname, and we're not being strict, use a default
nickname = nickname or 'openiduser'
......@@ -188,7 +185,7 @@ class OpenIDBackend:
if getattr(settings, 'OPENID_STRICT_USERNAMES', False):
if User.objects.filter(username__exact=nickname).count() > 0:
raise StrictUsernameViolation("Duplicate username: %s" % nickname)
raise DuplicateUsernameViolation("Duplicate username: %s" % nickname)
# Pick a username for the user based on their nickname,
# checking for conflicts.
......
# django-openid-auth - OpenID integration for django.contrib.auth
#
# Copyright (C) 2008-2010 Canonical Ltd.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
"""Exception classes thrown by OpenID Authentication and Validation."""
class DjangoOpenIDException(Exception):
pass
class IdentityAlreadyClaimed(DjangoOpenIDException):
def __init__(self, message=None):
if message is None:
self.message = "Another user already exists for your selected OpenID"
else:
self.message = message
class StrictUsernameViolation(DjangoOpenIDException):
pass
class DuplicateUsernameViolation(StrictUsernameViolation):
def __init__(self, message=None):
if message is None:
self.message = "Your desired username is already being used."
else:
self.message = message
class MissingUsernameViolation(StrictUsernameViolation):
def __init__(self, message=None):
if message is None:
self.message = "No nickname given for your account."
else:
self.message = message
class MissingPhysicalMultiFactor(DjangoOpenIDException):
def __init__(self, message=None):
if message is None:
self.message = "Login requires physical multi-factor authentication."
else:
self.message = message
......@@ -55,6 +55,13 @@ from django_openid_auth.forms import OpenIDLoginForm
from django_openid_auth.models import UserOpenID
from django_openid_auth.signals import openid_login_complete
from django_openid_auth.store import DjangoOpenIDStore
from django_openid_auth.exceptions import (
DjangoOpenIDException,
IdentityAlreadyClaimed,
DuplicateUsernameViolation,
MissingUsernameViolation,
MissingPhysicalMultiFactor,
)
next_url_re = re.compile('^/[-\w/]+$')
......@@ -118,10 +125,11 @@ def render_openid_request(request, openid_request, return_to, trust_root=None):
def default_render_failure(request, message, status=403,
template_name='openid/failure.html'):
template_name='openid/failure.html',
exception=None):
"""Render an error page to the user."""
data = render_to_string(
template_name, dict(message=message),
template_name, dict(message=message, exception=exception),
context_instance=RequestContext(request))
return HttpResponse(data, status=status)
......@@ -171,7 +179,8 @@ def login_begin(request, template_name='openid/login.html',
openid_request = consumer.begin(openid_url)
except DiscoveryFailure, exc:
return render_failure(
request, "OpenID discovery error: %s" % (str(exc),), status=500)
request, "OpenID discovery error: %s" % (str(exc),), status=500,
exception=exc)
# Request some user details. If the provider advertises support
# for attribute exchange, use that.
......@@ -248,7 +257,11 @@ def login_complete(request, redirect_field_name=REDIRECT_FIELD_NAME,
request, 'This is an OpenID relying party endpoint.')
if openid_response.status == SUCCESS:
user = authenticate(openid_response=openid_response)
try:
user = authenticate(openid_response=openid_response)
except DjangoOpenIDException, e:
return render_failure(request, "Login Failed", exception=e)
if user is not None:
if user.is_active:
auth_login(request, user)
......
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