"Fossies" - the Fresh Open Source Software Archive

Member "glance-19.0.0/glance/api/middleware/context.py" (16 Oct 2019, 7466 Bytes) of package /linux/misc/openstack/glance-19.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 "context.py" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 16.0.1_vs_18.0.0.

    1 # Copyright 2011-2012 OpenStack Foundation
    2 # All Rights Reserved.
    3 #
    4 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
    5 #    not use this file except in compliance with the License. You may obtain
    6 #    a copy of the License at
    7 #
    8 #         http://www.apache.org/licenses/LICENSE-2.0
    9 #
   10 #    Unless required by applicable law or agreed to in writing, software
   11 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
   12 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   13 #    License for the specific language governing permissions and limitations
   14 #    under the License.
   15 
   16 from oslo_config import cfg
   17 from oslo_log import log as logging
   18 from oslo_serialization import jsonutils
   19 import webob.exc
   20 
   21 from glance.api import policy
   22 from glance.common import wsgi
   23 import glance.context
   24 from glance.i18n import _, _LW
   25 
   26 
   27 context_opts = [
   28     cfg.BoolOpt('owner_is_tenant',
   29                 default=True,
   30                 deprecated_for_removal=True,
   31                 deprecated_since="Rocky",
   32                 deprecated_reason=_("""
   33 The non-default setting for this option misaligns Glance with other
   34 OpenStack services with respect to resource ownership.  Further, surveys
   35 indicate that this option is not used by operators.  The option will be
   36 removed early in the 'S' development cycle following the standard OpenStack
   37 deprecation policy.  As the option is not in wide use, no migration path is
   38 proposed.
   39 """),
   40                 help=_("""
   41 Set the image owner to tenant or the authenticated user.
   42 
   43 Assign a boolean value to determine the owner of an image. When set to
   44 True, the owner of the image is the tenant. When set to False, the
   45 owner of the image will be the authenticated user issuing the request.
   46 Setting it to False makes the image private to the associated user and
   47 sharing with other users within the same tenant (or "project")
   48 requires explicit image sharing via image membership.
   49 
   50 Possible values:
   51     * True
   52     * False
   53 
   54 Related options:
   55     * None
   56 
   57 """)),
   58 
   59     cfg.StrOpt('admin_role', default='admin',
   60                help=_("""
   61 Role used to identify an authenticated user as administrator.
   62 
   63 Provide a string value representing a Keystone role to identify an
   64 administrative user. Users with this role will be granted
   65 administrative privileges. The default value for this option is
   66 'admin'.
   67 
   68 Possible values:
   69     * A string value which is a valid Keystone role
   70 
   71 Related options:
   72     * None
   73 
   74 """)),
   75 
   76     cfg.BoolOpt('allow_anonymous_access', default=False,
   77                 help=_("""
   78 Allow limited access to unauthenticated users.
   79 
   80 Assign a boolean to determine API access for unathenticated
   81 users. When set to False, the API cannot be accessed by
   82 unauthenticated users. When set to True, unauthenticated users can
   83 access the API with read-only privileges. This however only applies
   84 when using ContextMiddleware.
   85 
   86 Possible values:
   87     * True
   88     * False
   89 
   90 Related options:
   91     * None
   92 
   93 """)),
   94 
   95     cfg.IntOpt('max_request_id_length', default=64, min=0,
   96                help=_("""
   97 Limit the request ID length.
   98 
   99 Provide  an integer value to limit the length of the request ID to
  100 the specified length. The default value is 64. Users can change this
  101 to any ineteger value between 0 and 16384 however keeping in mind that
  102 a larger value may flood the logs.
  103 
  104 Possible values:
  105     * Integer value between 0 and 16384
  106 
  107 Related options:
  108     * None
  109 
  110 """)),
  111 ]
  112 
  113 CONF = cfg.CONF
  114 CONF.register_opts(context_opts)
  115 
  116 LOG = logging.getLogger(__name__)
  117 
  118 
  119 class BaseContextMiddleware(wsgi.Middleware):
  120     def process_response(self, resp):
  121         try:
  122             request_id = resp.request.context.request_id
  123         except AttributeError:
  124             LOG.warn(_LW('Unable to retrieve request id from context'))
  125         else:
  126             # For python 3 compatibility need to use bytes type
  127             prefix = b'req-' if isinstance(request_id, bytes) else 'req-'
  128 
  129             if not request_id.startswith(prefix):
  130                 request_id = prefix + request_id
  131 
  132             resp.headers['x-openstack-request-id'] = request_id
  133 
  134         return resp
  135 
  136 
  137 class ContextMiddleware(BaseContextMiddleware):
  138     def __init__(self, app):
  139         self.policy_enforcer = policy.Enforcer()
  140         super(ContextMiddleware, self).__init__(app)
  141 
  142     def process_request(self, req):
  143         """Convert authentication information into a request context
  144 
  145         Generate a glance.context.RequestContext object from the available
  146         authentication headers and store on the 'context' attribute
  147         of the req object.
  148 
  149         :param req: wsgi request object that will be given the context object
  150         :raises webob.exc.HTTPUnauthorized: when value of the
  151                                             X-Identity-Status  header is not
  152                                             'Confirmed' and anonymous access
  153                                             is disallowed
  154         """
  155         if req.headers.get('X-Identity-Status') == 'Confirmed':
  156             req.context = self._get_authenticated_context(req)
  157         elif CONF.allow_anonymous_access:
  158             req.context = self._get_anonymous_context()
  159         else:
  160             raise webob.exc.HTTPUnauthorized()
  161 
  162     def _get_anonymous_context(self):
  163         kwargs = {
  164             'user': None,
  165             'tenant': None,
  166             'roles': [],
  167             'is_admin': False,
  168             'read_only': True,
  169             'policy_enforcer': self.policy_enforcer,
  170         }
  171         return glance.context.RequestContext(**kwargs)
  172 
  173     def _get_authenticated_context(self, req):
  174         service_catalog = None
  175         if req.headers.get('X-Service-Catalog') is not None:
  176             try:
  177                 catalog_header = req.headers.get('X-Service-Catalog')
  178                 service_catalog = jsonutils.loads(catalog_header)
  179             except ValueError:
  180                 raise webob.exc.HTTPInternalServerError(
  181                     _('Invalid service catalog json.'))
  182 
  183         request_id = req.headers.get('X-Openstack-Request-ID')
  184         if request_id and (0 < CONF.max_request_id_length <
  185                            len(request_id)):
  186             msg = (_('x-openstack-request-id is too long, max size %s') %
  187                    CONF.max_request_id_length)
  188             return webob.exc.HTTPRequestHeaderFieldsTooLarge(comment=msg)
  189 
  190         kwargs = {
  191             'owner_is_tenant': CONF.owner_is_tenant,
  192             'service_catalog': service_catalog,
  193             'policy_enforcer': self.policy_enforcer,
  194             'request_id': request_id,
  195         }
  196 
  197         ctxt = glance.context.RequestContext.from_environ(req.environ,
  198                                                           **kwargs)
  199 
  200         # FIXME(jamielennox): glance has traditionally lowercased its roles.
  201         # This was related to bug #1010519 where at least the admin role was
  202         # case insensitive. This seems to no longer be the case and should be
  203         # fixed.
  204         ctxt.roles = [r.lower() for r in ctxt.roles]
  205 
  206         if CONF.admin_role.strip().lower() in ctxt.roles:
  207             ctxt.is_admin = True
  208 
  209         return ctxt
  210 
  211 
  212 class UnauthenticatedContextMiddleware(BaseContextMiddleware):
  213     def process_request(self, req):
  214         """Create a context without an authorized user."""
  215         kwargs = {
  216             'user': None,
  217             'tenant': None,
  218             'roles': [],
  219             'is_admin': True,
  220         }
  221 
  222         req.context = glance.context.RequestContext(**kwargs)