Add support for app cred access rules

This change adds access_rules as a parameter for creating application
credentials, and also adds the ability to list access rules and to
retrieve and delete individual rules. Directly creating an access rule
or updating one is not supported.

bp whitelist-extension-for-app-creds

Depends-On: https://review.opendev.org/671374
Change-Id: I490f1e6b421d4f36f588f83a511ce39b9b4204e2
This commit is contained in:
Colleen Murphy 2019-08-20 17:37:34 -07:00
parent f7e75f43d8
commit 6c116ec084
6 changed files with 194 additions and 1 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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.'))

View File

@ -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):

View File

@ -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)
)

View File

@ -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.