User with creator role can delete his/her own secret and container

Modified policy and tests to verify this change.

As per this change, user with 'creator' role can delete a secret or
a container as long as that user has initially created that secret
or container.

There is still a difference between 'admin' role and 'creator' role
behavior around delete operation. With this change, users with 'creator'
role cannot delete any other user's secret/container in same project
while user with 'admin' role can do that.

Updated role docs to reflect this behavior.

Change-Id: I53e5529ed34ac4acc76348ca0431cb3de7934b6d
This commit is contained in:
Arun Kant 2016-05-02 13:11:41 -07:00
parent e994d4dd91
commit ce6336f393
10 changed files with 87 additions and 22 deletions

View File

@ -648,11 +648,24 @@ class WhenTestingSecretResource(BaseTestCase):
project_id=self.external_project_id)
def test_should_raise_delete_secret(self):
self._assert_fail_rbac([None, 'audit', 'observer', 'creator', 'bogus'],
self._invoke_on_delete)
"""A non-admin user cannot delete other user's secret.
User id is different from initial user who has created the secret.
"""
self._assert_fail_rbac([None, 'audit', 'observer', 'creator', 'bogus'],
self._invoke_on_delete,
user_id=self.user_id,
project_id=self.external_project_id)
def test_should_pass_delete_secret_for_owner(self):
"""Non-admin user can delete his/her own secret
Secret creator_id should match with token user to establish ownership.
"""
self._assert_pass_rbac(['creator'], self._invoke_on_delete,
user_id=self.creator_user_id,
project_id=self.external_project_id)
# @mock.patch.object(secrets.SecretController, 'get_acl_tuple',
# return_value=(None, None))
def _invoke_on_get(self):
self.resource.on_get(self.req, self.resp)
@ -883,8 +896,24 @@ class WhenTestingContainerResource(BaseTestCase):
project_id=self.external_project_id)
def test_should_raise_delete_container(self):
"""A non-admin user cannot delete other user's container.
User id is different from initial user who has created the container.
"""
self._assert_fail_rbac([None, 'audit', 'observer', 'creator', 'bogus'],
self._invoke_on_delete)
self._invoke_on_delete,
user_id=self.user_id,
project_id=self.external_project_id)
def test_should_pass_delete_container_for_owner(self):
"""Non-admin user can delete his/her own container
Container creator_id should match with token user to establish
ownership.
"""
self._assert_pass_rbac(['creator'], self._invoke_on_delete,
user_id=self.creator_user_id,
project_id=self.external_project_id)
def _invoke_on_get(self):
self.resource.on_get(self.req, self.resp)

View File

@ -104,6 +104,15 @@ if [[ "$ENABLED_SERVICES" =~ "barbican" ]]; then
--user "$USER_ID" \
--project "$PROJECT_A_ID" \
"$ROLE_CREATOR_ID"
# Adding second creator user in project_a
USER_ID=$(openstack user create \
--password "$PASSWORD" \
--email "creator2_a@example.net" \
"project_a_creator_2" -f value -c id)
openstack role add \
--user "$USER_ID" \
--project "$PROJECT_A_ID" \
"$ROLE_CREATOR_ID"
#
# Setup RBAC Observer of Project A
#

View File

