horizon/horizon/decorators.py

145 lines
5.1 KiB
Python

# 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',))