# vim: tabstop=4 shiftwidth=4 softtabstop=4 # Copyright 2012 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Copyright 2012 CRS4 # # 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. """ General-purpose decorators for use with Horizon. """ import functools from django.utils.decorators import available_attrs from django.utils.translation import ugettext as _ from horizon.exceptions import NotAuthorized, NotFound def _current_component(view_func, dashboard=None, panel=None): """ Sets the currently-active dashboard and/or panel on the request. """ @functools.wraps(view_func, assigned=available_attrs(view_func)) def dec(request, *args, **kwargs): if dashboard: request.horizon['dashboard'] = dashboard if panel: request.horizon['panel'] = panel return view_func(request, *args, **kwargs) return dec def require_auth(view_func): """ Performs user authentication check. Similar to Django's `login_required` decorator, except that this throws NotAuthorized exception if the user is not signed-in. Raises a :exc:`~horizon.exceptions.NotAuthorized` exception if the user is not authenticated. """ @functools.wraps(view_func, assigned=available_attrs(view_func)) def dec(request, *args, **kwargs): if request.user.is_authenticated(): return view_func(request, *args, **kwargs) raise NotAuthorized(_("You are not authorized to access %s") % request.path) return dec def require_roles(view_func, required): """ Enforces role-based access controls. :param list required: A tuple of role names, all of which the request user must possess in order access the decorated view. Example usage:: from horizon.decorators import require_roles @require_roles(['admin', 'member']) def my_view(request): ... Raises a :exc:`~horizon.exceptions.NotAuthorized` exception if the requirements are not met. """ # We only need to check each role once for a view, so we'll use a set current_roles = getattr(view_func, '_required_roles', set([])) view_func._required_roles = current_roles | set(required) @functools.wraps(view_func, assigned=available_attrs(view_func)) def dec(request, *args, **kwargs): if request.user.is_authenticated(): roles = set([role['name'].lower() for role in request.user.roles]) # set operator <= tests that all members of set 1 are in set 2 if view_func._required_roles <= set(roles): return view_func(request, *args, **kwargs) raise NotAuthorized(_("You are not authorized to access %s") % request.path) # If we don't have any roles, just return the original view. if required: return dec else: return view_func def require_services(view_func, required): """ Enforces service-based access controls. :param list required: A tuple of service type names, all of which the must be present in the service catalog in order access the decorated view. Example usage:: from horizon.decorators import require_services @require_services(['object-store']) def my_swift_view(request): ... Raises a :exc:`~horizon.exceptions.NotFound` exception if the requirements are not met. """ # We only need to check each service once for a view, so we'll use a set current_services = getattr(view_func, '_required_services', set([])) view_func._required_services = current_services | set(required) @functools.wraps(view_func, assigned=available_attrs(view_func)) def dec(request, *args, **kwargs): if request.user.is_authenticated(): services = set([service['type'] for service in request.user.service_catalog]) # set operator <= tests that all members of set 1 are in set 2 if view_func._required_services <= set(services): return view_func(request, *args, **kwargs) raise NotFound(_("The services for this view are not available.")) # If we don't have any services, just return the original view. if required: return dec else: return view_func def enforce_admin_access(view_func): """ Marks a view as requiring the ``"admin"`` role for access. """ return require_roles(view_func, ('admin',))