python-barbicanclient-4.10.0/0000775000175000017500000000000013620530306016073 5ustar zuulzuul00000000000000python-barbicanclient-4.10.0/releasenotes/0000775000175000017500000000000013620530306020564 5ustar zuulzuul00000000000000python-barbicanclient-4.10.0/releasenotes/notes/0000775000175000017500000000000013620530306021714 5ustar zuulzuul00000000000000python-barbicanclient-4.10.0/releasenotes/notes/use-only-uuid-from-href-81710d1b388dce57.yaml0000664000175000017500000000061313620530200031333 0ustar zuulzuul00000000000000--- features: - | Lookups (for all Read/Update/Delete actions) are now performed using only the UUID of the entity. For backward compatability, full HATEOS refs may be used, but everything before the UUID will be stripped and the service catalog entry for Barbican will be substituted. This should have no impact on accessing existing secrets with any version of Barbican. python-barbicanclient-4.10.0/PKG-INFO0000664000175000017500000003120113620530306017165 0ustar zuulzuul00000000000000Metadata-Version: 1.1 Name: python-barbicanclient Version: 4.10.0 Summary: Client Library for OpenStack Barbican Key Management API Home-page: https://docs.openstack.org/python-barbicanclient/latest/ Author: OpenStack Author-email: openstack-discuss@lists.openstack.org License: UNKNOWN Description: python-barbicanclient ===================== .. image:: https://img.shields.io/pypi/v/python-barbicanclient.svg :target: https://pypi.org/project/python-barbicanclient/ :alt: Latest Version This is a client for the `Barbican `__ Key Management API. There is a Python library for accessing the API (`barbicanclient` module), and a command-line script (`barbican`). Installation ------------ The client is `pip installable `__ as follows: .. code:: console pip install python-barbicanclient barbicanclient - Python Library ------------------------------- The full api is `documented in the official OpenStack documentation site `__. Here's an example of storing a secret in barbican using the python library with keystone authentication: .. code:: python >>> from keystoneclient.auth import identity >>> from keystoneauth1 import session >>> from barbicanclient import client >>> # We'll use Keystone API v3 for authentication >>> auth = identity.v3.Password(auth_url=u'http://localhost:5000/v3', ... username=u'admin_user', ... user_domain_name=u'Default', ... password=u'password', ... project_name=u'demo', ... project_domain_name=u'Default') >>> # Next we'll create a Keystone session using the auth plugin we just created >>> sess = session.Session(auth=auth) >>> # Now we use the session to create a Barbican client >>> barbican = client.Client(session=sess) >>> # Let's create a Secret to store some sensitive data >>> secret = barbican.secrets.create(name=u'Self destruction sequence', ... payload=u'the magic words are squeamish ossifrage') >>> # Now let's store the secret by using its store() method. This will send the secret data >>> # to Barbican, where it will be encrypted and stored securely in the cloud. >>> secret.store() u'http://localhost:9311/v1/secrets/85b220fd-f414-483f-94e4-2f422480f655' >>> # The URI returned by store() uniquely identifies your secret in the Barbican service. >>> # After a secret is stored, the URI is also available by accessing >>> # the secret_ref attribute. >>> print(secret.secret_ref) http://localhost:9311/v1/secrets/091adb32-4050-4980-8558-90833c531413 >>> # When we need to retrieve our secret at a later time, we can use the secret_ref >>> retrieved_secret = barbican.secrets.get(u'http://localhost:9311/v1/secrets/091adb32-4050-4980-8558-90833c531413') >>> # We can access the secret payload by using the payload attribute. >>> # Barbican decrypts the secret and sends it back. >>> print(retrieved_secret.payload) the magic words are squeamish ossifrage .. note:: In order for the example above to work Barbican must be running and configured to use the Keystone Middleware. For more information on setting this up please visit: https://docs.openstack.org/barbican/latest/configuration/keystone.html [1]_ barbican - Command Line Client ------------------------------ The command line client is self-documenting. Use the --help flag to access the usage options .. code:: console $ barbican --help usage: barbican [--version] [-v] [--log-file LOG_FILE] [-q] [-h] [--debug] [--no-auth] [--os-identity-api-version ] [--os-auth-url ] [--os-username ] [--os-user-id ] [--os-password ] [--os-user-domain-id ] [--os-user-domain-name ] [--os-tenant-name ] [--os-tenant-id ] [--os-project-id ] [--os-project-name ] [--os-project-domain-id ] [--os-project-domain-name ] [--endpoint ] [--insecure] [--os-cacert ] [--os-cert ] [--os-key ] [--timeout ] Command-line interface to the Barbican API. optional arguments: --version show program's version number and exit -v, --verbose Increase verbosity of output. Can be repeated. --log-file LOG_FILE Specify a file to log output. Disabled by default. -q, --quiet suppress output except warnings and errors -h, --help show this help message and exit --debug show trace backs on errors --no-auth, -N Do not use authentication. --os-identity-api-version Specify Identity API version to use. Defaults to env[OS_IDENTITY_API_VERSION] or 3. --os-auth-url , -A Defaults to env[OS_AUTH_URL]. --os-username , -U Defaults to env[OS_USERNAME]. --os-user-id Defaults to env[OS_USER_ID]. --os-password , -P Defaults to env[OS_PASSWORD]. --os-user-domain-id Defaults to env[OS_USER_DOMAIN_ID]. --os-user-domain-name Defaults to env[OS_USER_DOMAIN_NAME]. --os-tenant-name , -T Defaults to env[OS_TENANT_NAME]. --os-tenant-id , -I Defaults to env[OS_TENANT_ID]. --os-project-id Another way to specify tenant ID. This option is mutually exclusive with --os-tenant-id. Defaults to env[OS_PROJECT_ID]. --os-project-name Another way to specify tenant name. This option is mutually exclusive with --os-tenant-name. Defaults to env[OS_PROJECT_NAME]. --os-project-domain-id Defaults to env[OS_PROJECT_DOMAIN_ID]. --os-project-domain-name Defaults to env[OS_PROJECT_DOMAIN_NAME]. --endpoint , -E --endpoint , -E Defaults to env[BARBICAN_ENDPOINT]. --insecure Explicitly allow client to perform "insecure" TLS (https) requests. The server's certificate will not be verified against any certificate authorities. This option should be used with caution. --os-cacert Specify a CA bundle file to use in verifying a TLS (https) server certificate. Defaults to env[OS_CACERT]. --os-cert Defaults to env[OS_CERT]. --os-key Defaults to env[OS_KEY]. --timeout Set request timeout (in seconds). See "barbican help COMMAND" for help on a specific command. Commands: 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. ca get Retrieve a CA by providing its URI. ca list List CAs. complete print bash completion command secret container create Store a container in Barbican. secret container delete Delete a container by providing its href. secret container get Retrieve a container by providing its URI. secret container list List containers. help print detailed help for another command secret order create Create a new order. secret order delete Delete an order by providing its href. secret order get Retrieve an order by providing its URI. secret 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 * `PyPi`_ - package installation * `Online Documentation`_ * `Launchpad project`_ - release management * `Blueprints`_ - feature specifications * `Bugs`_ - issue tracking * `Source`_ * `Specs`_ * `Getting involved`_ .. _PyPi: https://pypi.org/project/python-barbicanclient/ .. _Online Documentation: https://docs.openstack.org/python-barbicanclient/latest/ .. _Launchpad project: https://launchpad.net/python-barbicanclient/ .. _Blueprints: https://blueprints.launchpad.net/python-barbicanclient/ .. _Bugs: https://storyboard.openstack.org/#!/project/984 .. _Source: https://git.openstack.org/cgit/openstack/python-barbicanclient/ .. _Getting involved: https://docs.openstack.org/barbican/latest/contributor/getting_involved.html .. _Specs: https://specs.openstack.org/openstack/barbican-specs/ .. [1] Documentation in this link is currently incomplete. Please use the `devstack setup `__. Platform: UNKNOWN Classifier: Environment :: OpenStack Classifier: Intended Audience :: Information Technology Classifier: Intended Audience :: System Administrators Classifier: License :: OSI Approved :: Apache Software License Classifier: Operating System :: POSIX :: Linux Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 python-barbicanclient-4.10.0/test-requirements.txt0000664000175000017500000000110513620530200022322 0ustar zuulzuul00000000000000# The order of packages is significant, because pip processes them in the order # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. coverage!=4.4,>=4.1 # Apache-2.0 hacking>=1.1.0,<1.2.0 # Apache-2.0 fixtures>=3.0.0 # Apache-2.0/BSD requests-mock>=1.2.0 # Apache-2.0 mock>=2.0.0 # BSD stestr>=2.0.0 # Apache-2.0 testtools>=2.2.0 # MIT oslotest>=3.2.0 # Apache-2.0 nose>=1.3.7 # LGPL oslo.config>=5.2.0 # Apache-2.0 python-openstackclient>=3.12.0 # Apache-2.0 sphinxcontrib-svg2pdfconverter>=0.1.0 # BSD python-barbicanclient-4.10.0/setup.cfg0000664000175000017500000000463213620530306017721 0ustar zuulzuul00000000000000[metadata] name = python-barbicanclient summary = Client Library for OpenStack Barbican Key Management API description-file = README.rst author = OpenStack author-email = openstack-discuss@lists.openstack.org home-page = https://docs.openstack.org/python-barbicanclient/latest/ classifier = Environment :: OpenStack Intended Audience :: Information Technology Intended Audience :: System Administrators License :: OSI Approved :: Apache Software License Operating System :: POSIX :: Linux Programming Language :: Python Programming Language :: Python :: 2 Programming Language :: Python :: 2.7 Programming Language :: Python :: 3 Programming Language :: Python :: 3.5 Programming Language :: Python :: 3.6 [files] packages = barbicanclient [entry_points] console_scripts = barbican = barbicanclient.barbican:main openstack.cli.extension = key_manager = barbicanclient.osc_plugin openstack.key_manager.v1 = secret_order_create = barbicanclient.barbican_cli.v1.orders:CreateOrder secret_order_delete = barbicanclient.barbican_cli.v1.orders:DeleteOrder secret_order_get = barbicanclient.barbican_cli.v1.orders:GetOrder secret_order_list = barbicanclient.barbican_cli.v1.orders:ListOrder secret_delete = barbicanclient.barbican_cli.v1.secrets:DeleteSecret secret_get = barbicanclient.barbican_cli.v1.secrets:GetSecret secret_list = barbicanclient.barbican_cli.v1.secrets:ListSecret secret_store = barbicanclient.barbican_cli.v1.secrets:StoreSecret secret_update = barbicanclient.barbican_cli.v1.secrets:UpdateSecret secret_container_delete = barbicanclient.barbican_cli.v1.containers:DeleteContainer secret_container_get = barbicanclient.barbican_cli.v1.containers:GetContainer secret_container_list = barbicanclient.barbican_cli.v1.containers:ListContainer secret_container_create = barbicanclient.barbican_cli.v1.containers:CreateContainer ca_get = barbicanclient.barbican_cli.v1.cas:GetCA ca_list = barbicanclient.barbican_cli.v1.cas:ListCA acl_delete = barbicanclient.barbican_cli.v1.acls:DeleteACLs acl_get = barbicanclient.barbican_cli.v1.acls:GetACLs acl_submit = barbicanclient.barbican_cli.v1.acls:SubmitACL acl_user_add = barbicanclient.barbican_cli.v1.acls:AddACLUsers acl_user_remove = barbicanclient.barbican_cli.v1.acls:RemoveACLUsers [build_sphinx] source-dir = doc/source build-dir = doc/build all_files = 1 [upload_sphinx] upload-dir = doc/build/html [egg_info] tag_build = tag_date = 0 python-barbicanclient-4.10.0/functionaltests/0000775000175000017500000000000013620530306021320 5ustar zuulzuul00000000000000python-barbicanclient-4.10.0/functionaltests/utils.py0000664000175000017500000001320613620530200023025 0ustar zuulzuul00000000000000# Copyright (c) 2013-2014 Rackspace, Inc. # # 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. import datetime import functools from os import path import time import types import oslotest.base as oslotest import six import six.moves.urllib.parse as urlparse class BaseTestCase(oslotest.BaseTestCase): def setUp(self): super(BaseTestCase, self).setUp() self.order_id = 'order1234' self.external_project_id = 'keystone1234' def tearDown(self): super(BaseTestCase, self).tearDown() def construct_new_test_function(original_func, name, build_params): """Builds a new test function based on parameterized data. :param original_func: The original test function that is used as a template :param name: The fullname of the new test function :param build_params: A dictionary or list containing args or kwargs for the new test :return: A new function object """ new_func = types.FunctionType( six.get_function_code(original_func), six.get_function_globals(original_func), name=name, argdefs=six.get_function_defaults(original_func) ) # Support either an arg list or kwarg dict for our data build_args = build_params if isinstance(build_params, list) else [] build_kwargs = build_params if isinstance(build_params, dict) else {} # Build a test wrapper to execute with our kwargs def test_wrapper(func, test_args, test_kwargs): @functools.wraps(func) def wrapper(self): return func(self, *test_args, **test_kwargs) return wrapper return test_wrapper(new_func, build_args, build_kwargs) def process_parameterized_function(name, func_obj, build_data): """Build lists of functions to add and remove to a test case.""" to_remove = [] to_add = [] for subtest_name, params in build_data.items(): # Build new test function func_name = '{0}_{1}'.format(name, subtest_name) new_func = construct_new_test_function(func_obj, func_name, params) # Mark the new function as needed to be added to the class to_add.append((func_name, new_func)) # Mark key for removal to_remove.append(name) return to_remove, to_add def parameterized_test_case(cls): """Class decorator to process parameterized tests This allows for parameterization to be used for potentially any unittest compatible runner; including testr and py.test. """ tests_to_remove = [] tests_to_add = [] for key, val in vars(cls).items(): # Only process tests with build data on them if key.startswith('test_') and val.__dict__.get('build_data'): to_remove, to_add = process_parameterized_function( name=key, func_obj=val, build_data=val.__dict__.get('build_data') ) tests_to_remove.extend(to_remove) tests_to_add.extend(to_add) # Add all new test functions [setattr(cls, name, func) for name, func in tests_to_add] # Remove all old test function templates (if they still exist) [delattr(cls, key) for key in tests_to_remove if hasattr(cls, key)] return cls def parameterized_dataset(build_data): """Simple decorator to mark a test method for processing.""" def decorator(func): func.__dict__['build_data'] = build_data return func return decorator def create_timestamp_w_tz_and_offset(timezone=None, days=0, hours=0, minutes=0, seconds=0): """Creates a timestamp with a timezone and offset in days :param timezone: Timezone used in creation of timestamp :param days: The offset in days :param hours: The offset in hours :param minutes: The offset in minutes :return: a timestamp """ if timezone is None: timezone = time.strftime("%z") timestamp = '{time}{timezone}'.format( time=(datetime.datetime.today() + datetime.timedelta(days=days, hours=hours, minutes=minutes, seconds=seconds)), timezone=timezone) return timestamp def get_limit_and_offset_from_ref(ref): matches = dict(urlparse.parse_qsl(urlparse.urlparse(ref).query)) ref_limit = matches['limit'] ref_offset = matches['offset'] return ref_limit, ref_offset def get_tomorrow_timestamp(): tomorrow = (datetime.today() + datetime.timedelta(days=1)) return tomorrow.isoformat() def string_to_datetime(datetimestring, date_formats=None): date_formats = date_formats or [ '%Y-%m-%d %H:%M:%S', '%Y-%m-%d %H:%M:%S.%f', '%Y-%m-%dT%H:%M:%S.%fZ', '%Y-%m-%dT%H:%M:%S.%f', "%Y-%m-%dT%H:%M:%SZ", "%Y-%m-%dT%H:%M:%S"] for dateformat in date_formats: try: return datetime.datetime.strptime(datetimestring, dateformat) except ValueError: continue else: raise def get_id_from_ref(ref): """Returns id from reference.""" ref_id = None if ref is not None and len(ref) > 0: ref_id = path.split(ref)[1] return ref_id python-barbicanclient-4.10.0/functionaltests/__init__.py0000664000175000017500000000116613620530200023426 0ustar zuulzuul00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ from functionaltests.common import config CONF = config.get_config() python-barbicanclient-4.10.0/functionaltests/base.py0000664000175000017500000000270613620530200022602 0ustar zuulzuul00000000000000""" Copyright 2015 Rackspace 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. """ import logging from functionaltests.common import config import oslotest.base as oslotest CONF = config.get_config() class BaseTestCase(oslotest.BaseTestCase): max_payload_size = CONF.keymanager.max_payload_size max_sized_payload = u'a' * max_payload_size oversized_payload = 'a' * (max_payload_size + 1) max_field_size = 255 max_sized_field = 'a' * max_field_size oversized_field = 'a' * (max_field_size + 1) @classmethod def setUpClass(cls): cls.LOG = logging.getLogger(cls._get_full_case_name()) super(BaseTestCase, cls).setUpClass() def tearDown(self): super(BaseTestCase, self).tearDown() self.LOG.info('Finished: %s\n', self._testMethodName) @classmethod def _get_full_case_name(cls): name = '{module}:{case_name}'.format( module=cls.__module__, case_name=cls.__name__ ) return name python-barbicanclient-4.10.0/functionaltests/run_tests.sh0000775000175000017500000000132713620530200023701 0ustar zuulzuul00000000000000#!/bin/bash # # 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. # Install test-requirements pip install -r /opt/stack/new/python-barbicanclient/test-requirements.txt echo "Running functional tests on $(python -V)" nosetests -v . python-barbicanclient-4.10.0/functionaltests/cli/0000775000175000017500000000000013620530306022067 5ustar zuulzuul00000000000000python-barbicanclient-4.10.0/functionaltests/cli/__init__.py0000664000175000017500000000000013620530200024157 0ustar zuulzuul00000000000000python-barbicanclient-4.10.0/functionaltests/cli/base.py0000664000175000017500000000140313620530200023342 0ustar zuulzuul00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ from functionaltests.base import BaseTestCase class CmdLineTestCase(BaseTestCase): def setUp(self): self.LOG.info('Starting: %s', self._testMethodName) super(CmdLineTestCase, self).setUp() python-barbicanclient-4.10.0/functionaltests/cli/v1/0000775000175000017500000000000013620530306022415 5ustar zuulzuul00000000000000python-barbicanclient-4.10.0/functionaltests/cli/v1/functional/0000775000175000017500000000000013620530306024557 5ustar zuulzuul00000000000000python-barbicanclient-4.10.0/functionaltests/cli/v1/functional/__init__.py0000664000175000017500000000000013620530200026647 0ustar zuulzuul00000000000000python-barbicanclient-4.10.0/functionaltests/cli/v1/smoke/0000775000175000017500000000000013620530306023533 5ustar zuulzuul00000000000000python-barbicanclient-4.10.0/functionaltests/cli/v1/smoke/test_container.py0000664000175000017500000000551413620530200027124 0ustar zuulzuul00000000000000# Copyright (c) 2015 Rackspace, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. from functionaltests.cli.base import CmdLineTestCase from functionaltests.cli.v1.behaviors import container_behaviors from functionaltests.cli.v1.behaviors import secret_behaviors from testtools import testcase class ContainerTestCase(CmdLineTestCase): def setUp(self): super(ContainerTestCase, self).setUp() self.secret_behaviors = secret_behaviors.SecretBehaviors() self.container_behaviors = container_behaviors.ContainerBehaviors() def tearDown(self): super(ContainerTestCase, self).tearDown() self.secret_behaviors.delete_all_created_secrets() self.container_behaviors.delete_all_created_containers() @testcase.attr('positive') def test_container_create(self): secret_href = self.secret_behaviors.store_secret() container_href = self.container_behaviors.create_container( secret_hrefs=[secret_href]) self.assertIsNotNone(container_href) container = self.container_behaviors.get_container(container_href) self.assertEqual(container_href, container['Container href']) @testcase.attr('positive') def test_container_list(self): containers_to_create = 10 for _ in range(containers_to_create): secret_href = self.secret_behaviors.store_secret() self.container_behaviors.create_container( secret_hrefs=[secret_href]) container_list = self.container_behaviors.list_containers() self.assertGreaterEqual(len(container_list), containers_to_create) @testcase.attr('positive') def test_container_delete(self): secret_href = self.secret_behaviors.store_secret() container_href = self.container_behaviors.create_container( secret_hrefs=[secret_href]) self.container_behaviors.delete_container(container_href) container = self.container_behaviors.get_container(container_href) self.assertFalse(container) @testcase.attr('positive') def test_container_get(self): secret_href = self.secret_behaviors.store_secret() container_href = self.container_behaviors.create_container( secret_hrefs=[secret_href]) container = self.container_behaviors.get_container(container_href) self.assertIsNotNone(container) python-barbicanclient-4.10.0/functionaltests/cli/v1/smoke/__init__.py0000664000175000017500000000000013620530200025623 0ustar zuulzuul00000000000000python-barbicanclient-4.10.0/functionaltests/cli/v1/smoke/test_secret.py0000664000175000017500000001340113620530200026421 0ustar zuulzuul00000000000000# Copyright (c) 2015 Rackspace, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. from functionaltests.cli.base import CmdLineTestCase from functionaltests.cli.v1.behaviors.secret_behaviors import SecretBehaviors from functionaltests.common import keys from functionaltests import utils from testtools import testcase @utils.parameterized_test_case class SecretTestCase(CmdLineTestCase): def setUp(self): super(SecretTestCase, self).setUp() self.secret_behaviors = SecretBehaviors() self.expected_payload = "Top secret payload for secret smoke tests" self.payload_content_type = "text/plain" def tearDown(self): super(SecretTestCase, self).tearDown() self.secret_behaviors.delete_all_created_secrets() @utils.parameterized_dataset({ 'symmetric': ['symmetric', 'aes', '128', ('\x00\x01\x02\x03\x04\x05\x06\x07' '\x00\x01\x02\x03\x04\x05\x06\x07')], 'private': ['private', 'rsa', '2048', keys.get_private_key_pem()], 'public': ['public', 'rsa', '2048', keys.get_public_key_pem()], 'certificate': ['certificate', 'rsa', '2048', keys.get_certificate_pem()], 'opaque': ['opaque', None, None, (b'\x00\x01\x02\x03\x04\x05\x06\x07')], 'passphrase': ['passphrase', None, None, keys.get_passphrase_txt()], }) @testcase.attr('positive') def test_secret_store_with_secret_type(self, secret_type, algorithm, bit_length, secret): payload = secret secret_argv = ['--secret-type', secret_type] if algorithm: secret_argv.extend(['--algorithm', algorithm]) if bit_length: secret_argv.extend(['--bit-length', bit_length]) secret_href = self.secret_behaviors.store_secret(payload, secret_argv) self.assertIsNotNone(secret_href) secret = self.secret_behaviors.get_secret(secret_href) self.assertEqual(secret_href, secret['Secret href']) @testcase.attr('positive') def test_secret_store(self): secret_href = self.secret_behaviors.store_secret() self.assertIsNotNone(secret_href) secret = self.secret_behaviors.get_secret(secret_href) self.assertEqual(secret_href, secret['Secret href']) @testcase.attr('positive') def test_secret_update(self): secret_href = self.secret_behaviors.store_secret( payload=None) payload = 'time for an ice cold!!!' self.assertIsNotNone(secret_href) self.secret_behaviors.update_secret(secret_href, payload) payload_update = self.secret_behaviors.get_secret_payload(secret_href) self.assertEqual(payload, payload_update) @testcase.attr('positive') def test_secret_list(self): secrets_to_create = 10 for _ in range(secrets_to_create): self.secret_behaviors.store_secret() secret_list = self.secret_behaviors.list_secrets() self.assertGreaterEqual(len(secret_list), secrets_to_create) @testcase.attr('positive') def test_secret_delete(self): secret_href = self.secret_behaviors.store_secret() self.secret_behaviors.delete_secret(secret_href) secret = self.secret_behaviors.get_secret(secret_href) self.assertEqual(0, len(secret)) @testcase.attr('positive') def test_secret_get(self): secret_href = self.secret_behaviors.store_secret() secret = self.secret_behaviors.get_secret(secret_href) self.assertIsNotNone(secret) @testcase.attr('positive') def test_secret_get_payload(self): secret_href = self.secret_behaviors.store_secret( payload=self.expected_payload) payload = self.secret_behaviors.get_secret_payload(secret_href) self.assertEqual(payload, self.expected_payload) @testcase.attr('positive') def test_secret_get_raw_payload(self): secret_href = self.secret_behaviors.store_secret( payload=self.expected_payload) payload = self.secret_behaviors.get_secret_payload(secret_href, raw=True) self.assertEqual(payload, self.expected_payload) @testcase.attr('positive') def test_secret_file_parameter_read(self): secret_href = self.secret_behaviors.store_secret( payload=self.expected_payload) self.secret_behaviors.get_secret_file(secret_href=secret_href) payload = self.secret_behaviors.read_secret_test_file() self.assertEqual(payload, self.expected_payload) @testcase.attr('positive') def test_secret_file_parameter_write(self): self.secret_behaviors.write_secret_test_file( payload=self.expected_payload) secret_href = self.secret_behaviors.store_secret_file() payload = self.secret_behaviors.get_secret_payload(secret_href) self.assertEqual(payload, self.expected_payload) python-barbicanclient-4.10.0/functionaltests/cli/v1/smoke/test_acl.py0000664000175000017500000002476613620530200025713 0ustar zuulzuul00000000000000# 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. from functionaltests.cli.base import CmdLineTestCase from functionaltests.cli.v1.behaviors import acl_behaviors from functionaltests.cli.v1.behaviors import container_behaviors from functionaltests.cli.v1.behaviors import secret_behaviors from functionaltests import utils from testtools import testcase ARGS_TYPE = {'short_arg_false': [False], 'short_arg_true': [True]} @utils.parameterized_test_case class ACLTestCase(CmdLineTestCase): def setUp(self): super(ACLTestCase, self).setUp() self.secret_behaviors = secret_behaviors.SecretBehaviors() self.container_behaviors = container_behaviors.ContainerBehaviors() self.acl_behaviors = acl_behaviors.ACLBehaviors() def tearDown(self): super(ACLTestCase, self).tearDown() self.acl_behaviors.delete_all_created_acls() self.container_behaviors.delete_all_created_containers() self.secret_behaviors.delete_all_created_secrets() @utils.parameterized_dataset(ARGS_TYPE) @testcase.attr('positive') def test_acl_submit(self, use_short_arg): secret_ref = self.secret_behaviors.store_secret() container_ref = self.container_behaviors.create_container( secret_hrefs=[secret_ref]) data = self.acl_behaviors.acl_submit(entity_ref=secret_ref, users=['u1', 'u2'], use_short_arg=use_short_arg) self.assertIsNotNone(data) self.assertIn('u1', data['Users']) self.assertIn('u2', data['Users']) self.assertEqual('True', data['Project Access']) self.assertIn(secret_ref, data['Secret ACL Ref']) data = self.acl_behaviors.acl_submit(entity_ref=container_ref, users=['u2', 'u3'], use_short_arg=use_short_arg) self.assertIsNotNone(data) self.assertIn('u3', data['Users']) self.assertNotIn('u1', data['Users']) self.assertEqual('True', data['Project Access']) self.assertIn(container_ref, data['Container ACL Ref']) @utils.parameterized_dataset(ARGS_TYPE) @testcase.attr('positive') def test_acl_submit_for_overwriting_existing_users(self, use_short_arg): secret_ref = self.secret_behaviors.store_secret() container_ref = self.container_behaviors.create_container( secret_hrefs=[secret_ref]) data = self.acl_behaviors.acl_submit(entity_ref=secret_ref, users=['u1', 'u2'], project_access=False, use_short_arg=use_short_arg) self.assertIsNotNone(data) self.assertIn('u1', data['Users']) self.assertIn('u2', data['Users']) self.assertEqual('False', data['Project Access']) self.assertIn(secret_ref, data['Secret ACL Ref']) data = self.acl_behaviors.acl_submit(entity_ref=container_ref, users=[], project_access=True, use_short_arg=use_short_arg) self.assertIsNotNone(data) self.assertNotIn('u1', data['Users']) self.assertNotIn('u2', data['Users']) self.assertEqual('True', data['Project Access']) self.assertIn(container_ref, data['Container ACL Ref']) @utils.parameterized_dataset(ARGS_TYPE) @testcase.attr('positive') def test_acl_add(self, use_short_arg): secret_ref = self.secret_behaviors.store_secret() data = self.acl_behaviors.acl_submit(entity_ref=secret_ref, project_access=False, users=['u1', 'u2']) self.assertIsNotNone(data) self.assertEqual('False', data['Project Access']) acls = self.acl_behaviors.acl_add(entity_ref=secret_ref, users=['u2', 'u3'], use_short_arg=use_short_arg) data = acls[0] # get 'read' operation ACL data self.assertIsNotNone(data) self.assertIn('u1', data['Users']) self.assertIn('u3', data['Users']) self.assertEqual('False', data['Project Access']) self.assertIn(secret_ref, data['Secret ACL Ref']) # make sure there is no change in existing users with blank users add acls = self.acl_behaviors.acl_add(entity_ref=secret_ref, users=[], project_access=False, use_short_arg=use_short_arg) data = acls[0] # get 'read' operation ACL data self.assertIsNotNone(data) self.assertIn('u1', data['Users']) self.assertIn('u2', data['Users']) self.assertIn('u3', data['Users']) acls = self.acl_behaviors.acl_add(entity_ref=secret_ref, users=None, project_access=True, use_short_arg=use_short_arg) data = acls[0] # get 'read' operation ACL data self.assertIsNotNone(data) self.assertIn('u2', data['Users']) self.assertEqual('True', data['Project Access']) @utils.parameterized_dataset(ARGS_TYPE) @testcase.attr('positive') def test_acl_remove(self, use_short_arg): secret_ref = self.secret_behaviors.store_secret() container_ref = self.container_behaviors.create_container( secret_hrefs=[secret_ref]) data = self.acl_behaviors.acl_submit(entity_ref=container_ref, project_access=False, users=['u1', 'u2']) self.assertIsNotNone(data) self.assertEqual('False', data['Project Access']) acls = self.acl_behaviors.acl_remove(entity_ref=container_ref, users=['u2', 'u3'], use_short_arg=use_short_arg) data = acls[0] # get 'read' operation ACL data self.assertIsNotNone(data) self.assertIn('u1', data['Users']) self.assertNotIn('u2', data['Users']) self.assertEqual('False', data['Project Access']) self.assertIn(container_ref, data['Container ACL Ref']) # make sure there is no change in existing users with blank users # remove acls = self.acl_behaviors.acl_remove(entity_ref=container_ref, users=[], project_access=False, use_short_arg=use_short_arg) data = acls[0] # get 'read' operation ACL data self.assertIsNotNone(data) self.assertIn('u1', data['Users']) self.assertEqual('False', data['Project Access']) @testcase.attr('positive') def test_acl_get(self): secret_ref = self.secret_behaviors.store_secret() container_ref = self.container_behaviors.create_container( secret_hrefs=[secret_ref]) data = self.acl_behaviors.acl_submit(entity_ref=secret_ref, users=['u1', 'u2']) self.assertIsNotNone(data) data = self.acl_behaviors.acl_get(entity_ref=secret_ref) self.assertIn('u2', data['Users']) self.assertEqual('True', data['Project Access']) self.assertEqual(secret_ref + "/acl", data['Secret ACL Ref']) data = self.acl_behaviors.acl_get(entity_ref=secret_ref + "///") self.assertIn('u2', data['Users']) self.assertEqual('True', data['Project Access']) self.assertEqual(secret_ref + "/acl", data['Secret ACL Ref']) data = self.acl_behaviors.acl_submit(entity_ref=container_ref, project_access=False, users=['u4', 'u5']) self.assertIsNotNone(data) data = self.acl_behaviors.acl_get(entity_ref=container_ref) self.assertIn('u4', data['Users']) self.assertIn('u5', data['Users']) self.assertEqual('False', data['Project Access']) self.assertEqual(container_ref + '/acl', data['Container ACL Ref']) @testcase.attr('positive') def test_acl_delete(self): secret_ref = self.secret_behaviors.store_secret() data = self.acl_behaviors.acl_submit(entity_ref=secret_ref, users=['u1', 'u2']) self.assertIsNotNone(data) self.acl_behaviors.acl_delete(entity_ref=secret_ref) data = self.acl_behaviors.acl_get(entity_ref=secret_ref) self.assertEqual('[]', data['Users']) self.assertEqual('True', data['Project Access']) self.assertEqual(secret_ref + "/acl", data['Secret ACL Ref']) # deleting again should be okay as secret or container always has # default ACL settings self.acl_behaviors.acl_delete(entity_ref=secret_ref + '////') data = self.acl_behaviors.acl_get(entity_ref=secret_ref) self.assertEqual('[]', data['Users']) self.assertEqual('True', data['Project Access']) @testcase.attr('negative') def test_acl_entity_ref_input_with_acl_uri(self): secret_ref = self.secret_behaviors.store_secret() container_ref = self.container_behaviors.create_container( secret_hrefs=[secret_ref]) data = self.acl_behaviors.acl_submit(entity_ref=secret_ref, users=['u1', 'u2']) self.assertIsNotNone(data) err = self.acl_behaviors.acl_delete(entity_ref=container_ref + '/acl') # above container ACL ref is passed instead of expected container_ref self.assertIn('Container ACL URI', err) err = self.acl_behaviors.acl_delete(entity_ref=secret_ref + '/acl') # above secret ACL ref is passed instead of expected secret_ref self.assertIn('Secret ACL URI', err) python-barbicanclient-4.10.0/functionaltests/cli/v1/smoke/test_help.py0000664000175000017500000000262013620530200026065 0ustar zuulzuul00000000000000# Copyright (c) 2015 Rackspace, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. from functionaltests.cli.base import CmdLineTestCase from functionaltests.cli.v1.behaviors import base_behaviors from functionaltests import utils from testtools import testcase @utils.parameterized_test_case class HelpTestCase(CmdLineTestCase): def setUp(self): super(HelpTestCase, self).setUp() self.help_behaviors = base_behaviors.BaseBehaviors() def tearDown(self): super(HelpTestCase, self).tearDown() @utils.parameterized_dataset({ 'dash_h': [['-h']], 'doubledash_help': [['--help']] }) @testcase.attr('positive') def test_help(self, argv): stdout, stderr = self.help_behaviors.issue_barbican_command(argv) self.assertIsNotNone(stdout, "{0} returned None".format(argv)) self.assertGreater(len(stdout), 0, "{0} invalid length".format(argv)) python-barbicanclient-4.10.0/functionaltests/cli/v1/__init__.py0000664000175000017500000000000013620530200024505 0ustar zuulzuul00000000000000python-barbicanclient-4.10.0/functionaltests/cli/v1/behaviors/0000775000175000017500000000000013620530306024377 5ustar zuulzuul00000000000000python-barbicanclient-4.10.0/functionaltests/cli/v1/behaviors/__init__.py0000664000175000017500000000000013620530200026467 0ustar zuulzuul00000000000000python-barbicanclient-4.10.0/functionaltests/cli/v1/behaviors/acl_behaviors.py0000664000175000017500000001653113620530200027551 0ustar zuulzuul00000000000000# 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. import logging import base_behaviors class ACLBehaviors(base_behaviors.BaseBehaviors): _args_map_list = {'users': ['--user', '-u'], 'operation_type': ['--operation-type', '-o'] } def __init__(self): super(ACLBehaviors, self).__init__() self.LOG = logging.getLogger(type(self).__name__) self.acl_entity_set = set() def _add_ref_arg(self, argv, entity_ref): argv.extend([entity_ref]) return argv def _add_per_acl_args(self, argv, users=[], project_access=None, operation_type=None, use_short_arg=False): index = 1 if use_short_arg else 0 if users is not None: if users: for user in users: argv.extend([self._args_map_list['users'][index], user]) else: # empty list case argv.extend([self._args_map_list['users'][index]]) if project_access is not None: if project_access: argv.extend(['--project-access']) else: argv.extend(['--no-project-access']) if operation_type and operation_type is not 'read': argv.extend([self._args_map_list['operation_type'][index], operation_type]) return argv def acl_delete(self, entity_ref): """Delete a secret or container acl :param entity_ref: Reference to secret or container entity :return: If error returns stderr string otherwise returns None. """ argv = ['acl', 'delete'] self.add_auth_and_endpoint(argv) self._add_ref_arg(argv, entity_ref) _, stderr = self.issue_barbican_command(argv) self.acl_entity_set.discard(entity_ref) if stderr: return stderr def acl_get(self, entity_ref): """Get a 'read' ACL setting for a secret or a container. :param entity_ref: Reference to secret or container entity :return: dict of 'read' operation ACL settings if found otherwise empty dict in case of error. """ argv = ['acl', 'get'] self.add_auth_and_endpoint(argv) self._add_ref_arg(argv, entity_ref) stdout, stderr = self.issue_barbican_command(argv) if '4xx Client error: Not Found' in stderr: return {} acl_list = self._prettytable_to_list(stdout) return acl_list[0] # return first ACL which is for 'read' op type def acl_submit(self, entity_ref, users=None, project_access=None, use_short_arg=False, operation_type='read'): """Submits a secret or container ACL :param entity_ref: Reference to secret or container entity :param users: List of users for ACL :param project_access: Flag to pass for project access behavior :param use_short_arg: Flag to indicate if use short arguments in cli. Default is False :param operation_type: ACL operation type. Default is 'read' as Barbican currently supports only that type of operation. :return: dict of 'read' operation ACL settings if found otherwise empty dict in case of error. """ argv = ['acl', 'submit'] self.add_auth_and_endpoint(argv) self._add_per_acl_args(argv, users=users, project_access=project_access, use_short_arg=use_short_arg, operation_type=operation_type) self._add_ref_arg(argv, entity_ref) stdout, stderr = self.issue_barbican_command(argv) if '4xx Client error: Not Found' in stderr: return {} acl_list = self._prettytable_to_list(stdout) self.acl_entity_set.add(entity_ref) return acl_list[0] # return first ACL which is for 'read' op type def acl_add(self, entity_ref, users=None, project_access=None, use_short_arg=False, operation_type='read'): """Add to a secret or container ACL :param entity_ref: Reference to secret or container entity :param users: List of users to be added in ACL :param project_access: Flag to pass for project access behavior :param use_short_arg: Flag to indicate if use short arguments in cli. Default is False :param operation_type: ACL operation type. Default is 'read' as Barbican currently supports only that type of operation. :return: dict of 'read' operation ACL settings if found otherwise empty dict in case of error. """ argv = ['acl', 'user', 'add'] self.add_auth_and_endpoint(argv) self._add_per_acl_args(argv, users=users, project_access=project_access, use_short_arg=use_short_arg, operation_type=operation_type) self._add_ref_arg(argv, entity_ref) stdout, stderr = self.issue_barbican_command(argv) if '4xx Client error: Not Found' in stderr: return {} self.acl_entity_set.add(entity_ref) acl_list = self._prettytable_to_list(stdout) return acl_list def acl_remove(self, entity_ref, users=None, project_access=None, use_short_arg=False, operation_type='read'): """Remove users from a secret or container ACL :param entity_ref: Reference to secret or container entity :param users: List of users to be removed from ACL :param project_access: Flag to pass for project access behavior :param use_short_arg: Flag to indicate if use short arguments in cli. Default is False :param operation_type: ACL operation type. Default is 'read' as Barbican currently supports only that type of operation. :return: dict of 'read' operation ACL settings if found otherwise empty dict in case of error. """ argv = ['acl', 'user', 'remove'] self.add_auth_and_endpoint(argv) self._add_per_acl_args(argv, users=users, project_access=project_access, use_short_arg=use_short_arg, operation_type=operation_type) self._add_ref_arg(argv, entity_ref) stdout, stderr = self.issue_barbican_command(argv) if '4xx Client error: Not Found' in stderr: return {} acl_list = self._prettytable_to_list(stdout) return acl_list def delete_all_created_acls(self): """Delete all ACLs that we created""" entities_to_delete = [entry for entry in self.acl_entity_set] for entity_ref in entities_to_delete: self.acl_delete(entity_ref) python-barbicanclient-4.10.0/functionaltests/cli/v1/behaviors/container_behaviors.py0000664000175000017500000000624113620530200030771 0ustar zuulzuul00000000000000# Copyright (c) 2015 Rackspace, Inc. # # 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. import logging import base_behaviors class ContainerBehaviors(base_behaviors.BaseBehaviors): def __init__(self): super(ContainerBehaviors, self).__init__() self.LOG = logging.getLogger(type(self).__name__) self.container_hrefs_to_delete = [] def delete_container(self, container_href): """Delete a container :param container_href the href to the container to delete """ argv = ['secret', 'container', 'delete'] self.add_auth_and_endpoint(argv) argv.extend([container_href]) stdout, stderr = self.issue_barbican_command(argv) self.container_hrefs_to_delete.remove(container_href) def create_container(self, secret_hrefs=[]): """Create a container :param secret_hrefs A list of existing secrets :return: the href to the newly created container """ argv = ['secret', 'container', 'create'] self.add_auth_and_endpoint(argv) for secret_href in secret_hrefs: argv.extend(['--secret', secret_href]) stdout, stderr = self.issue_barbican_command(argv) container_data = self._prettytable_to_dict(stdout) container_href = container_data['Container href'] self.container_hrefs_to_delete.append(container_href) return container_href def get_container(self, container_href): """Get a container :param: the href to a container :return: dict of container values, or an empty dict if the container is not found. """ argv = ['secret', 'container', 'get'] self.add_auth_and_endpoint(argv) argv.extend([container_href]) stdout, stderr = self.issue_barbican_command(argv) if '4xx Client error: Not Found' in stderr: return {} container_data = self._prettytable_to_dict(stdout) return container_data def list_containers(self): """List containers :return: a list of containers """ argv = ['secret', 'container', 'list'] self.add_auth_and_endpoint(argv) stdout, stderr = self.issue_barbican_command(argv) container_list = self._prettytable_to_list(stdout) return container_list def delete_all_created_containers(self): """Delete all containers that we created""" # Create a copy of the list -- otherwise delete_container will remove # items from the list as we are iterating over it containers_to_delete = list(self.container_hrefs_to_delete) for href in containers_to_delete: self.delete_container(href) python-barbicanclient-4.10.0/functionaltests/cli/v1/behaviors/secret_behaviors.py0000664000175000017500000001541413620530200030276 0ustar zuulzuul00000000000000# Copyright (c) 2015 Rackspace, Inc. # # 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. import logging import base_behaviors class SecretBehaviors(base_behaviors.BaseBehaviors): def __init__(self): super(SecretBehaviors, self).__init__() self.LOG = logging.getLogger(type(self).__name__) self.secret_hrefs_to_delete = [] def update_secret(self, secret_href, payload): """Update a secret :param secret_href the href to the secret to update. :param payload the payload to put into the secret. :param payload_content_type the payload content type. """ argv = ['secret', 'update'] self.add_auth_and_endpoint(argv) argv.extend([secret_href]) argv.extend([payload]) stdout, stderr = self.issue_barbican_command(argv) def delete_secret(self, secret_href): """Delete a secret :param secret_href the href to the secret to delete """ argv = ['secret', 'delete'] self.add_auth_and_endpoint(argv) argv.extend([secret_href]) stdout, stderr = self.issue_barbican_command(argv) self.secret_hrefs_to_delete.remove(secret_href) def store_secret(self, payload="Payload for testing", store_argv=[]): """Store (aka create) a secret The store_argv parameter allows additional command line parameters for the store operation to be specified. This can be used to specify -a for algorithm as an example. :param payload The payload to use when storing the secret :param store_argv The store command line parameters :return: the href to the newly created secret """ argv = ['secret', 'store'] self.add_auth_and_endpoint(argv) argv.extend(['--payload', payload]) argv.extend(store_argv) stdout, stderr = self.issue_barbican_command(argv) secret_data = self._prettytable_to_dict(stdout) secret_href = secret_data['Secret href'] self.secret_hrefs_to_delete.append(secret_href) return secret_href def store_secret_file(self, filename="/tmp/storesecret", store_argv=[]): """Store (aka create) a secret from file The store_argv parameter allows additional command line parameters for the store operation to be specified. This can be used to specify -a for algorithm as an example. :param payload The payload to use when storing the secret :param store_argv The store command line parameters :return: the href to the newly created secret """ argv = ['secret', 'store'] self.add_auth_and_endpoint(argv) argv.extend(['--file', filename]) argv.extend(store_argv) stdout, stderr = self.issue_barbican_command(argv) secret_data = self._prettytable_to_dict(stdout) secret_href = secret_data['Secret href'] self.secret_hrefs_to_delete.append(secret_href) return secret_href def get_secret(self, secret_href): """Get a secret :param: the href to a secret :return: dict of secret values, or an empty dict if the secret is not found. """ argv = ['secret', 'get'] self.add_auth_and_endpoint(argv) argv.extend([secret_href]) stdout, stderr = self.issue_barbican_command(argv) if '4xx Client error: Not Found' in stderr: return {} secret_data = self._prettytable_to_dict(stdout) return secret_data def get_secret_payload(self, secret_href, raw=False): """Get a secret :param: the href to a secret :param raw if True then add "-f value" to get raw payload (ie not within a PrettyTable). If False then omit -f. :return: string representing the secret payload. """ argv = ['secret', 'get'] self.add_auth_and_endpoint(argv) argv.extend([secret_href]) argv.extend(['--payload']) if raw: argv.extend(['-f', 'value']) stdout, stderr = self.issue_barbican_command(argv) if '4xx Client error: Not Found' in stderr: return {} if raw: secret = stdout.rstrip() else: secret_data = self._prettytable_to_dict(stdout) secret = secret_data['Payload'] return secret def get_secret_file(self, secret_href, filename='/tmp/getsecret'): """Get a secret and store in a file :param: the href to a secret :param filename: name of file to store secret in :return string representing the file name. """ argv = ['secret', 'get'] self.add_auth_and_endpoint(argv) argv.extend([secret_href]) argv.extend(['--file', filename]) stdout, stderr = self.issue_barbican_command(argv) if '4xx Client error: Not Found' in stderr: return {} return filename def list_secrets(self): """List secrets :return: a list of secrets """ argv = ['secret', 'list'] self.add_auth_and_endpoint(argv) stdout, stderr = self.issue_barbican_command(argv) secret_list = self._prettytable_to_list(stdout) return secret_list def delete_all_created_secrets(self): """Delete all secrets that we created""" # Create a copy of the list -- otherwise delete_secret will remove # items from the list as we are iterating over it secrets_to_delete = list(self.secret_hrefs_to_delete) for href in secrets_to_delete: self.delete_secret(href) def read_secret_test_file(self, filename='/tmp/getsecret'): """Read payload from file used in testing :param filename: name of file to write :return contents of the file """ with open(filename, "r") as myfile: data = myfile.read() return data def write_secret_test_file(self, filename='/tmp/storesecret', payload="Payload for testing"): """Write payload to file for use in testing :param filename: name of file to write :param payload: data to store :return """ myfile = open(filename, "wb") myfile.write(payload) myfile.close() return python-barbicanclient-4.10.0/functionaltests/cli/v1/behaviors/base_behaviors.py0000664000175000017500000001201113620530200027711 0ustar zuulzuul00000000000000""" Copyright 2015 Rackspace 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. """ import exceptions as exc import logging import re import six from barbicanclient import barbican from functionaltests.common import config CONF = config.get_config() class BaseBehaviors(object): def __init__(self): self.LOG = logging.getLogger(type(self).__name__) self.cmdline_client = barbican.Barbican() def add_auth_and_endpoint(self, arg_list): """Update an argument list with authentication and endpoint data Keystone v3 introduced the concept of a domain, so only the v3 flavor will include domain names. Keystone v3 changed "tenant" to "project" so the v3 flavor uses the term 'project' in its args while v2 uses 'tenant'. Both v2 and v2 require the auth URL, userid/password, and barbican endpoint URL. :param arg_list: the current argument list :return: the argument list is updated with the authentication and endpoint args """ if 'v3' in CONF.identity.auth_version.lower(): arg_list.extend(['--os-project-name', CONF.keymanager.project_name]) # NOTE(jaosorior): Should we add the user_domain_name to the # config? arg_list.extend( ['--os-user-domain-name', CONF.keymanager.project_domain_name]) arg_list.extend( ['--os-project-domain-name', CONF.keymanager.project_domain_name]) arg_list.extend(['--os-identity-api-version', '3']) else: arg_list.extend(['--os-tenant-name', CONF.keymanager.project_name]) arg_list.extend(['--os-identity-api-version', '2.0']) arg_list.extend(['--os-auth-url', CONF.identity.uri]) arg_list.extend(['--os-username', CONF.keymanager.username, '--os-password', CONF.keymanager.password]) arg_list.extend(['--endpoint', CONF.keymanager.url]) self.LOG.info('updated command string: %s', arg_list) def issue_barbican_command(self, argv): """Issue the barbican command and return its output. The barbican command sometimes raises SystemExit, but not always, so we will handle either situation here. Also we will create new stdout/stderr streams for each command so that any output from a previous command doesn't contaminate the new command. :param argv: dict of keyword arguments to pass to the command. This does NOT include "barbican" - that's not needed. :return: Two strings - one the captured stdout and one the captured stderr. """ try: self.cmdline_client.stdout = six.StringIO() self.cmdline_client.stderr = six.StringIO() self.cmdline_client.run(argv) except exc.SystemExit: pass outstr = self.cmdline_client.stdout.getvalue() errstr = self.cmdline_client.stderr.getvalue() return outstr, errstr def _prettytable_to_dict(self, str): """Create a dict from the values in a PrettyTable string. :param str: a string representing a PrettyTable output from a barbican secret store or get command. :return: a dict containing the fields and values from the output. """ retval = {} if str is not None and len(str) > 0: table_body = re.split('\+-*\+-*\+\n', str)[2:-1] lines = table_body[0].split('\n') for line in lines: if len(line) > 0: row = line.split('|') key = row[1].strip() value = row[2].strip() retval[key] = value return retval def _prettytable_to_list(self, str): """Create a list from the values in a PrettyTable string. :param str: a string representing a PrettyTable output from a barbican secret list command. :return: a list containing one dict for each column in the table. If there are no entries then an empty list will be returned. """ retval = [] if str is not None and len(str) > 0: rows = re.findall('\|(.*?)\n', str) # Remove header header_row = rows.pop(0) key_names = re.findall('\s*(.*?)\s*\|', header_row) for row in rows: values = re.findall('\s*(.*?)\s*\|', row) entry_dict = dict(zip(key_names, values)) retval.append(entry_dict) return retval python-barbicanclient-4.10.0/functionaltests/client/0000775000175000017500000000000013620530306022576 5ustar zuulzuul00000000000000python-barbicanclient-4.10.0/functionaltests/client/test_client_connectivity.py0000664000175000017500000001603213620530200030256 0ustar zuulzuul00000000000000# Copyright (c) 2015 Ericsson AB. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. from barbicanclient import client from barbicanclient import exceptions from functionaltests.base import BaseTestCase from functionaltests.common import config from keystoneauth1 import exceptions as ks_exceptions from keystoneauth1 import identity from keystoneauth1 import session CONF = config.get_config() class WhenTestingClientConnectivity(BaseTestCase): @classmethod def setUpClass(cls): super(WhenTestingClientConnectivity, cls).setUpClass() if 'v2' in CONF.identity.auth_version: cls.auth = identity.Password( auth_url=CONF.identity.uri, username=CONF.keymanager.username, password=CONF.keymanager.password, tenant_name=CONF.keymanager.project_name) else: cls.auth = identity.Password( auth_url=CONF.identity.uri, username=CONF.keymanager.username, user_domain_name=CONF.identity.domain_name, password=CONF.keymanager.password, project_name=CONF.keymanager.project_name, project_domain_name=CONF.keymanager.project_domain_name) # enables the tests in this class to share a keystone token cls.sess = session.Session(auth=cls.auth) def setUp(self): self.LOG.info('Starting: %s', self._testMethodName) super(WhenTestingClientConnectivity, self).setUp() def assert_client_can_contact_barbican(self, client): """Asserts that the client has connectivity to Barbican. If there was an error with the connectivity, the operations that are attempted through the client would throw an exception. """ containers = client.containers.list() orders = client.orders.list() secrets = client.secrets.list() self.assertIsNotNone(containers) self.assertIsNotNone(orders) self.assertIsNotNone(secrets) def assert_client_cannot_contact_barbican(self, client): self.assertRaises(exceptions.HTTPClientError, client.containers.list) self.assertRaises(exceptions.HTTPClientError, client.orders.list) self.assertRaises(exceptions.HTTPClientError, client.secrets.list) def assert_client_cannot_get_endpoint(self, client): self.assertRaises(ks_exceptions.EndpointNotFound, client.containers.list) self.assertRaises(ks_exceptions.EndpointNotFound, client.orders.list) self.assertRaises(ks_exceptions.EndpointNotFound, client.secrets.list) def test_can_access_server_if_endpoint_and_session_specified(self): barbicanclient = client.Client( endpoint=CONF.keymanager.url, project_id=CONF.keymanager.project_id, session=self.sess) self.assert_client_can_contact_barbican(barbicanclient) def test_client_can_access_server_if_no_endpoint_specified(self): barbicanclient = client.Client( project_id=CONF.keymanager.project_id, session=self.sess) self.assert_client_can_contact_barbican(barbicanclient) def test_client_can_access_server_if_no_session_specified(self): barbicanclient = client.Client( endpoint=CONF.keymanager.url, project_id=CONF.keymanager.project_id, auth=self.auth) self.assert_client_can_contact_barbican(barbicanclient) def test_client_can_access_server_if_endpoint_filters_specified(self): barbicanclient = client.Client( project_id=CONF.keymanager.project_id, auth=self.auth, interface=client._DEFAULT_SERVICE_INTERFACE, service_type=client._DEFAULT_SERVICE_TYPE, version=client._DEFAULT_API_VERSION) self.assert_client_can_contact_barbican(barbicanclient) def test_client_cannot_access_server_if_endpoint_filter_wrong(self): barbicanclient = client.Client( project_id=CONF.keymanager.project_id, auth=self.auth, interface=client._DEFAULT_SERVICE_INTERFACE, service_type='wrong-service-type', version=client._DEFAULT_API_VERSION) self.assert_client_cannot_get_endpoint(barbicanclient) barbicanclient = client.Client( project_id=CONF.keymanager.project_id, auth=self.auth, interface='wrong-interface', service_type=client._DEFAULT_SERVICE_TYPE, version=client._DEFAULT_API_VERSION) self.assert_client_cannot_get_endpoint(barbicanclient) barbicanclient = client.Client( project_id=CONF.keymanager.project_id, auth=self.auth, interface=client._DEFAULT_SERVICE_INTERFACE, service_type=client._DEFAULT_SERVICE_TYPE, service_name='wrong-service-name', version=client._DEFAULT_API_VERSION) self.assert_client_cannot_get_endpoint(barbicanclient) barbicanclient = client.Client( project_id=CONF.keymanager.project_id, auth=self.auth, interface=client._DEFAULT_SERVICE_INTERFACE, service_type=client._DEFAULT_SERVICE_TYPE, region_name='wrong-region-name', version=client._DEFAULT_API_VERSION) self.assert_client_cannot_get_endpoint(barbicanclient) def test_cannot_create_client_if_nonexistent_version_specified(self): self.assertRaises(exceptions.UnsupportedVersion, client.Client, **{"project_id": CONF.keymanager.project_id, "auth": self.auth, "interface": client._DEFAULT_SERVICE_INTERFACE, "service_type": client._DEFAULT_SERVICE_TYPE, "version": 'wrong-version'}) self.assertRaises(exceptions.UnsupportedVersion, client.Client, **{"endpoint": CONF.keymanager.url, "project_id": CONF.keymanager.project_id, "auth": self.auth, "version": 'nonexistent_version'}) def test_client_can_access_server_if_no_version_is_specified(self): barbicanclient = client.Client( project_id=CONF.keymanager.project_id, auth=self.auth, interface=client._DEFAULT_SERVICE_INTERFACE, service_type=client._DEFAULT_SERVICE_TYPE) self.assert_client_can_contact_barbican(barbicanclient) python-barbicanclient-4.10.0/functionaltests/client/__init__.py0000664000175000017500000000000013620530200024666 0ustar zuulzuul00000000000000python-barbicanclient-4.10.0/functionaltests/client/base.py0000664000175000017500000000346213620530200024060 0ustar zuulzuul00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ from barbicanclient import client from functionaltests.base import BaseTestCase from functionaltests.common import config from keystoneauth1 import identity from keystoneauth1 import session CONF = config.get_config() class TestCase(BaseTestCase): def setUp(self): self.LOG.info('Starting: %s', self._testMethodName) super(TestCase, self).setUp() if 'v2' in CONF.identity.auth_version: self.auth = identity.Password( auth_url=CONF.identity.uri, username=CONF.keymanager.username, password=CONF.keymanager.password, tenant_name=CONF.keymanager.project_name) else: self.auth = identity.Password( auth_url=CONF.identity.uri, username=CONF.keymanager.username, user_domain_name=CONF.identity.domain_name, password=CONF.keymanager.password, project_name=CONF.keymanager.project_name, project_domain_name=CONF.keymanager.project_domain_name) self.sess = session.Session(auth=self.auth) self.barbicanclient = client.Client( endpoint=CONF.keymanager.url, project_id=CONF.keymanager.project_id, session=self.sess) python-barbicanclient-4.10.0/functionaltests/client/v1/0000775000175000017500000000000013620530306023124 5ustar zuulzuul00000000000000python-barbicanclient-4.10.0/functionaltests/client/v1/functional/0000775000175000017500000000000013620530306025266 5ustar zuulzuul00000000000000python-barbicanclient-4.10.0/functionaltests/client/v1/functional/test_containers.py0000664000175000017500000002771313620530200031047 0ustar zuulzuul00000000000000# Copyright (c) 2015 Rackspace, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. from functionaltests.client import base from functionaltests.common import cleanup from functionaltests import utils from testtools import testcase from barbicanclient import exceptions create_secret_defaults_data = { "name": "AES key", "expiration": "2020-02-28T19:14:44.180394", "algorithm": "aes", "bit_length": 256, "mode": "cbc", "payload": "gF6+lLoF3ohA9aPRpt+6bQ==", "payload_content_type": "application/octet-stream", "payload_content_encoding": "base64", } create_container_defaults_data = { "name": "containername", "secrets": {} } create_container_rsa_data = { "name": "rsacontainer", } create_container_empty_data = { "name": None, "secrets": {} } accepted_str_values = { 'alphanumeric': ['a2j3j6ll9'], 'punctuation': ['~!@#$%^&*()_+`-={}[]|:;<>,.?'], 'len_255': [str(bytearray().zfill(255))], 'uuid': ['54262d9d-4bc7-4821-8df0-dc2ca8e112bb'], 'empty': [''] } @utils.parameterized_test_case class BaseContainersTestCase(base.TestCase): def setUp(self): super(BaseContainersTestCase, self).setUp() self.cleanup = cleanup.CleanUp(self.barbicanclient) # Set up three secrets self.secret_ref_1, self.secret_1 = self._create_a_secret() self.secret_ref_2, self.secret_2 = self._create_a_secret() self.secret_ref_3, self.secret_3 = self._create_a_secret() self.secret_list = [self.secret_ref_1, self.secret_ref_2, self.secret_ref_3] secrets_dict = {'secret_1': self.secret_1, 'secret_2': self.secret_2, 'secret_3': self.secret_3} create_container_defaults_data['secrets'] = secrets_dict create_container_rsa_data['public_key'] = self.secret_1 create_container_rsa_data['private_key'] = self.secret_2 create_container_rsa_data['private_key_passphrase'] = self.secret_3 def tearDown(self): """Handles test cleanup. It should be noted that delete all secrets must be called before delete containers. """ self.cleanup.delete_all_entities() super(BaseContainersTestCase, self).tearDown() def _create_a_secret(self): secret = self.barbicanclient.secrets.create( **create_secret_defaults_data) secret_ref = self.cleanup.add_entity(secret) return secret_ref, secret @utils.parameterized_test_case class GenericContainersTestCase(BaseContainersTestCase): @testcase.attr('positive') def test_create_container_defaults_none_secret_name(self): """Covers creating a container with None as a secret name.""" container = self.barbicanclient.containers.create( **create_container_defaults_data) container.name = None container_ref = self.cleanup.add_entity(container) self.assertIsNotNone(container_ref) @testcase.attr('negative') def test_create_defaults_duplicate_secret_refs(self): """Covers creating a container with a duplicated secret ref.""" secrets = {'secret_1': self.secret_1, 'secret_2': self.secret_1, 'secret_3': self.secret_1} create_container_defaults_data['secrets'] = secrets container = self.barbicanclient.containers.create( **create_container_defaults_data) e = self.assertRaises( exceptions.HTTPClientError, container.store ) self.assertEqual(400, e.status_code) @testcase.attr('negative') def test_get_non_existent_container(self): """A get on a container that does not exist. This should return a container incorrectly specified error since the container does not have a correctly formatted UUID """ base_url = self.barbicanclient.containers._api.endpoint_override url = base_url + '/containers/notauuid' e = self.assertRaises(ValueError, self.barbicanclient.containers.get, url) self.assertEqual('Container incorrectly specified.', e.message) @testcase.attr('negative') def test_get_non_existent_container_valid_uuid(self): """A get on a container that does not exist with valid UUID This should return a 404. """ base_url = self.barbicanclient.containers._api.endpoint_override uuid = 'de305d54-75b4-431b-cccc-eb6b9e546013' url = base_url + '/containers/' + uuid e = self.assertRaises( exceptions.HTTPClientError, self.barbicanclient.containers.get, url ) self.assertEqual(404, e.status_code) @testcase.attr('negative') def test_delete_non_existent_container(self): """A delete on a container that does not exist. This should return a container incorrectly specified error since the container does not have a correctly formatted UUID """ base_url = self.barbicanclient.containers._api.endpoint_override url = base_url + '/containers/notauuid' e = self.assertRaises(ValueError, self.barbicanclient.containers.get, url) self.assertEqual('Container incorrectly specified.', e.message) @testcase.attr('negative') def test_delete_non_existent_container_valid_uuid(self): """A delete on a container that does not exist with valid UUID This should return a 404. """ uuid = 'de305d54-75b4-431b-cccc-eb6b9e546013' base_url = self.barbicanclient.containers._api.endpoint_override url = base_url + '/containers/' + uuid e = self.assertRaises( exceptions.HTTPClientError, self.barbicanclient.containers.get, url ) self.assertEqual(404, e.status_code) @utils.parameterized_dataset({'0': [0], '1': [1], '50': [50]}) @testcase.attr('positive') def test_create_container_defaults_size(self, num_secrets): """Covers creating containers of various sizes.""" secrets = {} for i in range(0, num_secrets): secret_ref, secret = self._create_a_secret() secrets['other_secret{0}'.format(i)] = secret create_container_defaults_data['secrets'] = secrets container = self.barbicanclient.containers.create( **create_container_defaults_data) container_ref = self.cleanup.add_entity(container) self.assertIsNotNone(container_ref) @utils.parameterized_dataset(accepted_str_values) @testcase.attr('positive') def test_create_container_defaults_name(self, name): """Covers creating generic containers with various names.""" container = self.barbicanclient.containers.create( **create_container_defaults_data) container.name = name container_ref = self.cleanup.add_entity(container) self.assertIsNotNone(container_ref) @utils.parameterized_dataset(accepted_str_values) @testcase.attr('positive') def test_create_container_defaults_secret_name(self, name=None): """Covers creating containers with various secret ref names.""" secrets = {name: self.secret_1} create_container_defaults_data['secrets'] = secrets container = self.barbicanclient.containers.create( **create_container_defaults_data) container_ref = self.cleanup.add_entity(container) self.assertIsNotNone(container_ref) container_resp = self.barbicanclient.containers.get(container_ref) self.assertIsNotNone(container_resp.secret_refs.get(name)) @testcase.attr('positive') def test_container_read_with_acls(self): """Access default ACL settings data on recently created container. By default, 'read' ACL settings are there for a container. """ test_model = self.barbicanclient.containers.create( **create_container_defaults_data) container_ref = self.cleanup.add_entity(test_model) self.assertIsNotNone(container_ref) container_entity = self.barbicanclient.containers.get(container_ref) self.assertIsNotNone(container_entity.acls) self.assertIsNotNone(container_entity.acls.read) self.assertEqual([], container_entity.acls.read.users) @utils.parameterized_test_case class RSAContainersTestCase(BaseContainersTestCase): @testcase.attr('positive') def test_create_containers_rsa_no_passphrase(self): """Covers creating an rsa container without a passphrase.""" create_container_rsa_data['private_key_passphrase'] = None container = self.barbicanclient.containers.create_rsa( **create_container_rsa_data) container_ref = self.cleanup.add_entity(container) self.assertIsNotNone(container_ref) container_resp = self.barbicanclient.containers.get(container_ref) self.assertIsNone(container_resp.private_key_passphrase) self.assertEqual(2, len(container_resp.secrets)) @utils.parameterized_dataset(accepted_str_values) @testcase.attr('positive') def test_create_container_rsa_name(self, name): """Covers creating rsa containers with various names.""" container = self.barbicanclient.containers.create_rsa( **create_container_rsa_data) container.name = name container_ref = self.cleanup.add_entity(container) self.assertIsNotNone(container_ref) container_resp = self.barbicanclient.containers.get(container_ref) self.assertEqual(name, container_resp.name) @testcase.attr('negative') def test_create_rsa_invalid_key_names(self): """Covers creating an RSA container with incorrect names.""" incorrect_names_rsa_container = { "name": "bad_container", "secret1": self.secret_ref_1, "secret2": self.secret_ref_2, "secret3": self.secret_ref_3 } e = self.assertRaises(TypeError, self.barbicanclient.containers.create_rsa, **incorrect_names_rsa_container) self.assertIn('got an unexpected keyword argument', e.message) @testcase.attr('negative') def test_create_rsa_no_public_key(self): """Creating an rsa container without a public key should fail. RSA containers must have at least a public key and private key. """ no_public_key_rsa_container = {"name": "no_pub_key", "private_key": self.secret_1, "private_key_passphrase": self.secret_2, } container = self.barbicanclient.containers.create_rsa( **no_public_key_rsa_container) e = self.assertRaises( exceptions.HTTPClientError, container.store ) self.assertEqual(400, e.status_code) @testcase.attr('negative') def test_create_rsa_no_private_key(self): """Creating an rsa container without a private key should fail. RSA containers must have at least a public key and private key. """ no_private_key_rsa_container = { "name": "no_pub_key", "public_key": self.secret_1, "private_key_passphrase": self.secret_2} container = self.barbicanclient.containers.create_rsa( **no_private_key_rsa_container) e = self.assertRaises( exceptions.HTTPClientError, container.store ) self.assertEqual(400, e.status_code) python-barbicanclient-4.10.0/functionaltests/client/v1/functional/__init__.py0000664000175000017500000000000013620530200027356 0ustar zuulzuul00000000000000python-barbicanclient-4.10.0/functionaltests/client/v1/functional/test_acl.py0000664000175000017500000005464113620530200027441 0ustar zuulzuul00000000000000# 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. from testtools import testcase from functionaltests.client import base from functionaltests.common import cleanup from functionaltests import utils from oslo_utils import uuidutils from barbicanclient import exceptions create_secret_defaults_data = { "name": "AES key", "expiration": "2020-02-28T19:14:44.180394", "algorithm": "aes", "bit_length": 256, "mode": "cbc", "payload": "gF6+lLoF3ohA9aPRpt+6bQ==", "payload_content_type": "application/octet-stream", "payload_content_encoding": "base64", } create_container_defaults_data = { "name": "containername", "secrets": {} } create_container_rsa_data = { "name": "rsacontainer", } ACL_SUBMIT_DATA_POSITIVE = { 'secret_no_users_access_flag': { 'users': None, 'project_access': True, 'entity_ref_method': '_create_a_secret', 'acl_type': 'secret', 'expect_users': [], 'expect_project_access': True}, 'secret_users_missing_access_flag': { 'users': ['u1', 'u2'], 'project_access': None, 'entity_ref_method': '_create_a_secret', 'acl_type': 'secret', 'expect_users': ['u1', 'u2'], 'expect_project_access': True}, 'container_users_no_project_access': { 'users': ['u1', 'u2', 'u3'], 'project_access': False, 'entity_ref_method': '_create_a_container', 'acl_type': 'container', 'expect_users': ['u1', 'u2', 'u3'], 'expect_project_access': False}, 'container_empty_users_with_project_access': { 'users': [], 'project_access': True, 'entity_ref_method': '_create_a_container', 'acl_type': 'container', 'expect_users': [], 'expect_project_access': True}, } ACL_SUBMIT_DATA_NEGATIVE = { 'secret_users_incorrect_access_flag': { 'users': ['u1', 'u2'], 'project_access': 'Incorrect_flag', 'entity_ref_method': '_create_a_secret', 'acl_type': 'secret', 'expect_users': ['u1', 'u2'], 'expect_project_access': True, 'expect_error': True, 'error_code': 400}, 'container_incorrect_users_as_str': { 'users': 'u1', 'project_access': True, 'entity_ref_method': '_create_a_container', 'acl_type': 'container', 'expect_users': ['u1'], 'expect_project_access': True, 'expect_error': True, 'error_code': None, 'error_class': ValueError}, } ACL_DELETE_DATA = { 'secret_no_users_access_flag': { 'users': None, 'project_access': True, 'create_acl': True, 'entity_ref_method': '_create_a_secret', 'acl_type': 'secret', 'expect_users': [], 'expect_project_access': True}, 'secret_users_missing_access_flag': { 'users': ['u1', 'u2'], 'project_access': None, 'create_acl': True, 'entity_ref_method': '_create_a_secret', 'acl_type': 'secret', 'expect_users': [], 'expect_project_access': True}, 'container_users_no_project_access': { 'users': ['u1', 'u2', 'u3'], 'project_access': False, 'create_acl': True, 'entity_ref_method': '_create_a_container', 'acl_type': 'container', 'expect_users': [], 'expect_project_access': True}, 'container_empty_users_with_project_access': { 'users': [], 'project_access': True, 'create_acl': True, 'entity_ref_method': '_create_a_container', 'acl_type': 'container', 'expect_users': [], 'expect_project_access': True}, 'existing_secret_no_acl_defined': { 'users': ['u1', 'u2'], 'project_access': False, 'create_acl': False, 'entity_ref_method': '_create_a_secret', 'acl_type': 'secret', 'expect_users': [], 'expect_project_access': True, 'expect_error': False}, 'acl_operation_specific_remove': { 'users': ['u1', 'u2', 'u3'], 'project_access': False, 'create_acl': True, 'per_op_acl_remove': True, 'entity_ref_method': '_create_a_container', 'acl_type': 'container', 'expect_users': [], 'expect_project_access': True}, } ACL_ADD_USERS_DATA_POSITIVE = { 'secret_no_initial_users_access_flag': { 'users': None, 'project_access': True, 'entity_ref_method': '_create_a_secret', 'acl_type': 'secret', 'add_users': ['u4'], 'expect_users': ['u4'], 'expect_project_access': True}, 'secret_users_missing_access_flag': { 'users': ['u1', 'u2'], 'project_access': None, 'entity_ref_method': '_create_a_secret', 'acl_type': 'secret', 'add_users': ['u2', 'u4'], 'expect_users': ['u1', 'u2', 'u4'], 'expect_project_access': True}, 'container_users_no_project_access_empty_add': { 'users': ['u1', 'u2', 'u3'], 'project_access': False, 'entity_ref_method': '_create_a_container', 'acl_type': 'container', 'add_users': [], 'expect_users': ['u1', 'u2', 'u3'], 'expect_project_access': False}, 'container_empty_users_with_project_access_none_add_users': { 'users': [], 'project_access': True, 'entity_ref_method': '_create_a_container', 'acl_type': 'container', 'add_users': None, 'expect_users': [], 'expect_project_access': True}, 'secret_users_modify_access_flag_in_add': { 'users': ['u1', 'u2', 'u3'], 'project_access': False, 'entity_ref_method': '_create_a_secret', 'acl_type': 'secret', 'add_users': [], 'add_project_access': True, 'expect_users': ['u1', 'u2', 'u3'], 'expect_project_access': True}, } ACL_ADD_USERS_DATA_NEGATIVE = { 'secret_users_incorrect_access_flag_during_add': { 'users': ['u1', 'u2'], 'project_access': False, 'entity_ref_method': '_create_a_secret', 'acl_type': 'secret', 'add_users': ['u5'], 'add_project_access': 'Incorrect', 'expect_users': ['u1', 'u2', 'u5'], 'expect_project_access': False, 'expect_error': True, 'error_code': 400}, } ACL_REMOVE_USERS_DATA_POSITIVE = { 'secret_no_initial_users_access_flag': { 'users': None, 'project_access': True, 'entity_ref_method': '_create_a_secret', 'acl_type': 'secret', 'remove_users': ['u4'], 'expect_users': [], 'expect_project_access': True}, 'secret_users_missing_access_flag': { 'users': ['u1', 'u2'], 'project_access': None, 'entity_ref_method': '_create_a_secret', 'acl_type': 'secret', 'remove_users': ['u2', 'u4'], 'expect_users': ['u1'], 'expect_project_access': True}, 'secret_users_no_matching_users': { 'users': ['u1', 'u2'], 'project_access': None, 'entity_ref_method': '_create_a_secret', 'acl_type': 'secret', 'remove_users': ['u3', 'u4'], 'expect_users': ['u1', 'u2'], 'expect_project_access': True}, 'container_users_no_project_access_empty_add': { 'users': ['u1', 'u2', 'u3'], 'project_access': False, 'entity_ref_method': '_create_a_container', 'acl_type': 'container', 'remove_users': [], 'expect_users': ['u1', 'u2', 'u3'], 'expect_project_access': False}, 'container_empty_users_with_project_access_none_add_users': { 'users': [], 'project_access': True, 'entity_ref_method': '_create_a_container', 'acl_type': 'container', 'remove_users': None, 'expect_users': [], 'expect_project_access': True}, 'secret_users_modify_access_flag_in_remove': { 'users': ['u1', 'u2', 'u3'], 'project_access': False, 'entity_ref_method': '_create_a_secret', 'acl_type': 'secret', 'remove_users': [], 'remove_project_access': True, 'expect_users': ['u1', 'u2', 'u3'], 'expect_project_access': True}, } ACL_REMOVE_USERS_DATA_NEGATIVE = { 'secret_users_incorrect_access_flag_during_add': { 'users': ['u1', 'u2'], 'project_access': False, 'entity_ref_method': '_create_a_secret', 'acl_type': 'secret', 'remove_users': ['u5'], 'remove_project_access': 'Incorrect', 'expect_users': ['u1', 'u2'], 'expect_project_access': False, 'expect_error': True, 'error_code': 400}, } class BaseACLsTestCase(base.TestCase): def setUp(self): super(BaseACLsTestCase, self).setUp() self.cleanup = cleanup.CleanUp(self.barbicanclient) # Set up three secrets self.secret_ref_1, self.secret_1 = self._create_a_secret() self.secret_ref_2, self.secret_2 = self._create_a_secret() self.secret_ref_3, self.secret_3 = self._create_a_secret() self.secret_list = [self.secret_ref_1, self.secret_ref_2, self.secret_ref_3] secrets_dict = {'secret_1': self.secret_1, 'secret_2': self.secret_2, 'secret_3': self.secret_3} create_container_defaults_data['secrets'] = secrets_dict create_container_rsa_data['public_key'] = self.secret_1 create_container_rsa_data['private_key'] = self.secret_2 create_container_rsa_data['private_key_passphrase'] = self.secret_3 def tearDown(self): """Handles test cleanup. It should be noted that delete all secrets must be called before delete containers. """ self.cleanup.delete_all_entities() super(BaseACLsTestCase, self).tearDown() def _create_a_secret(self): secret = self.barbicanclient.secrets.create( **create_secret_defaults_data) secret_ref = self.cleanup.add_entity(secret) return secret_ref, secret def _create_a_container(self): container = self.barbicanclient.containers.create( **create_container_defaults_data) container_ref = self.cleanup.add_entity(container) return container_ref, container @utils.parameterized_test_case class ACLsTestCase(BaseACLsTestCase): @testcase.attr('negative') def test_get_non_existent_secret_valid_uuid(self): """A get on a container that does not exist with valid UUID This should return a 404. """ base_url = self.barbicanclient.acls._api.endpoint_override new_uuid = uuidutils.generate_uuid() url = '{0}/containers/{1}'.format(base_url, new_uuid) e = self.assertRaises( exceptions.HTTPClientError, self.barbicanclient.acls.get, url ) self.assertEqual(404, e.status_code) @testcase.attr('negative') def test_delete_non_existent_secret_valid_uuid(self): """A delete on an ACL when secret with a valid UUID does not exist This should return a 404. """ base_url = self.barbicanclient.acls._api.endpoint_override new_uuid = uuidutils.generate_uuid() url = '{0}/secrets/{1}'.format(base_url, new_uuid) acl_data = {'entity_ref': url} entity = self.barbicanclient.acls.create(**acl_data) e = self.assertRaises( exceptions.HTTPClientError, entity.remove ) self.assertEqual(404, e.status_code) @utils.parameterized_dataset(ACL_SUBMIT_DATA_POSITIVE) @testcase.attr('positive') def test_acl_successful_submit(self, users, project_access, entity_ref_method, acl_type, expect_users, expect_project_access, **kwargs): """Submit operation on ACL entity which stores ACL setting in Barbican. """ entity_ref, _ = getattr(self, entity_ref_method)() acl_data = {'entity_ref': entity_ref, 'users': users, 'project_access': project_access} entity = self.barbicanclient.acls.create(**acl_data) acl_ref = self.cleanup.add_entity(entity) self.assertIsNotNone(acl_ref) self.assertEqual(entity_ref + "/acl", acl_ref) acl_entity = self.barbicanclient.acls.get(entity.entity_ref) self.assertIsNotNone(acl_entity) # read acl as dictionary lookup acl = acl_entity.get('read') self.assertEqual(set(expect_users), set(acl.users)) self.assertEqual(expect_project_access, acl.project_access) self.assertIsNotNone(acl.created) self.assertIsNotNone(acl.updated) self.assertEqual(acl_type, acl_entity._acl_type) # read acl as property lookup acl = acl_entity.read self.assertEqual(set(expect_users), set(acl.users)) self.assertEqual(expect_project_access, acl.project_access) @utils.parameterized_dataset(ACL_SUBMIT_DATA_NEGATIVE) @testcase.attr('negative') def test_acl_incorrect_submit(self, users, project_access, entity_ref_method, acl_type, expect_users, expect_project_access, **kwargs): """Check incorrect submit operation failure on ACL entity.""" entity_ref, _ = getattr(self, entity_ref_method)() acl_data = {'entity_ref': entity_ref, 'users': users, 'project_access': project_access} entity = self.barbicanclient.acls.create(**acl_data) error_class = kwargs.get('error_class', exceptions.HTTPClientError) e = self.assertRaises( error_class, entity.submit ) if hasattr(e, 'status_code'): self.assertEqual(kwargs.get('error_code'), e.status_code) @utils.parameterized_dataset(ACL_DELETE_DATA) def test_acl_delete(self, users, project_access, entity_ref_method, create_acl, acl_type, expect_users, expect_project_access, **kwargs): """remove operation on ACL entity which stores ACL setting in Barbican. """ entity_ref, _ = getattr(self, entity_ref_method)() acl_data = {'entity_ref': entity_ref, 'users': users, 'project_access': project_access} entity = self.barbicanclient.acls.create(**acl_data) entity_ref = entity.entity_ref if create_acl: self.cleanup.add_entity(entity) acl_op_remove = kwargs.get('per_op_acl_remove') if acl_op_remove: entity.read.remove() else: entity.remove() acl_entity = self.barbicanclient.acls.get(entity_ref) self.assertIsNotNone(acl_entity) # read acl as dictionary lookup acl = acl_entity.get('read') self.assertEqual(set(expect_users), set(acl.users)) self.assertEqual(expect_project_access, acl.project_access) self.assertIsNone(acl.created) self.assertIsNone(acl.updated) self.assertEqual(acl_type, acl_entity._acl_type) # read acl as property lookup acl = acl_entity.read self.assertEqual(set(expect_users), set(acl.users)) self.assertEqual(expect_project_access, acl.project_access) @utils.parameterized_dataset(ACL_ADD_USERS_DATA_POSITIVE) @testcase.attr('positive') def test_acl_successful_add_users(self, users, project_access, entity_ref_method, acl_type, add_users, expect_users, expect_project_access, **kwargs): """Checks client add users behavior on existing ACL entity. In this new users or project access flag is modified and verified for expected behavior """ entity_ref, _ = getattr(self, entity_ref_method)() acl_data = {'entity_ref': entity_ref, 'users': users, 'project_access': project_access} entity = self.barbicanclient.acls.create(**acl_data) acl_ref = self.cleanup.add_entity(entity) self.assertIsNotNone(acl_ref) self.assertEqual(entity_ref + "/acl", acl_ref) server_acl = self.barbicanclient.acls.get(entity.entity_ref) if server_acl.get('read').users is not None and add_users: server_acl.get('read').users.extend(add_users) if kwargs.get('add_project_access') is not None: server_acl.get('read').project_access = \ kwargs.get('add_project_access') acl_ref = server_acl.submit() self.assertIsNotNone(acl_ref) self.assertEqual(entity_ref + "/acl", acl_ref) acl_entity = self.barbicanclient.acls.get(server_acl.entity_ref) self.assertIsNotNone(acl_entity) # read acl as dictionary lookup acl = acl_entity.get('read') self.assertEqual(set(expect_users), set(acl.users)) self.assertEqual(expect_project_access, acl.project_access) self.assertIsNotNone(acl.created) self.assertIsNotNone(acl.updated) self.assertEqual(acl_type, acl_entity._acl_type) # read acl as property lookup acl = acl_entity.read self.assertEqual(set(expect_users), set(acl.users)) self.assertEqual(expect_project_access, acl.project_access) @utils.parameterized_dataset(ACL_ADD_USERS_DATA_NEGATIVE) @testcase.attr('negative') def test_acl_add_users_failure(self, users, project_access, entity_ref_method, acl_type, add_users, expect_users, expect_project_access, **kwargs): """Checks client add users failures on existing ACL entity. In this new users or project access flag is modified and verified for expected behavior """ entity_ref, _ = getattr(self, entity_ref_method)() acl_data = {'entity_ref': entity_ref, 'users': users, 'project_access': project_access} entity = self.barbicanclient.acls.create(**acl_data) acl_ref = self.cleanup.add_entity(entity) self.assertIsNotNone(acl_ref) self.assertEqual(entity_ref + "/acl", acl_ref) server_acl = self.barbicanclient.acls.get(entity.entity_ref) if server_acl.get('read').users is not None and add_users: server_acl.get('read').users.extend(add_users) if kwargs.get('add_project_access') is not None: server_acl.get('read').project_access = \ kwargs.get('add_project_access') error_class = kwargs.get('error_class', exceptions.HTTPClientError) e = self.assertRaises( error_class, server_acl.submit ) if hasattr(e, 'status_code'): self.assertEqual(kwargs.get('error_code'), e.status_code) @utils.parameterized_dataset(ACL_REMOVE_USERS_DATA_POSITIVE) @testcase.attr('positive') def test_acl_remove_users_successful(self, users, project_access, entity_ref_method, acl_type, remove_users, expect_users, expect_project_access, **kwargs): """Checks client remove users behavior on existing ACL entity. In this users are removed from existing users list or project access flag is modified and then verified for expected behavior """ entity_ref, _ = getattr(self, entity_ref_method)() acl_data = {'entity_ref': entity_ref, 'users': users, 'project_access': project_access} entity = self.barbicanclient.acls.create(**acl_data) acl_ref = self.cleanup.add_entity(entity) self.assertIsNotNone(acl_ref) self.assertEqual(entity_ref + "/acl", acl_ref) server_acl = self.barbicanclient.acls.get(entity.entity_ref) acl_users = server_acl.read.users if acl_users and remove_users: acl_users = set(acl_users).difference(remove_users) # Python sets are not JSON serializable. Cast acl_users to a list. server_acl.read.users = list(acl_users) if kwargs.get('remove_project_access') is not None: server_acl.read.project_access = \ kwargs.get('remove_project_access') acl_ref = server_acl.submit() self.assertIsNotNone(acl_ref) self.assertEqual(entity_ref + "/acl", acl_ref) acl_entity = self.barbicanclient.acls.get(server_acl.entity_ref) self.assertIsNotNone(acl_entity) # read acl as dictionary lookup acl = acl_entity.get('read') self.assertEqual(set(expect_users), set(acl.users)) self.assertEqual(expect_project_access, acl.project_access) self.assertIsNotNone(acl.created) self.assertIsNotNone(acl.updated) self.assertEqual(acl_type, acl_entity._acl_type) # read acl as property lookup acl = acl_entity.read self.assertEqual(set(expect_users), set(acl.users)) self.assertEqual(expect_project_access, acl.project_access) @utils.parameterized_dataset(ACL_REMOVE_USERS_DATA_NEGATIVE) @testcase.attr('negative') def test_acl_remove_users_failure(self, users, project_access, entity_ref_method, acl_type, remove_users, expect_users, expect_project_access, **kwargs): """Checks client remove users failures on existing ACL entity. In this users are removed from existing users list or project access flag is modified and then verified for expected behavior """ entity_ref, _ = getattr(self, entity_ref_method)() acl_data = {'entity_ref': entity_ref, 'users': users, 'project_access': project_access} entity = self.barbicanclient.acls.create(**acl_data) acl_ref = self.cleanup.add_entity(entity) self.assertIsNotNone(acl_ref) self.assertEqual(entity_ref + "/acl", acl_ref) server_acl = self.barbicanclient.acls.get(entity.entity_ref) acl_users = server_acl.read.users if acl_users and remove_users: acl_users = set(acl_users).difference(remove_users) # Python sets are not JSON serializable. Cast acl_users to a list. server_acl.read.users = list(acl_users) if kwargs.get('remove_project_access') is not None: server_acl.read.project_access = \ kwargs.get('remove_project_access') error_class = kwargs.get('error_class', exceptions.HTTPClientError) e = self.assertRaises( error_class, server_acl.submit ) if hasattr(e, 'status_code'): self.assertEqual(kwargs.get('error_code'), e.status_code) python-barbicanclient-4.10.0/functionaltests/client/v1/functional/test_secrets.py0000664000175000017500000010140413620530200030340 0ustar zuulzuul00000000000000# Copyright (c) 2015 Rackspace, Inc. # # 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. import base64 import datetime import sys import time from barbicanclient import exceptions from functionaltests.client import base from functionaltests.common import cleanup from functionaltests.common import keys from functionaltests import utils from testtools import testcase secret_create_defaults_data = { "name": "AES key", "expiration": "2020-02-28T19:14:44.180394", "algorithm": "aes", "bit_length": 256, "mode": "cbc", "payload": "gF6+lLoF3ohA9aPRpt+6bQ==" } secret_create_nones_data = { "name": None, "expiration": None, "algorithm": None, "bit_length": None, "mode": None, "payload": "gF6+lLoF3ohA9aPRpt+6bQ==", "payload_content_type": "application/octet-stream", "payload_content_encoding": "base64", } secret_create_emptystrings_data = { "name": '', "expiration": '', "algorithm": '', "bit_length": '', "mode": '', "payload": '', "payload_content_type": '', "payload_content_encoding": '', } @utils.parameterized_test_case class SecretsTestCase(base.TestCase): def setUp(self): super(SecretsTestCase, self).setUp() self.cleanup = cleanup.CleanUp(self.barbicanclient) def tearDown(self): self.cleanup.delete_all_entities() super(SecretsTestCase, self).tearDown() @testcase.attr('positive') def test_secret_create_defaults_check_content_types(self): """Check that set content-type attribute is retained in metadata.""" secret = self.barbicanclient.secrets.create( **secret_create_defaults_data) secret_ref = self.cleanup.add_entity(secret) self.assertIsNotNone(secret_ref) resp = self.barbicanclient.secrets.get(secret_ref) content_types = resp.content_types self.assertIsNotNone(content_types) self.assertIn('default', content_types) self.assertEqual('application/octet-stream', content_types['default']) @testcase.attr('positive') def test_secret_create_defaults_non_standard_algorithm(self): """Create a secret with a non standard algorithm. Currently the client will accept any string for the algorithm. """ secret = self.barbicanclient.secrets.create( **secret_create_defaults_data) secret.algorithm = "not-an-algorithm" secret_ref = self.cleanup.add_entity(secret) self.assertIsNotNone(secret_ref) resp = self.barbicanclient.secrets.get(secret_ref) self.assertEqual(secret.algorithm, resp.algorithm) @testcase.attr('positive') def test_secret_read_with_acls(self): """Access default ACL settings data on recently created secret. By default, 'read' ACL settings are there for a secret. """ test_model = self.barbicanclient.secrets.create( **secret_create_defaults_data) secret_ref = self.cleanup.add_entity(test_model) self.assertIsNotNone(secret_ref) secret_entity = self.barbicanclient.secrets.get(secret_ref) self.assertIsNotNone(secret_entity.acls) self.assertIsNotNone(secret_entity.acls.read) self.assertEqual([], secret_entity.acls.read.users) @testcase.attr('positive') def test_secret_create_defaults_non_standard_mode(self): """Create a secret with a non standard mode. Currently the client will accept any string for the mode. """ secret = self.barbicanclient.secrets.create( **secret_create_defaults_data) secret.mode = 'not-a-mode' secret_ref = self.cleanup.add_entity(secret) self.assertIsNotNone(secret_ref) resp = self.barbicanclient.secrets.get(secret_ref) self.assertEqual(secret.mode, resp.mode) @testcase.attr('negative') def test_secret_delete_doesnt_exist(self): """Deletes a non-existent secret. This delete uses a reference with an invalid UUID format """ url = self.barbicanclient.secrets._api.endpoint_override + \ '/secrets/notauuid' e = self.assertRaises(ValueError, self.barbicanclient.secrets.delete, url) self.assertEqual('Secret incorrectly specified.', e.message) @testcase.attr('negative') def test_secret_delete_doesnt_exist_valid_uuid_format(self): """Deletes a non-existent secret. This delete has a valid UUID format but there is no secret associated with this UUID """ uuid = 'de20ad54-85b4-421b-adb2-eb7b9e546013' url = self.barbicanclient.secrets._api.endpoint_override + \ '/secrets/' + uuid e = self.assertRaises( exceptions.HTTPClientError, self.barbicanclient.secrets.delete, url ) self.assertEqual(404, e.status_code) @testcase.attr('negative') def test_secret_get_secret_doesnt_exist(self): """GET an invalid secret ref. Will get value error secret incorrectly specified since "notauuid" is not a properly formatted uuid. """ url = self.barbicanclient.secrets._api.endpoint_override + \ '/secrets/notauuid' e = self.assertRaises(ValueError, self.barbicanclient.secrets.get, url, 'text/plain') self.assertIn("Secret incorrectly specified", e.message) @testcase.attr('negative') def test_secret_create_defaults_expiration_passed(self): """Create a secret with an expiration that has already passed. Returns a 400. """ secret = self.barbicanclient.secrets.create( **secret_create_defaults_data) secret.expiration = '2000-01-10T14:58:52.546795' e = self.assertRaises( exceptions.HTTPClientError, secret.store ) self.assertEqual(400, e.status_code) @testcase.attr('negative') def test_secret_create_emptystrings(self): """Secret create with empty Strings for all attributes. Fails with a value error, Payload incorrectly specified. """ secret = self.barbicanclient.secrets.create( **secret_create_emptystrings_data) self.assertRaises( exceptions.PayloadException, secret.store ) @testcase.attr('negative') def test_secret_create_defaults_oversized_payload(self): """Create a secret with a payload that is larger than the allowed size. Should return a 413 if the secret size is greater than the maximum allowed size. """ secret = self.barbicanclient.secrets.create( **secret_create_defaults_data) secret.payload = str(self.oversized_payload) e = self.assertRaises( exceptions.HTTPClientError, secret.store ) self.assertEqual(413, e.status_code) @utils.parameterized_dataset({ 'alphanumeric': ['1f34ds'], 'punctuation': ['~!@#$%^&*()_+`-={}[]|:;<>,.?'], 'uuid': ['54262d9d-4bc7-4821-8df0-dc2ca8e112bb'], 'len_255': [base.TestCase.max_sized_field], 'empty': [''], 'null': [None] }) @testcase.attr('positive') def test_secret_create_defaults_valid_name(self, name): """Covers cases of creating secrets with valid names.""" secret = self.barbicanclient.secrets.create( **secret_create_defaults_data) secret.name = name secret_ref = self.cleanup.add_entity(secret) self.assertIsNotNone(secret_ref) resp = self.barbicanclient.secrets.get(secret_ref) self.assertEqual(secret.name, resp.name) @utils.parameterized_dataset({ 'int': [400] }) @testcase.attr('negative') def test_secret_create_defaults_invalid_name(self, name): """Create secrets with various invalid names. Should return 400. """ secret = self.barbicanclient.secrets.create( **secret_create_defaults_data) secret.name = name e = self.assertRaises( exceptions.HTTPClientError, secret.store ) self.assertEqual(400, e.status_code) @utils.parameterized_dataset({ 'aes': ['aes'] }) @testcase.attr('positive') def test_secret_create_defaults_valid_algorithms(self, algorithm): """Creates secrets with various valid algorithms.""" secret = self.barbicanclient.secrets.create( **secret_create_defaults_data) secret.algorithm = algorithm secret_ref = self.cleanup.add_entity(secret) self.assertIsNotNone(secret_ref) resp = self.barbicanclient.secrets.get(secret_ref) self.assertEqual(secret.algorithm, resp.algorithm) @utils.parameterized_dataset({ 'int': [400] }) @testcase.attr('negative') def test_secret_create_defaults_invalid_algorithms(self, algorithm): """Creates secrets with various invalid algorithms.""" secret = self.barbicanclient.secrets.create( **secret_create_defaults_data) secret.algorithm = algorithm # We are currently testing for exception with http_code # launchpad bug 1431514 will address the change to this functionality e = self.assertRaises( exceptions.HTTPClientError, secret.store ) self.assertEqual(400, e.status_code) @utils.parameterized_dataset({ 'symmetric': ['symmetric', 'aes', 128, ('\x00\x01\x02\x03\x04\x05\x06\x07' '\x00\x01\x02\x03\x04\x05\x06\x07')], 'private': ['private', 'rsa', 2048, keys.get_private_key_pem()], 'public': ['public', 'rsa', 2048, keys.get_public_key_pem()], 'certificate': ['certificate', 'rsa', 2048, keys.get_certificate_pem()], 'opaque': ['opaque', None, None, (b'\x00\x01\x02\x03\x04\x05\x06\x07')], 'passphrase': ['passphrase', None, None, keys.get_passphrase_txt()], }) @testcase.attr('positive') def test_secret_create_defaults_valid_secret_type( self, secret_type, algorithm, bit_length, payload): """Covers cases of creating secrets with valid secret types.""" secret = self.barbicanclient.secrets.create( **secret_create_defaults_data) secret.secret_type = secret_type secret.algorithm = algorithm secret.bit_length = bit_length # payload should not be encoded. secret.payload = payload secret_ref = self.cleanup.add_entity(secret) self.assertIsNotNone(secret_ref) resp = self.barbicanclient.secrets.get(secret_ref) self.assertEqual(secret_type, resp.secret_type) @testcase.attr('negative') def test_secret_create_defaults_invalid_secret_type(self): """Covers cases of creating secrets with invalid secret types.""" secret = self.barbicanclient.secrets.create( **secret_create_defaults_data) secret.secret_type = 'not a valid secret type' e = self.assertRaises( exceptions.HTTPClientError, secret.store ) self.assertEqual(400, e.status_code) @utils.parameterized_dataset({ '512': [512], 'sixteen': [16], 'fifteen': [15], 'eight': [8], 'seven': [7], 'one': [1], 'none': [None] }) @testcase.attr('positive') def test_secret_create_defaults_valid_bit_length(self, bit_length): """Covers cases of creating secrets with valid bit lengths.""" secret = self.barbicanclient.secrets.create( **secret_create_defaults_data) secret.bit_length = bit_length secret_ref = self.cleanup.add_entity(secret) self.assertIsNotNone(secret_ref) resp = self.barbicanclient.secrets.get(secret_ref) self.assertEqual(secret.bit_length, resp.bit_length) @utils.parameterized_dataset({ 'str_type': ['not-an-int'], 'empty': [''], 'blank': [' '], 'negative_maxint': [-sys.maxint], 'negative_one': [-1], 'zero': [0] }) @testcase.attr('negative') def test_secret_create_defaults_invalid_bit_length(self, bit_length): """Covers cases of creating secrets with invalid bit lengths.""" secret = self.barbicanclient.secrets.create( **secret_create_defaults_data) secret.bit_length = bit_length e = self.assertRaises( exceptions.HTTPClientError, secret.store ) self.assertEqual(400, e.status_code) @utils.parameterized_dataset({ 'cbc': ['cbc'] }) @testcase.attr('positive') def test_secret_create_defaults_valid_mode(self, mode): """Covers cases of creating secrets with valid modes.""" secret = self.barbicanclient.secrets.create( **secret_create_defaults_data) secret.mode = mode secret_ref = self.cleanup.add_entity(secret) self.assertIsNotNone(secret_ref) resp = self.barbicanclient.secrets.get(secret_ref) self.assertEqual(secret.mode, resp.mode) @utils.parameterized_dataset({ 'zero': [0], 'oversized_string': [base.TestCase.oversized_field], 'int': [400] }) @testcase.attr('negative') def test_secret_create_defaults_invalid_mode(self, mode): """Covers cases of creating secrets with invalid modes.""" secret = self.barbicanclient.secrets.create( **secret_create_defaults_data) secret.mode = mode e = self.assertRaises( exceptions.HTTPClientError, secret.store ) self.assertEqual(400, e.status_code) @utils.parameterized_dataset({ 'text_content_type_none_encoding': { 'payload_content_type': 'text/plain', 'payload_content_encoding': None}, 'utf8_text_content_type_none_encoding': { 'payload_content_type': 'text/plain; charset=utf-8', 'payload_content_encoding': None}, 'no_space_utf8_text_content_type_none_encoding': { 'payload_content_type': 'text/plain;charset=utf-8', 'payload_content_encoding': None}, 'octet_content_type_base64_encoding': { 'payload_content_type': 'application/octet-stream', 'payload_content_encoding': 'base64'} }) @testcase.attr('positive') def test_secret_create_deprecated_types_and_encoding( self, payload_content_type, payload_content_encoding): """Creates secrets with various content types and encodings.""" secret = self.barbicanclient.secrets.create( **secret_create_defaults_data) secret.payload_content_type = payload_content_type secret.payload_content_encoding = payload_content_encoding secret_ref = self.cleanup.add_entity(secret) self.assertIsNotNone(secret_ref) resp = self.barbicanclient.secrets.get(secret_ref) if secret.payload_content_encoding == 'base64': self.assertEqual( base64.b64decode(secret.payload), resp.payload ) else: self.assertEqual(secret.payload, str(resp.payload)) @utils.parameterized_dataset({ 'large_string_content_type_and_encoding': { 'payload_content_type': base.TestCase.oversized_field, 'payload_content_encoding': base.TestCase.oversized_field}, 'int_content_type_and_encoding': { 'payload_content_type': 123, 'payload_content_encoding': 123}, 'text_content_type_none_content_encoding': { 'payload_content_type': 'text/plain', 'payload_content_encoding': ''}, 'text_no_subtype_content_type_none_content_encoding': { 'payload_content_type': 'text', 'payload_content_encoding': None}, 'text_slash_no_subtype_content_type_none_content_encoding': { 'payload_content_type': 'text/', 'payload_content_encoding': None}, 'text_content_type_empty_content_encoding': { 'payload_content_type': 'text/plain', 'payload_content_encoding': ' '}, 'text_content_type_spaces_content_encoding': { 'payload_content_type': 'text/plain', 'payload_content_encoding': ' '}, 'text_content_type_base64_content_encoding': { 'payload_content_type': 'text/plain', 'payload_content_encoding': 'base64'}, 'text_and_utf88_content_type_none_content_encoding': { 'payload_content_type': 'text/plain; charset=utf-88', 'payload_content_encoding': None}, 'invalid_content_type_base64_content_encoding': { 'payload_content_type': 'invalid', 'payload_content_encoding': 'base64'}, 'invalid_content_type_none_content_encoding': { 'payload_content_type': 'invalid', 'payload_content_encoding': None}, 'octet_content_type_invalid_content_encoding': { 'payload_content_type': 'application/octet-stream', 'payload_content_encoding': 'invalid'}, 'text_content_type_invalid_content_encoding': { 'payload_content_type': 'text/plain', 'payload_content_encoding': 'invalid'}, 'none_content_type_invalid_content_encoding': { 'payload_content_type': None, 'payload_content_encoding': 'invalid'}, 'none_content_type_base64_content_encoding': { 'payload_content_type': None, 'payload_content_encoding': 'base64'} }) @testcase.attr('negative') def test_secret_create_defaults_invalid_types_and_encoding(self, **kwargs): """Creating secrets with invalid payload types and encodings.""" secret = self.barbicanclient.secrets.create( **secret_create_defaults_data) secret.payload_content_encoding = kwargs[ 'payload_content_encoding'] secret.payload_content_type = kwargs[ 'payload_content_type'] e = self.assertRaises( exceptions.HTTPClientError, secret.store ) self.assertEqual(400, e.status_code) @utils.parameterized_dataset({ 'max_payload_string': [base.TestCase.max_sized_payload] }) @testcase.attr('positive') def test_secret_create_defaults_valid_payload(self, payload): """Create secrets with a various valid payloads.""" secret = self.barbicanclient.secrets.create( **secret_create_defaults_data) secret.payload = payload secret_ref = self.cleanup.add_entity(secret) self.assertIsNotNone(secret_ref) resp = self.barbicanclient.secrets.get(secret_ref) self.assertEqual(secret.payload, resp.payload) @utils.parameterized_dataset({ 'list': [['boom']], 'int': [123] }) @testcase.attr('negative') def test_secret_create_with_invalid_payload_(self, payload): """Covers attempting to create secret with invalid payload types Tests the negative cases of invalid types (list and int). """ secret = self.barbicanclient.secrets.create( **secret_create_defaults_data) secret.payload = payload self.assertRaises( exceptions.PayloadException, secret.store ) @utils.parameterized_dataset({ 'empty': [''], 'zero': [0] }) @testcase.attr('negative') def test_secret_with_no_payload_exception(self, payload): """Covers creating secrets with various invalid payloads. These requests will fail with a value error before the request to the server is made """ secret = self.barbicanclient.secrets.create( **secret_create_defaults_data) secret.payload = payload self.assertRaises( exceptions.PayloadException, secret.store ) @utils.parameterized_dataset({ 'negative_five_long_expire': { 'timezone': '-05:00', 'days': 5}, 'positive_five_long_expire': { 'timezone': '+05:00', 'days': 5}, 'negative_one_short_expire': { 'timezone': '-01', 'days': 1}, 'positive_one_short_expire': { 'timezone': '+01', 'days': 1} }) @testcase.attr('positive') def test_secret_create_defaults_valid_expiration(self, **kwargs): """Create secrets with a various valid expiration data.""" timestamp = utils.create_timestamp_w_tz_and_offset(**kwargs) secret = self.barbicanclient.secrets.create( **secret_create_defaults_data) secret.expiration = timestamp secret_ref = self.cleanup.add_entity(secret) self.assertIsNotNone(secret_ref) resp = self.barbicanclient.secrets.get(secret_ref) self.assertIsNotNone(resp) self.assertEqual(secret.name, resp.name) @utils.parameterized_dataset({ 'malformed_timezone': { 'timezone': '-5:00', 'days': 0} }) @testcase.attr('negative') def test_secret_create_defaults_invalid_expiration(self, **kwargs): """Create secrets with various invalid expiration data.""" timestamp = utils.create_timestamp_w_tz_and_offset(**kwargs) secret = self.barbicanclient.secrets.create( **secret_create_defaults_data) secret.expiration = timestamp e = self.assertRaises( exceptions.HTTPClientError, secret.store ) self.assertEqual(400, e.status_code) @utils.parameterized_dataset({ 'text/plain': [ u'meowwwwwwwmeowwwwwww', 'text/plain'], 'application/octet-stream': [ base64.b64encode( b'F\x130\x89f\x8e\xd9\xa1\x0e\x1f\r\xf67uu\x8b'), 'application/octet-stream' ] }) @testcase.attr('positive') def test_secret_update_nones(self, payload, payload_content_type): """Cover case of updating with all nones in the Secret object.""" secret = self.barbicanclient.secrets.create(**secret_create_nones_data) secret.payload = None secret.payload_content_type = None secret_ref = self.cleanup.add_entity(secret) self.assertIsNotNone(secret_ref) secret.payload = payload secret.update() resp = self.barbicanclient.secrets.get(secret_ref) self.assertEqual(payload, resp.payload) self.assertEqual(payload_content_type, resp.payload_content_type) @utils.parameterized_dataset({ 'alphanumeric': ['1f34ds'], 'punctuation': ['~!@#$%^&*()_+`-={}[]|:;<>,.?'], 'uuid': ['54262d9d-4bc7-4821-8df0-dc2ca8e112bb'], 'len_255': [str(bytearray().zfill(255))], 'empty': [''], 'null': [None] }) @testcase.attr('positive') def test_secret_get_defaults_metadata_w_valid_name(self, name): """Covers getting and checking a secret's metadata.""" secret = self.barbicanclient.secrets.create( **secret_create_defaults_data) secret.name = name secret_ref = self.cleanup.add_entity(secret) self.assertIsNotNone(secret_ref) resp = self.barbicanclient.secrets.get(secret_ref) self.assertEqual("ACTIVE", resp.status) self.assertEqual(name, resp.name) self.assertEqual(secret.mode, resp.mode) self.assertEqual(secret.algorithm, resp.algorithm) self.assertEqual(secret.bit_length, resp.bit_length) @utils.parameterized_dataset({ 'symmetric': ['symmetric', 'aes', 128, ('\x00\x01\x02\x03\x04\x05\x06\x07' '\x00\x01\x02\x03\x04\x05\x06\x07')], 'private': ['private', 'rsa', 2048, keys.get_private_key_pem()], 'public': ['public', 'rsa', 2048, keys.get_public_key_pem()], 'certificate': ['certificate', 'rsa', 2048, keys.get_certificate_pem()], 'opaque': ['opaque', None, None, (b'\x00\x01\x02\x03\x04\x05\x06\x07')], 'passphrase': ['passphrase', None, None, keys.get_passphrase_txt()], }) @testcase.attr('positive') def test_secret_get_defaults_secret_type(self, secret_type, algorithm, bit_length, payload): """Covers getting and checking a secret's metadata.""" secret = self.barbicanclient.secrets.create( **secret_create_defaults_data) secret.secret_type = secret_type secret.algorithm = algorithm secret.bit_length = bit_length # payload should not be encoded. secret.payload = payload secret_ref = self.cleanup.add_entity(secret) self.assertIsNotNone(secret_ref) resp = self.barbicanclient.secrets.get(secret_ref) self.assertEqual("ACTIVE", resp.status) self.assertEqual(secret_type, resp.secret_type) @utils.parameterized_dataset({ 'query_by_name': { 'secret_1_dict': dict(name="name1"), 'secret_2_dict': dict(name="name2"), 'query_dict': dict(name="name1") }, 'query_by_algorithm': { 'secret_1_dict': dict(algorithm="algorithm1"), 'secret_2_dict': dict(algorithm="algorithm2"), 'query_dict': dict(algorithm="algorithm1") }, 'query_by_mode': { 'secret_1_dict': dict(mode="mode1"), 'secret_2_dict': dict(mode="mode2"), 'query_dict': dict(mode="mode1") }, 'query_by_bit_length': { 'secret_1_dict': dict(bit_length=1024), 'secret_2_dict': dict(bit_length=2048), 'query_dict': dict(bits=1024) }, 'query_by_secret_type': { 'secret_1_dict': dict(secret_type='opaque'), 'secret_2_dict': dict(secret_type='symmetric'), 'query_dict': dict(secret_type='opaque') }, }) @testcase.attr('positive') def test_secret_list_with_filter(self, secret_1_dict, secret_2_dict, query_dict): secret_1 = self.barbicanclient.secrets.create(**secret_1_dict) secret_1_ref = self.cleanup.add_entity(secret_1) self.assertIsNotNone(secret_1_ref) secret_2 = self.barbicanclient.secrets.create(**secret_2_dict) secret_2_ref = self.cleanup.add_entity(secret_2) self.assertIsNotNone(secret_2_ref) secret_list = self.barbicanclient.secrets.list(**query_dict) self.assertEqual(1, len(secret_list)) @utils.parameterized_dataset({ 'query_by_name': { 'secret_1_dict': dict(name="name1"), 'secret_2_dict': dict(name="name2"), 'sort': 'name' }, 'query_by_algorithm': { 'secret_1_dict': dict(algorithm="algorithm1"), 'secret_2_dict': dict(algorithm="algorithm2"), 'sort': 'algorithm' }, 'query_by_mode': { 'secret_1_dict': dict(mode="mode1"), 'secret_2_dict': dict(mode="mode2"), 'sort': 'mode' }, 'query_by_bit_length': { 'secret_1_dict': dict(bit_length=1024), 'secret_2_dict': dict(bit_length=2048), 'sort': 'bit_length' }, 'query_by_secret_type': { 'secret_1_dict': dict(secret_type='opaque'), 'secret_2_dict': dict(secret_type='symmetric'), 'sort': 'secret_type' }, }) @testcase.attr('positive') def test_secret_list_with_sort(self, secret_1_dict, secret_2_dict, sort): secret_1 = self.barbicanclient.secrets.create(**secret_1_dict) secret_1_ref = self.cleanup.add_entity(secret_1) self.assertIsNotNone(secret_1_ref) secret_2 = self.barbicanclient.secrets.create(**secret_2_dict) secret_2_ref = self.cleanup.add_entity(secret_2) self.assertIsNotNone(secret_2_ref) query_dict = {'sort': sort + ":asc"} secret_list = self.barbicanclient.secrets.list(**query_dict) self.assertEqual(2, len(secret_list)) self.assertEqual(secret_1_ref, secret_list[0].secret_ref) query_dict = {'sort': sort + ":desc"} secret_list = self.barbicanclient.secrets.list(**query_dict) self.assertEqual(2, len(secret_list)) self.assertEqual(secret_2_ref, secret_list[0].secret_ref) @utils.parameterized_dataset({ 'created': { 'date_type': 'created', }, 'updated': { 'date_type': 'updated', }, 'expiration': { 'date_type': 'expiration', }, }) @testcase.attr('positive') def test_secret_list_with_date_filter(self, date_type): now = datetime.datetime.utcnow() expiration_1 = (now + datetime.timedelta(days=3)).isoformat() expiration_2 = (now + datetime.timedelta(days=5)).isoformat() secret_1 = self.barbicanclient.secrets.create(expiration=expiration_1) secret_1_ref = self.cleanup.add_entity(secret_1) self.assertIsNotNone(secret_1_ref) payload = "gF6+lLoF3ohA9aPRpt+6bQ==" self.barbicanclient.secrets.update(secret_1_ref, payload) time.sleep(1) secret_2 = self.barbicanclient.secrets.create(expiration=expiration_2) secret_2_ref = self.cleanup.add_entity(secret_2) self.assertIsNotNone(secret_2_ref) time_to_search_1 = getattr(secret_1, date_type).isoformat() time_to_search_2 = getattr(secret_2, date_type).isoformat() # Search for secrets with secret 1's time query_dict = {date_type: time_to_search_1} secret_list = self.barbicanclient.secrets.list(**query_dict) self.assertEqual(1, len(secret_list)) self.assertEqual(secret_1_ref, secret_list[0].secret_ref) # Search for secrets with time < secret 2, i.e. secret 1 query_dict = {date_type: 'lt:' + time_to_search_2} secret_list = self.barbicanclient.secrets.list(**query_dict) self.assertEqual(1, len(secret_list)) self.assertEqual(secret_1_ref, secret_list[0].secret_ref) # Search for secrets with time < secret 1, i.e. none query_dict = {date_type: 'lt:' + time_to_search_1} secret_list = self.barbicanclient.secrets.list(**query_dict) self.assertEqual(0, len(secret_list)) # Search for secrets with time <= secret 2, i.e. both secrets query_dict = {date_type: 'lte:' + time_to_search_2} secret_list = self.barbicanclient.secrets.list(**query_dict) self.assertEqual(2, len(secret_list)) # Search for secrets with time > secret 1, i.e. secret 2 query_dict = {date_type: 'gt:' + time_to_search_1} secret_list = self.barbicanclient.secrets.list(**query_dict) self.assertEqual(1, len(secret_list)) self.assertEqual(secret_2_ref, secret_list[0].secret_ref) # Search for secrets with time > secret 2, i.e. none query_dict = {date_type: 'gt:' + time_to_search_2} secret_list = self.barbicanclient.secrets.list(**query_dict) self.assertEqual(0, len(secret_list)) # Search for secrets with time >= secret 1, i.e. both secrets query_dict = {date_type: 'gte:' + time_to_search_1} secret_list = self.barbicanclient.secrets.list(**query_dict) self.assertEqual(2, len(secret_list)) # Sort secrets by date query_dict = {'sort': date_type + ":asc"} secret_list = self.barbicanclient.secrets.list(**query_dict) self.assertEqual(2, len(secret_list)) self.assertEqual(secret_1_ref, secret_list[0].secret_ref) # Sort secrets by date query_dict = {'sort': date_type + ":desc"} secret_list = self.barbicanclient.secrets.list(**query_dict) self.assertEqual(2, len(secret_list)) self.assertEqual(secret_2_ref, secret_list[0].secret_ref) python-barbicanclient-4.10.0/functionaltests/client/v1/functional/test_orders.py0000664000175000017500000003771013620530200030176 0ustar zuulzuul00000000000000# Copyright (c) 2015 Rackspace, Inc. # # 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. import pytz import sys from functionaltests.client import base from functionaltests.common import cleanup from functionaltests import utils from oslo_utils import timeutils from testtools import testcase from barbicanclient import exceptions order_create_key_data = { "name": "barbican functional test secret name", "algorithm": "aes", "bit_length": 256, "mode": "cbc", "payload_content_type": "application/octet-stream", } # Any field with None will be created in the model with None as the value # but will be omitted in the final request (via the requests package) # to the server. # # Given that fact, order_create_nones_data is effectively an empty json request # to the server. order_create_nones_data = { "name": None, "algorithm": None, "bit_length": None, "mode": None, "payload_content_type": None, } @utils.parameterized_test_case class OrdersTestCase(base.TestCase): def setUp(self): super(OrdersTestCase, self).setUp() self.cleanup = cleanup.CleanUp(self.barbicanclient) def tearDown(self): self.cleanup.delete_all_entities() super(OrdersTestCase, self).tearDown() @testcase.attr('positive') def test_create_order_defaults_wout_name(self): """Create an order without the name attribute.""" order = self.barbicanclient.orders.create_key(**order_create_key_data) order.name = None order_ref = self.cleanup.add_entity(order) self.assertIsNotNone(order_ref) order_resp = self.barbicanclient.orders.get(order_ref) self.assertEqual(order.name, order_resp.name) @testcase.attr('positive') def test_create_order_defaults_w_empty_name(self): """Create an order the name attribute an empty string.""" order = self.barbicanclient.orders.create_key(**order_create_key_data) order.name = "" order_ref = self.cleanup.add_entity(order) self.assertIsNotNone(order_ref) order_resp = self.barbicanclient.orders.get(order_ref) self.assertEqual(order.name, order_resp.name) @testcase.skip('Launchpad 1425667') @testcase.attr('positive') def test_create_order_defaults_payload_content_type_none(self): """Covers creating orders with various valid payload content types.""" order = self.barbicanclient.orders.create_key(**order_create_key_data) order.payload_content_type = None order_ref = self.cleanup.add_entity(order) self.assertIsNotNone(order_ref) order_resp = self.barbicanclient.orders.get(order_ref) self.assertTrue(order_resp.status == "ACTIVE" or order_resp.status == "PENDING") @testcase.attr('positive') def test_create_order_defaults_check_empty_name(self): """Create order with empty meta name. The resulting secret name should be a UUID. """ # first create an order with defaults order = self.barbicanclient.orders.create_key(**order_create_key_data) order.name = "" order_ref = self.cleanup.add_entity(order) # verify that the order was created successfully self.assertIsNotNone(order_ref) # given the order href, retrieve the order order_resp = self.barbicanclient.orders.get(order_ref) # verify that the get was successful self.assertTrue(order_resp.status == "ACTIVE" or order_resp.status == "PENDING") # verify the new secret's name matches the name in the secret ref # in the newly created order. secret_resp = self.barbicanclient.secrets.get(order_resp.secret_ref) self.assertEqual(order.name, secret_resp.name) @testcase.attr('positive') def test_order_and_secret_metadata_same(self): """Checks that metadata from secret GET and order GET are the same. Covers checking that secret metadata from a get on the order and secret metadata from a get on the secret are the same. Assumes that the order status will be active and not pending. """ order = self.barbicanclient.orders.create_key(**order_create_key_data) order_ref = self.cleanup.add_entity(order) self.assertIsNotNone(order_ref) order_resp = self.barbicanclient.orders.get(order_ref) self.assertIsNotNone(order_resp.secret_ref) secret_resp = self.barbicanclient.secrets.get(order_resp.secret_ref) self.assertEqual(secret_resp.name, order_resp.name, 'Names were not the same') self.assertEqual(secret_resp.algorithm, order_resp.algorithm, 'Algorithms were not the same') self.assertEqual(secret_resp.bit_length, order_resp.bit_length, 'Bit lengths were not the same') self.assertEqual(secret_resp.expiration, order_resp.expiration, 'Expirations were not the same') self.assertEqual(secret_resp.mode, order_resp.mode, 'Modes were not the same') @testcase.attr('negative') def test_get_order_defaults_that_doesnt_exist(self): """Covers case of getting a non-existent order.""" ref = self.barbicanclient.orders._api.endpoint_override + \ '/orders/notauuid' # try to get a non-existent order e = self.assertRaises(ValueError, self.barbicanclient.orders.get, ref) # verify that the order get failed self.assertEqual('Order incorrectly specified.', e.message) @testcase.attr('negative') def test_get_order_defaults_that_doesnt_exist_valid_uuid(self): """Covers case of getting a non-existent order with a valid UUID""" uuid = '54262d9d-4bc7-4821-8df0-dc2ca8e112bb' ref = self.barbicanclient.orders._api.endpoint_override + \ '/orders/' + uuid # try to get a non-existent order e = self.assertRaises( exceptions.HTTPClientError, self.barbicanclient.orders.get, ref ) # verify that the order get failed self.assertEqual(404, e.status_code) @testcase.attr('negative') def test_create_order_nones(self): """Covers order creation with empty JSON.""" order = self.barbicanclient.orders.create_key( **order_create_nones_data) e = self.assertRaises( exceptions.HTTPClientError, order.submit ) self.assertEqual(400, e.status_code) @testcase.attr('negative') def test_create_order_empty_entries(self): """Covers order creation with empty JSON.""" order = self.barbicanclient.orders.create_key( **order_create_nones_data) order.name = "" order.algorithm = "" order.mode = "" order.bit_length = "" order.payload_content_type = "" e = self.assertRaises( exceptions.HTTPClientError, order.submit ) self.assertEqual(400, e.status_code) @testcase.attr('negative') def test_create_order_defaults_oversized_strings(self): """Covers order creation with empty JSON.""" order = self.barbicanclient.orders.create_key(**order_create_key_data) order.name = base.TestCase.oversized_field order.algorithm = base.TestCase.oversized_field order.mode = base.TestCase.oversized_field e = self.assertRaises( exceptions.HTTPClientError, order.submit ) self.assertEqual(400, e.status_code) @utils.parameterized_dataset({ '8': [8], '64': [64], '128': [128], '192': [192], '256': [256], '1024': [1024], '2048': [2048], '4096': [4096] }) @testcase.attr('positive') def test_create_order_defaults_valid_bit_length(self, bit_length): """Covers creating orders with various valid bit lengths.""" order = self.barbicanclient.orders.create_key(**order_create_key_data) order.bit_length = bit_length order_ref = self.cleanup.add_entity(order) self.assertIsNotNone(order_ref) order_resp = self.barbicanclient.orders.get(order_ref) self.assertEqual(order.bit_length, order_resp.bit_length) @utils.parameterized_dataset({ 'negative_maxint': [-sys.maxint], 'negative_7': [-7], 'negative_1': [-1], '0': [0], '1': [1], '7': [7], '129': [129], 'none': [None], 'empty': [''], 'space': [' '], 'over_signed_small_int': [32768] }) @testcase.attr('negative') def test_create_order_defaults_invalid_bit_length(self, bit_length): """Covers creating orders with various invalid bit lengths.""" order = self.barbicanclient.orders.create_key(**order_create_key_data) order.bit_length = bit_length e = self.assertRaises( exceptions.HTTPClientError, order.submit ) self.assertEqual(400, e.status_code) @utils.parameterized_dataset({ 'alphanumeric': ['1f34ds'], 'len_255': [base.TestCase.max_sized_field], 'uuid': ['54262d9d-4bc7-4821-8df0-dc2ca8e112bb'], 'punctuation': ['~!@#$%^&*()_+`-={}[]|:;<>,.?'] }) @testcase.attr('positive') def test_create_order_defaults_valid_name(self, name): """Covers creating orders with various valid names.""" order = self.barbicanclient.orders.create_key(**order_create_key_data) order.name = name order_ref = self.cleanup.add_entity(order) self.assertIsNotNone(order_ref) order_resp = self.barbicanclient.orders.get(order_ref) self.assertEqual(order.name, order_resp.name) @utils.parameterized_dataset({ 'int': [123] }) @testcase.attr('negative') def test_create_order_defaults_invalid_name(self, name): """Covers creating orders with various invalid names.""" order = self.barbicanclient.orders.create_key(**order_create_key_data) order.name = name e = self.assertRaises( exceptions.HTTPClientError, order.submit ) self.assertEqual(400, e.status_code) @utils.parameterized_dataset({ 'cbc': ['cbc'] }) @testcase.attr('positive') def test_create_order_defaults_valid_mode(self, mode): """Covers creating orders with various valid modes.""" order = self.barbicanclient.orders.create_key(**order_create_key_data) order.mode = mode order_ref = self.cleanup.add_entity(order) self.assertIsNotNone(order_ref) order_resp = self.barbicanclient.orders.get(order_ref) self.assertEqual(order.mode, order_resp.mode) @utils.parameterized_dataset({ 'int': [123] }) @testcase.attr('negative') def test_create_order_defaults_invalid_mode(self, mode): """Covers creating orders with various invalid modes.""" order = self.barbicanclient.orders.create_key(**order_create_key_data) order.mode = mode e = self.assertRaises( exceptions.HTTPClientError, order.submit ) self.assertEqual(400, e.status_code) @utils.parameterized_dataset({ 'aes': ['aes'] }) @testcase.attr('positive') def test_create_order_defaults_valid_algorithm(self, algorithm): """Covers creating orders with various valid algorithms.""" order = self.barbicanclient.orders.create_key(**order_create_key_data) order.algorithm = algorithm order_ref = self.cleanup.add_entity(order) self.assertIsNotNone(order_ref) order_resp = self.barbicanclient.orders.get(order_ref) self.assertEqual(order.algorithm, order_resp.algorithm) @utils.parameterized_dataset({ 'int': [123] }) @testcase.attr('negative') def test_create_order_defaults_invalid_algorithm(self, algorithm): """Covers creating orders with various invalid algorithms.""" order = self.barbicanclient.orders.create_key(**order_create_key_data) order.algorithm = algorithm e = self.assertRaises( exceptions.HTTPClientError, order.submit ) self.assertEqual(400, e.status_code) # TODO(tdink) Add empty after Launchpad 1420444 is resolved @utils.parameterized_dataset({ 'text/plain': ['text/plain'], 'text_plain_space_charset_utf8': ['text/plain; charset=utf-8'], }) @testcase.attr('positive') def test_create_order_defaults_valid_payload_content_type(self, pct): """Covers order creation with various valid payload content types.""" order = self.barbicanclient.orders.create_key(**order_create_key_data) order.payload_content_type = pct order_ref = self.cleanup.add_entity(order) self.assertIsNotNone(order_ref) order_resp = self.barbicanclient.orders.get(order_ref) self.assertEqual(order.payload_content_type, order_resp.payload_content_type) @utils.parameterized_dataset({ 'int': [123], 'invalid': ['invalid'], 'oversized_string': [base.TestCase.oversized_field], 'text': ['text'], 'text_slash_with_no_subtype': ['text/'], }) @testcase.attr('negative') def test_create_order_defaults_invalid_payload_content_type(self, pct): """Covers order creation with various invalid payload content types.""" order = self.barbicanclient.orders.create_key(**order_create_key_data) order.payload_content_type = pct e = self.assertRaises( exceptions.HTTPClientError, order.submit ) self.assertEqual(400, e.status_code) @utils.parameterized_dataset({ 'negative_five_long_expire': { 'timezone': '-05:00', 'days': 5}, 'positive_five_long_expire': { 'timezone': '+05:00', 'days': 5}, 'negative_one_short_expire': { 'timezone': '-01', 'days': 1}, 'positive_one_short_expire': { 'timezone': '+01', 'days': 1} }) @testcase.attr('positive') def test_create_order_defaults_valid_expiration(self, **kwargs): """Covers creating orders with various valid expiration data.""" timestamp = utils.create_timestamp_w_tz_and_offset(**kwargs) date = timeutils.parse_isotime(timestamp) date = date.astimezone(pytz.utc) order = self.barbicanclient.orders.create_key(**order_create_key_data) order.expiration = timestamp order_ref = self.cleanup.add_entity(order) self.assertIsNotNone(order_ref) order_resp = self.barbicanclient.orders.get(order_ref) self.assertIsNotNone(order_resp) self.assertEqual(date, order_resp.expiration) @utils.parameterized_dataset({ 'malformed_timezone': { 'timezone': '-5:00', 'days': 5}, }) @testcase.attr('negative') def test_create_order_defaults_invalid_expiration(self, **kwargs): """Covers creating orders with various invalid expiration data.""" timestamp = utils.create_timestamp_w_tz_and_offset(**kwargs) order = self.barbicanclient.orders.create_key(**order_create_key_data) order.expiration = timestamp e = self.assertRaises( exceptions.HTTPClientError, order.submit ) self.assertEqual(400, e.status_code) python-barbicanclient-4.10.0/functionaltests/client/v1/smoke/0000775000175000017500000000000013620530306024242 5ustar zuulzuul00000000000000python-barbicanclient-4.10.0/functionaltests/client/v1/smoke/test_containers.py0000664000175000017500000001571213620530200030017 0ustar zuulzuul00000000000000# Copyright (c) 2015 Rackspace, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. from functionaltests.client import base from functionaltests.common import cleanup from functionaltests import utils from testtools import testcase create_secret_defaults_data = { "name": "AES key", "expiration": "2020-02-28T19:14:44.180394", "algorithm": "aes", "bit_length": 256, "mode": "cbc", "payload": "gF6+lLoF3ohA9aPRpt+6bQ==", "payload_content_type": "application/octet-stream", "payload_content_encoding": "base64", } create_container_defaults_data = { "name": "containername", "secrets": {} } create_container_rsa_data = { "name": "rsacontainer", } create_container_empty_data = { "name": None, "secrets": {} } @utils.parameterized_test_case class ContainersTestCase(base.TestCase): def setUp(self): super(ContainersTestCase, self).setUp() self.cleanup = cleanup.CleanUp(self.barbicanclient) # Set up three secrets secret_ref_1, secret_1 = self._create_a_secret() secret_ref_2, secret_2 = self._create_a_secret() secret_ref_3, secret_3 = self._create_a_secret() self.secret_list = [secret_ref_1, secret_ref_2, secret_ref_3] secrets_dict = {'secret_1': secret_1, 'secret_2': secret_2, 'secret_3': secret_3} create_container_defaults_data['secrets'] = secrets_dict create_container_rsa_data['public_key'] = secret_1 create_container_rsa_data['private_key'] = secret_2 create_container_rsa_data['private_key_passphrase'] = secret_3 def tearDown(self): """Handles test cleanup. It should be noted that delete all secrets must be called before delete containers. """ self.cleanup.delete_all_entities() super(ContainersTestCase, self).tearDown() def _create_a_secret(self): secret = self.barbicanclient.secrets.create( **create_secret_defaults_data) secret_ref = self.cleanup.add_entity(secret) return secret_ref, secret @testcase.attr('positive') def test_container_create_empty(self): """Covers creating an empty generic container.""" container = self.barbicanclient.containers.create( **create_container_defaults_data) container_ref = self.cleanup.add_entity(container) self.assertIsNotNone(container_ref) @testcase.attr('positive') def test_container_create_defaults(self): """Covers creating a container with three secret refs.""" container = self.barbicanclient.containers.create( **create_container_defaults_data) container_ref = self.cleanup.add_entity(container) self.assertIsNotNone(container_ref) @testcase.attr('positive') def test_container_create_rsa(self): """Create an RSA container with expected secret refs.""" container = self.barbicanclient.containers.create_rsa( **create_container_rsa_data) container_ref = self.cleanup.add_entity(container) self.assertIsNotNone(container_ref) @utils.parameterized_dataset({ 'alphanumeric': ['a2j3j6ll9'], 'punctuation': ['~!@#$%^&*()_+`-={}[]|:;<>,.?'], 'len_255': [str(bytearray().zfill(255))], 'uuid': ['54262d9d-4bc7-4821-8df0-dc2ca8e112bb'], 'empty': [''] }) @testcase.attr('positive') def test_container_get_defaults_w_valid_name(self, name): """Covers getting a generic container with a three secrets.""" container = self.barbicanclient.containers.create( **create_container_defaults_data) container.name = name secret_refs = self.secret_list container_ref = self.cleanup.add_entity(container) self.assertIsNotNone(container_ref) container_resp = self.barbicanclient.containers.get(container_ref) # Verify the response data self.assertEqual(container.name, container_resp.name) self.assertEqual(container_ref, container_resp.container_ref) get_resp_secret_refs = [] for name, ref in container_resp.secret_refs.iteritems(): get_resp_secret_refs.append(str(ref)) # Verify the secret refs in the response self.assertEqual(3, len(container_resp.secret_refs)) self.assertIn(secret_refs[0], get_resp_secret_refs) self.assertIn(secret_refs[1], get_resp_secret_refs) self.assertIn(secret_refs[2], get_resp_secret_refs) @testcase.attr('positive') def test_container_get_rsa(self): """Covers getting an rsa container.""" container = self.barbicanclient.containers.create_rsa( **create_container_rsa_data) secret_refs = self.secret_list container_ref = self.cleanup.add_entity(container) self.assertIsNotNone(container_ref) container_resp = self.barbicanclient.containers.get(container_ref) # Verify the response data self.assertEqual("rsacontainer", container_resp.name) self.assertEqual(container_ref, container_resp.container_ref) get_resp_secret_refs = [] for name, ref in container_resp.secret_refs.iteritems(): get_resp_secret_refs.append(str(ref)) # Verify the secret refs in the response self.assertEqual(3, len(container_resp.secret_refs)) self.assertIn(secret_refs[0], get_resp_secret_refs) self.assertIn(secret_refs[1], get_resp_secret_refs) self.assertIn(secret_refs[2], get_resp_secret_refs) @testcase.attr('positive') def test_containers_get_defaults(self): """Covers getting a list of containers.""" limit = 10 offset = 0 total = 10 for i in range(0, total + 1): container = self.barbicanclient.containers.create( **create_container_defaults_data) container_ref = self.cleanup.add_entity(container) self.assertIsNotNone(container_ref) containers = self.barbicanclient.containers.list(limit=limit, offset=offset) self.assertEqual(limit, len(containers)) def test_container_delete_defaults(self): """Covers deleting a container.""" container = self.barbicanclient.containers.create( **create_container_defaults_data) container_ref = container.store() self.assertIsNotNone(container_ref) del_resp = self.barbicanclient.containers.delete(container_ref) self.assertIsNone(del_resp) python-barbicanclient-4.10.0/functionaltests/client/v1/smoke/__init__.py0000664000175000017500000000000013620530200026332 0ustar zuulzuul00000000000000python-barbicanclient-4.10.0/functionaltests/client/v1/smoke/test_secrets.py0000664000175000017500000001314213620530200027315 0ustar zuulzuul00000000000000# Copyright (c) 2015 Rackspace, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. from functionaltests.client import base from functionaltests.common import cleanup from functionaltests.common import keys from functionaltests import utils from testtools import testcase secret_create_defaults_data = { "name": "AES key", "expiration": "2020-02-28T19:14:44.180394", "algorithm": "aes", "bit_length": 256, "mode": "cbc", "payload": "gF6+lLoF3ohA9aPRpt+6bQ==" } secret_create_nones_data = { "name": None, "expiration": None, "algorithm": None, "bit_length": None, "mode": None, "payload": "gF6+lLoF3ohA9aPRpt+6bQ==", "payload_content_type": "application/octet-stream", "payload_content_encoding": "base64", } @utils.parameterized_test_case class SecretsTestCase(base.TestCase): def setUp(self): super(SecretsTestCase, self).setUp() self.cleanup = cleanup.CleanUp(self.barbicanclient) def tearDown(self): self.cleanup.delete_all_entities() super(SecretsTestCase, self).tearDown() @testcase.attr('positive') def test_create_secret_defaults(self): """Creates a secret with default values""" secret = self.barbicanclient.secrets.create( **secret_create_defaults_data) secret_ref = self.cleanup.add_entity(secret) self.assertIsNotNone(secret_ref) @testcase.attr('positive') @utils.parameterized_dataset({ 'symmetric': ['symmetric', 'aes', 128, ('\x00\x01\x02\x03\x04\x05\x06\x07' '\x00\x01\x02\x03\x04\x05\x06\x07')], 'private': ['private', 'rsa', 2048, keys.get_private_key_pem()], 'public': ['public', 'rsa', 2048, keys.get_public_key_pem()], 'certificate': ['certificate', 'rsa', 2048, keys.get_certificate_pem()], 'opaque': ['opaque', None, None, (b'\x00\x01\x02\x03\x04\x05\x06\x07')], 'passphrase': ['passphrase', None, None, keys.get_passphrase_txt()], }) def test_create_secret_with_type(self, secret_type, algorithm, bit_length, secret): """Creates a secret with default values""" secret_data = secret_create_defaults_data secret_data['secret_type'] = secret_type secret_data['algorithm'] = algorithm secret_data['bit_length'] = bit_length # payload should not be encoded. secret_data['payload'] = secret secret = self.barbicanclient.secrets.create( **secret_create_defaults_data) secret_ref = self.cleanup.add_entity(secret) self.assertIsNotNone(secret_ref) @testcase.attr('positive') def test_secret_create_defaults_no_expiration(self): """Covers creating a secret without an expiration.""" secret = self.barbicanclient.secrets.create( **secret_create_defaults_data) secret.expiration = None secret_ref = self.cleanup.add_entity(secret) self.assertIsNotNone(secret_ref) @testcase.attr('positive') def test_secret_delete_defaults(self): """Covers deleting a secret.""" secret = self.barbicanclient.secrets.create( **secret_create_defaults_data) secret_ref = secret.store() del_response = self.barbicanclient.secrets.delete(secret_ref) self.assertIsNone(del_response) @testcase.attr('positive') def test_secret_delete_minimal_secret_w_no_metadata(self): """Covers deleting a secret with nones data.""" secret = self.barbicanclient.secrets.create( **secret_create_nones_data) secret_ref = secret.store() self.assertIsNotNone(secret_ref) del_resp = self.barbicanclient.secrets.delete(secret_ref) self.assertIsNone(del_resp) @testcase.attr('positive') def test_secret_get_defaults_payload(self): """Covers getting a secret's payload data.""" secret = self.barbicanclient.secrets.create( **secret_create_defaults_data) secret_ref = self.cleanup.add_entity(secret) secret_resp = self.barbicanclient.secrets.get(secret_ref) self.assertEqual(secret.payload, secret_resp.payload) @testcase.attr('positive') def test_secrets_get_defaults_multiple_secrets(self): """Covers getting a list of secrets. Creates 11 secrets then returns a list of 5 secrets """ limit = 5 offset = 5 total = 10 for i in range(0, total + 1): secret = self.barbicanclient.secrets.create( **secret_create_defaults_data) self.cleanup.add_entity(secret) secret_list = self.barbicanclient.secrets.list(limit=limit, offset=offset) self.assertEqual(limit, len(secret_list)) python-barbicanclient-4.10.0/functionaltests/client/v1/smoke/test_orders.py0000664000175000017500000001233613620530200027147 0ustar zuulzuul00000000000000# Copyright (c) 2015 Rackspace, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. from testtools import testcase from functionaltests.client import base from functionaltests.common import cleanup from functionaltests import utils order_create_key_data = { "name": "barbican functional test secret name", "algorithm": "aes", "bit_length": 256, "mode": "cbc", "payload_content_type": "application/octet-stream", } # Any field with None will be created in the model with None as the value # but will be omitted in the final request (via the requests package) # to the server. # # Given that fact, order_create_nones_data is effectively an empty json request # to the server. order_create_nones_data = { 'type': None, "meta": { "name": None, "algorithm": None, "bit_length": None, "mode": None, "payload_content_type": None, } } @utils.parameterized_test_case class OrdersTestCase(base.TestCase): def setUp(self): super(OrdersTestCase, self).setUp() self.cleanup = cleanup.CleanUp(self.barbicanclient) def tearDown(self): self.cleanup.delete_all_entities() super(OrdersTestCase, self).tearDown() @testcase.attr('positive') def test_create_order_defaults(self): """Covers simple order creation.""" order = self.barbicanclient.orders.create_key( **order_create_key_data) order_ref = self.cleanup.add_entity(order) self.assertIsNotNone(order_ref) @testcase.attr('positive') def test_get_order_defaults_metadata(self): """Covers order metadata. Assumes that the order status will be active or pending. """ # first create an order order = self.barbicanclient.orders.create_key( **order_create_key_data) order_ref = self.cleanup.add_entity(order) # verify that the order was created successfully self.assertIsNotNone(order_ref) # given the order href, retrieve the order order_resp = self.barbicanclient.orders.get(order_ref) # verify that the get was successful self.assertTrue(order_resp.status == "ACTIVE" or order_resp.status == "PENDING") # verify the metadata self.assertEqual(order.name, order_resp.name) self.assertEqual(order.mode, order_resp.mode) self.assertEqual(order.algorithm, order_resp.algorithm) self.assertEqual(order.bit_length, order_resp.bit_length) self.assertEqual(order.payload_content_type, order_resp.payload_content_type) @testcase.attr('positive') def test_get_order_defaults(self): """Covers getting an order. Assumes that the order status will be active or pending. """ # create an order order = self.barbicanclient.orders.create_key( **order_create_key_data) order_ref = self.cleanup.add_entity(order) self.assertIsNotNone(order_ref) # get the order order_resp = self.barbicanclient.orders.get(order_ref) # verify the order self.assertIsNotNone(order_resp.order_ref) self.assertEqual('key', order_resp._type) self.assertTrue(order_resp.status == "ACTIVE" or order_resp.status == "PENDING") if order_resp.status == "ACTIVE": self.assertIsNotNone(order_resp.secret_ref) @testcase.attr('positive') def test_delete_order_defaults(self): """Covers simple order deletion.""" # create an order order = self.barbicanclient.orders.create_key( **order_create_key_data) order_ref = order.submit() secret_ref = self.barbicanclient.orders.get(order_ref).secret_ref # delete the order delete_resp = self.barbicanclient.orders.delete(order_ref) self.assertIsNone(delete_resp) # delete the secret self.barbicanclient.secrets.delete(secret_ref) @testcase.attr('positive') def test_get_orders_defaults(self): """Covers getting a list of orders.""" limit = 7 offset = 0 total = 10 # create the orders for i in range(0, total + 1): order = self.barbicanclient.orders.create_key( **order_create_key_data) order_ref = self.cleanup.add_entity(order) self.assertIsNotNone(order_ref) # get a list of orders orders_list = self.barbicanclient.orders.list(limit=limit, offset=offset) # verify that the get for the list was successful self.assertEqual(limit, len(orders_list)) python-barbicanclient-4.10.0/functionaltests/client/v1/__init__.py0000664000175000017500000000000013620530200025214 0ustar zuulzuul00000000000000python-barbicanclient-4.10.0/functionaltests/post_test_hook.sh0000775000175000017500000000170313620530200024715 0ustar zuulzuul00000000000000#!/bin/bash # # 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. # This script is executed inside post_test_hook function in devstack gate. # Install packages from test-requirements.txt sudo pip install -r /opt/stack/new/python-barbicanclient/test-requirements.txt # Make sure we're running the trunk client before we run the tests sudo pip install -U /opt/stack/new/python-barbicanclient cd /opt/stack/new/python-barbicanclient/functionaltests sudo ./run_tests.sh python-barbicanclient-4.10.0/functionaltests/common/0000775000175000017500000000000013620530306022610 5ustar zuulzuul00000000000000python-barbicanclient-4.10.0/functionaltests/common/config.py0000664000175000017500000000532713620530200024427 0ustar zuulzuul00000000000000""" Copyright 2015 Rackspace 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. """ import os from oslo_config import cfg TEST_CONF = None def setup_config(config_file=''): global TEST_CONF TEST_CONF = cfg.ConfigOpts() identity_group = cfg.OptGroup(name='identity') identity_options = [ cfg.StrOpt('uri', default='http://localhost/identity'), cfg.StrOpt('auth_version', default='v3'), cfg.StrOpt('username', default='admin'), cfg.StrOpt('password', default='secretadmin'), cfg.StrOpt('tenant_name', default='admin'), cfg.StrOpt('domain_name', default='Default'), cfg.StrOpt('admin_username', default='admin'), cfg.StrOpt('admin_password', default='secretadmin'), cfg.StrOpt('admin_tenant_name', default='admin'), cfg.StrOpt('admin_domain_name', default='Default') ] TEST_CONF.register_group(identity_group) TEST_CONF.register_opts(identity_options, group=identity_group) keymanager_group = cfg.OptGroup(name='keymanager') keymanager_options = [ cfg.StrOpt('url', default='http://localhost/key-manager'), cfg.StrOpt('username', default='admin'), cfg.StrOpt('password', default='secretadmin'), cfg.StrOpt('project_name', default='admin'), cfg.StrOpt('project_id', default='admin'), cfg.StrOpt('project_domain_name', default='Default'), cfg.IntOpt('max_payload_size', default=10000) ] TEST_CONF.register_group(keymanager_group) TEST_CONF.register_opts(keymanager_options, group=keymanager_group) # Figure out which config to load config_to_load = [] local_config = './etc/functional_tests.conf' devstack_config = '../etc/functional_tests.conf' if os.path.isfile(config_file): config_to_load.append(config_file) elif os.path.isfile(local_config): config_to_load.append(local_config) elif os.path.isfile(devstack_config): config_to_load.append(devstack_config) else: config_to_load.append('/etc/functional_tests.conf') # Actually parse config TEST_CONF( (), # Required to load an anonymous config default_config_files=config_to_load ) def get_config(): if not TEST_CONF: setup_config() return TEST_CONF python-barbicanclient-4.10.0/functionaltests/common/keys.py0000664000175000017500000005077513620530200024144 0ustar zuulzuul00000000000000# Copyright (c) 2015 Cisco Systems # # 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. def get_private_key_pem(): """Returns a private key in PCKS#8 format This key was created by issuing the following openssl commands: openssl genrsa -out private.pem 2048 openssl pkcs8 -topk8 -nocrypt -in private.pem -out private.pk8 The byte string returned by this function is the contents of the private.pk8 file. """ return """-----BEGIN PRIVATE KEY----- MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCza2VoDXmBUMmw jFu9F6MM5q/AZ1WjnWA2YNdNy237TrGN/nobDDv8FBBpUPmHNZ04H1LyxFcP8ReF rcIXpifsReu2lAWaqRPxovu5CuAhfecKv+RhjLVLJ0I+MZIb72ROKpfZTmb7dhlF gGD3vkC51BCfhGVW35w52OY/23x5MeO4yvx5myPccnxMVQ42KuDrzKqjBlSjmBnc pGYx0JgCT+syFmHsl8rOkqCPPFLo24YQn+4/pr1AYwaZAbMTl9zoLtEQj6sxScuH cS9e8niptDxlsbLQgqGVaGdE117stC95QH7UvITbuYzdjZwBFc1Sgz8GZ/2hLSsH ujJiIQcvAgMBAAECggEAMOlUKbuSpigp85Ev6Sqqbnfs7Zy+Ae6DLg/UYgbVIq9f RABdtUXujFfD6ZIDlFKPW59ec4QG3/evm+e0g9HuDEE7cviDVphFMZhm2xkV5Mt3 0rxhPB6pxaUcL+w/kpH+XDjMUJdJB8A4P3Qx+xfIeWBQb8wd/ELVSgfRLRNeqYL0 0KXVs04/FOBEhqSiqi/oHYJ4gxNrSoINX71PHVbaEikIygzi4HZVyMut3LE6ceHz fSj71ftn+Ui0TzkLOb+NoBP31haHC/sfCrpKg7QtUP9q9dRq6dZcI17q5d7oEdET eDRKhT2vm7bx2bLGeF1w2H9B/V81upjiAah2RVnecQKBgQDsfHSjR1gd+SHw/2A9 SaXS1k9LeXLt+UbDQdbjYOsh5LoT+EN/utO70RyDYqjlhzqJzciKTuAW5SVPC6gQ uCppA29Kntq7x1+Lw/4wG947poXb60tLdg3BK5mBFTORk5ATqAwVq7t+2NtS5S/J unzs5xrRolDFnSX4KnvVl6Jj3QKBgQDCOXZTVXRPEFhnqnqLErZe6EJkySwG8wgt OdCmr660bocY1i9vV+RaM1iARHX6u/suMhkz+3KRinzxIG5gQsyiWmTpFV298W9v kRtmsCQDn2my90yv4e6sLI0ng7l/N3r7CwLLNIV/CqeyaN40suzE8AjgEga5jTua 6bP5m+x8ewKBgQCeuW3DxXfkLjnUumMK36qX11XDb5FvHjebiE5FsOBAkHdAPgp3 6ZqBXfoISSjZXakxotft1MDdPRGMe2NjTWjRsQd6iyJ+lHORqIusGJhRaxQ/Ji8U R/k1ZSETnXpORD+YodrylKA0pDKY8dDgUfXVP8wlVg9mg3JfnYweMTdCVQKBgQCx 133iNmgmkTfxzGci+wJkitVohdA7mMOO7daBGnKlImOvuUd784XTlhpecNF6wi/w D82GDKLOY3meLO0EVYYczxqBVqAccXtxM/RcJcMEUi6twcXFcuJhYvXpDbOHqlyA jIeFW9U1C6OcOGvm40Lr3UKzMa5Yrtq6MW4ri7uSCwKBgQDfdqVjT4uXmGwOh1z4 Pzv6GCoc+6GobXg4DvvCUjP9MR+2+5sX0AY/f+aVCD05/Nj0RqpAwUc03zZU5ZtL 2uNe6XDjEugfFtlzea6+rbD6KpFS+nxPJA8YyWYRpNhpRWGWQakHedr3BtMtGs0h pKNAQG72HKWtSfJQMXvn2RlicA== -----END PRIVATE KEY-----""" def get_private_key_der(): """Returns a private key in DER format This key was created by issuing the following openssl commands: openssl genrsa -out private.pem 2048 openssl pkcs8 -in private.pem -topk8 -nocrypt \ -outform DER -out private_pk8.der The byte string returned by this function is the contents of the private_pk8.der file. """ key_der = ( '\x30\x82\x04\xbf\x02\x01\x00\x30\x0d\x06\x09\x2a\x86\x48\x86' '\xf7\x0d\x01\x01\x01\x05\x00\x04\x82\x04\xa9\x30\x82\x04\xa5' '\x02\x01\x00\x02\x82\x01\x01\x00\xb3\x6b\x65\x68\x0d\x79\x81' '\x50\xc9\xb0\x8c\x5b\xbd\x17\xa3\x0c\xe6\xaf\xc0\x67\x55\xa3' '\x9d\x60\x36\x60\xd7\x4d\xcb\x6d\xfb\x4e\xb1\x8d\xfe\x7a\x1b' '\x0c\x3b\xfc\x14\x10\x69\x50\xf9\x87\x35\x9d\x38\x1f\x52\xf2' '\xc4\x57\x0f\xf1\x17\x85\xad\xc2\x17\xa6\x27\xec\x45\xeb\xb6' '\x94\x05\x9a\xa9\x13\xf1\xa2\xfb\xb9\x0a\xe0\x21\x7d\xe7\x0a' '\xbf\xe4\x61\x8c\xb5\x4b\x27\x42\x3e\x31\x92\x1b\xef\x64\x4e' '\x2a\x97\xd9\x4e\x66\xfb\x76\x19\x45\x80\x60\xf7\xbe\x40\xb9' '\xd4\x10\x9f\x84\x65\x56\xdf\x9c\x39\xd8\xe6\x3f\xdb\x7c\x79' '\x31\xe3\xb8\xca\xfc\x79\x9b\x23\xdc\x72\x7c\x4c\x55\x0e\x36' '\x2a\xe0\xeb\xcc\xaa\xa3\x06\x54\xa3\x98\x19\xdc\xa4\x66\x31' '\xd0\x98\x02\x4f\xeb\x32\x16\x61\xec\x97\xca\xce\x92\xa0\x8f' '\x3c\x52\xe8\xdb\x86\x10\x9f\xee\x3f\xa6\xbd\x40\x63\x06\x99' '\x01\xb3\x13\x97\xdc\xe8\x2e\xd1\x10\x8f\xab\x31\x49\xcb\x87' '\x71\x2f\x5e\xf2\x78\xa9\xb4\x3c\x65\xb1\xb2\xd0\x82\xa1\x95' '\x68\x67\x44\xd7\x5e\xec\xb4\x2f\x79\x40\x7e\xd4\xbc\x84\xdb' '\xb9\x8c\xdd\x8d\x9c\x01\x15\xcd\x52\x83\x3f\x06\x67\xfd\xa1' '\x2d\x2b\x07\xba\x32\x62\x21\x07\x2f\x02\x03\x01\x00\x01\x02' '\x82\x01\x00\x30\xe9\x54\x29\xbb\x92\xa6\x28\x29\xf3\x91\x2f' '\xe9\x2a\xaa\x6e\x77\xec\xed\x9c\xbe\x01\xee\x83\x2e\x0f\xd4' '\x62\x06\xd5\x22\xaf\x5f\x44\x00\x5d\xb5\x45\xee\x8c\x57\xc3' '\xe9\x92\x03\x94\x52\x8f\x5b\x9f\x5e\x73\x84\x06\xdf\xf7\xaf' '\x9b\xe7\xb4\x83\xd1\xee\x0c\x41\x3b\x72\xf8\x83\x56\x98\x45' '\x31\x98\x66\xdb\x19\x15\xe4\xcb\x77\xd2\xbc\x61\x3c\x1e\xa9' '\xc5\xa5\x1c\x2f\xec\x3f\x92\x91\xfe\x5c\x38\xcc\x50\x97\x49' '\x07\xc0\x38\x3f\x74\x31\xfb\x17\xc8\x79\x60\x50\x6f\xcc\x1d' '\xfc\x42\xd5\x4a\x07\xd1\x2d\x13\x5e\xa9\x82\xf4\xd0\xa5\xd5' '\xb3\x4e\x3f\x14\xe0\x44\x86\xa4\xa2\xaa\x2f\xe8\x1d\x82\x78' '\x83\x13\x6b\x4a\x82\x0d\x5f\xbd\x4f\x1d\x56\xda\x12\x29\x08' '\xca\x0c\xe2\xe0\x76\x55\xc8\xcb\xad\xdc\xb1\x3a\x71\xe1\xf3' '\x7d\x28\xfb\xd5\xfb\x67\xf9\x48\xb4\x4f\x39\x0b\x39\xbf\x8d' '\xa0\x13\xf7\xd6\x16\x87\x0b\xfb\x1f\x0a\xba\x4a\x83\xb4\x2d' '\x50\xff\x6a\xf5\xd4\x6a\xe9\xd6\x5c\x23\x5e\xea\xe5\xde\xe8' '\x11\xd1\x13\x78\x34\x4a\x85\x3d\xaf\x9b\xb6\xf1\xd9\xb2\xc6' '\x78\x5d\x70\xd8\x7f\x41\xfd\x5f\x35\xba\x98\xe2\x01\xa8\x76' '\x45\x59\xde\x71\x02\x81\x81\x00\xec\x7c\x74\xa3\x47\x58\x1d' '\xf9\x21\xf0\xff\x60\x3d\x49\xa5\xd2\xd6\x4f\x4b\x79\x72\xed' '\xf9\x46\xc3\x41\xd6\xe3\x60\xeb\x21\xe4\xba\x13\xf8\x43\x7f' '\xba\xd3\xbb\xd1\x1c\x83\x62\xa8\xe5\x87\x3a\x89\xcd\xc8\x8a' '\x4e\xe0\x16\xe5\x25\x4f\x0b\xa8\x10\xb8\x2a\x69\x03\x6f\x4a' '\x9e\xda\xbb\xc7\x5f\x8b\xc3\xfe\x30\x1b\xde\x3b\xa6\x85\xdb' '\xeb\x4b\x4b\x76\x0d\xc1\x2b\x99\x81\x15\x33\x91\x93\x90\x13' '\xa8\x0c\x15\xab\xbb\x7e\xd8\xdb\x52\xe5\x2f\xc9\xba\x7c\xec' '\xe7\x1a\xd1\xa2\x50\xc5\x9d\x25\xf8\x2a\x7b\xd5\x97\xa2\x63' '\xdd\x02\x81\x81\x00\xc2\x39\x76\x53\x55\x74\x4f\x10\x58\x67' '\xaa\x7a\x8b\x12\xb6\x5e\xe8\x42\x64\xc9\x2c\x06\xf3\x08\x2d' '\x39\xd0\xa6\xaf\xae\xb4\x6e\x87\x18\xd6\x2f\x6f\x57\xe4\x5a' '\x33\x58\x80\x44\x75\xfa\xbb\xfb\x2e\x32\x19\x33\xfb\x72\x91' '\x8a\x7c\xf1\x20\x6e\x60\x42\xcc\xa2\x5a\x64\xe9\x15\x5d\xbd' '\xf1\x6f\x6f\x91\x1b\x66\xb0\x24\x03\x9f\x69\xb2\xf7\x4c\xaf' '\xe1\xee\xac\x2c\x8d\x27\x83\xb9\x7f\x37\x7a\xfb\x0b\x02\xcb' '\x34\x85\x7f\x0a\xa7\xb2\x68\xde\x34\xb2\xec\xc4\xf0\x08\xe0' '\x12\x06\xb9\x8d\x3b\x9a\xe9\xb3\xf9\x9b\xec\x7c\x7b\x02\x81' '\x81\x00\x9e\xb9\x6d\xc3\xc5\x77\xe4\x2e\x39\xd4\xba\x63\x0a' '\xdf\xaa\x97\xd7\x55\xc3\x6f\x91\x6f\x1e\x37\x9b\x88\x4e\x45' '\xb0\xe0\x40\x90\x77\x40\x3e\x0a\x77\xe9\x9a\x81\x5d\xfa\x08' '\x49\x28\xd9\x5d\xa9\x31\xa2\xd7\xed\xd4\xc0\xdd\x3d\x11\x8c' '\x7b\x63\x63\x4d\x68\xd1\xb1\x07\x7a\x8b\x22\x7e\x94\x73\x91' '\xa8\x8b\xac\x18\x98\x51\x6b\x14\x3f\x26\x2f\x14\x47\xf9\x35' '\x65\x21\x13\x9d\x7a\x4e\x44\x3f\x98\xa1\xda\xf2\x94\xa0\x34' '\xa4\x32\x98\xf1\xd0\xe0\x51\xf5\xd5\x3f\xcc\x25\x56\x0f\x66' '\x83\x72\x5f\x9d\x8c\x1e\x31\x37\x42\x55\x02\x81\x81\x00\xb1' '\xd7\x7d\xe2\x36\x68\x26\x91\x37\xf1\xcc\x67\x22\xfb\x02\x64' '\x8a\xd5\x68\x85\xd0\x3b\x98\xc3\x8e\xed\xd6\x81\x1a\x72\xa5' '\x22\x63\xaf\xb9\x47\x7b\xf3\x85\xd3\x96\x1a\x5e\x70\xd1\x7a' '\xc2\x2f\xf0\x0f\xcd\x86\x0c\xa2\xce\x63\x79\x9e\x2c\xed\x04' '\x55\x86\x1c\xcf\x1a\x81\x56\xa0\x1c\x71\x7b\x71\x33\xf4\x5c' '\x25\xc3\x04\x52\x2e\xad\xc1\xc5\xc5\x72\xe2\x61\x62\xf5\xe9' '\x0d\xb3\x87\xaa\x5c\x80\x8c\x87\x85\x5b\xd5\x35\x0b\xa3\x9c' '\x38\x6b\xe6\xe3\x42\xeb\xdd\x42\xb3\x31\xae\x58\xae\xda\xba' '\x31\x6e\x2b\x8b\xbb\x92\x0b\x02\x81\x81\x00\xdf\x76\xa5\x63' '\x4f\x8b\x97\x98\x6c\x0e\x87\x5c\xf8\x3f\x3b\xfa\x18\x2a\x1c' '\xfb\xa1\xa8\x6d\x78\x38\x0e\xfb\xc2\x52\x33\xfd\x31\x1f\xb6' '\xfb\x9b\x17\xd0\x06\x3f\x7f\xe6\x95\x08\x3d\x39\xfc\xd8\xf4' '\x46\xaa\x40\xc1\x47\x34\xdf\x36\x54\xe5\x9b\x4b\xda\xe3\x5e' '\xe9\x70\xe3\x12\xe8\x1f\x16\xd9\x73\x79\xae\xbe\xad\xb0\xfa' '\x2a\x91\x52\xfa\x7c\x4f\x24\x0f\x18\xc9\x66\x11\xa4\xd8\x69' '\x45\x61\x96\x41\xa9\x07\x79\xda\xf7\x06\xd3\x2d\x1a\xcd\x21' '\xa4\xa3\x40\x40\x6e\xf6\x1c\xa5\xad\x49\xf2\x50\x31\x7b\xe7' '\xd9\x19\x62\x70') return key_der def get_public_key_pem(): """Returns a public key in PEM format This key was created by issuing the following openssl commands: openssl genrsa -out private.pem 2048 openssl rsa -in private.pem -pubout > public.pem The byte string returned by this function is the contents of the public.pem file. """ return """-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs2tlaA15gVDJsIxbvRej DOavwGdVo51gNmDXTctt+06xjf56Gww7/BQQaVD5hzWdOB9S8sRXD/EXha3CF6Yn 7EXrtpQFmqkT8aL7uQrgIX3nCr/kYYy1SydCPjGSG+9kTiqX2U5m+3YZRYBg975A udQQn4RlVt+cOdjmP9t8eTHjuMr8eZsj3HJ8TFUONirg68yqowZUo5gZ3KRmMdCY Ak/rMhZh7JfKzpKgjzxS6NuGEJ/uP6a9QGMGmQGzE5fc6C7REI+rMUnLh3EvXvJ4 qbQ8ZbGy0IKhlWhnRNde7LQveUB+1LyE27mM3Y2cARXNUoM/Bmf9oS0rB7oyYiEH LwIDAQAB -----END PUBLIC KEY-----""" def get_public_key_der(): """Returns a public key in DER format This key was created by issuing the following openssl commands: openssl genrsa -out private.pem 2048 openssl rsa -in private.pem -pubout > public.pem The byte string returned by this function is the contents of the public.der file. """ key_der = ( '\x30\x82\x01\x22\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01' '\x01\x01\x05\x00\x03\x82\x01\x0f\x00\x30\x82\x01\x0a\x02\x82' '\x01\x01\x00\xb3\x6b\x65\x68\x0d\x79\x81\x50\xc9\xb0\x8c\x5b' '\xbd\x17\xa3\x0c\xe6\xaf\xc0\x67\x55\xa3\x9d\x60\x36\x60\xd7' '\x4d\xcb\x6d\xfb\x4e\xb1\x8d\xfe\x7a\x1b\x0c\x3b\xfc\x14\x10' '\x69\x50\xf9\x87\x35\x9d\x38\x1f\x52\xf2\xc4\x57\x0f\xf1\x17' '\x85\xad\xc2\x17\xa6\x27\xec\x45\xeb\xb6\x94\x05\x9a\xa9\x13' '\xf1\xa2\xfb\xb9\x0a\xe0\x21\x7d\xe7\x0a\xbf\xe4\x61\x8c\xb5' '\x4b\x27\x42\x3e\x31\x92\x1b\xef\x64\x4e\x2a\x97\xd9\x4e\x66' '\xfb\x76\x19\x45\x80\x60\xf7\xbe\x40\xb9\xd4\x10\x9f\x84\x65' '\x56\xdf\x9c\x39\xd8\xe6\x3f\xdb\x7c\x79\x31\xe3\xb8\xca\xfc' '\x79\x9b\x23\xdc\x72\x7c\x4c\x55\x0e\x36\x2a\xe0\xeb\xcc\xaa' '\xa3\x06\x54\xa3\x98\x19\xdc\xa4\x66\x31\xd0\x98\x02\x4f\xeb' '\x32\x16\x61\xec\x97\xca\xce\x92\xa0\x8f\x3c\x52\xe8\xdb\x86' '\x10\x9f\xee\x3f\xa6\xbd\x40\x63\x06\x99\x01\xb3\x13\x97\xdc' '\xe8\x2e\xd1\x10\x8f\xab\x31\x49\xcb\x87\x71\x2f\x5e\xf2\x78' '\xa9\xb4\x3c\x65\xb1\xb2\xd0\x82\xa1\x95\x68\x67\x44\xd7\x5e' '\xec\xb4\x2f\x79\x40\x7e\xd4\xbc\x84\xdb\xb9\x8c\xdd\x8d\x9c' '\x01\x15\xcd\x52\x83\x3f\x06\x67\xfd\xa1\x2d\x2b\x07\xba\x32' '\x62\x21\x07\x2f\x02\x03\x01\x00\x01') return key_der def get_encrypted_private_key_pem(): """Returns an encrypted private key in PKCS#8 format This key was created by issuing the following openssl commands: openssl genrsa -out private.pem 2048 echo password > passphrase.txt openssl pkcs8 -topk8 -passout file:passphrase.txt \ -in private.pem -out private_encrypted.pk8 The byte string returned by this function is the contents of the private_encrypted.pk8 file. """ return """-----BEGIN ENCRYPTED PRIVATE KEY----- MIIE6TAbBgkqhkiG9w0BBQMwDgQIssadeQrYhhACAggABIIEyDNw3SV2b19yy4Q/ kTbtJ/p2X2zKDqr7GgLeAowqqhcMfvprI7G8C0XtwxkR4SjMZUXNcmOwQB2kNKtK ZilCz6pSx81iUj4s1fU460XkhkIeV+F7aB2PsTG1oDfPCuzKFjT6EuSE6lFUH89r TRuHWMPseW7lrvEB5kNMFag5QxeKjsSCNkZWOT74o4fh3cEplgCEaA+nCclXU79m 5rhaa9e1SUpPuPlhnAIDkBtHcC38B+SOYKQxLdZT1f72oZ1ozWJ4bEhKxvnNu5J+ tCvgWOXMIEJVGgf8Cu58PoR18LyyAIk7zza+1LkCiyuLNgiz8a1sVw8uBcrVgD5R 8f4XgI/Yjb16Bmpp/0iEjNcURaby9GnCCEc+W/ivSJTnG3o1Xn00FO98l2aggNpt S8gxK05NeCtdWoFFjTeIXxnb1ct0Iep8RwuO+FnupAf6aw12Uqj4qYNvNiY/kBhS P/Yd3KznasrolUZ9+PVTMUI45UTMN/XhNvXrozMq9nItWTV7wHyEL3mrYipvcxrm SnLlAp2zkmSu923cHN1teLE99/rV2jaBM03ROqvYWaxjfOjxfwz6PhdE8G//kWd0 tf2Om+fyCkBRxo1sUcuiE79hJXgP5KJCMbPsDyG/aQk4oeS1nbn15AhthwiU7A13 h9X6asgV2H+4Ljf+tr1b8p3qj3CSljfzoVErLqoHagjVB45WktHhrWbUSRpXSvPo Hh0LY62qxTa67gKjwarH5hYr5IaH39iR9bcyuvzE+u9TJWvWmeLJ7UmesfVPZtSf /JTpvr0zu4C95lXKt4FdxOhGcWwDN1Zp+lCsF5ruBGc+/pEggiXi1qvW9xUny1Of 8NqdPxGPb4/zPHGaysypPsc6LiY3esI8wa7FnDsS4e79dWinD/BPWEa5N2jLm0Rr njkHTy0xtnw/a8Ofrtyy9V1tBBOCaswzGIZZj6oHyFCtAvjZuYa8TWVmSi6EqJKi lY5wSdQQXg3H0HnQYivtOY1YbfjtRkUB9e4xkSVhvYJpY1QWBtApdUGBsxsELkDC 6cv/Kxnd9U7dz9+VhD0hAdrhFqbWqOEGTWt7xE44yzWokdKQWu5FsTs6gyXsGPen ZgZlR5pjPNGbMdftW0M473YyvtzjrCuSVgJspCzpA9uo6wfejaFb4RF/tcWtXglE Q5FzfsO1OZr6nONraShj9N1kxGBXUUOtAjZI/zoTWk3yndxw3IpvPtDTg9ByCp7F RFUtDyrki+YAIAiTgPq7qwc1upjU7R1Zlg4jIe0RI9A73NyLwa4QhgO+HmRBt7At LLuUeCFKuXMBHzlDaMYwq5ZPOb8VcMkhUoug2YJIc4YOOHh5O0mYnat0vaYO+A58 DiuYgxKmO5+6+OMk2ovZgk1sFawR4rk9HUt8goUUptZ+hoHUVGtte5YcQniIOcds qY3ni/zwswHWQRaAu8Ej4qJKt1XwZo2K04xHhL90TMaY8NpLSMCfVqDDL409TqIj zHUfYl6N2Me4eKc8vl6Sm63g57NzLqTttD6KSn8v+OmUF5mOQwcLnr3nK7S+BQfI DLPY1Oh7Kec/M/d1080/Qv9YBAJhz50TLKoxXwVeH4OOvuaHVaotElMkr5QEkEXl gRgwkbMrQjg0II0O9g== -----END ENCRYPTED PRIVATE KEY-----""" def get_passphrase_txt(): """Returns the plain text string used to encrypt the private key This key was created by issuing the following commands: echo password > passphrase.txt The byte string returned by this function is the contents of the passphrase.txt file. """ return """password""" def get_csr_pem(): """Returns a Certificate Signing Request (CSR) in PEM format This key was created by issuing the following openssl commands: openssl genrsa -out private.pem 2048 openssl req -new -key private.pem -out csr.pem -subj '/CN=example.com' The byte string returned by this function is the contents of the csr.pem file. """ return """-----BEGIN CERTIFICATE REQUEST----- MIICWzCCAUMCAQAwFjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQCza2VoDXmBUMmwjFu9F6MM5q/AZ1WjnWA2YNdN y237TrGN/nobDDv8FBBpUPmHNZ04H1LyxFcP8ReFrcIXpifsReu2lAWaqRPxovu5 CuAhfecKv+RhjLVLJ0I+MZIb72ROKpfZTmb7dhlFgGD3vkC51BCfhGVW35w52OY/ 23x5MeO4yvx5myPccnxMVQ42KuDrzKqjBlSjmBncpGYx0JgCT+syFmHsl8rOkqCP PFLo24YQn+4/pr1AYwaZAbMTl9zoLtEQj6sxScuHcS9e8niptDxlsbLQgqGVaGdE 117stC95QH7UvITbuYzdjZwBFc1Sgz8GZ/2hLSsHujJiIQcvAgMBAAGgADANBgkq hkiG9w0BAQsFAAOCAQEAPJDIxzgtUDRgpfTbTOPDJYap+Lm4jYxsCuAFbYiQ43B+ c7RyzEFOB2anrldTm3XzNytHZAkRTnN4dH09p1K1Pyepv+weSv8rvN9OohfYgpcj wQqw8ksdGb3Q6oPnTgGxmWvV4PbzHmDnOvOiQ+wuBHWXYks6tdgU7iCZ1djYibmL 1j+XEvtstou8gu1lWhzH6tStwmA9udncg5rEvfDUDyvMN3T06QFqrlK9K1TXIlbM RvUDrBjINIOuEeZ/5czjBl1CX1Z1YqdunrPiCQM4+oUAtjyD6ZAsyAEXLKdSYtKZ hSZgIl7v+UAIM+9bhpVg15aTjRzfH2OsZodFIbsMDw== -----END CERTIFICATE REQUEST-----""" def get_certificate_pem(): """Returns an X509 certificate in PEM format This certificate was created by issuing the following openssl commands: openssl genrsa -out private.pem 2048 openssl req -new -x509 -key private.pem -out cert.pem \ -days 1000 -subj '/CN=example.com' The byte string returned by this function is the contents of the cert.pem file. """ return """-----BEGIN CERTIFICATE----- MIIC/zCCAeegAwIBAgIJAOLqXKJ9q9/nMA0GCSqGSIb3DQEBCwUAMBYxFDASBgNV BAMMC2V4YW1wbGUuY29tMB4XDTE1MDQxMTAyMTUyOVoXDTE4MDEwNTAyMTUyOVow FjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQCza2VoDXmBUMmwjFu9F6MM5q/AZ1WjnWA2YNdNy237TrGN/nobDDv8 FBBpUPmHNZ04H1LyxFcP8ReFrcIXpifsReu2lAWaqRPxovu5CuAhfecKv+RhjLVL J0I+MZIb72ROKpfZTmb7dhlFgGD3vkC51BCfhGVW35w52OY/23x5MeO4yvx5myPc cnxMVQ42KuDrzKqjBlSjmBncpGYx0JgCT+syFmHsl8rOkqCPPFLo24YQn+4/pr1A YwaZAbMTl9zoLtEQj6sxScuHcS9e8niptDxlsbLQgqGVaGdE117stC95QH7UvITb uYzdjZwBFc1Sgz8GZ/2hLSsHujJiIQcvAgMBAAGjUDBOMB0GA1UdDgQWBBSUq2A0 b2Xo+sKvmKgN8Wq8l6j82jAfBgNVHSMEGDAWgBSUq2A0b2Xo+sKvmKgN8Wq8l6j8 2jAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBjiuqhlzNVOVLrHDQy Gr0fTACFJdDREnuhZp4d91++DmMCT+bcTG0+GCp3rfFOuEWpJLLLPdSOnIsnibsO syKPXuBBX5kmdYIojbdjUTSwnhcx9JTAfKSmxXWSC0rnKCefAf44Mm6fqvoTyTbe GSQP6nHzc7eLaK/efcrMvYdct+TeTkHjqR8Lu4pjZvRdUQadQHhDyN+ONKdKD9Tr jvfPim0b7Aq885PjSN6Qo4Z9HXR6+nK+bTz9HyUATMfDGNQt0L3vyfVxbNOxkCBc YI4hFtGfkOzd6B7r2sY1wGKdTLHkuT4m4/9A/SOzvnH+epnJqIS9jw+1iRj8xcDA 6PNT -----END CERTIFICATE----- """ def get_certificate_der(): """Returns an X509 certificate in DER format This certificate was created by issuing the following openssl commands: openssl genrsa -out private.pem 2048 openssl req -new -x509 -key private.pem -out cert.pem \ -days 1000 -subj '/CN=example.com' openssl x509 -outform der -in cert.pem -out cert.der The byte string returned by this function is the contents of the cert.der file. """ cert_der = ( '\x30\x82\x02\xff\x30\x82\x01\xe7\xa0\x03\x02\x01\x02\x02\x09' '\x00\xe2\xea\x5c\xa2\x7d\xab\xdf\xe7\x30\x0d\x06\x09\x2a\x86' '\x48\x86\xf7\x0d\x01\x01\x0b\x05\x00\x30\x16\x31\x14\x30\x12' '\x06\x03\x55\x04\x03\x0c\x0b\x65\x78\x61\x6d\x70\x6c\x65\x2e' '\x63\x6f\x6d\x30\x1e\x17\x0d\x31\x35\x30\x34\x31\x31\x30\x32' '\x31\x35\x32\x39\x5a\x17\x0d\x31\x38\x30\x31\x30\x35\x30\x32' '\x31\x35\x32\x39\x5a\x30\x16\x31\x14\x30\x12\x06\x03\x55\x04' '\x03\x0c\x0b\x65\x78\x61\x6d\x70\x6c\x65\x2e\x63\x6f\x6d\x30' '\x82\x01\x22\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01' '\x01\x05\x00\x03\x82\x01\x0f\x00\x30\x82\x01\x0a\x02\x82\x01' '\x01\x00\xb3\x6b\x65\x68\x0d\x79\x81\x50\xc9\xb0\x8c\x5b\xbd' '\x17\xa3\x0c\xe6\xaf\xc0\x67\x55\xa3\x9d\x60\x36\x60\xd7\x4d' '\xcb\x6d\xfb\x4e\xb1\x8d\xfe\x7a\x1b\x0c\x3b\xfc\x14\x10\x69' '\x50\xf9\x87\x35\x9d\x38\x1f\x52\xf2\xc4\x57\x0f\xf1\x17\x85' '\xad\xc2\x17\xa6\x27\xec\x45\xeb\xb6\x94\x05\x9a\xa9\x13\xf1' '\xa2\xfb\xb9\x0a\xe0\x21\x7d\xe7\x0a\xbf\xe4\x61\x8c\xb5\x4b' '\x27\x42\x3e\x31\x92\x1b\xef\x64\x4e\x2a\x97\xd9\x4e\x66\xfb' '\x76\x19\x45\x80\x60\xf7\xbe\x40\xb9\xd4\x10\x9f\x84\x65\x56' '\xdf\x9c\x39\xd8\xe6\x3f\xdb\x7c\x79\x31\xe3\xb8\xca\xfc\x79' '\x9b\x23\xdc\x72\x7c\x4c\x55\x0e\x36\x2a\xe0\xeb\xcc\xaa\xa3' '\x06\x54\xa3\x98\x19\xdc\xa4\x66\x31\xd0\x98\x02\x4f\xeb\x32' '\x16\x61\xec\x97\xca\xce\x92\xa0\x8f\x3c\x52\xe8\xdb\x86\x10' '\x9f\xee\x3f\xa6\xbd\x40\x63\x06\x99\x01\xb3\x13\x97\xdc\xe8' '\x2e\xd1\x10\x8f\xab\x31\x49\xcb\x87\x71\x2f\x5e\xf2\x78\xa9' '\xb4\x3c\x65\xb1\xb2\xd0\x82\xa1\x95\x68\x67\x44\xd7\x5e\xec' '\xb4\x2f\x79\x40\x7e\xd4\xbc\x84\xdb\xb9\x8c\xdd\x8d\x9c\x01' '\x15\xcd\x52\x83\x3f\x06\x67\xfd\xa1\x2d\x2b\x07\xba\x32\x62' '\x21\x07\x2f\x02\x03\x01\x00\x01\xa3\x50\x30\x4e\x30\x1d\x06' '\x03\x55\x1d\x0e\x04\x16\x04\x14\x94\xab\x60\x34\x6f\x65\xe8' '\xfa\xc2\xaf\x98\xa8\x0d\xf1\x6a\xbc\x97\xa8\xfc\xda\x30\x1f' '\x06\x03\x55\x1d\x23\x04\x18\x30\x16\x80\x14\x94\xab\x60\x34' '\x6f\x65\xe8\xfa\xc2\xaf\x98\xa8\x0d\xf1\x6a\xbc\x97\xa8\xfc' '\xda\x30\x0c\x06\x03\x55\x1d\x13\x04\x05\x30\x03\x01\x01\xff' '\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x0b\x05\x00' '\x03\x82\x01\x01\x00\x63\x8a\xea\xa1\x97\x33\x55\x39\x52\xeb' '\x1c\x34\x32\x1a\xbd\x1f\x4c\x00\x85\x25\xd0\xd1\x12\x7b\xa1' '\x66\x9e\x1d\xf7\x5f\xbe\x0e\x63\x02\x4f\xe6\xdc\x4c\x6d\x3e' '\x18\x2a\x77\xad\xf1\x4e\xb8\x45\xa9\x24\xb2\xcb\x3d\xd4\x8e' '\x9c\x8b\x27\x89\xbb\x0e\xb3\x22\x8f\x5e\xe0\x41\x5f\x99\x26' '\x75\x82\x28\x8d\xb7\x63\x51\x34\xb0\x9e\x17\x31\xf4\x94\xc0' '\x7c\xa4\xa6\xc5\x75\x92\x0b\x4a\xe7\x28\x27\x9f\x01\xfe\x38' '\x32\x6e\x9f\xaa\xfa\x13\xc9\x36\xde\x19\x24\x0f\xea\x71\xf3' '\x73\xb7\x8b\x68\xaf\xde\x7d\xca\xcc\xbd\x87\x5c\xb7\xe4\xde' '\x4e\x41\xe3\xa9\x1f\x0b\xbb\x8a\x63\x66\xf4\x5d\x51\x06\x9d' '\x40\x78\x43\xc8\xdf\x8e\x34\xa7\x4a\x0f\xd4\xeb\x8e\xf7\xcf' '\x8a\x6d\x1b\xec\x0a\xbc\xf3\x93\xe3\x48\xde\x90\xa3\x86\x7d' '\x1d\x74\x7a\xfa\x72\xbe\x6d\x3c\xfd\x1f\x25\x00\x4c\xc7\xc3' '\x18\xd4\x2d\xd0\xbd\xef\xc9\xf5\x71\x6c\xd3\xb1\x90\x20\x5c' '\x60\x8e\x21\x16\xd1\x9f\x90\xec\xdd\xe8\x1e\xeb\xda\xc6\x35' '\xc0\x62\x9d\x4c\xb1\xe4\xb9\x3e\x26\xe3\xff\x40\xfd\x23\xb3' '\xbe\x71\xfe\x7a\x99\xc9\xa8\x84\xbd\x8f\x0f\xb5\x89\x18\xfc' '\xc5\xc0\xc0\xe8\xf3\x53') return cert_der python-barbicanclient-4.10.0/functionaltests/common/__init__.py0000664000175000017500000000000013620530200024700 0ustar zuulzuul00000000000000python-barbicanclient-4.10.0/functionaltests/common/cleanup.py0000664000175000017500000000626613620530200024614 0ustar zuulzuul00000000000000""" Copyright 2015 IBM 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. """ class CleanUp(object): def __init__(self, barbicanclient): self.created_entities = { 'secret': [], 'container': [], 'acl': [], 'order': [] } self.barbicanclient = barbicanclient def delete_all_entities(self): """Helper method to delete all entities used for testing""" self._delete_all_acls() self._delete_all_containers() self._delete_all_orders() self._delete_all_secrets() def add_entity(self, entity): """Stores an entity in Barbican used for testing and keeps track of entity for removal after tests are running """ entity_type = str(type(entity)).lower() if 'acl' in entity_type: entity_ref = entity.submit() entity_type = 'acl' elif 'secret' in entity_type: entity_ref = entity.store() entity_type = 'secret' elif 'container' in entity_type: entity_ref = entity.store() entity_type = 'container' else: entity_ref = entity.submit() entity_type = 'order' self.created_entities[entity_type].append(entity_ref) return entity_ref def _delete_all_containers(self): """Helper method to delete all containers used for testing""" for container_ref in self.created_entities['container']: self.barbicanclient.containers.delete(container_ref) def _delete_all_secrets(self): """Helper method to delete all secrets used for testing""" for secret_ref in self.created_entities['secret']: self.barbicanclient.secrets.delete(secret_ref) def _delete_all_acls(self): """Helper method to delete all acls used for testing""" for acl_ref in self.created_entities['acl']: entity_ref = acl_ref.replace("/acl", "") blank_acl_entity = self.barbicanclient.acls.create( entity_ref=entity_ref) blank_acl_entity.remove() def _delete_all_orders(self): """Helper method to delete all orders and secrets used for testing""" for order_ref in self.created_entities['order']: order = self.barbicanclient.orders.get(order_ref) if order.secret_ref: self.barbicanclient.secrets.delete(order.secret_ref) # see if containers are supported container_attr_exists = getattr(order, "container_ref", None) if container_attr_exists and order.container_ref: self.barbicanclient.containers.delete(order.container_ref) self.barbicanclient.orders.delete(order_ref) python-barbicanclient-4.10.0/clientrc0000664000175000017500000000126413620530200017615 0ustar zuulzuul00000000000000export OS_PROJECT_NAME= # Either Project Domain ID or Project Domain Name is required export OS_PROJECT_DOMAIN_ID= export OS_PROJECT_DOMAIN_NAME= # Either User Domain ID or User Domain Name is required export OS_USER_DOMAIN_ID= export OS_USER_DOMAIN_NAME= # Either User ID or Username can be used export OS_USER_ID = export OS_USERNAME= export OS_PASSWORD= # OS_AUTH_URL should be your location of Keystone # Barbican Client defaults to Keystone V3 export OS_AUTH_URL=":5000/v3/" export BARBICAN_ENDPOINT=":9311" python-barbicanclient-4.10.0/AUTHORS0000664000175000017500000001007113620530306017142 0ustar zuulzuul0000000000000098k <18552437190@163.com> Adam Harwell Ade Lee Alex Gaynor Alexandra Settle Anderson Mesquita Andreas Jaeger Anh Tran Anusree Arash Ghoreyshi Arun Kant Arun Kant Chellygel Chen Chris Solis Christian Berendt Christopher Solis Clenimar Filemon Colleen Murphy Corey Bryant Craig Tracey Cyril Roelandt Dave McCowan Deepak Dirk Mueller Donald Stufft Doug Hellmann Douglas Mendizábal Douglas Mendizábal Elvin Tubillara Fernando Diaz Gage Hugo Gregory Haynes Gábor Antal Ian Wienand Jamie Lennox Jamie Lennox Jarret Raim Jeremy Liu Jeremy Stanley Jiong Liu Joe Gordon John Vrbanac John Wood Juan Antonio Osorio Juan Antonio Osorio Robles Juan Antonio Osorio Robles KATO Tomoyuki Kaitlin Farr Kiran_totad Laurent Luce LiuNanke Luong Anh Tuan M V P Nitesh Martin Geisler Max Abidi Michael Perng Monty Taylor Nathan Reller Nguyen Hai Oleksii Chuprykov Ondřej Nový Paul Kehrer Petr Kovar Richard Lee Robert Collins Rui Chen ShangXiao Shuquan Huang Stephen Finucane Steve Heyman Steven Gonzales Swapnil Kulkarni (coolsvap) Thiago da Silva Thomas Dinkjian Thomas Herve Thomas Herve Tin Lam Tony Breeds Tony Xu Van Hung Pham Vieri <15050873171@163.com> Vu Cong Tuan Wyllys Ingersoll Yushiro FURUKAWA ZhiQiang Fan ZhijunWei cao.yuan chadlung chenlx chenxing hongzhezheng huang.zhiping huangshan ji-xuepeng jonnary lingyongxu liujiong melissaml pengyuesheng qingszhao rajat29 reedip rico.lin ricolin sonu.kumar ting.wang tsv venkatamahesh weiweigu yushangbin “Fernando python-barbicanclient-4.10.0/.coveragerc0000664000175000017500000000011413620530200020201 0ustar zuulzuul00000000000000[run] branch = True omit = barbicanclient/openstack/*,barbicanclient/tests/*python-barbicanclient-4.10.0/barbicanclient/0000775000175000017500000000000013620530306021033 5ustar zuulzuul00000000000000python-barbicanclient-4.10.0/barbicanclient/__init__.py0000664000175000017500000000375513620530200023147 0ustar zuulzuul00000000000000# Copyright 2017 Huawei, Inc. All rights reserved. # # 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. # """Barbican Client Library Binding""" import importlib import sys import warnings import pbr.version from barbicanclient.v1 import acls from barbicanclient.v1 import cas from barbicanclient.v1 import containers from barbicanclient.v1 import orders from barbicanclient.v1 import secrets version_info = pbr.version.VersionInfo("python-barbicanclient") __version__ = version_info.version_string() __all__ = ( 'acls', 'cas', 'containers', 'orders', 'secrets', ) class _LazyImporter(object): def __init__(self, module): self._module = module def __getattr__(self, name): # This is only called until the import has been done. lazy_submodules = [ 'acls', 'cas', 'containers', 'orders', 'secrets', ] if name in lazy_submodules: warnings.warn("The %s module is moved to barbicanclient/v1 " "directory, direct import of barbicanclient.%s " "will be deprecated. Please import " "barbicanclient.v1.%s instead." % (name, name, name)) return importlib.import_module('barbicanclient.v1.%s' % name) # Return module attributes like __all__ etc. return getattr(self._module, name) sys.modules[__name__] = _LazyImporter(sys.modules[__name__]) python-barbicanclient-4.10.0/barbicanclient/_i18n.py0000664000175000017500000000217213620530200022316 0ustar zuulzuul00000000000000# 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. """oslo.i18n integration module. See https://docs.openstack.org/oslo.i18n/latest/user/usage.html . """ import oslo_i18n as i18n _translators = i18n.TranslatorFactory(domain='python-barbicanclient') # The primary translation function using the well-known name "_" _ = _translators.primary # Translators for log levels. # # The abbreviated names are meant to reflect the usual use of a short # name like '_'. The "L" is for "log" and the other letter comes from # the level. _LI = _translators.log_info _LW = _translators.log_warning _LE = _translators.log_error _LC = _translators.log_critical python-barbicanclient-4.10.0/barbicanclient/base.py0000664000175000017500000000456213620530200022317 0ustar zuulzuul00000000000000# Copyright (c) 2013 Rackspace, Inc. # # 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. """ Base utilities to build API operation managers. """ import logging import uuid LOG = logging.getLogger(__name__) def filter_null_keys(dictionary): return dict(((k, v) for k, v in dictionary.items() if v is not None)) def censored_copy(data_dict, censor_keys): '''Returns redacted dict copy for censored keys''' if censor_keys is None: censor_keys = [] return {k: v if k not in censor_keys else '' for k, v in data_dict.items()} def validate_ref_and_return_uuid(ref, entity): """Verifies that there is a real uuid (possibly at the end of a uri) :return: The uuid.UUID object :raises ValueError: If it cannot correctly parse the uuid in the ref. """ try: # This works for a ref *or* a UUID, since we just pick the last piece ref_pieces = ref.rstrip('/').rsplit('/', 1) return uuid.UUID(ref_pieces[-1]) except Exception: raise ValueError('{0} incorrectly specified.'.format(entity)) def calculate_uuid_ref(ref, entity): entity_uuid = validate_ref_and_return_uuid( ref, entity.capitalize().rstrip('s')) entity_ref = "{entity}/{uuid}".format(entity=entity, uuid=entity_uuid) LOG.info("Calculated %s uuid ref: %s", entity.capitalize(), entity_ref) return entity_ref class ImmutableException(Exception): def __init__(self, attribute=None): message = "This object is immutable!" super(ImmutableException, self).__init__(message) class BaseEntityManager(object): def __init__(self, api, entity): self._api = api self._entity = entity def total(self): """Returns the total number of entities stored in Barbican.""" params = {'limit': 0, 'offset': 0} resp = self._api.get(self._entity, params=params) return resp['total'] python-barbicanclient-4.10.0/barbicanclient/barbican.py0000664000175000017500000004035113620530200023142 0ustar zuulzuul00000000000000# Copyright (c) 2013 Rackspace, Inc. # # 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 to the Barbican API. """ from collections import namedtuple import logging import sys from cliff import app from cliff import command from cliff import commandmanager from cliff import complete from cliff import help from keystoneauth1 import identity from keystoneauth1 import loading from keystoneauth1 import session import barbicanclient from barbicanclient._i18n import _LW from barbicanclient import client LOG = logging.getLogger(__name__) _DEFAULT_IDENTITY_API_VERSION = '3' _IDENTITY_API_VERSION_2 = ['2', '2.0'] _IDENTITY_API_VERSION_3 = ['3'] class Barbican(app.App): """Barbican command line interface.""" # verbose logging levels WARNING_LEVEL = 0 INFO_LEVEL = 1 DEBUG_LEVEL = 2 CONSOLE_MESSAGE_FORMAT = '%(message)s' DEBUG_MESSAGE_FORMAT = '%(levelname)s: %(name)s %(message)s' def __init__(self, **kwargs): self.client = None # Patch command.Command to add a default auth_required = True command.Command.auth_required = True # Some commands do not need authentication help.HelpCommand.auth_required = False complete.CompleteCommand.auth_required = False super(Barbican, self).__init__( description=__doc__.strip(), version=barbicanclient.__version__, command_manager=commandmanager.CommandManager( 'openstack.key_manager.v1'), deferred_help=True, **kwargs ) def check_auth_arguments(self, args, api_version=None, raise_exc=False): """Verifies that we have the correct arguments for authentication Supported Keystone v3 combinations: - Project Id - Project Name + Project Domain Name - Project Name + Project Domain Id Supported Keystone v2 combinations: - Tenant Id - Tenant Name """ successful = True v3_arg_combinations = [ args.os_project_id, args.os_project_name and args.os_project_domain_name, args.os_project_name and args.os_project_domain_id ] v2_arg_combinations = [args.os_tenant_id, args.os_tenant_name] # Keystone V3 if not api_version or api_version == _DEFAULT_IDENTITY_API_VERSION: if not any(v3_arg_combinations): msg = ('ERROR: please specify the following --os-project-id or' ' (--os-project-name and --os-project-domain-name) or ' ' (--os-project-name and --os-project-domain-id)') successful = False # Keystone V2 else: if not any(v2_arg_combinations): msg = ('ERROR: please specify --os-tenant-id or' ' --os-tenant-name') successful = False if not successful and raise_exc: raise Exception(msg) return successful def build_kwargs_based_on_version(self, args, api_version=None): if not api_version or api_version == _DEFAULT_IDENTITY_API_VERSION: kwargs = { 'project_id': args.os_project_id, 'project_name': args.os_project_name, 'user_domain_id': args.os_user_domain_id, 'user_domain_name': args.os_user_domain_name, 'project_domain_id': args.os_project_domain_id, 'project_domain_name': args.os_project_domain_name } else: kwargs = { 'tenant_name': args.os_tenant_name, 'tenant_id': args.os_tenant_id } # Return a dictionary with only the populated (not None) values return dict((k, v) for (k, v) in kwargs.items() if v) def create_keystone_session( self, args, api_version, kwargs_dict, auth_type ): # Make sure we have the correct arguments to function self.check_auth_arguments(args, api_version, raise_exc=True) kwargs = self.build_kwargs_based_on_version(args, api_version) kwargs.update(kwargs_dict) _supported_version = _IDENTITY_API_VERSION_2 + _IDENTITY_API_VERSION_3 if not api_version or api_version not in _supported_version: self.stderr.write( "WARNING: The identity version <{0}> is not in supported " "versions <{1}>, falling back to <{2}>.".format( api_version, _IDENTITY_API_VERSION_2 + _IDENTITY_API_VERSION_3, _DEFAULT_IDENTITY_API_VERSION ) ) method = identity.Token if auth_type == 'token' else identity.Password auth = method(**kwargs) cacert = args.os_cacert cert = args.os_cert key = args.os_key insecure = args.insecure if insecure: verify = False else: verify = cacert or True if cert and key: cert = (cert, key) return session.Session(auth=auth, verify=verify, cert=cert) def create_client(self, args): created_client = None endpoint_filter_kwargs = self._get_endpoint_filter_kwargs(args) api_version = args.os_identity_api_version if args.no_auth and args.os_auth_url: raise Exception( 'ERROR: argument --os-auth-url/-A: not allowed ' 'with argument --no-auth/-N' ) if args.no_auth: if not all([args.endpoint, args.os_tenant_id or args.os_project_id]): raise Exception( 'ERROR: please specify --endpoint and ' '--os-project-id (or --os-tenant-id)') created_client = client.Client( endpoint=args.endpoint, project_id=args.os_tenant_id or args.os_project_id, verify=not args.insecure, **endpoint_filter_kwargs ) # Token-based authentication elif args.os_auth_token: if not args.os_auth_url: raise Exception('ERROR: please specify --os-auth-url') token_kwargs = { 'auth_url': args.os_auth_url, 'token': args.os_auth_token } session = self.create_keystone_session( args, api_version, token_kwargs, auth_type='token' ) created_client = client.Client( session=session, endpoint=args.endpoint, **endpoint_filter_kwargs ) # Password-based authentication elif args.os_auth_url: password_kwargs = { 'auth_url': args.os_auth_url, 'password': args.os_password, 'user_id': args.os_user_id, 'username': args.os_username } session = self.create_keystone_session( args, api_version, password_kwargs, auth_type='password' ) created_client = client.Client( session=session, endpoint=args.endpoint, **endpoint_filter_kwargs ) else: raise Exception('ERROR: please specify authentication credentials') return created_client def _get_endpoint_filter_kwargs(self, args): endpoint_filter_keys = ('interface', 'service_type', 'service_name', 'barbican_api_version', 'region_name') kwargs = dict((key, getattr(args, key)) for key in endpoint_filter_keys if getattr(args, key, None)) if 'barbican_api_version' in kwargs: kwargs['version'] = kwargs.pop('barbican_api_version') return kwargs def build_option_parser(self, description, version, argparse_kwargs=None): """Introduces global arguments for the application. This is inherited from the framework. """ parser = super(Barbican, self).build_option_parser( description, version, argparse_kwargs) parser.add_argument('--no-auth', '-N', action='store_true', help='Do not use authentication.') parser.add_argument('--os-identity-api-version', metavar='', default=client.env('OS_IDENTITY_API_VERSION'), help='Specify Identity API version to use. ' 'Defaults to env[OS_IDENTITY_API_VERSION]' ' or 3.') parser.add_argument('--os-auth-url', '-A', metavar='', default=client.env('OS_AUTH_URL'), help='Defaults to env[OS_AUTH_URL].') parser.add_argument('--os-username', '-U', metavar='', default=client.env('OS_USERNAME'), help='Defaults to env[OS_USERNAME].') parser.add_argument('--os-user-id', metavar='', default=client.env('OS_USER_ID'), help='Defaults to env[OS_USER_ID].') parser.add_argument('--os-password', '-P', metavar='', default=client.env('OS_PASSWORD'), help='Defaults to env[OS_PASSWORD].') parser.add_argument('--os-user-domain-id', metavar='', default=client.env('OS_USER_DOMAIN_ID'), help='Defaults to env[OS_USER_DOMAIN_ID].') parser.add_argument('--os-user-domain-name', metavar='', default=client.env('OS_USER_DOMAIN_NAME'), help='Defaults to env[OS_USER_DOMAIN_NAME].') parser.add_argument('--os-tenant-name', '-T', metavar='', default=client.env('OS_TENANT_NAME'), help='Defaults to env[OS_TENANT_NAME].') parser.add_argument('--os-tenant-id', '-I', metavar='', default=client.env('OS_TENANT_ID'), help='Defaults to env[OS_TENANT_ID].') parser.add_argument('--os-project-id', metavar='', default=client.env('OS_PROJECT_ID'), help='Another way to specify tenant ID. ' 'This option is mutually exclusive with ' ' --os-tenant-id. ' 'Defaults to env[OS_PROJECT_ID].') parser.add_argument('--os-project-name', metavar='', default=client.env('OS_PROJECT_NAME'), help='Another way to specify tenant name. ' 'This option is mutually exclusive with ' ' --os-tenant-name. ' 'Defaults to env[OS_PROJECT_NAME].') parser.add_argument('--os-project-domain-id', metavar='', default=client.env('OS_PROJECT_DOMAIN_ID'), help='Defaults to env[OS_PROJECT_DOMAIN_ID].') parser.add_argument('--os-project-domain-name', metavar='', default=client.env('OS_PROJECT_DOMAIN_NAME'), help='Defaults to env[OS_PROJECT_DOMAIN_NAME].') parser.add_argument('--os-auth-token', metavar='', default=client.env('OS_AUTH_TOKEN'), help='Defaults to env[OS_AUTH_TOKEN].') parser.add_argument('--endpoint', '-E', metavar='', default=client.env('BARBICAN_ENDPOINT'), help='Defaults to env[BARBICAN_ENDPOINT].') parser.add_argument('--interface', metavar='', default=client.env('BARBICAN_INTERFACE'), help='Defaults to env[BARBICAN_INTERFACE].') parser.add_argument('--service-type', metavar='', default=client.env('BARBICAN_SERVICE_TYPE'), help='Defaults to env[BARBICAN_SERVICE_TYPE].') parser.add_argument('--service-name', metavar='', default=client.env('BARBICAN_SERVICE_NAME'), help='Defaults to env[BARBICAN_SERVICE_NAME].') parser.add_argument('--region-name', metavar='', default=client.env('BARBICAN_REGION_NAME'), help='Defaults to env[BARBICAN_REGION_NAME].') parser.add_argument('--barbican-api-version', metavar='', default=client.env('BARBICAN_API_VERSION'), help='Defaults to env[BARBICAN_API_VERSION].') parser.epilog = ('See "barbican help COMMAND" for help ' 'on a specific command.') loading.register_session_argparse_arguments(parser) return parser def prepare_to_run_command(self, cmd): """Prepares to run the command Checks if the minimal parameters are provided and creates the client interface. This is inherited from the framework. """ self.client_manager = namedtuple('ClientManager', 'key_manager') if cmd.auth_required: # NOTE(liujiong): cliff sets log level to DEBUG in run function, # need to overwrite this configuration to depress DEBUG messages. self.configure_logging() self.client_manager.key_manager = self.create_client(self.options) def run(self, argv): # If no arguments are provided, usage is displayed if not argv: self.stderr.write(self.parser.format_usage()) return 1 return super(Barbican, self).run(argv) def configure_logging(self): """Create logging handlers for any log output.""" root_logger = logging.getLogger('') # Set log level to INFO root_logger.setLevel(logging.INFO) # Send higher-level messages to the console via stderr console = logging.StreamHandler(self.stderr) console_level = {self.WARNING_LEVEL: logging.WARNING, self.INFO_LEVEL: logging.INFO, self.DEBUG_LEVEL: logging.DEBUG, }.get(self.options.verbose_level, logging.INFO) if logging.DEBUG == console_level: formatter = logging.Formatter(self.DEBUG_MESSAGE_FORMAT) else: formatter = logging.Formatter(self.CONSOLE_MESSAGE_FORMAT) console.setFormatter(formatter) root_logger.addHandler(console) return def main(argv=sys.argv[1:]): logging.basicConfig() LOG.warning(_LW("This Barbican CLI interface has been deprecated and " "will be removed in the O release. Please use the " "openstack unified client instead.")) barbican_app = Barbican() return barbican_app.run(argv) if __name__ == '__main__': # pragma: no cover sys.exit(main(sys.argv[1:])) python-barbicanclient-4.10.0/barbicanclient/version.py0000664000175000017500000000163213620530200023065 0ustar zuulzuul00000000000000# Copyright 2010-2011 OpenStack LLC. # All Rights Reserved. # # 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. """ Cloudkeep's Barbican Client version """ import barbicanclient # NOTE(RuiChen): According to PEP 396, barbicanclient.version.__version__ # should be deprecated, please use barbicanclient.__version__ # instead. __version__ = barbicanclient.__version__ python-barbicanclient-4.10.0/barbicanclient/client.py0000664000175000017500000002074013620530200022657 0ustar zuulzuul00000000000000# Copyright (c) 2013 Rackspace, Inc. # # 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. import importlib import logging import os import sys import warnings from keystoneauth1 import adapter from keystoneauth1 import session as ks_session from oslo_utils import importutils from barbicanclient import exceptions LOG = logging.getLogger(__name__) _DEFAULT_SERVICE_TYPE = 'key-manager' _DEFAULT_SERVICE_INTERFACE = 'public' _DEFAULT_API_VERSION = 'v1' _SUPPORTED_API_VERSION_MAP = {'v1': 'barbicanclient.v1.client.Client'} class _HTTPClient(adapter.Adapter): def __init__(self, session, project_id=None, **kwargs): kwargs.setdefault('interface', _DEFAULT_SERVICE_INTERFACE) kwargs.setdefault('service_type', _DEFAULT_SERVICE_TYPE) kwargs.setdefault('version', _DEFAULT_API_VERSION) endpoint = kwargs.pop('endpoint', None) super(_HTTPClient, self).__init__(session, **kwargs) if endpoint: self.endpoint_override = '{0}/{1}'.format(endpoint, self.version) if project_id is None: self._default_headers = dict() else: # If provided we'll include the project ID in all requests. self._default_headers = {'X-Project-Id': project_id} def request(self, *args, **kwargs): headers = kwargs.setdefault('headers', {}) headers.update(self._default_headers) # Set raise_exc=False by default so that we handle request exceptions kwargs.setdefault('raise_exc', False) resp = super(_HTTPClient, self).request(*args, **kwargs) self._check_status_code(resp) return resp def get(self, *args, **kwargs): headers = kwargs.setdefault('headers', {}) headers.setdefault('Accept', 'application/json') return super(_HTTPClient, self).get(*args, **kwargs).json() def post(self, path, *args, **kwargs): path = self._fix_path(path) return super(_HTTPClient, self).post(path, *args, **kwargs).json() def _fix_path(self, path): if not path[-1] == '/': path += '/' return path def _get_raw(self, path, *args, **kwargs): return self.request(path, 'GET', *args, **kwargs).content def _check_status_code(self, resp): status = resp.status_code LOG.debug('Response status {0}'.format(status)) if status == 401: LOG.error('Auth error: {0}'.format(self._get_error_message(resp))) raise exceptions.HTTPAuthError( '{0}'.format(self._get_error_message(resp)) ) if not status or status >= 500: LOG.error('5xx Server error: {0}'.format( self._get_error_message(resp) )) raise exceptions.HTTPServerError( '{0}'.format(self._get_error_message(resp)), status ) if status >= 400: LOG.error('4xx Client error: {0}'.format( self._get_error_message(resp) )) raise exceptions.HTTPClientError( '{0}'.format(self._get_error_message(resp)), status ) def _get_error_message(self, resp): try: response_data = resp.json() message = response_data['title'] description = response_data.get('description') if description: message = '{0}: {1}'.format(message, description) except ValueError: message = resp.content return message def Client(version=None, session=None, *args, **kwargs): """Barbican client used to interact with barbican service. :param version: The API version to use. :param session: An instance of keystoneauth1.session.Session that can be either authenticated, or not authenticated. When using a non-authenticated Session, you must provide some additional parameters. When no session is provided it will default to a non-authenticated Session. :param endpoint: Barbican endpoint url. Required when a session is not given, or when using a non-authenticated session. When using an authenticated session, the client will attempt to get an endpoint from the session. :param project_id: The project ID used for context in Barbican. Required when a session is not given, or when using a non-authenticated session. When using an authenticated session, the project ID will be provided by the authentication mechanism. :param verify: When a session is not given, the client will create a non-authenticated session. This parameter is passed to the session that is created. If set to False, it allows barbicanclient to perform "insecure" TLS (https) requests. The server's certificate will not be verified against any certificate authorities. WARNING: This option should be used with caution. :param service_type: Used as an endpoint filter when using an authenticated keystone session. Defaults to 'key-manager'. :param service_name: Used as an endpoint filter when using an authenticated keystone session. :param interface: Used as an endpoint filter when using an authenticated keystone session. Defaults to 'public'. :param region_name: Used as an endpoint filter when using an authenticated keystone session. """ LOG.debug("Creating Client object") if not session: session = ks_session.Session(verify=kwargs.pop('verify', True)) if session.auth is None and kwargs.get('auth') is None: if not kwargs.get('endpoint'): raise ValueError('Barbican endpoint url must be provided when ' 'not using auth in the Keystone Session.') if kwargs.get('project_id') is None: raise ValueError('Project ID must be provided when not using ' 'auth in the Keystone Session') if not version: version = _DEFAULT_API_VERSION try: client_path = _SUPPORTED_API_VERSION_MAP[version] client_class = importutils.import_class(client_path) return client_class(session=session, *args, **kwargs) except (KeyError, ValueError): supported_versions = ', '.join(_SUPPORTED_API_VERSION_MAP.keys()) msg = ("Invalid client version %(version)s; must be one of: " "%(versions)s") % {'version': version, 'versions': supported_versions} raise exceptions.UnsupportedVersion(msg) def env(*vars, **kwargs): """Search for the first defined of possibly many env vars Returns the first environment variable defined in vars, or returns the default defined in kwargs. Source: Keystone's shell.py """ for v in vars: value = os.environ.get(v, None) if value: return value return kwargs.get('default', '') class _LazyImporter(object): def __init__(self, module): self._module = module def __getattr__(self, name): # This is only called until the import has been done. lazy_submodules = [ 'acls', 'cas', 'containers', 'orders', 'secrets', ] if name in lazy_submodules: warnings.warn("The %s module is moved to barbicanclient/v1 " "directory, direct import of " "barbicanclient.client.%s " "will be deprecated. Please import " "barbicanclient.v1.%s instead." % (name, name, name)) return importlib.import_module('barbicanclient.v1.%s' % name) # Return module attributes like __all__ etc. return getattr(self._module, name) sys.modules[__name__] = _LazyImporter(sys.modules[__name__]) python-barbicanclient-4.10.0/barbicanclient/v1/0000775000175000017500000000000013620530306021361 5ustar zuulzuul00000000000000python-barbicanclient-4.10.0/barbicanclient/v1/__init__.py0000664000175000017500000000000013620530200023451 0ustar zuulzuul00000000000000python-barbicanclient-4.10.0/barbicanclient/v1/secrets.py0000664000175000017500000005336113620530200023404 0ustar zuulzuul00000000000000# Copyright (c) 2013 Rackspace, Inc. # # 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. import base64 import functools import logging from oslo_utils.timeutils import parse_isotime import six from barbicanclient import base from barbicanclient import exceptions from barbicanclient import formatter from barbicanclient.v1 import acls as acl_manager LOG = logging.getLogger(__name__) def lazy(func): @functools.wraps(func) def wrapper(self, *args): self._fill_lazy_properties() return func(self, *args) return wrapper def immutable_after_save(func): @functools.wraps(func) def wrapper(self, *args): if self._secret_ref: raise base.ImmutableException() return func(self, *args) return wrapper class SecretFormatter(formatter.EntityFormatter): columns = ("Secret href", "Name", "Created", "Status", "Content types", "Algorithm", "Bit length", "Secret type", "Mode", "Expiration", ) def _get_formatted_data(self): created = self.created.isoformat() if self.created else None expiration = self.expiration.isoformat() if self.expiration else None data = (self.secret_ref, self.name, created, self.status, self.content_types, self.algorithm, self.bit_length, self.secret_type, self.mode, expiration, ) return data class Secret(SecretFormatter): """Secrets managed by Barbican Secrets represent keys, credentials, and other sensitive data that is stored by the Barbican service. """ _entity = 'secrets' def __init__(self, api, name=None, expiration=None, algorithm=None, bit_length=None, mode=None, payload=None, payload_content_type=None, payload_content_encoding=None, secret_ref=None, created=None, updated=None, content_types=None, status=None, secret_type=None, creator_id=None): """Secret objects should not be instantiated directly. You should use the `create` or `get` methods of the :class:`barbicanclient.secrets.SecretManager` instead. """ self._api = api self._secret_ref = secret_ref self._fill_from_data( name=name, expiration=expiration, algorithm=algorithm, bit_length=bit_length, secret_type=secret_type, mode=mode, payload=payload, payload_content_type=payload_content_type, payload_content_encoding=payload_content_encoding, created=created, updated=updated, content_types=content_types, status=status, creator_id=creator_id ) self._acl_manager = acl_manager.ACLManager(api) self._acls = None @property def secret_ref(self): return self._secret_ref @property @lazy def name(self): return self._name @property @lazy def expiration(self): return self._expiration @property @lazy def algorithm(self): return self._algorithm @property @lazy def bit_length(self): return self._bit_length @property @lazy def secret_type(self): return self._secret_type @property @lazy def mode(self): return self._mode @property @lazy def payload_content_encoding(self): return self._payload_content_encoding @property @lazy def created(self): return self._created @property @lazy def updated(self): return self._updated @property @lazy def content_types(self): if self._content_types: return self._content_types elif self._payload_content_type: return {u'default': self.payload_content_type} return None @property @lazy def status(self): return self._status @property def payload_content_type(self): if not self._payload_content_type and self.content_types: self._payload_content_type = self.content_types.get('default') return self._payload_content_type @property def payload(self): """Lazy-loaded property that holds the unencrypted data""" if self._payload is None and self.secret_ref is not None: try: self._fetch_payload() except ValueError: LOG.warning("Secret does not contain a payload") 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): self._name = value @expiration.setter @immutable_after_save def expiration(self, value): self._expiration = value @algorithm.setter @immutable_after_save def algorithm(self, value): self._algorithm = value @bit_length.setter @immutable_after_save def bit_length(self, value): self._bit_length = value @secret_type.setter @immutable_after_save def secret_type(self, value): self._secret_type = value @mode.setter @immutable_after_save def mode(self, value): self._mode = value @payload.setter def payload(self, value): self._payload = value @payload_content_type.setter @immutable_after_save def payload_content_type(self, value): LOG.warning( 'DEPRECATION WARNING: Manually setting the ' 'payload_content_type can lead to unexpected ' 'results. It will be removed in a future release. ' 'See Launchpad Bug #1419166.') self._payload_content_type = value @payload_content_encoding.setter @immutable_after_save def payload_content_encoding(self, value): LOG.warning( 'DEPRECATION WARNING: Manually setting the ' 'payload_content_encoding can lead to unexpected ' 'results. It will be removed in a future release. ' 'See Launchpad Bug #1419166.') self._payload_content_encoding = value def _fetch_payload(self): if not self.payload_content_type and not self.content_types: raise ValueError('Secret has no encrypted data to decrypt.') elif not self.payload_content_type: raise ValueError("Must specify decrypt content-type as " "secret does not specify a 'default' " "content-type.") headers = {'Accept': self.payload_content_type} uuid_ref = base.calculate_uuid_ref(self._secret_ref, self._entity) payload_url = uuid_ref + '/payload' payload = self._api._get_raw(payload_url, headers=headers) if self.payload_content_type == u'text/plain': self._payload = payload.decode('UTF-8') else: self._payload = payload @immutable_after_save def store(self): """Stores the Secret in Barbican. New Secret objects are not persisted in Barbican until this method is called. :raises: PayloadException """ secret_dict = { 'name': self.name, 'algorithm': self.algorithm, 'mode': self.mode, 'bit_length': self.bit_length, 'secret_type': self.secret_type, 'expiration': self.expiration } if self.payload == '': raise exceptions.PayloadException("Invalid Payload: " "Cannot Be Empty String") if self.payload is not None and not isinstance(self.payload, (six.text_type, six.binary_type)): raise exceptions.PayloadException("Invalid Payload Type") if self.payload_content_type or self.payload_content_encoding: ''' Setting the payload_content_type and payload_content_encoding manually is deprecated. This clause of the if statement is here for backwards compatibility and should be removed in a future release. ''' secret_dict['payload'] = self.payload secret_dict['payload_content_type'] = self.payload_content_type secret_dict['payload_content_encoding'] = ( self.payload_content_encoding ) elif type(self.payload) is six.binary_type: ''' six.binary_type is stored as application/octet-stream and it is base64 encoded for a one-step POST ''' secret_dict['payload'] = ( base64.b64encode(self.payload) ).decode('UTF-8') secret_dict['payload_content_type'] = u'application/octet-stream' secret_dict['payload_content_encoding'] = u'base64' elif type(self.payload) is six.text_type: ''' six.text_type is stored as text/plain ''' secret_dict['payload'] = self.payload secret_dict['payload_content_type'] = u'text/plain' secret_dict = base.filter_null_keys(secret_dict) LOG.debug("Request body: {0}".format(base.censored_copy(secret_dict, ['payload']))) # Save, store secret_ref and return response = self._api.post(self._entity, json=secret_dict) if response: self._secret_ref = response.get('secret_ref') return self.secret_ref def update(self): """Updates the secret in Barbican.""" if not self.payload: raise exceptions.PayloadException("Invalid or Missing Payload") if not self.secret_ref: raise LookupError("Secret is not yet stored.") if type(self.payload) is six.binary_type: headers = {'content-type': "application/octet-stream"} elif type(self.payload) is six.text_type: headers = {'content-type': "text/plain"} else: raise exceptions.PayloadException("Invalid Payload Type") uuid_ref = base.calculate_uuid_ref(self._secret_ref, self._entity) self._api.put(uuid_ref, headers=headers, data=self.payload) def delete(self): """Deletes the Secret from Barbican""" if self._secret_ref: uuid_ref = base.calculate_uuid_ref(self._secret_ref, self._entity) self._api.delete(uuid_ref) self._secret_ref = None else: raise LookupError("Secret is not yet stored.") def _fill_from_data(self, name=None, expiration=None, algorithm=None, bit_length=None, secret_type=None, mode=None, payload=None, payload_content_type=None, payload_content_encoding=None, created=None, updated=None, content_types=None, status=None, creator_id=None): self._name = name self._algorithm = algorithm self._bit_length = bit_length self._mode = mode self._secret_type = secret_type self._payload = payload self._payload_content_encoding = payload_content_encoding self._expiration = expiration self._creator_id = creator_id if not self._secret_type: self._secret_type = "opaque" if self._expiration: self._expiration = parse_isotime(self._expiration) if self._secret_ref: self._content_types = content_types self._status = status self._created = created self._updated = updated if self._created: self._created = parse_isotime(self._created) if self._updated: self._updated = parse_isotime(self._updated) else: self._content_types = None self._status = None self._created = None self._updated = None if not self._content_types: self._payload_content_type = payload_content_type else: self._payload_content_type = self._content_types.get('default', None) def _fill_lazy_properties(self): if self._secret_ref and not self._name: uuid_ref = base.calculate_uuid_ref(self._secret_ref, self._entity) result = self._api.get(uuid_ref) self._fill_from_data( name=result.get('name'), expiration=result.get('expiration'), algorithm=result.get('algorithm'), bit_length=result.get('bit_length'), secret_type=result.get('secret_type'), mode=result.get('mode'), payload_content_type=result.get('payload_content_type'), payload_content_encoding=result.get( 'payload_content_encoding' ), created=result.get('created'), updated=result.get('updated'), content_types=result.get('content_types'), status=result.get('status') ) def __repr__(self): if self._secret_ref: return 'Secret(secret_ref="{0}")'.format(self._secret_ref) return 'Secret(name="{0}")'.format(self._name) class SecretManager(base.BaseEntityManager): """Entity Manager for Secret entities""" def __init__(self, api): super(SecretManager, self).__init__(api, 'secrets') def get(self, secret_ref, payload_content_type=None): """Retrieve an existing Secret from Barbican :param str secret_ref: Full HATEOAS reference to a Secret, or a UUID :param str payload_content_type: DEPRECATED: Content type to use for payload decryption. Setting this can lead to unexpected results. See Launchpad Bug #1419166. :returns: Secret object retrieved from Barbican :rtype: :class:`barbicanclient.v1.secrets.Secret` :raises barbicanclient.exceptions.HTTPAuthError: 401 Responses :raises barbicanclient.exceptions.HTTPClientError: 4xx Responses :raises barbicanclient.exceptions.HTTPServerError: 5xx Responses """ LOG.debug("Getting secret - Secret href: {0}".format(secret_ref)) base.validate_ref_and_return_uuid(secret_ref, 'Secret') return Secret( api=self._api, payload_content_type=payload_content_type, secret_ref=secret_ref ) def update(self, secret_ref, payload=None): """Update an existing Secret in Barbican :param str secret_ref: Full HATEOAS reference to a Secret, or a UUID :param str payload: New payload to add to secret :raises barbicanclient.exceptions.HTTPAuthError: 401 Responses :raises barbicanclient.exceptions.HTTPClientError: 4xx Responses :raises barbicanclient.exceptions.HTTPServerError: 5xx Responses """ base.validate_ref_and_return_uuid(secret_ref, 'Secret') if not secret_ref: raise ValueError('secret_ref is required.') if type(payload) is six.binary_type: headers = {'content-type': "application/octet-stream"} elif type(payload) is six.text_type: headers = {'content-type': "text/plain"} else: raise exceptions.PayloadException("Invalid Payload Type") uuid_ref = base.calculate_uuid_ref(secret_ref, self._entity) self._api.put(uuid_ref, headers=headers, data=payload) def create(self, name=None, payload=None, payload_content_type=None, payload_content_encoding=None, algorithm=None, bit_length=None, secret_type=None, mode=None, expiration=None): """Factory method for creating new `Secret` objects Secrets returned by this method have not yet been stored in the Barbican service. :param name: A friendly name for the Secret :param payload: The unencrypted secret data :param payload_content_type: DEPRECATED: The format/type of the secret data. Setting this can lead to unexpected results. See Launchpad Bug #1419166. :param payload_content_encoding: DEPRECATED: The encoding of the secret data. Setting this can lead to unexpected results. See Launchpad Bug #1419166. :param algorithm: The algorithm associated with this secret key :param bit_length: The bit length of this secret key :param mode: The algorithm mode used with this secret key :param secret_type: The secret type for this secret key :param expiration: The expiration time of the secret in ISO 8601 format :returns: A new Secret object :rtype: :class:`barbicanclient.v1.secrets.Secret` :raises barbicanclient.exceptions.HTTPAuthError: 401 Responses :raises barbicanclient.exceptions.HTTPClientError: 4xx Responses :raises barbicanclient.exceptions.HTTPServerError: 5xx Responses """ return Secret(api=self._api, name=name, payload=payload, payload_content_type=payload_content_type, payload_content_encoding=payload_content_encoding, algorithm=algorithm, bit_length=bit_length, mode=mode, secret_type=secret_type, expiration=expiration) def delete(self, secret_ref): """Delete a Secret from Barbican :param secret_ref: Full HATEOAS reference to a Secret, or a UUID :raises barbicanclient.exceptions.HTTPAuthError: 401 Responses :raises barbicanclient.exceptions.HTTPClientError: 4xx Responses :raises barbicanclient.exceptions.HTTPServerError: 5xx Responses """ base.validate_ref_and_return_uuid(secret_ref, 'Secret') if not secret_ref: raise ValueError('secret_ref is required.') uuid_ref = base.calculate_uuid_ref(secret_ref, self._entity) self._api.delete(uuid_ref) def list(self, limit=10, offset=0, name=None, algorithm=None, mode=None, bits=0, secret_type=None, created=None, updated=None, expiration=None, sort=None): """List Secrets for the project This method uses the limit and offset parameters for paging, and also supports filtering. The time filters (created, updated, and expiration) are expected to be an ISO 8601 formatted string, which can be prefixed with comparison operators: 'gt:' (greater-than), 'gte:' (greater-than-or-equal), 'lt:' (less-than), or 'lte': (less-than-or-equal). :param limit: Max number of secrets returned :param offset: Offset secrets to begin list :param name: Name filter for the list :param algorithm: Algorithm filter for the list :param mode: Mode filter for the list :param bits: Bits filter for the list :param secret_type: Secret type filter for the list :param created: Created time filter for the list, an ISO 8601 format string, optionally prefixed with 'gt:', 'gte:', 'lt:', or 'lte:' :param updated: Updated time filter for the list, an ISO 8601 format string, optionally prefixed with 'gt:', 'gte:', 'lt:', or 'lte:' :param expiration: Expiration time filter for the list, an ISO 8601 format string, optionally prefixed with 'gt:', 'gte:', 'lt:', or 'lte:' :param sort: Determines the sorted order of the returned list, a string of comma-separated sort keys ('created', 'expiration', 'mode', 'name', 'secret_type', 'status', or 'updated') with a direction appended (':asc' or ':desc') to each key :returns: list of Secret objects that satisfy the provided filter criteria. :rtype: list :raises barbicanclient.exceptions.HTTPAuthError: 401 Responses :raises barbicanclient.exceptions.HTTPClientError: 4xx Responses :raises barbicanclient.exceptions.HTTPServerError: 5xx Responses """ LOG.debug('Listing secrets - offset {0} limit {1}'.format(offset, limit)) params = {'limit': limit, 'offset': offset} if name: params['name'] = name if algorithm: params['alg'] = algorithm if mode: params['mode'] = mode if bits > 0: params['bits'] = bits if secret_type: params['secret_type'] = secret_type if created: params['created'] = created if updated: params['updated'] = updated if expiration: params['expiration'] = expiration if sort: params['sort'] = sort response = self._api.get(self._entity, params=params) return [ Secret(api=self._api, **s) for s in response.get('secrets', []) ] python-barbicanclient-4.10.0/barbicanclient/v1/orders.py0000664000175000017500000004625613620530200023237 0ustar zuulzuul00000000000000# Copyright (c) 2013 Rackspace, Inc. # # 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. import abc import functools import logging from oslo_utils.timeutils import parse_isotime import six from barbicanclient import base from barbicanclient import formatter LOG = logging.getLogger(__name__) def immutable_after_save(func): @functools.wraps(func) def wrapper(self, *args): if self._order_ref: raise base.ImmutableException() return func(self, *args) return wrapper class KeyOrderFormatter(formatter.EntityFormatter): columns = ("Order href", "Type", "Container href", "Secret href", "Created", "Status", "Error code", "Error message" ) def _get_formatted_data(self): created = self.created.isoformat() if self.created else None data = (self.order_ref, "Key", "N/A", self.secret_ref, created, self.status, self.error_status_code, self.error_reason ) return data class AsymmetricOrderFormatter(formatter.EntityFormatter): columns = ("Order href", "Type", "Container href", "Secret href", "Created", "Status", "Error code", "Error message" ) def _get_formatted_data(self): created = self.created.isoformat() if self.created else None data = (self.order_ref, "Asymmetric", self.container_ref, "N/A", created, self.status, self.error_status_code, self.error_reason ) return data class CertificateOrderFormatter(formatter.EntityFormatter): columns = ("Order href", "Type", "Container href", "Secret href", "Created", "Status", "Error code", "Error message" ) def _get_formatted_data(self): created = self.created.isoformat() if self.created else None data = (self.order_ref, "Certificate", self.container_ref, "N/A", created, self.status, self.error_status_code, self.error_reason ) return data @six.add_metaclass(abc.ABCMeta) class Order(object): """Base order object to hold common functionality This should be considered an abstract class that should not be instantiated directly. """ _entity = 'orders' def __init__(self, api, type, status=None, created=None, updated=None, meta=None, order_ref=None, error_status_code=None, error_reason=None, sub_status=None, sub_status_message=None, creator_id=None): super(Order, self).__init__() self._api = api self._type = type self._status = status self._sub_status = sub_status self._sub_status_message = sub_status_message self._creator_id = creator_id if created: self._created = parse_isotime(created) else: self._created = None if updated: self._updated = parse_isotime(updated) else: self._updated = None self._order_ref = order_ref self._meta = base.filter_null_keys(meta) self._error_status_code = error_status_code self._error_reason = error_reason if 'expiration' in self._meta.keys(): self._meta['expiration'] = parse_isotime(self._meta['expiration']) @property def name(self): return self._meta.get('name') @name.setter @immutable_after_save def name(self, value): self._meta['name'] = value @property def algorithm(self): return self._meta.get('algorithm') @algorithm.setter @immutable_after_save def algorithm(self, value): self._meta['algorithm'] = value @property def bit_length(self): return self._meta.get('bit_length') @bit_length.setter @immutable_after_save def bit_length(self, value): self._meta['bit_length'] = value @property def expiration(self): return self._meta.get('expiration') @expiration.setter @immutable_after_save def expiration(self, value): self._meta['expiration'] = value @property def payload_content_type(self): return self._meta.get('payload_content_type') @payload_content_type.setter @immutable_after_save def payload_content_type(self, value): self._meta['payload_content_type'] = value @property def order_ref(self): return self._order_ref @property def created(self): return self._created @property def updated(self): return self._updated @property def status(self): return self._status @property def error_status_code(self): return self._error_status_code @property def error_reason(self): return self._error_reason @immutable_after_save def submit(self): """Submit the Order to Barbican. New Order objects are not persisted in Barbican until this method is called. """ order_dict = {'type': self._type, 'meta': self._meta} LOG.debug("Request body: {0}".format(order_dict)) response = self._api.post(self._entity, json=order_dict) if response: self._order_ref = response.get('order_ref') return self._order_ref def delete(self): """Deletes the Order from Barbican""" if self._order_ref: uuid_ref = base.calculate_uuid_ref(self._order_ref, self._entity) self._api.delete(uuid_ref) self._order_ref = None else: raise LookupError("Order is not yet stored.") class KeyOrder(Order, KeyOrderFormatter): """KeyOrders can be used to request random key material from Barbican""" _type = 'key' _validMeta = (u'name', u'algorithm', u'mode', u'bit_length', u'expiration', u'payload_content_type') def __init__(self, api, name=None, algorithm=None, bit_length=None, mode=None, expiration=None, payload_content_type=None, status=None, created=None, updated=None, order_ref=None, secret_ref=None, error_status_code=None, error_reason=None, sub_status=None, sub_status_message=None, creator_id=None): super(KeyOrder, self).__init__( api, self._type, status=status, created=created, updated=updated, meta={ 'name': name, 'algorithm': algorithm, 'bit_length': bit_length, 'expiration': expiration, 'payload_content_type': payload_content_type }, order_ref=order_ref, error_status_code=error_status_code, error_reason=error_reason, sub_status=sub_status, sub_status_message=sub_status_message, creator_id=creator_id) self._secret_ref = secret_ref if mode: self._meta['mode'] = mode @property def mode(self): """Encryption mode being used with this key The mode could be set to "CBC" for example, when requesting a key that will be used for AES encryption in CBC mode. """ return self._meta.get('mode') @property def secret_ref(self): return self._secret_ref @mode.setter @immutable_after_save def mode(self, value): self._meta['mode'] = value def __repr__(self): return 'KeyOrder(order_ref={0})'.format(self.order_ref) class AsymmetricOrder(Order, AsymmetricOrderFormatter): _type = 'asymmetric' def __init__(self, api, name=None, algorithm=None, bit_length=None, mode=None, passphrase=None, pass_phrase=None, expiration=None, payload_content_type=None, status=None, created=None, updated=None, order_ref=None, container_ref=None, error_status_code=None, error_reason=None, sub_status=None, sub_status_message=None, creator_id=None): super(AsymmetricOrder, self).__init__( api, self._type, status=status, created=created, updated=updated, meta={ 'name': name, 'algorithm': algorithm, 'bit_length': bit_length, 'expiration': expiration, 'payload_content_type': payload_content_type }, order_ref=order_ref, error_status_code=error_status_code, error_reason=error_reason, sub_status=sub_status, sub_status_message=sub_status_message, creator_id=creator_id) self._container_ref = container_ref if passphrase: self._meta['pass_phrase'] = passphrase elif pass_phrase: # NOTE(jaosorior): Needed for backwards compatibility. # See bug #1635213 self._meta['pass_phrase'] = pass_phrase @property def container_ref(self): return self._container_ref @property def pass_phrase(self): """Passphrase to be used for passphrase protected asymmetric keys""" return self._meta.get('pass_phrase') @pass_phrase.setter @immutable_after_save def pass_phrase(self, value): self._meta['pass_phrase'] = value def __repr__(self): return 'AsymmetricOrder(order_ref={0})'.format(self.order_ref) class CertificateOrder(Order, CertificateOrderFormatter): _type = 'certificate' def __init__(self, api, name=None, status=None, created=None, updated=None, order_ref=None, container_ref=None, error_status_code=None, error_reason=None, sub_status=None, sub_status_message=None, creator_id=None, request_type=None, subject_dn=None, source_container_ref=None, ca_id=None, profile=None, request_data=None, requestor_name=None, requestor_email=None, requestor_phone=None): super(CertificateOrder, self).__init__( api, self._type, status=status, created=created, updated=updated, meta={ 'name': name, 'request_type': request_type, 'subject_dn': subject_dn, 'container_ref': source_container_ref, 'ca_id': ca_id, 'profile': profile, 'request_data': request_data, 'requestor_name': requestor_name, 'requestor_email': requestor_email, 'requestor_phone': requestor_phone}, order_ref=order_ref, error_status_code=error_status_code, error_reason=error_reason) self._container_ref = container_ref @property def container_ref(self): return self._container_ref def __repr__(self): return 'CertificateOrder(order_ref={0})'.format(self.order_ref) class OrderManager(base.BaseEntityManager): """Entity Manager for Order entitites""" _order_type_to_class_map = { 'key': KeyOrder, 'asymmetric': AsymmetricOrder, 'certificate': CertificateOrder } def __init__(self, api): super(OrderManager, self).__init__(api, 'orders') def get(self, order_ref): """Retrieve an existing Order from Barbican :param order_ref: Full HATEOAS reference to an Order, or a UUID :returns: An instance of the appropriate subtype of Order :raises barbicanclient.exceptions.HTTPAuthError: 401 Responses :raises barbicanclient.exceptions.HTTPClientError: 4xx Responses :raises barbicanclient.exceptions.HTTPServerError: 5xx Responses """ LOG.debug("Getting order - Order href: {0}".format(order_ref)) uuid_ref = base.calculate_uuid_ref(order_ref, self._entity) try: response = self._api.get(uuid_ref) except AttributeError: raise LookupError( 'Order {0} could not be found.'.format(order_ref) ) return self._create_typed_order(response) def _create_typed_order(self, response): resp_type = response.pop('type').lower() order_type = self._order_type_to_class_map.get(resp_type) if (resp_type == 'certificate' and 'container_ref' in response.get('meta', ())): response['source_container_ref'] = response['meta'].pop( 'container_ref') # validate key_order meta fields. if resp_type == 'key' and ( set(response['meta'].keys()) - set(KeyOrder._validMeta)): invalidFields = ', '.join( map(str, set( response['meta'].keys()) - set(KeyOrder._validMeta))) raise TypeError( 'Invalid KeyOrder meta field: [%s]' % invalidFields) response.update(response.pop('meta')) if order_type is not None: return order_type(self._api, **response) else: raise TypeError('Unknown Order type "{0}"'.format(order_type)) def create(self, type=None, **kwargs): if not type: raise TypeError('No Order type provided') order_type = self._order_type_to_class_map.get(type.lower()) if not order_type: raise TypeError('Unknown Order type "{0}"'.format(type)) return order_type(self._api, **kwargs) def create_key(self, name=None, algorithm=None, bit_length=None, mode=None, payload_content_type=None, expiration=None): """Factory method for `KeyOrder` objects `KeyOrder` objects returned by this method have not yet been submitted to the Barbican service. :param name: A friendly name for the secret to be created :param algorithm: The algorithm associated with this secret key :param bit_length: The bit length of this secret key :param mode: The algorithm mode used with this secret key :param payload_content_type: The format/type of the secret data :param expiration: The expiration time of the secret in ISO 8601 format :returns: KeyOrder :rtype: :class:`barbicanclient.v1.orders.KeyOrder` :raises barbicanclient.exceptions.HTTPAuthError: 401 Responses :raises barbicanclient.exceptions.HTTPClientError: 4xx Responses :raises barbicanclient.exceptions.HTTPServerError: 5xx Responses """ return KeyOrder(api=self._api, name=name, algorithm=algorithm, bit_length=bit_length, mode=mode, payload_content_type=payload_content_type, expiration=expiration) def create_asymmetric(self, name=None, algorithm=None, bit_length=None, pass_phrase=None, payload_content_type=None, expiration=None): """Factory method for `AsymmetricOrder` objects `AsymmetricOrder` objects returned by this method have not yet been submitted to the Barbican service. :param name: A friendly name for the container to be created :param algorithm: The algorithm associated with this secret key :param bit_length: The bit length of this secret key :param pass_phrase: Optional passphrase :param payload_content_type: The format/type of the secret data :param expiration: The expiration time of the secret in ISO 8601 format :returns: AsymmetricOrder :rtype: :class:`barbicanclient.v1.orders.AsymmetricOrder` :raises barbicanclient.exceptions.HTTPAuthError: 401 Responses :raises barbicanclient.exceptions.HTTPClientError: 4xx Responses :raises barbicanclient.exceptions.HTTPServerError: 5xx Responses """ return AsymmetricOrder(api=self._api, name=name, algorithm=algorithm, bit_length=bit_length, passphrase=pass_phrase, payload_content_type=payload_content_type, expiration=expiration) def create_certificate(self, name=None, request_type=None, subject_dn=None, source_container_ref=None, ca_id=None, profile=None, request_data=None): """Factory method for `CertificateOrder` objects `CertificateOrder` objects returned by this method have not yet been submitted to the Barbican service. :param name: A friendly name for the container to be created :param request_type: The type of the certificate request :param subject_dn: A subject for the certificate :param source_container_ref: A container with a public/private key pair to use as source for stored-key requests :param ca_id: The identifier of the CA to use :param profile: The profile of certificate to use :param request_data: The CSR content :returns: CertificateOrder :rtype: :class:`barbicanclient.v1.orders.CertificateOrder` """ return CertificateOrder(api=self._api, name=name, request_type=request_type, subject_dn=subject_dn, source_container_ref=source_container_ref, ca_id=ca_id, profile=profile, request_data=request_data) def delete(self, order_ref): """Delete an Order from Barbican :param order_ref: Full HATEOAS reference to an Order, or a UUID """ if not order_ref: raise ValueError('order_ref is required.') uuid_ref = base.calculate_uuid_ref(order_ref, self._entity) self._api.delete(uuid_ref) def list(self, limit=10, offset=0): """List Orders for the project This method uses the limit and offset parameters for paging. :param limit: Max number of orders returned :param offset: Offset orders to begin list :returns: list of Order objects :raises barbicanclient.exceptions.HTTPAuthError: 401 Responses :raises barbicanclient.exceptions.HTTPClientError: 4xx Responses :raises barbicanclient.exceptions.HTTPServerError: 5xx Responses """ LOG.debug('Listing orders - offset {0} limit {1}'.format(offset, limit)) params = {'limit': limit, 'offset': offset} response = self._api.get(self._entity, params=params) return [ self._create_typed_order(o) for o in response.get('orders', []) ] python-barbicanclient-4.10.0/barbicanclient/v1/containers.py0000664000175000017500000006763713620530200024114 0ustar zuulzuul00000000000000# Copyright (c) 2014 Rackspace, Inc. # # 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. import functools import logging from oslo_utils.timeutils import parse_isotime from barbicanclient import base from barbicanclient import formatter from barbicanclient.v1 import acls as acl_manager from barbicanclient.v1 import secrets as secret_manager LOG = logging.getLogger(__name__) def _immutable_after_save(func): @functools.wraps(func) def wrapper(self, *args): if hasattr(self, '_container_ref') and self._container_ref: raise base.ImmutableException() return func(self, *args) return wrapper class ContainerFormatter(formatter.EntityFormatter): columns = ("Container href", "Name", "Created", "Status", "Type", "Secrets", "Consumers", ) def _get_formatted_data(self): formatted_secrets = None formatted_consumers = None if self.secrets: formatted_secrets = '\n'.join(( '='.join((name, secret_ref)) if name else secret_ref for name, secret_ref in self.secret_refs.items() )) if self.consumers: formatted_consumers = '\n'.join((str(c) for c in self.consumers)) created = self.created.isoformat() if self.created else None data = (self.container_ref, self.name, created, self.status, self._type, formatted_secrets, formatted_consumers, ) return data class Container(ContainerFormatter): """Container is a generic grouping of Secrets""" _entity = 'containers' _type = 'generic' def __init__(self, api, name=None, secrets=None, consumers=None, container_ref=None, created=None, updated=None, status=None, secret_refs=None): self._api = api self._secret_manager = secret_manager.SecretManager(api) self._name = name self._container_ref = container_ref self._secret_refs = secret_refs self._cached_secrets = dict() self._initialize_secrets(secrets) if container_ref: self._consumers = consumers if consumers else list() self._created = parse_isotime(created) if created else None self._updated = parse_isotime(updated) if updated else None self._status = status else: self._consumers = list() 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: self._fill_secrets_from_secret_refs() except Exception: raise ValueError("One or more of the provided secret_refs could " "not be retrieved!") if secrets: try: for name, secret in secrets.items(): self.add(name, secret) except Exception: raise ValueError("One or more of the provided secrets are not " "valid Secret objects!") def _fill_secrets_from_secret_refs(self): if self._secret_refs: self._cached_secrets = dict( (name.lower() if name else "", self._secret_manager.get(secret_ref=secret_ref)) for name, secret_ref in self._secret_refs.items() ) @property def container_ref(self): return self._container_ref @property def name(self): if self._container_ref and not self._name: self._reload() return self._name @property def created(self): return self._created @property def updated(self): return self._updated @property def status(self): if self._container_ref and not self._status: self._reload() 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( (name, secret.secret_ref) for name, secret in self._cached_secrets.items() ) return self._secret_refs @property def secrets(self, cache=True): """List of Secrets in Containers""" if not self._cached_secrets or not cache: self._fill_secrets_from_secret_refs() return self._cached_secrets @property def consumers(self): return self._consumers @name.setter @_immutable_after_save def name(self, value): self._name = value @_immutable_after_save def add(self, name, secret): if not isinstance(secret, secret_manager.Secret): raise ValueError("Must provide a valid Secret object") if name.lower() in self.secrets: raise KeyError("A secret with this name already exists!") self._cached_secrets[name.lower()] = secret @_immutable_after_save def remove(self, name): self._cached_secrets.pop(name.lower(), None) if self._secret_refs: self._secret_refs.pop(name.lower(), None) @_immutable_after_save def store(self): """Store Container in Barbican""" secret_refs = self._get_secrets_and_store_them_if_necessary() container_dict = base.filter_null_keys({ 'name': self.name, 'type': self._type, 'secret_refs': secret_refs }) LOG.debug("Request body: {0}".format(container_dict)) # Save, store container_ref and return response = self._api.post(self._entity, json=container_dict) if response: self._container_ref = response['container_ref'] return self.container_ref def delete(self): """Delete container from Barbican""" if self._container_ref: uuid_ref = base.calculate_uuid_ref(self._container_ref, self._entity) self._api.delete(uuid_ref) self._container_ref = None self._status = None self._created = None self._updated = None else: raise LookupError("Secret is not yet stored.") def _get_secrets_and_store_them_if_necessary(self): # Save all secrets if they are not yet saved LOG.debug("Storing secrets: {0}".format(base.censored_copy( self.secrets, ['payload']))) secret_refs = [] for name, secret in self.secrets.items(): if secret and not secret.secret_ref: secret.store() secret_refs.append({'name': name, 'secret_ref': secret.secret_ref}) return secret_refs def _reload(self): if not self._container_ref: raise AttributeError("container_ref not set, cannot reload data.") LOG.debug('Getting container - Container href: {0}' .format(self._container_ref)) uuid_ref = base.calculate_uuid_ref(self._container_ref, self._entity) try: response = self._api.get(uuid_ref) except AttributeError: raise LookupError('Container {0} could not be found.' .format(self._container_ref)) self._name = response.get('name') self._consumers = response.get('consumers', []) created = response.get('created') updated = response.get('updated') self._created = parse_isotime(created) if created else None self._updated = parse_isotime(updated) if updated else None self._status = response.get('status') def _get_named_secret(self, name): return self.secrets.get(name) def __repr__(self): return 'Container(name="{0}")'.format(self.name) class RSAContainerFormatter(formatter.EntityFormatter): _get_generic_data = ContainerFormatter._get_formatted_data def _get_generic_columns(self): return ContainerFormatter.columns columns = ("Container href", "Name", "Created", "Status", "Type", "Public Key", "Private Key", "PK Passphrase", "Consumers", ) def _get_formatted_data(self): formatted_public_key = None formatted_private_key = None formatted_pkp = None formatted_consumers = None if self.public_key: formatted_public_key = self.public_key.secret_ref if self.private_key: formatted_private_key = self.private_key.secret_ref if self.private_key_passphrase: formatted_pkp = self.private_key_passphrase.secret_ref if self.consumers: formatted_consumers = '\n'.join((str(c) for c in self.consumers)) data = (self.container_ref, self.name, self.created, self.status, self._type, formatted_public_key, formatted_private_key, formatted_pkp, formatted_consumers, ) return data class RSAContainer(RSAContainerFormatter, Container): _required_secrets = ["public_key", "private_key"] _optional_secrets = ["private_key_passphrase"] _type = 'rsa' def __init__(self, api, name=None, public_key=None, private_key=None, private_key_passphrase=None, consumers=[], container_ref=None, created=None, updated=None, status=None, public_key_ref=None, private_key_ref=None, private_key_passphrase_ref=None): secret_refs = {} if public_key_ref: secret_refs['public_key'] = public_key_ref if private_key_ref: secret_refs['private_key'] = private_key_ref if private_key_passphrase_ref: secret_refs['private_key_passphrase'] = private_key_passphrase_ref super(RSAContainer, self).__init__( api=api, name=name, consumers=consumers, container_ref=container_ref, created=created, updated=updated, status=status, secret_refs=secret_refs ) if public_key: self.public_key = public_key if private_key: self.private_key = private_key if private_key_passphrase: self.private_key_passphrase = private_key_passphrase @property def public_key(self): """Secret containing the Public Key""" return self._get_named_secret("public_key") @property def private_key(self): """Secret containing the Private Key""" return self._get_named_secret("private_key") @property def private_key_passphrase(self): """Secret containing the Passphrase""" return self._get_named_secret("private_key_passphrase") @public_key.setter @_immutable_after_save def public_key(self, value): super(RSAContainer, self).remove("public_key") super(RSAContainer, self).add("public_key", value) @private_key.setter @_immutable_after_save def private_key(self, value): super(RSAContainer, self).remove("private_key") super(RSAContainer, self).add("private_key", value) @private_key_passphrase.setter @_immutable_after_save def private_key_passphrase(self, value): super(RSAContainer, self).remove("private_key_passphrase") super(RSAContainer, self).add("private_key_passphrase", value) def add(self, name, sec): raise NotImplementedError("`add()` is not implemented for " "Typed Containers") def __repr__(self): return 'RSAContainer(name="{0}")'.format(self.name) class CertificateContainerFormatter(formatter.EntityFormatter): _get_generic_data = ContainerFormatter._get_formatted_data def _get_generic_columns(self): return ContainerFormatter.columns columns = ("Container href", "Name", "Created", "Status", "Type", "Certificate", "Intermediates", "Private Key", "PK Passphrase", "Consumers", ) def _get_formatted_data(self): formatted_certificate = None formatted_private_key = None formatted_pkp = None formatted_intermediates = None formatted_consumers = None if self.certificate: formatted_certificate = self.certificate.secret_ref if self.intermediates: formatted_intermediates = self.intermediates.secret_ref if self.private_key: formatted_private_key = self.private_key.secret_ref if self.private_key_passphrase: formatted_pkp = self.private_key_passphrase.secret_ref if self.consumers: formatted_consumers = '\n'.join((str(c) for c in self.consumers)) data = (self.container_ref, self.name, self.created, self.status, self._type, formatted_certificate, formatted_intermediates, formatted_private_key, formatted_pkp, formatted_consumers, ) return data class CertificateContainer(CertificateContainerFormatter, Container): _required_secrets = ["certificate", "private_key"] _optional_secrets = ["private_key_passphrase", "intermediates"] _type = 'certificate' def __init__(self, api, name=None, certificate=None, intermediates=None, private_key=None, private_key_passphrase=None, consumers=[], container_ref=None, created=None, updated=None, status=None, certificate_ref=None, intermediates_ref=None, private_key_ref=None, private_key_passphrase_ref=None): secret_refs = {} if certificate_ref: secret_refs['certificate'] = certificate_ref if intermediates_ref: secret_refs['intermediates'] = intermediates_ref if private_key_ref: secret_refs['private_key'] = private_key_ref if private_key_passphrase_ref: secret_refs['private_key_passphrase'] = private_key_passphrase_ref super(CertificateContainer, self).__init__( api=api, name=name, consumers=consumers, container_ref=container_ref, created=created, updated=updated, status=status, secret_refs=secret_refs ) if certificate: self.certificate = certificate if intermediates: self.intermediates = intermediates if private_key: self.private_key = private_key if private_key_passphrase: self.private_key_passphrase = private_key_passphrase @property def certificate(self): """Secret containing the certificate""" return self._get_named_secret("certificate") @property def private_key(self): """Secret containing the private key""" return self._get_named_secret("private_key") @property def private_key_passphrase(self): """Secret containing the passphrase""" return self._get_named_secret("private_key_passphrase") @property def intermediates(self): """Secret containing intermediate certificates""" return self._get_named_secret("intermediates") @certificate.setter @_immutable_after_save def certificate(self, value): super(CertificateContainer, self).remove("certificate") super(CertificateContainer, self).add("certificate", value) @private_key.setter @_immutable_after_save def private_key(self, value): super(CertificateContainer, self).remove("private_key") super(CertificateContainer, self).add("private_key", value) @private_key_passphrase.setter @_immutable_after_save def private_key_passphrase(self, value): super(CertificateContainer, self).remove("private_key_passphrase") super(CertificateContainer, self).add("private_key_passphrase", value) @intermediates.setter @_immutable_after_save def intermediates(self, value): super(CertificateContainer, self).remove("intermediates") super(CertificateContainer, self).add("intermediates", value) def add(self, name, sec): raise NotImplementedError("`add()` is not implemented for " "Typed Containers") def __repr__(self): return 'CertificateContainer(name="{0}")'.format(self.name) class ContainerManager(base.BaseEntityManager): """EntityManager for Container entities You should use the ContainerManager exposed by the Client and should not need to instantiate your own. """ _container_map = { 'generic': Container, 'rsa': RSAContainer, 'certificate': CertificateContainer } def __init__(self, api): super(ContainerManager, self).__init__(api, 'containers') def get(self, container_ref): """Retrieve an existing Container from Barbican :param container_ref: Full HATEOAS reference to a Container, or a UUID :returns: Container object or a subclass of the appropriate type """ LOG.debug('Getting container - Container href: {0}' .format(container_ref)) uuid_ref = base.calculate_uuid_ref(container_ref, self._entity) try: response = self._api.get(uuid_ref) except AttributeError: raise LookupError('Container {0} could not be found.' .format(container_ref)) return self._generate_typed_container(response) def _generate_typed_container(self, response): resp_type = response.get('type', '').lower() container_type = self._container_map.get(resp_type) if not container_type: raise TypeError('Unknown container type "{0}".' .format(resp_type)) name = response.get('name') consumers = response.get('consumers', []) container_ref = response.get('container_ref') created = response.get('created') updated = response.get('updated') status = response.get('status') secret_refs = self._translate_secret_refs_from_json( response.get('secret_refs') ) if container_type is RSAContainer: public_key_ref = secret_refs.get('public_key') private_key_ref = secret_refs.get('private_key') private_key_pass_ref = secret_refs.get('private_key_passphrase') return RSAContainer( api=self._api, name=name, consumers=consumers, container_ref=container_ref, created=created, updated=updated, status=status, public_key_ref=public_key_ref, private_key_ref=private_key_ref, private_key_passphrase_ref=private_key_pass_ref, ) elif container_type is CertificateContainer: certificate_ref = secret_refs.get('certificate') intermediates_ref = secret_refs.get('intermediates') private_key_ref = secret_refs.get('private_key') private_key_pass_ref = secret_refs.get('private_key_passphrase') return CertificateContainer( api=self._api, name=name, consumers=consumers, container_ref=container_ref, created=created, updated=updated, status=status, certificate_ref=certificate_ref, intermediates_ref=intermediates_ref, private_key_ref=private_key_ref, private_key_passphrase_ref=private_key_pass_ref, ) return container_type( api=self._api, name=name, secret_refs=secret_refs, consumers=consumers, container_ref=container_ref, created=created, updated=updated, status=status ) @staticmethod def _translate_secret_refs_from_json(json_refs): return dict( (ref_pack.get('name'), ref_pack.get('secret_ref')) for ref_pack in json_refs ) def create(self, name=None, secrets=None): """Factory method for `Container` objects `Container` objects returned by this method have not yet been stored in Barbican. :param name: A friendly name for the Container :param secrets: Secrets to populate when creating a Container :returns: Container :rtype: :class:`barbicanclient.v1.containers.Container` :raises barbicanclient.exceptions.HTTPAuthError: 401 Responses :raises barbicanclient.exceptions.HTTPClientError: 4xx Responses :raises barbicanclient.exceptions.HTTPServerError: 5xx Responses """ return Container( api=self._api, name=name, secrets=secrets ) def create_rsa(self, name=None, public_key=None, private_key=None, private_key_passphrase=None): """Factory method for `RSAContainer` objects `RSAContainer` objects returned by this method have not yet been stored in Barbican. :param name: A friendly name for the RSAContainer :param public_key: Secret object containing a Public Key :param private_key: Secret object containing a Private Key :param private_key_passphrase: Secret object containing a passphrase :returns: RSAContainer :rtype: :class:`barbicanclient.v1.containers.RSAContainer` :raises barbicanclient.exceptions.HTTPAuthError: 401 Responses :raises barbicanclient.exceptions.HTTPClientError: 4xx Responses :raises barbicanclient.exceptions.HTTPServerError: 5xx Responses """ return RSAContainer( api=self._api, name=name, public_key=public_key, private_key=private_key, private_key_passphrase=private_key_passphrase ) def create_certificate(self, name=None, certificate=None, intermediates=None, private_key=None, private_key_passphrase=None): """Factory method for `CertificateContainer` objects `CertificateContainer` objects returned by this method have not yet been stored in Barbican. :param name: A friendly name for the CertificateContainer :param certificate: Secret object containing a Certificate :param intermediates: Secret object containing Intermediate Certs :param private_key: Secret object containing a Private Key :param private_key_passphrase: Secret object containing a passphrase :returns: CertificateContainer :rtype: :class:`barbicanclient.v1.containers.CertificateContainer` :raises barbicanclient.exceptions.HTTPAuthError: 401 Responses :raises barbicanclient.exceptions.HTTPClientError: 4xx Responses :raises barbicanclient.exceptions.HTTPServerError: 5xx Responses """ return CertificateContainer( api=self._api, name=name, certificate=certificate, intermediates=intermediates, private_key=private_key, private_key_passphrase=private_key_passphrase ) def delete(self, container_ref): """Delete a Container from Barbican :param container_ref: Full HATEOAS reference to a Container, or a UUID :raises barbicanclient.exceptions.HTTPAuthError: 401 Responses :raises barbicanclient.exceptions.HTTPClientError: 4xx Responses :raises barbicanclient.exceptions.HTTPServerError: 5xx Responses """ if not container_ref: raise ValueError('container_ref is required.') uuid_ref = base.calculate_uuid_ref(container_ref, self._entity) self._api.delete(uuid_ref) def list(self, limit=10, offset=0, name=None, type=None): """List containers for the project. This method uses the limit and offset parameters for paging. :param limit: Max number of containers returned :param offset: Offset containers to begin list :param name: Name filter for the list :param type: Type filter for the list :returns: list of Container metadata objects :raises barbicanclient.exceptions.HTTPAuthError: 401 Responses :raises barbicanclient.exceptions.HTTPClientError: 4xx Responses :raises barbicanclient.exceptions.HTTPServerError: 5xx Responses """ LOG.debug('Listing containers - offset {0} limit {1} name {2} type {3}' .format(offset, limit, name, type)) params = {'limit': limit, 'offset': offset} if name: params['name'] = name if type: params['type'] = type response = self._api.get(self._entity, params=params) return [self._generate_typed_container(container) for container in response.get('containers', [])] def register_consumer(self, container_ref, name, url): """Add a consumer to the container :param container_ref: Full HATEOAS reference to a Container, or a UUID :param name: Name of the consuming service :param url: URL of the consuming resource :returns: A container object per the get() method :raises barbicanclient.exceptions.HTTPAuthError: 401 Responses :raises barbicanclient.exceptions.HTTPClientError: 4xx Responses :raises barbicanclient.exceptions.HTTPServerError: 5xx Responses """ LOG.debug('Creating consumer registration for container ' '{0} as {1}: {2}'.format(container_ref, name, url)) container_uuid = base.validate_ref_and_return_uuid( container_ref, 'Container') href = '{0}/{1}/consumers'.format(self._entity, container_uuid) consumer_dict = dict() consumer_dict['name'] = name consumer_dict['URL'] = url response = self._api.post(href, json=consumer_dict) return self._generate_typed_container(response) def remove_consumer(self, container_ref, name, url): """Remove a consumer from the container :param container_ref: Full HATEOAS reference to a Container, or a UUID :param name: Name of the previously consuming service :param url: URL of the previously consuming resource :raises barbicanclient.exceptions.HTTPAuthError: 401 Responses :raises barbicanclient.exceptions.HTTPClientError: 4xx Responses :raises barbicanclient.exceptions.HTTPServerError: 5xx Responses """ LOG.debug('Deleting consumer registration for container ' '{0} as {1}: {2}'.format(container_ref, name, url)) container_uuid = base.validate_ref_and_return_uuid( container_ref, 'Container') href = '{0}/{1}/consumers'.format(self._entity, container_uuid) consumer_dict = { 'name': name, 'URL': url } self._api.delete(href, json=consumer_dict) python-barbicanclient-4.10.0/barbicanclient/v1/client.py0000664000175000017500000000626513620530200023213 0ustar zuulzuul00000000000000# Copyright (c) 2016 GohighSec, Inc. # # 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. import logging from barbicanclient import client as base_client from barbicanclient.v1 import acls from barbicanclient.v1 import cas from barbicanclient.v1 import containers from barbicanclient.v1 import orders from barbicanclient.v1 import secrets LOG = logging.getLogger(__name__) class Client(object): def __init__(self, session=None, *args, **kwargs): """Barbican client object used to interact with barbican service. :param session: An instance of keystoneauth1.session.Session that can be either authenticated, or not authenticated. When using a non-authenticated Session, you must provide some additional parameters. When no session is provided it will default to a non-authenticated Session. :param endpoint: Barbican endpoint url. Required when a session is not given, or when using a non-authenticated session. When using an authenticated session, the client will attempt to get an endpoint from the session. :param project_id: The project ID used for context in Barbican. Required when a session is not given, or when using a non-authenticated session. When using an authenticated session, the project ID will be provided by the authentication mechanism. :param verify: When a session is not given, the client will create a non-authenticated session. This parameter is passed to the session that is created. If set to False, it allows barbicanclient to perform "insecure" TLS (https) requests. The server's certificate will not be verified against any certificate authorities. WARNING: This option should be used with caution. :param service_type: Used as an endpoint filter when using an authenticated keystone session. Defaults to 'key-management'. :param service_name: Used as an endpoint filter when using an authenticated keystone session. :param interface: Used as an endpoint filter when using an authenticated keystone session. Defaults to 'public'. :param region_name: Used as an endpoint filter when using an authenticated keystone session. """ self.client = base_client._HTTPClient(session=session, *args, **kwargs) self.secrets = secrets.SecretManager(self.client) self.orders = orders.OrderManager(self.client) self.containers = containers.ContainerManager(self.client) self.cas = cas.CAManager(self.client) self.acls = acls.ACLManager(self.client) python-barbicanclient-4.10.0/barbicanclient/v1/cas.py0000664000175000017500000001626313620530200022502 0ustar zuulzuul00000000000000# Copyright (c) 2015 Red Hat Inc. # # 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. import functools import logging from oslo_utils.timeutils import parse_isotime from barbicanclient import base from barbicanclient import formatter LOG = logging.getLogger(__name__) def lazy(func): @functools.wraps(func) def wrapper(self, *args): self._fill_lazy_properties() return func(self, *args) return wrapper class CAFormatter(formatter.EntityFormatter): columns = ("CA href", "Name", "Description", "Created", "Updated", "Status", "Plugin Name", "Plugin CA ID", "Expiration" ) def _get_formatted_data(self): created = self.created.isoformat() if self.created else None updated = self.updated.isoformat() if self.updated else None expiration = self.expiration.isoformat() if self.expiration else None data = (self.ca_ref, self.name, self.description, created, updated, self.status, self.plugin_name, self.plugin_ca_id, expiration ) return data class CA(CAFormatter): """Certificate authority CAs represent certificate authorities or subCAs with which the Barbican service is configured to interact. """ _entity = 'cas' def __init__(self, api, meta=None, expiration=None, plugin_name=None, plugin_ca_id=None, ca_ref=None, created=None, updated=None, status=None, creator_id=None): """Certificate authority CA objects should not be instantiated directly. You should use the `create` or `get` methods of the :class:`barbicanclient.cas.CAManager` instead. """ self._api = api self._ca_ref = ca_ref self._fill_from_data( meta=meta, expiration=expiration, plugin_name=plugin_name, plugin_ca_id=plugin_ca_id, created=created, updated=updated, status=status, creator_id=creator_id ) @property def ca_ref(self): return self._ca_ref @property @lazy def name(self): return self._name @property @lazy def expiration(self): return self._expiration @property @lazy def description(self): return self._description @property @lazy def plugin_name(self): return self._plugin_name @property @lazy def plugin_ca_id(self): return self._plugin_ca_id @property @lazy def created(self): return self._created @property @lazy def updated(self): return self._updated @property @lazy def status(self): return self._status def _fill_from_data(self, meta=None, expiration=None, plugin_name=None, plugin_ca_id=None, created=None, updated=None, status=None, creator_id=None): self._name = None self._description = None if meta: for s in meta: key = list(s.keys())[0] value = list(s.values())[0] if key == 'name': self._name = value if key == 'description': self._description = value self._plugin_name = plugin_name self._plugin_ca_id = plugin_ca_id self._expiration = expiration self._creator_id = creator_id if self._expiration: self._expiration = parse_isotime(self._expiration) if self._ca_ref: self._status = status self._created = created self._updated = updated if self._created: self._created = parse_isotime(self._created) if self._updated: self._updated = parse_isotime(self._updated) else: self._status = None self._created = None self._updated = None def _fill_lazy_properties(self): if self._ca_ref and not self._plugin_name: uuid_ref = base.calculate_uuid_ref(self._ca_ref, self._entity) result = self._api.get(uuid_ref) self._fill_from_data( meta=result.get('meta'), expiration=result.get('expiration'), plugin_name=result.get('plugin_name'), plugin_ca_id=result.get('plugin_ca_id'), created=result.get('created'), updated=result.get('updated'), status=result.get('status') ) def __repr__(self): if self._ca_ref: return 'CA(ca_ref="{0}")'.format(self._ca_ref) return 'CA(name="{0}")'.format(self._name) class CAManager(base.BaseEntityManager): """Entity Manager for Secret entities""" def __init__(self, api): super(CAManager, self).__init__(api, 'cas') def get(self, ca_ref): """Retrieve an existing CA from Barbican :param str ca_ref: Full HATEOAS reference to a CA :returns: CA object retrieved from Barbican :rtype: :class:`barbicanclient.v1.cas.CA` :raises barbicanclient.exceptions.HTTPAuthError: 401 Responses :raises barbicanclient.exceptions.HTTPClientError: 4xx Responses :raises barbicanclient.exceptions.HTTPServerError: 5xx Responses """ LOG.debug("Getting ca - CA href: {0}".format(ca_ref)) base.validate_ref_and_return_uuid(ca_ref, 'CA') return CA( api=self._api, ca_ref=ca_ref ) def list(self, limit=10, offset=0, name=None): """List CAs for the project This method uses the limit and offset parameters for paging, and also supports filtering. :param limit: Max number of CAs returned :param offset: Offset secrets to begin list :param name: Name filter for the list :returns: list of CA objects that satisfy the provided filter criteria. :rtype: list :raises barbicanclient.exceptions.HTTPAuthError: 401 Responses :raises barbicanclient.exceptions.HTTPClientError: 4xx Responses :raises barbicanclient.exceptions.HTTPServerError: 5xx Responses """ LOG.debug('Listing CAs - offset {0} limit {1}'.format(offset, limit)) params = {'limit': limit, 'offset': offset} if name: params['name'] = name response = self._api.get(self._entity, params=params) return [ CA(api=self._api, ca_ref=s) for s in response.get('cas', []) ] python-barbicanclient-4.10.0/barbicanclient/v1/acls.py0000664000175000017500000004500213620530200022647 0ustar zuulzuul00000000000000# 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. import logging from oslo_utils.timeutils import parse_isotime from barbicanclient import base from barbicanclient import formatter LOG = logging.getLogger(__name__) DEFAULT_OPERATION_TYPE = 'read' VALID_ACL_OPERATIONS = ['read', 'write', 'delete', 'list'] class ACLFormatter(formatter.EntityFormatter): columns = ("Operation Type", "Project Access", "Users", "Created", "Updated", ) def _get_formatted_data(self): created = self.created.isoformat() if self.created else None updated = self.updated.isoformat() if self.updated else None data = (self.operation_type, self.project_access, self.users, created, updated, self.acl_ref, ) return data class _PerOperationACL(ACLFormatter): def __init__(self, parent_acl, entity_ref=None, users=None, project_access=None, operation_type=None, created=None, updated=None): """Per Operation ACL data instance for secret or container. This class not to be instantiated outside of this module. :param parent_acl: acl entity to this per operation data belongs to :param str entity_ref: Full HATEOAS reference to a secret or container :param users: List of Keystone userid(s) to be used for ACL. :type users: List or None :param bool project_access: Flag indicating project access behavior :param str operation_type: Type indicating which class of Barbican operations this ACL is defined for e.g. 'read' operations :param str created: Time string indicating ACL create timestamp. This is populated only when populating data from api response. Not needed in client input. :param str updated: Time string indicating ACL last update timestamp. This is populated only when populating data from api response. Not needed in client input. """ self._parent_acl = parent_acl self._entity_ref = entity_ref self._users = users if users else list() self._project_access = project_access self._operation_type = operation_type self._created = parse_isotime(created) if created else None self._updated = parse_isotime(updated) if updated else None @property def acl_ref(self): return ACL.get_acl_ref_from_entity_ref(self.entity_ref) @property def acl_ref_relative(self): return self._parent_acl.acl_ref_relative @property def entity_ref(self): return self._entity_ref @property def entity_uuid(self): return self._parent_acl.entity_uuid @property def project_access(self): """Flag indicating project access behavior is enabled or not""" return self._project_access @property def users(self): """List of users for this ACL setting""" return self._users @property def operation_type(self): """Type indicating class of Barbican operations for this ACL""" return self._operation_type @property def created(self): return self._created @property def updated(self): return self._updated @operation_type.setter def operation_type(self, value): self._operation_type = value @project_access.setter def project_access(self, value): self._project_access = value @users.setter def users(self, value): self._users = value def remove(self): """Remove operation specific setting defined for a secret or container :raises barbicanclient.exceptions.HTTPAuthError: 401 Responses :raises barbicanclient.exceptions.HTTPClientError: 4xx Responses """ LOG.debug('Removing {0} operation specific ACL for href: {1}' .format(self.operation_type, self.acl_ref)) self._parent_acl.load_acls_data() acl_entity = self._parent_acl # Find matching operation specific acl entry and remove from list per_op_acl = acl_entity.get(self.operation_type) if per_op_acl: acl_entity.operation_acls.remove(per_op_acl) # after above operation specific acl removal, check if there are # any remaining acls. If yes, then submit updates to server. # If not, then remove/delete acls from server. if acl_entity.operation_acls: acl_entity.submit() else: acl_entity.remove() def _validate_users_type(self): if self.users and not (type(self.users) is list or type(self.users) is set): raise ValueError('Users value is expected to be provided' ' as list/set.') class ACL(object): _resource_name = 'acl' def __init__(self, api, entity_ref, users=None, project_access=None, operation_type=DEFAULT_OPERATION_TYPE, created=None, updated=None): """Base ACL entity instance for secret or container. Provide ACL data arguments to set ACL setting for given operation_type. To add ACL setting for other operation types, use `add_operation_acl` method. :param api: client instance reference :param str entity_ref: Full HATEOAS reference to a secret or container :param users: List of Keystone userid(s) to be used for ACL. :type users: str List or None :param bool project_access: Flag indicating project access behavior :param str operation_type: Type indicating which class of Barbican operations this ACL is defined for e.g. 'read' operations :param str created: Time string indicating ACL create timestamp. This is populated only when populating data from api response. Not needed in client input. :param str updated: Time string indicating ACL last update timestamp. This is populated only when populating data from api response. Not needed in client input. """ self._api = api self._entity_ref = entity_ref self._operation_acls = [] # create per operation ACL data entity only when client has set users # or project_access flag. if users is not None or project_access is not None: acl = _PerOperationACL(parent_acl=self, entity_ref=entity_ref, users=users, project_access=project_access, operation_type=operation_type, created=created, updated=updated) self._operation_acls.append(acl) @property def entity_ref(self): """Entity URI reference.""" return self._entity_ref @property def entity_uuid(self): """Entity UUID""" return str(base.validate_ref_and_return_uuid( self._entity_ref, self._acl_type)) @property def operation_acls(self): """List of operation specific ACL settings.""" return self._operation_acls @property def acl_ref(self): return ACL.get_acl_ref_from_entity_ref(self.entity_ref) @property def acl_ref_relative(self): return ACL.get_acl_ref_from_entity_ref_relative( self.entity_uuid, self._parent_entity_path) def add_operation_acl(self, users=None, project_access=None, operation_type=None, created=None, updated=None,): """Add ACL settings to entity for specific operation type. If matching operation_type ACL already exists, then it replaces it with new PerOperationACL object using provided inputs. Otherwise it appends new PerOperationACL object to existing per operation ACL list. This just adds to local entity and have not yet applied these changes to server. :param users: List of Keystone userid(s) to be used in ACL. :type users: List or None :param bool project_access: Flag indicating project access behavior :param str operation_type: Type indicating which class of Barbican operations this ACL is defined for e.g. 'read' operations :param str created: Time string indicating ACL create timestamp. This is populated only when populating data from api response. Not needed in client input. :param str updated: Time string indicating ACL last update timestamp. This is populated only when populating data from api response. Not needed in client input. """ new_acl = _PerOperationACL(parent_acl=self, entity_ref=self.entity_ref, users=users, project_access=project_access, operation_type=operation_type, created=created, updated=updated) for i, acl in enumerate(self._operation_acls): if acl.operation_type == operation_type: # replace with new ACL setting self._operation_acls[i] = new_acl break else: self._operation_acls.append(new_acl) def _get_operation_acl(self, operation_type): return next((acl for acl in self._operation_acls if acl.operation_type == operation_type), None) def get(self, operation_type): """Get operation specific ACL instance. :param str operation_type: Type indicating which operation's ACL setting is needed. """ return self._get_operation_acl(operation_type) def __getattr__(self, name): if name in VALID_ACL_OPERATIONS: return self._get_operation_acl(name) else: raise AttributeError(name) def submit(self): """Submits ACLs for a secret or a container defined in server In existing ACL case, this overwrites the existing ACL setting with provided inputs. If input users are None or empty list, this will remove existing ACL users if there. If input project_access flag is None, then default project access behavior is enabled. :returns: str acl_ref: Full HATEOAS reference to a secret or container ACL. :raises barbicanclient.exceptions.HTTPAuthError: 401 Responses :raises barbicanclient.exceptions.HTTPClientError: 4xx Responses :raises barbicanclient.exceptions.HTTPServerError: 5xx Responses """ LOG.debug('Submitting complete {0} ACL for href: {1}' .format(self.acl_type, self.entity_ref)) if not self.operation_acls: raise ValueError('ACL data for {0} is not provided.'. format(self._acl_type)) self.validate_input_ref() acl_dict = {} for per_op_acl in self.operation_acls: per_op_acl._validate_users_type() op_type = per_op_acl.operation_type acl_data = {} if per_op_acl.project_access is not None: acl_data['project-access'] = per_op_acl.project_access if per_op_acl.users is not None: acl_data['users'] = per_op_acl.users acl_dict[op_type] = acl_data response = self._api.put(self.acl_ref_relative, json=acl_dict) return response.json().get('acl_ref') def remove(self): """Remove Barbican ACLs setting defined for a secret or container :raises barbicanclient.exceptions.HTTPAuthError: 401 Responses :raises barbicanclient.exceptions.HTTPClientError: 4xx Responses """ self.validate_input_ref() LOG.debug('Removing ACL for {0} for href: {1}' .format(self.acl_type, self.entity_ref)) self._api.delete(self.acl_ref_relative) def load_acls_data(self): """Loads ACL entity from Barbican server using its acl_ref Clears the existing list of per operation ACL settings if there. Populates current ACL entity with ACL settings received from Barbican server. :raises barbicanclient.exceptions.HTTPAuthError: 401 Responses :raises barbicanclient.exceptions.HTTPClientError: 4xx Responses :raises barbicanclient.exceptions.HTTPServerError: 5xx Responses """ response = self._api.get(self.acl_ref_relative) del self.operation_acls[:] # clearing list for all of its references for op_type in response: acl_dict = response.get(op_type) proj_access = acl_dict.get('project-access') users = acl_dict.get('users') created = acl_dict.get('created') updated = acl_dict.get('updated') self.add_operation_acl(operation_type=op_type, project_access=proj_access, users=users, created=created, updated=updated) def validate_input_ref(self): res_title = self._acl_type.title() if not self.entity_ref: raise ValueError('{0} href is required.'.format(res_title)) if self._parent_entity_path in self.entity_ref: if '/acl' in self.entity_ref: raise ValueError('{0} ACL URI provided. Expecting {0} URI.' .format(res_title)) ref_type = self._acl_type else: raise ValueError('{0} URI is not specified.'.format(res_title)) base.validate_ref_and_return_uuid(self.entity_ref, ref_type) return ref_type @staticmethod def get_acl_ref_from_entity_ref(entity_ref): # Utility for converting entity ref to acl ref if entity_ref: entity_ref = entity_ref.rstrip('/') return '{0}/{1}'.format(entity_ref, ACL._resource_name) @staticmethod def get_acl_ref_from_entity_ref_relative(entity_ref, entity_type): # Utility for converting entity ref to acl ref if entity_ref: entity_ref = entity_ref.rstrip('/') return '{0}/{1}/{2}'.format(entity_type, entity_ref, ACL._resource_name) @staticmethod def identify_ref_type(entity_ref): # Utility for identifying ACL type from given entity URI. if not entity_ref: raise ValueError('Secret or container href is required.') if '/secrets' in entity_ref: ref_type = 'secret' elif '/containers' in entity_ref: ref_type = 'container' else: raise ValueError('Secret or container URI is not specified.') return ref_type class SecretACL(ACL): """ACL entity for a secret""" columns = ACLFormatter.columns + ("Secret ACL Ref",) _acl_type = 'secret' _parent_entity_path = '/secrets' @property def acl_type(self): return self._acl_type class ContainerACL(ACL): """ACL entity for a container""" columns = ACLFormatter.columns + ("Container ACL Ref",) _acl_type = 'container' _parent_entity_path = '/containers' @property def acl_type(self): return self._acl_type class ACLManager(base.BaseEntityManager): """Entity Manager for Secret or Container ACL entities""" acl_class_map = { 'secret': SecretACL, 'container': ContainerACL } def __init__(self, api): super(ACLManager, self).__init__(api, ACL._resource_name) def create(self, entity_ref=None, users=None, project_access=None, operation_type=DEFAULT_OPERATION_TYPE): """Factory method for creating `ACL` entity. `ACL` object returned by this method have not yet been stored in Barbican. Input entity_ref is used to determine whether ACL object type needs to be :class:`barbicanclient.acls.SecretACL` or :class:`barbicanclient.acls.ContainerACL`. :param str entity_ref: Full HATEOAS reference to a secret or container :param users: List of Keystone userid(s) to be used in ACL. :type users: List or None :param bool project_access: Flag indicating project access behavior :param str operation_type: Type indicating which class of Barbican operations this ACL is defined for e.g. 'read' operations :returns: ACL object instance :rtype: :class:`barbicanclient.v1.acls.SecretACL` or :class:`barbicanclient.v1.acls.ContainerACL` """ entity_type = ACL.identify_ref_type(entity_ref) entity_class = ACLManager.acl_class_map.get(entity_type) # entity_class cannot be None as entity_ref is already validated above return entity_class(api=self._api, entity_ref=entity_ref, users=users, project_access=project_access, operation_type=operation_type) def get(self, entity_ref): """Retrieve existing ACLs for a secret or container found in Barbican :param str entity_ref: Full HATEOAS reference to a secret or container. :returns: ACL entity object instance :rtype: :class:`barbicanclient.v1.acls.SecretACL` or :class:`barbicanclient.v1.acls.ContainerACL` :raises barbicanclient.exceptions.HTTPAuthError: 401 Responses :raises barbicanclient.exceptions.HTTPClientError: 4xx Responses """ entity = self._validate_acl_ref(entity_ref) LOG.debug('Getting ACL for {0} href: {1}' .format(entity.acl_type, entity.acl_ref)) entity.load_acls_data() return entity def _validate_acl_ref(self, entity_ref): if entity_ref is None: raise ValueError('Expected secret or container URI is not ' 'specified.') entity_ref = entity_ref.rstrip('/') entity_type = ACL.identify_ref_type(entity_ref) entity_class = ACLManager.acl_class_map.get(entity_type) acl_entity = entity_class(api=self._api, entity_ref=entity_ref) acl_entity.validate_input_ref() return acl_entity python-barbicanclient-4.10.0/barbicanclient/formatter.py0000664000175000017500000000363313620530200023406 0ustar zuulzuul00000000000000# 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. import prettytable class EntityFormatter(object): """Base Mixin class providing functions that format entities for display. Must be used in conjunction with a Formatter mixin that provides the function _get_formatted_data(). """ @staticmethod def _list_objects(obj_list): columns = [] data = (obj._get_generic_data() for obj in obj_list) if obj_list: columns = obj_list[0]._get_generic_columns() return columns, data def _get_generic_data(self): return self._get_formatted_data() def _get_generic_columns(self): return self.columns def _get_formatted_entity(self): return self.columns, self._get_formatted_data() def __str__(self): """Provides a common prettytable based format for object strings.""" data = self._get_formatted_data() table = prettytable.PrettyTable(field_names=('Field', 'Value'), print_empty=False) table.padding_width = 1 table.align['Field'] = 'l' table.align['Value'] = 'l' for name, value in zip(self.columns, data): table.add_row((name, value)) return table.get_string(fields=('Field', 'Value')) def to_dict(self): columns, data = self._get_formatted_entity() return dict((key, value) for (key, value) in zip(columns, data)) python-barbicanclient-4.10.0/barbicanclient/exceptions.py0000664000175000017500000000262213620530200023561 0ustar zuulzuul00000000000000# Copyright (c) 2015 Rackspace, Inc. # # 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. class BarbicanException(Exception): pass class PayloadException(BarbicanException): pass class UnsupportedVersion(BarbicanException): """User is trying to use an unsupported version of the API.""" pass class HTTPError(Exception): """Base exception for HTTP errors.""" def __init__(self, message, status_code=0): super(HTTPError, self).__init__(message) self.status_code = status_code class HTTPServerError(HTTPError): """Raised for 5xx responses from the server.""" pass class HTTPClientError(HTTPError): """Raised for 4xx responses from the server.""" pass class HTTPAuthError(HTTPError): """Raised for 401 Unauthorized responses from the server.""" def __init__(self, message, status_code=401): super(HTTPError, self).__init__(message, status_code) python-barbicanclient-4.10.0/barbicanclient/barbican_cli/0000775000175000017500000000000013620530306023423 5ustar zuulzuul00000000000000python-barbicanclient-4.10.0/barbicanclient/barbican_cli/__init__.py0000664000175000017500000000000013620530200025513 0ustar zuulzuul00000000000000python-barbicanclient-4.10.0/barbicanclient/barbican_cli/v1/0000775000175000017500000000000013620530306023751 5ustar zuulzuul00000000000000python-barbicanclient-4.10.0/barbicanclient/barbican_cli/v1/__init__.py0000664000175000017500000000000013620530200026041 0ustar zuulzuul00000000000000python-barbicanclient-4.10.0/barbicanclient/barbican_cli/v1/secrets.py0000664000175000017500000002105313620530200025765 0ustar zuulzuul00000000000000# 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 secrets. """ import os from cliff import command from cliff import lister from cliff import show from barbicanclient import secrets class DeleteSecret(command.Command): """Delete a secret by providing its URI.""" def get_parser(self, prog_name): parser = super(DeleteSecret, self).get_parser(prog_name) parser.add_argument('URI', help='The URI reference for the secret') return parser def take_action(self, args): self.app.client_manager.key_manager.secrets.delete(args.URI) class GetSecret(show.ShowOne): """Retrieve a secret by providing its URI.""" def get_parser(self, prog_name): parser = super(GetSecret, self).get_parser(prog_name) parser.add_argument('URI', help='The URI reference for the secret.') payload_params = parser.add_mutually_exclusive_group(required=False) payload_params.add_argument('--decrypt', '-d', help='if specified, retrieve the ' 'unencrypted secret data.', action='store_true') payload_params.add_argument('--payload', '-p', help='if specified, retrieve the ' 'unencrypted secret data.', action='store_true') payload_params.add_argument('--file', '-F', metavar='', help='if specified, save the payload to a ' 'new file with the given filename.') parser.add_argument('--payload_content_type', '-t', default='text/plain', help='the content type of the decrypted' ' secret (default: %(default)s).') return parser def take_action(self, args): if args.decrypt or args.payload or args.file: entity = self.app.client_manager.key_manager.secrets.get( args.URI, args.payload_content_type) return (('Payload',), (entity.payload,)) else: entity = self.app.client_manager.key_manager.secrets.get( secret_ref=args.URI) return entity._get_formatted_entity() def produce_output(self, parsed_args, column_names, data): if parsed_args.file: if os.path.exists(parsed_args.file): raise ValueError("ERROR: file already exists.") with open(parsed_args.file, 'wb') as f: f.write(data[0]) else: super(GetSecret, self).produce_output( parsed_args, column_names, data ) class UpdateSecret(command.Command): """Update a secret with no payload in Barbican.""" def get_parser(self, prog_name): parser = super(UpdateSecret, self).get_parser(prog_name) parser.add_argument('URI', help='The URI reference for the secret.') parser.add_argument('payload', help='the unencrypted secret') return parser def take_action(self, args): self.app.client_manager.key_manager.secrets.update(args.URI, args.payload) class ListSecret(lister.Lister): """List secrets.""" def get_parser(self, prog_name): parser = super(ListSecret, self).get_parser(prog_name) parser.add_argument('--limit', '-l', default=10, help='specify the limit to the number of items ' 'to list per page (default: %(default)s; ' 'maximum: 100)', type=int) parser.add_argument('--offset', '-o', default=0, help='specify the page offset ' '(default: %(default)s)', type=int) parser.add_argument('--name', '-n', default=None, help='specify the secret name ' '(default: %(default)s)') parser.add_argument('--algorithm', '-a', default=None, help='the algorithm filter for the list' '(default: %(default)s).') parser.add_argument('--bit-length', '-b', default=0, help='the bit length filter for the list' ' (default: %(default)s).', type=int) parser.add_argument('--mode', '-m', default=None, help='the algorithm mode filter for the' ' list (default: %(default)s).') parser.add_argument('--secret-type', '-s', default=None, help='specify the secret type ' '(default: %(default)s).') return parser def take_action(self, args): obj_list = self.app.client_manager.key_manager.secrets.list( limit=args.limit, offset=args.offset, name=args.name, algorithm=args.algorithm, mode=args.mode, bits=args.bit_length, secret_type=args.secret_type) return secrets.Secret._list_objects(obj_list) class StoreSecret(show.ShowOne): """Store a secret in Barbican.""" def get_parser(self, prog_name): parser = super(StoreSecret, self).get_parser(prog_name) parser.add_argument('--name', '-n', help='a human-friendly name.') parser.add_argument('--secret-type', '-s', default='opaque', help='the secret type; must be one of symmetric, ' 'public, private, certificate, passphrase, ' 'opaque (default)') parser.add_argument('--payload-content-type', '-t', help='the type/format of the provided ' 'secret data; "text/plain" is assumed to be ' 'UTF-8; required when --payload is ' 'supplied.') parser.add_argument('--payload-content-encoding', '-e', help='required if --payload-content-type is ' '"application/octet-stream".') parser.add_argument('--algorithm', '-a', default='aes', help='the algorithm (default: ' '%(default)s).') parser.add_argument('--bit-length', '-b', default=256, help='the bit length ' '(default: %(default)s).', type=int) parser.add_argument('--mode', '-m', default='cbc', help='the algorithm mode; used only for ' 'reference (default: %(default)s)') parser.add_argument('--expiration', '-x', help='the expiration time for the secret in ' 'ISO 8601 format.') payload_params = parser.add_mutually_exclusive_group(required=False) payload_params.add_argument('--payload', '-p', help='the unencrypted secret data.') payload_params.add_argument('--file', '-F', metavar='', help='file containing the secret payload') return parser def take_action(self, args): data = None if args.file: with open(args.file, 'rb') as f: data = f.read() entity = self.app.client_manager.key_manager.secrets.create( name=args.name, payload=args.payload or data, payload_content_type=args.payload_content_type, payload_content_encoding=args.payload_content_encoding, algorithm=args.algorithm, bit_length=args.bit_length, mode=args.mode, expiration=args.expiration, secret_type=args.secret_type) entity.store() return entity._get_formatted_entity() python-barbicanclient-4.10.0/barbicanclient/barbican_cli/v1/orders.py0000664000175000017500000001374513620530200025624 0ustar zuulzuul00000000000000# 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 orders. """ from cliff import command from cliff import lister from cliff import show class CreateOrder(show.ShowOne): """Create a new order.""" def get_parser(self, prog_name): parser = super(CreateOrder, self).get_parser(prog_name) parser.add_argument('type', help='the type of the order ' '(key, asymmetric, certificate)' ' to create.') parser.add_argument('--name', '-n', help='a human-friendly name.') parser.add_argument('--algorithm', '-a', default='aes', help='the algorithm to be used with the ' 'requested key (default: ' '%(default)s).') parser.add_argument('--bit-length', '-b', default=256, help='the bit length of the requested' ' secret key (default: %(default)s).', type=int) parser.add_argument('--mode', '-m', default='cbc', help='the algorithm mode to be used with ' 'the requested key (default: %(default)s).') parser.add_argument('--payload-content-type', '-t', default='application/octet-stream', help='the type/format of the secret to be' ' generated (default: %(default)s).') parser.add_argument('--expiration', '-x', help='the expiration ' 'time for the secret in ISO 8601 format.') parser.add_argument('--request-type', help='the type of the certificate request.') parser.add_argument('--subject-dn', help='the subject of the certificate.') parser.add_argument('--source-container-ref', help='the source of the certificate when using ' 'stored-key requests.') parser.add_argument('--ca-id', help='the identifier of the CA to use for the ' 'certificate request.') parser.add_argument('--profile', help='the profile of certificate to use.') parser.add_argument('--request-file', help='the file containing the CSR.') return parser def take_action(self, args): if args.type == 'certificate': request_data = None if args.request_file: try: request_data = open(args.request_file, 'r').read() except IOError: raise ValueError( 'Couldn\'t read request file %s.' % args.request_file) entity = self.app.client_manager.key_manager.orders.create( name=args.name, type=args.type, subject_dn=args.subject_dn, request_type=args.request_type, source_container_ref=args.source_container_ref, ca_id=args.ca_id, profile=args.profile, request_data=request_data) else: entity = self.app.client_manager.key_manager.orders.create( name=args.name, type=args.type, payload_content_type=args.payload_content_type, algorithm=args.algorithm, bit_length=args.bit_length, mode=args.mode, expiration=args.expiration) entity.submit() return entity._get_formatted_entity() class DeleteOrder(command.Command): """Delete an order by providing its href.""" def get_parser(self, prog_name): parser = super(DeleteOrder, self).get_parser(prog_name) parser.add_argument('URI', help='The URI reference for the order') return parser def take_action(self, args): self.app.client_manager.key_manager.orders.delete(args.URI) class GetOrder(show.ShowOne): """Retrieve an order by providing its URI.""" def get_parser(self, prog_name): parser = super(GetOrder, self).get_parser(prog_name) parser.add_argument('URI', help='The URI reference order.') return parser def take_action(self, args): entity = self.app.client_manager.key_manager.orders.get( order_ref=args.URI) return entity._get_formatted_entity() class ListOrder(lister.Lister): """List orders.""" def get_parser(self, prog_name): parser = super(ListOrder, self).get_parser(prog_name) parser.add_argument('--limit', '-l', default=10, help='specify the limit to the number of items ' 'to list per page (default: %(default)s; ' 'maximum: 100)', type=int) parser.add_argument('--offset', '-o', default=0, help='specify the page offset ' '(default: %(default)s)', type=int) return parser def take_action(self, args): obj_list = self.app.client_manager.key_manager.orders.list( args.limit, args.offset) if not obj_list: return [], [] columns = obj_list[0]._get_generic_columns() data = (obj._get_generic_data() for obj in obj_list) return columns, data python-barbicanclient-4.10.0/barbicanclient/barbican_cli/v1/containers.py0000664000175000017500000001333513620530200026466 0ustar zuulzuul00000000000000# 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 containers. """ from cliff import command from cliff import lister from cliff import show from barbicanclient.v1.containers import CertificateContainer from barbicanclient.v1.containers import Container from barbicanclient.v1.containers import RSAContainer class DeleteContainer(command.Command): """Delete a container by providing its href.""" def get_parser(self, prog_name): parser = super(DeleteContainer, self).get_parser(prog_name) parser.add_argument('URI', help='The URI reference for the container') return parser def take_action(self, args): self.app.client_manager.key_manager.containers.delete(args.URI) class GetContainer(show.ShowOne): """Retrieve a container by providing its URI.""" def get_parser(self, prog_name): parser = super(GetContainer, self).get_parser(prog_name) parser.add_argument('URI', help='The URI reference for the container.') return parser def take_action(self, args): entity = self.app.client_manager.key_manager.containers.get( args.URI) return entity._get_formatted_entity() class ListContainer(lister.Lister): """List containers.""" def get_parser(self, prog_name): parser = super(ListContainer, self).get_parser(prog_name) parser.add_argument('--limit', '-l', default=10, help='specify the limit to the number of items ' 'to list per page (default: %(default)s; ' 'maximum: 100)', type=int) parser.add_argument('--offset', '-o', default=0, help='specify the page offset ' '(default: %(default)s)', type=int) parser.add_argument('--name', '-n', default=None, help='specify the container name ' '(default: %(default)s)') parser.add_argument('--type', '-t', default=None, help='specify the type filter for the list ' '(default: %(default)s).') return parser def take_action(self, args): obj_list = self.app.client_manager.key_manager.containers.list( args.limit, args.offset, args.name, args.type) return Container._list_objects(obj_list) class CreateContainer(show.ShowOne): """Store a container in Barbican.""" def get_parser(self, prog_name): parser = super(CreateContainer, self).get_parser(prog_name) parser.add_argument('--name', '-n', help='a human-friendly name.') parser.add_argument('--type', default='generic', help='type of container to create (default: ' '%(default)s).') parser.add_argument('--secret', '-s', action='append', help='one secret to store in a container ' '(can be set multiple times). Example: ' '--secret "private_key=' 'https://url.test/v1/secrets/1-2-3-4"') return parser def take_action(self, args): client = self.app.client_manager.key_manager container_type = client.containers._container_map.get(args.type) if not container_type: raise ValueError('Invalid container type specified.') secret_refs = CreateContainer._parse_secrets(args.secret) if container_type is RSAContainer: public_key_ref = secret_refs.get('public_key') private_key_ref = secret_refs.get('private_key') private_key_pass_ref = secret_refs.get('private_key_passphrase') entity = RSAContainer( api=client.containers._api, name=args.name, public_key_ref=public_key_ref, private_key_ref=private_key_ref, private_key_passphrase_ref=private_key_pass_ref, ) elif container_type is CertificateContainer: certificate_ref = secret_refs.get('certificate') intermediates_ref = secret_refs.get('intermediates') private_key_ref = secret_refs.get('private_key') private_key_pass_ref = secret_refs.get('private_key_passphrase') entity = CertificateContainer( api=client.containers._api, name=args.name, certificate_ref=certificate_ref, intermediates_ref=intermediates_ref, private_key_ref=private_key_ref, private_key_passphrase_ref=private_key_pass_ref, ) else: entity = container_type(api=client.containers._api, name=args.name, secret_refs=secret_refs) entity.store() return entity._get_formatted_entity() @staticmethod def _parse_secrets(secrets): if not secrets: raise ValueError("Must supply at least one secret.") return dict( (s.split('=')[0], s.split('=')[1]) for s in secrets if s.count('=') is 1 ) python-barbicanclient-4.10.0/barbicanclient/barbican_cli/v1/cas.py0000664000175000017500000000416013620530200025063 0ustar zuulzuul00000000000000# 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 cas. """ from cliff import lister from cliff import show from barbicanclient.v1 import cas class GetCA(show.ShowOne): """Retrieve a CA by providing its URI.""" def get_parser(self, prog_name): parser = super(GetCA, self).get_parser(prog_name) parser.add_argument('URI', help='The URI reference for the CA.') return parser def take_action(self, args): entity = self.app.client_manager.key_manager.cas.get(ca_ref=args.URI) return entity._get_formatted_entity() class ListCA(lister.Lister): """List CAs.""" def get_parser(self, prog_name): parser = super(ListCA, self).get_parser(prog_name) parser.add_argument('--limit', '-l', default=10, help='specify the limit to the number of items ' 'to list per page (default: %(default)s; ' 'maximum: 100)', type=int) parser.add_argument('--offset', '-o', default=0, help='specify the page offset ' '(default: %(default)s)', type=int) parser.add_argument('--name', '-n', default=None, help='specify the ca name ' '(default: %(default)s)') return parser def take_action(self, args): obj_list = self.app.client_manager.key_manager.cas.list( args.limit, args.offset, args.name) return cas.CA._list_objects(obj_list) python-barbicanclient-4.10.0/barbicanclient/barbican_cli/v1/acls.py0000664000175000017500000002455113620530200025245 0ustar zuulzuul00000000000000# 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.v1 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[:] # Python sets are not JSON serializable. # Cast acl_users to a list. server_acl.users = list(acl_users) server_entity.submit() # apply changes to server server_entity.load_acls_data() return self.get_acls_as_lister(server_entity) python-barbicanclient-4.10.0/barbicanclient/osc_plugin.py0000664000175000017500000000311213620530200023535 0ustar zuulzuul00000000000000# 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. """OpenStackClient plugin for Key Manager service.""" from barbicanclient import client DEFAULT_API_VERSION = '1' API_VERSION_OPTION = 'os_key_manager_api_version' API_NAME = 'key_manager' API_VERSIONS = { '1': 'barbicanclient.client.Client', } def make_client(instance): """Returns a Barbican service client.""" return client.Client(session=instance.session, region_name=instance._region_name, interface=instance.interface) def build_option_parser(parser): """Hook to add global options.""" parser.add_argument('--os-key-manager-api-version', metavar='', default=client.env( 'OS_KEY_MANAGER_API_VERSION', default=DEFAULT_API_VERSION), help=('Barbican API version, default=' + DEFAULT_API_VERSION + ' (Env: OS_KEY_MANAGER_API_VERSION)')) return parser python-barbicanclient-4.10.0/barbicanclient/tests/0000775000175000017500000000000013620530306022175 5ustar zuulzuul00000000000000python-barbicanclient-4.10.0/barbicanclient/tests/test_base.py0000664000175000017500000000421513620530200024513 0ustar zuulzuul00000000000000# Copyright (c) 2017 # # 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. import testtools import uuid import barbicanclient from barbicanclient import base from barbicanclient import version class TestValidateRef(testtools.TestCase): def test_valid_ref(self): secret_uuid = uuid.uuid4() ref = 'http://localhost/' + str(secret_uuid) self.assertEqual(secret_uuid, base.validate_ref_and_return_uuid(ref, 'Thing')) def test_valid_uuid(self): secret_uuid = uuid.uuid4() self.assertEqual(secret_uuid, base.validate_ref_and_return_uuid(str(secret_uuid), 'Thing')) def test_invalid_uuid(self): ref = 'http://localhost/not_a_uuid' self.assertRaises(ValueError, base.validate_ref_and_return_uuid, ref, 'Thing') def test_censored_copy(self): d1 = {'a': '1', 'password': 'my_password', 'payload': 'my_key', 'b': '2'} d2 = base.censored_copy(d1, None) self.assertEqual(d1, d2, 'd2 contents are unchanged') self.assertFalse(d1 is d2, 'd1 and d2 are different instances') d3 = base.censored_copy(d1, ['payload']) self.assertNotEqual(d1, d3, 'd3 has redacted payload value') self.assertNotEqual(d3['payload'], 'my_key', 'no key in payload') def test_module_version(self): self.assertTrue(hasattr(barbicanclient, '__version__')) # Test forward compatibility, please remove the case when all reference # switch to barbicanclient.__version__ self.assertTrue(hasattr(version, '__version__')) python-barbicanclient-4.10.0/barbicanclient/tests/__init__.py0000664000175000017500000000000013620530200024265 0ustar zuulzuul00000000000000python-barbicanclient-4.10.0/barbicanclient/tests/test_barbican.py0000664000175000017500000002776213620530200025356 0ustar zuulzuul00000000000000# Copyright (c) 2013 Rackspace, Inc. # # 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. import six from barbicanclient import barbican as barb from barbicanclient.barbican import Barbican from barbicanclient import client from barbicanclient import exceptions from barbicanclient.tests import keystone_client_fixtures from barbicanclient.tests import test_client class WhenTestingBarbicanCLI(test_client.BaseEntityResource): def setUp(self): self._setUp('barbican') self.captured_stdout = six.StringIO() self.captured_stderr = six.StringIO() self.barbican = Barbican( stdout=self.captured_stdout, stderr=self.captured_stderr ) self.parser = self.barbican.build_option_parser('desc', 'vers') def assert_client_raises(self, args, message): argv, remainder = self.parser.parse_known_args(args.split()) e = self.assertRaises( Exception, self.barbican.create_client, argv ) self.assertIn(message, str(e)) def create_and_assert_client(self, args): argv, remainder = self.parser.parse_known_args(args.split()) client = self.barbican.create_client(argv) self.assertIsNotNone(client) return client def test_should_show_usage_with_help_flag(self): e = self.assertRaises(SystemExit, self.barbican.run, ['-h']) self.assertEqual(0, e.code) self.assertIn('usage', self.captured_stdout.getvalue()) def test_should_show_usage_with_no_args(self): exit_code = self.barbican.run([]) self.assertEqual(1, exit_code) self.assertIn('usage', self.captured_stderr.getvalue()) def test_should_error_if_noauth_and_authurl_both_specified(self): args = "--no-auth --os-auth-url http://localhost:5000/v3" message = ( 'ERROR: argument --os-auth-url/-A: not allowed with ' 'argument --no-auth/-N' ) self.assert_client_raises(args, message) def _expect_error_with_invalid_noauth_args(self, args): expected_err_msg = ( 'ERROR: please specify --endpoint ' 'and --os-project-id (or --os-tenant-id)' ) self.assert_client_raises(args, expected_err_msg) def test_should_error_if_noauth_and_missing_endpoint_tenantid_args(self): self._expect_error_with_invalid_noauth_args("--no-auth secret list") self._expect_error_with_invalid_noauth_args( "--no-auth --endpoint http://xyz secret list") self._expect_error_with_invalid_noauth_args( "--no-auth --os-tenant-id 123 secret list") self._expect_error_with_invalid_noauth_args( "--no-auth --os-project-id 123 secret list") def test_should_succeed_if_noauth_with_valid_args_specified(self): args = ( '--no-auth --endpoint {0} --os-tenant-id {1}' 'secret list'.format(self.endpoint, self.project_id) ) list_secrets_url = '{0}/v1/secrets'.format(self.endpoint) self.responses.get(list_secrets_url, json={"secrets": [], "total": 0}) client = self.create_and_assert_client(args) secret_list = client.secrets.list() self.assertTrue(self.responses._adapter.called) self.assertEqual(1, self.responses._adapter.call_count) self.assertEqual([], secret_list) def test_should_error_if_required_keystone_auth_arguments_are_missing( self): expected_error_msg = ( 'ERROR: please specify the following --os-project-id or' ' (--os-project-name and --os-project-domain-name) or ' ' (--os-project-name and --os-project-domain-id)' ) self.assert_client_raises( '--os-auth-url http://localhost:35357/v2.0 secret list', expected_error_msg) self.assert_client_raises( '--os-auth-url http://localhost:35357/v2.0 --os-username barbican ' '--os-password barbican secret list', expected_error_msg ) def test_check_auth_arguments_v2(self): args = ("--os-username 'bob' --os-password 'jan' --os-auth-url 'boop'" " --os-tenant-id 123 --os-identity-api-version '2.0'") argv, remainder = self.parser.parse_known_args(args.split()) api_version = argv.os_identity_api_version barbican = Barbican() response = barbican.check_auth_arguments(argv, api_version) self.assertTrue(response) def test_should_fail_check_auth_arguments_v2(self): args = ("--os-username bob --os-password jan --os-auth-url boop" " --os-identity-api-version 2.0") message = 'ERROR: please specify --os-tenant-id or --os-tenant-name' argv, remainder = self.parser.parse_known_args(args.split()) api_version = argv.os_identity_api_version e = self.assertRaises( Exception, self.barbican.check_auth_arguments, argv, api_version, True ) self.assertIn(message, str(e)) def test_should_fail_create_client_with_no_auth_url(self): args = '--os-auth-token 1234567890 --os-tenant-id 123' message = 'ERROR: please specify --os-auth-url' argv, remainder = self.parser.parse_known_args(args.split()) e = self.assertRaises( Exception, self.barbican.create_client, argv ) self.assertIn(message, str(e)) def test_should_fail_missing_credentials(self): message = 'ERROR: please specify authentication credentials' args = '' argv, remainder = self.parser.parse_known_args(args.split()) e = self.assertRaises( Exception, self.barbican.create_client, argv ) self.assertIn(message, str(e)) def test_main(self): args = '' response = barb.main(args) self.assertEqual(1, response) def test_default_endpoint_filter_kwargs_set_correctly(self): auth_args = ('--no-auth --endpoint http://barbican_endpoint:9311/v1 ' '--os-project-id project1') argv, remainder = self.parser.parse_known_args(auth_args.split()) barbican_client = self.barbican.create_client(argv) httpclient = barbican_client.secrets._api self.assertEqual(client._DEFAULT_SERVICE_INTERFACE, httpclient.interface) self.assertEqual(client._DEFAULT_SERVICE_TYPE, httpclient.service_type) self.assertEqual(client._DEFAULT_API_VERSION, httpclient.version) self.assertIsNone(httpclient.service_name) def test_endpoint_filter_kwargs_set_correctly(self): auth_args = ('--no-auth --endpoint http://barbican_endpoint:9311 ' '--os-project-id project1') endpoint_filter_args = ('--interface private ' '--service-type custom-type ' '--service-name Burrbican ' '--region-name RegionTwo ' '--barbican-api-version v1') args = auth_args + ' ' + endpoint_filter_args argv, remainder = self.parser.parse_known_args(args.split()) barbican_client = self.barbican.create_client(argv) httpclient = barbican_client.secrets._api self.assertEqual('private', httpclient.interface) self.assertEqual('custom-type', httpclient.service_type) self.assertEqual('Burrbican', httpclient.service_name) self.assertEqual('RegionTwo', httpclient.region_name) self.assertEqual('v1', httpclient.version) def test_should_fail_if_provide_unsupported_api_version(self): auth_args = ('--no-auth --endpoint http://barbican_endpoint:9311/v1 ' '--os-project-id project1') endpoint_filter_args = ('--interface private ' '--service-type custom-type ' '--service-name Burrbican ' '--region-name RegionTwo ' '--barbican-api-version v2') args = auth_args + ' ' + endpoint_filter_args argv, remainder = self.parser.parse_known_args(args.split()) self.assertRaises(exceptions.UnsupportedVersion, self.barbican.create_client, argv) def test_should_prevent_mutual_exclusive_file_opt(self): args = ( '--no-auth --endpoint {0} --os-tenant-id {1}' '--file foo --payload' 'secret get'.format(self.endpoint, self.project_id) ) list_secrets_url = '{0}/v1/secrets'.format(self.endpoint) self.responses.get(list_secrets_url, json={"secrets": [], "total": 0}) client = self.create_and_assert_client(args) secret_list = client.secrets.list() self.assertTrue(self.responses._adapter.called) self.assertEqual(1, self.responses._adapter.call_count) self.assertEqual([], secret_list) def test_insecure_true_kwargs_set_correctly(self): auth_args = ('--no-auth --endpoint https://barbican_endpoint:9311/v1 ' '--os-project-id project1') endpoint_filter_args = ('--interface public ' '--service-type custom-type ' '--service-name Burrbican ' '--region-name RegionTwo ' '--barbican-api-version v1') args = auth_args + ' ' + endpoint_filter_args argv, remainder = self.parser.parse_known_args(args.split()) argv.insecure = True argv.os_identity_api_version = '2.0' argv.os_tenant_name = 'my_tenant_name' barbican_client = self.barbican.create_client(argv) httpclient = barbican_client.secrets._api self.assertFalse(httpclient.session.verify) def test_cafile_certfile_keyfile_kwargs_set_correctly(self): auth_args = ('no_auth ' '--os-auth-url https://keystone_endpoint:5000/v2 ' '--os-auth-token f554ccb5-e157-4824-b67b-d139c87bc555 ' '--os-project-id project1') endpoint_filter_args = ('--interface public ' '--service-type custom-type ' '--service-name Burrbican ' '--region-name RegionTwo ' '--barbican-api-version v1') args = auth_args + ' ' + endpoint_filter_args argv, remainder = self.parser.parse_known_args(args.split()) argv.os_cacert = 'ca.pem' argv.os_cert = 'cert.pem' argv.os_key = 'key.pem' argv.os_identity_api_version = '2.0' argv.os_tenant_name = 'my_tenant_name' barbican_client = self.barbican.create_client(argv) httpclient = barbican_client.secrets._api self.assertEqual('ca.pem', httpclient.session.verify) self.assertEqual('cert.pem', httpclient.session.cert[0]) self.assertEqual('key.pem', httpclient.session.cert[1]) class TestBarbicanWithKeystonePasswordAuth( keystone_client_fixtures.KeystoneClientFixture): def setUp(self): super(TestBarbicanWithKeystonePasswordAuth, self).setUp() self.test_arguments = { '--os-username': 'some_user', '--os-password': 'some_pass', } class TestBarbicanWithKeystoneTokenAuth( keystone_client_fixtures.KeystoneClientFixture): def setUp(self): super(TestBarbicanWithKeystoneTokenAuth, self).setUp() self.test_arguments = { '--os-auth-token': 'some_token', '--os-project-id': 'some_project_id', } python-barbicanclient-4.10.0/barbicanclient/tests/test_client.py0000664000175000017500000002710713620530200025064 0ustar zuulzuul00000000000000# Copyright (c) 2013 Rackspace, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. from keystoneauth1 import session import mock from requests_mock.contrib import fixture import testtools from barbicanclient import client from barbicanclient import exceptions class TestClient(testtools.TestCase): def setUp(self): super(TestClient, self).setUp() self.responses = self.useFixture(fixture.Fixture()) self.endpoint = 'http://localhost:9311' self.project_id = 'project_id' self.session = session.Session() self.httpclient = client._HTTPClient(session=self.session, endpoint=self.endpoint, project_id=self.project_id) class WhenTestingClientInit(TestClient): def test_api_version_is_appended_to_endpoint(self): c = client._HTTPClient(session=self.session, endpoint=self.endpoint, project_id=self.project_id) self.assertEqual('http://localhost:9311/v1', c.endpoint_override) def test_default_headers_are_empty(self): c = client._HTTPClient(session=self.session, endpoint=self.endpoint) self.assertIsInstance(c._default_headers, dict) self.assertFalse(bool(c._default_headers)) def test_project_id_is_added_to_default_headers(self): c = client._HTTPClient(session=self.session, endpoint=self.endpoint, project_id=self.project_id) self.assertIn('X-Project-Id', c._default_headers.keys()) self.assertEqual(self.project_id, c._default_headers['X-Project-Id']) def test_error_thrown_when_no_session_and_no_endpoint(self): self.assertRaises(ValueError, client.Client, **{"project_id": self.project_id}) def test_error_thrown_when_no_session_and_no_project_id(self): self.assertRaises(ValueError, client.Client, **{"endpoint": self.endpoint}) def test_endpoint_override_starts_with_endpoint_url(self): c = client._HTTPClient(session=self.session, endpoint=self.endpoint, project_id=self.project_id) self.assertTrue(c.endpoint_override.startswith(self.endpoint)) def test_endpoint_override_ends_with_default_api_version(self): c = client._HTTPClient(session=self.session, endpoint=self.endpoint, project_id=self.project_id) self.assertTrue( c.endpoint_override.endswith(client._DEFAULT_API_VERSION)) class WhenTestingClientPost(TestClient): def setUp(self): super(WhenTestingClientPost, self).setUp() self.httpclient = client._HTTPClient(session=self.session, endpoint=self.endpoint) self.href = self.endpoint + '/v1/secrets/' self.post_mock = self.responses.post(self.href, json={}) def test_post_normalizes_url_with_traling_slash(self): self.httpclient.post(path='secrets', json={'test_data': 'test'}) self.assertTrue(self.post_mock.last_request.url.endswith('/')) def test_post_includes_content_type_header_of_application_json(self): self.httpclient.post(path='secrets', json={'test_data': 'test'}) self.assertEqual('application/json', self.post_mock.last_request.headers['Content-Type']) def test_post_includes_default_headers(self): self.httpclient._default_headers = {'Test-Default-Header': 'test'} self.httpclient.post(path='secrets', json={'test_data': 'test'}) self.assertEqual( 'test', self.post_mock.last_request.headers['Test-Default-Header']) def test_post_checks_status_code(self): self.httpclient._check_status_code = mock.MagicMock() self.httpclient.post(path='secrets', json={'test_data': 'test'}) self.httpclient._check_status_code.assert_has_calls([]) class WhenTestingClientPut(TestClient): def setUp(self): super(WhenTestingClientPut, self).setUp() self.httpclient = client._HTTPClient(session=self.session, endpoint=self.endpoint) self.href = 'http://test_href/' self.put_mock = self.responses.put(self.href, status_code=204) def test_put_uses_href_as_is(self): self.httpclient.put(self.href) self.assertTrue(self.put_mock.called) def test_put_passes_data(self): data = "test" self.httpclient.put(self.href, data=data) self.assertEqual("test", self.put_mock.last_request.text) def test_put_includes_default_headers(self): self.httpclient._default_headers = {'Test-Default-Header': 'test'} self.httpclient.put(self.href) self.assertEqual( 'test', self.put_mock.last_request.headers['Test-Default-Header']) def test_put_checks_status_code(self): self.httpclient._check_status_code = mock.MagicMock() self.httpclient.put(self.href, data='test') self.httpclient._check_status_code.assert_has_calls([]) class WhenTestingClientGet(TestClient): def setUp(self): super(WhenTestingClientGet, self).setUp() self.httpclient = client._HTTPClient(session=self.session, endpoint=self.endpoint) self.headers = dict() self.href = 'http://test_href/' self.get_mock = self.responses.get(self.href, json={}) def test_get_uses_href_as_is(self): self.httpclient.get(self.href) self.assertEqual(self.href, self.get_mock.last_request.url) def test_get_passes_params(self): params = {'test': 'test1'} self.httpclient.get(self.href, params=params) self.assertEqual(self.href, self.get_mock.last_request.url.split('?')[0]) self.assertEqual(['test1'], self.get_mock.last_request.qs['test']) def test_get_includes_accept_header_of_application_json(self): self.httpclient.get(self.href) self.assertEqual('application/json', self.get_mock.last_request.headers['Accept']) def test_get_includes_default_headers(self): self.httpclient._default_headers = {'Test-Default-Header': 'test'} self.httpclient.get(self.href) self.assertEqual( 'test', self.get_mock.last_request.headers['Test-Default-Header']) def test_get_checks_status_code(self): self.httpclient._check_status_code = mock.MagicMock() self.httpclient.get(self.href) self.httpclient._check_status_code.assert_has_calls([]) def test_get_raw_uses_href_as_is(self): self.httpclient._get_raw(self.href, headers=self.headers) self.assertEqual(self.href, self.get_mock.last_request.url) def test_get_raw_passes_headers(self): self.httpclient._get_raw(self.href, headers={'test': 'test'}) self.assertEqual('test', self.get_mock.last_request.headers['test']) def test_get_raw_includes_default_headers(self): self.httpclient._default_headers = {'Test-Default-Header': 'test'} self.httpclient._get_raw(self.href, headers=self.headers) self.assertIn('Test-Default-Header', self.get_mock.last_request.headers) def test_get_raw_checks_status_code(self): self.httpclient._check_status_code = mock.MagicMock() self.httpclient._get_raw(self.href, headers=self.headers) self.httpclient._check_status_code.assert_has_calls([]) class WhenTestingClientDelete(TestClient): def setUp(self): super(WhenTestingClientDelete, self).setUp() self.httpclient = client._HTTPClient(session=self.session, endpoint=self.endpoint) self.href = 'http://test_href/' self.del_mock = self.responses.delete(self.href, status_code=204) def test_delete_uses_href_as_is(self): self.httpclient.delete(self.href) self.assertTrue(self.del_mock.called) def test_delete_passes_json(self): json = {"test": "test"} self.httpclient.delete(self.href, json=json) self.assertEqual('{"test": "test"}', self.del_mock.last_request.text) def test_delete_includes_default_headers(self): self.httpclient._default_headers = {'Test-Default-Header': 'test'} self.httpclient.delete(self.href) self.assertEqual( 'test', self.del_mock.last_request.headers['Test-Default-Header']) def test_delete_checks_status_code(self): self.httpclient._check_status_code = mock.MagicMock() self.httpclient.delete(self.href) self.httpclient._check_status_code.assert_has_calls([]) class WhenTestingCheckStatusCodes(TestClient): def test_raises_http_auth_error_for_401_response(self): resp = mock.MagicMock() resp.status_code = 401 self.assertRaises(exceptions.HTTPAuthError, self.httpclient._check_status_code, resp) def test_raises_http_server_error_for_500_response(self): resp = mock.MagicMock() resp.status_code = 500 self.assertRaises(exceptions.HTTPServerError, self.httpclient._check_status_code, resp) def test_raises_http_client_error_for_400_response(self): resp = mock.MagicMock() resp.status_code = 400 self.assertRaises(exceptions.HTTPClientError, self.httpclient._check_status_code, resp) class WhenTestingGetErrorMessage(TestClient): def test_gets_error_message_from_title_in_json(self): resp = mock.MagicMock() resp.json.return_value = {'title': 'test_text'} msg = self.httpclient._get_error_message(resp) self.assertEqual('test_text', msg) def test_gets_error_message_from_content_when_no_json(self): resp = mock.MagicMock() resp.json.side_effect = ValueError() resp.content = content = 'content' msg = self.httpclient._get_error_message(resp) self.assertEqual(content, msg) def test_gets_error_message_from_description_in_json(self): resp = mock.MagicMock() resp.json.return_value = {'title': 'test_text', 'description': 'oopsie'} msg = self.httpclient._get_error_message(resp) self.assertEqual('test_text: oopsie', msg) class BaseEntityResource(testtools.TestCase): def _setUp(self, entity, entity_id='abcd1234-eabc-5678-9abc-abcdef012345'): super(BaseEntityResource, self).setUp() self.responses = self.useFixture(fixture.Fixture()) self.endpoint = 'http://localhost:9311' self.project_id = '1234567' self.entity = entity self.entity_id = entity_id self.entity_base = self.endpoint + "/v1/" + self.entity self.entity_href = self.entity_base + "/" + self.entity_id self.entity_payload_href = self.entity_href + "/payload" self.client = client.Client(endpoint=self.endpoint, project_id=self.project_id) python-barbicanclient-4.10.0/barbicanclient/tests/keystone_client_fixtures.py0000664000175000017500000002365313620530200027701 0ustar zuulzuul00000000000000# 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. import copy from oslo_serialization import jsonutils from oslo_utils import uuidutils from requests_mock.contrib import fixture import testtools import barbicanclient.barbican # these are copied from python-keystoneclient tests BASE_HOST = 'http://keystone.example.com' BASE_URL = "%s:5000/" % BASE_HOST UPDATED = '2013-03-06T00:00:00Z' V2_URL = "%sv2.0" % BASE_URL V2_DESCRIBED_BY_HTML = {'href': 'http://docs.openstack.org/api/' 'openstack-identity-service/2.0/content/', 'rel': 'describedby', 'type': 'text/html'} V2_DESCRIBED_BY_PDF = {'href': 'http://docs.openstack.org/api/openstack-ident' 'ity-service/2.0/identity-dev-guide-2.0.pdf', 'rel': 'describedby', 'type': 'application/pdf'} V2_VERSION = {'id': 'v2.0', 'links': [{'href': V2_URL, 'rel': 'self'}, V2_DESCRIBED_BY_HTML, V2_DESCRIBED_BY_PDF], 'status': 'stable', 'updated': UPDATED} V3_URL = "%sv3" % BASE_URL V3_MEDIA_TYPES = [{'base': 'application/json', 'type': 'application/vnd.openstack.identity-v3+json'}, {'base': 'application/xml', 'type': 'application/vnd.openstack.identity-v3+xml'}] V3_VERSION = {'id': 'v3', 'links': [{'href': V3_URL, 'rel': 'self'}], 'media-types': V3_MEDIA_TYPES, 'status': 'stable', 'updated': UPDATED} def _create_version_list(versions): return jsonutils.dumps({'versions': {'values': versions}}) def _create_single_version(version): return jsonutils.dumps({'version': version}) V3_VERSION_LIST = _create_version_list([V3_VERSION, V2_VERSION]) V2_VERSION_LIST = _create_version_list([V2_VERSION]) V3_VERSION_ENTRY = _create_single_version(V3_VERSION) V2_VERSION_ENTRY = _create_single_version(V2_VERSION) BARBICAN_ENDPOINT = 'http://www.barbican.com/v1' def _get_normalized_token_data(**kwargs): ref = copy.deepcopy(kwargs) # normalized token data ref['user_id'] = ref.get('user_id', uuidutils.generate_uuid(dashed=False)) ref['username'] = ref.get('username', uuidutils.generate_uuid(dashed=False)) ref['project_id'] = ref.get( 'project_id', ref.get('tenant_id', uuidutils.generate_uuid(dashed=False))) ref['project_name'] = ref.get( 'tenant_name', ref.get('tenant_name', uuidutils.generate_uuid(dashed=False))) ref['user_domain_id'] = ref.get( 'user_domain_id', uuidutils.generate_uuid(dashed=False)) ref['user_domain_name'] = ref.get( 'user_domain_name', uuidutils.generate_uuid(dashed=False)) ref['project_domain_id'] = ref.get( 'project_domain_id', uuidutils.generate_uuid(dashed=False)) ref['project_domain_name'] = ref.get( 'project_domain_name', uuidutils.generate_uuid(dashed=False)) ref['roles'] = ref.get( 'roles', [{'name': uuidutils.generate_uuid(dashed=False), 'id': uuidutils.generate_uuid(dashed=False)}]) ref['roles_link'] = ref.get('roles_link', []) ref['barbican_url'] = ref.get('barbican_url', BARBICAN_ENDPOINT) return ref def generate_v2_project_scoped_token(**kwargs): """Generate a Keystone V2 token based on auth request.""" ref = _get_normalized_token_data(**kwargs) o = {'access': {'token': {'id': uuidutils.generate_uuid(dashed=False), 'expires': '2099-05-22T00:02:43.941430Z', 'issued_at': '2013-05-21T00:02:43.941473Z', 'tenant': {'enabled': True, 'id': ref.get('project_id'), 'name': ref.get('project_id') } }, 'user': {'id': ref.get('user_id'), 'name': uuidutils.generate_uuid(dashed=False), 'username': ref.get('username'), 'roles': ref.get('roles'), 'roles_links': ref.get('roles_links') } }} # we only care about Barbican and Keystone endpoints o['access']['serviceCatalog'] = [ {'endpoints': [ {'publicURL': ref.get('barbican_url'), 'id': uuidutils.generate_uuid(dashed=False), 'region': 'RegionOne' }], 'endpoints_links': [], 'name': 'Barbican', 'type': 'keystore'}, {'endpoints': [ {'publicURL': ref.get('auth_url'), 'adminURL': ref.get('auth_url'), 'id': uuidutils.generate_uuid(dashed=False), 'region': 'RegionOne' }], 'endpoint_links': [], 'name': 'keystone', 'type': 'identity'}] return o def generate_v3_project_scoped_token(**kwargs): """Generate a Keystone V3 token based on auth request.""" ref = _get_normalized_token_data(**kwargs) o = {'token': {'expires_at': '2099-05-22T00:02:43.941430Z', 'issued_at': '2013-05-21T00:02:43.941473Z', 'methods': ['password'], 'project': {'id': ref.get('project_id'), 'name': ref.get('project_name'), 'domain': {'id': ref.get('project_domain_id'), 'name': ref.get( 'project_domain_name') } }, 'user': {'id': ref.get('user_id'), 'name': ref.get('username'), 'domain': {'id': ref.get('user_domain_id'), 'name': ref.get('user_domain_name') } }, 'roles': ref.get('roles') }} # we only care about Barbican and Keystone endpoints o['token']['catalog'] = [ {'endpoints': [ { 'id': uuidutils.generate_uuid(dashed=False), 'interface': 'public', 'region': 'RegionTwo', 'url': ref.get('barbican_url') }], 'id': uuidutils.generate_uuid(dashed=False), 'type': 'keystore'}, {'endpoints': [ { 'id': uuidutils.generate_uuid(dashed=False), 'interface': 'public', 'region': 'RegionTwo', 'url': ref.get('auth_url') }, { 'id': uuidutils.generate_uuid(dashed=False), 'interface': 'admin', 'region': 'RegionTwo', 'url': ref.get('auth_url') }], 'id': uuidutils.generate_uuid(dashed=False), 'type': 'identity'}] # token ID is conveyed via the X-Subject-Token header so we are generating # one to stash there token_id = uuidutils.generate_uuid(dashed=False) return token_id, o class KeystoneClientFixture(testtools.TestCase): def setUp(self): super(KeystoneClientFixture, self).setUp() self.responses = self.useFixture(fixture.Fixture()) self.barbican = barbicanclient.barbican.Barbican() self.test_arguments = {} def get_arguments(self, auth_version='v3'): if auth_version.lower() == 'v3': version_specific = { '--os-auth-url': V3_URL, '--os-project-name': 'my_project_name' } else: version_specific = { '--os-auth-url': V2_URL, '--os-identity-api-version': '2.0', '--os-tenant-name': 'my_tenant_name' } self.test_arguments.update(version_specific) return self._to_argv(self.test_arguments) def _to_argv(self, argument_dict): # Convert to argv to pass into the client argv = [] for k, v in argument_dict.items(): argv.extend([k, v]) return argv def _delete_secret(self, auth_version): ref = '{0}/secrets/{1}'.format(BARBICAN_ENDPOINT, uuidutils.generate_uuid()) # Mock delete secret self.responses.delete(ref, status_code=204) argv = self.get_arguments(auth_version) argv.extend(['--endpoint', BARBICAN_ENDPOINT, 'secret', 'delete', ref]) try: self.barbican.run(argv=argv) except Exception: self.fail('failed to delete secret') def test_v2_auth(self): # Mock Keystone version discovery and token request self.responses.get(V2_URL, body=V2_VERSION_ENTRY) self.responses.post( '{0}/tokens'.format(V2_URL), json=generate_v2_project_scoped_token() ) self._delete_secret('v2') def test_v3_auth(self): # Mock Keystone version discovery and token request self.responses.get(V3_URL, text=V3_VERSION_ENTRY) id, v3_token = generate_v3_project_scoped_token() self.responses.post( '{0}/auth/tokens'.format(V3_URL), json=v3_token, headers={'X-Subject-Token': '1234'} ) self._delete_secret('v3') python-barbicanclient-4.10.0/barbicanclient/tests/v1/0000775000175000017500000000000013620530306022523 5ustar zuulzuul00000000000000python-barbicanclient-4.10.0/barbicanclient/tests/v1/test_containers.py0000664000175000017500000006236113620530200026302 0ustar zuulzuul00000000000000# Copyright (c) 2013 Rackspace, Inc. # # 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. import mock from oslo_serialization import jsonutils from oslo_utils import timeutils import six from barbicanclient import base from barbicanclient.tests import test_client from barbicanclient.v1 import acls from barbicanclient.v1 import containers from barbicanclient.v1 import secrets class ContainerData(object): def __init__(self): self.name = 'Self destruction sequence' self.type = 'generic' self.secret = mock.Mock(spec=secrets.Secret) self.secret.__bases__ = (secrets.Secret,) self.secret.secret_ref = ('http://barbican/v1/secrets/' 'a73b62e4-eee2-4169-9a14-b8bb4da71d87') self.secret.name = 'thing1' self.generic_secret_refs = {self.secret.name: self.secret.secret_ref} self.generic_secret_refs_json = [{'name': self.secret.name, 'secret_ref': self.secret.secret_ref}] self.generic_secrets = {self.secret.name: self.secret} self.rsa_secret_refs = { 'private_key': self.secret.secret_ref, 'public_key': self.secret.secret_ref, 'private_key_passphrase': self.secret.secret_ref, } self.rsa_secret_refs_json = [ {'name': 'private_key', 'secret_ref': self.secret.secret_ref}, {'name': 'public_key', 'secret_ref': self.secret.secret_ref}, {'name': 'private_key_passphrase', 'secret_ref': self.secret.secret_ref}, ] self.certificate_secret_refs = { 'certificate': self.secret.secret_ref, 'private_key': self.secret.secret_ref, 'private_key_passphrase': self.secret.secret_ref, 'intermediates': self.secret.secret_ref, } self.certificate_secret_refs_json = [ {'name': 'certificate', 'secret_ref': self.secret.secret_ref}, {'name': 'private_key', 'secret_ref': self.secret.secret_ref}, {'name': 'private_key_passphrase', 'secret_ref': self.secret.secret_ref}, {'name': 'intermediates', 'secret_ref': self.secret.secret_ref}, ] self.created = str(timeutils.utcnow()) self.consumer = {'name': 'testing', 'URL': 'http://c.d/e'} self.container_dict = {'name': self.name, 'status': 'ACTIVE', 'created': self.created} def get_dict(self, container_ref=None, type='generic', consumers=None): container = self.container_dict if container_ref: container['container_ref'] = container_ref container['type'] = type if type == 'rsa': container['secret_refs'] = self.rsa_secret_refs_json elif type == 'certificate': container['secret_refs'] = self.certificate_secret_refs_json else: container['secret_refs'] = self.generic_secret_refs_json if consumers: container['consumers'] = consumers return container class WhenTestingContainers(test_client.BaseEntityResource): def setUp(self): self._setUp('containers') self.container = ContainerData() self.manager = self.client.containers self.consumers_post_resource = self.entity_href + '/consumers/' self.consumers_delete_resource = self.entity_href + '/consumers' def test_should_generic_container_str(self): container_obj = self.manager.create(name=self.container.name) self.assertIn(self.container.name, str(container_obj)) self.assertIn(' generic ', str(container_obj)) def test_should_certificate_container_str(self): container_obj = self.manager.create_certificate( name=self.container.name) self.assertIn(self.container.name, str(container_obj)) self.assertIn(' certificate ', str(container_obj)) def test_should_rsa_container_str(self): container_obj = self.manager.create_rsa(name=self.container.name) self.assertIn(self.container.name, str(container_obj)) self.assertIn(' rsa ', str(container_obj)) def test_should_generic_container_repr(self): container_obj = self.manager.create(name=self.container.name) self.assertIn('name="{0}"'.format(self.container.name), repr(container_obj)) def test_should_certificate_container_repr(self): container_obj = self.manager.create_certificate( name=self.container.name) self.assertIn('name="{0}"'.format(self.container.name), repr(container_obj)) def test_should_rsa_container_repr(self): container_obj = self.manager.create_rsa(name=self.container.name) self.assertIn('name="{0}"'.format(self.container.name), repr(container_obj)) def test_should_store_generic_via_constructor(self): data = {'container_ref': self.entity_href} self.responses.post(self.entity_base + '/', json=data) container = self.manager.create( name=self.container.name, secrets=self.container.generic_secrets ) container_href = container.store() self.assertEqual(self.entity_href, container_href) # Verify the correct URL was used to make the call. self.assertEqual(self.entity_base + '/', self.responses.last_request.url) # Verify that correct information was sent in the call. container_req = jsonutils.loads(self.responses.last_request.text) self.assertEqual(self.container.name, container_req['name']) self.assertEqual(self.container.type, container_req['type']) self.assertEqual(self.container.generic_secret_refs_json, container_req['secret_refs']) def test_should_store_generic_via_attributes(self): data = {'container_ref': self.entity_href} self.responses.post(self.entity_base + '/', json=data) container = self.manager.create() container.name = self.container.name container.add(self.container.secret.name, self.container.secret) container_href = container.store() self.assertEqual(self.entity_href, container_href) # Verify the correct URL was used to make the call. self.assertEqual(self.entity_base + '/', self.responses.last_request.url) # Verify that correct information was sent in the call. container_req = jsonutils.loads(self.responses.last_request.text) self.assertEqual(self.container.name, container_req['name']) self.assertEqual(self.container.type, container_req['type']) self.assertEqual(self.container.generic_secret_refs_json, container_req['secret_refs']) def test_should_store_certificate_via_attributes(self): data = {'container_ref': self.entity_href} self.responses.post(self.entity_base + '/', json=data) container = self.manager.create_certificate() container.name = self.container.name container.certificate = self.container.secret container.private_key = self.container.secret container.private_key_passphrase = self.container.secret container.intermediates = self.container.secret container_href = container.store() self.assertEqual(self.entity_href, container_href) # Verify the correct URL was used to make the call. self.assertEqual(self.entity_base + '/', self.responses.last_request.url) # Verify that correct information was sent in the call. container_req = jsonutils.loads(self.responses.last_request.text) self.assertEqual(self.container.name, container_req['name']) self.assertEqual('certificate', container_req['type']) self.assertItemsEqual(self.container.certificate_secret_refs_json, container_req['secret_refs']) def test_should_store_certificate_via_constructor(self): data = {'container_ref': self.entity_href} self.responses.post(self.entity_base + '/', json=data) container = self.manager.create_certificate( name=self.container.name, certificate=self.container.secret, private_key=self.container.secret, private_key_passphrase=self.container.secret, intermediates=self.container.secret ) container_href = container.store() self.assertEqual(self.entity_href, container_href) # Verify the correct URL was used to make the call. self.assertEqual(self.entity_base + '/', self.responses.last_request.url) # Verify that correct information was sent in the call. container_req = jsonutils.loads(self.responses.last_request.text) self.assertEqual(self.container.name, container_req['name']) self.assertEqual('certificate', container_req['type']) self.assertItemsEqual(self.container.certificate_secret_refs_json, container_req['secret_refs']) def test_should_store_rsa_via_attributes(self): data = {'container_ref': self.entity_href} self.responses.post(self.entity_base + '/', json=data) container = self.manager.create_rsa() container.name = self.container.name container.private_key = self.container.secret container.private_key_passphrase = self.container.secret container.public_key = self.container.secret container_href = container.store() self.assertEqual(self.entity_href, container_href) # Verify the correct URL was used to make the call. self.assertEqual(self.entity_base + '/', self.responses.last_request.url) # Verify that correct information was sent in the call. container_req = jsonutils.loads(self.responses.last_request.text) self.assertEqual(self.container.name, container_req['name']) self.assertEqual('rsa', container_req['type']) self.assertItemsEqual(self.container.rsa_secret_refs_json, container_req['secret_refs']) def test_should_store_rsa_via_constructor(self): data = {'container_ref': self.entity_href} self.responses.post(self.entity_base + '/', json=data) container = self.manager.create_rsa( name=self.container.name, private_key=self.container.secret, private_key_passphrase=self.container.secret, public_key=self.container.secret ) container_href = container.store() self.assertEqual(self.entity_href, container_href) # Verify the correct URL was used to make the call. self.assertEqual(self.entity_base + '/', self.responses.last_request.url) # Verify that correct information was sent in the call. container_req = jsonutils.loads(self.responses.last_request.text) self.assertEqual(self.container.name, container_req['name']) self.assertEqual('rsa', container_req['type']) self.assertItemsEqual(self.container.rsa_secret_refs_json, container_req['secret_refs']) def test_should_get_secret_refs_when_created_using_secret_objects(self): data = {'container_ref': self.entity_href} self.responses.post(self.entity_base + '/', json=data) container = self.manager.create( name=self.container.name, secrets=self.container.generic_secrets ) self.assertEqual(self.container.generic_secret_refs, container.secret_refs) def test_should_reload_attributes_after_store(self): data = {'container_ref': self.entity_href} self.responses.post(self.entity_base + '/', json=data) data = self.container.get_dict(self.entity_href) self.responses.get(self.entity_href, json=data) container = self.manager.create( name=self.container.name, secrets=self.container.generic_secrets ) self.assertIsNone(container.status) self.assertIsNone(container.created) self.assertIsNone(container.updated) container_href = container.store() self.assertEqual(self.entity_href, container_href) self.assertIsNotNone(container.status) self.assertIsNotNone(container.created) def test_should_fail_add_invalid_secret_object(self): container = self.manager.create() self.assertRaises(ValueError, container.add, "Not-a-secret", "Actually a string") def test_should_fail_add_duplicate_named_secret_object(self): container = self.manager.create() container.add(self.container.secret.name, self.container.secret) self.assertRaises(KeyError, container.add, self.container.secret.name, self.container.secret) def test_should_add_remove_add_secret_object(self): container = self.manager.create() container.add(self.container.secret.name, self.container.secret) container.remove(self.container.secret.name) container.add(self.container.secret.name, self.container.secret) def test_should_be_immutable_after_store(self): data = {'container_ref': self.entity_href} self.responses.post(self.entity_base + '/', json=data) container = self.manager.create( name=self.container.name, secrets=self.container.generic_secrets ) container_href = container.store() self.assertEqual(self.entity_href, container_href) # Verify that attributes are immutable after store. attributes = [ "name" ] for attr in attributes: try: setattr(container, attr, "test") self.fail("didn't raise an ImmutableException exception") except base.ImmutableException: pass self.assertRaises(base.ImmutableException, container.add, self.container.secret.name, self.container.secret) def test_should_not_be_able_to_set_generated_attributes(self): container = self.manager.create() # Verify that generated attributes cannot be set. attributes = [ "container_ref", "created", "updated", "status", "consumers" ] for attr in attributes: try: setattr(container, attr, "test") self.fail("didn't raise an AttributeError exception") except AttributeError: pass def test_should_get_generic_container(self, container_ref=None): container_ref = container_ref or self.entity_href data = self.container.get_dict(container_ref) self.responses.get(self.entity_href, json=data) container = self.manager.get(container_ref=container_ref) self.assertIsInstance(container, containers.Container) self.assertEqual(container_ref, container.container_ref) # Verify the correct URL was used to make the call. self.assertEqual(self.entity_href, self.responses.last_request.url) self.assertIsNotNone(container.secrets) def test_should_get_certificate_container(self): data = self.container.get_dict(self.entity_href, type='certificate') self.responses.get(self.entity_href, json=data) container = self.manager.get(container_ref=self.entity_href) self.assertIsInstance(container, containers.Container) self.assertEqual(self.entity_href, container.container_ref) # Verify the correct URL was used to make the call. self.assertEqual(self.entity_href, self.responses.last_request.url) # Verify the returned type is correct self.assertIsInstance(container, containers.CertificateContainer) self.assertIsNotNone(container.certificate) self.assertIsNotNone(container.private_key) self.assertIsNotNone(container.private_key_passphrase) self.assertIsNotNone(container.intermediates) def test_should_get_rsa_container(self): data = self.container.get_dict(self.entity_href, type='rsa') self.responses.get(self.entity_href, json=data) container = self.manager.get(container_ref=self.entity_href) self.assertIsInstance(container, containers.Container) self.assertEqual(self.entity_href, container.container_ref) # Verify the correct URL was used to make the call. self.assertEqual(self.entity_href, self.responses.last_request.url) # Verify the returned type is correct self.assertIsInstance(container, containers.RSAContainer) self.assertIsNotNone(container.private_key) self.assertIsNotNone(container.public_key) self.assertIsNotNone(container.private_key_passphrase) def test_should_get_generic_container_using_stripped_uuid(self): bad_href = "http://badsite.com/" + self.entity_id self.test_should_get_generic_container(bad_href) def test_should_get_generic_container_using_only_uuid(self): self.test_should_get_generic_container(self.entity_id) def test_should_delete_from_manager(self, container_ref=None): container_ref = container_ref or self.entity_href self.responses.delete(self.entity_href, status_code=204) self.manager.delete(container_ref=container_ref) # Verify the correct URL was used to make the call. self.assertEqual(self.entity_href, self.responses.last_request.url) def test_should_delete_from_manager_using_stripped_uuid(self): bad_href = "http://badsite.com/" + self.entity_id self.test_should_delete_from_manager(bad_href) def test_should_delete_from_manager_using_only_uuid(self): self.test_should_delete_from_manager(self.entity_id) def test_should_delete_from_object(self, container_ref=None): container_ref = container_ref or self.entity_href data = self.container.get_dict(container_ref) m = self.responses.get(self.entity_href, json=data) n = self.responses.delete(self.entity_href, status_code=204) container = self.manager.get(container_ref=container_ref) self.assertEqual(container_ref, container.container_ref) container.delete() # Verify the correct URL was used to make the call. self.assertTrue(m.called) self.assertTrue(n.called) # Verify that the Container no longer has a container_ref self.assertIsNone(container.container_ref) def test_should_delete_from_object_using_stripped_uuid(self): bad_href = "http://badsite.com/" + self.entity_id self.test_should_delete_from_object(bad_href) def test_should_delete_from_object_using_only_uuid(self): self.test_should_delete_from_object(self.entity_id) def test_should_store_after_delete_from_object(self): data = self.container.get_dict(self.entity_href) self.responses.get(self.entity_href, json=data) data = self.container.get_dict(self.entity_href) self.responses.post(self.entity_base + '/', json=data) m = self.responses.delete(self.entity_href, status_code=204) container = self.manager.get(container_ref=self.entity_href) self.assertIsNotNone(container.container_ref) container.delete() # Verify the correct URL was used to make the call. self.assertEqual(self.entity_href, m.last_request.url) # Verify that the Container no longer has a container_ref self.assertIsNone(container.container_ref) container.store() # Verify that the Container has a container_ref again self.assertIsNotNone(container.container_ref) def test_should_get_list(self): container_resp = self.container.get_dict(self.entity_href) data = {"containers": [container_resp for v in range(3)]} self.responses.get(self.entity_base, json=data) containers_list = self.manager.list(limit=10, offset=5) self.assertTrue(len(containers_list) == 3) self.assertIsInstance(containers_list[0], containers.Container) self.assertEqual(self.entity_href, containers_list[0].container_ref) # Verify the correct URL was used to make the call. self.assertEqual(self.entity_base, self.responses.last_request.url.split('?')[0]) # Verify that correct information was sent in the call. self.assertEqual(['10'], self.responses.last_request.qs['limit']) self.assertEqual(['5'], self.responses.last_request.qs['offset']) def test_should_get_list_when_secret_ref_without_name(self): container_resp = self.container.get_dict(self.entity_href) del container_resp.get("secret_refs")[0]["name"] data = {"containers": [container_resp for v in range(3)]} self.responses.get(self.entity_base, json=data) containers_list = self.manager.list(limit=10, offset=5) self.assertTrue(len(containers_list) == 3) self.assertIsInstance(containers_list[0], containers.Container) self.assertEqual(self.entity_href, containers_list[0].container_ref) # Verify the correct URL was used to make the call. self.assertEqual(self.entity_base, self.responses.last_request.url.split('?')[0]) # Verify that the names of the secret_refs in the containers are None for container in containers_list: for name in six.iterkeys(container._secret_refs): self.assertIsNone(name) def test_should_fail_get_invalid_container(self): self.assertRaises(ValueError, self.manager.get, **{'container_ref': '12345'}) def test_should_fail_delete_no_href(self): self.assertRaises(ValueError, self.manager.delete, None) def test_should_register_consumer(self): data = self.container.get_dict(self.entity_href, consumers=[self.container.consumer]) self.responses.post(self.entity_href + '/consumers/', json=data) container = self.manager.register_consumer( self.entity_href, self.container.consumer.get('name'), self.container.consumer.get('URL') ) self.assertIsInstance(container, containers.Container) self.assertEqual(self.entity_href, container.container_ref) body = jsonutils.loads(self.responses.last_request.text) self.assertEqual(self.consumers_post_resource, self.responses.last_request.url) self.assertEqual(self.container.consumer, body) self.assertEqual([self.container.consumer], container.consumers) def test_should_remove_consumer(self): self.responses.delete(self.entity_href + '/consumers', status_code=204) self.manager.remove_consumer( self.entity_href, self.container.consumer.get('name'), self.container.consumer.get('URL') ) body = jsonutils.loads(self.responses.last_request.text) self.assertEqual(self.consumers_delete_resource, self.responses.last_request.url) self.assertEqual(self.container.consumer, body) def test_should_get_total(self): self.responses.get(self.entity_base, json={'total': 1}) total = self.manager.total() self.assertEqual(1, total) 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) def test_get_formatted_data(self): data = self.container.get_dict(self.entity_href) self.responses.get(self.entity_href, json=data) container = self.manager.get(container_ref=self.entity_href) data = container._get_formatted_data() self.assertEqual(self.container.name, data[1]) self.assertEqual(timeutils.parse_isotime( self.container.created).isoformat(), data[2]) python-barbicanclient-4.10.0/barbicanclient/tests/v1/__init__.py0000664000175000017500000000000013620530200024613 0ustar zuulzuul00000000000000python-barbicanclient-4.10.0/barbicanclient/tests/v1/test_cas.py0000664000175000017500000001241613620530200024677 0ustar zuulzuul00000000000000# Copyright (c) 2013 Rackspace, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. from oslo_utils import timeutils from barbicanclient.tests import test_client from barbicanclient.v1 import cas class CAData(object): def __init__(self, description=u'Test CA description'): self.name = u'Test CA' self.description = description self.plugin_name = u'Test CA Plugin' self.plugin_ca_id = 'plugin_uuid' now = timeutils.utcnow() self.expiration = str(now) self.created = str(now) self.meta = [] self.meta.append({'name': self.name}) if self.description: self.meta.append({'description': self.description}) self.ca_dict = {'meta': self.meta, 'status': u'ACTIVE', 'plugin_name': self.plugin_name, 'plugin_ca_id': self.plugin_ca_id, 'created': self.created} def get_dict(self, ca_ref=None): ca = self.ca_dict if ca_ref: ca['ca_ref'] = ca_ref return ca class WhenTestingCAs(test_client.BaseEntityResource): def setUp(self): self._setUp('cas') self.ca = CAData() self.manager = self.client.cas def test_should_get_lazy(self, ca_ref=None): ca_ref = ca_ref or self.entity_href data = self.ca.get_dict(ca_ref) m = self.responses.get(self.entity_href, json=data) ca = self.manager.get(ca_ref=ca_ref) self.assertIsInstance(ca, cas.CA) self.assertEqual(ca_ref, ca._ca_ref) # Verify GET wasn't called yet self.assertFalse(m.called) # Check an attribute to trigger lazy-load self.assertEqual(self.ca.plugin_ca_id, ca.plugin_ca_id) # Verify the correct URL was used to make the GET call self.assertEqual(self.entity_href, m.last_request.url) def test_should_get_lazy_using_stripped_uuid(self): bad_href = "http://badsite.com/" + self.entity_id self.test_should_get_lazy(bad_href) def test_should_get_lazy_using_only_uuid(self): self.test_should_get_lazy(self.entity_id) def test_should_get_lazy_in_meta(self): data = self.ca.get_dict(self.entity_href) m = self.responses.get(self.entity_href, json=data) ca = self.manager.get(ca_ref=self.entity_href) self.assertIsInstance(ca, cas.CA) self.assertEqual(self.entity_href, ca._ca_ref) # Verify GET wasn't called yet self.assertFalse(m.called) # Check an attribute in meta to trigger lazy-load self.assertEqual(self.ca.name, ca.name) # Verify the correct URL was used to make the GET call self.assertEqual(self.entity_href, m.last_request.url) def test_should_get_list(self): ca_resp = self.entity_href data = {"cas": [ca_resp for v in range(3)]} m = self.responses.get(self.entity_base, json=data) ca_list = self.manager.list(limit=10, offset=5) self.assertTrue(len(ca_list) == 3) self.assertIsInstance(ca_list[0], cas.CA) self.assertEqual(self.entity_href, ca_list[0].ca_ref) # Verify the correct URL was used to make the call. self.assertEqual(self.entity_base, m.last_request.url.split('?')[0]) # Verify that correct information was sent in the call. self.assertEqual(['10'], m.last_request.qs['limit']) self.assertEqual(['5'], m.last_request.qs['offset']) def test_should_fail_get_invalid_ca(self): self.assertRaises(ValueError, self.manager.get, **{'ca_ref': '12345'}) def test_should_get_ca_that_has_no_meta_description(self): self.ca = CAData(description=None) data = self.ca.get_dict(self.entity_href) m = self.responses.get(self.entity_href, json=data) ca = self.manager.get(ca_ref=self.entity_href) self.assertIsInstance(ca, cas.CA) self.assertEqual(self.entity_href, ca._ca_ref) # Verify GET wasn't called yet self.assertFalse(m.called) # Get description from CA, check it is None self.assertIsNone(self.ca.description) self.assertIsNone(ca.description) # Verify the correct URL was used to make the GET call self.assertEqual(self.entity_href, m.last_request.url) def test_get_formatted_data(self): c_entity = cas.CA(api=None, expiration=self.ca.expiration, plugin_name=self.ca.plugin_name, created=self.ca.created) data = c_entity._get_formatted_data() self.assertEqual(self.ca.plugin_name, data[6]) self.assertEqual(timeutils.parse_isotime( self.ca.expiration).isoformat(), data[8]) python-barbicanclient-4.10.0/barbicanclient/tests/v1/test_secrets.py0000664000175000017500000005437013620530200025606 0ustar zuulzuul00000000000000# Copyright (c) 2013 Rackspace, Inc. # # 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. import base64 from oslo_serialization import jsonutils from oslo_utils import timeutils from barbicanclient import base from barbicanclient import exceptions from barbicanclient.tests import test_client from barbicanclient.v1 import acls from barbicanclient.v1 import secrets class SecretData(object): def __init__(self): self.name = u'Self destruction sequence' self.payload = u'the magic words are squeamish ossifrage' self.payload_content_type = u'text/plain' self.algorithm = u'AES' self.created = str(timeutils.utcnow()) self.secret_dict = {'name': self.name, 'status': u'ACTIVE', 'algorithm': self.algorithm, 'created': self.created} def get_dict(self, secret_ref=None, content_types_dict=None): secret = self.secret_dict if secret_ref: secret['secret_ref'] = secret_ref if content_types_dict: secret['content_types'] = content_types_dict return secret class WhenTestingSecrets(test_client.BaseEntityResource): def setUp(self): self._setUp('secrets') self.secret = SecretData() self.manager = self.client.secrets def test_should_entity_str(self): secret_obj = self.manager.create(name=self.secret.name) self.assertIn(self.secret.name, str(secret_obj)) def test_should_entity_repr(self): secret_obj = self.manager.create(name=self.secret.name) self.assertIn('name="{0}"'.format(self.secret.name), repr(secret_obj)) def test_should_store_via_constructor(self): data = {'secret_ref': self.entity_href} self.responses.post(self.entity_base + '/', json=data) secret = self.manager.create(name=self.secret.name, payload=self.secret.payload) secret_href = secret.store() self.assertEqual(self.entity_href, secret_href) # Verify that correct information was sent in the call. secret_req = jsonutils.loads(self.responses.last_request.text) self.assertEqual(self.secret.name, secret_req['name']) self.assertEqual(self.secret.payload, secret_req['payload']) def test_should_store_via_attributes(self): data = {'secret_ref': self.entity_href} self.responses.post(self.entity_base + '/', json=data) secret = self.manager.create() secret.name = self.secret.name secret.payload = self.secret.payload secret_href = secret.store() self.assertEqual(self.entity_href, secret_href) # Verify that correct information was sent in the call. secret_req = jsonutils.loads(self.responses.last_request.text) self.assertEqual(self.secret.name, secret_req['name']) self.assertEqual(self.secret.payload, secret_req['payload']) def test_should_store_binary_type_as_octet_stream(self): """We use six.binary_type as the canonical binary type. The client should base64 encode the payload before sending the request. """ data = {'secret_ref': self.entity_href} self.responses.post(self.entity_base + '/', json=data) # This literal will have type(str) in Python 2, but will have # type(bytes) in Python 3. It is six.binary_type in both cases. binary_payload = b'F\x130\x89f\x8e\xd9\xa1\x0e\x1f\r\xf67uu\x8b' secret = self.manager.create() secret.name = self.secret.name secret.payload = binary_payload secret.store() secret_req = jsonutils.loads(self.responses.last_request.text) self.assertEqual(self.secret.name, secret_req['name']) self.assertEqual(u'application/octet-stream', secret_req['payload_content_type']) self.assertEqual(u'base64', secret_req['payload_content_encoding']) self.assertNotEqual(binary_payload, secret_req['payload']) def test_should_store_text_type_as_text_plain(self): """We use six.text_type as the canonical text type.""" data = {'secret_ref': self.entity_href} self.responses.post(self.entity_base + '/', json=data) # This literal will have type(unicode) in Python 2, but will have # type(str) in Python 3. It is six.text_type in both cases. text_payload = u'time for an ice cold \U0001f37a' secret = self.manager.create() secret.payload = text_payload secret.store() secret_req = jsonutils.loads(self.responses.last_request.text) self.assertEqual(text_payload, secret_req['payload']) self.assertEqual(u'text/plain', secret_req['payload_content_type']) def test_should_store_with_deprecated_content_type(self): """DEPRECATION WARNING Manually setting the payload_content_type is deprecated and will be removed in a future release. """ data = {'secret_ref': self.entity_href} self.responses.post(self.entity_base + '/', json=data) payload = 'I should be octet-stream' payload_content_type = u'text/plain' secret = self.manager.create() secret.payload = payload secret.payload_content_type = payload_content_type secret.store() secret_req = jsonutils.loads(self.responses.last_request.text) self.assertEqual(payload, secret_req['payload']) self.assertEqual(payload_content_type, secret_req['payload_content_type']) def test_should_store_with_deprecated_content_encoding(self): """DEPRECATION WARNING Manually setting the payload_content_encoding is deprecated and will be removed in a future release. """ data = {'secret_ref': self.entity_href} self.responses.post(self.entity_base + '/', json=data) encoded_payload = base64.b64encode( b'F\x130\x89f\x8e\xd9\xa1\x0e\x1f\r\xf67uu\x8b' ).decode('UTF-8') payload_content_type = u'application/octet-stream' payload_content_encoding = u'base64' secret = self.manager.create() secret.payload = encoded_payload secret.payload_content_type = payload_content_type secret.payload_content_encoding = payload_content_encoding secret.store() secret_req = jsonutils.loads(self.responses.last_request.text) self.assertEqual(encoded_payload, secret_req['payload']) self.assertEqual(payload_content_type, secret_req['payload_content_type']) self.assertEqual(payload_content_encoding, secret_req['payload_content_encoding']) def test_should_be_immutable_after_submit(self): data = {'secret_ref': self.entity_href} self.responses.post(self.entity_base + '/', json=data) secret = self.manager.create(name=self.secret.name, payload=self.secret.payload) secret_href = secret.store() self.assertEqual(self.entity_href, secret_href) # Verify that attributes are immutable after store. attributes = [ "name", "expiration", "algorithm", "bit_length", "mode", "payload_content_type", "payload_content_encoding", "secret_type"] for attr in attributes: try: setattr(secret, attr, "test") self.fail("didn't raise an ImmutableException exception") except base.ImmutableException: pass def test_should_not_be_able_to_set_generated_attributes(self): secret = self.manager.create() # Verify that generated attributes cannot be set. attributes = [ "secret_ref", "created", "updated", "content_types", "status" ] for attr in attributes: try: setattr(secret, attr, "test") self.fail("didn't raise an AttributeError exception") except AttributeError: pass def test_should_get_lazy(self, secret_ref=None): secret_ref = secret_ref or self.entity_href data = self.secret.get_dict(secret_ref) m = self.responses.get(self.entity_href, json=data) secret = self.manager.get(secret_ref=secret_ref) self.assertIsInstance(secret, secrets.Secret) self.assertEqual(secret_ref, secret.secret_ref) # Verify GET wasn't called yet self.assertFalse(m.called) # Check an attribute to trigger lazy-load self.assertEqual(self.secret.name, secret.name) # Verify the correct URL was used to make the GET call self.assertEqual(self.entity_href, m.last_request.url) def test_should_get_lazy_using_stripped_uuid(self): bad_href = "http://badsite.com/" + self.entity_id self.test_should_get_lazy(bad_href) def test_should_get_lazy_using_only_uuid(self): self.test_should_get_lazy(self.entity_id) 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 Manually setting the payload_content_type is deprecated and will be removed in a future release. """ m = self.responses.get(self.entity_href, request_headers={'Accept': 'application/json'}, json=self.secret.get_dict(self.entity_href)) n = self.responses.get(self.entity_payload_href, request_headers={'Accept': 'text/plain'}, text=self.secret.payload) secret = self.manager.get( secret_ref=self.entity_href, payload_content_type=self.secret.payload_content_type ) self.assertIsInstance(secret, secrets.Secret) self.assertEqual(self.entity_href, secret.secret_ref) # Verify `get` wasn't called yet (metadata) self.assertFalse(m.called) # Verify `get_raw` wasn't called yet (payload) self.assertFalse(n.called) # GET payload (with payload_content_type) self.assertEqual(self.secret.payload, secret.payload) # Verify `get` still wasn't called (metadata) self.assertFalse(m.called) # Verify `get_raw` was called (payload) self.assertTrue(n.called) # Verify the correct URL was used to make the `get_raw` call self.assertEqual(self.entity_payload_href, n.last_request.url) def test_should_fetch_metadata_to_get_payload(self): content_types_dict = {'default': 'text/plain'} data = self.secret.get_dict(self.entity_href, content_types_dict=content_types_dict) metadata_response = self.responses.get( self.entity_href, request_headers={'Accept': 'application/json'}, json=data) request_headers = {'Accept': 'text/plain'} decryption_response = self.responses.get( self.entity_payload_href, request_headers=request_headers, text=self.secret.payload) secret = self.manager.get(secret_ref=self.entity_href) self.assertIsInstance(secret, secrets.Secret) self.assertEqual(self.entity_href, secret.secret_ref) # Verify `get` wasn't called yet (metadata) self.assertFalse(metadata_response.called) # Verify `get_raw` wasn't called yet (payload) self.assertFalse(decryption_response.called) # GET payload (with no payload_content_type) trigger lazy-load self.assertEqual(self.secret.payload, secret.payload) # Verify `get` was called (metadata) self.assertTrue(metadata_response.called) # Verify `get_raw` was called (payload) self.assertTrue(decryption_response.called) # Verify the correct URL was used to make the `get` calls self.assertEqual(self.entity_href, metadata_response.last_request.url) self.assertEqual(self.entity_payload_href, decryption_response.last_request.url) def test_should_decrypt_when_content_type_is_set(self): """DEPRECATION WARNING Manually setting the payload_content_type is deprecated and will be removed in a future release. """ decrypted = b'decrypted text here' request_headers = {'Accept': 'application/octet-stream'} m = self.responses.get(self.entity_payload_href, request_headers=request_headers, content=decrypted) secret = self.manager.get( secret_ref=self.entity_href, payload_content_type='application/octet-stream' ) secret_payload = secret.payload self.assertEqual(decrypted, secret_payload) # Verify the correct URL was used to make the call. self.assertEqual(self.entity_payload_href, m.last_request.url) def test_should_decrypt(self, secret_ref=None): secret_ref = secret_ref or self.entity_href content_types_dict = {'default': 'application/octet-stream'} json = self.secret.get_dict(secret_ref, content_types_dict) metadata_response = self.responses.get( self.entity_href, request_headers={'Accept': 'application/json'}, json=json) decrypted = b'decrypted text here' request_headers = {'Accept': 'application/octet-stream'} decryption_response = self.responses.get( self.entity_payload_href, request_headers=request_headers, content=decrypted) secret = self.manager.get(secret_ref=secret_ref) secret_payload = secret.payload self.assertEqual(decrypted, secret_payload) # Verify the correct URL was used to make the call. self.assertEqual(self.entity_href, metadata_response.last_request.url) # Verify the correct URL was used to make the call. self.assertEqual(self.entity_payload_href, decryption_response.last_request.url) def test_should_decrypt_using_stripped_uuid(self): bad_href = "http://badsite.com/" + self.entity_id self.test_should_decrypt(bad_href) def test_should_delete_from_manager(self, secret_ref=None): secret_ref = secret_ref or self.entity_href self.responses.delete(self.entity_href, status_code=204) self.manager.delete(secret_ref=secret_ref) # Verify the correct URL was used to make the call. self.assertEqual(self.entity_href, self.responses.last_request.url) def test_should_delete_from_manager_using_stripped_uuid(self): bad_href = "http://badsite.com/" + self.entity_id self.test_should_delete_from_manager(bad_href) def test_should_delete_from_manager_using_only_uuid(self): self.test_should_delete_from_manager(self.entity_id) def test_should_delete_from_object(self, secref_ref=None): secref_ref = secref_ref or self.entity_href data = {'secret_ref': secref_ref} self.responses.post(self.entity_base + '/', json=data) secret = self.manager.create() secret.payload = None secret.store() # Verify the secret has the correct ref for testing deletes self.assertEqual(secref_ref, secret.secret_ref) self.responses.delete(self.entity_href, status_code=204) secret.delete() # Verify the correct URL was used to make the call. self.assertEqual(self.entity_href, self.responses.last_request.url) def test_should_delete_from_object_using_stripped_uuid(self): bad_href = "http://badsite.com/" + self.entity_id self.test_should_delete_from_object(bad_href) def test_should_delete_from_object_using_only_uuid(self): self.test_should_delete_from_object(self.entity_id) def test_should_update_from_manager(self, secret_ref=None): # This literal will have type(unicode) in Python 2, but will have # type(str) in Python 3. It is six.text_type in both cases. text_payload = u'time for an ice cold \U0001f37a' secret_ref = secret_ref or self.entity_href self.responses.put(self.entity_href, status_code=204) self.manager.update(secret_ref=secret_ref, payload=text_payload) # Verify the correct URL was used to make the call. self.assertEqual(self.entity_href, self.responses.last_request.url) def test_should_update_from_manager_using_stripped_uuid(self): bad_href = "http://badsite.com/" + self.entity_id self.test_should_update_from_manager(bad_href) def test_should_update_from_manager_using_only_uuid(self): self.test_should_update_from_manager(self.entity_id) def test_should_update_from_object(self, secref_ref=None): secref_ref = secref_ref or self.entity_href data = {'secret_ref': secref_ref} self.responses.post(self.entity_base + '/', json=data) secret = self.manager.create() secret.payload = None secret.store() # Verify the secret has the correct ref for testing updates self.assertEqual(secref_ref, secret.secret_ref) # This literal will have type(unicode) in Python 2, but will have # type(str) in Python 3. It is six.text_type in both cases. text_payload = u'time for an ice cold \U0001f37a' self.responses.put(self.entity_href, status_code=204) secret.payload = text_payload secret.update() # Verify the correct URL was used to make the call. self.assertEqual(self.entity_href, self.responses.last_request.url) # Verify that the data has been updated self.assertEqual(text_payload, secret.payload) def test_should_update_from_object_using_stripped_uuid(self): bad_href = "http://badsite.com/" + self.entity_id self.test_should_update_from_object(bad_href) def test_should_update_from_object_using_only_uuid(self): self.test_should_update_from_object(self.entity_id) def test_should_get_list(self): secret_resp = self.secret.get_dict(self.entity_href) data = {"secrets": [secret_resp for v in range(3)]} m = self.responses.get(self.entity_base, json=data) secrets_list = self.manager.list(limit=10, offset=5) self.assertTrue(len(secrets_list) == 3) self.assertIsInstance(secrets_list[0], secrets.Secret) self.assertEqual(self.entity_href, secrets_list[0].secret_ref) # Verify the correct URL was used to make the call. self.assertEqual(self.entity_base, m.last_request.url.split('?')[0]) # Verify that correct information was sent in the call. self.assertEqual(['10'], m.last_request.qs['limit']) self.assertEqual(['5'], m.last_request.qs['offset']) def test_should_fail_get_invalid_secret(self): self.assertRaises(ValueError, self.manager.get, **{'secret_ref': '12345'}) def test_should_fail_update_zero(self): data = {'secret_ref': self.entity_href} self.responses.post(self.entity_base + '/', json=data) secret = self.manager.create() secret.payload = None secret.store() self.responses.put(self.entity_href, status_code=204) secret.payload = 0 # Verify that an error is thrown self.assertRaises(exceptions.PayloadException, secret.update) def test_should_fail_store_zero(self): data = {'secret_ref': self.entity_href} self.responses.post(self.entity_base + '/', json=data) secret = self.manager.create() secret.name = self.secret.name secret.payload = 0 self.assertRaises(exceptions.PayloadException, secret.store) def test_should_fail_decrypt_no_content_types(self): data = self.secret.get_dict(self.entity_href) self.responses.get(self.entity_href, json=data) secret = self.manager.get(secret_ref=self.entity_href) self.assertIsNone(secret.payload) def test_should_fail_decrypt_no_default_content_type(self): content_types_dict = {'no-default': 'application/octet-stream'} data = self.secret.get_dict(self.entity_href, content_types_dict) self.responses.get(self.entity_href, json=data) secret = self.manager.get(secret_ref=self.entity_href) self.assertIsNone(secret.payload) def test_should_fail_delete_no_href(self): self.assertRaises(ValueError, self.manager.delete, None) def test_should_get_total(self): self.responses.get(self.entity_base, json={'total': 1}) total = self.manager.total() self.assertEqual(1, total) def test_get_formatted_data(self): data = self.secret.get_dict(self.entity_href) self.responses.get(self.entity_href, json=data) secret = self.manager.get(secret_ref=self.entity_href) f_data = secret._get_formatted_data() self.assertEqual( timeutils.parse_isotime(data['created']).isoformat(), f_data[2]) python-barbicanclient-4.10.0/barbicanclient/tests/v1/test_acls.py0000664000175000017500000005353713620530200025064 0ustar zuulzuul00000000000000# 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. from oslo_utils import timeutils import requests_mock from barbicanclient.tests import test_client from barbicanclient.v1 import acls class ACLTestCase(test_client.BaseEntityResource): def setUp(self): self._setUp('acl', entity_id='d9f95d61-8863-49d3-a045-5c2cb77130b5') self.secret_uuid = '8a3108ec-88fc-4f5c-86eb-f37b8ae8358e' self.secret_ref = (self.endpoint + '/v1/secrets/' + self.secret_uuid) self.secret_acl_ref = '{0}/acl'.format(self.secret_ref) self.container_uuid = '83c302c7-86fe-4f07-a277-c4962f121f19' self.container_ref = (self.endpoint + '/v1/containers/' + self.container_uuid) self.container_acl_ref = '{0}/acl'.format(self.container_ref) self.manager = self.client.acls self.users1 = ['2d0ee7c681cc4549b6d76769c320d91f', '721e27b8505b499e8ab3b38154705b9e'] self.users2 = ['2d0ee7c681cc4549b6d76769c320d91f'] self.created = str(timeutils.utcnow()) def get_acl_response_data(self, operation_type='read', users=None, project_access=False): if users is None: users = self.users1 op_data = {'users': users} op_data['project-access'] = project_access op_data['created'] = self.created op_data['updated'] = str(timeutils.utcnow()) acl_data = {operation_type: op_data} return acl_data class WhenTestingACLManager(ACLTestCase): def test_should_get_secret_acl(self, entity_ref=None): entity_ref = entity_ref or self.secret_ref self.responses.get(self.secret_acl_ref, json=self.get_acl_response_data()) api_resp = self.manager.get(entity_ref=entity_ref) self.assertEqual(self.secret_acl_ref, self.responses.last_request.url) self.assertFalse(api_resp.get('read').project_access) self.assertEqual('read', api_resp.get('read').operation_type) self.assertIn(api_resp.get('read').acl_ref_relative, self.secret_acl_ref) def test_should_get_secret_acl_using_stripped_uuid(self): bad_href = "http://badsite.com/secrets/" + self.secret_uuid self.test_should_get_secret_acl(bad_href) def test_should_get_secret_acl_with_extra_trailing_slashes(self): self.responses.get(requests_mock.ANY, json=self.get_acl_response_data()) # check if trailing slashes are corrected in get call. self.manager.get(entity_ref=self.secret_ref + '///') self.assertEqual(self.secret_acl_ref, self.responses.last_request.url) def test_should_get_container_acl(self, entity_ref=None): entity_ref = entity_ref or self.container_ref self.responses.get(self.container_acl_ref, json=self.get_acl_response_data()) api_resp = self.manager.get(entity_ref=entity_ref) self.assertEqual(self.container_acl_ref, self.responses.last_request.url) self.assertFalse(api_resp.get('read').project_access) self.assertEqual('read', api_resp.get('read').operation_type) self.assertIn(api_resp.get('read').acl_ref_relative, self.container_acl_ref) def test_should_get_container_acl_using_stripped_uuid(self): bad_href = "http://badsite.com/containers/" + self.container_uuid self.test_should_get_container_acl(bad_href) def test_should_get_container_acl_with_trailing_slashes(self): self.responses.get(requests_mock.ANY, json=self.get_acl_response_data()) # check if trailing slashes are corrected in get call. self.manager.get(entity_ref=self.container_ref + '///') self.assertEqual(self.container_acl_ref, self.responses.last_request.url) def test_should_fail_get_no_href(self): self.assertRaises(ValueError, self.manager.get, None) def test_should_fail_get_invalid_uri(self): # secret_acl URI expected and not secret URI self.assertRaises(ValueError, self.manager.get, self.secret_acl_ref) self.assertRaises(ValueError, self.manager.get, self.endpoint + '/containers/consumers') def test_should_create_secret_acl(self): entity = self.manager.create(entity_ref=self.secret_ref + '///', users=self.users1, project_access=True) self.assertIsInstance(entity, acls.SecretACL) read_acl = entity.read # entity ref is kept same as provided input. self.assertEqual(self.secret_ref + '///', read_acl.entity_ref) self.assertTrue(read_acl.project_access) self.assertEqual(self.users1, read_acl.users) self.assertEqual(acls.DEFAULT_OPERATION_TYPE, read_acl.operation_type) # acl ref removes extra trailing slashes if there self.assertIn(self.secret_ref, read_acl.acl_ref, 'ACL ref has additional /acl') self.assertIsNone(read_acl.created) self.assertIsNone(read_acl.updated) read_acl_via_get = entity.get('read') self.assertEqual(read_acl, read_acl_via_get) def test_should_create_acl_with_users(self, entity_ref=None): entity_ref = entity_ref or self.container_ref entity = self.manager.create(entity_ref=entity_ref + '///', users=self.users2, project_access=False) self.assertIsInstance(entity, acls.ContainerACL) # entity ref is kept same as provided input. self.assertEqual(entity_ref + '///', entity.entity_ref) read_acl = entity.read self.assertFalse(read_acl.project_access) self.assertEqual(self.users2, read_acl.users) self.assertEqual(acls.DEFAULT_OPERATION_TYPE, read_acl.operation_type) # acl ref removes extra trailing slashes if there self.assertIn(entity_ref, read_acl.acl_ref, 'ACL ref has additional /acl') self.assertIn(read_acl.acl_ref_relative, self.container_acl_ref) def test_should_create_acl_with_users_stripped_uuid(self): bad_href = "http://badsite.com/containers/" + self.container_uuid self.test_should_create_acl_with_users(bad_href) def test_should_create_acl_with_no_users(self): entity = self.manager.create(entity_ref=self.container_ref, users=[]) read_acl = entity.read self.assertEqual([], read_acl.users) self.assertEqual(acls.DEFAULT_OPERATION_TYPE, read_acl.operation_type) self.assertIsNone(read_acl.project_access) read_acl_via_get = entity.get('read') self.assertEqual(read_acl, read_acl_via_get) def test_create_no_acl_settings(self): entity = self.manager.create(entity_ref=self.container_ref) self.assertEqual([], entity.operation_acls) self.assertEqual(self.container_ref, entity.entity_ref) self.assertEqual(self.container_ref + '/acl', entity.acl_ref) def test_should_fail_create_invalid_uri(self): self.assertRaises(ValueError, self.manager.create, self.endpoint + '/orders') self.assertRaises(ValueError, self.manager.create, None) class WhenTestingACLEntity(ACLTestCase): def test_should_submit_acl_with_users_project_access_set(self, href=None): href = href or self.secret_ref data = {'acl_ref': self.secret_acl_ref} # register put acl URI with expected acl ref in response self.responses.put(self.secret_acl_ref, json=data) entity = self.manager.create(entity_ref=href + '///', users=self.users1, project_access=True) api_resp = entity.submit() self.assertEqual(self.secret_acl_ref, api_resp) self.assertEqual(self.secret_acl_ref, self.responses.last_request.url) def test_should_submit_acl_with_users_project_access_stripped_uuid(self): bad_href = "http://badsite.com/secrets/" + self.secret_uuid self.test_should_submit_acl_with_users_project_access_set(bad_href) def test_should_submit_acl_with_project_access_set_but_no_users(self): data = {'acl_ref': self.secret_acl_ref} # register put acl URI with expected acl ref in response self.responses.put(self.secret_acl_ref, json=data) entity = self.manager.create(entity_ref=self.secret_ref, project_access=False) api_resp = entity.submit() self.assertEqual(self.secret_acl_ref, api_resp) self.assertEqual(self.secret_acl_ref, self.responses.last_request.url) self.assertFalse(entity.read.project_access) self.assertEqual([], entity.get('read').users) def test_should_submit_acl_with_user_set_but_not_project_access(self): data = {'acl_ref': self.container_acl_ref} # register put acl URI with expected acl ref in response self.responses.put(self.container_acl_ref, json=data) entity = self.manager.create(entity_ref=self.container_ref, users=self.users2) api_resp = entity.submit() self.assertEqual(self.container_acl_ref, api_resp) self.assertEqual(self.container_acl_ref, self.responses.last_request.url) self.assertEqual(self.users2, entity.read.users) self.assertIsNone(entity.get('read').project_access) def test_should_fail_submit_acl_invalid_secret_uri(self): data = {'acl_ref': self.secret_acl_ref} # register put acl URI with expected acl ref in response self.responses.put(self.secret_acl_ref, json=data) entity = self.manager.create(entity_ref=self.secret_acl_ref + '///', users=self.users1, project_access=True) # Submit checks provided URI is entity URI and not ACL URI. self.assertRaises(ValueError, entity.submit) entity = self.manager.create(entity_ref=self.secret_ref, users=self.users1, project_access=True) entity._entity_ref = None self.assertRaises(ValueError, entity.submit) entity = self.manager.create(entity_ref=self.secret_ref, users=self.users1, project_access=True) entity._entity_ref = self.container_ref # expected secret uri here self.assertRaises(ValueError, entity.submit) def test_should_fail_submit_acl_invalid_container_uri(self): """Adding tests for container URI validation. Container URI validation is different from secret URI validation. That's why adding separate tests for code coverage. """ data = {'acl_ref': self.container_acl_ref} # register put acl URI with expected acl ref in response self.responses.put(self.container_acl_ref, json=data) entity = self.manager.create(entity_ref=self.container_acl_ref + '///', users=self.users1, project_access=True) # Submit checks provided URI is entity URI and not ACL URI. self.assertRaises(ValueError, entity.submit) entity = self.manager.create(entity_ref=self.container_ref, users=self.users1, project_access=True) entity._entity_ref = None self.assertRaises(ValueError, entity.submit) entity = self.manager.create(entity_ref=self.container_ref, users=self.users1, project_access=True) entity._entity_ref = self.secret_ref # expected container uri here self.assertRaises(ValueError, entity.submit) def test_should_fail_submit_acl_no_acl_data(self): data = {'acl_ref': self.secret_acl_ref} # register put acl URI with expected acl ref in response self.responses.put(self.secret_acl_ref, json=data) entity = self.manager.create(entity_ref=self.secret_ref + '///') # Submit checks that ACL setting data is there or not. self.assertRaises(ValueError, entity.submit) def test_should_fail_submit_acl_input_users_as_not_list(self): data = {'acl_ref': self.secret_acl_ref} # register put acl URI with expected acl ref in response self.responses.put(self.secret_acl_ref, json=data) entity = self.manager.create(entity_ref=self.secret_ref, users='u1') # Submit checks that input users are provided as list or not self.assertRaises(ValueError, entity.submit) def test_should_load_acls_data(self): self.responses.get( self.container_acl_ref, json=self.get_acl_response_data( users=self.users2, project_access=True)) entity = self.manager.create(entity_ref=self.container_ref, users=self.users1) self.assertEqual(self.container_ref, entity.entity_ref) self.assertEqual(self.container_acl_ref, entity.acl_ref) entity.load_acls_data() self.assertEqual(self.users2, entity.read.users) self.assertTrue(entity.get('read').project_access) self.assertEqual(timeutils.parse_isotime(self.created), entity.read.created) self.assertEqual(timeutils.parse_isotime(self.created), entity.get('read').created) self.assertEqual(1, len(entity.operation_acls)) self.assertEqual(self.container_acl_ref, entity.get('read').acl_ref) self.assertEqual(self.container_ref, entity.read.entity_ref) def test_should_add_operation_acl(self): entity = self.manager.create(entity_ref=self.secret_ref + '///', users=self.users1, project_access=True) self.assertIsInstance(entity, acls.SecretACL) entity.add_operation_acl(users=self.users2, project_access=False, operation_type='read') read_acl = entity.read # entity ref is kept same as provided input. self.assertEqual(self.secret_ref + '/acl', read_acl.acl_ref) self.assertFalse(read_acl.project_access) self.assertEqual(self.users2, read_acl.users) self.assertEqual(acls.DEFAULT_OPERATION_TYPE, read_acl.operation_type) entity.add_operation_acl(users=[], project_access=False, operation_type='dummy') dummy_acl = entity.get('dummy') self.assertFalse(dummy_acl.project_access) self.assertEqual([], dummy_acl.users) def test_acl_entity_properties(self): entity = self.manager.create(entity_ref=self.secret_ref, users=self.users2) self.assertEqual(self.secret_ref, entity.entity_ref) self.assertEqual(self.secret_acl_ref, entity.acl_ref) self.assertEqual(self.users2, entity.read.users) self.assertEqual(self.users2, entity.get('read').users) self.assertIsNone(entity.read.project_access) self.assertIsNone(entity.get('read').project_access) self.assertIsNone(entity.read.created) self.assertIsNone(entity.get('read').created) self.assertEqual('read', entity.read.operation_type) self.assertEqual('read', entity.get('read').operation_type) self.assertEqual(1, len(entity.operation_acls)) self.assertEqual(self.secret_acl_ref, entity.read.acl_ref) self.assertEqual(self.secret_acl_ref, entity.get('read').acl_ref) self.assertEqual(self.secret_ref, entity.read.entity_ref) self.assertIsNone(entity.get('dummyOperation')) entity.read.users = ['u1'] entity.read.project_access = False entity.read.operation_type = 'my_operation' self.assertFalse(entity.get('my_operation').project_access) self.assertEqual(['u1'], entity.get('my_operation').users) self.assertRaises(AttributeError, lambda x: x.dummy_operation, entity) def test_get_formatted_data(self): s_entity = acls.SecretACL(api=None, entity_ref=self.secret_ref, users=self.users1) data = s_entity.read._get_formatted_data() self.assertEqual(acls.DEFAULT_OPERATION_TYPE, data[0]) self.assertIsNone(data[1]) self.assertEqual(self.users1, data[2]) self.assertIsNone(data[3]) # created self.assertIsNone(data[4]) # updated self.assertEqual(self.secret_acl_ref, data[5]) c_entity = acls.ContainerACL(api=None, entity_ref=self.container_ref, users=self.users2, created=self.created) data = c_entity.get('read')._get_formatted_data() self.assertEqual(acls.DEFAULT_OPERATION_TYPE, data[0]) self.assertIsNone(data[1]) self.assertEqual(self.users2, data[2]) self.assertEqual(timeutils.parse_isotime(self.created).isoformat(), data[3]) # created self.assertIsNone(data[4]) # updated self.assertEqual(self.container_acl_ref, data[5]) def test_should_secret_acl_remove(self, entity_ref=None): entity_ref = entity_ref or self.secret_ref self.responses.delete(self.secret_acl_ref) entity = self.manager.create(entity_ref=entity_ref, users=self.users2) api_resp = entity.remove() self.assertEqual(self.secret_acl_ref, self.responses.last_request.url) self.assertIsNone(api_resp) def test_should_secret_acl_remove_uri_with_slashes(self): self.responses.delete(self.secret_acl_ref) # check if trailing slashes are corrected in delete call. entity = self.manager.create(entity_ref=self.secret_ref + '///', users=self.users2) entity.remove() self.assertEqual(self.secret_acl_ref, self.responses.last_request.url) self.responses.delete(self.container_acl_ref) def test_should_secret_acl_remove_stripped_uuid(self): bad_href = "http://badsite.com/secrets/" + self.secret_uuid self.test_should_secret_acl_remove(bad_href) def test_should_container_acl_remove(self, entity_ref=None): entity_ref = entity_ref or self.container_ref self.responses.delete(self.container_acl_ref) entity = self.manager.create(entity_ref=entity_ref) entity.remove() self.assertEqual(self.container_acl_ref, self.responses.last_request.url) def test_should_container_acl_remove_stripped_uuid(self): bad_href = "http://badsite.com/containers/" + self.container_uuid self.test_should_container_acl_remove(bad_href) def test_should_fail_acl_remove_invalid_uri(self): # secret_acl URI expected and not secret acl URI entity = self.manager.create(entity_ref=self.secret_acl_ref) self.assertRaises(ValueError, entity.remove) entity = self.manager.create(entity_ref=self.container_acl_ref) self.assertRaises(ValueError, entity.remove) entity = self.manager.create(entity_ref=self.container_ref + '/consumers') self.assertRaises(ValueError, entity.remove) # check to make sure UUID is passed in entity = self.manager.create(entity_ref=self.endpoint + '/secrets' + '/consumers') self.assertRaises(ValueError, entity.remove) def test_should_per_operation_acl_remove(self): self.responses.get(self.secret_acl_ref, json=self.get_acl_response_data(users=self.users2, project_access=True) ) self.responses.delete(self.secret_acl_ref) entity = self.manager.create(entity_ref=self.secret_ref, users=self.users2) api_resp = entity.read.remove() self.assertEqual(self.secret_acl_ref, self.responses.last_request.url) self.assertIsNone(api_resp) self.assertEqual(0, len(entity.operation_acls)) # now try case where there are 2 operation acls defined # and one operation specific acl is removed. In that case, # entity.submit() is called instead of remove to update rest of entity acl_data = self.get_acl_response_data(users=self.users2, project_access=True) data = self.get_acl_response_data(users=self.users1, operation_type='write', project_access=False) acl_data['write'] = data['write'] self.responses.get(self.secret_acl_ref, json=acl_data) self.responses.put(self.secret_acl_ref, json={}) # check if trailing slashes are corrected in delete call. entity = self.manager.create(entity_ref=self.secret_ref, users=self.users2) entity.read.remove() self.assertEqual(self.secret_acl_ref, self.responses.last_request.url) self.assertEqual(1, len(entity.operation_acls)) self.assertEqual('write', entity.operation_acls[0].operation_type) self.assertEqual(self.users1, entity.operation_acls[0].users) python-barbicanclient-4.10.0/barbicanclient/tests/v1/test_orders.py0000664000175000017500000004122413620530200025426 0ustar zuulzuul00000000000000# Copyright (c) 2013 Rackspace, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. from oslo_serialization import jsonutils from oslo_utils import timeutils import uuid from barbicanclient import base from barbicanclient.tests import test_client from barbicanclient.v1 import orders class OrdersTestCase(test_client.BaseEntityResource): def setUp(self): self._setUp('orders', entity_id='d0460cc4-2876-4493-b7de-fc5c812883cc') self.secret_ref = (self.endpoint + '/secrets/a2292306-6da0-4f60-bd8a-84fc8d692716') self.key_order_data = """{{ "status": "ACTIVE", "secret_ref": "{0}", "updated": "2014-10-21T17:15:50.871596", "meta": {{ "name": "secretname", "algorithm": "aes", "payload_content_type": "application/octet-stream", "mode": "cbc", "bit_length": 256, "expiration": "2015-02-28T19:14:44.180394" }}, "created": "2014-10-21T17:15:50.824202", "type": "key", "order_ref": "{1}" }}""".format(self.secret_ref, self.entity_href) self.key_order_invalid_data = """{{ "status": "ACTIVE", "secret_ref": "{0}", "updated": "2014-10-21T17:15:50.871596", "meta": {{ "name": "secretname", "algorithm": "aes", "request_type":"invalid", "payload_content_type": "application/octet-stream", "mode": "cbc", "bit_length": 256, "expiration": "2015-02-28T19:14:44.180394" }}, "created": "2014-10-21T17:15:50.824202", "type": "key", "order_ref": "{1}" }}""".format(self.secret_ref, self.entity_href) self.container_ref = ( self.endpoint + '/containers/a2292306-6da0-4f60-bd8a-84fc8d692716') self.source_container_ref = ( self.endpoint + '/containers/c6f20480-c1e5-442b-94a0-cb3b5e0cf179') self.cert_order_data = """{{ "status": "ACTIVE", "container_ref": "{0}", "updated": "2014-10-21T17:15:50.871596", "meta": {{ "name": "secretname", "subject_dn": "cn=server.example.com,o=example.com", "request_type": "stored-key", "container_ref": "{1}" }}, "created": "2014-10-21T17:15:50.824202", "type": "certificate", "order_ref": "{2}" }}""".format(self.container_ref, self.source_container_ref, self.entity_href) self.manager = self.client.orders def _get_order_args(self, order_data): order_args = jsonutils.loads(order_data) order_args.update(order_args.pop('meta')) order_args.pop('type') return order_args class WhenTestingKeyOrders(OrdersTestCase): def test_should_include_errors_in_str(self): order_args = self._get_order_args(self.key_order_data) error_code = 500 error_reason = 'Something is broken' order_obj = orders.KeyOrder(api=None, error_status_code=error_code, error_reason=error_reason, **order_args) self.assertIn(str(error_code), str(order_obj)) self.assertIn(error_reason, str(order_obj)) def test_should_include_order_ref_in_repr(self): order_args = self._get_order_args(self.key_order_data) order_obj = orders.KeyOrder(api=None, **order_args) self.assertIn('order_ref=' + self.entity_href, repr(order_obj)) def test_should_be_immutable_after_submit(self): data = {'order_ref': self.entity_href} self.responses.post(self.entity_base + '/', json=data) order = self.manager.create_key( name='name', algorithm='algorithm', payload_content_type='payload_content_type' ) order_href = order.submit() self.assertEqual(self.entity_href, order_href) # Verify that attributes are immutable after store. attributes = [ "name", "expiration", "algorithm", "bit_length", "mode", "payload_content_type" ] for attr in attributes: try: setattr(order, attr, "test") self.fail("didn't raise an ImmutableException exception") except base.ImmutableException: pass def test_should_submit_via_constructor(self): data = {'order_ref': self.entity_href} self.responses.post(self.entity_base + '/', json=data) order = self.manager.create_key( name='name', algorithm='algorithm', payload_content_type='payload_content_type' ) order_href = order.submit() self.assertEqual(self.entity_href, order_href) # Verify the correct URL was used to make the call. self.assertEqual(self.entity_base + '/', self.responses.last_request.url) # Verify that correct information was sent in the call. order_req = jsonutils.loads(self.responses.last_request.text) self.assertEqual('name', order_req['meta']['name']) self.assertEqual('algorithm', order_req['meta']['algorithm']) self.assertEqual('payload_content_type', order_req['meta']['payload_content_type']) def test_should_submit_via_attributes(self): data = {'order_ref': self.entity_href} self.responses.post(self.entity_base + '/', json=data) order = self.manager.create_key() order.name = 'name' order.algorithm = 'algorithm' order.payload_content_type = 'payload_content_type' order_href = order.submit() self.assertEqual(self.entity_href, order_href) # Verify the correct URL was used to make the call. self.assertEqual(self.entity_base + '/', self.responses.last_request.url) # Verify that correct information was sent in the call. order_req = jsonutils.loads(self.responses.last_request.text) self.assertEqual('name', order_req['meta']['name']) self.assertEqual('algorithm', order_req['meta']['algorithm']) self.assertEqual('payload_content_type', order_req['meta']['payload_content_type']) def test_should_not_be_able_to_set_generated_attributes(self): order = self.manager.create_key() # Verify that generated attributes cannot be set. attributes = [ "order_ref", "secret_ref", "created", "updated", "status", "error_status_code", "error_reason" ] for attr in attributes: try: setattr(order, attr, "test") self.fail("didn't raise an AttributeError exception") except AttributeError: pass def test_should_delete_from_object(self, order_ref=None): order_ref = order_ref or self.entity_href data = {'order_ref': order_ref} self.responses.post(self.entity_base + '/', json=data) self.responses.delete(self.entity_href, status_code=204) order = self.manager.create_key( name='name', algorithm='algorithm', payload_content_type='payload_content_type' ) order_href = order.submit() self.assertEqual(order_ref, order_href) order.delete() # Verify the correct URL was used to make the call. self.assertEqual(self.entity_href, self.responses.last_request.url) def test_should_delete_from_object_using_stripped_uuid(self): bad_href = "http://badsite.com/" + self.entity_id self.test_should_delete_from_object(bad_href) def test_should_delete_from_object_using_only_uuid(self): self.test_should_delete_from_object(self.entity_id) class WhenTestingAsymmetricOrders(OrdersTestCase): def test_should_be_immutable_after_submit(self): data = {'order_ref': self.entity_href} self.responses.post(self.entity_base + '/', json=data) order = self.manager.create_asymmetric( name='name', algorithm='algorithm', payload_content_type='payload_content_type' ) order_href = order.submit() self.assertEqual(self.entity_href, order_href) # Verify that attributes are immutable after store. attributes = [ "name", "expiration", "algorithm", "bit_length", "pass_phrase", "payload_content_type" ] for attr in attributes: try: setattr(order, attr, "test") self.fail( "{0} didn't raise an ImmutableException exception".format( attr ) ) except base.ImmutableException: pass def test_create_asymmetric_order_w_passphrase(self): data = {'order_ref': self.entity_href} self.responses.post(self.entity_base + '/', json=data) passphrase = str(uuid.uuid4()) order = orders.AsymmetricOrder( api=self.manager._api, name='name', algorithm='algorithm', payload_content_type='payload_content_type', passphrase=passphrase, ) order_href = order.submit() self.assertEqual(self.entity_href, order_href) self.assertEqual(passphrase, order.pass_phrase) def test_create_asymmetric_order_w_legacy_pass_phrase_param(self): data = {'order_ref': self.entity_href} self.responses.post(self.entity_base + '/', json=data) passphrase = str(uuid.uuid4()) order = orders.AsymmetricOrder( api=self.manager._api, name='name', algorithm='algorithm', payload_content_type='payload_content_type', pass_phrase=passphrase, ) order_href = order.submit() self.assertEqual(self.entity_href, order_href) self.assertEqual(passphrase, order.pass_phrase) class WhenTestingOrderManager(OrdersTestCase): def test_should_get(self, order_ref=None): order_ref = order_ref or self.entity_href self.responses.get(self.entity_href, text=self.key_order_data) order = self.manager.get(order_ref=order_ref) self.assertIsInstance(order, orders.KeyOrder) self.assertEqual(self.entity_href, order.order_ref) # Verify the correct URL was used to make the call. self.assertEqual(self.entity_href, self.responses.last_request.url) def test_should_get_using_stripped_uuid(self): bad_href = "http://badsite.com/" + self.entity_id self.test_should_get(bad_href) def test_should_get_using_only_uuid(self): self.test_should_get(self.entity_id) def test_should_get_invalid_meta(self): self.responses.get(self.entity_href, text=self.key_order_invalid_data) # Verify checking for invalid meta fields. self.assertRaises(TypeError, self.manager.get, self.entity_href) def test_should_get_list(self): data = {"orders": [jsonutils.loads(self.key_order_data) for _ in range(3)]} self.responses.get(self.entity_base, json=data) orders_list = self.manager.list(limit=10, offset=5) self.assertTrue(len(orders_list) == 3) self.assertIsInstance(orders_list[0], orders.KeyOrder) self.assertEqual(self.entity_href, orders_list[0].order_ref) # Verify the correct URL was used to make the call. self.assertEqual(self.entity_base, self.responses.last_request.url.split('?')[0]) # Verify that correct information was sent in the call. self.assertEqual(['10'], self.responses.last_request.qs['limit']) self.assertEqual(['5'], self.responses.last_request.qs['offset']) def test_should_delete(self, order_ref=None): order_ref = order_ref or self.entity_href self.responses.delete(self.entity_href, status_code=204) self.manager.delete(order_ref=order_ref) # Verify the correct URL was used to make the call. self.assertEqual(self.entity_href, self.responses.last_request.url) def test_should_delete_using_stripped_uuid(self): bad_href = "http://badsite.com/" + self.entity_id self.test_should_delete(bad_href) def test_should_delete_using_only_uuid(self): self.test_should_delete(self.entity_id) def test_should_fail_delete_no_href(self): self.assertRaises(ValueError, self.manager.delete, None) def test_should_get_total(self): self.responses.get(self.entity_base, json={'total': 1}) total = self.manager.total() self.assertEqual(1, total) def test_get_formatted_data(self): self.responses.get(self.entity_href, text=self.key_order_data) order = self.manager.get(order_ref=self.entity_href) data = order._get_formatted_data() order_args = self._get_order_args(self.key_order_data) self.assertEqual(timeutils.parse_isotime( order_args['created']).isoformat(), data[4]) class WhenTestingCertificateOrders(OrdersTestCase): def test_get(self, order_ref=None): order_ref = order_ref or self.entity_href self.responses.get(self.entity_href, text=self.cert_order_data) order = self.manager.get(order_ref=order_ref) self.assertIsInstance(order, orders.CertificateOrder) self.assertEqual(self.entity_href, order.order_ref) # Verify the correct URL was used to make the call. self.assertEqual(self.entity_href, self.responses.last_request.url) def test_get_using_stripped_uuid(self): bad_href = "http://badsite.com/" + self.entity_id self.test_get(bad_href) def test_get_using_only_uuid(self): self.test_get(self.entity_id) def test_repr(self): order_args = self._get_order_args(self.cert_order_data) order_obj = orders.CertificateOrder(api=None, **order_args) self.assertIn('order_ref=' + self.entity_href, repr(order_obj)) def test_constructor(self): data = {'order_ref': self.entity_href} self.responses.post(self.entity_base + '/', json=data) order = self.manager.create_certificate( name='name', subject_dn='cn=server.example.com,o=example.com', request_type='stored-key', source_container_ref=self.source_container_ref ) order_href = order.submit() self.assertEqual(self.entity_href, order_href) # Verify the correct URL was used to make the call. self.assertEqual(self.entity_base + '/', self.responses.last_request.url) # Verify that correct information was sent in the call. order_req = jsonutils.loads(self.responses.last_request.text) self.assertEqual('name', order_req['meta']['name']) self.assertEqual('cn=server.example.com,o=example.com', order_req['meta']['subject_dn']) self.assertEqual('stored-key', order_req['meta']['request_type']) self.assertEqual(self.source_container_ref, order_req['meta']['container_ref']) def test_list(self): data = {"orders": [jsonutils.loads(self.cert_order_data) for _ in range(3)]} self.responses.get(self.entity_base, json=data) orders_list = self.manager.list(limit=10, offset=5) self.assertEqual(3, len(orders_list)) self.assertIsInstance(orders_list[0], orders.CertificateOrder) self.assertEqual(self.entity_href, orders_list[0].order_ref) def test_get_formatted_data(self): self.responses.get(self.entity_href, text=self.cert_order_data) order = self.manager.get(order_ref=self.entity_href) data = order._get_formatted_data() order_args = self._get_order_args(self.cert_order_data) self.assertEqual(timeutils.parse_isotime( order_args['created']).isoformat(), data[4]) python-barbicanclient-4.10.0/barbicanclient/tests/test_formatter.py0000664000175000017500000000526213620530200025607 0ustar zuulzuul00000000000000# Copyright (c) 2017 # # 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. import testtools from barbicanclient import formatter class EntityFormatter(formatter.EntityFormatter): columns = ("Column A", "Column B", "Column C") def _get_formatted_data(self): data = (self._attr_a, self._attr_b, self._attr_c) return data class Entity(EntityFormatter): def __init__(self, attr_a, attr_b, attr_c): self._attr_a = attr_a self._attr_b = attr_b self._attr_c = attr_c class TestFormatter(testtools.TestCase): def test_should_get_list_objects(self): entity_1 = Entity('test_attr_a_1', 'test_attr_b_1', 'test_attr_c_1') entity_2 = Entity('test_attr_a_2', 'test_attr_b_2', 'test_attr_c_2') columns, data = EntityFormatter._list_objects([entity_1, entity_2]) self.assertEqual(('Column A', 'Column B', 'Column C'), columns) self.assertEqual([('test_attr_a_1', 'test_attr_b_1', 'test_attr_c_1'), ('test_attr_a_2', 'test_attr_b_2', 'test_attr_c_2')], [e for e in data]) def test_should_get_list_objects_empty(self): columns, data = EntityFormatter._list_objects([]) self.assertEqual([], columns) self.assertEqual([], [e for e in data]) def test_should_get_str(self): entity = Entity('test_attr_a_1', 'test_attr_b_1', 'test_attr_c_1') self.assertEqual('+----------+---------------+\n' '| Field | Value |\n' '+----------+---------------+\n' '| Column A | test_attr_a_1 |\n' '| Column B | test_attr_b_1 |\n' '| Column C | test_attr_c_1 |\n' '+----------+---------------+', str(entity)) def test_should_to_dict(self): entity = Entity('test_attr_a_1', 'test_attr_b_1', 'test_attr_c_1') self.assertEqual({'Column A': 'test_attr_a_1', 'Column B': 'test_attr_b_1', 'Column C': 'test_attr_c_1'}, entity.to_dict()) python-barbicanclient-4.10.0/python_barbicanclient.egg-info/0000775000175000017500000000000013620530306024126 5ustar zuulzuul00000000000000python-barbicanclient-4.10.0/python_barbicanclient.egg-info/requires.txt0000664000175000017500000000024313620530306026525 0ustar zuulzuul00000000000000pbr!=2.1.0,>=2.0.0 requests>=2.14.2 six>=1.10.0 cliff!=2.9.0,>=2.8.0 keystoneauth1>=3.4.0 oslo.i18n>=3.15.3 oslo.serialization!=2.19.1,>=2.18.0 oslo.utils>=3.33.0 python-barbicanclient-4.10.0/python_barbicanclient.egg-info/PKG-INFO0000664000175000017500000003120113620530306025220 0ustar zuulzuul00000000000000Metadata-Version: 1.1 Name: python-barbicanclient Version: 4.10.0 Summary: Client Library for OpenStack Barbican Key Management API Home-page: https://docs.openstack.org/python-barbicanclient/latest/ Author: OpenStack Author-email: openstack-discuss@lists.openstack.org License: UNKNOWN Description: python-barbicanclient ===================== .. image:: https://img.shields.io/pypi/v/python-barbicanclient.svg :target: https://pypi.org/project/python-barbicanclient/ :alt: Latest Version This is a client for the `Barbican `__ Key Management API. There is a Python library for accessing the API (`barbicanclient` module), and a command-line script (`barbican`). Installation ------------ The client is `pip installable `__ as follows: .. code:: console pip install python-barbicanclient barbicanclient - Python Library ------------------------------- The full api is `documented in the official OpenStack documentation site `__. Here's an example of storing a secret in barbican using the python library with keystone authentication: .. code:: python >>> from keystoneclient.auth import identity >>> from keystoneauth1 import session >>> from barbicanclient import client >>> # We'll use Keystone API v3 for authentication >>> auth = identity.v3.Password(auth_url=u'http://localhost:5000/v3', ... username=u'admin_user', ... user_domain_name=u'Default', ... password=u'password', ... project_name=u'demo', ... project_domain_name=u'Default') >>> # Next we'll create a Keystone session using the auth plugin we just created >>> sess = session.Session(auth=auth) >>> # Now we use the session to create a Barbican client >>> barbican = client.Client(session=sess) >>> # Let's create a Secret to store some sensitive data >>> secret = barbican.secrets.create(name=u'Self destruction sequence', ... payload=u'the magic words are squeamish ossifrage') >>> # Now let's store the secret by using its store() method. This will send the secret data >>> # to Barbican, where it will be encrypted and stored securely in the cloud. >>> secret.store() u'http://localhost:9311/v1/secrets/85b220fd-f414-483f-94e4-2f422480f655' >>> # The URI returned by store() uniquely identifies your secret in the Barbican service. >>> # After a secret is stored, the URI is also available by accessing >>> # the secret_ref attribute. >>> print(secret.secret_ref) http://localhost:9311/v1/secrets/091adb32-4050-4980-8558-90833c531413 >>> # When we need to retrieve our secret at a later time, we can use the secret_ref >>> retrieved_secret = barbican.secrets.get(u'http://localhost:9311/v1/secrets/091adb32-4050-4980-8558-90833c531413') >>> # We can access the secret payload by using the payload attribute. >>> # Barbican decrypts the secret and sends it back. >>> print(retrieved_secret.payload) the magic words are squeamish ossifrage .. note:: In order for the example above to work Barbican must be running and configured to use the Keystone Middleware. For more information on setting this up please visit: https://docs.openstack.org/barbican/latest/configuration/keystone.html [1]_ barbican - Command Line Client ------------------------------ The command line client is self-documenting. Use the --help flag to access the usage options .. code:: console $ barbican --help usage: barbican [--version] [-v] [--log-file LOG_FILE] [-q] [-h] [--debug] [--no-auth] [--os-identity-api-version ] [--os-auth-url ] [--os-username ] [--os-user-id ] [--os-password ] [--os-user-domain-id ] [--os-user-domain-name ] [--os-tenant-name ] [--os-tenant-id ] [--os-project-id ] [--os-project-name ] [--os-project-domain-id ] [--os-project-domain-name ] [--endpoint ] [--insecure] [--os-cacert ] [--os-cert ] [--os-key ] [--timeout ] Command-line interface to the Barbican API. optional arguments: --version show program's version number and exit -v, --verbose Increase verbosity of output. Can be repeated. --log-file LOG_FILE Specify a file to log output. Disabled by default. -q, --quiet suppress output except warnings and errors -h, --help show this help message and exit --debug show trace backs on errors --no-auth, -N Do not use authentication. --os-identity-api-version Specify Identity API version to use. Defaults to env[OS_IDENTITY_API_VERSION] or 3. --os-auth-url , -A Defaults to env[OS_AUTH_URL]. --os-username , -U Defaults to env[OS_USERNAME]. --os-user-id Defaults to env[OS_USER_ID]. --os-password , -P Defaults to env[OS_PASSWORD]. --os-user-domain-id Defaults to env[OS_USER_DOMAIN_ID]. --os-user-domain-name Defaults to env[OS_USER_DOMAIN_NAME]. --os-tenant-name , -T Defaults to env[OS_TENANT_NAME]. --os-tenant-id , -I Defaults to env[OS_TENANT_ID]. --os-project-id Another way to specify tenant ID. This option is mutually exclusive with --os-tenant-id. Defaults to env[OS_PROJECT_ID]. --os-project-name Another way to specify tenant name. This option is mutually exclusive with --os-tenant-name. Defaults to env[OS_PROJECT_NAME]. --os-project-domain-id Defaults to env[OS_PROJECT_DOMAIN_ID]. --os-project-domain-name Defaults to env[OS_PROJECT_DOMAIN_NAME]. --endpoint , -E --endpoint , -E Defaults to env[BARBICAN_ENDPOINT]. --insecure Explicitly allow client to perform "insecure" TLS (https) requests. The server's certificate will not be verified against any certificate authorities. This option should be used with caution. --os-cacert Specify a CA bundle file to use in verifying a TLS (https) server certificate. Defaults to env[OS_CACERT]. --os-cert Defaults to env[OS_CERT]. --os-key Defaults to env[OS_KEY]. --timeout Set request timeout (in seconds). See "barbican help COMMAND" for help on a specific command. Commands: 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. ca get Retrieve a CA by providing its URI. ca list List CAs. complete print bash completion command secret container create Store a container in Barbican. secret container delete Delete a container by providing its href. secret container get Retrieve a container by providing its URI. secret container list List containers. help print detailed help for another command secret order create Create a new order. secret order delete Delete an order by providing its href. secret order get Retrieve an order by providing its URI. secret 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 * `PyPi`_ - package installation * `Online Documentation`_ * `Launchpad project`_ - release management * `Blueprints`_ - feature specifications * `Bugs`_ - issue tracking * `Source`_ * `Specs`_ * `Getting involved`_ .. _PyPi: https://pypi.org/project/python-barbicanclient/ .. _Online Documentation: https://docs.openstack.org/python-barbicanclient/latest/ .. _Launchpad project: https://launchpad.net/python-barbicanclient/ .. _Blueprints: https://blueprints.launchpad.net/python-barbicanclient/ .. _Bugs: https://storyboard.openstack.org/#!/project/984 .. _Source: https://git.openstack.org/cgit/openstack/python-barbicanclient/ .. _Getting involved: https://docs.openstack.org/barbican/latest/contributor/getting_involved.html .. _Specs: https://specs.openstack.org/openstack/barbican-specs/ .. [1] Documentation in this link is currently incomplete. Please use the `devstack setup `__. Platform: UNKNOWN Classifier: Environment :: OpenStack Classifier: Intended Audience :: Information Technology Classifier: Intended Audience :: System Administrators Classifier: License :: OSI Approved :: Apache Software License Classifier: Operating System :: POSIX :: Linux Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 python-barbicanclient-4.10.0/python_barbicanclient.egg-info/not-zip-safe0000664000175000017500000000000113620530306026354 0ustar zuulzuul00000000000000 python-barbicanclient-4.10.0/python_barbicanclient.egg-info/entry_points.txt0000664000175000017500000000272513620530306027432 0ustar zuulzuul00000000000000[console_scripts] barbican = barbicanclient.barbican:main [openstack.cli.extension] key_manager = barbicanclient.osc_plugin [openstack.key_manager.v1] acl_delete = barbicanclient.barbican_cli.v1.acls:DeleteACLs acl_get = barbicanclient.barbican_cli.v1.acls:GetACLs acl_submit = barbicanclient.barbican_cli.v1.acls:SubmitACL acl_user_add = barbicanclient.barbican_cli.v1.acls:AddACLUsers acl_user_remove = barbicanclient.barbican_cli.v1.acls:RemoveACLUsers ca_get = barbicanclient.barbican_cli.v1.cas:GetCA ca_list = barbicanclient.barbican_cli.v1.cas:ListCA secret_container_create = barbicanclient.barbican_cli.v1.containers:CreateContainer secret_container_delete = barbicanclient.barbican_cli.v1.containers:DeleteContainer secret_container_get = barbicanclient.barbican_cli.v1.containers:GetContainer secret_container_list = barbicanclient.barbican_cli.v1.containers:ListContainer secret_delete = barbicanclient.barbican_cli.v1.secrets:DeleteSecret secret_get = barbicanclient.barbican_cli.v1.secrets:GetSecret secret_list = barbicanclient.barbican_cli.v1.secrets:ListSecret secret_order_create = barbicanclient.barbican_cli.v1.orders:CreateOrder secret_order_delete = barbicanclient.barbican_cli.v1.orders:DeleteOrder secret_order_get = barbicanclient.barbican_cli.v1.orders:GetOrder secret_order_list = barbicanclient.barbican_cli.v1.orders:ListOrder secret_store = barbicanclient.barbican_cli.v1.secrets:StoreSecret secret_update = barbicanclient.barbican_cli.v1.secrets:UpdateSecret python-barbicanclient-4.10.0/python_barbicanclient.egg-info/SOURCES.txt0000664000175000017500000000733013620530306026015 0ustar zuulzuul00000000000000.coveragerc .mailmap .stestr.conf .zuul.yaml AUTHORS CONTRIBUTING.rst ChangeLog LICENSE README.rst clientrc lower-constraints.txt requirements.txt setup.cfg setup.py test-requirements.txt tox.ini barbicanclient/__init__.py barbicanclient/_i18n.py barbicanclient/barbican.py barbicanclient/base.py barbicanclient/client.py barbicanclient/exceptions.py barbicanclient/formatter.py barbicanclient/osc_plugin.py barbicanclient/version.py barbicanclient/barbican_cli/__init__.py barbicanclient/barbican_cli/v1/__init__.py barbicanclient/barbican_cli/v1/acls.py barbicanclient/barbican_cli/v1/cas.py barbicanclient/barbican_cli/v1/containers.py barbicanclient/barbican_cli/v1/orders.py barbicanclient/barbican_cli/v1/secrets.py barbicanclient/tests/__init__.py barbicanclient/tests/keystone_client_fixtures.py barbicanclient/tests/test_barbican.py barbicanclient/tests/test_base.py barbicanclient/tests/test_client.py barbicanclient/tests/test_formatter.py barbicanclient/tests/v1/__init__.py barbicanclient/tests/v1/test_acls.py barbicanclient/tests/v1/test_cas.py barbicanclient/tests/v1/test_containers.py barbicanclient/tests/v1/test_orders.py barbicanclient/tests/v1/test_secrets.py barbicanclient/v1/__init__.py barbicanclient/v1/acls.py barbicanclient/v1/cas.py barbicanclient/v1/client.py barbicanclient/v1/containers.py barbicanclient/v1/orders.py barbicanclient/v1/secrets.py doc/requirements.txt doc/source/conf.py doc/source/index.rst doc/source/cli/authentication.rst doc/source/cli/cli_usage.rst doc/source/cli/details.rst doc/source/cli/index.rst doc/source/cli/usage.rst doc/source/contributor/contributing.rst doc/source/contributor/index.rst doc/source/contributor/testing.rst doc/source/install/index.rst doc/source/reference/index.rst etc/barbicanclient.conf etc/functional_tests.conf functionaltests/__init__.py functionaltests/base.py functionaltests/post_test_hook.sh functionaltests/run_tests.sh functionaltests/utils.py functionaltests/cli/__init__.py functionaltests/cli/base.py functionaltests/cli/v1/__init__.py functionaltests/cli/v1/behaviors/__init__.py functionaltests/cli/v1/behaviors/acl_behaviors.py functionaltests/cli/v1/behaviors/base_behaviors.py functionaltests/cli/v1/behaviors/container_behaviors.py functionaltests/cli/v1/behaviors/secret_behaviors.py functionaltests/cli/v1/functional/__init__.py functionaltests/cli/v1/smoke/__init__.py functionaltests/cli/v1/smoke/test_acl.py functionaltests/cli/v1/smoke/test_container.py functionaltests/cli/v1/smoke/test_help.py functionaltests/cli/v1/smoke/test_secret.py functionaltests/client/__init__.py functionaltests/client/base.py functionaltests/client/test_client_connectivity.py functionaltests/client/v1/__init__.py functionaltests/client/v1/functional/__init__.py functionaltests/client/v1/functional/test_acl.py functionaltests/client/v1/functional/test_containers.py functionaltests/client/v1/functional/test_orders.py functionaltests/client/v1/functional/test_secrets.py functionaltests/client/v1/smoke/__init__.py functionaltests/client/v1/smoke/test_containers.py functionaltests/client/v1/smoke/test_orders.py functionaltests/client/v1/smoke/test_secrets.py functionaltests/common/__init__.py functionaltests/common/cleanup.py functionaltests/common/config.py functionaltests/common/keys.py playbooks/python-barbicanclient-dsvm/post.yaml playbooks/python-barbicanclient-dsvm/run.yaml python_barbicanclient.egg-info/PKG-INFO python_barbicanclient.egg-info/SOURCES.txt python_barbicanclient.egg-info/dependency_links.txt python_barbicanclient.egg-info/entry_points.txt python_barbicanclient.egg-info/not-zip-safe python_barbicanclient.egg-info/pbr.json python_barbicanclient.egg-info/requires.txt python_barbicanclient.egg-info/top_level.txt releasenotes/notes/use-only-uuid-from-href-81710d1b388dce57.yamlpython-barbicanclient-4.10.0/python_barbicanclient.egg-info/pbr.json0000664000175000017500000000005613620530306025605 0ustar zuulzuul00000000000000{"git_version": "e5fdd10", "is_release": true}python-barbicanclient-4.10.0/python_barbicanclient.egg-info/top_level.txt0000664000175000017500000000001713620530306026656 0ustar zuulzuul00000000000000barbicanclient python-barbicanclient-4.10.0/python_barbicanclient.egg-info/dependency_links.txt0000664000175000017500000000000113620530306030174 0ustar zuulzuul00000000000000 python-barbicanclient-4.10.0/.zuul.yaml0000664000175000017500000000141613620530200020027 0ustar zuulzuul00000000000000- job: name: python-barbicanclient-dsvm parent: legacy-dsvm-base run: playbooks/python-barbicanclient-dsvm/run.yaml post-run: playbooks/python-barbicanclient-dsvm/post.yaml timeout: 4200 required-projects: - openstack/devstack-gate - openstack/barbican - openstack/barbican-tempest-plugin - openstack/python-barbicanclient - project: templates: - check-requirements - openstack-lower-constraints-jobs - openstack-python-jobs - openstack-python35-jobs - openstack-python36-jobs - openstack-python37-jobs - openstackclient-plugin-jobs - publish-openstack-docs-pti check: jobs: - python-barbicanclient-dsvm gate: jobs: - python-barbicanclient-dsvm python-barbicanclient-4.10.0/doc/0000775000175000017500000000000013620530306016640 5ustar zuulzuul00000000000000python-barbicanclient-4.10.0/doc/source/0000775000175000017500000000000013620530306020140 5ustar zuulzuul00000000000000python-barbicanclient-4.10.0/doc/source/reference/0000775000175000017500000000000013620530306022076 5ustar zuulzuul00000000000000python-barbicanclient-4.10.0/doc/source/reference/index.rst0000664000175000017500000000245313620530200023734 0ustar zuulzuul00000000000000========= Reference ========= Client ====== .. autofunction:: barbicanclient.client.Client Secrets ======= .. autoclass:: barbicanclient.v1.secrets.SecretManager :members: .. autoclass:: barbicanclient.v1.secrets.Secret :members: Orders ====== .. autoclass:: barbicanclient.v1.orders.OrderManager :members: .. autoclass:: barbicanclient.v1.orders.Order :members: .. autoclass:: barbicanclient.v1.orders.KeyOrder :members: .. autoclass:: barbicanclient.v1.orders.AsymmetricOrder :members: Containers ========== .. autoclass:: barbicanclient.v1.containers.ContainerManager :members: .. autoclass:: barbicanclient.v1.containers.Container :members: .. autoclass:: barbicanclient.v1.containers.RSAContainer :members: .. autoclass:: barbicanclient.v1.containers.CertificateContainer :members: Certificate Authorities ======================= .. autoclass:: barbicanclient.v1.cas.CAManager :members: .. autoclass:: barbicanclient.v1.cas.CA :members: ACLs ==== .. autoclass:: barbicanclient.v1.acls.ACLManager :members: .. autoclass:: barbicanclient.v1.acls.SecretACL :members: :inherited-members: .. autoclass:: barbicanclient.v1.acls.ContainerACL :members: :inherited-members: Exceptions ========== .. automodule:: barbicanclient.exceptions :members: python-barbicanclient-4.10.0/doc/source/install/0000775000175000017500000000000013620530306021606 5ustar zuulzuul00000000000000python-barbicanclient-4.10.0/doc/source/install/index.rst0000664000175000017500000000034713620530200023444 0ustar zuulzuul00000000000000============ Installation ============ At the command line:: $ pip install python-barbicanclient Or, if you have virtualenvwrapper installed:: $ mkvirtualenv python-barbicanclient $ pip install python-barbicanclientpython-barbicanclient-4.10.0/doc/source/index.rst0000664000175000017500000000076013620530200021775 0ustar zuulzuul00000000000000Python bindings to the OpenStack Key Management API (Barbican) ============================================================== This is a client for OpenStack Key Management API (Barbican). There's a Python API (the `barbicanclient` module), and a command-line interface (installed as `barbican`). Contents: .. toctree:: :maxdepth: 2 install/index cli/index contributor/index reference/index .. rubric:: Indices and tables * :ref:`genindex` * :ref:`modindex` * :ref:`search` python-barbicanclient-4.10.0/doc/source/cli/0000775000175000017500000000000013620530306020707 5ustar zuulzuul00000000000000python-barbicanclient-4.10.0/doc/source/cli/details.rst0000664000175000017500000005463413620530200023073 0ustar zuulzuul00000000000000.. ################################################### .. ## WARNING ###################################### .. ############## WARNING ########################## .. ########################## WARNING ############## .. ###################################### WARNING ## .. ################################################### .. ################################################### .. ## .. This file is tool-generated. Do not edit manually. .. http://docs.openstack.org/contributor-guide/ .. doc-tools/cli-reference.html .. ## .. ## WARNING ###################################### .. ############## WARNING ########################## .. ########################## WARNING ############## .. ###################################### WARNING ## .. ################################################### ================================================== Key Manager service (barbican) command-line client ================================================== The barbican client is the command-line interface (CLI) for the Key Manager service (barbican) API and its extensions. This chapter documents :command:`barbican` version ``4.3.0``. For help on a specific :command:`barbican` command, enter: .. code-block:: console $ barbican help COMMAND .. _barbican_command_usage: barbican usage ~~~~~~~~~~~~~~ .. code-block:: console usage: barbican [--version] [-v | -q] [--log-file LOG_FILE] [-h] [--debug] [--no-auth] [--os-identity-api-version ] [--os-auth-url ] [--os-username ] [--os-user-id ] [--os-password ] [--os-user-domain-id ] [--os-user-domain-name ] [--os-tenant-name ] [--os-tenant-id ] [--os-project-id ] [--os-project-name ] [--os-project-domain-id ] [--os-project-domain-name ] [--os-auth-token ] [--endpoint ] [--interface ] [--service-type ] [--service-name ] [--region-name ] [--barbican-api-version ] [--insecure] [--os-cacert ] [--os-cert ] [--os-key ] [--timeout ] .. _barbican_command_options: barbican optional arguments ~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``--version`` show program's version number and exit ``-v, --verbose`` Increase verbosity of output. Can be repeated. ``-q, --quiet`` Suppress output except warnings and errors. ``--log-file LOG_FILE`` Specify a file to log output. Disabled by default. ``-h, --help`` Show help message and exit. ``--debug`` Show tracebacks on errors. ``--no-auth, -N`` Do not use authentication. ``--os-identity-api-version `` Specify Identity API version to use. Defaults to ``env[OS_IDENTITY_API_VERSION]`` or 3. ``--os-auth-url , -A `` Defaults to ``env[OS_AUTH_URL]``. ``--os-username , -U `` Defaults to ``env[OS_USERNAME]``. ``--os-user-id `` Defaults to ``env[OS_USER_ID]``. ``--os-password , -P `` Defaults to ``env[OS_PASSWORD]``. ``--os-user-domain-id `` Defaults to ``env[OS_USER_DOMAIN_ID]``. ``--os-user-domain-name `` Defaults to ``env[OS_USER_DOMAIN_NAME]``. ``--os-tenant-name , -T `` Defaults to ``env[OS_TENANT_NAME]``. ``--os-tenant-id , -I `` Defaults to ``env[OS_TENANT_ID]``. ``--os-project-id `` Another way to specify tenant ID. This option is mutually exclusive with --os-tenant-id. Defaults to ``env[OS_PROJECT_ID]``. ``--os-project-name `` Another way to specify tenant name. This option is mutually exclusive with --os-tenant-name. Defaults to ``env[OS_PROJECT_NAME]``. ``--os-project-domain-id `` Defaults to ``env[OS_PROJECT_DOMAIN_ID]``. ``--os-project-domain-name `` Defaults to ``env[OS_PROJECT_DOMAIN_NAME]``. ``--os-auth-token `` Defaults to ``env[OS_AUTH_TOKEN]``. ``--endpoint , -E `` Defaults to ``env[BARBICAN_ENDPOINT]``. ``--interface `` Defaults to ``env[BARBICAN_INTERFACE]``. ``--service-type `` Defaults to ``env[BARBICAN_SERVICE_TYPE]``. ``--service-name `` Defaults to ``env[BARBICAN_SERVICE_NAME]``. ``--region-name `` Defaults to ``env[BARBICAN_REGION_NAME]``. ``--barbican-api-version `` Defaults to ``env[BARBICAN_API_VERSION]``. .. _barbican_acl_delete: barbican acl delete ------------------- .. code-block:: console usage: barbican acl delete [-h] URI Delete ACLs for a secret or container as identified by its href. **Positional arguments:** ``URI`` The URI reference for the secret or container. **Optional arguments:** ``-h, --help`` show this help message and exit .. _barbican_acl_get: barbican acl get ---------------- .. code-block:: console usage: barbican acl get [-h] [-f {csv,html,json,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--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 .. _barbican_acl_submit: barbican acl submit ------------------- .. code-block:: console usage: barbican acl submit [-h] [-f {csv,html,json,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--quote {all,minimal,none,nonnumeric}] [--user [USERS]] [--project-access | --no-project-access] [--operation-type {read}] URI Submit ACL on a secret or container as identified by its href. **Positional arguments:** ``URI`` The URI reference for the secret or container. **Optional arguments:** ``-h, --help`` show this help message and exit ``--user [USERS], -u [USERS]`` 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 .. _barbican_acl_user_add: barbican acl user add --------------------- .. code-block:: console usage: barbican acl user add [-h] [-f {csv,html,json,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--quote {all,minimal,none,nonnumeric}] [--user [USERS]] [--project-access | --no-project-access] [--operation-type {read}] URI Add ACL users to a secret or container as identified by its href. **Positional arguments:** ``URI`` The URI reference for the secret or container. **Optional arguments:** ``-h, --help`` show this help message and exit ``--user [USERS], -u [USERS]`` 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 .. _barbican_acl_user_remove: barbican acl user remove ------------------------ .. code-block:: console usage: barbican acl user remove [-h] [-f {csv,html,json,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--quote {all,minimal,none,nonnumeric}] [--user [USERS]] [--project-access | --no-project-access] [--operation-type {read}] URI Remove ACL users from a secret or container as identified by its href. **Positional arguments:** ``URI`` The URI reference for the secret or container. **Optional arguments:** ``-h, --help`` show this help message and exit ``--user [USERS], -u [USERS]`` 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 .. _barbican_ca_get: barbican ca get --------------- .. code-block:: console usage: barbican ca get [-h] [-f {html,json,shell,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--prefix PREFIX] URI Retrieve a CA by providing its URI. **Positional arguments:** ``URI`` The URI reference for the CA. **Optional arguments:** ``-h, --help`` show this help message and exit .. _barbican_ca_list: barbican ca list ---------------- .. code-block:: console usage: barbican ca list [-h] [-f {csv,html,json,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--quote {all,minimal,none,nonnumeric}] [--limit LIMIT] [--offset OFFSET] [--name NAME] List CAs. **Optional arguments:** ``-h, --help`` show this help message and exit ``--limit LIMIT, -l LIMIT`` specify the limit to the number of items to list per page (default: 10; maximum: 100) ``--offset OFFSET, -o OFFSET`` specify the page offset (default: 0) ``--name NAME, -n NAME`` specify the ca name (default: None) .. _barbican_secret_container_create: barbican secret container create -------------------------------- .. code-block:: console usage: barbican secret container create [-h] [-f {html,json,shell,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--prefix PREFIX] [--name NAME] [--type TYPE] [--secret SECRET] Store a container in Barbican. **Optional arguments:** ``-h, --help`` show this help message and exit ``--name NAME, -n NAME`` a human-friendly name. ``--type TYPE`` type of container to create (default: generic). ``--secret SECRET, -s SECRET`` one secret to store in a container (can be set multiple times). Example: --secret "private_key=https://url.test/v1/secrets/1-2-3-4" .. _barbican_secret_container_delete: barbican secret container delete -------------------------------- .. code-block:: console usage: barbican secret container delete [-h] URI Delete a container by providing its href. **Positional arguments:** ``URI`` The URI reference for the container **Optional arguments:** ``-h, --help`` show this help message and exit .. _barbican_secret_container_get: barbican secret container get ----------------------------- .. code-block:: console usage: barbican secret container get [-h] [-f {html,json,shell,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--prefix PREFIX] URI Retrieve a container by providing its URI. **Positional arguments:** ``URI`` The URI reference for the container. **Optional arguments:** ``-h, --help`` show this help message and exit .. _barbican_secret_container_list: barbican secret container list ------------------------------ .. code-block:: console usage: barbican secret container list [-h] [-f {csv,html,json,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--quote {all,minimal,none,nonnumeric}] [--limit LIMIT] [--offset OFFSET] [--name NAME] [--type TYPE] List containers. **Optional arguments:** ``-h, --help`` show this help message and exit ``--limit LIMIT, -l LIMIT`` specify the limit to the number of items to list per page (default: 10; maximum: 100) ``--offset OFFSET, -o OFFSET`` specify the page offset (default: 0) ``--name NAME, -n NAME`` specify the container name (default: None) ``--type TYPE, -t TYPE`` specify the type filter for the list (default: None). .. _barbican_secret_delete: barbican secret delete ---------------------- .. code-block:: console usage: barbican secret delete [-h] URI Delete a secret by providing its URI. **Positional arguments:** ``URI`` The URI reference for the secret **Optional arguments:** ``-h, --help`` show this help message and exit .. _barbican_secret_get: barbican secret get ------------------- .. code-block:: console usage: barbican secret get [-h] [-f {html,json,shell,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--prefix PREFIX] [--decrypt] [--payload] [--payload_content_type PAYLOAD_CONTENT_TYPE] URI Retrieve a secret by providing its URI. **Positional arguments:** ``URI`` The URI reference for the secret. **Optional arguments:** ``-h, --help`` show this help message and exit ``--decrypt, -d`` if specified, retrieve the unencrypted secret data; the data type can be specified with --payload_content_type. ``--payload, -p`` if specified, retrieve the unencrypted secret data; the data type can be specified with --payload_content_type. If the user wishes to only retrieve the value of the payload they must add "-f value" to format returning only the value of the payload ``--payload_content_type PAYLOAD_CONTENT_TYPE, -t PAYLOAD_CONTENT_TYPE`` the content type of the decrypted secret (default: text/plain). .. _barbican_secret_list: barbican secret list -------------------- .. code-block:: console usage: barbican secret list [-h] [-f {csv,html,json,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--quote {all,minimal,none,nonnumeric}] [--limit LIMIT] [--offset OFFSET] [--name NAME] [--algorithm ALGORITHM] [--bit-length BIT_LENGTH] [--mode MODE] List secrets. **Optional arguments:** ``-h, --help`` show this help message and exit ``--limit LIMIT, -l LIMIT`` specify the limit to the number of items to list per page (default: 10; maximum: 100) ``--offset OFFSET, -o OFFSET`` specify the page offset (default: 0) ``--name NAME, -n NAME`` specify the secret name (default: None) ``--algorithm ALGORITHM, -a ALGORITHM`` the algorithm filter for the list(default: None). ``--bit-length BIT_LENGTH, -b BIT_LENGTH`` the bit length filter for the list (default: 0). ``--mode MODE, -m MODE`` the algorithm mode filter for the list (default: None). .. _barbican_secret_order_create: barbican secret order create ---------------------------- .. code-block:: console usage: barbican secret order create [-h] [-f {html,json,shell,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--prefix PREFIX] [--name NAME] [--algorithm ALGORITHM] [--bit-length BIT_LENGTH] [--mode MODE] [--payload-content-type PAYLOAD_CONTENT_TYPE] [--expiration EXPIRATION] [--request-type REQUEST_TYPE] [--subject-dn SUBJECT_DN] [--source-container-ref SOURCE_CONTAINER_REF] [--ca-id CA_ID] [--profile PROFILE] [--request-file REQUEST_FILE] type Create a new order. **Positional arguments:** ``type`` the type of the order (key, asymmetric, certificate) to create. **Optional arguments:** ``-h, --help`` show this help message and exit ``--name NAME, -n NAME`` a human-friendly name. ``--algorithm ALGORITHM, -a ALGORITHM`` the algorithm to be used with the requested key (default: aes). ``--bit-length BIT_LENGTH, -b BIT_LENGTH`` the bit length of the requested secret key (default: 256). ``--mode MODE, -m MODE`` the algorithm mode to be used with the requested key (default: cbc). ``--payload-content-type PAYLOAD_CONTENT_TYPE, -t PAYLOAD_CONTENT_TYPE`` the type/format of the secret to be generated (default: application/octet-stream). ``--expiration EXPIRATION, -x EXPIRATION`` the expiration time for the secret in ISO 8601 format. ``--request-type REQUEST_TYPE`` the type of the certificate request. ``--subject-dn SUBJECT_DN`` the subject of the certificate. ``--source-container-ref SOURCE_CONTAINER_REF`` the source of the certificate when using stored-key requests. ``--ca-id CA_ID`` the identifier of the CA to use for the certificate request. ``--profile PROFILE`` the profile of certificate to use. ``--request-file REQUEST_FILE`` the file containing the CSR. .. _barbican_secret_order_delete: barbican secret order delete ---------------------------- .. code-block:: console usage: barbican secret order delete [-h] URI Delete an order by providing its href. **Positional arguments:** ``URI`` The URI reference for the order **Optional arguments:** ``-h, --help`` show this help message and exit .. _barbican_secret_order_get: barbican secret order get ------------------------- .. code-block:: console usage: barbican secret order get [-h] [-f {html,json,shell,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--prefix PREFIX] URI Retrieve an order by providing its URI. **Positional arguments:** ``URI`` The URI reference order. **Optional arguments:** ``-h, --help`` show this help message and exit .. _barbican_secret_order_list: barbican secret order list -------------------------- .. code-block:: console usage: barbican secret order list [-h] [-f {csv,html,json,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--quote {all,minimal,none,nonnumeric}] [--limit LIMIT] [--offset OFFSET] List orders. **Optional arguments:** ``-h, --help`` show this help message and exit ``--limit LIMIT, -l LIMIT`` specify the limit to the number of items to list per page (default: 10; maximum: 100) ``--offset OFFSET, -o OFFSET`` specify the page offset (default: 0) .. _barbican_secret_store: barbican secret store --------------------- .. code-block:: console usage: barbican secret store [-h] [-f {html,json,shell,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--prefix PREFIX] [--name NAME] [--payload PAYLOAD] [--secret-type SECRET_TYPE] [--payload-content-type PAYLOAD_CONTENT_TYPE] [--payload-content-encoding PAYLOAD_CONTENT_ENCODING] [--algorithm ALGORITHM] [--bit-length BIT_LENGTH] [--mode MODE] [--expiration EXPIRATION] Store a secret in Barbican. **Optional arguments:** ``-h, --help`` show this help message and exit ``--name NAME, -n NAME`` a human-friendly name. ``--payload PAYLOAD, -p PAYLOAD`` the unencrypted secret; if provided, you must also provide a payload_content_type ``--secret-type SECRET_TYPE, -s SECRET_TYPE`` the secret type; must be one of symmetric, public, private, certificate, passphrase, opaque (default) ``--payload-content-type PAYLOAD_CONTENT_TYPE, -t PAYLOAD_CONTENT_TYPE`` the type/format of the provided secret data; "text/plain" is assumed to be UTF-8; required when --payload is supplied. ``--payload-content-encoding PAYLOAD_CONTENT_ENCODING, -e PAYLOAD_CONTENT_ENCODING`` required if --payload-content-type is "application /octet-stream". ``--algorithm ALGORITHM, -a ALGORITHM`` the algorithm (default: aes). ``--bit-length BIT_LENGTH, -b BIT_LENGTH`` the bit length (default: 256). ``--mode MODE, -m MODE`` the algorithm mode; used only for reference (default: cbc) ``--expiration EXPIRATION, -x EXPIRATION`` the expiration time for the secret in ISO 8601 format. .. _barbican_secret_update: barbican secret update ---------------------- .. code-block:: console usage: barbican secret update [-h] URI payload Update a secret with no payload in Barbican. **Positional arguments:** ``URI`` The URI reference for the secret. ``payload`` the unencrypted secret **Optional arguments:** ``-h, --help`` show this help message and exit python-barbicanclient-4.10.0/doc/source/cli/usage.rst0000664000175000017500000002663313620530200022550 0ustar zuulzuul00000000000000============ Client Usage ============ 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. See :doc:`authentication` for more details. Example: .. code-block:: python from barbicanclient import client barbican = client.Client(...) The client object has different attributes that can be used to interact with the Barbican service. Each attribute represents an entity in the Barbican 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. Example: .. code-block:: python # Store a random text password in Barbican from barbicanclient import client import random import string def random_password(length): sys_random = random.SystemRandom() return u''.join( sys_random.choice(string.ascii_letters + string.digits) for _ in range(length) ) barbican = client.Client(...) my_secret = barbican.secrets.create() my_secret.name = u'Random plain text password' my_secret.payload = random_password(24) 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. Example: .. code-block:: python # Retrieve Secret from secret reference retrieved_secret = barbican.secrets.get(my_secret_ref) my_password = retrieved_secret.payload 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 `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.binary_type | str | bytes | application/octet-stream | +-----------------+---------------+---------------+--------------------------+ | six.text_type | unicode | str | text/plain | +-----------------+---------------+---------------+--------------------------+ .. WARNING:: Previous versions of python-barbicanclient allowed the user to set the `payload_content_type` and `payload_content_encoding` properties for any secret. This can lead to unexpected behavior such as changing a unicode string back to a byte string in Python 2, and dropping the base64 encoding of a binary secret as in Launchpad Bug #1419166. Because of this, manually setting the `payload_content_type` and the `payload_content_encoding` has been deprecated. Orders ====== 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`. Example: .. code-block:: python # Submit an order to generate a random encryption key from barbicanclient import client barbican = client.Client(...) my_order = barbican.orders.create_key() my_order.algorithm = 'AES' my_order.mode = 'CBC' my_order.bit_length = 256 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. Example: .. code-block:: python # Retrieve Order from order reference 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 secret (or container). Example: .. code-block:: python # Retrieve Encryption Key generated by the above KeyOrder generated_secret = barbican.secrets.get(retrieved_order.secret_ref) 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. 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 should be managed using the :class:`barbicanclient.containers.ContainerManager` instance in the `containers` attribute of the `Client` Example: .. code-block:: python # Add the Secrets created above to a container my_container = barbican.containers.create() my_container.add('Retrieved Secret', retrieved_secret) my_container.add('Generated Secret', generated_secret) 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. Example: .. code-block:: python # Retrieve container from Barbican 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: .. code-block:: python # 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: .. code-block:: python # 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: .. code-block:: python # 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: .. code-block:: python # 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: .. code-block:: python # 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: .. code-block:: python # 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() python-barbicanclient-4.10.0/doc/source/cli/index.rst0000664000175000017500000000021313620530200022535 0ustar zuulzuul00000000000000================== User Documentation ================== .. toctree:: :maxdepth: 2 cli_usage authentication usage details python-barbicanclient-4.10.0/doc/source/cli/cli_usage.rst0000664000175000017500000006460613620530200023401 0ustar zuulzuul00000000000000CLI Usage ========= .. code-block:: bash usage: barbican [--version] [-v] [--log-file LOG_FILE] [-q] [-h] [--debug] [--no-auth] [--os-identity-api-version ] [--os-auth-url ] [--os-username ] [--os-user-id ] [--os-password ] [--os-user-domain-id ] [--os-user-domain-name ] [--os-tenant-name ] [--os-tenant-id ] [--os-project-id ] [--os-project-name ] [--os-project-domain-id ] [--os-project-domain-name ] [--os-auth-token ] [--endpoint ] [--insecure] [--os-cacert ] [--os-cert ] [--os-key ] [--timeout ] The examples below assume that credentials have been saved to your environment. 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 , which specifies whether you wish to operate on a secret or an order. Secrets ------- .. code-block:: bash $ barbican secret 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: .. code-block:: bash secret delete Delete a secret by providing its URI. secret get Retrieve a secret by providing its URI. secret list List secrets. secret store Store a secret in Barbican. Each subcommand takes in a different set of arguments, and the help message varies from one to another. The help message for **get** can be seen below. .. code-block:: bash $ barbican help secret get usage: barbican secret get [-h] [-f {json,shell,table,value,yaml}] [-c COLUMN] [--max-width ] [--fit-width] [--print-empty] [--noindent] [--prefix PREFIX] [--decrypt | --payload | --file ] [--payload_content_type PAYLOAD_CONTENT_TYPE] URI Retrieve a secret by providing its URI. positional arguments: URI The URI reference for the secret. optional arguments: -h, --help show this help message and exit --decrypt, -d if specified, retrieve the unencrypted secret data. --payload, -p if specified, retrieve the unencrypted secret data. --file , -F if specified, save the payload to a new file with the given filename. --payload_content_type PAYLOAD_CONTENT_TYPE, -t PAYLOAD_CONTENT_TYPE the content type of the decrypted secret (default: text/plain). output formatters: output formatter options -f {shell,table,value}, --format {shell,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 Maximum display width, 0 to disable shell formatter: a format a UNIX shell can parse (variable="value") --prefix PREFIX add a prefix to all variable names Secret Create ~~~~~~~~~~~~~ .. code-block:: bash $ barbican secret store -n mysecretname -p 'my secret value' +---------------+-----------------------------------------------------------------------+ | Field | Value | +---------------+-----------------------------------------------------------------------+ | Secret href | http://localhost:9311/v1/secrets/a70a45d8-4076-42a2-b111-8893d3b92a3e | | Name | mysecretname | | Created | None | | Status | None | | Content types | None | | Algorithm | aes | | Bit length | 256 | | Mode | cbc | | Expiration | None | +---------------+-----------------------------------------------------------------------+ Instead of using the :code:`-p` or :code:`--payload` option with the value of the secret in the command line, the value of the secret may be stored in a file. For this method the :code:`-F ` or :code:`--file ` option can be used. Secret Get ~~~~~~~~~~ .. code-block:: bash $ barbican secret get http://localhost:9311/v1/secrets/a70a45d8-4076-42a2-b111-8893d3b92a3e +---------------+-----------------------------------------------------------------------+ | Field | Value | +---------------+-----------------------------------------------------------------------+ | Secret href | http://localhost:9311/v1/secrets/a70a45d8-4076-42a2-b111-8893d3b92a3e | | Name | mysecretname | | Created | 2015-04-16 20:36:40.334696+00:00 | | Status | ACTIVE | | Content types | {u'default': u'application/octet-stream'} | | Algorithm | aes | | Bit length | 256 | | Mode | cbc | | Expiration | None | +---------------+-----------------------------------------------------------------------+ To retrieve only the raw value of the payload we have introduced the :code:`-p` or :code:`--payload` option paired with the :code:`-f value` cliff formatting option. (The :code:`--decrypt` option will perform the same action; however, it will be deprecated) .. code-block:: bash $ barbican secret get http://localhost:9311/v1/secrets/a70a45d8-4076-42a2-b111-8893d3b92a3e --payload -f value my secret value Instead of using the :code:`-p` or :code:`--payload` option with the value of the secret returned to stdout, the value of the secret may be written to a file. For this method the :code:`-F ` or :code:`--file ` option can be used. Secret Delete ~~~~~~~~~~~~~ .. code-block:: bash $ barbican secret delete http://localhost:9311/v1/secrets/a70a45d8-4076-42a2-b111-8893d3b92a3e Secret Update ~~~~~~~~~~~~~ .. code-block:: bash $ barbican secret update http://localhost:9311/v1/secrets/a70a45d8-4076-42a2-b111-8893d3b92a3e ``my_payload`` In order for a secret to be updated it must have been created without a payload. ``my_payload`` will be added as the secret's payload. Secret List ~~~~~~~~~~~ .. code-block:: bash $ barbican secret list +-----------------------------------------------------------------------+------+----------------------------------+--------+-------------------------------------------+-----------+------------+------+------------+ | Secret href | Name | Created | Status | Content types | Algorithm | Bit length | Mode | Expiration | +-----------------------------------------------------------------------+------+----------------------------------+--------+-------------------------------------------+-----------+------------+------+------------+ | 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 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 ] [--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 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 ] [--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 ] [--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 ] [--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 | +----------------+----------------+-------+---------+---------+---------------------------------------------------------------------------+ python-barbicanclient-4.10.0/doc/source/cli/authentication.rst0000664000175000017500000001213213620530200024450 0ustar zuulzuul00000000000000Authentication ============== Keystone Authentication ----------------------- The client defers authentication to `Keystone Sessions`_, which provide several authentication plugins in the `keystoneauth1.identity` namespace. Below we give examples of the most commonly used auth plugins. .. _`Keystone Sessions`: https://docs.openstack.org/keystoneauth/latest/using-sessions.html Keystone API Version 3 Authentication ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Authentication using Keystone API Version 3 can be achieved using the `keystoneauth1.identity.V3Password` auth plugin. Example: .. code-block:: python from barbicanclient import client from keystoneauth1 import identity from keystoneauth1 import session auth = identity.V3Password(auth_url='http://localhost:5000/v3', username='admin_user', user_domain_name='Default', password='password', project_name='demo', project_domain_name='Default') sess = session.Session(auth=auth) barbican = client.Client(session=sess) Keystone API Version 2 Authentication ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Authentication using Keystone API Version 2 can be achieved using the `keystoneauth1.identity.V2Password` auth plugin. Example: .. code-block:: python from barbicanclient import client from keystoneauth1 import identity from keystoneauth1 import session auth = identity.V2Password(auth_url='http://localhost:5000/v2.0', username='admin_user', password='password', tenant_name='demo') sess = session.Session(auth=auth) barbican = client.Client(session=sess) Unauthenticated Context ----------------------- Sometimes it may be useful to work with the client in an unauthenticated context, for example when using a development instance of Barbican that is not yet configured to use Keystone for authentication. In this case, the Barbican Service endpoint must be provided, in addition to the Project ID that will be used for context (i.e. the project that owns the secrets you'll be working with). Example: .. code-block:: python from barbicanclient import client barbican = client.Client(endpoint='http://localhost:9311', project_id='123456') CLI Authentication ================== Keystone V3 Authentication -------------------------- Barbican can be configured to use Keystone for authentication. The user's credentials can be passed to Barbican via arguments. .. code-block:: bash $ barbican --os-auth-url --os-project-domain-id \ --os-user-domain-id --os-username \ --os-password --os-project-name secret list This can become annoying and tedious, so authentication via Keystone can also be configured by setting environment variables. Barbican uses the same env variables as python-keystoneclient so if you already have keystone client configured you can skip this section. An example clientrc file is provided in the main python-barbicanclient directory. .. code-block:: bash export OS_PROJECT_NAME= # Either Project Domain ID or Project Domain Name is required export OS_PROJECT_DOMAIN_ID= export OS_PROJECT_DOMAIN_NAME= # Either User Domain ID or User Domain Name is required export OS_USER_DOMAIN_ID= export OS_USER_DOMAIN_NAME= # Either User ID or Username can be used export OS_USER_ID = export OS_USERNAME= export OS_PASSWORD= # OS_AUTH_URL should be your location of Keystone # Barbican Client defaults to Keystone V3 export OS_AUTH_URL=":5000/v3/" export BARBICAN_ENDPOINT=":9311" Make any appropriate changes to this file. You will need to source it into your environment on each load: .. code-block:: bash source ~/clientrc If you would like, you can configure your bash to load the variables on each login: .. code-block:: bash echo "source ~/clientrc" >> ~/.bashrc Keystone Token Authentication ----------------------------- Barbican can be configured to use Keystone tokens for authentication. The user's credentials can be passed to Barbican via arguments. .. code-block:: bash $ barbican --os-auth-url --os-auth-token \ --os-project-id secret list Much like normal password authentication you can specify these values via environmental variables. Refer to `Keystone V3 authentication`_ for more information. No Auth Mode ------------ When working with a Barbican instance that does not use Keystone authentication (e.g. during development) you can use the :code:`--no-auth` option. If you do this, you'll have to specify the Barbican endpoint and project ID :code:`--os-project-id`. This is because Barbican normally gets the endpoint and tenant ID from Keystone. python-barbicanclient-4.10.0/doc/source/conf.py0000775000175000017500000000532613620530200021441 0ustar zuulzuul00000000000000# 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. import os import sys sys.path.insert(0, os.path.abspath('../..')) # -- General configuration ---------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = [ 'sphinx.ext.autodoc', #'sphinx.ext.intersphinx', 'openstackdocstheme', 'sphinxcontrib.rsvgconverter', ] # autodoc generation is a bit aggressive and a nuisance when doing heavy # text edit cycles. # execute "export SPHINX_DEBUG=1" in your terminal to disable autoclass_content = 'both' # The suffix of source filenames. source_suffix = '.rst' # The master toctree document. master_doc = 'index' # General information about the project. copyright = u'2014, OpenStack Foundation' # If true, '()' will be appended to :func: etc. cross-reference text. add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). add_module_names = True # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # -- Options for HTML output -------------------------------------------------- # The theme to use for HTML and HTML Help pages. Major themes that come with # Sphinx are currently 'default' and 'sphinxdoc'. # html_theme_path = ["."] # html_theme = '_theme' # html_static_path = ['static'] html_theme_options = {} html_theme = 'openstackdocs' # Output file base name for HTML help builder. htmlhelp_basename = 'python-barbicanclientdoc' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass # [howto/manual]). latex_documents = [ ('index', 'doc-python-barbicanclient.tex', u'python-barbicanclient Documentation', u'OpenStack Foundation', 'manual'), ] latex_use_xindy = False # Example configuration for intersphinx: refer to the Python standard library. #intersphinx_mapping = {'http://docs.python.org/': None} # -- Options for openstackdocstheme ------------------------------------------- repository_name = 'openstack/python-barbicanclient' bug_project = 'python-barbicanclient' bug_tag = '' python-barbicanclient-4.10.0/doc/source/contributor/0000775000175000017500000000000013620530306022512 5ustar zuulzuul00000000000000python-barbicanclient-4.10.0/doc/source/contributor/testing.rst0000664000175000017500000001325113620530200024714 0ustar zuulzuul00000000000000Writing and Running Barbican Client Tests ========================================= As a part of every code review that is submitted to the python-barbicanclient project there are a number of gating jobs which aid in the prevention of regression issues within python-barbicanclient. As a result, a python-barbicanclient developer should be familiar with running python-barbicanclient tests locally. For your convenience we provide the ability to run all tests through the ``tox`` utility. If you are unfamiliar with tox please see refer to the `tox documentation`_ for assistance. .. _`tox documentation`: https://tox.readthedocs.org/en/latest/ Unit Tests ---------- Currently, we provide tox environments for Python 2.7. By default all available test environments within the tox configuration will execute when calling ``tox``. If you want to run them independently, you can do so with the following command: .. code-block:: bash # Executes tests on Python 2.7 tox -e py27 .. note:: If you do not have the appropriate Python versions available, consider setting up PyEnv to install multiple versions of Python. See the documentation `setting up a Barbican development environment `_. .. note:: Individual unit tests can also be run, using the following commands: .. code-block:: bash # runs a single test with the function named # test_should_entity_str tox -e py27 -- test_should_entity_str # runs only tests in the WhenTestingSecrets class and # the WhenTestingOrderManager class tox -e py27 -- '(WhenTestingSecrets|WhenTestingOrderManager)' The function name or class specified must be one located in the `barbicanclient/tests` directory. Groups of tests can also be run with a regex match after the ``--``. For more information on what can be done with ``testr``, please see: http://testrepository.readthedocs.org/en/latest/MANUAL.html You can also setup breakpoints in the unit tests. This can be done by adding ``import pdb; pdb.set_trace()`` to the line of the unit test you want to examine, then running the following command: .. code-block:: bash # Executes tests on Python 2.7 tox -e debug .. note:: For a list of pdb commands, please see: https://docs.python.org/2/library/pdb.html Functional Tests ---------------- Unlike running unit tests, the functional tests require Barbican and Keystone services to be running in order to execute. For more information on `setting up a Barbican development environment `_ and using `Keystone with Barbican `_, see our accompanying project documentation. A configuration file for functional tests must be edited before the tests can be run. In the top-level directory of the python-barbicanclient, edit ``/etc/functional_tests.conf`` to the values you setup in Keystone. .. code-block:: bash [DEFAULT] # Leaving this as a placeholder [keymanager] # Replace values that represent barbican server and user information url=http://localhost:9311 username=barbican password=secretservice project_name=service project_id=service #max_payload_size=10000 project_domain_name=Default [identity] # Replace these with values that represent your identity configuration uri=http://localhost:5000/v2.0 uri_v3=http://localhost:5000/v3 auth_version=v3 username=admin tenant_name=admin password=password domain_name=Default admin_username=admin admin_tenant_name=admin admin_password=password admin_domain_name=Default [identity-feature-enabled] # Leaving this as a placeholder Once you have the appropriate services running and configured you can execute the functional tests through tox. .. code-block:: bash # Execute Barbican Functional Tests tox -e functional By default, the functional tox job will use nosetests to execute the functional tests. This is primarily due to nose being a very well known and common workflow among developers. .. note:: In order to run individual functional test functions, you must use the following commands: .. code-block:: bash # runs only tests in the test_secrets.py file tox -e functional -- client/v1/functional/test_secrets.py # runs only tests in the SecretsTestCase class tox -e functional -- client/v1/functional/test_secrets.py:\ SecretsTestCase # runs a single test with the function named # test_secret_create_defaults_check_content_types tox -e functional -- client/v1/functional/test_secrets.py:\ SecretsTestCase.test_secret_create_defaults_check_content_types The path specified must be one located in the `functionaltests` directory. Remote Debugging ---------------- In order to be able to hit break-points on API calls, you must use remote debugging. This can be done by adding ``import rpdb; rpdb.set_trace()`` to the line of the API call you wish to test. For example, adding the breakpoint in ``def create`` in ``barbicanclient.secrets.py`` will allow you to hit the breakpoint whenever the ``create`` function is called. .. note:: After performing the ``POST`` the application will freeze. In order to use ``rpdb``, you must open up another terminal and run the following: .. code-block:: bash # enter rpdb using telnet telnet localhost 4444 Once in rpdb, you can use the same commands as pdb, as seen here: https://docs.python.org/2/library/pdb.html python-barbicanclient-4.10.0/doc/source/contributor/index.rst0000664000175000017500000000022113620530200024337 0ustar zuulzuul00000000000000========================= Contributor Documentation ========================= .. toctree:: :maxdepth: 2 contributing.rst testing.rst python-barbicanclient-4.10.0/doc/source/contributor/contributing.rst0000664000175000017500000000011713620530200025743 0ustar zuulzuul00000000000000============ Contributing ============ .. include:: ../../../CONTRIBUTING.rst python-barbicanclient-4.10.0/doc/requirements.txt0000664000175000017500000000063313620530200022117 0ustar zuulzuul00000000000000# The order of packages is significant, because pip processes them in the order # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. sphinx!=1.6.6,!=1.6.7,>=1.6.2,<2.0.0;python_version=='2.7' # BSD sphinx>=1.8.0,!=2.1.0;python_version>='3.4' # BSD sphinxcontrib-svg2pdfconverter>=0.1.0 # BSD openstackdocstheme>=1.20.0 # Apache-2.0 python-barbicanclient-4.10.0/requirements.txt0000664000175000017500000000072613620530200021355 0ustar zuulzuul00000000000000# The order of packages is significant, because pip processes them in the order # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. pbr!=2.1.0,>=2.0.0 # Apache-2.0 requests>=2.14.2 # Apache-2.0 six>=1.10.0 # MIT cliff!=2.9.0,>=2.8.0 # Apache-2.0 keystoneauth1>=3.4.0 # Apache-2.0 oslo.i18n>=3.15.3 # Apache-2.0 oslo.serialization!=2.19.1,>=2.18.0 # Apache-2.0 oslo.utils>=3.33.0 # Apache-2.0 python-barbicanclient-4.10.0/CONTRIBUTING.rst0000664000175000017500000000106413620530200020526 0ustar zuulzuul00000000000000If you would like to contribute to the development of OpenStack, you must follow the steps in this page: https://docs.openstack.org/infra/manual/developers.html Once those steps have been completed, changes to OpenStack should be submitted for review via the Gerrit tool, following the workflow documented at: https://docs.openstack.org/infra/manual/developers.html#development-workflow Pull requests submitted through GitHub will be ignored. Bugs should be filed on OpenStack StoryBoard, not GitHub: https://storyboard.openstack.org/#!/project/984 python-barbicanclient-4.10.0/.mailmap0000664000175000017500000000044513620530200017510 0ustar zuulzuul00000000000000Douglas Mendizábal Douglas Mendizábal Douglas Mendizábal John Wood jfwood python-barbicanclient-4.10.0/LICENSE0000664000175000017500000002614613620530200017102 0ustar zuulzuul00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2013, Rackspace (http://www.rackspace.com) 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.python-barbicanclient-4.10.0/setup.py0000664000175000017500000000200613620530200017574 0ustar zuulzuul00000000000000# Copyright (c) 2013 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. # THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT import setuptools # In python < 2.7.4, a lazy loading of package `pbr` will break # setuptools if some other modules registered functions in `atexit`. # solution from: http://bugs.python.org/issue15881#msg170215 try: import multiprocessing # noqa except ImportError: pass setuptools.setup( setup_requires=['pbr>=2.0.0'], pbr=True) python-barbicanclient-4.10.0/README.rst0000664000175000017500000002416613620530200017564 0ustar zuulzuul00000000000000python-barbicanclient ===================== .. image:: https://img.shields.io/pypi/v/python-barbicanclient.svg :target: https://pypi.org/project/python-barbicanclient/ :alt: Latest Version This is a client for the `Barbican `__ Key Management API. There is a Python library for accessing the API (`barbicanclient` module), and a command-line script (`barbican`). Installation ------------ The client is `pip installable `__ as follows: .. code:: console pip install python-barbicanclient barbicanclient - Python Library ------------------------------- The full api is `documented in the official OpenStack documentation site `__. Here's an example of storing a secret in barbican using the python library with keystone authentication: .. code:: python >>> from keystoneclient.auth import identity >>> from keystoneauth1 import session >>> from barbicanclient import client >>> # We'll use Keystone API v3 for authentication >>> auth = identity.v3.Password(auth_url=u'http://localhost:5000/v3', ... username=u'admin_user', ... user_domain_name=u'Default', ... password=u'password', ... project_name=u'demo', ... project_domain_name=u'Default') >>> # Next we'll create a Keystone session using the auth plugin we just created >>> sess = session.Session(auth=auth) >>> # Now we use the session to create a Barbican client >>> barbican = client.Client(session=sess) >>> # Let's create a Secret to store some sensitive data >>> secret = barbican.secrets.create(name=u'Self destruction sequence', ... payload=u'the magic words are squeamish ossifrage') >>> # Now let's store the secret by using its store() method. This will send the secret data >>> # to Barbican, where it will be encrypted and stored securely in the cloud. >>> secret.store() u'http://localhost:9311/v1/secrets/85b220fd-f414-483f-94e4-2f422480f655' >>> # The URI returned by store() uniquely identifies your secret in the Barbican service. >>> # After a secret is stored, the URI is also available by accessing >>> # the secret_ref attribute. >>> print(secret.secret_ref) http://localhost:9311/v1/secrets/091adb32-4050-4980-8558-90833c531413 >>> # When we need to retrieve our secret at a later time, we can use the secret_ref >>> retrieved_secret = barbican.secrets.get(u'http://localhost:9311/v1/secrets/091adb32-4050-4980-8558-90833c531413') >>> # We can access the secret payload by using the payload attribute. >>> # Barbican decrypts the secret and sends it back. >>> print(retrieved_secret.payload) the magic words are squeamish ossifrage .. note:: In order for the example above to work Barbican must be running and configured to use the Keystone Middleware. For more information on setting this up please visit: https://docs.openstack.org/barbican/latest/configuration/keystone.html [1]_ barbican - Command Line Client ------------------------------ The command line client is self-documenting. Use the --help flag to access the usage options .. code:: console $ barbican --help usage: barbican [--version] [-v] [--log-file LOG_FILE] [-q] [-h] [--debug] [--no-auth] [--os-identity-api-version ] [--os-auth-url ] [--os-username ] [--os-user-id ] [--os-password ] [--os-user-domain-id ] [--os-user-domain-name ] [--os-tenant-name ] [--os-tenant-id ] [--os-project-id ] [--os-project-name ] [--os-project-domain-id ] [--os-project-domain-name ] [--endpoint ] [--insecure] [--os-cacert ] [--os-cert ] [--os-key ] [--timeout ] Command-line interface to the Barbican API. optional arguments: --version show program's version number and exit -v, --verbose Increase verbosity of output. Can be repeated. --log-file LOG_FILE Specify a file to log output. Disabled by default. -q, --quiet suppress output except warnings and errors -h, --help show this help message and exit --debug show trace backs on errors --no-auth, -N Do not use authentication. --os-identity-api-version Specify Identity API version to use. Defaults to env[OS_IDENTITY_API_VERSION] or 3. --os-auth-url , -A Defaults to env[OS_AUTH_URL]. --os-username , -U Defaults to env[OS_USERNAME]. --os-user-id Defaults to env[OS_USER_ID]. --os-password , -P Defaults to env[OS_PASSWORD]. --os-user-domain-id Defaults to env[OS_USER_DOMAIN_ID]. --os-user-domain-name Defaults to env[OS_USER_DOMAIN_NAME]. --os-tenant-name , -T Defaults to env[OS_TENANT_NAME]. --os-tenant-id , -I Defaults to env[OS_TENANT_ID]. --os-project-id Another way to specify tenant ID. This option is mutually exclusive with --os-tenant-id. Defaults to env[OS_PROJECT_ID]. --os-project-name Another way to specify tenant name. This option is mutually exclusive with --os-tenant-name. Defaults to env[OS_PROJECT_NAME]. --os-project-domain-id Defaults to env[OS_PROJECT_DOMAIN_ID]. --os-project-domain-name Defaults to env[OS_PROJECT_DOMAIN_NAME]. --endpoint , -E --endpoint , -E Defaults to env[BARBICAN_ENDPOINT]. --insecure Explicitly allow client to perform "insecure" TLS (https) requests. The server's certificate will not be verified against any certificate authorities. This option should be used with caution. --os-cacert Specify a CA bundle file to use in verifying a TLS (https) server certificate. Defaults to env[OS_CACERT]. --os-cert Defaults to env[OS_CERT]. --os-key Defaults to env[OS_KEY]. --timeout Set request timeout (in seconds). See "barbican help COMMAND" for help on a specific command. Commands: 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. ca get Retrieve a CA by providing its URI. ca list List CAs. complete print bash completion command secret container create Store a container in Barbican. secret container delete Delete a container by providing its href. secret container get Retrieve a container by providing its URI. secret container list List containers. help print detailed help for another command secret order create Create a new order. secret order delete Delete an order by providing its href. secret order get Retrieve an order by providing its URI. secret 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 * `PyPi`_ - package installation * `Online Documentation`_ * `Launchpad project`_ - release management * `Blueprints`_ - feature specifications * `Bugs`_ - issue tracking * `Source`_ * `Specs`_ * `Getting involved`_ .. _PyPi: https://pypi.org/project/python-barbicanclient/ .. _Online Documentation: https://docs.openstack.org/python-barbicanclient/latest/ .. _Launchpad project: https://launchpad.net/python-barbicanclient/ .. _Blueprints: https://blueprints.launchpad.net/python-barbicanclient/ .. _Bugs: https://storyboard.openstack.org/#!/project/984 .. _Source: https://git.openstack.org/cgit/openstack/python-barbicanclient/ .. _Getting involved: https://docs.openstack.org/barbican/latest/contributor/getting_involved.html .. _Specs: https://specs.openstack.org/openstack/barbican-specs/ .. [1] Documentation in this link is currently incomplete. Please use the `devstack setup `__. python-barbicanclient-4.10.0/playbooks/0000775000175000017500000000000013620530306020076 5ustar zuulzuul00000000000000python-barbicanclient-4.10.0/playbooks/python-barbicanclient-dsvm/0000775000175000017500000000000013620530306025324 5ustar zuulzuul00000000000000python-barbicanclient-4.10.0/playbooks/python-barbicanclient-dsvm/post.yaml0000664000175000017500000000063313620530200027170 0ustar zuulzuul00000000000000- hosts: primary tasks: - name: Copy files from {{ ansible_user_dir }}/workspace/ on node synchronize: src: '{{ ansible_user_dir }}/workspace/' dest: '{{ zuul.executor.log_root }}' mode: pull copy_links: true verify_host: true rsync_opts: - --include=/logs/** - --include=*/ - --exclude=* - --prune-empty-dirs python-barbicanclient-4.10.0/playbooks/python-barbicanclient-dsvm/run.yaml0000664000175000017500000000402613620530200027007 0ustar zuulzuul00000000000000- hosts: all name: Autoconverted job legacy-python-barbicanclient-dsvm from old job gate-python-barbicanclient-dsvm-ubuntu-xenial tasks: - name: Ensure legacy workspace directory file: path: '{{ ansible_user_dir }}/workspace' state: directory - shell: cmd: | set -e set -x cat > clonemap.yaml << EOF clonemap: - name: openstack/devstack-gate dest: devstack-gate EOF /usr/zuul-env/bin/zuul-cloner -m clonemap.yaml --cache-dir /opt/git \ https://opendev.org \ openstack/devstack-gate executable: /bin/bash chdir: '{{ ansible_user_dir }}/workspace' environment: '{{ zuul | zuul_legacy_vars }}' - shell: cmd: | set -e set -x cat << 'EOF' >>"/tmp/dg-local.conf" [[local|localrc]] enable_plugin barbican https://opendev.org/openstack/barbican EOF executable: /bin/bash chdir: '{{ ansible_user_dir }}/workspace' environment: '{{ zuul | zuul_legacy_vars }}' - shell: cmd: | set -e set -x export PYTHONUNBUFFERED=true export OVERRIDE_ENABLED_SERVICES=tempest,rabbit,mysql,key export PROJECTS="openstack/barbican $PROJECTS" export PROJECTS="openstack/python-barbicanclient $PROJECTS" export PROJECTS="openstack/barbican-tempest-plugin $PROJECTS" function gate_hook { $BASE/new/barbican/devstack/gate_hook.sh } export -f gate_hook function post_test_hook { cd /opt/stack/new/python-barbicanclient/functionaltests ./post_test_hook.sh } export -f post_test_hook cp devstack-gate/devstack-vm-gate-wrap.sh ./safe-devstack-vm-gate-wrap.sh ./safe-devstack-vm-gate-wrap.sh executable: /bin/bash chdir: '{{ ansible_user_dir }}/workspace' environment: '{{ zuul | zuul_legacy_vars }}' python-barbicanclient-4.10.0/tox.ini0000664000175000017500000000374013620530200017403 0ustar zuulzuul00000000000000[tox] minversion = 2.0 envlist = py35,py36,py27,pep8 skipsdist = True [testenv] usedevelop = True install_command = pip install {opts} {packages} setenv = PYTHON=coverage run --source barbicanclient --parallel-mode VIRTUAL_ENV={envdir} deps = -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} -r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt commands = rm -f .testrepository/times.dbm coverage erase stestr run {posargs} coverage combine coverage html -d cover coverage xml -o cover/coverage.xml coverage report -m whitelist_externals = rm [testenv:debug] basepython = python3 commands = oslo_debug_helper -t barbicanclient/tests {posargs} [testenv:pep8] basepython = python3 commands = flake8 {posargs} [testenv:venv] basepython = python3 commands = {posargs} [testenv:docs] # This environment is called from CI scripts to test and publish # the main docs to https://docs.openstack.org/python-barbicanclient description = Build main documentation basepython = python3 deps = -r{toxinidir}/doc/requirements.txt commands= rm -rf doc/build/html doc/build/doctrees sphinx-build -W -b html -d doc/build/doctrees doc/source doc/build/html whitelist_externals = rm [testenv:pdf-docs] basepython = python3 deps = {[testenv:docs]deps} whitelist_externals = make rm commands = rm -rf doc/build/pdf sphinx-build -W -b latex doc/source doc/build/pdf make -C doc/build/pdf [testenv:functional] # This tox env is purely to make local test development easier # Note: This requires local running instances of Barbican deps = {[testenv]deps} commands = nosetests {toxinidir}/functionaltests/{posargs} -v [flake8] ignore = H202 show-source = True exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build [testenv:lower-constraints] basepython = python3 deps = -c{toxinidir}/lower-constraints.txt -r{toxinidir}/test-requirements.txt -r{toxinidir}/requirements.txt python-barbicanclient-4.10.0/lower-constraints.txt0000664000175000017500000000244713620530200022331 0ustar zuulzuul00000000000000appdirs==1.3.0 asn1crypto==0.23.0 Babel==2.3.4 cffi==1.7.0 cliff==2.8.0 cmd2==0.8.0 coverage==4.1 cryptography==2.1 debtcollector==1.2.0 decorator==3.4.0 deprecation==1.0 dogpile.cache==0.6.2 extras==1.0.0 fixtures==3.0.0 flake8==2.5.5 hacking==0.12.0 idna==2.6 iso8601==0.1.11 jmespath==0.9.0 jsonpatch==1.16 jsonpointer==1.13 jsonschema==2.6.0 keystoneauth1==3.4.0 linecache2==1.0.0 mccabe==0.2.1 mock==2.0.0 monotonic==0.6 mox3==0.20.0 msgpack-python==0.4.0 munch==2.1.0 netaddr==0.7.18 netifaces==0.10.4 nose==1.3.7 openstacksdk==0.11.2 os-client-config==1.28.0 os-service-types==1.2.0 osc-lib==1.8.0 oslo.config==5.2.0 oslo.i18n==3.15.3 oslo.serialization==2.18.0 oslo.utils==3.33.0 oslotest==3.2.0 pbr==2.0.0 pep8==1.5.7 positional==1.2.1 prettytable==0.7.2 pycparser==2.18 pyflakes==0.8.1 pyOpenSSL==17.1.0 pyparsing==2.1.0 pyperclip==1.5.27 python-cinderclient==3.3.0 python-glanceclient==2.8.0 python-keystoneclient==3.8.0 python-mimeparse==1.6.0 python-novaclient==9.1.0 python-openstackclient==3.12.0 python-subunit==1.0.0 pytz==2013.6 PyYAML==3.12 requests==2.14.2 requests-mock==1.2.0 requestsexceptions==1.2.0 rfc3986==0.3.1 simplejson==3.5.1 six==1.10.0 sphinxcontrib-svg2pdfconverter==0.1.0 stevedore==1.20.0 stestr==2.0.0 testtools==2.2.0 traceback2==1.4.0 unittest2==1.1.0 warlock==1.2.0 wrapt==1.7.0 python-barbicanclient-4.10.0/.stestr.conf0000664000175000017500000000006713620530200020340 0ustar zuulzuul00000000000000[DEFAULT] test_path=./barbicanclient/tests top_dir=./ python-barbicanclient-4.10.0/etc/0000775000175000017500000000000013620530306016646 5ustar zuulzuul00000000000000python-barbicanclient-4.10.0/etc/barbicanclient.conf0000664000175000017500000000045213620530200022447 0ustar zuulzuul00000000000000[DEFAULT] # Show more verbose log output (sets INFO log level output) verbose = True # Show debugging output in logs (sets DEBUG log level output) debug = False # Log to this file. Make sure you do not set the same log # file for both the API and registry servers! #log_file = barbicanclient.log python-barbicanclient-4.10.0/etc/functional_tests.conf0000664000175000017500000000121013620530200023064 0ustar zuulzuul00000000000000[DEFAULT] # Leaving this as a placeholder [keymanager] #Replace values that represent barbican server and user information url=http://localhost/key-manager username=barbican password=secretservice project_name=service project_id=service #max_payload_size=10000 project_domain_name=Default [identity] # Replace these with values that represent your identity configuration uri=http://localhost/identity auth_version=v3 username=admin tenant_name=admin password=password domain_name=Default admin_username=admin admin_tenant_name=admin admin_password=password admin_domain_name=Default [identity-feature-enabled] # Leaving this as a placeholder python-barbicanclient-4.10.0/ChangeLog0000664000175000017500000005020113620530306017643 0ustar zuulzuul00000000000000CHANGES ======= 4.10.0 ------ * Support two-way auth for barbicanclient * PDF Documentation Build tox target * docs: Turn on warning-as-error * Fix lower-constraints tox target * Bump the openstackdocstheme extension to 1.20 4.9.0 ----- * OpenDev Migration Patch * Replace openstack.org git:// URLs with https:// * Update json module to jsonutils * add python 3.7 unit test job 4.8.1 ----- * Update hacking version * Secret payload should also be fetched by UUID * Use template for lower-constraints * Update mailinglist from dev to discuss * Change openstack-dev to openstack-discuss * Add Python 3.6 classifier to setup.cfg * add python 3.6 unit test job * Update min tox version to 2.0 4.8.0 ----- * Don't quote {posargs} in tox.ini * Allow fetching by UUID, and respect interface * Import python-barbicanclient-dsvm * add python 3.6 unit test job * switch documentation job to new PTI * import zuul job settings from project-config 4.7.0 ----- * Switch to stestr * fix tox python3 overrides * use open() instead of file() * Remove PyPI downloads * Add --file flag for secrets * Update the bugs link address * Trivial: Update pypi url to new url * add lower-constraints job * Updated from global requirements * pypy is not checked at gate * Follow the new PTI for document build * Supress client debug messages * Update the old http links in docs * Updating time for functional tests * Update doc to use the correct order method 4.6.0 ----- * Updated from global requirements * Updated from global requirements * Pass OSC interface through to barbican plugin * Fix some reST field lists in docstrings * Updated from global requirements * Avoid tox\_install.sh for constraints support * Switch to use new barbican endpoint * Updated from global requirements * Add 'rm -f .testrepository/times.dbm' command in testenv * Updated from global requirements * Updated from global requirements * Correct docs usage of keystoneauth1 session * Updated from global requirements * Updated from global requirements * Updated from global requirements 4.5.2 ----- * Support import modules from barbicanclient.client module 4.5.1 ----- * Workaround for importing objects from old path 4.5.0 ----- * Update api references according to refactor result * Add secret\_type filter to CLI * Updated from global requirements * Update the documentation link for doc migration * Updated from global requirements * fix default version * Updated from global requirements * Update doc references * import content from cli-reference in openstack-manuals * rearrange the existing docs into the new standard layout * Switch from oslosphinx to openstackdocstheme 4.4.0 ----- * Updated from global requirements * Refactor barbicanclient * Updated from global requirements * Updated from global requirements 4.3.0 ----- * Updated from global requirements * Updated from global requirements * Use generic auth plugin instead of specific version * Add client list filter functionality * Updated from global requirements * Updated from global requirements * Updated from global requirements * Extend pep8 test coverage * Updated from global requirements * Update keystone endpoint for functional tests * Updated from global requirements * Correct the regex for parsing output * Replace six.iteritems() with .items() * Enable F and H flake8 rules * Set client module \_\_version\_\_ * Clean up all secrets in functional tests * Updated from global requirements * Updated from global requirements * Fix gate failure on pep8 * Updated from global requirements * Make test directory more specific * Change parent class of \`WhenTestingCertificateOrders\` * Fix serializable issues when retrieving json format resources * [openstack-manuals] description of command barbican ca list * Remove support for py34 * Updated from global requirements * Remove unused barbicanclient/common directory 4.2.0 ----- * Updated from global requirements * Skip order with 'None' payload content type * Remove invalid smoke test that is failing in the gate * Fix doc referencing --payload-content-type * Update .gitignore * Removes unnecessary utf-8 encoding * Updated from global requirements * Remove discover from test-requirements * Replaces uuid.uuid4 with uuidutils.generate\_uuid() * Accept 'pass\_phrase' for AsymmetricOrder constructor * Updated from global requirements * Add missing param to certificate order initialization * Fix error in doc * Removed openstack/common from tox.in * Updated from global requirements * Updated from global requirements * Add Python 3.5 classifier and venv * Updated from global requirements * Use keystoneauth * Fix bug when uploading secret using unified CLI * Fix order of arguments in assertEqual * Add plug-in summary for osc doc * Support upper-constraints in tox.ini * Updated from global requirements * Use 'code-block' for pieces of code * Remove redundant space in docstring * Using assertTrue/False() instead of assertEqual(True/False) * Using assertEqual instead of assertEquals * Remove imported but unused * Add oslo.config to requirements * Handle container list command correctly * Fix CLI message in CA module * Replaced bare except * Cast sets to lists in acl functional tests * Validate key order meta fields * Use international logging message 4.1.0 ----- * Updated from global requirements * Fix jenkins failing on coverage report * Do not write except:, use except Exception instead * Fix argument order for assertEqual to (expected, observed) * Fixed python-barbicanclient functional tests * Updated from global requirements * Remove unused import * Updated from global requirements * Update mailmap for Douglas Mendizábal * Update the home-page with developer documentation link * Issue deprecation message for the barbican CLI * Fixed python-barbicanclient functional tests * Censoring secrets payload value from debug log * Fix argument order for assertEqual to (exp, obs) * Fixed barbican client order list * Display error description * Updated from global requirements 4.0.0 ----- * Replace assertEqual(None, \*) with assertIsNone in tests * Updated from global requirements * Use six.moves.urllib.parse to replace urlparse * Updated from global requirements * Remove argparse from requirements * Updated from global requirements * Updated from global requirements * Replace deprecated keystoneclient...exceptions * Update typos * Remove unused import logging * Update Order Create Type Help Dialog * Removes MANIFEST.in as it is not needed explicitely by PBR * Deprecated tox -downloadcache option removed * Remove py26 support * Updated from global requirements * Updated from global requirements * Updated from global requirements * Make Client test documentation similar to Barbican * Updated from global requirements * Update Readme to include new/updated CLI commands * Allow tox to be able to run independent functional tests * Make CLI Order's type field a required argument * Remove invalid skipping of tests * Fix Secrets Filter * Updated from global requirements * Updated from global requirements * README.rst devstack link not properly displayed * improve readme contents * Updated from global requirements * Add to\_dict method to EntityFormatter * Updated from global requirements * Part 3: Adding ACL functional tests * Updated from global requirements * Initialize optional attributes in CA object * Fix keystone version selection * Part 2: Adding ACL support for CLI commands and docs * Fix incorrect error when performing Barbican Secret Update * Part 1: Adding ACL support for Client API * Fix error where barbican order create returns invalid error * Create Openstack CLI plugin for Barbican * Fix OS\_PROJECT\_ID not getting read by client * Remove Client V1 Behaviors * enable barbican help without authentication * Fix barbican-client README.rst * Add functional test for updating a Secret * Remove test behaviors abstraction for containers smoke tests * Remove test behaviors abstraction for orders smoke tests * Remove test behaviors abstraction for secrets smoke tests * Remove test behaviors abstraction for containers * Remove test behaviors abstraction for orders * Remove test behaviors abstraction for secrets * Create Common functions used for cleaning up items used for testing * Add epilog to parser * Add Unit Tests for Store and Update Payload when Payload is zero * Allow Barbican Client Secret Update Functionality 3.3.0 ----- * Updated from global requirements * Updated from global requirements * Updated from global requirements * Add ability to add and list CAs * Remove unneeded dependency in tox.ini * Adding Documentation for running Functional Tests on the Python-Barbican Client * Updated from global requirements * Updated from global requirements * Updated from global requirements * Updated from global requirements * Added secret type command line option * Updated from global requirements * New mock release(1.1.0) broke unit/function tests * Enable endpoint filter parameters for the CLI * Updated from global requirements * Use keystone discovery instead of endpoint\_override * Updated from global requirements * Updated from global requirements * Updated from global requirements 3.2.0 ----- * Drop incubating theme from docs * Remove tempest config dependency in functional tests * Add capability of specifying Barbican version to client * Remove instances of \_base\_url * Re-merge CLI test update for auth URL and version * Add CLI smoke functional tests for containers * Create behaviors for secrets * Pass in keystone version and correct v2 URL to CLI * Add support for certificate order * Updated from global requirements * Adding new tests to cover failure scenarios * Drop use of 'oslo' namespace package 3.1.1 ----- * Updated from global requirements * Add Secret CLI smoke tests * Fix bug in CLI authentication * Updated from global requirements * Refactored barbican.py for better testability * Update stdout and stderr capture in functional tests * Use keystoneclient to get endpoint if it's empty * Initial setup for command line tests * Fixing misspelling in client docstring * Adding support for token based authentication * Cleaning up validate\_ref() * Update README to work with release tools * Cleaning up Keystone auth tests 3.1.0 ----- * Excluding tests from coverage report * Fix the clientrc file to match defaults and add docs * Updating client and client docs for accuracy * Porting over more documentation to RST from cli wiki * Uncap library requirements for liberty * Adding payload flag to get secret * Raising errors from the client instead of ksclient * Fix order listing on the command line * Fixing the broken functional tests * Use the ksc Adapter instead of custom HTTPClient 3.0.3 ----- * Fix --decrypt command line option * Fix order creation on the command line * Don't ignore payload\_content\_encoding if set * Consolidate Payload Exceptions * Negative tests for orders * Container negative tests * Updated from global requirements * Second set of negative secrets tests * First set of negative functional test for secrets * Fix smoke test for client with bad data set * Fixed deprecated type and encoding test and encoding bug * Removing assertItemsEqual workaround, fixed upstream * Fixes tests on invalid payload secret creation and adds new exception * Ensuring secret ref is not none with payload * Added new exception, renamed test, and adjusted test * Fixed max payload size error * Fix secret-store empty-key filtering bug * Enable usage of 'payload' path to fetch decrypted secrets * Don't use tempest log * Deprecate setting the payload type and encoding * Use functional\_test.conf for devstack gate * Fix when submitting with empty string, none and zero * Fix delete a secret that does not exist * Refactor test modules * Pass correct api object to Container constructor * Moved parameterized test from smoke to functional * Add default max payload to functional test conf registry * Adds positive orders functional tests * Updated functional tests to use both identity v2 and v3 * Do not filter empty strings * Add secret\_type to Secret constructor * Update functionaltests to be able to run tox -e functional * Additional requests-mock testing * Remove cyclical dependency * Convert CRUD tests to requests-mock * Adds orders behaviors and smoke tests * Run client functional tests * Updated from global requirements * Adds positive container functional tests * Add hooks for devstack testing * update tox.ini files to run functional tests * Fix serialization of datetime objects * Remove py33 tox environment * Updated from global requirements * All of the containers behaviors and container smoke tests * Update documentation * Adds positive secrets functional tests * Update documentation * Change usage example to show plain/text secret * Adds base behaviors, secret behaviors and the secret smoke tests * Initial directory changes and files for python-babricanclient functional tests * Drop old namespace for some oslo libraries 3.0.2 ----- * Updated from global requirements * Replace httpretty with requests\_mock * Enable usage of oslo\_debug\_helper from tox * Updated from global requirements * Updated from global requirements * Enable passing test regex to testr from tox * Updated from global requirements * Replace trivial docstring instances of tenant * Workflow documentation is now in infra-manual * Correctly set pbr version name * Trivial change to docs * Defer loading Secret meta-data until requested * Updated from global requirements * Updated from global requirements * Add Usage documentation * Updated from global requirements * Add Python 3 classifiers * Updated from global requirements 3.0.1 ----- * Sync with global requirements * update cliff requirement to >=1.7.0 3.0.0 ----- * Remove unnecessary try/except in container delete * Update Order models * Add sphinx docs * Refactored Client to use Keystone Sessions * Remove outdated examples * Fix consistency between Order/Secret/Container * Remove code from oslo-incubator * Change object \_\_str\_\_() to use pretty formatting * Add Containers to python-barbicanclient * Work toward Python 3.4 support and testing * Refactor client models in python-barbicanclient * Remove hardcoded version * remove tenant-id from uri * Introduce cliff for cli framework 2.2.1 ----- * Update tox.ini to match rest of project 2.2.0 ----- * Fix Testing Failure due to Argparse * Move docstring inside relevant class * Fixed typos in the example files * Add Keystone V3 compliant session/auth plugin support * Added PyPy env to tox.ini * Updating documentation from stackforge to openstack * Added py33 to tox * Fix the gitreview * Remove unnecessary coding line * debug level logs should not be translated * Metaclass Python 3.x Compatibility * Remove Tox from test-requirements.txt * python 3 support * port tests to testtools, add branch coverage, omit openstack common * sync oslo * Remove OpenStack log in favor of native logging * Conditionally validate KeystoneAuthV2 credentials * Add missing tenant\_id to Keystone init * Add version to setup.cfg 2.1.0 ----- * Drop version requirement for argparse 2.0.0 ----- * Remove version from setup.cfg * Use summary not description for the short summary * Switch README.md to README.rst * Migrate to pbr * Rename the command line client to barbican * Add auth plugin for Rackspace Identity * Removing conditional around client status code check * Add filtering CLI options to 'secrets list' sub command * secrets.get should verify that the request is for a single secret * Add .gitreview file for StackForge v1.0.0 ------ * Version bump for Icehouse M1 * Add mailmap file * Remove extra header (H2) in the readme * Update README.md to mention the pypi location, and to add verification information * Client should use endpoint from command line if it is not found in the auth catalog * Add mods per peer review; Added new testing log files to gitignore file; * Remove unused utils file * Fix merge conflicts * Add remaining verification unit test and keep files/mods * Rework logging to support importing externally * Revamped unit tests to remove redundant testing, added some tests for the verification service * Add unit tests for secrets * Add verifications resource * Adding the --insecure cli argument * Fixing typo in exception message * Fixed typo in keep Client initialization * Version bump * Fix a couple of bugs caused by typos v0.4.0 ------ * Version bump * Remove unused exception * Update unit tests for Client * Add total() to both secrets and orders * pep-8 fixes * Update README.md * Rename KeystoneAuth to KeystoneAuthV2 * Update keep to use URIs instead of UUIDs * Last of the changes to Client * Update Client to use hrefs instead of parsing IDs * Raise exceptions for error responses from the server * Update README.md * Clean up imports and update requirements * Add store command to keep. Rename options to match other openstack clients * Update keep to use refactored client * Client.py cleanup * Moved order crud to order manager * Move raw secret get to secret manager * Added get and delete to secret manager * Moved secret create and list into secret manager * Use KeystoneAuth in authenticate method * Added KeystoneAuth class for auth stuff * Added auth param to Client * Rename Connection to Client * Update tox to run pep8 by default * Move tests inside main package * PEP 8/Pyflakes fixes * Change the lookup method for Secret dict fields * Remove payload\_content\_encoding from orders * Modify default behaviors and the create\_order signature * Modifications to reflect payload\_content\_encoding being required for order creation * Make payload\_content\_type in keep default to 'text/plain' for secrets and 'application/octet-stream' for orders, and stop constraining the content options * Modify client library to comply with MIME revamp * Update keep to comply with the MIME type revamp * Add the option to provide a secret expiration date when creating orders * Change setup.py so that it reads the version from version.py * Bump client version to 0.2.1 * Add the skeleton for keep\_test, and make a small change to client\_test * Fixed a bug involving secret expiration dates * Bump client version to 0.2.0 * Change the SERVICE\_TOKEN env variable to AUTH\_TOKEN * Add an option to provide arguments through kwargs for testing * Move keep script into barbicanclient module * Change the SERVICE\_ENDPOINT env variable to BARBICAN\_ENDPOINT * Delete and stop tracking an OSX metadata file * Complete docstrings in the client library and make them uniform * Stop overriding the endpoint when it's provided without a token * Stop overriding the endpoint when it's provided without a token * Fix authentication and service endpoint fetching * Add docstrings to the client library along with a couple minor changes * In keep, make environment variables the defaults of several args * In keep, modify 'get' and 'delete' to use UUIDS * Add complete functionality to the command line tool * Implement secret and order list paging * Add the intial version of the client command line tool Currently the only implemented action is 'create' * Add a method to the client unit test that checks for equivalence and remove the \_\_eq\_\_() and \_\_ne\_\_() methods of secrets and orders * Split several unit tests into separate tests * Add more unittests for client.py * Make create\_secret() and create\_order() return objects rather than dicts and get metadata before returning * Minor fixes and adjustments * Add a test file, a configuration file, and various generated files * Add logging * remove last marconi refs * get rid of a stray debug print * First stab at packaging * modified get/delete methods on order and secrets and renamed dicts * change string formatting to use .format() * updated property on orders should default to none * orders & secrets now use \_\_str\_\_ instead of \_\_repr\_\_ + example fixes * collapsed \_\_repr\_\_ methods to one line per jarret's comments * add get order and get secret metadata functionality * create, delete, get secret * expand exception text to return text reason from endpoint * added generic .venv dirs to the gitignore * New objects and methods for create/read/delete * pep8 fixes * List Secrets * WIP: Architecture * pip requirements * Copied auth.py and tests from python-reddwarf client * Initial copy of oslo commons code * Placeholder for v1 of api * Openstack Common init * Initial setup.py configuration * Adding tox configuration * Adding Apache license * Updating .gitignore to ignore PyCharm files * Initial commit