aboutsummaryrefslogtreecommitdiffstats
path: root/keystone-moon/keystone/contrib/revoke
diff options
context:
space:
mode:
Diffstat (limited to 'keystone-moon/keystone/contrib/revoke')
-rw-r--r--keystone-moon/keystone/contrib/revoke/__init__.py0
-rw-r--r--keystone-moon/keystone/contrib/revoke/backends/__init__.py0
-rw-r--r--keystone-moon/keystone/contrib/revoke/backends/kvs.py74
-rw-r--r--keystone-moon/keystone/contrib/revoke/backends/sql.py28
-rw-r--r--keystone-moon/keystone/contrib/revoke/controllers.py44
-rw-r--r--keystone-moon/keystone/contrib/revoke/core.py262
-rw-r--r--keystone-moon/keystone/contrib/revoke/migrate_repo/__init__.py0
-rw-r--r--keystone-moon/keystone/contrib/revoke/migrate_repo/migrate.cfg25
-rw-r--r--keystone-moon/keystone/contrib/revoke/migrate_repo/versions/001_revoke_table.py17
-rw-r--r--keystone-moon/keystone/contrib/revoke/migrate_repo/versions/002_add_audit_id_and_chain_to_revoke_table.py17
-rw-r--r--keystone-moon/keystone/contrib/revoke/migrate_repo/versions/__init__.py0
-rw-r--r--keystone-moon/keystone/contrib/revoke/model.py371
-rw-r--r--keystone-moon/keystone/contrib/revoke/routers.py31
13 files changed, 0 insertions, 869 deletions
diff --git a/keystone-moon/keystone/contrib/revoke/__init__.py b/keystone-moon/keystone/contrib/revoke/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/keystone-moon/keystone/contrib/revoke/__init__.py
+++ /dev/null
diff --git a/keystone-moon/keystone/contrib/revoke/backends/__init__.py b/keystone-moon/keystone/contrib/revoke/backends/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/keystone-moon/keystone/contrib/revoke/backends/__init__.py
+++ /dev/null
diff --git a/keystone-moon/keystone/contrib/revoke/backends/kvs.py b/keystone-moon/keystone/contrib/revoke/backends/kvs.py
deleted file mode 100644
index 086becb0..00000000
--- a/keystone-moon/keystone/contrib/revoke/backends/kvs.py
+++ /dev/null
@@ -1,74 +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.
-
-import datetime
-
-from oslo_config import cfg
-from oslo_log import versionutils
-from oslo_utils import timeutils
-
-from keystone.common import kvs
-from keystone.contrib import revoke
-from keystone import exception
-
-
-CONF = cfg.CONF
-
-_EVENT_KEY = 'os-revoke-events'
-_KVS_BACKEND = 'openstack.kvs.Memory'
-
-
-class Revoke(revoke.RevokeDriverV8):
-
- @versionutils.deprecated(
- versionutils.deprecated.JUNO,
- in_favor_of='keystone.contrib.revoke.backends.sql',
- remove_in=+1,
- what='keystone.contrib.revoke.backends.kvs')
- def __init__(self, **kwargs):
- super(Revoke, self).__init__()
- self._store = kvs.get_key_value_store('os-revoke-driver')
- self._store.configure(backing_store=_KVS_BACKEND, **kwargs)
-
- def _list_events(self):
- try:
- return self._store.get(_EVENT_KEY)
- except exception.NotFound:
- return []
-
- def list_events(self, last_fetch=None):
- results = []
-
- with self._store.get_lock(_EVENT_KEY):
- events = self._list_events()
-
- for event in events:
- revoked_at = event.revoked_at
- if last_fetch is None or revoked_at > last_fetch:
- results.append(event)
- return results
-
- def revoke(self, event):
- pruned = []
- expire_delta = datetime.timedelta(seconds=CONF.token.expiration)
- oldest = timeutils.utcnow() - expire_delta
-
- with self._store.get_lock(_EVENT_KEY) as lock:
- events = self._list_events()
- if event:
- events.append(event)
-
- for event in events:
- revoked_at = event.revoked_at
- if revoked_at > oldest:
- pruned.append(event)
- self._store.set(_EVENT_KEY, pruned, lock)
diff --git a/keystone-moon/keystone/contrib/revoke/backends/sql.py b/keystone-moon/keystone/contrib/revoke/backends/sql.py
deleted file mode 100644
index 0bf493ae..00000000
--- a/keystone-moon/keystone/contrib/revoke/backends/sql.py
+++ /dev/null
@@ -1,28 +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_log import versionutils
-
-from keystone.revoke.backends import sql
-
-
-_OLD = "keystone.contrib.revoke.backends.sql.Revoke"
-_NEW = "sql"
-
-
-class Revoke(sql.Revoke):
-
- @versionutils.deprecated(versionutils.deprecated.MITAKA,
- in_favor_of=_NEW,
- what=_OLD)
- def __init__(self, *args, **kwargs):
- super(Revoke, self).__init__(*args, **kwargs)
diff --git a/keystone-moon/keystone/contrib/revoke/controllers.py b/keystone-moon/keystone/contrib/revoke/controllers.py
deleted file mode 100644
index 40151bae..00000000
--- a/keystone-moon/keystone/contrib/revoke/controllers.py
+++ /dev/null
@@ -1,44 +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 keystone.common import controller
-from keystone.common import dependency
-from keystone import exception
-from keystone.i18n import _
-
-
-@dependency.requires('revoke_api')
-class RevokeController(controller.V3Controller):
- @controller.protected()
- def list_revoke_events(self, context):
- since = context['query_string'].get('since')
- last_fetch = None
- if since:
- try:
- last_fetch = timeutils.normalize_time(
- timeutils.parse_isotime(since))
- except ValueError:
- raise exception.ValidationError(
- message=_('invalid date format %s') % since)
- events = self.revoke_api.list_events(last_fetch=last_fetch)
- # Build the links by hand as the standard controller calls require ids
- response = {'events': [event.to_dict() for event in events],
- 'links': {
- 'next': None,
- 'self': RevokeController.base_url(
- context,
- path=context['path']),
- 'previous': None}
- }
- return response
diff --git a/keystone-moon/keystone/contrib/revoke/core.py b/keystone-moon/keystone/contrib/revoke/core.py
deleted file mode 100644
index 3b108c9e..00000000
--- a/keystone-moon/keystone/contrib/revoke/core.py
+++ /dev/null
@@ -1,262 +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.
-
-"""Main entry point into the Revoke service."""
-
-import abc
-import datetime
-
-from oslo_config import cfg
-from oslo_log import log
-from oslo_log import versionutils
-from oslo_utils import timeutils
-import six
-
-from keystone.common import cache
-from keystone.common import dependency
-from keystone.common import extension
-from keystone.common import manager
-from keystone.contrib.revoke import model
-from keystone import exception
-from keystone.i18n import _
-from keystone import notifications
-
-
-CONF = cfg.CONF
-LOG = log.getLogger(__name__)
-
-
-EXTENSION_DATA = {
- 'name': 'OpenStack Revoke API',
- 'namespace': 'http://docs.openstack.org/identity/api/ext/'
- 'OS-REVOKE/v1.0',
- 'alias': 'OS-REVOKE',
- 'updated': '2014-02-24T20:51:0-00:00',
- 'description': 'OpenStack revoked token reporting mechanism.',
- 'links': [
- {
- 'rel': 'describedby',
- 'type': 'text/html',
- 'href': ('https://github.com/openstack/identity-api/blob/master/'
- 'openstack-identity-api/v3/src/markdown/'
- 'identity-api-v3-os-revoke-ext.md'),
- }
- ]}
-extension.register_admin_extension(EXTENSION_DATA['alias'], EXTENSION_DATA)
-extension.register_public_extension(EXTENSION_DATA['alias'], EXTENSION_DATA)
-
-MEMOIZE = cache.get_memoization_decorator(section='revoke')
-
-
-def revoked_before_cutoff_time():
- expire_delta = datetime.timedelta(
- seconds=CONF.token.expiration + CONF.revoke.expiration_buffer)
- oldest = timeutils.utcnow() - expire_delta
- return oldest
-
-
-@dependency.provider('revoke_api')
-class Manager(manager.Manager):
- """Default pivot point for the Revoke backend.
-
- Performs common logic for recording revocations.
-
- See :mod:`keystone.common.manager.Manager` for more details on
- how this dynamically calls the backend.
-
- """
-
- driver_namespace = 'keystone.revoke'
-
- def __init__(self):
- super(Manager, self).__init__(CONF.revoke.driver)
- self._register_listeners()
- self.model = model
-
- def _user_callback(self, service, resource_type, operation,
- payload):
- self.revoke_by_user(payload['resource_info'])
-
- def _role_callback(self, service, resource_type, operation,
- payload):
- self.revoke(
- model.RevokeEvent(role_id=payload['resource_info']))
-
- def _project_callback(self, service, resource_type, operation,
- payload):
- self.revoke(
- model.RevokeEvent(project_id=payload['resource_info']))
-
- def _domain_callback(self, service, resource_type, operation,
- payload):
- self.revoke(
- model.RevokeEvent(domain_id=payload['resource_info']))
-
- def _trust_callback(self, service, resource_type, operation,
- payload):
- self.revoke(
- model.RevokeEvent(trust_id=payload['resource_info']))
-
- def _consumer_callback(self, service, resource_type, operation,
- payload):
- self.revoke(
- model.RevokeEvent(consumer_id=payload['resource_info']))
-
- def _access_token_callback(self, service, resource_type, operation,
- payload):
- self.revoke(
- model.RevokeEvent(access_token_id=payload['resource_info']))
-
- def _role_assignment_callback(self, service, resource_type, operation,
- payload):
- info = payload['resource_info']
- self.revoke_by_grant(role_id=info['role_id'], user_id=info['user_id'],
- domain_id=info.get('domain_id'),
- project_id=info.get('project_id'))
-
- def _register_listeners(self):
- callbacks = {
- notifications.ACTIONS.deleted: [
- ['OS-TRUST:trust', self._trust_callback],
- ['OS-OAUTH1:consumer', self._consumer_callback],
- ['OS-OAUTH1:access_token', self._access_token_callback],
- ['role', self._role_callback],
- ['user', self._user_callback],
- ['project', self._project_callback],
- ['role_assignment', self._role_assignment_callback]
- ],
- notifications.ACTIONS.disabled: [
- ['user', self._user_callback],
- ['project', self._project_callback],
- ['domain', self._domain_callback],
- ],
- notifications.ACTIONS.internal: [
- [notifications.INVALIDATE_USER_TOKEN_PERSISTENCE,
- self._user_callback],
- ]
- }
-
- for event, cb_info in callbacks.items():
- for resource_type, callback_fns in cb_info:
- notifications.register_event_callback(event, resource_type,
- callback_fns)
-
- def revoke_by_user(self, user_id):
- return self.revoke(model.RevokeEvent(user_id=user_id))
-
- def _assert_not_domain_and_project_scoped(self, domain_id=None,
- project_id=None):
- if domain_id is not None and project_id is not None:
- msg = _('The revoke call must not have both domain_id and '
- 'project_id. This is a bug in the Keystone server. The '
- 'current request is aborted.')
- raise exception.UnexpectedError(exception=msg)
-
- @versionutils.deprecated(as_of=versionutils.deprecated.JUNO,
- remove_in=0)
- def revoke_by_expiration(self, user_id, expires_at,
- domain_id=None, project_id=None):
-
- self._assert_not_domain_and_project_scoped(domain_id=domain_id,
- project_id=project_id)
-
- self.revoke(
- model.RevokeEvent(user_id=user_id,
- expires_at=expires_at,
- domain_id=domain_id,
- project_id=project_id))
-
- def revoke_by_audit_id(self, audit_id):
- self.revoke(model.RevokeEvent(audit_id=audit_id))
-
- def revoke_by_audit_chain_id(self, audit_chain_id, project_id=None,
- domain_id=None):
-
- self._assert_not_domain_and_project_scoped(domain_id=domain_id,
- project_id=project_id)
-
- self.revoke(model.RevokeEvent(audit_chain_id=audit_chain_id,
- domain_id=domain_id,
- project_id=project_id))
-
- def revoke_by_grant(self, role_id, user_id=None,
- domain_id=None, project_id=None):
- self.revoke(
- model.RevokeEvent(user_id=user_id,
- role_id=role_id,
- domain_id=domain_id,
- project_id=project_id))
-
- def revoke_by_user_and_project(self, user_id, project_id):
- self.revoke(
- model.RevokeEvent(project_id=project_id, user_id=user_id))
-
- def revoke_by_project_role_assignment(self, project_id, role_id):
- self.revoke(model.RevokeEvent(project_id=project_id, role_id=role_id))
-
- def revoke_by_domain_role_assignment(self, domain_id, role_id):
- self.revoke(model.RevokeEvent(domain_id=domain_id, role_id=role_id))
-
- @MEMOIZE
- def _get_revoke_tree(self):
- events = self.driver.list_events()
- revoke_tree = model.RevokeTree(revoke_events=events)
-
- return revoke_tree
-
- def check_token(self, token_values):
- """Checks the values from a token against the revocation list
-
- :param token_values: dictionary of values from a token,
- normalized for differences between v2 and v3. The checked values are a
- subset of the attributes of model.TokenEvent
-
- :raises exception.TokenNotFound: if the token is invalid
-
- """
- if self._get_revoke_tree().is_revoked(token_values):
- raise exception.TokenNotFound(_('Failed to validate token'))
-
- def revoke(self, event):
- self.driver.revoke(event)
- self._get_revoke_tree.invalidate(self)
-
-
-@six.add_metaclass(abc.ABCMeta)
-class RevokeDriverV8(object):
- """Interface for recording and reporting revocation events."""
-
- @abc.abstractmethod
- def list_events(self, last_fetch=None):
- """return the revocation events, as a list of objects
-
- :param last_fetch: Time of last fetch. Return all events newer.
- :returns: A list of keystone.contrib.revoke.model.RevokeEvent
- newer than `last_fetch.`
- If no last_fetch is specified, returns all events
- for tokens issued after the expiration cutoff.
-
- """
- raise exception.NotImplemented() # pragma: no cover
-
- @abc.abstractmethod
- def revoke(self, event):
- """register a revocation event
-
- :param event: An instance of
- keystone.contrib.revoke.model.RevocationEvent
-
- """
- raise exception.NotImplemented() # pragma: no cover
-
-
-Driver = manager.create_legacy_driver(RevokeDriverV8)
diff --git a/keystone-moon/keystone/contrib/revoke/migrate_repo/__init__.py b/keystone-moon/keystone/contrib/revoke/migrate_repo/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/keystone-moon/keystone/contrib/revoke/migrate_repo/__init__.py
+++ /dev/null
diff --git a/keystone-moon/keystone/contrib/revoke/migrate_repo/migrate.cfg b/keystone-moon/keystone/contrib/revoke/migrate_repo/migrate.cfg
deleted file mode 100644
index 0e61bcaa..00000000
--- a/keystone-moon/keystone/contrib/revoke/migrate_repo/migrate.cfg
+++ /dev/null
@@ -1,25 +0,0 @@
-[db_settings]
-# Used to identify which repository this database is versioned under.
-# You can use the name of your project.
-repository_id=revoke
-
-# The name of the database table used to track the schema version.
-# This name shouldn't already be used by your project.
-# If this is changed once a database is under version control, you'll need to
-# change the table name in each database too.
-version_table=migrate_version
-
-# When committing a change script, Migrate will attempt to generate the
-# sql for all supported databases; normally, if one of them fails - probably
-# because you don't have that database installed - it is ignored and the
-# commit continues, perhaps ending successfully.
-# Databases in this list MUST compile successfully during a commit, or the
-# entire commit will fail. List the databases your application will actually
-# be using to ensure your updates to that database work properly.
-# This must be a list; example: ['postgres','sqlite']
-required_dbs=[]
-
-# When creating new change scripts, Migrate will stamp the new script with
-# a version number. By default this is latest_version + 1. You can set this
-# to 'true' to tell Migrate to use the UTC timestamp instead.
-use_timestamp_numbering=False
diff --git a/keystone-moon/keystone/contrib/revoke/migrate_repo/versions/001_revoke_table.py b/keystone-moon/keystone/contrib/revoke/migrate_repo/versions/001_revoke_table.py
deleted file mode 100644
index 81c535e1..00000000
--- a/keystone-moon/keystone/contrib/revoke/migrate_repo/versions/001_revoke_table.py
+++ /dev/null
@@ -1,17 +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 keystone import exception
-
-
-def upgrade(migrate_engine):
- raise exception.MigrationMovedFailure(extension='revoke')
diff --git a/keystone-moon/keystone/contrib/revoke/migrate_repo/versions/002_add_audit_id_and_chain_to_revoke_table.py b/keystone-moon/keystone/contrib/revoke/migrate_repo/versions/002_add_audit_id_and_chain_to_revoke_table.py
deleted file mode 100644
index 81c535e1..00000000
--- a/keystone-moon/keystone/contrib/revoke/migrate_repo/versions/002_add_audit_id_and_chain_to_revoke_table.py
+++ /dev/null
@@ -1,17 +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 keystone import exception
-
-
-def upgrade(migrate_engine):
- raise exception.MigrationMovedFailure(extension='revoke')
diff --git a/keystone-moon/keystone/contrib/revoke/migrate_repo/versions/__init__.py b/keystone-moon/keystone/contrib/revoke/migrate_repo/versions/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/keystone-moon/keystone/contrib/revoke/migrate_repo/versions/__init__.py
+++ /dev/null
diff --git a/keystone-moon/keystone/contrib/revoke/model.py b/keystone-moon/keystone/contrib/revoke/model.py
deleted file mode 100644
index e677bfb5..00000000
--- a/keystone-moon/keystone/contrib/revoke/model.py
+++ /dev/null
@@ -1,371 +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, None)
- 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']
- token_values['assignment_domain_id'] = project['domain']['id']
- 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/contrib/revoke/routers.py b/keystone-moon/keystone/contrib/revoke/routers.py
deleted file mode 100644
index a44c6194..00000000
--- a/keystone-moon/keystone/contrib/revoke/routers.py
+++ /dev/null
@@ -1,31 +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_log import log
-from oslo_log import versionutils
-
-from keystone.common import wsgi
-from keystone.i18n import _
-
-
-LOG = log.getLogger(__name__)
-
-
-class RevokeExtension(wsgi.Middleware):
-
- def __init__(self, *args, **kwargs):
- super(RevokeExtension, self).__init__(*args, **kwargs)
- msg = _("Remove revoke_extension from the paste pipeline, the "
- "revoke extension is now always available. Update the "
- "[pipeline:api_v3] section in keystone-paste.ini accordingly, "
- "as it will be removed in the O release.")
- versionutils.report_deprecated_feature(LOG, msg)