improve handling of authentication errors
All errors are logged as warnings, status message and status codes are logged, and if DEBUG is True, shown to the user.
This commit is contained in:
parent
e1a962608c
commit
bcb055263b
13
README
13
README
|
@ -216,3 +216,16 @@ MELLON_CREATE_GROUP
|
|||
-------------------
|
||||
|
||||
Whether to create group or only assign existing groups, default is True.
|
||||
|
||||
MELLON_ERROR_URL
|
||||
================
|
||||
|
||||
URL for the continue link when authentication fails, default is
|
||||
None. If not ERROR_URL is None, the RelayState is used. If there is
|
||||
no RelayState, the LOGIN_REDIRECT_URL, which defaults to /, is used.
|
||||
|
||||
MELLON_ERROR_REDIRECT_AFTER_TIMEOUT
|
||||
===================================
|
||||
|
||||
Timeout in seconds before automatically redirecting the user to the
|
||||
continue URL when authentication has failed. Default is 120 seconds.
|
||||
|
|
|
@ -21,6 +21,8 @@ class AppSettings(object):
|
|||
'AUTHN_CLASSREF': (),
|
||||
'GROUP_ATTRIBUTE': None,
|
||||
'CREATE_GROUP': True,
|
||||
'ERROR_URL': None,
|
||||
'ERROR_REDIRECT_AFTER_TIMEOUT': 120,
|
||||
}
|
||||
|
||||
@property
|
||||
|
|
|
@ -1,24 +1,38 @@
|
|||
{% extends "base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block extra_scripts %}
|
||||
{% if error_redirect_after_timeout %}
|
||||
<meta http-equiv="refresh" content="{{ error_redirect_after_timeout }};url={{ next_url }}"
|
||||
{% endif %}
|
||||
{% endblock
|
||||
|
||||
{% block content %}
|
||||
<div id="mellon-authentication-failure" class="mellon-message">
|
||||
<h2>{% trans "Authentication failed" %}</h2>
|
||||
<p>
|
||||
{% blocktrans %}The authentication has failed, you can return to
|
||||
the <a href="{{ next_url }}">last page</a> you where.
|
||||
{% endblocktrans %}
|
||||
<h2 class="mellon-message-header">{% trans "Authentication failed" %}</h2>
|
||||
<p class="mellon-message-body">
|
||||
{% blocktrans %}The authentication has failed.{% endblocktrans %}
|
||||
</p>
|
||||
<dl id="mellon-authentication-failure-details">
|
||||
<dt>{% trans "Issuer" %}</dt>
|
||||
<dd>{{ issuer }}</dd>
|
||||
{% if status_message %}
|
||||
<dt>{% trans "Message" %}</dt>
|
||||
<dd>{{ status_message }}</dd>
|
||||
{% endif %}
|
||||
<dt>{% trans "Codes" %}</dt>
|
||||
<dd><tt>{{ status_codes|join:", " }}</tt></dd>
|
||||
</dl>
|
||||
<p class="mellon-message-continue">
|
||||
<a class="mellon-link" href="{{ next_url }}">{% trans "Continue" %}</a>
|
||||
</p>
|
||||
{% if debug %}
|
||||
<dl id="mellon-authentication-failure-details">
|
||||
<dt class="mellon-issuer">{% trans "Issuer" %}</dt>
|
||||
<dd class="mellon-issuer"><tt>{{ issuer }}</tt></dd>
|
||||
{% if status_message %}
|
||||
<dt class="mellon-status-message">{% trans "Message" %}</dt>
|
||||
<dd class="mellon-status-message">{{ status_message }}</dd>
|
||||
{% endif %}
|
||||
{% if status_codes %}
|
||||
<dt class="mellon-status-codes">{% trans "Codes" %}</dt>
|
||||
<dd class="mellon-status-codes"><tt>{{ status_codes|join:", " }}</tt></dd>
|
||||
{% endif %}
|
||||
{% if relaystate %}
|
||||
<dt class="mellon-relaystate">{% trans "Relaystate" %}</dt>
|
||||
<dd class="mellon-relaystate"><tt>{{ relaystate }}</tt></dd>
|
||||
{% endif %}
|
||||
</dl>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
|
@ -7,6 +7,8 @@ from django.conf import settings
|
|||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.shortcuts import render, redirect, resolve_url
|
||||
from django.utils.http import same_origin
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.contrib import messages
|
||||
|
||||
import lasso
|
||||
|
||||
|
@ -29,31 +31,55 @@ class LoginView(View):
|
|||
if 'SAMLResponse' not in request.POST:
|
||||
return self.get(request, *args, **kwargs)
|
||||
login = utils.create_login(request)
|
||||
idp_message = None
|
||||
status_codes = []
|
||||
try:
|
||||
login.processAuthnResponseMsg(request.POST['SAMLResponse'])
|
||||
login.acceptSso()
|
||||
except lasso.ProfileStatusNotSuccessError, e:
|
||||
status_codes = []
|
||||
except lasso.ProfileCannotVerifySignatureError:
|
||||
log.warning('SAML authentication failed: signature validation failed for %r',
|
||||
login.remoteProviderId)
|
||||
except lasso.ParamError:
|
||||
log.exception('lasso param error')
|
||||
except (lasso.ProfileStatusNotSuccessError, lasso.ProfileRequestDeniedError):
|
||||
status = login.response.status
|
||||
a = status
|
||||
while a.statusCode:
|
||||
status_codes.append(a.statusCode.value)
|
||||
a = a.statusCode
|
||||
log.warning('SAML authentication failed, codes: %r', status_codes)
|
||||
args = ['SAML authentication failed: status is not success codes: %r', status_codes]
|
||||
if status.statusMessage:
|
||||
log.warning('SAML authentication failed, message: %r',
|
||||
status.statusMessage)
|
||||
next_url = login.msgRelayState or \
|
||||
resolve_url(settings.LOGIN_REDIRECT_URL)
|
||||
return render(request, 'mellon/authentication_failed.html', {
|
||||
'status_message': status.statusMessage,
|
||||
'status_codes': status_codes,
|
||||
'issuer': login.remoteProviderId,
|
||||
'next_url': next_url,
|
||||
})
|
||||
idp_message = status.statusMessage.decode('utf-8')
|
||||
args[0] += ' message: %r'
|
||||
args.append(status.statusMessage)
|
||||
log.warning(*args)
|
||||
except lasso.Error, e:
|
||||
return HttpResponseBadRequest('error processing the authentication '
|
||||
'response: %r' % e)
|
||||
else:
|
||||
return self.login_success(request, login)
|
||||
return self.login_failure(request, login, idp_message, status_codes)
|
||||
|
||||
def login_failure(self, request, login, idp_message, status_codes):
|
||||
'''show error message to user after a login failure'''
|
||||
idp = self.get_idp(request)
|
||||
error_url = utils.get_parameter(idp, 'ERROR_URL')
|
||||
error_redirect_after_timeout = utils.get_parameter(idp, 'ERROR_REDIRECT_AFTER_TIMEOUT')
|
||||
if error_url:
|
||||
error_url = resolve_url(error_url)
|
||||
next_url = error_url or login.msgRelayState or resolve_url(settings.LOGIN_REDIRECT_URL)
|
||||
return render(request, 'mellon/authentication_failed.html', {
|
||||
'debug': settings.DEBUG,
|
||||
'idp_message': idp_message,
|
||||
'status_codes': status_codes,
|
||||
'issuer': login.remoteProviderId,
|
||||
'next_url': next_url,
|
||||
'error_url': error_url,
|
||||
'relaystate': login.msgRelayState,
|
||||
'error_redirect_after_timeout': error_redirect_after_timeout,
|
||||
})
|
||||
|
||||
def login_success(self, request, login):
|
||||
name_id = login.nameIdentifier
|
||||
attributes = {}
|
||||
attribute_statements = login.assertion.attributeStatement
|
||||
|
|
Loading…
Reference in New Issue