@ -278,6 +278,15 @@ function create_barbican_accounts {
--user "$USER_ID" \
--project "$PROJECT_A_ID" \
"$ROLE_CREATOR_ID"
# Adding second creator user in project_a
USER_ID=$(openstack user create \
--password "$PASSWORD" \
--email "creator2_a@example.net" \
"project_a_creator_2" -f value -c id)
openstack role add \
--user "$USER_ID" \
--project "$PROJECT_A_ID" \
"$ROLE_CREATOR_ID"
#
# Setup RBAC Observer of Project A
#

View File

@ -5,8 +5,8 @@ Access Control
Role Based Access Control (RBAC)
--------------------------------
Like many other services, the Key Manager service supports the protection of
its APIs by enforcing policy rules defined in a policy file. The Key Manager
Like many other services, the Key Manager service supports the protection of its
APIs by enforcing policy rules defined in a policy file. The Key Manager
service stores a reference to a policy JSON file in its configuration file,
:file:`/etc/barbican/barbican.conf`. Typically this file is named
``policy.json`` and it is stored in :file:`/etc/barbican/policy.json`.
@ -58,9 +58,11 @@ admin
by the project for which the admin role is scoped.
creator
Users with this role are allowed to create new resources but are not
allowed to delete any existing resources. They are also allowed full
access to existing secrets owned by the project in scope.
Users with this role are allowed to create new resources and can only
delete resources which are originally created (owned) by them. Users with
this role cannot delete other user's resources managed within same project.
They are also allowed full access to existing secrets owned by the project
in scope.
observer
Users with this role are allowed to access to existing resources but are
@ -73,11 +75,11 @@ audit
Access Control List API
-----------------------
There are some limitations that result from scoping ownership of a secret
at the project level. For example, there is no easy way for a user to upload
a secret for which only they have access. There is also no easy way to grant
a user access to only a single secret.
There are some limitations that result from scoping ownership of a secret at the
project level. For example, there is no easy way for a user to upload a secret
for which only they have access. There is also no easy way to grant a user
access to only a single secret.
To address this limitations the Key Manager service includes an Access
Control List (ACL) API. For full details see the
To address this limitations the Key Manager service includes an Access Control
List (ACL) API. For full details see the
`ACL API User Guide <http://developer.openstack.org/api-guide/key-manager/acls.html>`__

View File

@ -24,6 +24,8 @@ admin_a=project_a_admin
admin_a_password=barbican
creator_a=project_a_creator
creator_a_password=barbican
creator_a_2=project_a_creator_2
creator_a_2_password=barbican
observer_a=project_a_observer
observer_a_password=barbican
auditor_a=project_a_auditor

View File

@ -30,7 +30,7 @@
"secret:decrypt": "rule:secret_decrypt_non_private_read or rule:secret_project_creator or rule:secret_project_admin or rule:secret_acl_read",
"secret:get": "rule:secret_non_private_read or rule:secret_project_creator or rule:secret_project_admin or rule:secret_acl_read",
"secret:put": "rule:admin_or_creator and rule:secret_project_match",
"secret:delete": "rule:admin and rule:secret_project_match",
"secret:delete": "rule:secret_project_admin or rule:secret_project_creator",
"secrets:post": "rule:admin_or_creator",
"secrets:get": "rule:all_but_audit",
"orders:post": "rule:admin_or_creator",
@ -45,7 +45,7 @@
"containers:post": "rule:admin_or_creator",
"containers:get": "rule:all_but_audit",
"container:get": "rule:container_non_private_read or rule:container_project_creator or rule:container_project_admin or rule:container_acl_read",
"container:delete": "rule:admin",
"container:delete": "rule:container_project_admin or rule:container_project_creator",
"container_secret:post": "rule:admin",
"container_secret:delete": "rule:admin",
"transport_key:get": "rule:all_users",

View File

@ -24,6 +24,7 @@ from functionaltests.common import config
CONF = config.get_config()
admin_a = CONF.rbac_users.admin_a
creator_a = CONF.rbac_users.creator_a
creator_a_2 = CONF.rbac_users.creator_a_2
observer_a = CONF.rbac_users.observer_a
auditor_a = CONF.rbac_users.auditor_a
@ -55,8 +56,10 @@ test_data_rbac_update_container = {
test_data_rbac_delete_container = {
'with_admin_a': {'user': admin_a, 'admin': admin_a,
'expected_return': 204},
'with_creator_a': {'user': creator_a, 'admin': admin_a,
'expected_return': 403},
'with_creator_a': {'user': creator_a, 'admin': creator_a,
'expected_return': 204},
'with_creator_a_2': {'user': creator_a_2, 'admin': creator_a,
'expected_return': 403},
'with_observer_a': {'user': observer_a, 'admin': admin_a,
'expected_return': 403},
'with_auditor_a': {'user': auditor_a, 'admin': admin_a,

View File

@ -24,6 +24,7 @@ from functionaltests.common import config
CONF = config.get_config()
admin_a = CONF.rbac_users.admin_a
creator_a = CONF.rbac_users.creator_a
creator_a_2 = CONF.rbac_users.creator_a_2
observer_a = CONF.rbac_users.observer_a
auditor_a = CONF.rbac_users.auditor_a
@ -86,8 +87,10 @@ test_data_rbac_get_list_of_secrets = {
test_data_rbac_delete_secret = {
'with_admin_a': {'user': admin_a, 'admin': admin_a,
'expected_return': 204},
'with_creator_a': {'user': creator_a, 'admin': admin_a,
'expected_return': 403},
'with_creator_a': {'user': creator_a, 'admin': creator_a,
'expected_return': 204},
'with_creator_a_2': {'user': creator_a_2, 'admin': creator_a,
'expected_return': 403},
'with_observer_a': {'user': observer_a, 'admin': admin_a,
'expected_return': 403},
'with_auditor_a': {'user': auditor_a, 'admin': admin_a,

View File

@ -65,6 +65,12 @@ class BarbicanClient(object):
username=CONF.rbac_users.creator_a,
password=CONF.rbac_users.creator_a_password,
project_name=CONF.rbac_users.project_a)
self._auth[CONF.rbac_users.creator_a_2] = auth.FunctionalTestAuth(
endpoint=CONF.identity.uri,
version=CONF.identity.version,
username=CONF.rbac_users.creator_a_2,
password=CONF.rbac_users.creator_a_2_password,
project_name=CONF.rbac_users.project_a)
self._auth[CONF.rbac_users.observer_a] = auth.FunctionalTestAuth(
endpoint=CONF.identity.uri,
version=CONF.identity.version,

View File

@ -48,6 +48,8 @@ def setup_config(config_file=''):
cfg.StrOpt('admin_a_password', default='barbican', secret=True),
cfg.StrOpt('creator_a', default='project_a_creator'),
cfg.StrOpt('creator_a_password', default='barbican', secret=True),
cfg.StrOpt('creator_a_2', default='project_a_creator_2'),
cfg.StrOpt('creator_a_2_password', default='barbican', secret=True),
cfg.StrOpt('observer_a', default='project_a_observer'),
cfg.StrOpt('observer_a_password', default='barbican', secret=True),
cfg.StrOpt('auditor_a', default='project_a_auditor'),