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):
|
||||
if len(_list) != 1:
|
||||
raise IndexError("Only single element list can be flatten")
|
||||
raise IndexError("Only single element is acceptable")
|
||||
return _list[0]
|
||||
|
||||
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)
|
||||
return access.AccessInfoV3(token,
|
||||
**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 import session
|
||||
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 utils
|
||||
|
||||
@@ -309,3 +310,79 @@ class AuthenticateviaSAML2Tests(auth_utils.TestCase, utils.TestCase):
|
||||
response = self.saml2plugin.get_auth_ref(self.session)
|
||||
self.assertEqual(saml2_fixtures.UNSCOPED_TOKEN_HEADER,
|
||||
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