From 6915ba0d7f737445b634fc5db67a8c7345d8b6d7 Mon Sep 17 00:00:00 2001 From: Chris Behrens Date: Tue, 19 Feb 2013 00:20:39 +0000 Subject: Move some context checking code from sqlalchemy Move some context related code from sqlalchemy into nova/context.py where it can be used outside of sqlalchemy. Change-Id: I6522a072132e27b42561435cb4fd671a2ece4867 --- .../api/openstack/compute/contrib/quota_classes.py | 3 +- nova/api/openstack/compute/contrib/quotas.py | 4 +- nova/context.py | 53 +++++++++++++ nova/db/sqlalchemy/api.py | 89 ++++++---------------- nova/virt/baremetal/db/sqlalchemy/api.py | 3 +- 5 files changed, 84 insertions(+), 68 deletions(-) diff --git a/nova/api/openstack/compute/contrib/quota_classes.py b/nova/api/openstack/compute/contrib/quota_classes.py index f3f5b9b08..7b94e45b1 100644 --- a/nova/api/openstack/compute/contrib/quota_classes.py +++ b/nova/api/openstack/compute/contrib/quota_classes.py @@ -18,6 +18,7 @@ import webob from nova.api.openstack import extensions from nova.api.openstack import wsgi from nova.api.openstack import xmlutil +import nova.context from nova import db from nova import exception from nova import quota @@ -59,7 +60,7 @@ class QuotaClassSetsController(object): context = req.environ['nova.context'] authorize(context) try: - db.sqlalchemy.api.authorize_quota_class_context(context, id) + nova.context.authorize_quota_class_context(context, id) return self._format_quota_set(id, QUOTAS.get_class_quotas(context, id)) except exception.NotAuthorized: diff --git a/nova/api/openstack/compute/contrib/quotas.py b/nova/api/openstack/compute/contrib/quotas.py index 728c3fad6..b1a461431 100644 --- a/nova/api/openstack/compute/contrib/quotas.py +++ b/nova/api/openstack/compute/contrib/quotas.py @@ -20,8 +20,8 @@ import webob from nova.api.openstack import extensions from nova.api.openstack import wsgi from nova.api.openstack import xmlutil +import nova.context from nova import db -from nova.db.sqlalchemy import api as sqlalchemy_api from nova import exception from nova.openstack.common import log as logging from nova import quota @@ -78,7 +78,7 @@ class QuotaSetsController(object): context = req.environ['nova.context'] authorize_show(context) try: - sqlalchemy_api.authorize_project_context(context, id) + nova.context.authorize_project_context(context, id) return self._format_quota_set(id, self._get_quotas(context, id)) except exception.NotAuthorized: raise webob.exc.HTTPForbidden() diff --git a/nova/context.py b/nova/context.py index 60fd5b4c0..831a91b11 100644 --- a/nova/context.py +++ b/nova/context.py @@ -22,6 +22,7 @@ import copy import uuid +from nova import exception from nova.openstack.common import local from nova.openstack.common import log as logging from nova.openstack.common import timeutils @@ -166,3 +167,55 @@ def get_admin_context(read_deleted="no"): is_admin=True, read_deleted=read_deleted, overwrite=False) + + +def is_user_context(context): + """Indicates if the request context is a normal user.""" + if not context: + return False + if context.is_admin: + return False + if not context.user_id or not context.project_id: + return False + return True + + +def require_admin_context(ctxt): + """Raise exception.AdminRequired() if context is an admin context.""" + if not ctxt.is_admin: + raise exception.AdminRequired() + + +def require_context(ctxt): + """Raise exception.NotAuthorized() if context is not a user or an + admin context. + """ + if not ctxt.is_admin and not is_user_context(ctxt): + raise exception.NotAuthorized() + + +def authorize_project_context(context, project_id): + """Ensures a request has permission to access the given project.""" + if is_user_context(context): + if not context.project_id: + raise exception.NotAuthorized() + elif context.project_id != project_id: + raise exception.NotAuthorized() + + +def authorize_user_context(context, user_id): + """Ensures a request has permission to access the given user.""" + if is_user_context(context): + if not context.user_id: + raise exception.NotAuthorized() + elif context.user_id != user_id: + raise exception.NotAuthorized() + + +def authorize_quota_class_context(context, class_name): + """Ensures a request has permission to access the given quota class.""" + if is_user_context(context): + if not context.quota_class: + raise exception.NotAuthorized() + elif context.quota_class != class_name: + raise exception.NotAuthorized() diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index c717871d1..642a948ce 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -45,6 +45,7 @@ from sqlalchemy import String from nova import block_device from nova.compute import task_states from nova.compute import vm_states +import nova.context from nova import db from nova.db.sqlalchemy import models from nova import exception @@ -74,44 +75,6 @@ get_engine = db_session.get_engine get_session = db_session.get_session -def is_user_context(context): - """Indicates if the request context is a normal user.""" - if not context: - return False - if context.is_admin: - return False - if not context.user_id or not context.project_id: - return False - return True - - -def authorize_project_context(context, project_id): - """Ensures a request has permission to access the given project.""" - if is_user_context(context): - if not context.project_id: - raise exception.NotAuthorized() - elif context.project_id != project_id: - raise exception.NotAuthorized() - - -def authorize_user_context(context, user_id): - """Ensures a request has permission to access the given user.""" - if is_user_context(context): - if not context.user_id: - raise exception.NotAuthorized() - elif context.user_id != user_id: - raise exception.NotAuthorized() - - -def authorize_quota_class_context(context, class_name): - """Ensures a request has permission to access the given quota class.""" - if is_user_context(context): - if not context.quota_class: - raise exception.NotAuthorized() - elif context.quota_class != class_name: - raise exception.NotAuthorized() - - def require_admin_context(f): """Decorator to require admin request context. @@ -120,9 +83,7 @@ def require_admin_context(f): """ def wrapper(*args, **kwargs): - context = args[0] - if not context.is_admin: - raise exception.AdminRequired() + nova.context.require_admin_context(args[0]) return f(*args, **kwargs) return wrapper @@ -131,17 +92,15 @@ def require_context(f): """Decorator to require *any* user or admin context. This does no authorization for user or project access matching, see - :py:func:`authorize_project_context` and - :py:func:`authorize_user_context`. + :py:func:`nova.context.authorize_project_context` and + :py:func:`nova.context.authorize_user_context`. The first argument to the wrapped function must be the context. """ def wrapper(*args, **kwargs): - context = args[0] - if not context.is_admin and not is_user_context(context): - raise exception.NotAuthorized() + nova.context.require_context(args[0]) return f(*args, **kwargs) return wrapper @@ -215,7 +174,7 @@ def model_query(context, model, *args, **kwargs): raise Exception(_("Unrecognized read_deleted value '%s'") % read_deleted) - if is_user_context(context) and project_only: + if nova.context.is_user_context(context) and project_only: if project_only == 'allow_none': query = query.\ filter(or_(base_model.project_id == context.project_id, @@ -658,7 +617,7 @@ def floating_ip_get_pools(context): @require_context def floating_ip_allocate_address(context, project_id, pool): - authorize_project_context(context, project_id) + nova.context.authorize_project_context(context, project_id) session = get_session() with session.begin(): floating_ip_ref = model_query(context, models.FloatingIp, @@ -749,7 +708,7 @@ def floating_ip_create(context, values, session=None): @require_context def floating_ip_count_by_project(context, project_id, session=None): - authorize_project_context(context, project_id) + nova.context.authorize_project_context(context, project_id) # TODO(tr3buchet): why leave auto_assigned floating IPs out? return model_query(context, models.FloatingIp, read_deleted="no", session=session).\ @@ -848,7 +807,7 @@ def floating_ip_get_all_by_host(context, host): @require_context def floating_ip_get_all_by_project(context, project_id): - authorize_project_context(context, project_id) + nova.context.authorize_project_context(context, project_id) # TODO(tr3buchet): why do we not want auto_assigned floating IPs here? return _floating_ip_get_all(context).\ filter_by(project_id=project_id).\ @@ -879,8 +838,8 @@ def _floating_ip_get_by_address(context, address, session=None): # If the floating IP has a project ID set, check to make sure # the non-admin user has access. - if result.project_id and is_user_context(context): - authorize_project_context(context, result.project_id) + if result.project_id and nova.context.is_user_context(context): + nova.context.authorize_project_context(context, result.project_id) return result @@ -1128,10 +1087,11 @@ def fixed_ip_get(context, id, get_network=False): # FIXME(sirp): shouldn't we just use project_only here to restrict the # results? - if is_user_context(context) and result['instance_uuid'] is not None: + if (nova.context.is_user_context(context) and + result['instance_uuid'] is not None): instance = instance_get_by_uuid(context.elevated(read_deleted='yes'), result['instance_uuid']) - authorize_project_context(context, instance.project_id) + nova.context.authorize_project_context(context, instance.project_id) return result @@ -1157,11 +1117,12 @@ def fixed_ip_get_by_address(context, address, session=None): # NOTE(sirp): shouldn't we just use project_only here to restrict the # results? - if is_user_context(context) and result['instance_uuid'] is not None: + if (nova.context.is_user_context(context) and + result['instance_uuid'] is not None): instance = _instance_get_by_uuid(context.elevated(read_deleted='yes'), result['instance_uuid'], session) - authorize_project_context(context, instance.project_id) + nova.context.authorize_project_context(context, instance.project_id) return result @@ -1966,7 +1927,7 @@ def key_pair_create(context, values): @require_context def key_pair_destroy(context, user_id, name): - authorize_user_context(context, user_id) + nova.context.authorize_user_context(context, user_id) model_query(context, models.KeyPair).\ filter_by(user_id=user_id).\ filter_by(name=name).\ @@ -1975,7 +1936,7 @@ def key_pair_destroy(context, user_id, name): @require_context def key_pair_get(context, user_id, name): - authorize_user_context(context, user_id) + nova.context.authorize_user_context(context, user_id) result = model_query(context, models.KeyPair).\ filter_by(user_id=user_id).\ filter_by(name=name).\ @@ -1989,14 +1950,14 @@ def key_pair_get(context, user_id, name): @require_context def key_pair_get_all_by_user(context, user_id): - authorize_user_context(context, user_id) + nova.context.authorize_user_context(context, user_id) return model_query(context, models.KeyPair, read_deleted="no").\ filter_by(user_id=user_id).\ all() def key_pair_count_by_user(context, user_id): - authorize_user_context(context, user_id) + nova.context.authorize_user_context(context, user_id) return model_query(context, models.KeyPair, read_deleted="no").\ filter_by(user_id=user_id).\ count() @@ -2368,7 +2329,7 @@ def quota_get(context, project_id, resource): @require_context def quota_get_all_by_project(context, project_id): - authorize_project_context(context, project_id) + nova.context.authorize_project_context(context, project_id) rows = model_query(context, models.Quota, read_deleted="no").\ filter_by(project_id=project_id).\ @@ -2420,7 +2381,7 @@ def quota_class_get(context, class_name, resource): @require_context def quota_class_get_all_by_name(context, class_name): - authorize_quota_class_context(context, class_name) + nova.context.authorize_quota_class_context(context, class_name) rows = model_query(context, models.QuotaClass, read_deleted="no").\ filter_by(class_name=class_name).\ @@ -2472,7 +2433,7 @@ def quota_usage_get(context, project_id, resource): @require_context def quota_usage_get_all_by_project(context, project_id): - authorize_project_context(context, project_id) + nova.context.authorize_project_context(context, project_id) rows = model_query(context, models.QuotaUsage, read_deleted="no").\ filter_by(project_id=project_id).\ @@ -3171,7 +3132,7 @@ def security_group_destroy(context, security_group_id): @require_context def security_group_count_by_project(context, project_id, session=None): - authorize_project_context(context, project_id) + nova.context.authorize_project_context(context, project_id) return model_query(context, models.SecurityGroup, read_deleted="no", session=session).\ filter_by(project_id=project_id).\ diff --git a/nova/virt/baremetal/db/sqlalchemy/api.py b/nova/virt/baremetal/db/sqlalchemy/api.py index bc5c2f773..5bbb3d62e 100644 --- a/nova/virt/baremetal/db/sqlalchemy/api.py +++ b/nova/virt/baremetal/db/sqlalchemy/api.py @@ -23,6 +23,7 @@ from sqlalchemy.sql.expression import asc from sqlalchemy.sql.expression import literal_column +import nova.context from nova.db.sqlalchemy import api as sqlalchemy_api from nova import exception from nova.openstack.common import log as logging @@ -59,7 +60,7 @@ def model_query(context, *args, **kwargs): raise Exception( _("Unrecognized read_deleted value '%s'") % read_deleted) - if project_only and sqlalchemy_api.is_user_context(context): + if project_only and nova.context.is_user_context(context): query = query.filter_by(project_id=context.project_id) return query -- cgit