summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.zuul.yaml4
-rw-r--r--doc/requirements.txt3
-rw-r--r--examples/pki/gen_cmsz.py1
-rw-r--r--keystoneclient/auth/__init__.py1
-rw-r--r--keystoneclient/auth/identity/v3/__init__.py2
-rw-r--r--keystoneclient/contrib/ec2/utils.py2
-rw-r--r--keystoneclient/exceptions.py2
-rw-r--r--keystoneclient/fixture/__init__.py2
-rw-r--r--keystoneclient/tests/unit/v3/test_access_rules.py41
-rw-r--r--keystoneclient/tests/unit/v3/test_application_credentials.py21
-rw-r--r--keystoneclient/v3/access_rules.py118
-rw-r--r--keystoneclient/v3/application_credentials.py6
-rw-r--r--keystoneclient/v3/client.py4
-rw-r--r--releasenotes/notes/bp-whitelist-extension-for-app-creds-d03526e52e3edcce.yaml5
-rw-r--r--releasenotes/notes/drop-py-2-7-5ac18e82de83fcfa.yaml6
-rw-r--r--setup.cfg2
-rw-r--r--test-requirements.txt2
-rw-r--r--tox.ini21
18 files changed, 219 insertions, 24 deletions
diff --git a/.zuul.yaml b/.zuul.yaml
index 8338d13..a632ace 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -19,11 +19,9 @@
templates:
- openstack-cover-jobs
- openstack-lower-constraints-jobs
- - openstack-python-jobs
- - openstack-python3-train-jobs
+ - openstack-python3-ussuri-jobs
- publish-openstack-docs-pti
- check-requirements
- - lib-forward-testing
- lib-forward-testing-python3
- release-notes-jobs-python3
check:
diff --git a/doc/requirements.txt b/doc/requirements.txt
index 67c99ed..c4f9c7d 100644
--- a/doc/requirements.txt
+++ b/doc/requirements.txt
@@ -4,8 +4,7 @@
# These are needed for docs generation
openstackdocstheme>=1.20.0 # Apache-2.0
-sphinx!=1.6.6,!=1.6.7,>=1.6.2,<2.0.0;python_version=='2.7' # BSD
-sphinx!=1.6.6,!=1.6.7,>=1.6.2;python_version>='3.4' # BSD
+sphinx!=1.6.6,!=1.6.7,>=1.6.2 # BSD
reno>=2.5.0 # Apache-2.0
lxml!=3.7.0,>=3.4.1 # BSD
fixtures>=3.0.0 # Apache-2.0/BSD
diff --git a/examples/pki/gen_cmsz.py b/examples/pki/gen_cmsz.py
index bd0d886..35a6a8f 100644
--- a/examples/pki/gen_cmsz.py
+++ b/examples/pki/gen_cmsz.py
@@ -84,6 +84,7 @@ def generate_der_form(name):
SIGNING_KEY_FILE_NAME, cms.PKIZ_CMS_FORM)
f.write(derform)
+
for name in EXAMPLE_TOKENS:
json_file = make_filename('cms', name + '.json')
pkiz_file = make_filename('cms', name + '.pkiz')
diff --git a/keystoneclient/auth/__init__.py b/keystoneclient/auth/__init__.py
index eeae768..c9acef8 100644
--- a/keystoneclient/auth/__init__.py
+++ b/keystoneclient/auth/__init__.py
@@ -10,6 +10,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+# flake8: noqa: F405
from keystoneclient.auth.base import * # noqa
from keystoneclient.auth.cli import * # noqa
diff --git a/keystoneclient/auth/identity/v3/__init__.py b/keystoneclient/auth/identity/v3/__init__.py
index f25bf5e..abbaa65 100644
--- a/keystoneclient/auth/identity/v3/__init__.py
+++ b/keystoneclient/auth/identity/v3/__init__.py
@@ -10,6 +10,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+# flake8: noqa: F405
+
from keystoneclient.auth.identity.v3.base import * # noqa
from keystoneclient.auth.identity.v3.federated import * # noqa
from keystoneclient.auth.identity.v3.password import * # noqa
diff --git a/keystoneclient/contrib/ec2/utils.py b/keystoneclient/contrib/ec2/utils.py
index 1ef5df4..4e14e78 100644
--- a/keystoneclient/contrib/ec2/utils.py
+++ b/keystoneclient/contrib/ec2/utils.py
@@ -225,7 +225,7 @@ class Ec2Signer(object):
# port if we detect an old boto version. FIXME: remove when all
# distros package boto >= 2.9.3, this is a transitional workaround
user_agent = headers_lower.get('user-agent', '')
- strip_port = re.match('Boto/2\.[0-9]\.[0-2]', user_agent)
+ strip_port = re.match(r'Boto/2\.[0-9]\.[0-2]', user_agent)
header_list = []
sh_str = auth_param('SignedHeaders')
diff --git a/keystoneclient/exceptions.py b/keystoneclient/exceptions.py
index 5b06be9..034e5c9 100644
--- a/keystoneclient/exceptions.py
+++ b/keystoneclient/exceptions.py
@@ -376,6 +376,7 @@ class CMSError(Exception):
msg = _('Unable to sign or verify data.')
super(CMSError, self).__init__(msg)
+
EmptyCatalog = _exc.EmptyCatalog
"""The service catalog is empty.
@@ -398,6 +399,7 @@ An alias of :py:exc:`keystoneauth1.exceptions.discovery.VersionNotAvailable`
class MethodNotImplemented(ClientException):
"""Method not implemented by the keystoneclient API."""
+
MissingAuthPlugin = _exc.MissingAuthPlugin
"""An authenticated request is required but no plugin available.
diff --git a/keystoneclient/fixture/__init__.py b/keystoneclient/fixture/__init__.py
index 768f969..92034a0 100644
--- a/keystoneclient/fixture/__init__.py
+++ b/keystoneclient/fixture/__init__.py
@@ -28,6 +28,8 @@ testing.
"""
+# flake8: noqa: F405
+
import warnings
from keystoneclient.fixture.discovery import * # noqa
diff --git a/keystoneclient/tests/unit/v3/test_access_rules.py b/keystoneclient/tests/unit/v3/test_access_rules.py
new file mode 100644
index 0000000..d3e22f8
--- /dev/null
+++ b/keystoneclient/tests/unit/v3/test_access_rules.py
@@ -0,0 +1,41 @@
+# 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 uuid
+
+from keystoneclient import exceptions
+from keystoneclient.tests.unit.v3 import utils
+from keystoneclient.v3 import access_rules
+
+
+class AccessRuleTests(utils.ClientTestCase, utils.CrudTests):
+ def setUp(self):
+ super(AccessRuleTests, self).setUp()
+ self.key = 'access_rule'
+ self.collection_key = 'access_rules'
+ self.model = access_rules.AccessRule
+ self.manager = self.client.access_rules
+ self.path_prefix = 'users/%s' % self.TEST_USER_ID
+
+ def new_ref(self, **kwargs):
+ kwargs = super(AccessRuleTests, self).new_ref(**kwargs)
+ kwargs.setdefault('path', uuid.uuid4().hex)
+ kwargs.setdefault('method', uuid.uuid4().hex)
+ kwargs.setdefault('service', uuid.uuid4().hex)
+ return kwargs
+
+ def test_update(self):
+ self.assertRaises(exceptions.MethodNotImplemented, self.manager.update)
+
+ def test_create(self):
+ self.assertRaises(exceptions.MethodNotImplemented, self.manager.create)
diff --git a/keystoneclient/tests/unit/v3/test_application_credentials.py b/keystoneclient/tests/unit/v3/test_application_credentials.py
index be3c62a..6e4bba3 100644
--- a/keystoneclient/tests/unit/v3/test_application_credentials.py
+++ b/keystoneclient/tests/unit/v3/test_application_credentials.py
@@ -98,6 +98,27 @@ class ApplicationCredentialTests(utils.ClientTestCase, utils.CrudTests):
super(ApplicationCredentialTests, self).test_create(ref=ref,
req_ref=req_ref)
+ def test_create_with_access_rules(self):
+ ref = self.new_ref(user=uuid.uuid4().hex)
+ access_rules = [
+ {
+ 'method': 'GET',
+ 'path': '/v3/projects',
+ 'service': 'identity'
+ }
+ ]
+ ref['access_rules'] = access_rules
+ req_ref = ref.copy()
+ req_ref.pop('id')
+ user = req_ref.pop('user')
+
+ self.stub_entity('POST',
+ ['users', user, self.collection_key],
+ status_code=201, entity=req_ref)
+
+ super(ApplicationCredentialTests, self).test_create(ref=ref,
+ req_ref=req_ref)
+
def test_get(self):
ref = self.new_ref(user=uuid.uuid4().hex)
diff --git a/keystoneclient/v3/access_rules.py b/keystoneclient/v3/access_rules.py
new file mode 100644
index 0000000..78fd015
--- /dev/null
+++ b/keystoneclient/v3/access_rules.py
@@ -0,0 +1,118 @@
+# Copyright 2019 SUSE LLC
+#
+# 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 keystoneclient import base
+from keystoneclient import exceptions
+from keystoneclient.i18n import _
+
+
+class AccessRule(base.Resource):
+ """Represents an Identity access rule for application credentials.
+
+ Attributes:
+ * id: a uuid that identifies the access rule
+ * method: The request method that the application credential is
+ permitted to use for a given API endpoint
+ * path: The API path that the application credential is permitted to
+ access
+ * service: The service type identifier for the service that the
+ application credential is permitted to access
+
+ """
+
+ pass
+
+
+class AccessRuleManager(base.CrudManager):
+ """Manager class for manipulating Identity access rules."""
+
+ resource_class = AccessRule
+ collection_key = 'access_rules'
+ key = 'access_rule'
+
+ def get(self, access_rule, user=None):
+ """Retrieve an access rule.
+
+ :param access_rule: the access rule to be retrieved from the
+ server
+ :type access_rule: str or
+ :class:`keystoneclient.v3.access_rules.AccessRule`
+ :param string user: User ID
+
+ :returns: the specified access rule
+ :rtype:
+ :class:`keystoneclient.v3.access_rules.AccessRule`
+
+ """
+ user = user or self.client.user_id
+ self.base_url = '/users/%(user)s' % {'user': user}
+
+ return super(AccessRuleManager, self).get(
+ access_rule_id=base.getid(access_rule))
+
+ def list(self, user=None, **kwargs):
+ """List access rules.
+
+ :param string user: User ID
+
+ :returns: a list of access rules
+ :rtype: list of
+ :class:`keystoneclient.v3.access_rules.AccessRule`
+ """
+ user = user or self.client.user_id
+ self.base_url = '/users/%(user)s' % {'user': user}
+
+ return super(AccessRuleManager, self).list(**kwargs)
+
+ def find(self, user=None, **kwargs):
+ """Find an access rule with attributes matching ``**kwargs``.
+
+ :param string user: User ID
+
+ :returns: a list of matching access rules
+ :rtype: list of
+ :class:`keystoneclient.v3.access_rules.AccessRule`
+ """
+ user = user or self.client.user_id
+ self.base_url = '/users/%(user)s' % {'user': user}
+
+ return super(AccessRuleManager, self).find(**kwargs)
+
+ def delete(self, access_rule, user=None):
+ """Delete an access rule.
+
+ :param access_rule: the access rule to be deleted
+ :type access_rule: str or
+ :class:`keystoneclient.v3.access_rules.AccessRule`
+ :param string user: User ID
+
+ :returns: response object with 204 status
+ :rtype: :class:`requests.models.Response`
+
+ """
+ user = user or self.client.user_id
+ self.base_url = '/users/%(user)s' % {'user': user}
+
+ return super(AccessRuleManager, self).delete(
+ access_rule_id=base.getid(access_rule))
+
+ def update(self):
+ raise exceptions.MethodNotImplemented(
+ _('Access rules are immutable, updating is not'
+ ' supported.'))
+
+ def create(self):
+ raise exceptions.MethodNotImplemented(
+ _('Access rules can only be created as attributes of application '
+ 'credentials.'))
diff --git a/keystoneclient/v3/application_credentials.py b/keystoneclient/v3/application_credentials.py
index 0fc94af..694ee8c 100644
--- a/keystoneclient/v3/application_credentials.py
+++ b/keystoneclient/v3/application_credentials.py
@@ -33,6 +33,8 @@ class ApplicationCredential(base.Resource):
* roles: role assignments on the project
* unrestricted: whether the application credential has restrictions
applied
+ * access_rules: a list of access rules defining what API requests the
+ application credential may be used for
"""
@@ -48,7 +50,7 @@ class ApplicationCredentialManager(base.CrudManager):
def create(self, name, user=None, secret=None, description=None,
expires_at=None, roles=None,
- unrestricted=False, **kwargs):
+ unrestricted=False, access_rules=None, **kwargs):
"""Create a credential.
:param string name: application credential name
@@ -60,6 +62,7 @@ class ApplicationCredentialManager(base.CrudManager):
or a list of dicts specifying role name and domain
:param bool unrestricted: whether the application credential has
restrictions applied
+ :param List access_rules: a list of dicts representing access rules
:returns: the created application credential
:rtype:
@@ -99,6 +102,7 @@ class ApplicationCredentialManager(base.CrudManager):
expires_at=expires_str,
roles=role_list,
unrestricted=unrestricted,
+ access_rules=access_rules,
**kwargs)
def get(self, application_credential, user=None):
diff --git a/keystoneclient/v3/client.py b/keystoneclient/v3/client.py
index 89ba5ac..e99b065 100644
--- a/keystoneclient/v3/client.py
+++ b/keystoneclient/v3/client.py
@@ -22,6 +22,7 @@ from keystoneclient.auth.identity import v3 as v3_auth
from keystoneclient import exceptions
from keystoneclient import httpclient
from keystoneclient.i18n import _
+from keystoneclient.v3 import access_rules
from keystoneclient.v3 import application_credentials
from keystoneclient.v3 import auth
from keystoneclient.v3.contrib import endpoint_filter
@@ -223,6 +224,9 @@ class Client(httpclient.HTTPClient):
'deprecated as of the 1.7.0 release and may be removed in '
'the 2.0.0 release.', DeprecationWarning)
+ self.access_rules = (
+ access_rules.AccessRuleManager(self._adapter)
+ )
self.application_credentials = (
application_credentials.ApplicationCredentialManager(self._adapter)
)
diff --git a/releasenotes/notes/bp-whitelist-extension-for-app-creds-d03526e52e3edcce.yaml b/releasenotes/notes/bp-whitelist-extension-for-app-creds-d03526e52e3edcce.yaml
new file mode 100644
index 0000000..9c7dc2b
--- /dev/null
+++ b/releasenotes/notes/bp-whitelist-extension-for-app-creds-d03526e52e3edcce.yaml
@@ -0,0 +1,5 @@
+---
+features:
+ - |
+ Adds support for creating access rules as an attribute of application
+ credentials as well as for retrieving and deleting them.
diff --git a/releasenotes/notes/drop-py-2-7-5ac18e82de83fcfa.yaml b/releasenotes/notes/drop-py-2-7-5ac18e82de83fcfa.yaml
new file mode 100644
index 0000000..b977484
--- /dev/null
+++ b/releasenotes/notes/drop-py-2-7-5ac18e82de83fcfa.yaml
@@ -0,0 +1,6 @@
+---
+upgrade:
+ - |
+ Python 2.7 support has been dropped. Last release of python-keystoneclient
+ to support python 2.7 is OpenStack Train. The minimum version of Python now
+ supported is Python 3.6. \ No newline at end of file
diff --git a/setup.cfg b/setup.cfg
index bf2d604..2e004ec 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -13,8 +13,6 @@ classifier =
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.6
Programming Language :: Python :: 3.7
diff --git a/test-requirements.txt b/test-requirements.txt
index 4683c46..d27f88c 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -2,7 +2,7 @@
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
-hacking>=1.1.0,<1.2.0 # Apache-2.0
+hacking>=3.0,<3.1.0 # Apache-2.0
flake8-docstrings==0.2.1.post1 # MIT
coverage!=4.4,>=4.0 # Apache-2.0
diff --git a/tox.ini b/tox.ini
index 374893c..a135278 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,7 +1,8 @@
[tox]
-minversion = 2.5.0
+minversion = 3.1.1
skipsdist = True
-envlist = py27,py37,pep8,releasenotes
+envlist = py37,pep8,releasenotes
+ignore_basepython_conflict = True
[testenv]
usedevelop = True
@@ -17,25 +18,22 @@ deps =
commands = find . -type f -name "*.pyc" -delete
stestr run --slowest {posargs}
whitelist_externals = find
+basepython = python3
[testenv:pep8]
-basepython = python3
commands =
flake8
bandit -r keystoneclient -x tests -n5
[testenv:bandit]
-basepython = python3
# NOTE(browne): This is required for the integration test job of the bandit
# project. Please do not remove.
commands = bandit -r keystoneclient -x tests -n5
[testenv:venv]
-basepython = python3
commands = {posargs}
[testenv:cover]
-basepython = python3
setenv =
PYTHON=coverage run --source keystoneclient --parallel-mode
commands =
@@ -46,11 +44,9 @@ commands =
coverage report
[testenv:debug]
-basepython = python3
commands = oslo_debug_helper -t keystoneclient/tests {posargs}
[testenv:functional]
-basepython = python3
setenv = {[testenv]setenv}
OS_TEST_PATH=./keystoneclient/tests/functional
passenv = OS_*
@@ -62,17 +58,17 @@ passenv = OS_*
# D103: Missing docstring in public function
# D104: Missing docstring in public package
# D203: 1 blank line required before class docstring (deprecated in pep257)
-ignore = D100,D101,D102,D103,D104,D203
+# W504 line break after binary operator
+# F601 dictionary key repeated with different value
+ignore = D100,D101,D102,D103,D104,D203,W504,F601
show-source = True
exclude = .venv,.tox,dist,doc,*egg,build
[testenv:docs]
-basepython = python3
commands = python setup.py build_sphinx
deps = -r{toxinidir}/doc/requirements.txt
[testenv:pdf-docs]
-basepython = python3
envdir = {toxworkdir}/docs
deps = {[testenv:docs]deps}
whitelist_externals =
@@ -84,7 +80,6 @@ commands =
make -C doc/build/pdf
[testenv:releasenotes]
-basepython = python3
commands = sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html
deps = -r{toxinidir}/doc/requirements.txt
@@ -93,7 +88,6 @@ import_exceptions =
keystoneclient.i18n
[testenv:bindep]
-basepython = python3
# Do not install any requirements. We want this to be fast and work even if
# system dependencies are missing, since it's used to tell you what system
# dependencies are missing! This also means that bindep must be installed
@@ -102,7 +96,6 @@ deps = bindep
commands = bindep test
[testenv:lower-constraints]
-basepython = python3
deps =
-c{toxinidir}/lower-constraints.txt
-r{toxinidir}/test-requirements.txt