aboutsummaryrefslogtreecommitdiffstats
path: root/keystone-moon/keystone/token/providers/fernet/core.py
diff options
context:
space:
mode:
Diffstat (limited to 'keystone-moon/keystone/token/providers/fernet/core.py')
-rw-r--r--keystone-moon/keystone/token/providers/fernet/core.py267
1 files changed, 267 insertions, 0 deletions
diff --git a/keystone-moon/keystone/token/providers/fernet/core.py b/keystone-moon/keystone/token/providers/fernet/core.py
new file mode 100644
index 00000000..b1da263b
--- /dev/null
+++ b/keystone-moon/keystone/token/providers/fernet/core.py
@@ -0,0 +1,267 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from oslo_config import cfg
+from oslo_log import log
+
+from keystone.common import dependency
+from keystone.contrib import federation
+from keystone import exception
+from keystone.i18n import _
+from keystone.token import provider
+from keystone.token.providers import common
+from keystone.token.providers.fernet import token_formatters as tf
+
+
+CONF = cfg.CONF
+LOG = log.getLogger(__name__)
+
+
+@dependency.requires('trust_api')
+class Provider(common.BaseProvider):
+ def __init__(self, *args, **kwargs):
+ super(Provider, self).__init__(*args, **kwargs)
+
+ self.token_formatter = tf.TokenFormatter()
+
+ def needs_persistence(self):
+ """Should the token be written to a backend."""
+ return False
+
+ def issue_v2_token(self, token_ref, roles_ref=None, catalog_ref=None):
+ """Issue a V2 formatted token.
+
+ :param token_ref: reference describing the token
+ :param roles_ref: reference describing the roles for the token
+ :param catalog_ref: reference describing the token's catalog
+ :returns: tuple containing the ID of the token and the token data
+
+ """
+ # TODO(lbragstad): Currently, Fernet tokens don't support bind in the
+ # token format. Raise a 501 if we're dealing with bind.
+ if token_ref.get('bind'):
+ raise exception.NotImplemented()
+
+ user_id = token_ref['user']['id']
+ # Default to password since methods not provided by token_ref
+ method_names = ['password']
+ project_id = None
+ # Verify that tenant is not None in token_ref
+ if token_ref.get('tenant'):
+ project_id = token_ref['tenant']['id']
+
+ parent_audit_id = token_ref.get('parent_audit_id')
+ # If parent_audit_id is defined then a token authentication was made
+ if parent_audit_id:
+ method_names.append('token')
+
+ audit_ids = provider.audit_info(parent_audit_id)
+
+ # Get v3 token data and exclude building v3 specific catalog. This is
+ # due to the fact that the V2TokenDataHelper.format_token() method
+ # doesn't build any of the token_reference from other Keystone APIs.
+ # Instead, it builds it from what is persisted in the token reference.
+ # Here we are going to leverage the V3TokenDataHelper.get_token_data()
+ # method written for V3 because it goes through and populates the token
+ # reference dynamically. Once we have a V3 token reference, we can
+ # attempt to convert it to a V2 token response.
+ v3_token_data = self.v3_token_data_helper.get_token_data(
+ user_id,
+ method_names,
+ project_id=project_id,
+ token=token_ref,
+ include_catalog=False,
+ audit_info=audit_ids)
+
+ expires_at = v3_token_data['token']['expires_at']
+ token_id = self.token_formatter.create_token(user_id, expires_at,
+ audit_ids,
+ methods=method_names,
+ project_id=project_id)
+ # Convert v3 to v2 token data and build v2 catalog
+ token_data = self.v2_token_data_helper.v3_to_v2_token(token_id,
+ v3_token_data)
+
+ return token_id, token_data
+
+ def _build_federated_info(self, token_data):
+ """Extract everything needed for federated tokens.
+
+ This dictionary is passed to the FederatedPayload token formatter,
+ which unpacks the values and builds the Fernet token.
+
+ """
+ group_ids = token_data.get('user', {}).get(
+ federation.FEDERATION, {}).get('groups')
+ idp_id = token_data.get('user', {}).get(
+ federation.FEDERATION, {}).get('identity_provider', {}).get('id')
+ protocol_id = token_data.get('user', {}).get(
+ federation.FEDERATION, {}).get('protocol', {}).get('id')
+ if not group_ids:
+ group_ids = list()
+ federated_dict = dict(group_ids=group_ids, idp_id=idp_id,
+ protocol_id=protocol_id)
+ return federated_dict
+
+ def _rebuild_federated_info(self, federated_dict, user_id):
+ """Format federated information into the token reference.
+
+ The federated_dict is passed back from the FederatedPayload token
+ formatter. The responsibility of this method is to format the
+ information passed back from the token formatter into the token
+ reference before constructing the token data from the
+ V3TokenDataHelper.
+
+ """
+ g_ids = federated_dict['group_ids']
+ idp_id = federated_dict['idp_id']
+ protocol_id = federated_dict['protocol_id']
+ federated_info = dict(groups=g_ids,
+ identity_provider=dict(id=idp_id),
+ protocol=dict(id=protocol_id))
+ token_dict = {'user': {federation.FEDERATION: federated_info}}
+ token_dict['user']['id'] = user_id
+ token_dict['user']['name'] = user_id
+ return token_dict
+
+ 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,
+ parent_audit_id=None):
+ """Issue a V3 formatted token.
+
+ Here is where we need to detect what is given to us, and what kind of
+ token the user is expecting. Depending on the outcome of that, we can
+ pass all the information to be packed to the proper token format
+ handler.
+
+ :param user_id: ID of the user
+ :param method_names: method of authentication
+ :param expires_at: token expiration time
+ :param project_id: ID of the project being scoped to
+ :param domain_id: ID of the domain being scoped to
+ :param auth_context: authentication context
+ :param trust: ID of the trust
+ :param metadata_ref: metadata reference
+ :param include_catalog: return the catalog in the response if True,
+ otherwise don't return the catalog
+ :param parent_audit_id: ID of the patent audit entity
+ :returns: tuple containing the id of the token and the token data
+
+ """
+ # TODO(lbragstad): Currently, Fernet tokens don't support bind in the
+ # token format. Raise a 501 if we're dealing with bind.
+ if auth_context.get('bind'):
+ raise exception.NotImplemented()
+
+ token_ref = None
+ # NOTE(lbragstad): This determines if we are dealing with a federated
+ # token or not. The groups for the user will be in the returned token
+ # reference.
+ federated_dict = None
+ if auth_context and self._is_mapped_token(auth_context):
+ token_ref = self._handle_mapped_tokens(
+ auth_context, project_id, domain_id)
+ federated_dict = self._build_federated_info(token_ref)
+
+ token_data = self.v3_token_data_helper.get_token_data(
+ user_id,
+ method_names,
+ auth_context.get('extras') if auth_context else None,
+ domain_id=domain_id,
+ project_id=project_id,
+ expires=expires_at,
+ trust=trust,
+ bind=auth_context.get('bind') if auth_context else None,
+ token=token_ref,
+ include_catalog=include_catalog,
+ audit_info=parent_audit_id)
+
+ token = self.token_formatter.create_token(
+ user_id,
+ token_data['token']['expires_at'],
+ token_data['token']['audit_ids'],
+ methods=method_names,
+ domain_id=domain_id,
+ project_id=project_id,
+ trust_id=token_data['token'].get('OS-TRUST:trust', {}).get('id'),
+ federated_info=federated_dict)
+ return token, token_data
+
+ def validate_v2_token(self, token_ref):
+ """Validate a V2 formatted token.
+
+ :param token_ref: reference describing the token to validate
+ :returns: the token data
+ :raises keystone.exception.Unauthorized: if v3 token is used
+
+ """
+ (user_id, methods,
+ audit_ids, domain_id,
+ project_id, trust_id,
+ federated_info, created_at,
+ expires_at) = self.token_formatter.validate_token(token_ref)
+
+ if trust_id or domain_id or federated_info:
+ msg = _('This is not a v2.0 Fernet token. Use v3 for trust, '
+ 'domain, or federated tokens.')
+ raise exception.Unauthorized(msg)
+
+ v3_token_data = self.v3_token_data_helper.get_token_data(
+ user_id,
+ methods,
+ project_id=project_id,
+ expires=expires_at,
+ issued_at=created_at,
+ token=token_ref,
+ include_catalog=False,
+ audit_info=audit_ids)
+ return self.v2_token_data_helper.v3_to_v2_token(token_ref,
+ v3_token_data)
+
+ def validate_v3_token(self, token):
+ """Validate a V3 formatted token.
+
+ :param token: a string describing the token to validate
+ :returns: the token data
+ :raises keystone.exception.Unauthorized: if token format version isn't
+ supported
+
+ """
+ (user_id, methods, audit_ids, domain_id, project_id, trust_id,
+ federated_info, created_at, expires_at) = (
+ self.token_formatter.validate_token(token))
+
+ token_dict = None
+ if federated_info:
+ token_dict = self._rebuild_federated_info(federated_info, user_id)
+ trust_ref = self.trust_api.get_trust(trust_id)
+
+ return self.v3_token_data_helper.get_token_data(
+ user_id,
+ method_names=methods,
+ domain_id=domain_id,
+ project_id=project_id,
+ issued_at=created_at,
+ expires=expires_at,
+ trust=trust_ref,
+ token=token_dict,
+ audit_info=audit_ids)
+
+ def _get_token_id(self, token_data):
+ """Generate the token_id based upon the data in token_data.
+
+ :param token_data: token information
+ :type token_data: dict
+ :raises keystone.exception.NotImplemented: when called
+ """
+ raise exception.NotImplemented()