Add support to create ECP assertion based on a token
A user should be able to exchange their token for an ECP wrapped SAML assertion. implements bp generate-saml-assertions Change-Id: Ic9c20aebc5cd91650576ad050c09779df54f1d94
This commit is contained in:
@@ -170,8 +170,9 @@ DOMAINS = {
|
||||
}
|
||||
}
|
||||
|
||||
TOKEN_BASED_SAML = """
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
SAML_ENCODING = "<?xml version='1.0' encoding='UTF-8'?>"
|
||||
|
||||
TOKEN_SAML_RESPONSE = """
|
||||
<ns2:Response Destination="http://beta.example.com/Shibboleth.sso/POST/ECP"
|
||||
ID="8c21de08d2f2435c9acf13e72c982846"
|
||||
IssueInstant="2015-03-25T14:43:21Z"
|
||||
@@ -253,3 +254,28 @@ TOKEN_BASED_SAML = """
|
||||
</saml:Assertion>
|
||||
</ns2:Response>
|
||||
"""
|
||||
|
||||
TOKEN_BASED_SAML = ''.join([SAML_ENCODING, TOKEN_SAML_RESPONSE])
|
||||
|
||||
ECP_ENVELOPE = """
|
||||
<ns0:Envelope
|
||||
xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/"
|
||||
xmlns:ns1="urn:oasis:names:tc:SAML:2.0:profiles:SSO:ecp"
|
||||
xmlns:ns2="urn:oasis:names:tc:SAML:2.0:protocol"
|
||||
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
|
||||
xmlns:xmldsig="http://www.w3.org/2000/09/xmldsig#"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<ns0:Header>
|
||||
<ns1:RelayState
|
||||
ns0:actor="http://schemas.xmlsoap.org/soap/actor/next"
|
||||
ns0:mustUnderstand="1">
|
||||
ss:mem:1ddfe8b0f58341a5a840d2e8717b0737
|
||||
</ns1:RelayState>
|
||||
</ns0:Header>
|
||||
<ns0:Body>
|
||||
{0}
|
||||
</ns0:Body>
|
||||
</ns0:Envelope>
|
||||
""".format(TOKEN_SAML_RESPONSE)
|
||||
|
||||
TOKEN_BASED_ECP = ''.join([SAML_ENCODING, ECP_ENVELOPE])
|
||||
|
@@ -631,6 +631,8 @@ class SAMLGenerationTests(utils.TestCase):
|
||||
self.manager = self.client.federation.saml
|
||||
self.SAML2_FULL_URL = ''.join([self.TEST_URL,
|
||||
saml_manager.SAML2_ENDPOINT])
|
||||
self.ECP_FULL_URL = ''.join([self.TEST_URL,
|
||||
saml_manager.ECP_ENDPOINT])
|
||||
|
||||
def test_saml_create(self):
|
||||
"""Test that a token can be exchanged for a SAML assertion."""
|
||||
@@ -654,3 +656,26 @@ class SAMLGenerationTests(utils.TestCase):
|
||||
self.assertEqual(service_provider_id,
|
||||
req_json['auth']['scope']['service_provider']['id'])
|
||||
self.assertRequestHeaderEqual('Content-Type', 'application/json')
|
||||
|
||||
def test_ecp_create(self):
|
||||
"""Test that a token can be exchanged for an ECP wrapped assertion."""
|
||||
|
||||
token_id = uuid.uuid4().hex
|
||||
service_provider_id = uuid.uuid4().hex
|
||||
|
||||
# Mock returned text for '/auth/OS-FEDERATION/saml2/ecp
|
||||
self.requests_mock.post(self.ECP_FULL_URL,
|
||||
text=saml2_fixtures.TOKEN_BASED_ECP)
|
||||
|
||||
text = self.manager.create_ecp_assertion(service_provider_id,
|
||||
token_id)
|
||||
|
||||
# Ensure returned text is correct
|
||||
self.assertEqual(saml2_fixtures.TOKEN_BASED_ECP, text)
|
||||
|
||||
# Ensure request headers and body are correct
|
||||
req_json = self.requests_mock.last_request.json()
|
||||
self.assertEqual(token_id, req_json['auth']['identity']['token']['id'])
|
||||
self.assertEqual(service_provider_id,
|
||||
req_json['auth']['scope']['service_provider']['id'])
|
||||
self.assertRequestHeaderEqual('Content-Type', 'application/json')
|
||||
|
@@ -14,6 +14,7 @@ from keystoneclient import base
|
||||
|
||||
|
||||
SAML2_ENDPOINT = '/auth/OS-FEDERATION/saml2'
|
||||
ECP_ENDPOINT = '/auth/OS-FEDERATION/saml2/ecp'
|
||||
|
||||
|
||||
class SamlManager(base.Manager):
|
||||
@@ -34,6 +35,33 @@ class SamlManager(base.Manager):
|
||||
:rtype: string
|
||||
"""
|
||||
|
||||
headers, body = self._create_common_request(service_provider, token_id)
|
||||
resp, body = self.client.post(SAML2_ENDPOINT, json=body,
|
||||
headers=headers)
|
||||
return resp.text
|
||||
|
||||
def create_ecp_assertion(self, service_provider, token_id):
|
||||
"""Create an ECP wrapped SAML assertion from a token.
|
||||
|
||||
Equivalent Identity API call:
|
||||
POST /auth/OS-FEDERATION/saml2/ecp
|
||||
|
||||
:param service_provider: Service Provider resource.
|
||||
:type service_provider: string
|
||||
:param token_id: Token to transform to SAML assertion.
|
||||
:type token_id: string
|
||||
|
||||
:returns: SAML representation of token_id, wrapped in ECP envelope
|
||||
:rtype: string
|
||||
"""
|
||||
|
||||
headers, body = self._create_common_request(service_provider, token_id)
|
||||
resp, body = self.client.post(ECP_ENDPOINT, json=body,
|
||||
headers=headers)
|
||||
return resp.text
|
||||
|
||||
def _create_common_request(self, service_provider, token_id):
|
||||
headers = {'Content-Type': 'application/json'}
|
||||
body = {
|
||||
'auth': {
|
||||
'identity': {
|
||||
@@ -50,7 +78,4 @@ class SamlManager(base.Manager):
|
||||
}
|
||||
}
|
||||
|
||||
headers = {'Content-Type': 'application/json'}
|
||||
resp, body = self.client.post(SAML2_ENDPOINT, json=body,
|
||||
headers=headers)
|
||||
return resp.text
|
||||
return (headers, body)
|
||||
|
Reference in New Issue
Block a user