from contextlib import closing from saml2 import BINDING_HTTP_POST from saml2.client import Saml2Client from saml2.server import Server import sys if sys.version_info.major < 3: from HTMLParser import HTMLParser else: from html.parser import HTMLParser # Typical RelayState used by Shibboleth SP. SHIB_SP_RELAY_STATE = """\ ss:mem:ab1e6a31f3bd040ffd1d64a2d0e15d61ce517f5e1a94a41ea4fae32cc8d70a04""" class RelayStateHTMLParser(HTMLParser, object): """Class used to parse HTML from a HTTP-POST binding response and determine if the HTML includes the expected relay state.""" def __init__(self, expected_relay_state): super(RelayStateHTMLParser, self).__init__() self.expected_relay_state = expected_relay_state self.expected_relay_state_found = False self.input_relay_state_element_found = False def handle_starttag(self, tag, attrs): """If the tag is found and it includes the correct value for the relay state set the relay state found flag to true.""" if tag == 'input': if ('name', 'RelayState') in attrs: self.input_relay_state_found = True if ('value', self.expected_relay_state) in attrs: self.expected_relay_state_found = True def test_relay_state(): # Identity information about a mock user. identity = { "eduPersonEntitlement": "Short stop", "surName": "Jeter", "givenName": "Derek", "mail": "derek.jeter@nyy.mlb.com", "title": "The man" } # Create a service provider using the servera_conf.py configuration. sp = Saml2Client(config_file="servera_conf") # Create an identity providver using the idp_all_conf.py configuration. with closing(Server(config_file="idp_all_conf")) as idp: # Create a response to an authentication request as if # it came from the SP. name_id = idp.ident.transient_nameid(sp.config.entityid, "id12") binding, destination = idp.pick_binding("assertion_consumer_service", bindings=[BINDING_HTTP_POST], entity_id=sp.config.entityid) resp = idp.create_authn_response(identity, "id-123456789", destination, sp.config.entityid, name_id=name_id) # Apply the HTTP_POST binding to the response with a relay state # typical from a Shibboleth SP to create the HTML that carries # the SAML response. relay_state = SHIB_SP_RELAY_STATE html = idp.apply_binding(BINDING_HTTP_POST, "%s" % resp, destination, relay_state)['data'] # Parse the HTML and verify that it contains the correct relay state. parser = RelayStateHTMLParser(relay_state) parser.feed(html) assert parser.expected_relay_state_found # Apply the HTTP_POST binding to the response with relay state None. relay_state = None html = idp.apply_binding(BINDING_HTTP_POST, "%s" % resp, destination, relay_state)['data'] # Parse the HTML and verify that it does not contain a relay state. parser = RelayStateHTMLParser(relay_state) parser.feed(html) assert not parser.input_relay_state_element_found # Apply the HTTP_POST binding to the response with empty # string relay state. relay_state = "" html = idp.apply_binding(BINDING_HTTP_POST, "%s" % resp, destination, relay_state)['data'] # Parse the HTML and verify that it does not contain a relay state. parser = RelayStateHTMLParser(relay_state) parser.feed(html) assert not parser.input_relay_state_element_found if __name__ == "__main__": test_relay_state()