# vim: tabstop=4 shiftwidth=4 softtabstop=4 # # 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 heat.common import exception from heat.common import wsgi from heat.openstack.common import cfg from heat.openstack.common import utils class RequestContext(object): """ Stores information about the security context under which the user accesses the system, as well as additional request information. """ def __init__(self, auth_tok=None, user=None, tenant=None, roles=None, is_admin=False, read_only=False, show_deleted=False, owner_is_tenant=True): self.auth_tok = auth_tok self.user = user self.tenant = tenant self.roles = roles or [] self.is_admin = is_admin self.read_only = read_only self._show_deleted = show_deleted self.owner_is_tenant = owner_is_tenant @property def owner(self): """Return the owner to correlate with an image.""" return self.tenant if self.owner_is_tenant else self.user @property def show_deleted(self): """Admins can see deleted by default""" if self._show_deleted or self.is_admin: return True return False class ContextMiddleware(wsgi.Middleware): opts = [ cfg.BoolOpt('owner_is_tenant', default=True), cfg.StrOpt('admin_role', default='admin'), ] def __init__(self, app, conf, **local_conf): self.conf = conf self.conf.register_opts(self.opts) # Determine the context class to use self.ctxcls = RequestContext if 'context_class' in local_conf: self.ctxcls = utils.import_class(local_conf['context_class']) super(ContextMiddleware, self).__init__(app) def make_context(self, *args, **kwargs): """ Create a context with the given arguments. """ kwargs.setdefault('owner_is_tenant', self.conf.owner_is_tenant) return self.ctxcls(*args, **kwargs) def process_request(self, req): """ Extract any authentication information in the request and construct an appropriate context from it. A few scenarios exist: 1. If X-Auth-Token is passed in, then consult TENANT and ROLE headers to determine permissions. 2. An X-Auth-Token was passed in, but the Identity-Status is not confirmed. For now, just raising a NotAuthenticated exception. 3. X-Auth-Token is omitted. If we were using Keystone, then the tokenauth middleware would have rejected the request, so we must be using NoAuth. In that case, assume that is_admin=True. """ auth_tok = req.headers.get('X-Auth-Token') # # hack alert, this is for POC only FIXME properly! # if False: if req.headers.get('X-Identity-Status') == 'Confirmed': # 1. Auth-token is passed, check other headers user = req.headers.get('X-User-Id') tenant = req.headers.get('X-Tenant-Id') roles = [r.strip() for r in req.headers.get('X-Roles', '').split(',')] is_admin = self.conf.admin_role in roles else: # 2. Indentity-Status not confirmed # FIXME(sirp): not sure what the correct behavior in this case # is; just raising NotAuthenticated for now raise exception.NotAuthenticated() else: # 3. Auth-token is ommited, assume NoAuth user = None tenant = None roles = [] is_admin = True req.context = self.make_context( auth_tok=auth_tok, user=user, tenant=tenant, roles=roles, is_admin=is_admin)