Refactor Token Providers for better version interfaces

Cleanup Token Providers to provider a cleaner interface for the
various token versions. Removal of named-arguments/kwargs is
for future caching capabilities.  Due to overhead and problems
with both generating consistent cache keys and invalidates
moving to an "arg" model is better for the manager calls.

Change-Id: I45764ade8bf726c57bf44dba783175bfac5032b4
blueprint: caching-layer-for-driver-calls
This commit is contained in:
Morgan Fainberg 2013-08-04 04:20:13 -07:00
parent 14cba15fcb
commit d20885acaf
6 changed files with 473 additions and 156 deletions

View File

@ -246,7 +246,7 @@ class AuthInfo(object):
:returns: (domain_id, project_id, trust_ref).
If scope to a project, (None, project_id, None)
will be returned.
If scoped to a domain, (domain_id, None,None)
If scoped to a domain, (domain_id, None, None)
will be returned.
If scoped to a trust, (None, project_id, trust_ref),
Will be returned, where the project_id comes from the
@ -293,16 +293,15 @@ class Auth(controller.V3Controller):
method_names += auth_context.get('method_names', [])
# make sure the list is unique
method_names = list(set(method_names))
expires_at = auth_context.get('expires_at')
# NOTE(morganfainberg): define this here so it is clear what the
# argument is during the issue_v3_token provider call.
metadata_ref = None
(token_id, token_data) = self.token_provider_api.issue_v3_token(
auth_context['user_id'], method_names, expires_at, project_id,
domain_id, auth_context, trust, metadata_ref, include_catalog)
(token_id, token_data) = self.token_provider_api.issue_token(
user_id=auth_context['user_id'],
method_names=method_names,
expires_at=auth_context.get('expires_at'),
project_id=project_id,
domain_id=domain_id,
auth_context=auth_context,
trust=trust,
include_catalog=include_catalog)
return render_token_data_response(token_id, token_data,
created=True)
except exception.TrustNotFound as e:
@ -358,7 +357,7 @@ class Auth(controller.V3Controller):
@controller.protected
def check_token(self, context):
token_id = context.get('subject_token_id')
self.token_provider_api.check_token(token_id)
self.token_provider_api.check_v3_token(token_id)
@controller.protected
def revoke_token(self, context):
@ -368,7 +367,7 @@ class Auth(controller.V3Controller):
@controller.protected
def validate_token(self, context):
token_id = context.get('subject_token_id')
token_data = self.token_provider_api.validate_token(token_id)
token_data = self.token_provider_api.validate_v3_token(token_id)
return render_token_data_response(token_id, token_data)
@controller.protected

View File

@ -194,11 +194,9 @@ class Ec2Controller(controller.V2Controller):
tenant=tenant_ref,
metadata=metadata_ref,
id='placeholder')
(token_id, token_data) = self.token_provider_api.issue_token(
version=token.provider.V2,
token_ref=auth_token_data,
roles_ref=roles_ref,
catalog_ref=catalog_ref)
(token_id, token_data) = self.token_provider_api.issue_v2_token(
auth_token_data, roles_ref, catalog_ref)
return token_data
def create_credential(self, context, user_id, tenant_id):

View File

