diff options
-rw-r--r-- | keystoneclient/contrib/auth/v3/saml2.py | 18 | ||||
-rw-r--r-- | keystoneclient/tests/unit/v3/test_auth_saml2.py | 27 |
2 files changed, 36 insertions, 9 deletions
diff --git a/keystoneclient/contrib/auth/v3/saml2.py b/keystoneclient/contrib/auth/v3/saml2.py index 929d99e..3a311d4 100644 --- a/keystoneclient/contrib/auth/v3/saml2.py +++ b/keystoneclient/contrib/auth/v3/saml2.py @@ -26,6 +26,8 @@ from keystoneclient.i18n import _ class _BaseSAMLPlugin(v3.AuthConstructor): HTTP_MOVED_TEMPORARILY = 302 + HTTP_SEE_OTHER = 303 + PROTOCOL = 'saml2' @staticmethod @@ -192,9 +194,9 @@ class Saml2UnscopedToken(_BaseSAMLPlugin): # Override to remove deprecation. self._password = value - def _handle_http_302_ecp_redirect(self, session, response, method, - **kwargs): - if response.status_code != self.HTTP_MOVED_TEMPORARILY: + def _handle_http_ecp_redirect(self, session, response, method, **kwargs): + if response.status_code not in (self.HTTP_MOVED_TEMPORARILY, + self.HTTP_SEE_OTHER): return response location = response.headers['location'] @@ -327,7 +329,7 @@ class Saml2UnscopedToken(_BaseSAMLPlugin): managed URL, for instance: ``https://<host>:<port>/Shibboleth.sso/ SAML2/ECP``. Upon success the there's a session created and access to the protected - resource is granted. Many implementations of the SP return HTTP 302 + resource is granted. Many implementations of the SP return HTTP 302/303 status code pointing to the protected URL (``https://<host>:<port>/v3/ OS-FEDERATION/identity_providers/{identity_provider}/protocols/ {protocol_id}/auth`` in this case). Saml2 plugin should point to that @@ -344,11 +346,11 @@ class Saml2UnscopedToken(_BaseSAMLPlugin): data=etree.tostring(self.saml2_idp_authn_response), authenticated=False, redirect=False) - # Don't follow HTTP specs - after the HTTP 302 response don't repeat - # the call directed to the Location URL. In this case, this is an - # indication that saml2 session is now active and protected resource + # Don't follow HTTP specs - after the HTTP 302/303 response don't + # repeat the call directed to the Location URL. In this case, this is + # an indication that saml2 session is now active and protected resource # can be accessed. - response = self._handle_http_302_ecp_redirect( + response = self._handle_http_ecp_redirect( session, response, method='GET', headers=self.ECP_SP_SAML2_REQUEST_HEADERS) diff --git a/keystoneclient/tests/unit/v3/test_auth_saml2.py b/keystoneclient/tests/unit/v3/test_auth_saml2.py index d64d962..e8eb9f1 100644 --- a/keystoneclient/tests/unit/v3/test_auth_saml2.py +++ b/keystoneclient/tests/unit/v3/test_auth_saml2.py @@ -283,7 +283,32 @@ class AuthenticateviaSAML2Tests(utils.TestCase): self.assertEqual(self.FEDERATION_AUTH_URL, response.headers['location']) - response = self.saml2plugin._handle_http_302_ecp_redirect( + response = self.saml2plugin._handle_http_ecp_redirect( + self.session, response, 'GET') + + self.assertEqual(self.FEDERATION_AUTH_URL, response.request.url) + self.assertEqual('GET', response.request.method) + + def test_custom_303_redirection(self): + self.requests_mock.post( + self.SHIB_CONSUMER_URL, + text='BODY', + headers={'location': self.FEDERATION_AUTH_URL}, + status_code=303) + + self.requests_mock.get( + self.FEDERATION_AUTH_URL, + json=saml2_fixtures.UNSCOPED_TOKEN, + headers={'X-Subject-Token': saml2_fixtures.UNSCOPED_TOKEN_HEADER}) + + self.session.redirect = False + response = self.session.post( + self.SHIB_CONSUMER_URL, data='CLIENT BODY') + self.assertEqual(303, response.status_code) + self.assertEqual(self.FEDERATION_AUTH_URL, + response.headers['location']) + + response = self.saml2plugin._handle_http_ecp_redirect( self.session, response, 'GET') self.assertEqual(self.FEDERATION_AUTH_URL, response.request.url) |