add MELLON_ASSERTION_CONSUMER_BINDINGS (#52063)

The default value is ['post', 'artifact'].
This commit is contained in:
Benjamin Dauvergne 2021-08-05 13:34:59 +02:00
parent 734a7bb51b
commit fbc3588f1b
6 changed files with 61 additions and 4 deletions

7
README
View File

@ -311,6 +311,13 @@ MELLON_METADATA_HTTP_TIMEOUT
Timeout in seconds for HTTP call made to retrieve metadata files. Default is 10
seconds.
MELLON_ASSERTION_CONSUMER_BINDINGS
----------------------------------
The list of supported assertion consumer bindings. Default is::
['post', 'artifact']
Tests
=====

View File

@ -26,6 +26,7 @@ class AppSettings:
'CREATE_GROUP': True,
'ERROR_URL': None,
'ERROR_REDIRECT_AFTER_TIMEOUT': 120,
'ASSERTION_CONSUMER_BINDINGS': ['post', 'artifact'],
'DEFAULT_ASSERTION_CONSUMER_BINDING': 'post', # or artifact
'VERIFY_SSL_CERTIFICATE': True,
'OPENED_SESSION_COOKIE_NAME': None,

View File

@ -32,21 +32,21 @@
{% for name_id_format in name_id_formats %}
<NameIDFormat>{{ name_id_format }}</NameIDFormat>
{% endfor %}
<AssertionConsumerService
{% if 'artifact' in assertion_consumer_bindings %} <AssertionConsumerService
index="0"
{% if default_assertion_consumer_binding == "artifact" %}
isDefault="true"
{% endif %}
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
Location="{{ login_url }}" />
<AssertionConsumerService
{% endif %}{% if 'post' in assertion_consumer_bindings %} <AssertionConsumerService
index="1"
{% if default_assertion_consumer_binding == "post" %}
isDefault="true"
{% endif %}
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Location="{{ login_url }}" />
</SPSSODescriptor>
{% endif %} </SPSSODescriptor>
{% if organization and organization.NAMES and organization.DISPLAY_NAMES and organization.URLS %}
<Organization>
{% for name in organization.NAMES %}

View File

@ -54,6 +54,7 @@ def create_metadata(request):
'logout_url': request.build_absolute_uri(logout_url),
'public_keys': public_keys,
'name_id_formats': name_id_formats,
'assertion_consumer_bindings': app_settings.ASSERTION_CONSUMER_BINDINGS,
'default_assertion_consumer_binding': app_settings.DEFAULT_ASSERTION_CONSUMER_BINDING,
'organization': app_settings.ORGANIZATION,
'contact_persons': app_settings.CONTACT_PERSONS,

View File

@ -29,7 +29,7 @@ from django.conf import settings
from django.contrib import auth
from django.contrib.auth import REDIRECT_FIELD_NAME, get_user_model
from django.db import transaction
from django.http import HttpResponse, HttpResponseForbidden, HttpResponseRedirect
from django.http import Http404, HttpResponse, HttpResponseForbidden, HttpResponseRedirect
from django.shortcuts import render, resolve_url
from django.urls import reverse
from django.utils import six
@ -163,8 +163,12 @@ class LoginView(ProfileMixin, LogMixin, View):
def post(self, request, *args, **kwargs):
'''Assertion consumer'''
if 'SAMLart' in request.POST:
if 'artifact' not in app_settings.ASSERTION_CONSUMER_BINDINGS:
raise Http404('artifact binding is not supported')
return self.continue_sso_artifact(request, lasso.HTTP_METHOD_ARTIFACT_POST)
if 'SAMLResponse' not in request.POST:
if 'post' not in app_settings.ASSERTION_CONSUMER_BINDINGS:
raise Http404('post binding is not supported')
return self.get(request, *args, **kwargs)
if not utils.is_nonnull(request.POST['SAMLResponse']):
return HttpResponseBadRequest('SAMLResponse contains a null character')
@ -462,6 +466,8 @@ class LoginView(ProfileMixin, LogMixin, View):
def get(self, request, *args, **kwargs):
'''Initialize login request'''
if 'SAMLart' in request.GET:
if 'artifact' not in app_settings.ASSERTION_CONSUMER_BINDINGS:
raise Http404('artifact binding is not supported')
return self.continue_sso_artifact(request, lasso.HTTP_METHOD_ARTIFACT_GET)
# redirect to discovery service if needed

View File

@ -112,6 +112,48 @@ def test_create_metadata(rf, private_settings, caplog):
namespaces=ns,
)
private_settings.MELLON_ASSERTION_CONSUMER_BINDINGS = ['post']
with mock.patch('mellon.utils.open', mock.mock_open(read_data='BEGIN\nyyy\nEND'), create=True):
metadata = create_metadata(request)
assert 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST'
assert_xml_constraints(
metadata.encode('utf-8'),
(
'/sm:EntityDescriptor/sm:SPSSODescriptor',
1,
(
'/sm:AssertionConsumerService[@Binding=\'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact\']',
0,
),
(
'/sm:AssertionConsumerService[@Binding=\'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\']',
1,
),
),
namespaces=ns,
)
private_settings.MELLON_ASSERTION_CONSUMER_BINDINGS = ['artifact']
with mock.patch('mellon.utils.open', mock.mock_open(read_data='BEGIN\nyyy\nEND'), create=True):
metadata = create_metadata(request)
assert 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST'
assert_xml_constraints(
metadata.encode('utf-8'),
(
'/sm:EntityDescriptor/sm:SPSSODescriptor',
1,
(
'/sm:AssertionConsumerService[@Binding=\'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact\']',
1,
),
(
'/sm:AssertionConsumerService[@Binding=\'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\']',
0,
),
),
namespaces=ns,
)
def test_iso8601_to_datetime(private_settings):
import django.utils.timezone