diff --git a/mellon/app_settings.py b/mellon/app_settings.py
index 33ac3ce..fdbf949 100644
--- a/mellon/app_settings.py
+++ b/mellon/app_settings.py
@@ -43,6 +43,7 @@ class AppSettings(object):
'LOOKUP_BY_ATTRIBUTES': [],
'METADATA_CACHE_TIME': 3600,
'METADATA_HTTP_TIMEOUT': 10,
+ 'METADATA_PUBLISH_DISCOVERY_RESPONSE': False,
}
@property
diff --git a/mellon/templates/mellon/metadata.xml b/mellon/templates/mellon/metadata.xml
index da01a4f..c67283e 100644
--- a/mellon/templates/mellon/metadata.xml
+++ b/mellon/templates/mellon/metadata.xml
@@ -6,12 +6,14 @@
AuthnRequestsSigned="true"
WantAssertionsSigned="true"
protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
+ {% if discovery_endpoint_url %}
-
+
+ {% endif %}
{% for public_key in public_keys %}
diff --git a/mellon/utils.py b/mellon/utils.py
index 5bbd726..b50e475 100644
--- a/mellon/utils.py
+++ b/mellon/utils.py
@@ -49,7 +49,8 @@ def create_metadata(request):
public_key = ''.join(content.splitlines()[1:-1])
public_keys.append(public_key)
name_id_formats = app_settings.NAME_ID_FORMATS
- return render_to_string('mellon/metadata.xml', {
+ ctx = {
+ 'request': request,
'entity_id': request.build_absolute_uri(entity_id),
'login_url': request.build_absolute_uri(login_url),
'logout_url': request.build_absolute_uri(logout_url),
@@ -58,8 +59,11 @@ def create_metadata(request):
'default_assertion_consumer_binding': app_settings.DEFAULT_ASSERTION_CONSUMER_BINDING,
'organization': app_settings.ORGANIZATION,
'contact_persons': app_settings.CONTACT_PERSONS,
- 'discovery_endpoint_url': request.build_absolute_uri(reverse('mellon_login')),
- })
+ }
+ if app_settings.METADATA_PUBLISH_DISCOVERY_RESPONSE:
+ ctx['discovery_endpoint_url'] = request.build_absolute_uri(
+ reverse('mellon_login'))
+ return render_to_string('mellon/metadata.xml', ctx)
def create_server(request):
diff --git a/tests/test_utils.py b/tests/test_utils.py
index 91247bc..832e7ae 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -35,6 +35,28 @@ def test_create_metadata(rf, private_settings, caplog):
private_settings.MELLON_NAME_ID_FORMATS = [lasso.SAML2_NAME_IDENTIFIER_FORMAT_UNSPECIFIED]
private_settings.MELLON_DEFAULT_ASSERTION_CONSUMER_BINDING = 'artifact'
request = rf.get('/')
+ with mock.patch('mellon.utils.open', mock.mock_open(read_data='BEGIN\nyyy\nEND'), create=True):
+ metadata = create_metadata(request)
+ assert_xml_constraints(
+ metadata.encode('utf-8'),
+ ('/sm:EntityDescriptor[@entityID="http://testserver/metadata/"]', 1,
+ ('/*', 1),
+ ('/sm:SPSSODescriptor', 1,
+ ('/*', 6),
+ ('/sm:NameIDFormat', 1),
+ ('/sm:SingleLogoutService', 1),
+ ('/sm:AssertionConsumerService[@isDefault=\'true\'][@Binding=\'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact\']', 1),
+ ('/sm:AssertionConsumerService[@isDefault=\'true\'][@Binding=\'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\']',
+ 0),
+ ('/sm:AssertionConsumerService[@Binding=\'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\']',
+ 1),
+ ('/sm:KeyDescriptor/ds:KeyInfo/ds:X509Data', 2,
+ ('/ds:X509Certificate', 2),
+ ('/ds:X509Certificate[text()=\'xxx\']', 1),
+ ('/ds:X509Certificate[text()=\'yyy\']', 1)))),
+ namespaces=ns)
+
+ private_settings.MELLON_METADATA_PUBLISH_DISCOVERY_RESPONSE = True
with mock.patch('mellon.utils.open', mock.mock_open(read_data='BEGIN\nyyy\nEND'), create=True):
metadata = create_metadata(request)
assert_xml_constraints(
diff --git a/tests/test_views.py b/tests/test_views.py
index 5bfe079..bf66855 100644
--- a/tests/test_views.py
+++ b/tests/test_views.py
@@ -112,7 +112,7 @@ def test_metadata(private_settings, client):
('/sm:EntityDescriptor[@entityID="http://testserver/metadata/"]', 1,
('/*', 4),
('/sm:SPSSODescriptor', 1,
- ('/*', 7),
+ ('/*', 6),
('/sm:NameIDFormat', 1),
('/sm:SingleLogoutService', 1),
('/sm:AssertionConsumerService', None,