aboutsummaryrefslogtreecommitdiffstats
path: root/keystone-moon/keystone/models
diff options
context:
space:
mode:
Diffstat (limited to 'keystone-moon/keystone/models')
-rw-r--r--keystone-moon/keystone/models/__init__.py0
-rw-r--r--keystone-moon/keystone/models/revoke_model.py373
-rw-r--r--keystone-moon/keystone/models/token_model.py339
3 files changed, 0 insertions, 712 deletions
diff --git a/keystone-moon/keystone/models/__init__.py b/keystone-moon/keystone/models/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/keystone-moon/keystone/models/__init__.py
+++ /dev/null
diff --git a/keystone-moon/keystone/models/revoke_model.py b/keystone-moon/keystone/models/revoke_model.py
deleted file mode 100644
index 0fc3e628..00000000
--- a/keystone-moon/keystone/models/revoke_model.py
+++ /dev/null
@@ -1,373 +0,0 @@
-# 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_utils import timeutils
-from six.moves import map
-
-from keystone.common import utils
-
-
-# The set of attributes common between the RevokeEvent
-# and the dictionaries created from the token Data.
-_NAMES = ['trust_id',
- 'consumer_id',
- 'access_token_id',
- 'audit_id',
- 'audit_chain_id',
- 'expires_at',
- 'domain_id',
- 'project_id',
- 'user_id',
- 'role_id']
-
-
-# Additional arguments for creating a RevokeEvent
-_EVENT_ARGS = ['issued_before', 'revoked_at']
-
-# Names of attributes in the RevocationEvent, including "virtual" attributes.
-# Virtual attributes are those added based on other values.
-_EVENT_NAMES = _NAMES + ['domain_scope_id']
-
-# Values that will be in the token data but not in the event.
-# These will compared with event values that have different names.
-# For example: both trustor_id and trustee_id are compared against user_id
-_TOKEN_KEYS = ['identity_domain_id',
- 'assignment_domain_id',
- 'issued_at',
- 'trustor_id',
- 'trustee_id']
-
-# Alternative names to be checked in token for every field in
-# revoke tree.
-ALTERNATIVES = {
- 'user_id': ['user_id', 'trustor_id', 'trustee_id'],
- 'domain_id': ['identity_domain_id', 'assignment_domain_id'],
- # For a domain-scoped token, the domain is in assignment_domain_id.
- 'domain_scope_id': ['assignment_domain_id', ],
-}
-
-
-REVOKE_KEYS = _NAMES + _EVENT_ARGS
-
-
-def blank_token_data(issued_at):
- token_data = dict()
- for name in _NAMES:
- token_data[name] = None
- for name in _TOKEN_KEYS:
- token_data[name] = None
- # required field
- token_data['issued_at'] = issued_at
- return token_data
-
-
-class RevokeEvent(object):
- def __init__(self, **kwargs):
- for k in REVOKE_KEYS:
- v = kwargs.get(k)
- setattr(self, k, v)
-
- if self.domain_id and self.expires_at:
- # This is revoking a domain-scoped token.
- self.domain_scope_id = self.domain_id
- self.domain_id = None
- else:
- # This is revoking all tokens for a domain.
- self.domain_scope_id = None
-
- if self.expires_at is not None:
- # Trim off the expiration time because MySQL timestamps are only
- # accurate to the second.
- self.expires_at = self.expires_at.replace(microsecond=0)
-
- if self.revoked_at is None:
- self.revoked_at = timeutils.utcnow()
- if self.issued_before is None:
- self.issued_before = self.revoked_at
-
- def to_dict(self):
- keys = ['user_id',
- 'role_id',
- 'domain_id',
- 'domain_scope_id',
- 'project_id',
- 'audit_id',
- 'audit_chain_id',
- ]
- event = {key: self.__dict__[key] for key in keys
- if self.__dict__[key] is not None}
- if self.trust_id is not None:
- event['OS-TRUST:trust_id'] = self.trust_id
- if self.consumer_id is not None:
- event['OS-OAUTH1:consumer_id'] = self.consumer_id
- if self.consumer_id is not None:
- event['OS-OAUTH1:access_token_id'] = self.access_token_id
- if self.expires_at is not None:
- event['expires_at'] = utils.isotime(self.expires_at)
- if self.issued_before is not None:
- event['issued_before'] = utils.isotime(self.issued_before,
- subsecond=True)
- return event
-
- def key_for_name(self, name):
- return "%s=%s" % (name, getattr(self, name) or '*')
-
-
-def attr_keys(event):
- return list(map(event.key_for_name, _EVENT_NAMES))
-
-
-class RevokeTree(object):
- """Fast Revocation Checking Tree Structure
-
- The Tree is an index to quickly match tokens against events.
- Each node is a hashtable of key=value combinations from revocation events.
- The
-
- """
-
- def __init__(self, revoke_events=None):
- self.revoke_map = dict()
- self.add_events(revoke_events)
-
- def add_event(self, event):
- """Updates the tree based on a revocation event.
-
- Creates any necessary internal nodes in the tree corresponding to the
- fields of the revocation event. The leaf node will always be set to
- the latest 'issued_before' for events that are otherwise identical.
-
- :param: Event to add to the tree
-
- :returns: the event that was passed in.
-
- """
- revoke_map = self.revoke_map
- for key in attr_keys(event):
- revoke_map = revoke_map.setdefault(key, {})
- revoke_map['issued_before'] = max(
- event.issued_before, revoke_map.get(
- 'issued_before', event.issued_before))
- return event
-
- def remove_event(self, event):
- """Update the tree based on the removal of a Revocation Event
-
- Removes empty nodes from the tree from the leaf back to the root.
-
- If multiple events trace the same path, but have different
- 'issued_before' values, only the last is ever stored in the tree.
- So only an exact match on 'issued_before' ever triggers a removal
-
- :param: Event to remove from the tree
-
- """
- stack = []
- revoke_map = self.revoke_map
- for name in _EVENT_NAMES:
- key = event.key_for_name(name)
- nxt = revoke_map.get(key)
- if nxt is None:
- break
- stack.append((revoke_map, key, nxt))
- revoke_map = nxt
- else:
- if event.issued_before == revoke_map['issued_before']:
- revoke_map.pop('issued_before')
- for parent, key, child in reversed(stack):
- if not any(child):
- del parent[key]
-
- def add_events(self, revoke_events):
- return list(map(self.add_event, revoke_events or []))
-
- @staticmethod
- def _next_level_keys(name, token_data):
- """Generate keys based on current field name and token data
-
- Generate all keys to look for in the next iteration of revocation
- event tree traversal.
- """
- yield '*'
- if name == 'role_id':
- # Roles are very special since a token has a list of them.
- # If the revocation event matches any one of them,
- # revoke the token.
- for role_id in token_data.get('roles', []):
- yield role_id
- else:
- # For other fields we try to get any branch that concur
- # with any alternative field in the token.
- for alt_name in ALTERNATIVES.get(name, [name]):
- yield token_data[alt_name]
-
- def _search(self, revoke_map, names, token_data):
- """Search for revocation event by token_data
-
- Traverse the revocation events tree looking for event matching token
- data issued after the token.
- """
- if not names:
- # The last (leaf) level is checked in a special way because we
- # verify issued_at field differently.
- try:
- return revoke_map['issued_before'] >= token_data['issued_at']
- except KeyError:
- return False
-
- name, remaining_names = names[0], names[1:]
-
- for key in self._next_level_keys(name, token_data):
- subtree = revoke_map.get('%s=%s' % (name, key))
- if subtree and self._search(subtree, remaining_names, token_data):
- return True
-
- # If we made it out of the loop then no element in revocation tree
- # corresponds to our token and it is good.
- return False
-
- def is_revoked(self, token_data):
- """Check if a token matches the revocation event
-
- Compare the values for each level of the tree with the values from
- the token, accounting for attributes that have alternative
- keys, and for wildcard matches.
- if there is a match, continue down the tree.
- if there is no match, exit early.
-
- token_data is a map based on a flattened view of token.
- The required fields are:
-
- 'expires_at','user_id', 'project_id', 'identity_domain_id',
- 'assignment_domain_id', 'trust_id', 'trustor_id', 'trustee_id'
- 'consumer_id', 'access_token_id'
-
- """
- return self._search(self.revoke_map, _EVENT_NAMES, token_data)
-
-
-def build_token_values_v2(access, default_domain_id):
- token_data = access['token']
-
- token_expires_at = timeutils.parse_isotime(token_data['expires'])
-
- # Trim off the microseconds because the revocation event only has
- # expirations accurate to the second.
- token_expires_at = token_expires_at.replace(microsecond=0)
-
- token_values = {
- 'expires_at': timeutils.normalize_time(token_expires_at),
- 'issued_at': timeutils.normalize_time(
- timeutils.parse_isotime(token_data['issued_at'])),
- 'audit_id': token_data.get('audit_ids', [None])[0],
- 'audit_chain_id': token_data.get('audit_ids', [None])[-1],
- }
-
- token_values['user_id'] = access.get('user', {}).get('id')
-
- project = token_data.get('tenant')
- if project is not None:
- token_values['project_id'] = project['id']
- else:
- token_values['project_id'] = None
-
- token_values['identity_domain_id'] = default_domain_id
- token_values['assignment_domain_id'] = default_domain_id
-
- trust = token_data.get('trust')
- if trust is None:
- token_values['trust_id'] = None
- token_values['trustor_id'] = None
- token_values['trustee_id'] = None
- else:
- token_values['trust_id'] = trust['id']
- token_values['trustor_id'] = trust['trustor_id']
- token_values['trustee_id'] = trust['trustee_id']
-
- token_values['consumer_id'] = None
- token_values['access_token_id'] = None
-
- role_list = []
- # Roles are by ID in metadata and by name in the user section
- roles = access.get('metadata', {}).get('roles', [])
- for role in roles:
- role_list.append(role)
- token_values['roles'] = role_list
- return token_values
-
-
-def build_token_values(token_data):
-
- token_expires_at = timeutils.parse_isotime(token_data['expires_at'])
-
- # Trim off the microseconds because the revocation event only has
- # expirations accurate to the second.
- token_expires_at = token_expires_at.replace(microsecond=0)
-
- token_values = {
- 'expires_at': timeutils.normalize_time(token_expires_at),
- 'issued_at': timeutils.normalize_time(
- timeutils.parse_isotime(token_data['issued_at'])),
- 'audit_id': token_data.get('audit_ids', [None])[0],
- 'audit_chain_id': token_data.get('audit_ids', [None])[-1],
- }
-
- user = token_data.get('user')
- if user is not None:
- token_values['user_id'] = user['id']
- # Federated users do not have a domain, be defensive and get the user
- # domain set to None in the federated user case.
- token_values['identity_domain_id'] = user.get('domain', {}).get('id')
- else:
- token_values['user_id'] = None
- token_values['identity_domain_id'] = None
-
- project = token_data.get('project', token_data.get('tenant'))
- if project is not None:
- token_values['project_id'] = project['id']
- # The domain_id of projects acting as domains is None
- token_values['assignment_domain_id'] = (
- project['domain']['id'] if project['domain'] else None)
- else:
- token_values['project_id'] = None
-
- domain = token_data.get('domain')
- if domain is not None:
- token_values['assignment_domain_id'] = domain['id']
- else:
- token_values['assignment_domain_id'] = None
-
- role_list = []
- roles = token_data.get('roles')
- if roles is not None:
- for role in roles:
- role_list.append(role['id'])
- token_values['roles'] = role_list
-
- trust = token_data.get('OS-TRUST:trust')
- if trust is None:
- token_values['trust_id'] = None
- token_values['trustor_id'] = None
- token_values['trustee_id'] = None
- else:
- token_values['trust_id'] = trust['id']
- token_values['trustor_id'] = trust['trustor_user']['id']
- token_values['trustee_id'] = trust['trustee_user']['id']
-
- oauth1 = token_data.get('OS-OAUTH1')
- if oauth1 is None:
- token_values['consumer_id'] = None
- token_values['access_token_id'] = None
- else:
- token_values['consumer_id'] = oauth1['consumer_id']
- token_values['access_token_id'] = oauth1['access_token_id']
- return token_values
diff --git a/keystone-moon/keystone/models/token_model.py b/keystone-moon/keystone/models/token_model.py
deleted file mode 100644
index 32e6b365..00000000
--- a/keystone-moon/keystone/models/token_model.py
+++ /dev/null
@@ -1,339 +0,0 @@
-# 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.
-
-"""Unified in-memory token model."""
-
-from keystoneclient.common import cms
-from oslo_config import cfg
-from oslo_utils import reflection
-from oslo_utils import timeutils
-import six
-
-from keystone import exception
-from keystone.federation import constants
-from keystone.i18n import _
-
-CONF = cfg.CONF
-# supported token versions
-V2 = 'v2.0'
-V3 = 'v3.0'
-VERSIONS = frozenset([V2, V3])
-
-
-def _parse_and_normalize_time(time_data):
- if isinstance(time_data, six.string_types):
- time_data = timeutils.parse_isotime(time_data)
- return timeutils.normalize_time(time_data)
-
-
-class KeystoneToken(dict):
- """An in-memory representation that unifies v2 and v3 tokens."""
-
- # TODO(morganfainberg): Align this in-memory representation with the
- # objects in keystoneclient. This object should be eventually updated
- # to be the source of token data with the ability to emit any version
- # of the token instead of only consuming the token dict and providing
- # property accessors for the underlying data.
-
- def __init__(self, token_id, token_data):
- self.token_data = token_data
- if 'access' in token_data:
- super(KeystoneToken, self).__init__(**token_data['access'])
- self.version = V2
- elif 'token' in token_data and 'methods' in token_data['token']:
- super(KeystoneToken, self).__init__(**token_data['token'])
- self.version = V3
- else:
- raise exception.UnsupportedTokenVersionException()
- self.token_id = token_id
- self.short_id = cms.cms_hash_token(token_id,
- mode=CONF.token.hash_algorithm)
-
- if self.project_scoped and self.domain_scoped:
- raise exception.UnexpectedError(_('Found invalid token: scoped to '
- 'both project and domain.'))
-
- def __repr__(self):
- desc = ('<%(type)s (audit_id=%(audit_id)s, '
- 'audit_chain_id=%(audit_chain_id)s) at %(loc)s>')
- self_cls_name = reflection.get_class_name(self,
- fully_qualified=False)
- return desc % {'type': self_cls_name,
- 'audit_id': self.audit_id,
- 'audit_chain_id': self.audit_chain_id,
- 'loc': hex(id(self))}
-
- @property
- def expires(self):
- if self.version is V3:
- expires_at = self['expires_at']
- else:
- expires_at = self['token']['expires']
- return _parse_and_normalize_time(expires_at)
-
- @property
- def issued(self):
- if self.version is V3:
- issued_at = self['issued_at']
- else:
- issued_at = self['token']['issued_at']
- return _parse_and_normalize_time(issued_at)
-
- @property
- def audit_id(self):
- if self.version is V3:
- return self.get('audit_ids', [None])[0]
- return self['token'].get('audit_ids', [None])[0]
-
- @property
- def audit_chain_id(self):
- if self.version is V3:
- return self.get('audit_ids', [None])[-1]
- return self['token'].get('audit_ids', [None])[-1]
-
- @property
- def auth_token(self):
- return self.token_id
-
- @property
- def user_id(self):
- return self['user']['id']
-
- @property
- def user_name(self):
- return self['user']['name']
-
- @property
- def user_domain_name(self):
- try:
- if self.version == V3:
- return self['user']['domain']['name']
- elif 'user' in self:
- return "Default"
- except KeyError: # nosec
- # Do not raise KeyError, raise UnexpectedError
- pass
- raise exception.UnexpectedError()
-
- @property
- def user_domain_id(self):
- try:
- if self.version == V3:
- return self['user']['domain']['id']
- elif 'user' in self:
- return CONF.identity.default_domain_id
- except KeyError: # nosec
- # Do not raise KeyError, raise UnexpectedError
- pass
- raise exception.UnexpectedError()
-
- @property
- def domain_id(self):
- if self.version is V3:
- try:
- return self['domain']['id']
- except KeyError:
- # Do not raise KeyError, raise UnexpectedError
- raise exception.UnexpectedError()
- # No domain scoped tokens in V2.
- raise NotImplementedError()
-
- @property
- def domain_name(self):
- if self.version is V3:
- try:
- return self['domain']['name']
- except KeyError:
- # Do not raise KeyError, raise UnexpectedError
- raise exception.UnexpectedError()
- # No domain scoped tokens in V2.
- raise NotImplementedError()
-
- @property
- def project_id(self):
- try:
- if self.version is V3:
- return self['project']['id']
- else:
- return self['token']['tenant']['id']
- except KeyError:
- # Do not raise KeyError, raise UnexpectedError
- raise exception.UnexpectedError()
-
- @property
- def project_name(self):
- try:
- if self.version is V3:
- return self['project']['name']
- else:
- return self['token']['tenant']['name']
- except KeyError:
- # Do not raise KeyError, raise UnexpectedError
- raise exception.UnexpectedError()
-
- @property
- def project_domain_id(self):
- try:
- if self.version is V3:
- return self['project']['domain']['id']
- elif 'tenant' in self['token']:
- return CONF.identity.default_domain_id
- except KeyError: # nosec
- # Do not raise KeyError, raise UnexpectedError
- pass
-
- raise exception.UnexpectedError()
-
- @property
- def project_domain_name(self):
- try:
- if self.version is V3:
- return self['project']['domain']['name']
- if 'tenant' in self['token']:
- return 'Default'
- except KeyError: # nosec
- # Do not raise KeyError, raise UnexpectedError
- pass
-
- raise exception.UnexpectedError()
-
- @property
- def project_scoped(self):
- if self.version is V3:
- return 'project' in self
- else:
- return 'tenant' in self['token']
-
- @property
- def domain_scoped(self):
- if self.version is V3:
- return 'domain' in self
- return False
-
- @property
- def scoped(self):
- return self.project_scoped or self.domain_scoped
-
- @property
- def trust_id(self):
- if self.version is V3:
- return self.get('OS-TRUST:trust', {}).get('id')
- else:
- return self.get('trust', {}).get('id')
-
- @property
- def trust_scoped(self):
- if self.version is V3:
- return 'OS-TRUST:trust' in self
- else:
- return 'trust' in self
-
- @property
- def trustee_user_id(self):
- if self.version is V3:
- return self.get(
- 'OS-TRUST:trust', {}).get('trustee_user_id')
- else:
- return self.get('trust', {}).get('trustee_user_id')
-
- @property
- def trustor_user_id(self):
- if self.version is V3:
- return self.get(
- 'OS-TRUST:trust', {}).get('trustor_user_id')
- else:
- return self.get('trust', {}).get('trustor_user_id')
-
- @property
- def trust_impersonation(self):
- if self.version is V3:
- return self.get('OS-TRUST:trust', {}).get('impersonation')
- else:
- return self.get('trust', {}).get('impersonation')
-
- @property
- def oauth_scoped(self):
- return 'OS-OAUTH1' in self
-
- @property
- def oauth_access_token_id(self):
- if self.version is V3 and self.oauth_scoped:
- return self['OS-OAUTH1']['access_token_id']
- return None
-
- @property
- def oauth_consumer_id(self):
- if self.version is V3 and self.oauth_scoped:
- return self['OS-OAUTH1']['consumer_id']
- return None
-
- @property
- def role_ids(self):
- if self.version is V3:
- return [r['id'] for r in self.get('roles', [])]
- else:
- return self.get('metadata', {}).get('roles', [])
-
- @property
- def role_names(self):
- if self.version is V3:
- return [r['name'] for r in self.get('roles', [])]
- else:
- return [r['name'] for r in self['user'].get('roles', [])]
-
- @property
- def bind(self):
- if self.version is V3:
- return self.get('bind')
- return self.get('token', {}).get('bind')
-
- @property
- def is_federated_user(self):
- try:
- return (self.version is V3 and
- constants.FEDERATION in self['user'])
- except KeyError:
- raise exception.UnexpectedError()
-
- @property
- def federation_group_ids(self):
- if self.is_federated_user:
- if self.version is V3:
- try:
- groups = self['user'][constants.FEDERATION].get(
- 'groups', [])
- return [g['id'] for g in groups]
- except KeyError:
- raise exception.UnexpectedError()
- return []
-
- @property
- def federation_idp_id(self):
- if self.version is not V3 or not self.is_federated_user:
- return None
- return self['user'][constants.FEDERATION]['identity_provider']['id']
-
- @property
- def federation_protocol_id(self):
- if self.version is V3 and self.is_federated_user:
- return self['user'][constants.FEDERATION]['protocol']['id']
- return None
-
- @property
- def metadata(self):
- return self.get('metadata', {})
-
- @property
- def methods(self):
- if self.version is V3:
- return self.get('methods', [])
- return []