diff --git a/README.md b/README.md index 963eb2e..8e7fc0d 100644 --- a/README.md +++ b/README.md @@ -56,8 +56,7 @@ XML. ```python saml_helper.register_service_provider( - name="synapse.local", - metadata=service_provider_metadata + name="synapse.local", metadata=service_provider_metadata ) ``` @@ -69,17 +68,15 @@ across service providers, it should result in a redirection to the SAML test IdP for SSO login. Capture the redirection URL, then pass it to the helper. Here, the helper completes all steps on the IdP side and returns -a `requests.Request` object holding the assertion. You can then inspect, modify, -or relay this request to the service provider to finalize the login. +a `SamlResponseHttpPost` object holding the assertion. You can then inspect, +modify, or relay this response to the service provider to finalize the login. ```python -next_request = saml_helper.sso_login(redirect_url) -assert "https://synapse.local" in next_request.url +saml_response = saml_helper.redirect_sso_login(redirect_url) +assert "https://synapse.local" in saml_response.url -next_request.url = next_request.url.replace( - "https://synapse.local", - f"http://{ip}:8080" +url = saml_response.url.replace("https://synapse.local", f"http://{ip}:8080") +logged_in_page = requests.post( + url, data=saml_response.data, headers={"Host": "synapse.local"} ) -next_request.headers["Host"] = "synapse.local" -logged_in_page = session.send(next_request.prepare()) ``` diff --git a/saml_test_helper/__init__.py b/saml_test_helper/__init__.py index 1f78bd8..b010fcf 100644 --- a/saml_test_helper/__init__.py +++ b/saml_test_helper/__init__.py @@ -1,10 +1,11 @@ import base64 +import dataclasses import logging import time import urllib.parse import zlib from pathlib import Path -from typing import List, Optional +from typing import Dict, List, Optional from xml.etree import ElementTree import kubernetes @@ -15,6 +16,19 @@ logger = logging.getLogger("saml_test_helper") +@dataclasses.dataclass +class SamlResponseHttpPost: + """Represent a SAML response transmitted via the HTTP-POST binding. + + :ivar url: Service provider's endpoint to receive the SAML assertion. + :ivar data: Dictionary containing the HTML form data for the SAML response. + """ + + url: str + data: Dict[str, str] + binding: str = "HTTP-POST" + + class SamlK8sTestHelper: CERTIFICATE = (Path(__file__).parent / "certs/certificate.pem").read_text() CERTIFICATE_HASH = "30be696d" @@ -222,9 +236,9 @@ def register_service_provider(self, name: str, metadata: str) -> None: ) response.raise_for_status() - def sso_login( + def redirect_sso_login( self, redirect_url: str, username: str = "ubuntu", password: str = "ubuntu" - ) -> requests.Request: + ) -> SamlResponseHttpPost: """Execute identity provider steps of SSO login process. This method runs the identity provider steps of SSO login process during the service @@ -232,14 +246,14 @@ def sso_login( users for authentication with the identity provider. You can obtain this URL by initiating a login request on the service provider's website. - After executing all identity provider steps, this method returns a ``requests.Request`` - instance. This object encapsulates the SAML assertion, which should be sent back to the - service provider to complete the SSO process. + After executing all identity provider steps, this method returns a + ``SamlResponseHttpPost`` instance. This object encapsulates the SAML assertion, which + should be sent back to the service provider to complete the SSO process. :param redirect_url: URL where the service provider redirects for IdP authentication. :param username: Username for SSO login, defaulting to "ubuntu". :param password: Password for SSO login, defaulting to "ubuntu". - :return: A ``requests.Request`` object encapsulating the SAML assertion. + :return: A ``SamlResponseHttpPost`` object encapsulating the SAML response. """ url = urllib.parse.urlparse(redirect_url) if url.netloc != self.SAML_HOST: @@ -274,4 +288,4 @@ def sso_login( for node in tree.iter("input") if "name" in node.attrib and "value" in node.attrib } - return requests.Request(method="POST", url=post_url, data=inputs) + return SamlResponseHttpPost(url=post_url, data=inputs)