summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2015-10-03 09:06:05 +0000
committerGerrit Code Review <review@openstack.org>2015-10-03 09:06:05 +0000
commit68adf0cecf9b38bdb4972030e9dd72839aab95e2 (patch)
tree0062adceb08455518b402ca493ce92344ff3c2b1
parente395a4d9ef9d89e65456dd0a4d8d2d0cc3bd73e2 (diff)
parentd083e1ed751b44a72bc8610515ebd09710acd964 (diff)
downloadpython-barbicanclient-68adf0cecf9b38bdb4972030e9dd72839aab95e2.tar.gz
Merge "Part 2: Adding ACL support for CLI commands and docs"
-rw-r--r--README.rst41
-rw-r--r--barbicanclient/barbican_cli/acls.py261
-rw-r--r--barbicanclient/containers.py11
-rw-r--r--barbicanclient/secrets.py10
-rw-r--r--barbicanclient/tests/test_containers.py26
-rw-r--r--barbicanclient/tests/test_secrets.py25
-rw-r--r--doc/source/cli_usage.rst272
-rw-r--r--doc/source/reference.rst14
-rw-r--r--doc/source/usage.rst223
-rw-r--r--setup.cfg6
10 files changed, 840 insertions, 49 deletions
diff --git a/README.rst b/README.rst
index b5e6d3c..5bf0a59 100644
--- a/README.rst
+++ b/README.rst
@@ -8,7 +8,9 @@ Key Management API. There is a Python library for accessing the API
Installation
------------
-The client is `pip installable <https://pypi.python.org/pypi/python-barbicanclient>`__ as follows:
+The client is
+`pip installable <https://pypi.python.org/pypi/python-barbicanclient>`__ as
+follows:
.. code:: console
@@ -18,7 +20,8 @@ The client is `pip installable <https://pypi.python.org/pypi/python-barbicanclie
barbicanclient - Python Library
-------------------------------
-The full api is `documented in the official OpenStack documentation site <http://docs.openstack.org/developer/python-barbicanclient>`__.
+The full api is
+`documented in the official OpenStack documentation site <http://docs.openstack.org/developer/python-barbicanclient>`__.
Here's an example of storing a secret in barbican using the python library
@@ -76,7 +79,8 @@ with keystone authentication:
barbican - Command Line Client
------------------------------
-The command line client is self-documenting. Use the --help flag to access the usage options
+The command line client is self-documenting. Use the --help flag to access the
+usage options
.. code:: console
@@ -158,21 +162,26 @@ The command line client is self-documenting. Use the --help flag to access the u
See "barbican help COMMAND" for help on a specific command.
Commands:
- complete print bash completion command
+ acl get Retrieve ACLs for a secret or container by providing its href.
+ acl delete Delete ACLs for a secret or container as identified by its href.
+ acl submit Submit ACL on a secret or container as identified by its href.
+ acl user add Add ACL users to a secret or container as identified by its href.
+ acl user remove Remove ACL users from a secret or container as identified by its href.
+ complete print bash completion command
container create Store a container in Barbican.
container delete Delete a container by providing its href.
- container get Retrieve a container by providing its URI.
- container list List containers.
- help print detailed help for another command
- order create Create a new order.
- order delete Delete an order by providing its href.
- order get Retrieve an order by providing its URI.
- order list List orders.
- secret delete Delete an secret by providing its href.
- secret get Retrieve a secret by providing its URI.
- secret list List secrets.
- secret store Store a secret in Barbican.
- secret update Update a secret with no payload in Barbican.
+ container get Retrieve a container by providing its URI.
+ container list List containers.
+ help print detailed help for another command
+ order create Create a new order.
+ order delete Delete an order by providing its href.
+ order get Retrieve an order by providing its URI.
+ order list List orders.
+ secret delete Delete an secret by providing its href.
+ secret get Retrieve a secret by providing its URI.
+ secret list List secrets.
+ secret store Store a secret in Barbican
+ secret update Update a secret with no payload in Barbican.
* License: Apache License, Version 2.0
* Documentation: http://docs.openstack.org/developer/python-barbicanclient
diff --git a/barbicanclient/barbican_cli/acls.py b/barbicanclient/barbican_cli/acls.py
new file mode 100644
index 0000000..938ba09
--- /dev/null
+++ b/barbicanclient/barbican_cli/acls.py
@@ -0,0 +1,261 @@
+# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
+#
+# 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.
+"""
+Command-line interface sub-commands related to ACLs.
+"""
+from cliff import command
+from cliff import lister
+
+from barbicanclient import acls
+
+
+class ArgMixin(object):
+ "Mixin class for CLI arguments and validation"
+
+ def add_ref_arg(self, parser):
+ parser.add_argument('URI',
+ help='The URI reference for the secret or '
+ 'container.')
+
+ def add_per_acl_args(self, parser):
+ parser.add_argument('--user', '-u',
+ action='append', default=None, nargs='?',
+ dest='users',
+ help='Keystone userid(s) for ACL.')
+
+ group = parser.add_mutually_exclusive_group()
+ group.add_argument('--project-access',
+ dest='project_access',
+ action='store_true',
+ default=None,
+ help='Flag to enable project access behavior.')
+ group.add_argument('--no-project-access',
+ dest='project_access',
+ action='store_false',
+ help='Flag to disable project access behavior.')
+
+ parser.add_argument('--operation-type', '-o',
+ default=acls.DEFAULT_OPERATION_TYPE,
+ dest='operation_type', choices=['read'],
+ help='Type of Barbican operation ACL is set for')
+
+ def create_blank_acl_entity_from_uri(self, acl_manager, args):
+ """Validates URI argument and creates blank ACL entity"""
+
+ entity = acl_manager.create(args.URI)
+ entity.validate_input_ref()
+ return entity
+
+ def create_acl_entity_from_args(self, acl_manager, args):
+ blank_entity = self.create_blank_acl_entity_from_uri(acl_manager, args)
+
+ users = args.users
+ if users is None:
+ users = []
+ else:
+ users = [user for user in users if user is not None]
+ entity = acl_manager.create(
+ entity_ref=blank_entity.entity_ref, users=users,
+ project_access=args.project_access,
+ operation_type=args.operation_type)
+ return entity
+
+ def get_acls_as_lister(self, acl_entity):
+ """Gets per operation ACL data in expected format for lister command"""
+
+ map(lambda acl: setattr(acl, 'columns', acl_entity.columns),
+ acl_entity.operation_acls)
+
+ return acls.ACLFormatter._list_objects(acl_entity.operation_acls)
+
+
+class DeleteACLs(command.Command, ArgMixin):
+ """Delete ACLs for a secret or container as identified by its href."""
+
+ def get_parser(self, prog_name):
+ parser = super(DeleteACLs, self).get_parser(prog_name)
+ self.add_ref_arg(parser)
+ return parser
+
+ def take_action(self, args):
+ """Deletes a secret or container ACL settings from Barbican.
+
+ This action removes all of defined ACL settings for a secret or
+ container in Barbican.
+ """
+ blank_entity = self.create_blank_acl_entity_from_uri(
+ self.app.client_manager.key_manager.acls, args)
+ blank_entity.remove()
+
+
+class GetACLs(lister.Lister, ArgMixin):
+ """Retrieve ACLs for a secret or container by providing its href."""
+
+ def get_parser(self, prog_name):
+ parser = super(GetACLs, self).get_parser(prog_name)
+ self.add_ref_arg(parser)
+ return parser
+
+ def take_action(self, args):
+ """Retrieves a secret or container ACL settings from Barbican.
+
+ This action provides list of all ACL settings for a secret or container
+ in Barbican.
+
+ :returns: List of objects for valid entity_ref
+ :rtype: :class:`barbicanclient.acls.SecretACL` or
+ :class:`barbicanclient.acls.ContainerACL`
+ :raises barbicanclient.exceptions.HTTPAuthError: 401 Responses
+ :raises barbicanclient.exceptions.HTTPClientError: 4xx Responses
+ :raises barbicanclient.exceptions.HTTPServerError: 5xx Responses
+ """
+ blank_entity = self.create_blank_acl_entity_from_uri(
+ self.app.client_manager.key_manager.acls, args)
+ acl_entity = self.app.client_manager.key_manager.acls.get(
+ blank_entity.entity_ref)
+ return self.get_acls_as_lister(acl_entity)
+
+
+class SubmitACL(lister.Lister, ArgMixin):
+ """Submit ACL on a secret or container as identified by its href."""
+
+ def get_parser(self, prog_name):
+ parser = super(SubmitACL, self).get_parser(prog_name)
+ self.add_ref_arg(parser)
+ self.add_per_acl_args(parser)
+ return parser
+
+ def take_action(self, args):
+ """Submit complete secret or container ACL settings to Barbican
+
+ This action replaces existing ACL setting on server with provided
+ inputs.
+
+ :returns: List of objects for valid entity_ref
+ :rtype: :class:`barbicanclient.acls.SecretACL` or
+ :class:`barbicanclient.acls.ContainerACL`
+ :raises barbicanclient.exceptions.HTTPAuthError: 401 Responses
+ :raises barbicanclient.exceptions.HTTPClientError: 4xx Responses
+ :raises barbicanclient.exceptions.HTTPServerError: 5xx Responses
+ """
+ entity = self.create_acl_entity_from_args(
+ self.app.client_manager.key_manager.acls, args)
+
+ entity.submit()
+ entity.load_acls_data() # read ACL settings from server
+ return self.get_acls_as_lister(entity)
+
+
+class AddACLUsers(lister.Lister, ArgMixin):
+ """Add ACL users to a secret or container as identified by its href."""
+
+ def get_parser(self, prog_name):
+ parser = super(AddACLUsers, self).get_parser(prog_name)
+ self.add_ref_arg(parser)
+ self.add_per_acl_args(parser)
+ return parser
+
+ def take_action(self, args):
+ """Add users to a secret or a container ACL defined in Barbican
+
+ Provided users are added to existing ACL users if there. If input users
+ is None or empty list, no change is made in existing ACL users list.
+ If input project_access flag is None, then no change is made in
+ existing project access behavior.
+
+ :returns: List of objects for valid entity_ref
+ :rtype: :class:`barbicanclient.acls.SecretACL` or
+ :class:`barbicanclient.acls.ContainerACL`
+ :raises barbicanclient.exceptions.HTTPAuthError: 401 Responses
+ :raises barbicanclient.exceptions.HTTPClientError: 4xx Responses
+ :raises barbicanclient.exceptions.HTTPServerError: 5xx Responses
+ """
+
+ input_entity = self.create_acl_entity_from_args(
+ self.app.client_manager.key_manager.acls, args)
+
+ server_entity = self.app.client_manager.key_manager.acls.get(
+ input_entity.entity_ref)
+
+ for input_acl in input_entity.operation_acls:
+ server_acl = server_entity.get(input_acl.operation_type)
+ if server_acl:
+ if input_acl.project_access is not None:
+ server_acl.project_access = input_acl.project_access
+ # if input data has users, add it to existing users list
+ if input_acl.users is not None:
+ server_acl.users.extend(input_acl.users)
+ # provided input operation_type does not exist in server entity
+ else:
+ server_entity.add_operation_acl(
+ users=input_acl.users,
+ project_access=input_acl.project_access,
+ operation_type=input_acl.operation_type)
+
+ server_entity.submit() # apply changes to server
+ server_entity.load_acls_data()
+ return self.get_acls_as_lister(server_entity)
+
+
+class RemoveACLUsers(lister.Lister, ArgMixin):
+ """Remove ACL users from a secret or container as identified by its href.
+
+ """
+
+ def get_parser(self, prog_name):
+ parser = super(RemoveACLUsers, self).get_parser(prog_name)
+ self.add_ref_arg(parser)
+ self.add_per_acl_args(parser)
+ return parser
+
+ def take_action(self, args):
+
+ """Remove users from a secret or a container ACL defined in Barbican
+
+ Provided users are removed from existing ACL users if there. If any of
+ input users are not part of ACL users, they are simply ignored.
+ If input project_access flag is None, then no change is made in
+ existing project access behavior.
+
+ :returns: List of objects for valid entity_ref
+ :rtype: :class:`barbicanclient.acls.SecretACL` or
+ :class:`barbicanclient.acls.ContainerACL`
+ :raises barbicanclient.exceptions.HTTPAuthError: 401 Responses
+ :raises barbicanclient.exceptions.HTTPClientError: 4xx Responses
+ :raises barbicanclient.exceptions.HTTPServerError: 5xx Responses
+ """
+ input_entity = self.create_acl_entity_from_args(
+ self.app.client_manager.key_manager.acls, args)
+
+ server_entity = self.app.client_manager.key_manager.acls.get(
+ input_entity.entity_ref)
+
+ for input_acl in input_entity.operation_acls:
+ server_acl = server_entity.get(input_acl.operation_type)
+ if server_acl:
+ if input_acl.project_access is not None:
+ server_acl.project_access = input_acl.project_access
+ # if input data has users, then remove matching one
+ # from server acl users
+ if input_acl.users is not None:
+ acl_users = server_acl.users
+ acl_users = set(acl_users).difference(input_acl.users)
+ del server_acl.users[:]
+ server_acl.users = acl_users
+
+ server_entity.submit() # apply changes to server
+ server_entity.load_acls_data()
+
+ return self.get_acls_as_lister(server_entity)
diff --git a/barbicanclient/containers.py b/barbicanclient/containers.py
index b318779..5cae098 100644
--- a/barbicanclient/containers.py
+++ b/barbicanclient/containers.py
@@ -18,8 +18,10 @@ import six
from oslo_utils.timeutils import parse_isotime
+from barbicanclient import acls as acl_manager
from barbicanclient import base
from barbicanclient import formatter
+
from barbicanclient import secrets as secret_manager
@@ -92,6 +94,8 @@ class Container(ContainerFormatter):
self._created = None
self._updated = None
self._status = None
+ self._acl_manager = acl_manager.ACLManager(api)
+ self._acls = None
def _initialize_secrets(self, secrets):
try:
@@ -139,6 +143,13 @@ class Container(ContainerFormatter):
return self._status
@property
+ def acls(self):
+ """Get ACL settings for this container."""
+ if self._container_ref and not self._acls:
+ self._acls = self._acl_manager.get(self.container_ref)
+ return self._acls
+
+ @property
def secret_refs(self):
if self._cached_secrets:
self._secret_refs = dict(
diff --git a/barbicanclient/secrets.py b/barbicanclient/secrets.py
index a8f5a4e..6b5ce9c 100644
--- a/barbicanclient/secrets.py
+++ b/barbicanclient/secrets.py
@@ -19,6 +19,7 @@ import logging
from oslo_utils.timeutils import parse_isotime
import six
+from barbicanclient import acls as acl_manager
from barbicanclient import base
from barbicanclient import exceptions
from barbicanclient import formatter
@@ -109,6 +110,8 @@ class Secret(SecretFormatter):
status=status,
creator_id=creator_id
)
+ self._acl_manager = acl_manager.ACLManager(api)
+ self._acls = None
@property
def secret_ref(self):
@@ -192,6 +195,13 @@ class Secret(SecretFormatter):
return None
return self._payload
+ @property
+ def acls(self):
+ """Get ACL settings for this secret."""
+ if self.secret_ref and not self._acls:
+ self._acls = self._acl_manager.get(self.secret_ref)
+ return self._acls
+
@name.setter
@immutable_after_save
def name(self, value):
diff --git a/barbicanclient/tests/test_containers.py b/barbicanclient/tests/test_containers.py
index b8a4db8..1327216 100644
--- a/barbicanclient/tests/test_containers.py
+++ b/barbicanclient/tests/test_containers.py
@@ -18,6 +18,7 @@ import json
import mock
from oslo_utils import timeutils
+from barbicanclient import acls
from barbicanclient.tests import test_client
from barbicanclient import base, containers, secrets
@@ -520,3 +521,28 @@ class WhenTestingContainers(test_client.BaseEntityResource):
self.responses.get(self.entity_base, json={'total': 1})
total = self.manager.total()
self.assertEqual(total, 1)
+
+ def test_should_get_acls_lazy(self):
+ data = self.container.get_dict(self.entity_href,
+ consumers=[self.container.consumer])
+ m = self.responses.get(self.entity_href, json=data)
+
+ acl_data = {'read': {'project-access': True, 'users': ['u2']}}
+ acl_ref = self.entity_href + '/acl'
+ n = self.responses.get(acl_ref, json=acl_data)
+
+ container = self.manager.get(container_ref=self.entity_href)
+ self.assertIsNotNone(container)
+
+ self.assertEqual(self.container.name, container.name)
+ # Verify GET was called for secret but for acl it was not called
+ self.assertTrue(m.called)
+ self.assertFalse(n.called)
+
+ # Check an attribute to trigger lazy-load
+ self.assertEqual(['u2'], container.acls.read.users)
+ self.assertTrue(container.acls.read.project_access)
+ self.assertIsInstance(container.acls, acls.ContainerACL)
+
+ # Verify the correct URL was used to make the GET call
+ self.assertEqual(acl_ref, n.last_request.url)
diff --git a/barbicanclient/tests/test_secrets.py b/barbicanclient/tests/test_secrets.py
index 4df946e..98f3975 100644
--- a/barbicanclient/tests/test_secrets.py
+++ b/barbicanclient/tests/test_secrets.py
@@ -18,6 +18,7 @@ import json
from oslo_utils import timeutils
from barbicanclient.tests import test_client
+from barbicanclient import acls
from barbicanclient import secrets, base, exceptions
@@ -235,6 +236,30 @@ class WhenTestingSecrets(test_client.BaseEntityResource):
# Verify the correct URL was used to make the GET call
self.assertEqual(self.entity_href, m.last_request.url)
+ def test_should_get_acls_lazy(self):
+ data = self.secret.get_dict(self.entity_href)
+ m = self.responses.get(self.entity_href, json=data)
+
+ acl_data = {'read': {'project-access': True, 'users': ['u1']}}
+ acl_ref = self.entity_href + '/acl'
+ n = self.responses.get(acl_ref, json=acl_data)
+
+ secret = self.manager.get(secret_ref=self.entity_href)
+ self.assertIsNotNone(secret)
+
+ self.assertEqual(self.secret.name, secret.name)
+ # Verify GET was called for secret but for acl it was not called
+ self.assertTrue(m.called)
+ self.assertFalse(n.called)
+
+ # Check an attribute to trigger lazy-load
+ self.assertEqual(['u1'], secret.acls.read.users)
+ self.assertTrue(secret.acls.read.project_access)
+ self.assertIsInstance(secret.acls, acls.SecretACL)
+
+ # Verify the correct URL was used to make the GET call
+ self.assertEqual(acl_ref, n.last_request.url)
+
def test_should_get_payload_only_when_content_type_is_set(self):
"""
DEPRECATION WARNING:
diff --git a/doc/source/cli_usage.rst b/doc/source/cli_usage.rst
index 2bbc0b0..e23692f 100644
--- a/doc/source/cli_usage.rst
+++ b/doc/source/cli_usage.rst
@@ -26,8 +26,8 @@ If you don't have variables saved to your environment or you wish to use
different credentials than those defined, any of the optional arguments listed
above may be passed to Barbican.
-Barbican takes a positional argument <entity>, which specifies whether you
-wish to operate on a secret or an order.
+Barbican takes a positional argument <entity>, which specifies whether you wish
+to operate on a secret or an order.
Secrets
-------
@@ -36,9 +36,9 @@ Secrets
$ barbican secret <action>
-A subcommand describing the action to be performed should follow.
-The subcommands are mostly the same for secrets and orders, although some
-optional arguments only apply to one or the other.
+A subcommand describing the action to be performed should follow. The
+subcommands are mostly the same for secrets and orders, although some optional
+arguments only apply to one or the other.
Subcommand actions that a user can take for secrets are:
@@ -179,3 +179,265 @@ Secret List
+-----------------------------------------------------------------------+------+----------------------------------+--------+-------------------------------------------+-----------+------------+------+------------+
| http://localhost:9311/v1/secrets/bb3d8c20-8ea5-4bfc-9645-c8da79c8b371 | None | 2015-04-15 20:37:37.501475+00:00 | ACTIVE | {u'default': u'application/octet-stream'} | aes | 256 | cbc | None |
+-----------------------------------------------------------------------+------+----------------------------------+--------+-------------------------------------------+-----------+------------+------+------------+
+
+
+ACLS
+----
+
+.. code-block:: bash
+
+ $ barbican acl <action>
+
+A subcommand describing the action to be performed should follow. The
+subcommands are mostly the same for secret and container ACLs.
+
+Subcommand actions that a user can take for ACLs are:
+
+.. code-block:: bash
+
+ acl delete Delete ACLs for a secret or container as identified by its href.
+ acl get Retrieve ACLs for a secret or container by providing its href.
+ acl submit Submit ACL on a secret or container as identified by its href.
+ acl user add Add ACL users to a secret or container as identified by its href.
+ acl user remove Remove ACL users from a secret or container as identified by its href.
+
+ACL **get** or **delete** subcommand, only takes secret or container href. All
+other ACL commands take additional arguments to specify ACL settings data.
+Please see help message for both cases of argument. Either secret ref or
+container ref is required for all of acl actions.
+
+.. code-block:: bash
+
+ $ barbican help acl get
+ usage: barbican acl get [-h] [-f {csv,table,value}] [-c COLUMN]
+ [--max-width <integer>]
+ [--quote {all,minimal,none,nonnumeric}]
+ URI
+
+ Retrieve ACLs for a secret or container by providing its href.
+
+ positional arguments:
+ URI The URI reference for the secret or container.
+
+ optional arguments:
+ -h, --help show this help message and exit
+
+ output formatters:
+ output formatter options
+
+ -f {csv,table,value}, --format {csv,table,value}
+ the output format, defaults to table
+ -c COLUMN, --column COLUMN
+ specify the column(s) to include, can be repeated
+
+ table formatter:
+ --max-width <integer>
+ Maximum display width, 0 to disable
+
+ CSV Formatter:
+ --quote {all,minimal,none,nonnumeric}
+ when to include quotes, defaults to nonnumeric
+
+
+Following is snippet of related command line options for an ACL modify action
+e.g. submit, add or remove.
+
+
+.. code-block:: bash
+
+ $ barbican help acl submit/user add/user remove
+ usage: barbican acl submit [-h] [-f {csv,table,value}] [-c COLUMN]
+ [--max-width <integer>]
+ [--quote {all,minimal,none,nonnumeric}]
+ [--user [USER]]
+ [--project-access | --no-project-access]
+ [--operation-type {read}]
+ URI
+
+ ....
+ ....
+
+ positional arguments:
+ URI The URI reference for the secret or container.
+
+ optional arguments:
+ -h, --help show this help message and exit
+ --user [USER], -u [USER]
+ Keystone userid(s) for ACL.
+ --project-access Flag to enable project access behavior.
+ --no-project-access Flag to disable project access behavior.
+ --operation-type {read}, -o {read}
+ Type of Barbican operation ACL is set for
+ ....
+ ....
+
+
+.. note::
+
+ Default for ``operation-type`` argument is 'read' as that's the only operation
+ currently supported by Barbican ACL API. So this argument can be skipped in
+ CLI call.
+
+
+ACLs Get
+~~~~~~~~
+
+To get complete ACL setting for a secret or container, use this ACL action.
+
+.. code-block:: bash
+
+ $ barbican acl get http://localhost:9311/v1/secrets/7776adb8-e865-413c-8ccc-4f09c3fe0213
+
+ +----------------+----------------+----------------------------------------------------------------------------+----------------------------------+----------------------------------+---------------------------------------------------------------------------+
+ | Operation Type | Project Access | Users | Created | Updated | Secret ACL Ref |
+ +----------------+----------------+----------------------------------------------------------------------------+----------------------------------+----------------------------------+---------------------------------------------------------------------------+
+ | read | False | [u'721e27b8505b499e8ab3b38154705b9e', u'2d0ee7c681cc4549b6d76769c320d91f'] | 2015-07-21 17:52:01.729370+00:00 | 2015-07-28 02:08:02.455276+00:00 | http://localhost:9311/v1/secrets/7776adb8-e865-413c-8ccc-4f09c3fe0213/acl |
+ +----------------+----------------+----------------------------------------------------------------------------+----------------------------------+----------------------------------+---------------------------------------------------------------------------+
+
+ $ barbican acl get http://localhost:9311/v1/containers/83c302c7-86fe-4f07-a277-c4962f121f19
+
+ +----------------+----------------+---------------------------------------+----------------------------------+----------------------------------+------------------------------------------------------------------------------+
+ | Operation Type | Project Access | Users | Created | Updated | Container ACL Ref |
+ +----------------+----------------+---------------------------------------+----------------------------------+----------------------------------+------------------------------------------------------------------------------+
+ | read | False | [u'2d0ee7c681cc4549b6d76769c320d91f'] | 2015-07-28 01:36:55.791381+00:00 | 2015-07-28 02:05:41.175386+00:00 | http://localhost:9311/v1/containers/83c302c7-86fe-4f07-a277-c4962f121f19/acl |
+ +----------------+----------------+---------------------------------------+----------------------------------+----------------------------------+------------------------------------------------------------------------------+
+
+
+Secret or container ref is required. If missing, it will result in error.
+
+.. code-block:: bash
+
+ $ barbican acl get
+
+ usage: barbican acl get [-h] [-f {csv,table,value}] [-c COLUMN]
+ [--max-width <integer>]
+ [--quote {all,minimal,none,nonnumeric}]
+ URI
+ barbican acl get: error: too few arguments
+
+
+ACLs Submit
+~~~~~~~~~~~
+
+To submit complete ACL setting for a secret or container, use this ACL action.
+
+.. code-block:: bash
+
+ $ barbican acl submit --user 2d0ee7c681cc4549b6d76769c320d91f --user 721e27b8505b499e8ab3b38154705b9e http://localhost:9311/v1/secrets/7776adb8-e865-413c-8ccc-4f09c3fe0213
+
+ +----------------+----------------+----------------------------------------------------------------------------+----------------------------------+----------------------------------+---------------------------------------------------------------------------+
+ | Operation Type | Project Access | Users | Created | Updated | Secret ACL Ref |
+ +----------------+----------------+----------------------------------------------------------------------------+----------------------------------+----------------------------------+---------------------------------------------------------------------------+
+ | read | True | [u'721e27b8505b499e8ab3b38154705b9e', u'2d0ee7c681cc4549b6d76769c320d91f'] | 2015-07-21 17:52:01.729370+00:00 | 2015-08-12 09:53:20.225971+00:00 | http://localhost:9311/v1/secrets/7776adb8-e865-413c-8ccc-4f09c3fe0213/acl |
+ +----------------+----------------+----------------------------------------------------------------------------+----------------------------------+----------------------------------+---------------------------------------------------------------------------+
+
+
+If ``user`` argument is missing or has no value, then empty list is passed for
+users and this approach can be used to remove existing ACL users. If project
+access argument is not provided, then by default project access is enabled. To
+disable project access behavior, just pass ``no-project-access`` argument
+without any value.
+
+.. code-block:: bash
+
+ $ barbican acl submit --user --no-project-access http://localhost:9311/v1/secrets/7776adb8-e865-413c-8ccc-4f09c3fe0213
+
+ +----------------+----------------+-------+----------------------------------+----------------------------------+---------------------------------------------------------------------------+
+ | Operation Type | Project Access | Users | Created | Updated | Secret ACL Ref |
+ +----------------+----------------+-------+----------------------------------+----------------------------------+---------------------------------------------------------------------------+
+ | read | False | [] | 2015-07-21 17:52:01.729370+00:00 | 2015-08-12 09:55:23.043433+00:00 | http://localhost:9311/v1/secrets/7776adb8-e865-413c-8ccc-4f09c3fe0213/acl |
+ +----------------+----------------+-------+----------------------------------+----------------------------------+---------------------------------------------------------------------------+
+
+ $ barbican acl submit --user 2d0ee7c681cc4549b6d76769c320d91f --no-project-access http://localhost:9311/v1/containers/83c302c7-86fe-4f07-a277-c4962f121f19
+
+ +----------------+----------------+---------------------------------------+----------------------------------+----------------------------------+------------------------------------------------------------------------------+
+ | Operation Type | Project Access | Users | Created | Updated | Container ACL Ref |
+ +----------------+----------------+---------------------------------------+----------------------------------+----------------------------------+------------------------------------------------------------------------------+
+ | read | False | [u'2d0ee7c681cc4549b6d76769c320d91f'] | 2015-07-29 22:01:00.878270+00:00 | 2015-08-19 05:56:09.930302+00:00 | http://localhost:9311/v1/containers/83c302c7-86fe-4f07-a277-c4962f121f19/acl |
+ +----------------+----------------+---------------------------------------+----------------------------------+----------------------------------+------------------------------------------------------------------------------+
+
+Following error is returned when both mutually exclusive flags are passed.
+
+.. code-block:: bash
+
+ $ barbican acl submit --project-access --no-project-access http://localhost:9311/v1/secrets/7776adb8-e865-413c-8ccc-4f09c3fe0213
+ usage: barbican acl submit [-h] [-f {csv,table,value}] [-c COLUMN]
+ [--max-width <integer>]
+ [--quote {all,minimal,none,nonnumeric}]
+ [--user [USER]]
+ [--project-access | --no-project-access]
+ [--operation-type {read}]
+ URI
+ barbican acl submit: error: argument --no-project-access: not allowed with argument --project-access
+
+
+ACL Add User(s)
+~~~~~~~~~~~~~~~
+
+To add ACL users for a secret or container, use this ACL action.
+
+If ``user`` argument is missing or has no value, then no change is made in ACL
+users. If project access argument is not provided, then no change is made in
+existing project access behavior flag.
+
+.. code-block:: bash
+
+ $ barbican acl user add --user c1d20e4b7e7d4917aee6f0832152269b http://localhost:9311/v1/containers/83c302c7-86fe-4f07-a277-c4962f121f19
+
+ +----------------+----------------+----------------------------------------------------------------------------+----------------------------------+----------------------------------+------------------------------------------------------------------------------+
+ | Operation Type | Project Access | Users | Created | Updated | Container ACL Ref |
+ +----------------+----------------+----------------------------------------------------------------------------+----------------------------------+----------------------------------+------------------------------------------------------------------------------+
+ | read | False | [u'2d0ee7c681cc4549b6d76769c320d91f', u'c1d20e4b7e7d4917aee6f0832152269b'] | 2015-07-29 22:01:00.878270+00:00 | 2015-08-12 10:08:19.129370+00:00 | http://localhost:9311/v1/containers/83c302c7-86fe-4f07-a277-c4962f121f19/acl |
+ +----------------+----------------+----------------------------------------------------------------------------+----------------------------------+----------------------------------+------------------------------------------------------------------------------+
+
+.. code-block:: bash
+
+ # Added 2 users for secret (084c2098-66db-4401-8348-d969be0eddaa) earlier via set action.
+ $ barbican acl user add --user --no-project-access http://localhost:9311/v1/secrets/084c2098-66db-4401-8348-d969be0eddaa
+
+ +----------------+----------------+----------------------------------------------------------------------------+----------------------------------+----------------------------------+---------------------------------------------------------------------------+
+ | Operation Type | Project Access | Users | Created | Updated | Secret ACL Ref |
+ +----------------+----------------+----------------------------------------------------------------------------+----------------------------------+----------------------------------+---------------------------------------------------------------------------+
+ | read | False | [u'721e27b8505b499e8ab3b38154705b9e', u'2d0ee7c681cc4549b6d76769c320d91f'] | 2015-08-12 10:09:27.564371+00:00 | 2015-08-12 10:11:09.749980+00:00 | http://localhost:9311/v1/secrets/084c2098-66db-4401-8348-d969be0eddaa/acl |
+ +----------------+----------------+----------------------------------------------------------------------------+----------------------------------+----------------------------------+---------------------------------------------------------------------------+
+
+
+ACL Remove User(s)
+~~~~~~~~~~~~~~~~~~
+
+To remove ACL users for a secret or container, use this ACL action.
+
+If ``user`` argument is missing or has no value, then no change is made in ACL
+users. If project access argument is not provided, then no change is made in
+existing project access behavior flag.
+
+If provided userid(s) does not exist in ACL, it is simply ignored and only
+existing userid(s) are removed from ACL.
+
+.. code-block:: bash
+
+ $ barbican acl user remove --user 2d0ee7c681cc4549b6d76769c320d91f --user invalid_user_id http://localhost:9311/v1/secrets/084c2098-66db-4401-8348-d969be0eddaa
+
+ +----------------+----------------+---------------------------------------+----------------------------------+----------------------------------+---------------------------------------------------------------------------+
+ | Operation Type | Project Access | Users | Created | Updated | Secret ACL Ref |
+ +----------------+----------------+---------------------------------------+----------------------------------+----------------------------------+---------------------------------------------------------------------------+
+ | read | False | [u'721e27b8505b499e8ab3b38154705b9e'] | 2015-08-12 10:09:27.564371+00:00 | 2015-08-12 10:12:21.842888+00:00 | http://localhost:9311/v1/secrets/084c2098-66db-4401-8348-d969be0eddaa/acl |
+ +----------------+----------------+---------------------------------------+----------------------------------+----------------------------------+---------------------------------------------------------------------------+
+
+
+ACLs Delete
+~~~~~~~~~~~
+
+To delete existing ACL setting for a secret or container, use this ACL action.
+
+.. code-block:: bash
+
+ $ barbican acl delete http://localhost:9311/v1/secrets/084c2098-66db-4401-8348-d969be0eddaa
+
+ $ barbican acl get http://localhost:9311/v1/secrets/084c2098-66db-4401-8348-d969be0eddaa
+
+ +----------------+----------------+-------+---------+---------+---------------------------------------------------------------------------+
+ | Operation Type | Project Access | Users | Created | Updated | Secret ACL Ref |
+ +----------------+----------------+-------+---------+---------+---------------------------------------------------------------------------+
+ | read | True | [] | None | None | http://localhost:9311/v1/secrets/084c2098-66db-4401-8348-d969be0eddaa/acl |
+ +----------------+----------------+-------+---------+---------+---------------------------------------------------------------------------+
diff --git a/doc/source/reference.rst b/doc/source/reference.rst
index b21dbb0..27f83a6 100644
--- a/doc/source/reference.rst
+++ b/doc/source/reference.rst
@@ -56,6 +56,20 @@ Certificate Authorities
.. autoclass:: barbicanclient.cas.CA
:members:
+ACLs
+====
+
+.. autoclass:: barbicanclient.acls.ACLManager
+ :members:
+
+.. autoclass:: barbicanclient.acls.SecretACL
+ :members:
+ :inherited-members:
+
+.. autoclass:: barbicanclient.acls.ContainerACL
+ :members:
+ :inherited-members:
+
Exceptions
==========
diff --git a/doc/source/usage.rst b/doc/source/usage.rst
index 2f6211c..16a0744 100644
--- a/doc/source/usage.rst
+++ b/doc/source/usage.rst
@@ -6,9 +6,9 @@ To use barbicanclient, you must first create an instance of the
:class:`barbicanclient.client.Client` class.
The client uses Keystone Sessions for both authentication and for handling HTTP
-requests. You can provide authentication credentials to the client by creating
-a Keystone Session with the appropriate auth plugin and then passing that
-session to the new Client.
+requests. You can provide authentication credentials to the client by
+creating a Keystone Session with the appropriate auth plugin and then passing
+that session to the new Client.
See :doc:`authentication` for more details.
@@ -25,10 +25,11 @@ service: Secrets, Orders and Containers.
Secrets
=======
-Secrets represent keys, credentials, and other sensitive data that is stored
-by the Barbican service. To store or retrieve a secret in the Barbican
-service you should use the different methods of the :class:`barbicanclient.secrets.SecretManager`
-class that is exposed as the `secrets` attribute of the Client.
+Secrets represent keys, credentials, and other sensitive data that is stored by
+the Barbican service. To store or retrieve a secret in the Barbican service
+you should use the different methods of the
+:class:`barbicanclient.secrets.SecretManager` class that is exposed as the
+`secrets` attribute of the Client.
Example::
@@ -52,8 +53,9 @@ Example::
my_secret_ref = my_secret.store()
-The secret reference returned by :meth:`barbicanclient.secrets.SecretManager.store`
-can later be used to retrieve the secret data from barbican.
+The secret reference returned by
+:meth:`barbicanclient.secrets.SecretManager.store` can later be used to
+retrieve the secret data from barbican.
Example::
@@ -65,17 +67,17 @@ Example::
Secret Content Types
--------------------
-The Barbican service defines a Secret Content Type. The client will choose
-the correct Content Type based on the type of the data that is set on the
+The Barbican service defines a Secret Content Type. The client will choose the
+correct Content Type based on the type of the data that is set on the
`Secret.payload` property. The following table summarizes the mapping of
Python types to Barbican Secret Content Types:
+-----------------+---------------+---------------+--------------------------+
-| six Type | Python 2 Type | Python 3 Type | Barbican Content Type |
+| six Type | Python 2 Type | Python 3 Type | Barbican Content Type |
+=================+===============+===============+==========================+
-| six.binary_type | str | bytes | application/octet-stream |
+| six.binary_type | str | bytes | application/octet-stream |
+-----------------+---------------+---------------+--------------------------+
-| six.text_type | unicode | str | text/plain |
+| six.text_type | unicode | str | text/plain |
+-----------------+---------------+---------------+--------------------------+
.. WARNING::
@@ -94,8 +96,8 @@ Orders are used to request secret material to be created by the Barbican
service. Submitting an order will result in a Secret being created on your
behalf. The Secret can then be used like any Secret you may have uploaded
yourself. Orders should be created using the factory methods in the
-:class:`barbicanclient.orders.OrderManager` instance in the `orders`
-attribute of the `Client`.
+:class:`barbicanclient.orders.OrderManager` instance in the `orders` attribute
+of the `Client`.
Example::
@@ -112,8 +114,8 @@ Example::
my_order_ref = my_order.submit()
-The order reference returned by :meth:`barbicanclient.orders.Order.submit`
-can later be used to retrieve the order from Barbican.
+The order reference returned by :meth:`barbicanclient.orders.Order.submit` can
+later be used to retrieve the order from Barbican.
Example::
@@ -121,8 +123,8 @@ Example::
retrieved_order = barbican.orders.get(my_order_ref)
-Once your order has been processed by Barbican, the order status will be set
-to `'ACTIVE'`. An active order will contain the reference to the requested
+Once your order has been processed by Barbican, the order status will be set to
+`'ACTIVE'`. An active order will contain the reference to the requested
secret (or container).
Example::
@@ -133,17 +135,19 @@ Example::
key = generated_secret.payload
Currently the client can submit :class:`barbicanclient.orders.KeyOrder` orders
-for Keys suitable for symmetric encryption, and :class:`barbicanclient.orders.AsymmetricOrder`
-for Asymmetric keys such as RSA keys.
+for Keys suitable for symmetric encryption, and
+:class:`barbicanclient.orders.AsymmetricOrder` for Asymmetric keys such as RSA
+keys.
Containers
==========
-Containers can be either arbitrary groupings of `Secrets` or a strict
-grouping of Secrets, such as the Public and Private keys of an RSA keypair.
+Containers can be either arbitrary groupings of `Secrets` or a strict grouping
+of Secrets, such as the Public and Private keys of an RSA keypair.
-Containers should be managed using the :class:`barbicanclient.containers.ContainerManager`
-instance in the `containers` attribute of the `Client`
+Containers should be managed using the
+:class:`barbicanclient.containers.ContainerManager` instance in the
+`containers` attribute of the `Client`
Example::
@@ -156,8 +160,9 @@ Example::
my_container_ref = my_container.store()
-The container reference returned by :meth:`barbicanclient.containers.Container.store`
-can later be used to retrieve the container from Barbican.
+The container reference returned by
+:meth:`barbicanclient.containers.Container.store` can later be used to
+retrieve the container from Barbican.
Example::
@@ -165,3 +170,165 @@ Example::
retrieved_container = barbican.containers.get(my_container_ref)
+
+ACLs
+====
+
+Access Control List (ACL) feature in Barbican provides user level access
+control for secrets and containers. By default Barbican manages access to its
+resources (secrets, containers) on a per project level and authorization is
+granted based on the roles a user has in that project.
+
+ACLs should be managed using the :class:`barbicanclient.acls.ACLManager`
+instance in the `acls` attribute of the `Client`.
+
+Example::
+
+ # Submits ACLs on an existing Secret with URI as 'secret_ref'
+
+ # create ACL entity object with needed settings
+ acl_entity = barbican.acls.create(entity_ref=secret_ref, users=[u1, u2],
+ project_access=False)
+
+ acl_ref = acl_entity.submit() # submits ACL setting to server at this point.
+
+The secret or container URI can be used to read all of its ACL setting.
+Returned value is instance of either :class:`barbicanclient.acls.SecretACL` or
+:class:`barbicanclient.acls.ContainerACL`. Refer to respective class for its
+available APIs.
+
+Example::
+
+ # Get ACL entity for a Secret
+ # Returned entity will be either SecretACL or ContainerACL.
+ # This entity has ACL settings per operation type (e.g. 'read')
+
+ secret_acl = barbican.acls.get(secret_ref)
+
+ # To retrieve (load) ACL using existing ACL entity e.g. container_acl
+ container_acl.load_acls_data()
+
+ACLs setting can also be retrieved directly from secret or container entity.
+Its data is lazy loaded i.e. related ACL settings are not read till `acls`
+attribute is accessed on secret or container entity.
+
+Example::
+
+ # Get secret entity for a given ref
+ secret = barbican.secrets.get(secret_ref)
+
+ # To get project access flag or users for 'read' operation
+ project_access_flag = secret.acls.read.project_access
+ read_acl_users = secret.acls.read.users
+
+
+ # Get container entity for a given ref
+ container = barbican.containers.get(container_ref)
+
+ # To get project access flag or users for 'read' operation
+ project_access_flag = container.acls.read.project_access
+ read_acl_users = container.acls.read.users
+
+
+If need to add users to existing 'read' ACL settings on a secret or container,
+above mentioned get and submit methods can be used.
+
+Example::
+
+ # Every Barbican secret and container has default ACL setting which
+ # reflects default project access behavior.
+
+ # ACL settings is modified via submit operation on ACL entity.
+
+ # provide users to be added as list.
+ add_users = ['user1', 'user2', 'users3']
+
+ # Case 1 - Add users to 'read' operation ACL setting
+ # --------------------------------------------------
+
+ # Get ACL entity from server
+ acl_entity = barbican.acls.get(entity_ref=secret_ref)
+
+ # add new users to existing users for 'read' operation
+ acl_entity.read.users.extend(add_users)
+ # OR
+ # acl_entity.get('read').users.extend(add_users)
+
+ acl_ref = acl_entity.submit() # here submits ACL changes to server.
+
+ # Case 2 - Add same users to ACL settings for each operation type
+ # ---------------------------------------------------------------
+
+ # Get ACL entity from server
+ acl_entity = barbican.acls.get(entity_ref=secret_ref)
+
+ # Go through each operation ACL setting and add users to existing list
+ for op_acl in acl_entity.operation_acls
+ op_acl.users.extend(add_users)
+
+ acl_ref = acl_entity.submit() # here submits ACL changes to server.
+
+If need to remove some users from existing ACL settings on a secret or
+container, similar approach can be used as mentioned above for `add` example.
+
+Example::
+
+ # provide users to be removed as list.
+ remove_users = ['user1', 'user2', 'users3']
+
+ # Case 1 - Remove users from 'read' operation ACL setting
+ # -------------------------------------------------------
+
+ # Get ACL entity from server
+ acl_entity = barbican.acls.get(entity_ref=container_ref)
+
+ existing_users = acl_entity.read.users
+ # OR
+ # existing users = acl_entity.get('read').users
+
+ # remove matching users from existing users list
+ updated_users = set(existing_users).difference(remove_users)
+
+ # set back updated users to operation specific acl setting
+ acl_entity.read.users = updated_users
+ # OR
+ # acl_entity.get('read').users = updated_users
+
+ acl_ref = acl_entity.submit() # here submits ACL changes to server.
+
+ # Case 2 - Remove same users from ACL settings for each operation type
+ # --------------------------------------------------------------------
+
+ # Get ACL entity from server
+ acl_entity = barbican.acls.get(secret_ref)
+
+ # Go through each operation ACL setting and remove users from existing list
+ for op_acl in acl_entity.operation_acls
+ existing_users = op_acl.users
+
+ # remove matching users from existing users list
+ updated_users = set(existing_users).difference(remove_users)
+
+ # set back updated users to operation specific acl setting
+ op_acl.users = updated_users
+
+ acl_ref = acl_entity.submit() # here submits ACL changes to server.
+
+
+If need to unset or delete ACL settings on a secret or container,
+:meth:`barbicanclient.acls.SecretACL.remove` or
+:meth:`barbicanclient.acls.ContainerACL.remove` can be used.
+
+Example::
+
+ # create ACL entity object with secret or container ref
+ blank_acl_entity = barbican.acls.create(entity_ref=secret_ref)
+
+ # removes all ACL settings for the secret on server
+ blank_acl_entity.remove()
+
+ # To remove 'read' operation specific ACL setting
+ acl_entity = barbican.acls.get(entity_ref=secret_ref)
+ acl_entity.read.remove()
+ # OR
+ # acl_entity.get('read').remove()
diff --git a/setup.cfg b/setup.cfg
index a6314f7..9573859 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -51,6 +51,12 @@ openstack.key_manager.v1 =
ca_get = barbicanclient.barbican_cli.cas:GetCA
ca_list = barbicanclient.barbican_cli.cas:ListCA
+ acl_delete = barbicanclient.barbican_cli.acls:DeleteACLs
+ acl_get = barbicanclient.barbican_cli.acls:GetACLs
+ acl_submit = barbicanclient.barbican_cli.acls:SubmitACL
+ acl_user_add = barbicanclient.barbican_cli.acls:AddACLUsers
+ acl_user_remove = barbicanclient.barbican_cli.acls:RemoveACLUsers
+
[build_sphinx]
source-dir = doc/source
build-dir = doc/build