Add user group assignment support in identity
Add possibility to add/remove/check user into/from group. Change-Id: I1e012471badcf6264dced53354472abd8312f62c
This commit is contained in:
parent
21795acff6
commit
d7d6464c6d
@ -42,7 +42,8 @@ Group Operations
|
|||||||
.. autoclass:: openstack.identity.v3._proxy.Proxy
|
.. autoclass:: openstack.identity.v3._proxy.Proxy
|
||||||
:noindex:
|
:noindex:
|
||||||
:members: create_group, update_group, delete_group, get_group, find_group,
|
:members: create_group, update_group, delete_group, get_group, find_group,
|
||||||
groups
|
groups, add_user_to_group, remove_user_from_group,
|
||||||
|
check_user_in_group
|
||||||
|
|
||||||
Policy Operations
|
Policy Operations
|
||||||
^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^
|
||||||
|
@ -295,11 +295,7 @@ class IdentityCloudMixin(_normalize.Normalizer):
|
|||||||
"""
|
"""
|
||||||
user, group = self._get_user_and_group(name_or_id, group_name_or_id)
|
user, group = self._get_user_and_group(name_or_id, group_name_or_id)
|
||||||
|
|
||||||
error_msg = "Error adding user {user} to group {group}".format(
|
self.identity.add_user_to_group(user, group)
|
||||||
user=name_or_id, group=group_name_or_id)
|
|
||||||
self._identity_client.put(
|
|
||||||
'/groups/{g}/users/{u}'.format(g=group['id'], u=user['id']),
|
|
||||||
error_message=error_msg)
|
|
||||||
|
|
||||||
def is_user_in_group(self, name_or_id, group_name_or_id):
|
def is_user_in_group(self, name_or_id, group_name_or_id):
|
||||||
"""Check to see if a user is in a group.
|
"""Check to see if a user is in a group.
|
||||||
@ -314,14 +310,7 @@ class IdentityCloudMixin(_normalize.Normalizer):
|
|||||||
"""
|
"""
|
||||||
user, group = self._get_user_and_group(name_or_id, group_name_or_id)
|
user, group = self._get_user_and_group(name_or_id, group_name_or_id)
|
||||||
|
|
||||||
try:
|
return self.identity.check_user_in_group(user, group)
|
||||||
self._identity_client.head(
|
|
||||||
'/groups/{g}/users/{u}'.format(g=group['id'], u=user['id']))
|
|
||||||
return True
|
|
||||||
except exc.OpenStackCloudURINotFound:
|
|
||||||
# NOTE(samueldmq): knowing this URI exists, let's interpret this as
|
|
||||||
# user not found in group rather than URI not found.
|
|
||||||
return False
|
|
||||||
|
|
||||||
def remove_user_from_group(self, name_or_id, group_name_or_id):
|
def remove_user_from_group(self, name_or_id, group_name_or_id):
|
||||||
"""Remove a user from a group.
|
"""Remove a user from a group.
|
||||||
@ -334,11 +323,7 @@ class IdentityCloudMixin(_normalize.Normalizer):
|
|||||||
"""
|
"""
|
||||||
user, group = self._get_user_and_group(name_or_id, group_name_or_id)
|
user, group = self._get_user_and_group(name_or_id, group_name_or_id)
|
||||||
|
|
||||||
error_msg = "Error removing user {user} from group {group}".format(
|
self.identity.remove_user_from_group(user, group)
|
||||||
user=name_or_id, group=group_name_or_id)
|
|
||||||
self._identity_client.delete(
|
|
||||||
'/groups/{g}/users/{u}'.format(g=group['id'], u=user['id']),
|
|
||||||
error_message=error_msg)
|
|
||||||
|
|
||||||
@_utils.valid_kwargs('type', 'service_type', 'description')
|
@_utils.valid_kwargs('type', 'service_type', 'description')
|
||||||
def create_service(self, name, enabled=True, **kwargs):
|
def create_service(self, name, enabled=True, **kwargs):
|
||||||
|
@ -362,6 +362,45 @@ class Proxy(proxy.Proxy):
|
|||||||
"""
|
"""
|
||||||
return self._update(_group.Group, group, **attrs)
|
return self._update(_group.Group, group, **attrs)
|
||||||
|
|
||||||
|
def add_user_to_group(self, user, group):
|
||||||
|
"""Add user to group
|
||||||
|
|
||||||
|
:param user: Either the ID of a user or a
|
||||||
|
:class:`~openstack.identity.v3.user.User` instance.
|
||||||
|
:param group: Either the ID of a group or a
|
||||||
|
:class:`~openstack.identity.v3.group.Group` instance.
|
||||||
|
:return: ``None``
|
||||||
|
"""
|
||||||
|
user = self._get_resource(_user.User, user)
|
||||||
|
group = self._get_resource(_group.Group, group)
|
||||||
|
group.add_user(self, user)
|
||||||
|
|
||||||
|
def remove_user_from_group(self, user, group):
|
||||||
|
"""Remove user to group
|
||||||
|
|
||||||
|
:param user: Either the ID of a user or a
|
||||||
|
:class:`~openstack.identity.v3.user.User` instance.
|
||||||
|
:param group: Either the ID of a group or a
|
||||||
|
:class:`~openstack.identity.v3.group.Group` instance.
|
||||||
|
:return: ``None``
|
||||||
|
"""
|
||||||
|
user = self._get_resource(_user.User, user)
|
||||||
|
group = self._get_resource(_group.Group, group)
|
||||||
|
group.remove_user(self, user)
|
||||||
|
|
||||||
|
def check_user_in_group(self, user, group):
|
||||||
|
"""Check whether user belongsto group
|
||||||
|
|
||||||
|
:param user: Either the ID of a user or a
|
||||||
|
:class:`~openstack.identity.v3.user.User` instance.
|
||||||
|
:param group: Either the ID of a group or a
|
||||||
|
:class:`~openstack.identity.v3.group.Group` instance.
|
||||||
|
:return: A boolean representing current relation
|
||||||
|
"""
|
||||||
|
user = self._get_resource(_user.User, user)
|
||||||
|
group = self._get_resource(_group.Group, group)
|
||||||
|
return group.check_user(self, user)
|
||||||
|
|
||||||
def create_policy(self, **attrs):
|
def create_policy(self, **attrs):
|
||||||
"""Create a new policy from attributes
|
"""Create a new policy from attributes
|
||||||
|
|
||||||
|
@ -10,7 +10,9 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
from openstack import exceptions
|
||||||
from openstack import resource
|
from openstack import resource
|
||||||
|
from openstack import utils
|
||||||
|
|
||||||
|
|
||||||
class Group(resource.Resource):
|
class Group(resource.Resource):
|
||||||
@ -40,3 +42,31 @@ class Group(resource.Resource):
|
|||||||
domain_id = resource.Body('domain_id')
|
domain_id = resource.Body('domain_id')
|
||||||
#: Unique group name, within the owning domain. *Type: string*
|
#: Unique group name, within the owning domain. *Type: string*
|
||||||
name = resource.Body('name')
|
name = resource.Body('name')
|
||||||
|
|
||||||
|
def add_user(self, session, user):
|
||||||
|
"""Add user to the group"""
|
||||||
|
url = utils.urljoin(
|
||||||
|
self.base_path, self.id, 'users', user.id)
|
||||||
|
resp = session.put(url,)
|
||||||
|
exceptions.raise_from_response(resp)
|
||||||
|
|
||||||
|
def remove_user(self, session, user):
|
||||||
|
"""Remove user from the group"""
|
||||||
|
url = utils.urljoin(
|
||||||
|
self.base_path, self.id, 'users', user.id)
|
||||||
|
resp = session.delete(url,)
|
||||||
|
exceptions.raise_from_response(resp)
|
||||||
|
|
||||||
|
def check_user(self, session, user):
|
||||||
|
"""Check whether user belongs to group"""
|
||||||
|
url = utils.urljoin(
|
||||||
|
self.base_path, self.id, 'users', user.id)
|
||||||
|
resp = session.head(url,)
|
||||||
|
if resp.status_code == 404:
|
||||||
|
# If we recieve 404 - treat this as False,
|
||||||
|
# rather then returning exception
|
||||||
|
return False
|
||||||
|
exceptions.raise_from_response(resp)
|
||||||
|
if resp.status_code == 204:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
@ -10,7 +10,12 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
|
from keystoneauth1 import adapter
|
||||||
|
|
||||||
from openstack.identity.v3 import group
|
from openstack.identity.v3 import group
|
||||||
|
from openstack.identity.v3 import user
|
||||||
from openstack.tests.unit import base
|
from openstack.tests.unit import base
|
||||||
|
|
||||||
|
|
||||||
@ -25,6 +30,16 @@ EXAMPLE = {
|
|||||||
|
|
||||||
class TestGroup(base.TestCase):
|
class TestGroup(base.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestGroup, self).setUp()
|
||||||
|
self.sess = mock.Mock(spec=adapter.Adapter)
|
||||||
|
self.sess.default_microversion = 1
|
||||||
|
self.sess._get_connection = mock.Mock(return_value=self.cloud)
|
||||||
|
self.good_resp = mock.Mock()
|
||||||
|
self.good_resp.body = None
|
||||||
|
self.good_resp.json = mock.Mock(return_value=self.good_resp.body)
|
||||||
|
self.good_resp.status_code = 204
|
||||||
|
|
||||||
def test_basic(self):
|
def test_basic(self):
|
||||||
sot = group.Group()
|
sot = group.Group()
|
||||||
self.assertEqual('group', sot.resource_key)
|
self.assertEqual('group', sot.resource_key)
|
||||||
@ -52,3 +67,38 @@ class TestGroup(base.TestCase):
|
|||||||
self.assertEqual(EXAMPLE['domain_id'], sot.domain_id)
|
self.assertEqual(EXAMPLE['domain_id'], sot.domain_id)
|
||||||
self.assertEqual(EXAMPLE['id'], sot.id)
|
self.assertEqual(EXAMPLE['id'], sot.id)
|
||||||
self.assertEqual(EXAMPLE['name'], sot.name)
|
self.assertEqual(EXAMPLE['name'], sot.name)
|
||||||
|
|
||||||
|
def test_add_user(self):
|
||||||
|
sot = group.Group(**EXAMPLE)
|
||||||
|
resp = self.good_resp
|
||||||
|
self.sess.put = mock.Mock(return_value=resp)
|
||||||
|
|
||||||
|
sot.add_user(
|
||||||
|
self.sess, user.User(id='1'))
|
||||||
|
|
||||||
|
self.sess.put.assert_called_with(
|
||||||
|
'groups/IDENTIFIER/users/1')
|
||||||
|
|
||||||
|
def test_remove_user(self):
|
||||||
|
sot = group.Group(**EXAMPLE)
|
||||||
|
resp = self.good_resp
|
||||||
|
self.sess.delete = mock.Mock(return_value=resp)
|
||||||
|
|
||||||
|
sot.remove_user(
|
||||||
|
self.sess, user.User(id='1'))
|
||||||
|
|
||||||
|
self.sess.delete.assert_called_with(
|
||||||
|
'groups/IDENTIFIER/users/1')
|
||||||
|
|
||||||
|
def test_check_user(self):
|
||||||
|
sot = group.Group(**EXAMPLE)
|
||||||
|
resp = self.good_resp
|
||||||
|
self.sess.head = mock.Mock(return_value=resp)
|
||||||
|
|
||||||
|
self.assertTrue(
|
||||||
|
sot.check_user(
|
||||||
|
self.sess,
|
||||||
|
user.User(id='1')))
|
||||||
|
|
||||||
|
self.sess.head.assert_called_with(
|
||||||
|
'groups/IDENTIFIER/users/1')
|
||||||
|
@ -35,7 +35,7 @@ class TestIdentityProxyBase(test_proxy_base.TestProxyBase):
|
|||||||
self.proxy = _proxy.Proxy(self.session)
|
self.proxy = _proxy.Proxy(self.session)
|
||||||
|
|
||||||
|
|
||||||
class TestIdentityProxy(TestIdentityProxyBase):
|
class TestIdentityProxyCredential(TestIdentityProxyBase):
|
||||||
|
|
||||||
def test_credential_create_attrs(self):
|
def test_credential_create_attrs(self):
|
||||||
self.verify_create(self.proxy.create_credential,
|
self.verify_create(self.proxy.create_credential,
|
||||||
@ -61,6 +61,9 @@ class TestIdentityProxy(TestIdentityProxyBase):
|
|||||||
def test_credential_update(self):
|
def test_credential_update(self):
|
||||||
self.verify_update(self.proxy.update_credential, credential.Credential)
|
self.verify_update(self.proxy.update_credential, credential.Credential)
|
||||||
|
|
||||||
|
|
||||||
|
class TestIdentityProxyDomain(TestIdentityProxyBase):
|
||||||
|
|
||||||
def test_domain_create_attrs(self):
|
def test_domain_create_attrs(self):
|
||||||
self.verify_create(self.proxy.create_domain, domain.Domain)
|
self.verify_create(self.proxy.create_domain, domain.Domain)
|
||||||
|
|
||||||
@ -82,6 +85,9 @@ class TestIdentityProxy(TestIdentityProxyBase):
|
|||||||
def test_domain_update(self):
|
def test_domain_update(self):
|
||||||
self.verify_update(self.proxy.update_domain, domain.Domain)
|
self.verify_update(self.proxy.update_domain, domain.Domain)
|
||||||
|
|
||||||
|
|
||||||
|
class TestIdentityProxyEndpoint(TestIdentityProxyBase):
|
||||||
|
|
||||||
def test_endpoint_create_attrs(self):
|
def test_endpoint_create_attrs(self):
|
||||||
self.verify_create(self.proxy.create_endpoint, endpoint.Endpoint)
|
self.verify_create(self.proxy.create_endpoint, endpoint.Endpoint)
|
||||||
|
|
||||||
@ -105,6 +111,9 @@ class TestIdentityProxy(TestIdentityProxyBase):
|
|||||||
def test_endpoint_update(self):
|
def test_endpoint_update(self):
|
||||||
self.verify_update(self.proxy.update_endpoint, endpoint.Endpoint)
|
self.verify_update(self.proxy.update_endpoint, endpoint.Endpoint)
|
||||||
|
|
||||||
|
|
||||||
|
class TestIdentityProxyGroup(TestIdentityProxyBase):
|
||||||
|
|
||||||
def test_group_create_attrs(self):
|
def test_group_create_attrs(self):
|
||||||
self.verify_create(self.proxy.create_group, group.Group)
|
self.verify_create(self.proxy.create_group, group.Group)
|
||||||
|
|
||||||
@ -126,6 +135,42 @@ class TestIdentityProxy(TestIdentityProxyBase):
|
|||||||
def test_group_update(self):
|
def test_group_update(self):
|
||||||
self.verify_update(self.proxy.update_group, group.Group)
|
self.verify_update(self.proxy.update_group, group.Group)
|
||||||
|
|
||||||
|
def test_add_user_to_group(self):
|
||||||
|
self._verify(
|
||||||
|
"openstack.identity.v3.group.Group.add_user",
|
||||||
|
self.proxy.add_user_to_group,
|
||||||
|
method_args=['uid', 'gid'],
|
||||||
|
expected_args=[
|
||||||
|
self.proxy,
|
||||||
|
self.proxy._get_resource(user.User, 'uid'),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_remove_user_from_group(self):
|
||||||
|
self._verify(
|
||||||
|
"openstack.identity.v3.group.Group.remove_user",
|
||||||
|
self.proxy.remove_user_from_group,
|
||||||
|
method_args=['uid', 'gid'],
|
||||||
|
expected_args=[
|
||||||
|
self.proxy,
|
||||||
|
self.proxy._get_resource(user.User, 'uid'),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_check_user_in_group(self):
|
||||||
|
self._verify(
|
||||||
|
"openstack.identity.v3.group.Group.check_user",
|
||||||
|
self.proxy.check_user_in_group,
|
||||||
|
method_args=['uid', 'gid'],
|
||||||
|
expected_args=[
|
||||||
|
self.proxy,
|
||||||
|
self.proxy._get_resource(user.User, 'uid'),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TestIdentityProxyPolicy(TestIdentityProxyBase):
|
||||||
|
|
||||||
def test_policy_create_attrs(self):
|
def test_policy_create_attrs(self):
|
||||||
self.verify_create(self.proxy.create_policy, policy.Policy)
|
self.verify_create(self.proxy.create_policy, policy.Policy)
|
||||||
|
|
||||||
@ -147,6 +192,9 @@ class TestIdentityProxy(TestIdentityProxyBase):
|
|||||||
def test_policy_update(self):
|
def test_policy_update(self):
|
||||||
self.verify_update(self.proxy.update_policy, policy.Policy)
|
self.verify_update(self.proxy.update_policy, policy.Policy)
|
||||||
|
|
||||||
|
|
||||||
|
class TestIdentityProxyProject(TestIdentityProxyBase):
|
||||||
|
|
||||||
def test_project_create_attrs(self):
|
def test_project_create_attrs(self):
|
||||||
self.verify_create(self.proxy.create_project, project.Project)
|
self.verify_create(self.proxy.create_project, project.Project)
|
||||||
|
|
||||||
@ -176,6 +224,9 @@ class TestIdentityProxy(TestIdentityProxyBase):
|
|||||||
def test_project_update(self):
|
def test_project_update(self):
|
||||||
self.verify_update(self.proxy.update_project, project.Project)
|
self.verify_update(self.proxy.update_project, project.Project)
|
||||||
|
|
||||||
|
|
||||||
|
class TestIdentityProxyService(TestIdentityProxyBase):
|
||||||
|
|
||||||
def test_service_create_attrs(self):
|
def test_service_create_attrs(self):
|
||||||
self.verify_create(self.proxy.create_service, service.Service)
|
self.verify_create(self.proxy.create_service, service.Service)
|
||||||
|
|
||||||
@ -197,6 +248,9 @@ class TestIdentityProxy(TestIdentityProxyBase):
|
|||||||
def test_service_update(self):
|
def test_service_update(self):
|
||||||
self.verify_update(self.proxy.update_service, service.Service)
|
self.verify_update(self.proxy.update_service, service.Service)
|
||||||
|
|
||||||
|
|
||||||
|
class TestIdentityProxyUser(TestIdentityProxyBase):
|
||||||
|
|
||||||
def test_user_create_attrs(self):
|
def test_user_create_attrs(self):
|
||||||
self.verify_create(self.proxy.create_user, user.User)
|
self.verify_create(self.proxy.create_user, user.User)
|
||||||
|
|
||||||
@ -218,6 +272,9 @@ class TestIdentityProxy(TestIdentityProxyBase):
|
|||||||
def test_user_update(self):
|
def test_user_update(self):
|
||||||
self.verify_update(self.proxy.update_user, user.User)
|
self.verify_update(self.proxy.update_user, user.User)
|
||||||
|
|
||||||
|
|
||||||
|
class TestIdentityProxyTrust(TestIdentityProxyBase):
|
||||||
|
|
||||||
def test_trust_create_attrs(self):
|
def test_trust_create_attrs(self):
|
||||||
self.verify_create(self.proxy.create_trust, trust.Trust)
|
self.verify_create(self.proxy.create_trust, trust.Trust)
|
||||||
|
|
||||||
@ -236,6 +293,9 @@ class TestIdentityProxy(TestIdentityProxyBase):
|
|||||||
def test_trusts(self):
|
def test_trusts(self):
|
||||||
self.verify_list(self.proxy.trusts, trust.Trust)
|
self.verify_list(self.proxy.trusts, trust.Trust)
|
||||||
|
|
||||||
|
|
||||||
|
class TestIdentityProxyRegion(TestIdentityProxyBase):
|
||||||
|
|
||||||
def test_region_create_attrs(self):
|
def test_region_create_attrs(self):
|
||||||
self.verify_create(self.proxy.create_region, region.Region)
|
self.verify_create(self.proxy.create_region, region.Region)
|
||||||
|
|
||||||
@ -257,6 +317,9 @@ class TestIdentityProxy(TestIdentityProxyBase):
|
|||||||
def test_region_update(self):
|
def test_region_update(self):
|
||||||
self.verify_update(self.proxy.update_region, region.Region)
|
self.verify_update(self.proxy.update_region, region.Region)
|
||||||
|
|
||||||
|
|
||||||
|
class TestIdentityProxyRole(TestIdentityProxyBase):
|
||||||
|
|
||||||
def test_role_create_attrs(self):
|
def test_role_create_attrs(self):
|
||||||
self.verify_create(self.proxy.create_role, role.Role)
|
self.verify_create(self.proxy.create_role, role.Role)
|
||||||
|
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Add support for user group assignments in identity service.
|
Loading…
x
Reference in New Issue
Block a user