diff options
author | Jenkins <jenkins@review.openstack.org> | 2015-10-03 09:06:05 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2015-10-03 09:06:05 +0000 |
commit | 68adf0cecf9b38bdb4972030e9dd72839aab95e2 (patch) | |
tree | 0062adceb08455518b402ca493ce92344ff3c2b1 | |
parent | e395a4d9ef9d89e65456dd0a4d8d2d0cc3bd73e2 (diff) | |
parent | d083e1ed751b44a72bc8610515ebd09710acd964 (diff) | |
download | python-barbicanclient-68adf0cecf9b38bdb4972030e9dd72839aab95e2.tar.gz |
Merge "Part 2: Adding ACL support for CLI commands and docs"
-rw-r--r-- | README.rst | 41 | ||||
-rw-r--r-- | barbicanclient/barbican_cli/acls.py | 261 | ||||
-rw-r--r-- | barbicanclient/containers.py | 11 | ||||
-rw-r--r-- | barbicanclient/secrets.py | 10 | ||||
-rw-r--r-- | barbicanclient/tests/test_containers.py | 26 | ||||
-rw-r--r-- | barbicanclient/tests/test_secrets.py | 25 | ||||
-rw-r--r-- | doc/source/cli_usage.rst | 272 | ||||
-rw-r--r-- | doc/source/reference.rst | 14 | ||||
-rw-r--r-- | doc/source/usage.rst | 223 | ||||
-rw-r--r-- | setup.cfg | 6 |
10 files changed, 840 insertions, 49 deletions
@@ -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() @@ -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 |