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:
Steve Martinelli
2015-03-29 02:55:01 -04:00
parent a2fc6cf4f4
commit 1628b77a79
3 changed files with 82 additions and 6 deletions

View File

@@ -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])

View File

@@ -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')

View File

@@ -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)