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 = """
|
SAML_ENCODING = "<?xml version='1.0' encoding='UTF-8'?>"
|
||||||
<?xml version='1.0' encoding='UTF-8'?>
|
|
||||||
|
TOKEN_SAML_RESPONSE = """
|
||||||
<ns2:Response Destination="http://beta.example.com/Shibboleth.sso/POST/ECP"
|
<ns2:Response Destination="http://beta.example.com/Shibboleth.sso/POST/ECP"
|
||||||
ID="8c21de08d2f2435c9acf13e72c982846"
|
ID="8c21de08d2f2435c9acf13e72c982846"
|
||||||
IssueInstant="2015-03-25T14:43:21Z"
|
IssueInstant="2015-03-25T14:43:21Z"
|
||||||
@@ -253,3 +254,28 @@ TOKEN_BASED_SAML = """
|
|||||||
</saml:Assertion>
|
</saml:Assertion>
|
||||||
</ns2:Response>
|
</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.manager = self.client.federation.saml
|
||||||
self.SAML2_FULL_URL = ''.join([self.TEST_URL,
|
self.SAML2_FULL_URL = ''.join([self.TEST_URL,
|
||||||
saml_manager.SAML2_ENDPOINT])
|
saml_manager.SAML2_ENDPOINT])
|
||||||
|
self.ECP_FULL_URL = ''.join([self.TEST_URL,
|
||||||
|
saml_manager.ECP_ENDPOINT])
|
||||||
|
|
||||||
def test_saml_create(self):
|
def test_saml_create(self):
|
||||||
"""Test that a token can be exchanged for a SAML assertion."""
|
"""Test that a token can be exchanged for a SAML assertion."""
|
||||||
@@ -654,3 +656,26 @@ class SAMLGenerationTests(utils.TestCase):
|
|||||||
self.assertEqual(service_provider_id,
|
self.assertEqual(service_provider_id,
|
||||||
req_json['auth']['scope']['service_provider']['id'])
|
req_json['auth']['scope']['service_provider']['id'])
|
||||||
self.assertRequestHeaderEqual('Content-Type', 'application/json')
|
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'
|
SAML2_ENDPOINT = '/auth/OS-FEDERATION/saml2'
|
||||||
|
ECP_ENDPOINT = '/auth/OS-FEDERATION/saml2/ecp'
|
||||||
|
|
||||||
|
|
||||||
class SamlManager(base.Manager):
|
class SamlManager(base.Manager):
|
||||||
@@ -34,6 +35,33 @@ class SamlManager(base.Manager):
|
|||||||
:rtype: string
|
: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 = {
|
body = {
|
||||||
'auth': {
|
'auth': {
|
||||||
'identity': {
|
'identity': {
|
||||||
@@ -50,7 +78,4 @@ class SamlManager(base.Manager):
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
headers = {'Content-Type': 'application/json'}
|
return (headers, body)
|
||||||
resp, body = self.client.post(SAML2_ENDPOINT, json=body,
|
|
||||||
headers=headers)
|
|
||||||
return resp.text
|
|
||||||
|
Reference in New Issue
Block a user