do not pass strings contening null characters to Lasso, return 400 or ignore (fixes #8939)

This commit is contained in:
Benjamin Dauvergne 2016-02-26 12:03:32 +01:00
parent f2cf86f7a6
commit 4f77ee0e24
5 changed files with 32 additions and 4 deletions

View File

@ -202,3 +202,6 @@ def create_logout(request):
logout.setSignatureHint(lasso.PROFILE_SIGNATURE_HINT_FORBID)
logout.setSessionFromDump(session_dump)
return logout
def is_nonnull(s):
return not '\x00' in s

View File

@ -34,9 +34,12 @@ class LoginView(LogMixin, View):
'''Assertion consumer'''
if 'SAMLResponse' not in request.POST:
return self.get(request, *args, **kwargs)
if not utils.is_nonnull(request.POST['SAMLResponse']):
return HttpResponseBadRequest('SAMLResponse contains a null character')
login = utils.create_login(request)
idp_message = None
status_codes = []
# prevent null characters in SAMLResponse
try:
login.processAuthnResponseMsg(request.POST['SAMLResponse'])
login.acceptSso()
@ -63,7 +66,7 @@ class LoginView(LogMixin, View):
return HttpResponseBadRequest('error processing the authentication '
'response: %r' % e)
else:
if 'RelayState' in request.POST:
if 'RelayState' in request.POST and utils.is_nonnull(request.POST['RelayState']):
login.msgRelayState = request.POST['RelayState']
return self.sso_success(request, login)
return self.sso_failure(request, login, idp_message, status_codes)
@ -204,7 +207,7 @@ class LoginView(LogMixin, View):
return HttpResponseBadRequest('error processing the authentication '
'response: %r' % e)
else:
if 'RelayState' in request.GET:
if 'RelayState' in request.GET and utils.is_nonnull(request.GET['RelayState']):
login.msgRelayState = request.GET['RelayState']
return self.sso_success(request, login)
return self.sso_failure(request, login, idp_message, status_codes)
@ -238,7 +241,7 @@ class LoginView(LogMixin, View):
req_authncontext = lasso.RequestedAuthnContext()
authn_request.requestedAuthnContext = req_authncontext
req_authncontext.authnContextClassRef = authn_classref
if next_url:
if next_url and utils.is_nonnull(next_url):
login.msgRelayState = next_url
login.buildAuthnRequestMsg()
except lasso.Error, e:
@ -300,7 +303,8 @@ class LogoutView(LogMixin, View):
else:
self.log.error('unable to find lasso session dump')
logout.initRequest(issuer, lasso.HTTP_METHOD_REDIRECT)
logout.msgRelayState = next_url
if utils.is_nonnull(next_url):
logout.msgRelayState = next_url
logout.buildRequestMsg()
except lasso.Error, e:
self.log.error('unable to initiate a logout request %r', e)

View File

@ -1,4 +1,13 @@
import pytest
import django_webtest
@pytest.fixture
def app(request):
wtm = django_webtest.WebTestMixin()
wtm._patch_settings()
request.addfinalizer(wtm._unpatch_settings)
return django_webtest.DjangoTestApp()
@pytest.fixture

4
tests/test_views.py Normal file
View File

@ -0,0 +1,4 @@
from django.core.urlresolvers import reverse
def test_null_character_on_samlresponse_post(app):
app.post(reverse('mellon_login'), {'SAMLResponse': '\x00'}, status=400)

View File

@ -12,6 +12,14 @@ DATABASES = {
}
DEBUG = True
SECRET_KEY='xx'
STATIC_URL = '/static/'
INSTALLED_APPS = ('mellon', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions')
MIDDLEWARE_CLASSES = global_settings.MIDDLEWARE_CLASSES
MIDDLEWARE_CLASSES += (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
)
AUTHENTICATION_BACKENDS = (
'mellon.backends.SAMLBackend',
)
ROOT_URLCONF = 'mellon.urls'