"Fossies" - the Fresh Open Source Software Archive

Member "keystone-17.0.0/keystone/receipt/provider.py" (13 May 2020, 6118 Bytes) of package /linux/misc/openstack/keystone-17.0.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "provider.py" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 16.0.1_vs_17.0.0.

    1 # Copyright 2018 Catalyst Cloud Ltd
    2 #
    3 # Licensed under the Apache License, Version 2.0 (the "License"); you may
    4 # not use this file except in compliance with the License. You may obtain
    5 # a copy of the License at
    6 #
    7 #      http://www.apache.org/licenses/LICENSE-2.0
    8 #
    9 # Unless required by applicable law or agreed to in writing, software
   10 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
   11 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   12 # License for the specific language governing permissions and limitations
   13 # under the License.
   14 
   15 """Receipt provider interface."""
   16 
   17 import datetime
   18 
   19 from oslo_log import log
   20 from oslo_utils import timeutils
   21 
   22 from keystone.common import cache
   23 from keystone.common import manager
   24 from keystone.common import provider_api
   25 from keystone.common import utils
   26 import keystone.conf
   27 from keystone import exception
   28 from keystone.i18n import _
   29 from keystone.models import receipt_model
   30 from keystone import notifications
   31 
   32 
   33 CONF = keystone.conf.CONF
   34 LOG = log.getLogger(__name__)
   35 PROVIDERS = provider_api.ProviderAPIs
   36 
   37 RECEIPTS_REGION = cache.create_region(name='receipts')
   38 MEMOIZE_RECEIPTS = cache.get_memoization_decorator(
   39     group='receipt',
   40     region=RECEIPTS_REGION)
   41 
   42 
   43 def default_expire_time():
   44     """Determine when a fresh receipt should expire.
   45 
   46     Expiration time varies based on configuration (see
   47     ``[receipt] expiration``).
   48 
   49     :returns: a naive UTC datetime.datetime object
   50 
   51     """
   52     expire_delta = datetime.timedelta(seconds=CONF.receipt.expiration)
   53     expires_at = timeutils.utcnow() + expire_delta
   54     return expires_at.replace(microsecond=0)
   55 
   56 
   57 class Manager(manager.Manager):
   58     """Default pivot point for the receipt provider backend.
   59 
   60     See :mod:`keystone.common.manager.Manager` for more details on how this
   61     dynamically calls the backend.
   62 
   63     """
   64 
   65     driver_namespace = 'keystone.receipt.provider'
   66     _provides_api = 'receipt_provider_api'
   67 
   68     def __init__(self):
   69         super(Manager, self).__init__(CONF.receipt.provider)
   70         self._register_callback_listeners()
   71 
   72     def _register_callback_listeners(self):
   73         callbacks = {
   74             notifications.ACTIONS.deleted: [
   75                 ['OS-TRUST:trust', self._drop_receipt_cache],
   76                 ['user', self._drop_receipt_cache],
   77                 ['domain', self._drop_receipt_cache],
   78             ],
   79             notifications.ACTIONS.disabled: [
   80                 ['user', self._drop_receipt_cache],
   81                 ['domain', self._drop_receipt_cache],
   82                 ['project', self._drop_receipt_cache],
   83             ],
   84             notifications.ACTIONS.internal: [
   85                 [notifications.INVALIDATE_TOKEN_CACHE,
   86                     self._drop_receipt_cache],
   87             ]
   88         }
   89 
   90         for event, cb_info in callbacks.items():
   91             for resource_type, callback_fns in cb_info:
   92                 notifications.register_event_callback(event, resource_type,
   93                                                       callback_fns)
   94 
   95     def _drop_receipt_cache(self, service, resource_type, operation, payload):
   96         """Invalidate the entire receipt cache.
   97 
   98         This is a handy private utility method that should be used when
   99         consuming notifications that signal invalidating the receipt cache.
  100 
  101         """
  102         if CONF.receipt.cache_on_issue:
  103             RECEIPTS_REGION.invalidate()
  104 
  105     def validate_receipt(self, receipt_id, window_seconds=0):
  106         if not receipt_id:
  107             raise exception.ReceiptNotFound(
  108                 _('No receipt in the request'), receipt_id=receipt_id)
  109 
  110         try:
  111             receipt = self._validate_receipt(receipt_id)
  112             self._is_valid_receipt(receipt, window_seconds=window_seconds)
  113             return receipt
  114         except exception.Unauthorized as e:
  115             LOG.debug('Unable to validate receipt: %s', e)
  116             raise exception.ReceiptNotFound(receipt_id=receipt_id)
  117 
  118     @MEMOIZE_RECEIPTS
  119     def _validate_receipt(self, receipt_id):
  120         (user_id, methods, issued_at,
  121             expires_at) = self.driver.validate_receipt(receipt_id)
  122 
  123         receipt = receipt_model.ReceiptModel()
  124         receipt.user_id = user_id
  125         receipt.methods = methods
  126         receipt.expires_at = expires_at
  127         receipt.mint(receipt_id, issued_at)
  128         return receipt
  129 
  130     def _is_valid_receipt(self, receipt, window_seconds=0):
  131         """Verify the receipt is valid format and has not expired."""
  132         current_time = timeutils.normalize_time(timeutils.utcnow())
  133 
  134         try:
  135             expiry = timeutils.parse_isotime(receipt.expires_at)
  136             expiry = timeutils.normalize_time(expiry)
  137 
  138             # add a window in which you can fetch a receipt beyond expiry
  139             expiry += datetime.timedelta(seconds=window_seconds)
  140 
  141         except Exception:
  142             LOG.exception('Unexpected error or malformed receipt '
  143                           'determining receipt expiry: %s', receipt)
  144             raise exception.ReceiptNotFound(
  145                 _('Failed to validate receipt'), receipt_id=receipt.id)
  146 
  147         if current_time < expiry:
  148             return None
  149         else:
  150             raise exception.ReceiptNotFound(
  151                 _('Failed to validate receipt'), receipt_id=receipt.id)
  152 
  153     def issue_receipt(self, user_id, method_names, expires_at=None):
  154 
  155         receipt = receipt_model.ReceiptModel()
  156         receipt.user_id = user_id
  157         receipt.methods = method_names
  158 
  159         if isinstance(expires_at, datetime.datetime):
  160             receipt.expires_at = utils.isotime(expires_at, subsecond=True)
  161         if isinstance(expires_at, str):
  162             receipt.expires_at = expires_at
  163         elif not expires_at:
  164             receipt.expires_at = utils.isotime(
  165                 default_expire_time(), subsecond=True
  166             )
  167 
  168         receipt_id, issued_at = self.driver.generate_id_and_issued_at(receipt)
  169         receipt.mint(receipt_id, issued_at)
  170 
  171         if CONF.receipt.cache_on_issue:
  172             self._validate_receipt.set(
  173                 receipt, RECEIPTS_REGION, receipt_id)
  174 
  175         return receipt