grafana / django-saml2-auth

Django SAML2 Authentication Made Easy. Easily integrate with SAML2 SSO identity providers like Okta, Azure AD and others.
Other
180 stars 53 forks source link

Making Tests Easier #325

Open ephes opened 1 month ago

ephes commented 1 month ago

Hi,

Thank you for creating this package; I really enjoy using it! 😃 While testing incoming SAML responses, I found it challenging to provide the IDP metadata. Here's my current approach:

import pytest

@pytest.fixture(scope="session")
def idp_metadata_path(tmp_path_factory):
    fn = tmp_path_factory.mktemp("data") / "idp.xml"
    with fn.open("w") as f:
        f.write('<EntityDescriptor entityID="https://localhost:8088/idp.xml" />')
    return fn

@pytest.mark.django_db
def test_sso_signin(settings, idp_metadata_path):
    settings.SAML2_AUTH["METADATA_LOCAL_FILE_PATH"] = idp_metadata_path
    ...

It would be great to avoid creating this temporary file. Could you add a setting to provide an inline metadata config? Here's a suggestion:

# django_saml_auth/saml.py line 123
    ...
    metadata_local_file_path = dictor(saml2_auth_settings, "METADATA_LOCAL_FILE_PATH")
    metadata_inline = dictor(saml2_auth_settings, "METADATA_INLINE")
    if metadata_local_file_path:
        return {"local": [metadata_local_file_path]}
    elif metadata_inline:
        return {"inline": [metadata_inline]}
    else:
        single_metadata_url = dictor(saml2_auth_settings, "METADATA_AUTO_CONF_URL")
        if validate_metadata_url(single_metadata_url):
            return {"remote": [{"url": single_metadata_url}]}
    ...

For the service provider metadata, I already use this approach to set up an IdP server object, which I then use to create custom SAML responses:

from saml2 import server
from saml2.config import Config as PysamlConfig

SP_XML_TEMPLATE = """
<ns0:EntityDescriptor
  xmlns:ns0="urn:oasis:names:tc:SAML:2.0:metadata"
  entityID="{entity_id}"
>
  <ns0:SPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol" />
</ns0:EntityDescriptor>
"""

...
    @property
    def identity_provider(self):
        sp_metadata = SP_XML_TEMPLATE.format(test_host=self.test_host, entity_id=self.entity_id)
        config_data = {
            "entityid": "https://localhost:8088/idp.xml",
            "service": {"idp": {}},
            "metadata": {"inline": [sp_metadata]},
        }
        config = PysamlConfig().load(config_data)
        idp = server.Server(config=config)
        idp.ticket = {}
        return idp
...

Best regards, Jochen

mostafa commented 1 month ago

Hey @ephes,

Can you send a PR for this?

ephes commented 1 month ago

Ok, I'll give it a try, but it will take probably until end of August until I'll have time to submit one.

github-actions[bot] commented 4 days ago

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.