RBAC support based on oslo.policy
This commit adds support for RBAC using oslo.policy. This allows Zaqar for having a fine-grained access control to the resources it exposes. As of this patch, the implementation allows to have access control in a per-operation basis rather than specific resources. Co-Authored-by: Thomas Herve <therve@redhat.com> Co-Authored-by: Flavio Percoco <flaper87@gmail.com> blueprint: fine-grained-permissions Change-Id: I90374a11815ac2bd9d31768588719d2d4c4e7f5d
This commit is contained in:
parent
e061305356
commit
d08f4913ca
@ -37,6 +37,7 @@ ZAQAR_DIR=$DEST/zaqar
|
|||||||
ZAQARCLIENT_DIR=$DEST/python-zaqarclient
|
ZAQARCLIENT_DIR=$DEST/python-zaqarclient
|
||||||
ZAQAR_CONF_DIR=/etc/zaqar
|
ZAQAR_CONF_DIR=/etc/zaqar
|
||||||
ZAQAR_CONF=$ZAQAR_CONF_DIR/zaqar.conf
|
ZAQAR_CONF=$ZAQAR_CONF_DIR/zaqar.conf
|
||||||
|
ZAQAR_POLICY_CONF=$ZAQAR_CONF_DIR/policy.json
|
||||||
ZAQAR_UWSGI_CONF=$ZAQAR_CONF_DIR/uwsgi.conf
|
ZAQAR_UWSGI_CONF=$ZAQAR_CONF_DIR/uwsgi.conf
|
||||||
ZAQAR_API_LOG_DIR=/var/log/zaqar
|
ZAQAR_API_LOG_DIR=/var/log/zaqar
|
||||||
ZAQAR_API_LOG_FILE=$ZAQAR_API_LOG_DIR/queues.log
|
ZAQAR_API_LOG_FILE=$ZAQAR_API_LOG_DIR/queues.log
|
||||||
@ -112,6 +113,10 @@ function configure_zaqar {
|
|||||||
[ ! -d $ZAQAR_CONF_DIR ] && sudo mkdir -m 755 -p $ZAQAR_CONF_DIR
|
[ ! -d $ZAQAR_CONF_DIR ] && sudo mkdir -m 755 -p $ZAQAR_CONF_DIR
|
||||||
sudo chown $USER $ZAQAR_CONF_DIR
|
sudo chown $USER $ZAQAR_CONF_DIR
|
||||||
|
|
||||||
|
if [[ -f $ZAQAR_DIR/etc/policy.json.sample ]]; then
|
||||||
|
cp -p $ZAQAR_DIR/etc/policy.json.sample $ZAQAR_POLICY_CONF
|
||||||
|
fi
|
||||||
|
|
||||||
[ ! -d $ZAQAR_API_LOG_DIR ] && sudo mkdir -m 755 -p $ZAQAR_API_LOG_DIR
|
[ ! -d $ZAQAR_API_LOG_DIR ] && sudo mkdir -m 755 -p $ZAQAR_API_LOG_DIR
|
||||||
sudo chown $USER $ZAQAR_API_LOG_DIR
|
sudo chown $USER $ZAQAR_API_LOG_DIR
|
||||||
|
|
||||||
|
45
etc/policy.json.sample
Normal file
45
etc/policy.json.sample
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
{
|
||||||
|
"context_is_admin": "role:admin",
|
||||||
|
"admin_or_owner": "is_admin:True or project_id:%(project_id)s",
|
||||||
|
"default": "rule:admin_or_owner",
|
||||||
|
|
||||||
|
"queues:get_all": "",
|
||||||
|
"queues:create": "",
|
||||||
|
"queues:get": "",
|
||||||
|
"queues:delete": "",
|
||||||
|
"queues:update": "",
|
||||||
|
"queues:stats": "",
|
||||||
|
|
||||||
|
"messages:get_all": "",
|
||||||
|
"messages:create": "",
|
||||||
|
"messages:get": "",
|
||||||
|
"messages:delete": "",
|
||||||
|
"messages:delete_all": "",
|
||||||
|
|
||||||
|
"claims:get_all": "",
|
||||||
|
"claims:create": "",
|
||||||
|
"claims:get": "",
|
||||||
|
"claims:delete": "",
|
||||||
|
"claims:update": "",
|
||||||
|
|
||||||
|
"subscription:get_all": "",
|
||||||
|
"subscription:create": "",
|
||||||
|
"subscription:get": "",
|
||||||
|
"subscription:delete": "",
|
||||||
|
"subscription:update": "",
|
||||||
|
|
||||||
|
"pools:get_all": "rule:context_is_admin",
|
||||||
|
"pools:create": "rule:context_is_admin",
|
||||||
|
"pools:get": "rule:context_is_admin",
|
||||||
|
"pools:delete": "rule:context_is_admin",
|
||||||
|
"pools:update": "rule:context_is_admin",
|
||||||
|
|
||||||
|
"flavors:get_all": "",
|
||||||
|
"flavors:create": "rule:context_is_admin",
|
||||||
|
"flavors:get": "",
|
||||||
|
"flavors:delete": "rule:context_is_admin",
|
||||||
|
"flavors:update": "rule:context_is_admin",
|
||||||
|
|
||||||
|
"ping:get": "",
|
||||||
|
"health:get": "rule:context_is_admin"
|
||||||
|
}
|
@ -21,6 +21,7 @@ oslo.i18n>=1.5.0 # Apache-2.0
|
|||||||
oslo.log>=1.8.0 # Apache-2.0
|
oslo.log>=1.8.0 # Apache-2.0
|
||||||
oslo.serialization>=1.4.0 # Apache-2.0
|
oslo.serialization>=1.4.0 # Apache-2.0
|
||||||
oslo.utils>=2.0.0 # Apache-2.0
|
oslo.utils>=2.0.0 # Apache-2.0
|
||||||
|
oslo.policy>=0.5.0 # Apache-2.0
|
||||||
SQLAlchemy<1.1.0,>=0.9.9
|
SQLAlchemy<1.1.0,>=0.9.9
|
||||||
enum34;python_version=='2.7' or python_version=='2.6'
|
enum34;python_version=='2.7' or python_version=='2.6'
|
||||||
trollius>=1.0
|
trollius>=1.0
|
||||||
|
@ -200,7 +200,19 @@ def inject_context(req, resp, params):
|
|||||||
"""
|
"""
|
||||||
client_id = req.get_header('Client-ID')
|
client_id = req.get_header('Client-ID')
|
||||||
project_id = params.get('project_id', None)
|
project_id = params.get('project_id', None)
|
||||||
|
request_id = req.headers.get('X-Openstack-Request-ID'),
|
||||||
|
auth_token = req.headers.get('X-AUTH-TOKEN')
|
||||||
|
user = req.headers.get('X-USER-ID')
|
||||||
|
tenant = req.headers.get('X-TENANT-ID')
|
||||||
|
|
||||||
|
roles = req.headers.get('X-ROLES')
|
||||||
|
roles = roles and roles.split(',') or []
|
||||||
|
|
||||||
ctxt = context.RequestContext(project_id=project_id,
|
ctxt = context.RequestContext(project_id=project_id,
|
||||||
client_id=client_id)
|
client_id=client_id,
|
||||||
|
request_id=request_id,
|
||||||
|
auth_token=auth_token,
|
||||||
|
user=user,
|
||||||
|
tenant=tenant,
|
||||||
|
roles=roles)
|
||||||
req.env['zaqar.context'] = ctxt
|
req.env['zaqar.context'] = ctxt
|
||||||
|
@ -26,7 +26,7 @@ class RequestContext(context.RequestContext):
|
|||||||
auth_token=None, user=None, tenant=None, domain=None,
|
auth_token=None, user=None, tenant=None, domain=None,
|
||||||
user_domain=None, project_domain=None, is_admin=False,
|
user_domain=None, project_domain=None, is_admin=False,
|
||||||
read_only=False, show_deleted=False, request_id=None,
|
read_only=False, show_deleted=False, request_id=None,
|
||||||
instance_uuid=None, **kwargs):
|
instance_uuid=None, roles=None, **kwargs):
|
||||||
super(RequestContext, self).__init__(auth_token=auth_token,
|
super(RequestContext, self).__init__(auth_token=auth_token,
|
||||||
user=user,
|
user=user,
|
||||||
tenant=tenant,
|
tenant=tenant,
|
||||||
@ -39,6 +39,7 @@ class RequestContext(context.RequestContext):
|
|||||||
request_id=request_id)
|
request_id=request_id)
|
||||||
self.project_id = project_id
|
self.project_id = project_id
|
||||||
self.client_id = client_id
|
self.client_id = client_id
|
||||||
|
self.roles = roles
|
||||||
if overwrite or not hasattr(context._request_store, 'context'):
|
if overwrite or not hasattr(context._request_store, 'context'):
|
||||||
self.update_store()
|
self.update_store()
|
||||||
|
|
||||||
@ -49,6 +50,8 @@ class RequestContext(context.RequestContext):
|
|||||||
ctx = super(RequestContext, self).to_dict()
|
ctx = super(RequestContext, self).to_dict()
|
||||||
ctx.update({
|
ctx.update({
|
||||||
'project_id': self.project_id,
|
'project_id': self.project_id,
|
||||||
'client_id': self.client_id
|
'client_id': self.client_id,
|
||||||
|
'tenant': self.tenant,
|
||||||
|
'roles': self.roles
|
||||||
})
|
})
|
||||||
return ctx
|
return ctx
|
||||||
|
45
zaqar/tests/etc/policy.json
Normal file
45
zaqar/tests/etc/policy.json
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
{
|
||||||
|
"context_is_admin": "role:admin",
|
||||||
|
"admin_or_owner": "is_admin:True or project_id:%(project_id)s",
|
||||||
|
"default": "rule:admin_or_owner",
|
||||||
|
|
||||||
|
"queues:get_all": "",
|
||||||
|
"queues:create": "",
|
||||||
|
"queues:get": "",
|
||||||
|
"queues:delete": "",
|
||||||
|
"queues:update": "",
|
||||||
|
"queues:stats": "",
|
||||||
|
|
||||||
|
"messages:get_all": "",
|
||||||
|
"messages:create": "",
|
||||||
|
"messages:get": "",
|
||||||
|
"messages:delete": "",
|
||||||
|
"messages:delete_all": "",
|
||||||
|
|
||||||
|
"claims:get_all": "",
|
||||||
|
"claims:create": "",
|
||||||
|
"claims:get": "",
|
||||||
|
"claims:delete": "",
|
||||||
|
"claims:update": "",
|
||||||
|
|
||||||
|
"subscription:get_all": "",
|
||||||
|
"subscription:create": "",
|
||||||
|
"subscription:get": "",
|
||||||
|
"subscription:delete": "",
|
||||||
|
"subscription:update": "",
|
||||||
|
|
||||||
|
"pools:get_all": "rule:context_is_admin",
|
||||||
|
"pools:create": "rule:context_is_admin",
|
||||||
|
"pools:get": "rule:context_is_admin",
|
||||||
|
"pools:delete": "rule:context_is_admin",
|
||||||
|
"pools:update": "rule:context_is_admin",
|
||||||
|
|
||||||
|
"flavors:get_all": "",
|
||||||
|
"flavors:create": "rule:context_is_admin",
|
||||||
|
"flavors:get": "",
|
||||||
|
"flavors:delete": "rule:context_is_admin",
|
||||||
|
"flavors:update": "rule:context_is_admin",
|
||||||
|
|
||||||
|
"ping:get": "",
|
||||||
|
"health:get": "rule:context_is_admin"
|
||||||
|
}
|
57
zaqar/tests/unit/transport/test_acl.py
Normal file
57
zaqar/tests/unit/transport/test_acl.py
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
# Copyright (c) 2015 Catalyst IT Ltd.
|
||||||
|
#
|
||||||
|
# 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 collections import namedtuple
|
||||||
|
|
||||||
|
from oslo_policy import policy
|
||||||
|
|
||||||
|
from zaqar import context
|
||||||
|
from zaqar.tests import base
|
||||||
|
from zaqar.transport import acl
|
||||||
|
from zaqar.transport.wsgi import errors
|
||||||
|
|
||||||
|
|
||||||
|
class TestAcl(base.TestBase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestAcl, self).setUp()
|
||||||
|
ctx = context.RequestContext()
|
||||||
|
request_class = namedtuple("Request", ("env",))
|
||||||
|
self.request = request_class({"zaqar.context": ctx})
|
||||||
|
|
||||||
|
def _set_policy(self, json):
|
||||||
|
acl.setup_policy(self.conf)
|
||||||
|
rules = policy.Rules.load_json(json)
|
||||||
|
acl.ENFORCER.set_rules(rules, use_conf=False)
|
||||||
|
|
||||||
|
def test_policy_allow(self):
|
||||||
|
@acl.enforce("queues:get_all")
|
||||||
|
def test(ign, request):
|
||||||
|
pass
|
||||||
|
|
||||||
|
json = '{"queues:get_all": ""}'
|
||||||
|
self._set_policy(json)
|
||||||
|
|
||||||
|
test(None, self.request)
|
||||||
|
|
||||||
|
def test_policy_deny(self):
|
||||||
|
@acl.enforce("queues:get_all")
|
||||||
|
def test(ign, request):
|
||||||
|
pass
|
||||||
|
|
||||||
|
json = '{"queues:get_all": "!"}'
|
||||||
|
self._set_policy(json)
|
||||||
|
|
||||||
|
self.assertRaises(errors.HTTPForbidden, test, None, self.request)
|
@ -53,6 +53,9 @@ class TestBase(testing.TestBase):
|
|||||||
|
|
||||||
self.headers = {
|
self.headers = {
|
||||||
'Client-ID': str(uuid.uuid4()),
|
'Client-ID': str(uuid.uuid4()),
|
||||||
|
'X-ROLES': 'admin',
|
||||||
|
'X-USER-ID': 'a12d157c7d0d41999096639078fd11fc',
|
||||||
|
'X-TENANT-ID': 'abb69142168841fcaa2785791b92467f',
|
||||||
}
|
}
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
|
@ -52,10 +52,10 @@ class TestMessagesMongoDB(base.V2Base):
|
|||||||
self.assertEqual(self.srmock.status, falcon.HTTP_201)
|
self.assertEqual(self.srmock.status, falcon.HTTP_201)
|
||||||
|
|
||||||
self.project_id = '7e55e1a7e'
|
self.project_id = '7e55e1a7e'
|
||||||
self.headers = {
|
self.headers.update({
|
||||||
'Client-ID': str(uuid.uuid4()),
|
'Client-ID': str(uuid.uuid4()),
|
||||||
'X-Project-ID': self.project_id
|
'X-Project-ID': self.project_id
|
||||||
}
|
})
|
||||||
|
|
||||||
# TODO(kgriffs): Add support in self.simulate_* for a "base path"
|
# TODO(kgriffs): Add support in self.simulate_* for a "base path"
|
||||||
# so that we don't have to concatenate against self.url_prefix
|
# so that we don't have to concatenate against self.url_prefix
|
||||||
|
44
zaqar/transport/acl.py
Normal file
44
zaqar/transport/acl.py
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
# Copyright (c) 2015 Catalyst IT Ltd.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
"""Policy enforcer of Zaqar"""
|
||||||
|
|
||||||
|
import functools
|
||||||
|
|
||||||
|
from oslo_policy import policy
|
||||||
|
|
||||||
|
ENFORCER = None
|
||||||
|
|
||||||
|
|
||||||
|
def setup_policy(conf):
|
||||||
|
global ENFORCER
|
||||||
|
|
||||||
|
ENFORCER = policy.Enforcer(conf)
|
||||||
|
|
||||||
|
|
||||||
|
def enforce(rule):
|
||||||
|
# Late import to prevent cycles
|
||||||
|
from zaqar.transport.wsgi import errors
|
||||||
|
|
||||||
|
def decorator(func):
|
||||||
|
@functools.wraps(func)
|
||||||
|
def handler(*args, **kwargs):
|
||||||
|
ctx = args[1].env['zaqar.context']
|
||||||
|
ENFORCER.enforce(rule, {}, ctx.to_dict(), do_raise=True,
|
||||||
|
exc=errors.HTTPForbidden)
|
||||||
|
|
||||||
|
return func(*args, **kwargs)
|
||||||
|
return handler
|
||||||
|
|
||||||
|
return decorator
|
@ -25,6 +25,7 @@ from zaqar.common import decorators
|
|||||||
from zaqar.common.transport.wsgi import helpers
|
from zaqar.common.transport.wsgi import helpers
|
||||||
from zaqar.i18n import _
|
from zaqar.i18n import _
|
||||||
from zaqar import transport
|
from zaqar import transport
|
||||||
|
from zaqar.transport import acl
|
||||||
from zaqar.transport import auth
|
from zaqar.transport import auth
|
||||||
from zaqar.transport import validation
|
from zaqar.transport import validation
|
||||||
from zaqar.transport.wsgi import v1_0
|
from zaqar.transport.wsgi import v1_0
|
||||||
@ -117,6 +118,8 @@ class Driver(transport.DriverBase):
|
|||||||
|
|
||||||
self.app = auth.SignedHeadersAuth(self.app, auth_app)
|
self.app = auth.SignedHeadersAuth(self.app, auth_app)
|
||||||
|
|
||||||
|
acl.setup_policy(self._conf)
|
||||||
|
|
||||||
def _error_handler(self, exc, request, response, params):
|
def _error_handler(self, exc, request, response, params):
|
||||||
if isinstance(exc, falcon.HTTPError):
|
if isinstance(exc, falcon.HTTPError):
|
||||||
raise exc
|
raise exc
|
||||||
|
@ -55,3 +55,13 @@ class HTTPDocumentTypeNotSupported(HTTPBadRequestBody):
|
|||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(HTTPDocumentTypeNotSupported, self).__init__(self.DESCRIPTION)
|
super(HTTPDocumentTypeNotSupported, self).__init__(self.DESCRIPTION)
|
||||||
|
|
||||||
|
|
||||||
|
class HTTPForbidden(falcon.HTTPForbidden):
|
||||||
|
"""Wraps falcon.HTTPForbidden with a contextual title."""
|
||||||
|
|
||||||
|
TITLE = _(u'Not authorized')
|
||||||
|
DESCRIPTION = _(u'You are not authorized to complete this action.')
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super(HTTPForbidden, self).__init__(self.TITLE, self.DESCRIPTION)
|
||||||
|
@ -19,6 +19,7 @@ import six
|
|||||||
|
|
||||||
from zaqar.i18n import _
|
from zaqar.i18n import _
|
||||||
from zaqar.storage import errors as storage_errors
|
from zaqar.storage import errors as storage_errors
|
||||||
|
from zaqar.transport import acl
|
||||||
from zaqar.transport import utils
|
from zaqar.transport import utils
|
||||||
from zaqar.transport import validation
|
from zaqar.transport import validation
|
||||||
from zaqar.transport.wsgi import errors as wsgi_errors
|
from zaqar.transport.wsgi import errors as wsgi_errors
|
||||||
@ -53,6 +54,7 @@ class CollectionResource(object):
|
|||||||
'grace': default_grace_ttl,
|
'grace': default_grace_ttl,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@acl.enforce("claims:create")
|
||||||
def on_post(self, req, resp, project_id, queue_name):
|
def on_post(self, req, resp, project_id, queue_name):
|
||||||
LOG.debug(u'Claims collection POST - queue: %(queue)s, '
|
LOG.debug(u'Claims collection POST - queue: %(queue)s, '
|
||||||
u'project: %(project)s',
|
u'project: %(project)s',
|
||||||
@ -125,6 +127,7 @@ class ItemResource(object):
|
|||||||
('grace', int, default_grace_ttl),
|
('grace', int, default_grace_ttl),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@acl.enforce("claims:get")
|
||||||
def on_get(self, req, resp, project_id, queue_name, claim_id):
|
def on_get(self, req, resp, project_id, queue_name, claim_id):
|
||||||
LOG.debug(u'Claim item GET - claim: %(claim_id)s, '
|
LOG.debug(u'Claim item GET - claim: %(claim_id)s, '
|
||||||
u'queue: %(queue_name)s, project: %(project_id)s',
|
u'queue: %(queue_name)s, project: %(project_id)s',
|
||||||
@ -162,6 +165,7 @@ class ItemResource(object):
|
|||||||
resp.body = utils.to_json(meta)
|
resp.body = utils.to_json(meta)
|
||||||
# status defaults to 200
|
# status defaults to 200
|
||||||
|
|
||||||
|
@acl.enforce("claims:update")
|
||||||
def on_patch(self, req, resp, project_id, queue_name, claim_id):
|
def on_patch(self, req, resp, project_id, queue_name, claim_id):
|
||||||
LOG.debug(u'Claim Item PATCH - claim: %(claim_id)s, '
|
LOG.debug(u'Claim Item PATCH - claim: %(claim_id)s, '
|
||||||
u'queue: %(queue_name)s, project:%(project_id)s' %
|
u'queue: %(queue_name)s, project:%(project_id)s' %
|
||||||
@ -196,6 +200,7 @@ class ItemResource(object):
|
|||||||
description = _(u'Claim could not be updated.')
|
description = _(u'Claim could not be updated.')
|
||||||
raise wsgi_errors.HTTPServiceUnavailable(description)
|
raise wsgi_errors.HTTPServiceUnavailable(description)
|
||||||
|
|
||||||
|
@acl.enforce("claims:delete")
|
||||||
def on_delete(self, req, resp, project_id, queue_name, claim_id):
|
def on_delete(self, req, resp, project_id, queue_name, claim_id):
|
||||||
LOG.debug(u'Claim item DELETE - claim: %(claim_id)s, '
|
LOG.debug(u'Claim item DELETE - claim: %(claim_id)s, '
|
||||||
u'queue: %(queue_name)s, project: %(project_id)s' %
|
u'queue: %(queue_name)s, project: %(project_id)s' %
|
||||||
|
@ -21,6 +21,7 @@ from zaqar.common.api.schemas import flavors as schema
|
|||||||
from zaqar.common import utils as common_utils
|
from zaqar.common import utils as common_utils
|
||||||
from zaqar.i18n import _
|
from zaqar.i18n import _
|
||||||
from zaqar.storage import errors
|
from zaqar.storage import errors
|
||||||
|
from zaqar.transport import acl
|
||||||
from zaqar.transport import utils as transport_utils
|
from zaqar.transport import utils as transport_utils
|
||||||
from zaqar.transport.wsgi import errors as wsgi_errors
|
from zaqar.transport.wsgi import errors as wsgi_errors
|
||||||
from zaqar.transport.wsgi import utils as wsgi_utils
|
from zaqar.transport.wsgi import utils as wsgi_utils
|
||||||
@ -38,6 +39,7 @@ class Listing(object):
|
|||||||
self._ctrl = flavors_controller
|
self._ctrl = flavors_controller
|
||||||
self._pools_ctrl = pools_controller
|
self._pools_ctrl = pools_controller
|
||||||
|
|
||||||
|
@acl.enforce("flavors:get_all")
|
||||||
def on_get(self, request, response, project_id):
|
def on_get(self, request, response, project_id):
|
||||||
"""Returns a flavor listing as objects embedded in an object:
|
"""Returns a flavor listing as objects embedded in an object:
|
||||||
|
|
||||||
@ -113,6 +115,7 @@ class Resource(object):
|
|||||||
'capabilities': validator_type(schema.patch_capabilities),
|
'capabilities': validator_type(schema.patch_capabilities),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@acl.enforce("flavors:get")
|
||||||
def on_get(self, request, response, project_id, flavor):
|
def on_get(self, request, response, project_id, flavor):
|
||||||
"""Returns a JSON object for a single flavor entry:
|
"""Returns a JSON object for a single flavor entry:
|
||||||
|
|
||||||
@ -140,6 +143,7 @@ class Resource(object):
|
|||||||
|
|
||||||
response.body = transport_utils.to_json(data)
|
response.body = transport_utils.to_json(data)
|
||||||
|
|
||||||
|
@acl.enforce("flavors:create")
|
||||||
def on_put(self, request, response, project_id, flavor):
|
def on_put(self, request, response, project_id, flavor):
|
||||||
"""Registers a new flavor. Expects the following input:
|
"""Registers a new flavor. Expects the following input:
|
||||||
|
|
||||||
@ -170,6 +174,7 @@ class Resource(object):
|
|||||||
dict(flavor=flavor, pool=data['pool']))
|
dict(flavor=flavor, pool=data['pool']))
|
||||||
raise falcon.HTTPBadRequest(_('Unable to create'), description)
|
raise falcon.HTTPBadRequest(_('Unable to create'), description)
|
||||||
|
|
||||||
|
@acl.enforce("flavors:delete")
|
||||||
def on_delete(self, request, response, project_id, flavor):
|
def on_delete(self, request, response, project_id, flavor):
|
||||||
"""Deregisters a flavor.
|
"""Deregisters a flavor.
|
||||||
|
|
||||||
@ -180,6 +185,7 @@ class Resource(object):
|
|||||||
self._ctrl.delete(flavor, project=project_id)
|
self._ctrl.delete(flavor, project=project_id)
|
||||||
response.status = falcon.HTTP_204
|
response.status = falcon.HTTP_204
|
||||||
|
|
||||||
|
@acl.enforce("flavors:update")
|
||||||
def on_patch(self, request, response, project_id, flavor):
|
def on_patch(self, request, response, project_id, flavor):
|
||||||
"""Allows one to update a flavors's pool and/or capabilities.
|
"""Allows one to update a flavors's pool and/or capabilities.
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
|
||||||
from zaqar.i18n import _
|
from zaqar.i18n import _
|
||||||
|
from zaqar.transport import acl
|
||||||
from zaqar.transport import utils
|
from zaqar.transport import utils
|
||||||
from zaqar.transport.wsgi import errors as wsgi_errors
|
from zaqar.transport.wsgi import errors as wsgi_errors
|
||||||
|
|
||||||
@ -29,6 +30,7 @@ class Resource(object):
|
|||||||
def __init__(self, driver):
|
def __init__(self, driver):
|
||||||
self._driver = driver
|
self._driver = driver
|
||||||
|
|
||||||
|
@acl.enforce("health:get")
|
||||||
def on_get(self, req, resp, **kwargs):
|
def on_get(self, req, resp, **kwargs):
|
||||||
try:
|
try:
|
||||||
resp_dict = self._driver.health()
|
resp_dict = self._driver.health()
|
||||||
|
@ -20,6 +20,7 @@ import six
|
|||||||
from zaqar.common.transport.wsgi import helpers as wsgi_helpers
|
from zaqar.common.transport.wsgi import helpers as wsgi_helpers
|
||||||
from zaqar.i18n import _
|
from zaqar.i18n import _
|
||||||
from zaqar.storage import errors as storage_errors
|
from zaqar.storage import errors as storage_errors
|
||||||
|
from zaqar.transport import acl
|
||||||
from zaqar.transport import utils
|
from zaqar.transport import utils
|
||||||
from zaqar.transport import validation
|
from zaqar.transport import validation
|
||||||
from zaqar.transport.wsgi import errors as wsgi_errors
|
from zaqar.transport.wsgi import errors as wsgi_errors
|
||||||
@ -149,6 +150,7 @@ class CollectionResource(object):
|
|||||||
# Interface
|
# Interface
|
||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@acl.enforce("messages:create")
|
||||||
def on_post(self, req, resp, project_id, queue_name):
|
def on_post(self, req, resp, project_id, queue_name):
|
||||||
LOG.debug(u'Messages collection POST - queue: %(queue)s, '
|
LOG.debug(u'Messages collection POST - queue: %(queue)s, '
|
||||||
u'project: %(project)s',
|
u'project: %(project)s',
|
||||||
@ -213,6 +215,7 @@ class CollectionResource(object):
|
|||||||
resp.body = utils.to_json(body)
|
resp.body = utils.to_json(body)
|
||||||
resp.status = falcon.HTTP_201
|
resp.status = falcon.HTTP_201
|
||||||
|
|
||||||
|
@acl.enforce("messages:get_all")
|
||||||
def on_get(self, req, resp, project_id, queue_name):
|
def on_get(self, req, resp, project_id, queue_name):
|
||||||
LOG.debug(u'Messages collection GET - queue: %(queue)s, '
|
LOG.debug(u'Messages collection GET - queue: %(queue)s, '
|
||||||
u'project: %(project)s',
|
u'project: %(project)s',
|
||||||
@ -237,6 +240,7 @@ class CollectionResource(object):
|
|||||||
resp.body = utils.to_json(response)
|
resp.body = utils.to_json(response)
|
||||||
# status defaults to 200
|
# status defaults to 200
|
||||||
|
|
||||||
|
@acl.enforce("messages:delete_all")
|
||||||
def on_delete(self, req, resp, project_id, queue_name):
|
def on_delete(self, req, resp, project_id, queue_name):
|
||||||
LOG.debug(u'Messages collection DELETE - queue: %(queue)s, '
|
LOG.debug(u'Messages collection DELETE - queue: %(queue)s, '
|
||||||
u'project: %(project)s',
|
u'project: %(project)s',
|
||||||
@ -306,6 +310,7 @@ class ItemResource(object):
|
|||||||
def __init__(self, message_controller):
|
def __init__(self, message_controller):
|
||||||
self._message_controller = message_controller
|
self._message_controller = message_controller
|
||||||
|
|
||||||
|
@acl.enforce("messages:get")
|
||||||
def on_get(self, req, resp, project_id, queue_name, message_id):
|
def on_get(self, req, resp, project_id, queue_name, message_id):
|
||||||
LOG.debug(u'Messages item GET - message: %(message)s, '
|
LOG.debug(u'Messages item GET - message: %(message)s, '
|
||||||
u'queue: %(queue)s, project: %(project)s',
|
u'queue: %(queue)s, project: %(project)s',
|
||||||
@ -336,6 +341,7 @@ class ItemResource(object):
|
|||||||
resp.body = utils.to_json(message)
|
resp.body = utils.to_json(message)
|
||||||
# status defaults to 200
|
# status defaults to 200
|
||||||
|
|
||||||
|
@acl.enforce("messages:delete")
|
||||||
def on_delete(self, req, resp, project_id, queue_name, message_id):
|
def on_delete(self, req, resp, project_id, queue_name, message_id):
|
||||||
|
|
||||||
LOG.debug(u'Messages item DELETE - message: %(message)s, '
|
LOG.debug(u'Messages item DELETE - message: %(message)s, '
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
|
|
||||||
import falcon
|
import falcon
|
||||||
|
|
||||||
|
from zaqar.transport import acl
|
||||||
|
|
||||||
|
|
||||||
class Resource(object):
|
class Resource(object):
|
||||||
|
|
||||||
@ -22,9 +24,11 @@ class Resource(object):
|
|||||||
def __init__(self, driver):
|
def __init__(self, driver):
|
||||||
self._driver = driver
|
self._driver = driver
|
||||||
|
|
||||||
|
@acl.enforce("ping:get")
|
||||||
def on_get(self, req, resp, **kwargs):
|
def on_get(self, req, resp, **kwargs):
|
||||||
resp.status = (falcon.HTTP_204 if self._driver.is_alive()
|
resp.status = (falcon.HTTP_204 if self._driver.is_alive()
|
||||||
else falcon.HTTP_503)
|
else falcon.HTTP_503)
|
||||||
|
|
||||||
|
@acl.enforce("ping:get")
|
||||||
def on_head(self, req, resp, **kwargs):
|
def on_head(self, req, resp, **kwargs):
|
||||||
resp.status = falcon.HTTP_204
|
resp.status = falcon.HTTP_204
|
||||||
|
@ -45,6 +45,7 @@ from zaqar.common import utils as common_utils
|
|||||||
from zaqar.i18n import _
|
from zaqar.i18n import _
|
||||||
from zaqar.storage import errors
|
from zaqar.storage import errors
|
||||||
from zaqar.storage import utils as storage_utils
|
from zaqar.storage import utils as storage_utils
|
||||||
|
from zaqar.transport import acl
|
||||||
from zaqar.transport import utils as transport_utils
|
from zaqar.transport import utils as transport_utils
|
||||||
from zaqar.transport.wsgi import errors as wsgi_errors
|
from zaqar.transport.wsgi import errors as wsgi_errors
|
||||||
from zaqar.transport.wsgi import utils as wsgi_utils
|
from zaqar.transport.wsgi import utils as wsgi_utils
|
||||||
@ -61,6 +62,7 @@ class Listing(object):
|
|||||||
def __init__(self, pools_controller):
|
def __init__(self, pools_controller):
|
||||||
self._ctrl = pools_controller
|
self._ctrl = pools_controller
|
||||||
|
|
||||||
|
@acl.enforce("pools:get_all")
|
||||||
def on_get(self, request, response, project_id):
|
def on_get(self, request, response, project_id):
|
||||||
"""Returns a pool listing as objects embedded in an object:
|
"""Returns a pool listing as objects embedded in an object:
|
||||||
|
|
||||||
@ -128,6 +130,7 @@ class Resource(object):
|
|||||||
'create': validator_type(schema.create)
|
'create': validator_type(schema.create)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@acl.enforce("pools:get")
|
||||||
def on_get(self, request, response, project_id, pool):
|
def on_get(self, request, response, project_id, pool):
|
||||||
"""Returns a JSON object for a single pool entry:
|
"""Returns a JSON object for a single pool entry:
|
||||||
|
|
||||||
@ -153,6 +156,7 @@ class Resource(object):
|
|||||||
|
|
||||||
response.body = transport_utils.to_json(data)
|
response.body = transport_utils.to_json(data)
|
||||||
|
|
||||||
|
@acl.enforce("pools:create")
|
||||||
def on_put(self, request, response, project_id, pool):
|
def on_put(self, request, response, project_id, pool):
|
||||||
"""Registers a new pool. Expects the following input:
|
"""Registers a new pool. Expects the following input:
|
||||||
|
|
||||||
@ -181,6 +185,7 @@ class Resource(object):
|
|||||||
response.status = falcon.HTTP_201
|
response.status = falcon.HTTP_201
|
||||||
response.location = request.path
|
response.location = request.path
|
||||||
|
|
||||||
|
@acl.enforce("pools:delete")
|
||||||
def on_delete(self, request, response, project_id, pool):
|
def on_delete(self, request, response, project_id, pool):
|
||||||
"""Deregisters a pool.
|
"""Deregisters a pool.
|
||||||
|
|
||||||
@ -201,6 +206,7 @@ class Resource(object):
|
|||||||
|
|
||||||
response.status = falcon.HTTP_204
|
response.status = falcon.HTTP_204
|
||||||
|
|
||||||
|
@acl.enforce("pools:update")
|
||||||
def on_patch(self, request, response, project_id, pool):
|
def on_patch(self, request, response, project_id, pool):
|
||||||
"""Allows one to update a pool's weight, uri, and/or options.
|
"""Allows one to update a pool's weight, uri, and/or options.
|
||||||
|
|
||||||
|
@ -19,12 +19,12 @@ import six
|
|||||||
|
|
||||||
from zaqar.i18n import _
|
from zaqar.i18n import _
|
||||||
from zaqar.storage import errors as storage_errors
|
from zaqar.storage import errors as storage_errors
|
||||||
|
from zaqar.transport import acl
|
||||||
from zaqar.transport import utils
|
from zaqar.transport import utils
|
||||||
from zaqar.transport import validation
|
from zaqar.transport import validation
|
||||||
from zaqar.transport.wsgi import errors as wsgi_errors
|
from zaqar.transport.wsgi import errors as wsgi_errors
|
||||||
from zaqar.transport.wsgi import utils as wsgi_utils
|
from zaqar.transport.wsgi import utils as wsgi_utils
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@ -37,6 +37,7 @@ class ItemResource(object):
|
|||||||
self._queue_controller = queue_controller
|
self._queue_controller = queue_controller
|
||||||
self._message_controller = message_controller
|
self._message_controller = message_controller
|
||||||
|
|
||||||
|
@acl.enforce("queues:get")
|
||||||
def on_get(self, req, resp, project_id, queue_name):
|
def on_get(self, req, resp, project_id, queue_name):
|
||||||
LOG.debug(u'Queue metadata GET - queue: %(queue)s, '
|
LOG.debug(u'Queue metadata GET - queue: %(queue)s, '
|
||||||
u'project: %(project)s',
|
u'project: %(project)s',
|
||||||
@ -58,6 +59,7 @@ class ItemResource(object):
|
|||||||
resp.body = utils.to_json(resp_dict)
|
resp.body = utils.to_json(resp_dict)
|
||||||
# status defaults to 200
|
# status defaults to 200
|
||||||
|
|
||||||
|
@acl.enforce("queues:create")
|
||||||
def on_put(self, req, resp, project_id, queue_name):
|
def on_put(self, req, resp, project_id, queue_name):
|
||||||
LOG.debug(u'Queue item PUT - queue: %(queue)s, '
|
LOG.debug(u'Queue item PUT - queue: %(queue)s, '
|
||||||
u'project: %(project)s',
|
u'project: %(project)s',
|
||||||
@ -93,6 +95,7 @@ class ItemResource(object):
|
|||||||
resp.status = falcon.HTTP_201 if created else falcon.HTTP_204
|
resp.status = falcon.HTTP_201 if created else falcon.HTTP_204
|
||||||
resp.location = req.path
|
resp.location = req.path
|
||||||
|
|
||||||
|
@acl.enforce("queues:delete")
|
||||||
def on_delete(self, req, resp, project_id, queue_name):
|
def on_delete(self, req, resp, project_id, queue_name):
|
||||||
LOG.debug(u'Queue item DELETE - queue: %(queue)s, '
|
LOG.debug(u'Queue item DELETE - queue: %(queue)s, '
|
||||||
u'project: %(project)s',
|
u'project: %(project)s',
|
||||||
@ -116,6 +119,7 @@ class CollectionResource(object):
|
|||||||
self._queue_controller = queue_controller
|
self._queue_controller = queue_controller
|
||||||
self._validate = validate
|
self._validate = validate
|
||||||
|
|
||||||
|
@acl.enforce("queues:get_all")
|
||||||
def on_get(self, req, resp, project_id):
|
def on_get(self, req, resp, project_id):
|
||||||
LOG.debug(u'Queue collection GET - project: %(project)s',
|
LOG.debug(u'Queue collection GET - project: %(project)s',
|
||||||
{'project': project_id})
|
{'project': project_id})
|
||||||
|
@ -19,6 +19,7 @@ import six
|
|||||||
|
|
||||||
from zaqar.i18n import _
|
from zaqar.i18n import _
|
||||||
from zaqar.storage import errors as storage_errors
|
from zaqar.storage import errors as storage_errors
|
||||||
|
from zaqar.transport import acl
|
||||||
from zaqar.transport import utils
|
from zaqar.transport import utils
|
||||||
from zaqar.transport import validation
|
from zaqar.transport import validation
|
||||||
from zaqar.transport.wsgi import errors as wsgi_errors
|
from zaqar.transport.wsgi import errors as wsgi_errors
|
||||||
@ -36,6 +37,7 @@ class ItemResource(object):
|
|||||||
self._validate = validate
|
self._validate = validate
|
||||||
self._subscription_controller = subscription_controller
|
self._subscription_controller = subscription_controller
|
||||||
|
|
||||||
|
@acl.enforce("subscription:get")
|
||||||
def on_get(self, req, resp, project_id, queue_name, subscription_id):
|
def on_get(self, req, resp, project_id, queue_name, subscription_id):
|
||||||
LOG.debug(u'Subscription GET - subscription id: %(subscription_id)s,'
|
LOG.debug(u'Subscription GET - subscription id: %(subscription_id)s,'
|
||||||
u' project: %(project)s, queue: %(queue)s',
|
u' project: %(project)s, queue: %(queue)s',
|
||||||
@ -58,6 +60,7 @@ class ItemResource(object):
|
|||||||
resp.body = utils.to_json(resp_dict)
|
resp.body = utils.to_json(resp_dict)
|
||||||
# status defaults to 200
|
# status defaults to 200
|
||||||
|
|
||||||
|
@acl.enforce("subscription:delete")
|
||||||
def on_delete(self, req, resp, project_id, queue_name, subscription_id):
|
def on_delete(self, req, resp, project_id, queue_name, subscription_id):
|
||||||
LOG.debug(u'Subscription DELETE - '
|
LOG.debug(u'Subscription DELETE - '
|
||||||
u'subscription id: %(subscription_id)s,'
|
u'subscription id: %(subscription_id)s,'
|
||||||
@ -76,6 +79,7 @@ class ItemResource(object):
|
|||||||
|
|
||||||
resp.status = falcon.HTTP_204
|
resp.status = falcon.HTTP_204
|
||||||
|
|
||||||
|
@acl.enforce("subscription:update")
|
||||||
def on_patch(self, req, resp, project_id, queue_name, subscription_id):
|
def on_patch(self, req, resp, project_id, queue_name, subscription_id):
|
||||||
LOG.debug(u'Subscription PATCH - subscription id: %(subscription_id)s,'
|
LOG.debug(u'Subscription PATCH - subscription id: %(subscription_id)s,'
|
||||||
u' project: %(project)s, queue: %(queue)s',
|
u' project: %(project)s, queue: %(queue)s',
|
||||||
@ -117,6 +121,7 @@ class CollectionResource(object):
|
|||||||
self._subscription_controller = subscription_controller
|
self._subscription_controller = subscription_controller
|
||||||
self._validate = validate
|
self._validate = validate
|
||||||
|
|
||||||
|
@acl.enforce("subscription:get_all")
|
||||||
def on_get(self, req, resp, project_id, queue_name):
|
def on_get(self, req, resp, project_id, queue_name):
|
||||||
LOG.debug(u'Subscription collection GET - project: %(project)s, '
|
LOG.debug(u'Subscription collection GET - project: %(project)s, '
|
||||||
u'queue: %(queue)s',
|
u'queue: %(queue)s',
|
||||||
@ -162,6 +167,7 @@ class CollectionResource(object):
|
|||||||
resp.body = utils.to_json(response_body)
|
resp.body = utils.to_json(response_body)
|
||||||
# status defaults to 200
|
# status defaults to 200
|
||||||
|
|
||||||
|
@acl.enforce("subscription:create")
|
||||||
def on_post(self, req, resp, project_id, queue_name):
|
def on_post(self, req, resp, project_id, queue_name):
|
||||||
LOG.debug(u'Subscription item POST - project: %(project)s, '
|
LOG.debug(u'Subscription item POST - project: %(project)s, '
|
||||||
u'queue: %(queue)s',
|
u'queue: %(queue)s',
|
||||||
|
Loading…
Reference in New Issue
Block a user