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
This commit is contained in:
Chris Behrens
2013-02-19 00:20:39 +00:00
parent cd9447f872
commit 6915ba0d7f
5 changed files with 84 additions and 68 deletions

View File

@@ -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:

View File

@@ -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()

View File

@@ -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()

View File

@@ -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).\

View File

@@ -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