Scope unscoped saml2 tokens.
Scope unscoped federation token. The plugin mimics standard v3.Token behaviour. Change-Id: I81f30a7c893be15e715c57bd43035b12d8435f58 Implements: blueprint add-saml2-cli-authentication
This commit is contained in:
@@ -141,7 +141,7 @@ class Saml2UnscopedToken(v3.AuthConstructor):
|
|||||||
|
|
||||||
def _first(self, _list):
|
def _first(self, _list):
|
||||||
if len(_list) != 1:
|
if len(_list) != 1:
|
||||||
raise IndexError("Only single element list can be flatten")
|
raise IndexError("Only single element is acceptable")
|
||||||
return _list[0]
|
return _list[0]
|
||||||
|
|
||||||
def _prepare_idp_saml2_request(self, saml2_authn_request):
|
def _prepare_idp_saml2_request(self, saml2_authn_request):
|
||||||
@@ -409,3 +409,27 @@ class Saml2UnscopedToken(v3.AuthConstructor):
|
|||||||
token, token_json = self._get_unscoped_token(session, **kwargs)
|
token, token_json = self._get_unscoped_token(session, **kwargs)
|
||||||
return access.AccessInfoV3(token,
|
return access.AccessInfoV3(token,
|
||||||
**token_json)
|
**token_json)
|
||||||
|
|
||||||
|
|
||||||
|
class Saml2ScopedTokenMethod(v3.TokenMethod):
|
||||||
|
_method_name = 'saml2'
|
||||||
|
|
||||||
|
def get_auth_data(self, session, auth, headers, **kwargs):
|
||||||
|
"""Build and return request body for token scoping step."""
|
||||||
|
|
||||||
|
t = super(Saml2ScopedTokenMethod, self).get_auth_data(
|
||||||
|
session, auth, headers, **kwargs)
|
||||||
|
_token_method, token = t
|
||||||
|
return self._method_name, token
|
||||||
|
|
||||||
|
|
||||||
|
class Saml2ScopedToken(v3.Token):
|
||||||
|
"""Class for scoping unscoped saml2 token."""
|
||||||
|
|
||||||
|
_auth_method_class = Saml2ScopedTokenMethod
|
||||||
|
|
||||||
|
def __init__(self, auth_url, token, **kwargs):
|
||||||
|
super(Saml2ScopedToken, self).__init__(auth_url, token, **kwargs)
|
||||||
|
if not (self.project_id or self.domain_id):
|
||||||
|
raise exceptions.ValidationError(
|
||||||
|
'Neither project nor domain specified')
|
||||||
|
@@ -119,3 +119,50 @@ UNSCOPED_TOKEN = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PROJECTS = {
|
||||||
|
"projects": [
|
||||||
|
{
|
||||||
|
"domain_id": "37ef61",
|
||||||
|
"enabled": 'true',
|
||||||
|
"id": "12d706",
|
||||||
|
"links": {
|
||||||
|
"self": "http://identity:35357/v3/projects/12d706"
|
||||||
|
},
|
||||||
|
"name": "a project name"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"domain_id": "37ef61",
|
||||||
|
"enabled": 'true',
|
||||||
|
"id": "9ca0eb",
|
||||||
|
"links": {
|
||||||
|
"self": "http://identity:35357/v3/projects/9ca0eb"
|
||||||
|
},
|
||||||
|
"name": "another project"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"links": {
|
||||||
|
"self": "http://identity:35357/v3/OS-FEDERATION/projects",
|
||||||
|
"previous": 'null',
|
||||||
|
"next": 'null'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DOMAINS = {
|
||||||
|
"domains": [
|
||||||
|
{
|
||||||
|
"description": "desc of domain",
|
||||||
|
"enabled": 'true',
|
||||||
|
"id": "37ef61",
|
||||||
|
"links": {
|
||||||
|
"self": "http://identity:35357/v3/domains/37ef61"
|
||||||
|
},
|
||||||
|
"name": "my domain"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"links": {
|
||||||
|
"self": "http://identity:35357/v3/OS-FEDERATION/domains",
|
||||||
|
"previous": 'null',
|
||||||
|
"next": 'null'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -23,6 +23,7 @@ from keystoneclient.openstack.common.fixture import config
|
|||||||
from keystoneclient.openstack.common import jsonutils
|
from keystoneclient.openstack.common import jsonutils
|
||||||
from keystoneclient import session
|
from keystoneclient import session
|
||||||
from keystoneclient.tests.auth import utils as auth_utils
|
from keystoneclient.tests.auth import utils as auth_utils
|
||||||
|
from keystoneclient.tests.v3 import client_fixtures
|
||||||
from keystoneclient.tests.v3 import saml2_fixtures
|
from keystoneclient.tests.v3 import saml2_fixtures
|
||||||
from keystoneclient.tests.v3 import utils
|
from keystoneclient.tests.v3 import utils
|
||||||
|
|
||||||
@@ -309,3 +310,79 @@ class AuthenticateviaSAML2Tests(auth_utils.TestCase, utils.TestCase):
|
|||||||
response = self.saml2plugin.get_auth_ref(self.session)
|
response = self.saml2plugin.get_auth_ref(self.session)
|
||||||
self.assertEqual(saml2_fixtures.UNSCOPED_TOKEN_HEADER,
|
self.assertEqual(saml2_fixtures.UNSCOPED_TOKEN_HEADER,
|
||||||
response.auth_token)
|
response.auth_token)
|
||||||
|
|
||||||
|
|
||||||
|
class ScopeFederationTokenTests(AuthenticateviaSAML2Tests):
|
||||||
|
def setUp(self):
|
||||||
|
super(ScopeFederationTokenTests, self).setUp()
|
||||||
|
|
||||||
|
self.PROJECT_SCOPED_TOKEN_JSON = client_fixtures.project_scoped_token()
|
||||||
|
self.PROJECT_SCOPED_TOKEN_JSON['methods'] = ['saml2']
|
||||||
|
|
||||||
|
# for better readibility
|
||||||
|
self.TEST_TENANT_ID = self.PROJECT_SCOPED_TOKEN_JSON.project_id
|
||||||
|
self.TEST_TENANT_NAME = self.PROJECT_SCOPED_TOKEN_JSON.project_name
|
||||||
|
|
||||||
|
self.DOMAIN_SCOPED_TOKEN_JSON = client_fixtures.domain_scoped_token()
|
||||||
|
self.DOMAIN_SCOPED_TOKEN_JSON['methods'] = ['saml2']
|
||||||
|
|
||||||
|
#for better readibility
|
||||||
|
self.TEST_DOMAIN_ID = self.DOMAIN_SCOPED_TOKEN_JSON.domain_id
|
||||||
|
self.TEST_DOMAIN_NAME = self.DOMAIN_SCOPED_TOKEN_JSON.domain_name
|
||||||
|
|
||||||
|
self.saml2_scope_plugin = saml2.Saml2ScopedToken(
|
||||||
|
self.TEST_URL, saml2_fixtures.UNSCOPED_TOKEN_HEADER,
|
||||||
|
project_id=self.TEST_TENANT_ID)
|
||||||
|
|
||||||
|
@httpretty.activate
|
||||||
|
def test_scope_saml2_token_to_project(self):
|
||||||
|
self.simple_http('POST', self.TEST_URL + '/auth/tokens',
|
||||||
|
body=jsonutils.dumps(self.PROJECT_SCOPED_TOKEN_JSON),
|
||||||
|
content_type='application/json',
|
||||||
|
headers=client_fixtures.AUTH_RESPONSE_HEADERS)
|
||||||
|
|
||||||
|
token = self.saml2_scope_plugin.get_auth_ref(self.session)
|
||||||
|
self.assertTrue(token.project_scoped, "Received token is not scoped")
|
||||||
|
self.assertEqual(client_fixtures.AUTH_SUBJECT_TOKEN, token.auth_token)
|
||||||
|
self.assertEqual(self.TEST_TENANT_ID, token.project_id)
|
||||||
|
self.assertEqual(self.TEST_TENANT_NAME, token.project_name)
|
||||||
|
|
||||||
|
@httpretty.activate
|
||||||
|
def test_scope_saml2_token_to_invalid_project(self):
|
||||||
|
self.simple_http('POST', self.TEST_URL + '/auth/tokens', status=401)
|
||||||
|
self.saml2_scope_plugin.project_id = uuid.uuid4().hex
|
||||||
|
self.saml2_scope_plugin.project_name = None
|
||||||
|
self.assertRaises(exceptions.Unauthorized,
|
||||||
|
self.saml2_scope_plugin.get_auth_ref,
|
||||||
|
self.session)
|
||||||
|
|
||||||
|
@httpretty.activate
|
||||||
|
def test_scope_saml2_token_to_invalid_domain(self):
|
||||||
|
self.simple_http('POST', self.TEST_URL + '/auth/tokens', status=401)
|
||||||
|
self.saml2_scope_plugin.project_id = None
|
||||||
|
self.saml2_scope_plugin.project_name = None
|
||||||
|
self.saml2_scope_plugin.domain_id = uuid.uuid4().hex
|
||||||
|
self.saml2_scope_plugin.domain_name = None
|
||||||
|
self.assertRaises(exceptions.Unauthorized,
|
||||||
|
self.saml2_scope_plugin.get_auth_ref,
|
||||||
|
self.session)
|
||||||
|
|
||||||
|
@httpretty.activate
|
||||||
|
def test_scope_saml2_token_to_domain(self):
|
||||||
|
self.simple_http('POST', self.TEST_URL + '/auth/tokens',
|
||||||
|
body=jsonutils.dumps(self.DOMAIN_SCOPED_TOKEN_JSON),
|
||||||
|
content_type='application/json',
|
||||||
|
headers=client_fixtures.AUTH_RESPONSE_HEADERS)
|
||||||
|
|
||||||
|
token = self.saml2_scope_plugin.get_auth_ref(self.session)
|
||||||
|
self.assertTrue(token.domain_scoped, "Received token is not scoped")
|
||||||
|
self.assertEqual(client_fixtures.AUTH_SUBJECT_TOKEN, token.auth_token)
|
||||||
|
self.assertEqual(self.TEST_DOMAIN_ID, token.domain_id)
|
||||||
|
self.assertEqual(self.TEST_DOMAIN_NAME, token.domain_name)
|
||||||
|
|
||||||
|
def test_dont_set_project_nor_domain(self):
|
||||||
|
self.saml2_scope_plugin.project_id = None
|
||||||
|
self.saml2_scope_plugin.domain_id = None
|
||||||
|
self.assertRaises(exceptions.ValidationError,
|
||||||
|
saml2.Saml2ScopedToken,
|
||||||
|
self.TEST_URL, client_fixtures.AUTH_SUBJECT_TOKEN)
|
||||||
|
Reference in New Issue
Block a user