@ -14,8 +14,6 @@
# License for the specific language governing permissions and limitations
# under the License.
import uuid
from keystone import exception
from keystone.tests import core as test
from keystone import token
@ -328,6 +326,314 @@ SAMPLE_V3_TOKEN = {
}
}
SAMPLE_V2_TOKEN_WITH_EMBEDED_VERSION = {
"access": {
"trust": {
"id": "abc123",
"trustee_user_id": "123456"
},
"serviceCatalog": [
{
"endpoints": [
{
"adminURL": "http://localhost:8774/v1.1/01257",
"id": "51934fe63a5b4ac0a32664f64eb462c3",
"internalURL": "http://localhost:8774/v1.1/01257",
"publicURL": "http://localhost:8774/v1.1/01257",
"region": "RegionOne"
}
],
"endpoints_links": [],
"name": "nova",
"type": "compute"
},
{
"endpoints": [
{
"adminURL": "http://localhost:9292",
"id": "aaa17a539e364297a7845d67c7c7cc4b",
"internalURL": "http://localhost:9292",
"publicURL": "http://localhost:9292",
"region": "RegionOne"
}
],
"endpoints_links": [],
"name": "glance",
"type": "image"
},
{
"endpoints": [
{
"adminURL": "http://localhost:8776/v1/01257",
"id": "077d82df25304abeac2294004441db5a",
"internalURL": "http://localhost:8776/v1/01257",
"publicURL": "http://localhost:8776/v1/01257",
"region": "RegionOne"
}
],
"endpoints_links": [],
"name": "volume",
"type": "volume"
},
{
"endpoints": [
{
"adminURL": "http://localhost:8773/services/Admin",
"id": "b06997fd08414903ad458836efaa9067",
"internalURL": "http://localhost:8773/services/Cloud",
"publicURL": "http://localhost:8773/services/Cloud",
"region": "RegionOne"
}
],
"endpoints_links": [],
"name": "ec2",
"type": "ec2"
},
{
"endpoints": [
{
"adminURL": "http://localhost:8888/v1",
"id": "7bd0c643e05a4a2ab40902b2fa0dd4e6",
"internalURL": "http://localhost:8888/v1/AUTH_01257",
"publicURL": "http://localhost:8888/v1/AUTH_01257",
"region": "RegionOne"
}
],
"endpoints_links": [],
"name": "swift",
"type": "object-store"
},
{
"endpoints": [
{
"adminURL": "http://localhost:35357/v2.0",
"id": "02850c5d1d094887bdc46e81e1e15dc7",
"internalURL": "http://localhost:5000/v2.0",
"publicURL": "http://localhost:5000/v2.0",
"region": "RegionOne"
}
],
"endpoints_links": [],
"name": "keystone",
"type": "identity"
}
],
"token": {
"expires": "2013-05-22T00:02:43.941430Z",
"id": "ce4fc2d36eea4cc9a36e666ac2f1029a",
"issued_at": "2013-05-21T00:02:43.941473Z",
"tenant": {
"enabled": True,
"id": "01257",
"name": "service"
}
},
"user": {
"id": "f19ddbe2c53c46f189fe66d0a7a9c9ce",
"name": "nova",
"roles": [
{
"name": "_member_"
},
{
"name": "admin"
}
],
"roles_links": [],
"username": "nova"
}
},
'token_version': 'v2.0'
}
SAMPLE_V3_TOKEN_WITH_EMBEDED_VERSION = SAMPLE_V3_TOKEN = {
"token": {
"catalog": [
{
"endpoints": [
{
"id": "02850c5d1d094887bdc46e81e1e15dc7",
"interface": "admin",
"region": "RegionOne",
"url": "http://localhost:35357/v2.0"
},
{
"id": "446e244b75034a9ab4b0811e82d0b7c8",
"interface": "internal",
"region": "RegionOne",
"url": "http://localhost:5000/v2.0"
},
{
"id": "47fa3d9f499240abb5dfcf2668f168cd",
"interface": "public",
"region": "RegionOne",
"url": "http://localhost:5000/v2.0"
}
],
"id": "26d7541715a44a4d9adad96f9872b633",
"type": "identity",
},
{
"endpoints": [
{
"id": "aaa17a539e364297a7845d67c7c7cc4b",
"interface": "admin",
"region": "RegionOne",
"url": "http://localhost:9292"
},
{
"id": "4fa9620e42394cb1974736dce0856c71",
"interface": "internal",
"region": "RegionOne",
"url": "http://localhost:9292"
},
{
"id": "9673687f9bc441d88dec37942bfd603b",
"interface": "public",
"region": "RegionOne",
"url": "http://localhost:9292"
}
],
"id": "d27a41843f4e4b0e8cf6dac4082deb0d",
"type": "image",
},
{
"endpoints": [
{
"id": "7bd0c643e05a4a2ab40902b2fa0dd4e6",
"interface": "admin",
"region": "RegionOne",
"url": "http://localhost:8888/v1"
},
{
"id": "43bef154594d4ccb8e49014d20624e1d",
"interface": "internal",
"region": "RegionOne",
"url": "http://localhost:8888/v1/AUTH_01257"
},
{
"id": "e63b5f5d7aa3493690189d0ff843b9b3",
"interface": "public",
"region": "RegionOne",
"url": "http://localhost:8888/v1/AUTH_01257"
}
],
"id": "a669e152f1104810a4b6701aade721bb",
"type": "object-store",
},
{
"endpoints": [
{
"id": "51934fe63a5b4ac0a32664f64eb462c3",
"interface": "admin",
"region": "RegionOne",
"url": "http://localhost:8774/v1.1/01257"
},
{
"id": "869b535eea0d42e483ae9da0d868ebad",
"interface": "internal",
"region": "RegionOne",
"url": "http://localhost:8774/v1.1/01257"
},
{
"id": "93583824c18f4263a2245ca432b132a6",
"interface": "public",
"region": "RegionOne",
"url": "http://localhost:8774/v1.1/01257"
}
],
"id": "7f32cc2af6c9476e82d75f80e8b3bbb8",
"type": "compute",
},
{
"endpoints": [
{
"id": "b06997fd08414903ad458836efaa9067",
"interface": "admin",
"region": "RegionOne",
"url": "http://localhost:8773/services/Admin"
},
{
"id": "411f7de7c9a8484c9b46c254fb2676e2",
"interface": "internal",
"region": "RegionOne",
"url": "http://localhost:8773/services/Cloud"
},
{
"id": "f21c93f3da014785854b4126d0109c49",
"interface": "public",
"region": "RegionOne",
"url": "http://localhost:8773/services/Cloud"
}
],
"id": "b08c9c7d4ef543eba5eeb766f72e5aa1",
"type": "ec2",
},
{
"endpoints": [
{
"id": "077d82df25304abeac2294004441db5a",
"interface": "admin",
"region": "RegionOne",
"url": "http://localhost:8776/v1/01257"
},
{
"id": "875bf282362c40219665278b4fd11467",
"interface": "internal",
"region": "RegionOne",
"url": "http://localhost:8776/v1/01257"
},
{
"id": "cd229aa6df0640dc858a8026eb7e640c",
"interface": "public",
"region": "RegionOne",
"url": "http://localhost:8776/v1/01257"
}
],
"id": "5db21b82617f4a95816064736a7bec22",
"type": "volume",
}
],
"expires_at": "2013-05-22T00:02:43.941430Z",
"issued_at": "2013-05-21T00:02:43.941473Z",
"methods": [
"password"
],
"project": {
"domain": {
"id": "default",
"name": "Default"
},
"id": "01257",
"name": "service"
},
"roles": [
{
"id": "9fe2ff9ee4384b1894a90878d3e92bab",
"name": "_member_"
},
{
"id": "53bff13443bd4450b97f978881d47b18",
"name": "admin"
}
],
"user": {
"domain": {
"id": "default",
"name": "Default"
},
"id": "f19ddbe2c53c46f189fe66d0a7a9c9ce",
"name": "nova"
},
"OS-TRUST:trust": {
"id": "abc123",
"trustee_user_id": "123456",
"trustor_user_id": "333333",
"impersonation": False
}
},
'token_version': 'v3.0'
}
class TestTokenProvider(test.TestCase):
def setUp(self):
@ -338,25 +644,21 @@ class TestTokenProvider(test.TestCase):
self.assertEqual(
token.provider.V2,
self.token_provider_api.get_token_version(SAMPLE_V2_TOKEN))
self.assertEqual(
token.provider.V2,
self.token_provider_api.get_token_version(
SAMPLE_V2_TOKEN_WITH_EMBEDED_VERSION))
self.assertEqual(
token.provider.V3,
self.token_provider_api.get_token_version(SAMPLE_V3_TOKEN))
self.assertEqual(
token.provider.V3,
self.token_provider_api.get_token_version(
SAMPLE_V3_TOKEN_WITH_EMBEDED_VERSION))
self.assertRaises(token.provider.UnsupportedTokenVersionException,
self.token_provider_api.get_token_version,
'bogus')
def test_issue_token(self):
self.assertRaises(token.provider.UnsupportedTokenVersionException,
self.token_provider_api.issue_token,
'bogus_version')
def test_validate_token(self):
self.assertRaises(token.provider.UnsupportedTokenVersionException,
self.token_provider_api.validate_token,
uuid.uuid4().hex,
None,
'bogus_version')
def test_token_format_provider_mismatch(self):
self.opt_in_group('signing', token_format='UUID')
self.opt_in_group('token',

View File

@ -9,7 +9,6 @@ from keystone import exception
from keystone.openstack.common import log as logging
from keystone.openstack.common import timeutils
from keystone.token import core
from keystone.token import provider as token_provider
CONF = config.CONF
@ -103,11 +102,8 @@ class Auth(controller.V2Controller):
role_ref = self.identity_api.get_role(role_id)
roles_ref.append(dict(name=role_ref['name']))
(token_id, token_data) = self.token_provider_api.issue_token(
version=token_provider.V2,
token_ref=auth_token_data,
roles_ref=roles_ref,
catalog_ref=catalog_ref)
(token_id, token_data) = self.token_provider_api.issue_v2_token(
auth_token_data, roles_ref=roles_ref, catalog_ref=catalog_ref)
return token_data
def _authenticate_token(self, context, auth):
@ -404,9 +400,7 @@ class Auth(controller.V2Controller):
"""
belongs_to = context['query_string'].get('belongsTo')
self.token_provider_api.check_token(token_id,
belongs_to=belongs_to,
version=token_provider.V2)
self.token_provider_api.check_v2_token(token_id, belongs_to)
@controller.protected
def validate_token(self, context, token_id):
@ -418,9 +412,7 @@ class Auth(controller.V2Controller):
"""
belongs_to = context['query_string'].get('belongsTo')
return self.token_provider_api.validate_token(
token_id, belongs_to=belongs_to,
version=token_provider.V2)
return self.token_provider_api.validate_v2_token(token_id, belongs_to)
def delete_token(self, context, token_id):
"""Delete a token, effectively invalidating it for authz."""

View File

@ -31,6 +31,7 @@ LOG = logging.getLogger(__name__)
# supported token versions
V2 = 'v2.0'
V3 = 'v3.0'
VERSIONS = frozenset([V2, V3])
# default token providers
PKI_PROVIDER = 'keystone.token.providers.pki.Provider'
@ -110,27 +111,41 @@ class Provider(object):
"""
raise exception.NotImplemented()
def issue_token(self, version='v3.0', **kwargs):
"""Issue a V3 token.
def issue_v2_token(self, token_ref, roles_ref=None, catalog_ref=None):
"""Issue a V2 token.
For V3 tokens, 'user_id', 'method_names', must present in kwargs.
Optionally, kwargs may contain 'expires_at' for rescope tokens;
'project_id' for project-scoped token; 'domain_id' for
domain-scoped token; and 'auth_context' from the authentication
plugins.
:param token_ref: token data to generate token from
:type token_ref: dict
:param roles_ref: optional roles list
:type roles_ref: dict
:param catalog_ref: optional catalog information
:type catalog_ref: dict
:return: (token_id, token_data)
"""
raise exception.NotImplemented()
For V2 tokens, 'token_ref' must be present in kwargs.
Optionally, kwargs may contain 'roles_ref' and 'catalog_ref'.
def issue_v3_token(self, user_id, method_names, expires_at=None,
project_id=None, domain_id=None, auth_context=None,
metadata_ref=None, include_catalog=True):
"""Issue a V3 Token.
:param context: request context
:type context: dictionary
:param version: version of the token to be issued
:type version: string
:param kwargs: information needed for token creation. Parameters
may be different depending on token version.
:type kwargs: dictionary
:param user_id: identity of the user
:type user_id: string
:param method_names: names of authentication methods
:type method_names: list
:param expires_at: optional time the token will expire
:type expires_at: string
:param project_id: optional project identity
:type project_id: string
:param domain_id: optional domain identity
:type domain_id: string
:param auth_context: optional context from the authorization plugins
:type auth_context: dict
:param metadata_ref: optional metadata reference
:type metadata_ref: dict
:param include_catalog: optional, include the catalog in token data
:type include_catalog: boolean
:returns: (token_id, token_data)
"""
raise exception.NotImplemented()
@ -143,35 +158,59 @@ class Provider(object):
"""
raise exception.NotImplemented()
def validate_token(self, token_id, belongs_to=None, version='v3.0'):
"""Validate the given token and return the token data.
def validate_v2_token(self, token_id, belongs_to=None):
"""Validate the given V2 token and return the token data.
Must raise Unauthorized exception if unable to validate token.
:param token_id: identity of the token
:type token_id: string
:param belongs_to: identity of the scoped project to validate
:param belongs_to: optional identity of the scoped project to validate
:type belongs_to: string
:param version: version of the token to be validated
:type version: string
:returns: token data
:raises: keystone.exception.Unauthorized
"""
raise exception.NotImplemented()
def check_token(self, token_id, belongs_to=None, version='v3.0'):
"""Check the validity of the given V3 token.
def validate_v3_token(self, token_id):
"""Validate the given V3 token and return the token_data.
Must raise Unauthorized exception if unable to check token.
:param token_id: identity of the token
:type token_id: string
:param belongs_to: project_id token belongs to
:type belongs_to: string
:returns: token data
:raises: keystone.exception.Unauthorized
"""
raise exception.NotImplemented()
def check_v2_token(self, token_id, belongs_to=None):
"""Check the validity of the given V2 token.
Must raise Unauthorized exception if unable to check token.
:param token_id: identity of the token
:type token_id: string
:param belongs_to: identity of the scoped project to validate
:type belongs_to: string
:param version: version of the token to check
:type version: string
:returns: None
:raises: keystone.exception.Unauthorized
"""
raise exception.NotImplemented()
def check_v3_token(self, token_id):
"""Check the validity of the given V3 token.
Must raise Unauthorized exception if unable to check token.
:param token_id: identity of the token
:type token_id: string
:param belongs_to: identity of the scoped project to validate
:type belongs_to: string
:returns: None
:raises: keystone.exception.Unauthorized
"""
raise exception.NotImplemented()

View File

@ -40,9 +40,11 @@ DEFAULT_DOMAIN_ID = CONF.identity.default_domain_id
class V2TokenDataHelper(object):
"""Creates V2 token data."""
@classmethod
def format_token(cls, token_ref, roles_ref, catalog_ref=None):
def format_token(cls, token_ref, roles_ref=None, catalog_ref=None):
user_ref = token_ref['user']
metadata_ref = token_ref['metadata']
if roles_ref is None:
roles_ref = []
expires = token_ref.get('expires', token.default_expire_time())
if expires is not None:
if not isinstance(expires, unicode):
@ -129,16 +131,6 @@ class V2TokenDataHelper(object):
return services.values()
@classmethod
def get_token_data(cls, **kwargs):
if 'token_ref' not in kwargs:
raise ValueError('Require token_ref to create V2 token data')
token_ref = kwargs.get('token_ref')
roles_ref = kwargs.get('roles_ref', [])
catalog_ref = kwargs.get('catalog_ref')
return V2TokenDataHelper.format_token(
token_ref, roles_ref, catalog_ref)
@dependency.requires('catalog_api', 'identity_api')
class V3TokenDataHelper(object):
@ -340,6 +332,13 @@ class Provider(token.provider.Provider):
def get_token_version(self, token_data):
if token_data and isinstance(token_data, dict):
if 'token_version' in token_data:
if token_data['token_version'] in token.provider.VERSIONS:
return token_data['token_version']
# FIXME(morganfainberg): deprecate the following logic in future
# revisions. It is better to just specify the token_version in
# the token_data itself. This way we can support future versions
# that might have the same fields.
if 'access' in token_data:
return token.provider.V2
if 'token' in token_data and 'methods' in token_data['token']:
@ -349,13 +348,14 @@ class Provider(token.provider.Provider):
def _get_token_id(self, token_data):
return uuid.uuid4().hex
def _issue_v2_token(self, **kwargs):
token_data = self.v2_token_data_helper.get_token_data(**kwargs)
def issue_v2_token(self, token_ref, roles_ref=None,
catalog_ref=None):
token_data = self.v2_token_data_helper.format_token(
token_ref, roles_ref, catalog_ref)
token_id = self._get_token_id(token_data)
token_data['access']['token']['id'] = token_id
try:
expiry = token_data['access']['token']['expires']
token_ref = kwargs.get('token_ref')
if isinstance(expiry, basestring):
expiry = timeutils.normalize_time(
timeutils.parse_isotime(expiry))
@ -367,7 +367,8 @@ class Provider(token.provider.Provider):
metadata=token_ref['metadata'],
token_data=token_data,
bind=token_ref.get('bind'),
trust_id=token_ref['metadata'].get('trust_id'))
trust_id=token_ref['metadata'].get('trust_id'),
token_version=token.provider.V2)
self.token_api.create_token(token_id, data)
except Exception:
exc_info = sys.exc_info()
@ -380,16 +381,9 @@ class Provider(token.provider.Provider):
return (token_id, token_data)
def _issue_v3_token(self, **kwargs):
user_id = kwargs.get('user_id')
method_names = kwargs.get('method_names')
expires_at = kwargs.get('expires_at')
project_id = kwargs.get('project_id')
domain_id = kwargs.get('domain_id')
auth_context = kwargs.get('auth_context')
trust = kwargs.get('trust')
metadata_ref = kwargs.get('metadata_ref')
include_catalog = kwargs.get('include_catalog')
def issue_v3_token(self, user_id, method_names, expires_at=None,
project_id=None, domain_id=None, auth_context=None,
trust=None, metadata_ref=None, include_catalog=True):
# for V2, trust is stashed in metadata_ref
if (CONF.trust.enabled and not trust and metadata_ref and
'trust_id' in metadata_ref):
@ -420,7 +414,8 @@ class Provider(token.provider.Provider):
timeutils.parse_isotime(expiry))
# FIXME(gyee): is there really a need to store roles in metadata?
role_ids = []
metadata_ref = kwargs.get('metadata_ref', {})
if metadata_ref is None:
metadata_ref = {}
if 'project' in token_data['token']:
# project-scoped token, fill in the v2 token data
# all we care are the role IDs
@ -437,7 +432,8 @@ class Provider(token.provider.Provider):
tenant=token_data['token'].get('project'),
metadata=metadata_ref,
token_data=token_data,
trust_id=trust['id'] if trust else None)
trust_id=trust['id'] if trust else None,
token_version=token.provider.V3)
self.token_api.create_token(token_id, data)
except Exception:
exc_info = sys.exc_info()
@ -450,20 +446,16 @@ class Provider(token.provider.Provider):
return (token_id, token_data)
def issue_token(self, version='v3.0', **kwargs):
if version == token.provider.V3:
return self._issue_v3_token(**kwargs)
elif version == token.provider.V2:
return self._issue_v2_token(**kwargs)
raise token.provider.UnsupportedTokenVersionException
def _verify_token(self, token_id, belongs_to=None):
"""Verify the given token and return the token_ref."""
token_ref = self.token_api.get_token(token_id)
assert token_ref
if not token_ref:
raise exception.ValidationError(_('Bad Token Reference'))
if belongs_to:
assert (token_ref['tenant'] and
token_ref['tenant']['id'] == belongs_to)
if not (token_ref['tenant'] and
token_ref['tenant']['id'] == belongs_to):
msg = _('id does not match belongs_to')
raise exception.ValidationError(msg)
return token_ref
def revoke_token(self, token_id):
@ -510,9 +502,9 @@ class Provider(token.provider.Provider):
if project_ref['domain_id'] != DEFAULT_DOMAIN_ID:
raise exception.Unauthorized(msg)
def _validate_v2_token(self, token_id, belongs_to=None, **kwargs):
def validate_v2_token(self, token_id, belongs_to=None):
try:
token_ref = self._verify_token(token_id, belongs_to=belongs_to)
token_ref = self._verify_token(token_id, belongs_to)
self._assert_default_domain(token_ref)
# FIXME(gyee): performance or correctness? Should we return the
# cached token or reconstruct it? Obviously if we are going with
@ -528,9 +520,9 @@ class Provider(token.provider.Provider):
token.provider.V2):
# token is created by old v2 logic
metadata_ref = token_ref['metadata']
role_refs = []
roles_ref = []
for role_id in metadata_ref.get('roles', []):
role_refs.append(self.identity_api.get_role(role_id))
roles_ref.append(self.identity_api.get_role(role_id))
# Get a service catalog if possible
# This is needed for on-behalf-of requests
@ -540,59 +532,54 @@ class Provider(token.provider.Provider):
token_ref['user']['id'],
token_ref['tenant']['id'],
metadata_ref)
token_data = self.v2_token_data_helper.get_token_data(
token_ref=token_ref,
roles_ref=role_refs,
catalog_ref=catalog_ref)
token_data = self.v2_token_data_helper.format_token(
token_ref, roles_ref, catalog_ref)
return token_data
except AssertionError as e:
except (exception.ValidationError, exception.TokenNotFound) as e:
LOG.exception(_('Failed to validate token'))
raise exception.Unauthorized(e)
def _validate_v3_token(self, token_id):
token_ref = self._verify_token(token_id)
# FIXME(gyee): performance or correctness? Should we return the
# cached token or reconstruct it? Obviously if we are going with
# the cached token, any role, project, or domain name changes
# will not be reflected. One may argue that with PKI tokens,
# we are essentially doing cached token validation anyway.
# Lets go with the cached token strategy. Since token
# management layer is now pluggable, one can always provide
# their own implementation to suit their needs.
token_data = token_ref.get('token_data')
if not token_data or 'token' not in token_data:
# token ref is created by V2 API
project_id = None
project_ref = token_ref.get('tenant')
if project_ref:
project_id = project_ref['id']
token_data = self.v3_token_data_helper.get_token_data(
token_ref['user']['id'],
['password', 'token'],
{},
project_id=project_id,
bind=token_ref.get('bind'),
expires=token_ref['expires'])
return token_data
def validate_token(self, token_id, belongs_to=None, version='v3.0'):
def validate_v3_token(self, token_id):
try:
if version == token.provider.V3:
return self._validate_v3_token(token_id)
elif version == token.provider.V2:
return self._validate_v2_token(token_id,
belongs_to=belongs_to)
raise token.provider.UnsupportedTokenVersionException()
except exception.TokenNotFound as e:
LOG.exception(_('Failed to verify token'))
token_ref = self._verify_token(token_id)
# FIXME(gyee): performance or correctness? Should we return the
# cached token or reconstruct it? Obviously if we are going with
# the cached token, any role, project, or domain name changes
# will not be reflected. One may argue that with PKI tokens,
# we are essentially doing cached token validation anyway.
# Lets go with the cached token strategy. Since token
# management layer is now pluggable, one can always provide
# their own implementation to suit their needs.
token_data = token_ref.get('token_data')
if not token_data or 'token' not in token_data:
# token ref is created by V2 API
project_id = None
project_ref = token_ref.get('tenant')
if project_ref:
project_id = project_ref['id']
token_data = self.v3_token_data_helper.get_token_data(
token_ref['user']['id'],
['password', 'token'],
{},
project_id=project_id,
bind=token_ref.get('bind'),
expires=token_ref['expires'])
return token_data
except (exception.ValidationError, exception.TokenNotFound) as e:
LOG.exception(_('Failed to validate token'))
raise exception.Unauthorized(e)
def check_token(self, token_id, belongs_to=None,
version='v3.0', **kwargs):
def check_v2_token(self, token_id, belongs_to=None):
try:
token_ref = self._verify_token(token_id, belongs_to=belongs_to)
if version == token.provider.V2:
self._assert_default_domain(token_ref)
except exception.TokenNotFound as e:
self._assert_default_domain(token_ref)
except (exception.TokenNotFound, exception.ValidationError) as e:
LOG.exception(_('Failed to verify token'))
raise exception.Unauthorized(e)
def check_v3_token(self, token_id):
try:
self._verify_token(token_id)
except (exception.TokenNotFound, exception.ValidationError) as e:
LOG.exception(_('Failed to verify token'))
raise exception.Unauthorized(e)