get tenant_add_and_remove_user test working
this actually required a lot of stuff, basically we have to emulate some legacy features where user-tenant association is only handled through roles. in the process we added a few high level calls that will make abstracting the backend easier, too
This commit is contained in:
parent
94e9d6bcc2
commit
c6d6d43b7e
|
@ -63,6 +63,52 @@ class KvsIdentity(object):
|
|||
role_ref = self.db.get('role-%s' % role_id)
|
||||
return role_ref
|
||||
|
||||
# These should probably be part of the high-level API
|
||||
def add_user_to_tenant(self, tenant_id, user_id):
|
||||
user_ref = self.get_user(user_id)
|
||||
tenants = set(user_ref.get('tenants', []))
|
||||
tenants.add(tenant_id)
|
||||
user_ref['tenants'] = list(tenants)
|
||||
self.update_user(user_id, user_ref)
|
||||
|
||||
def remove_user_from_tenant(self, tenant_id, user_id):
|
||||
user_ref = self.get_user(user_id)
|
||||
tenants = set(user_ref.get('tenants', []))
|
||||
tenants.remove(tenant_id)
|
||||
user_ref['tenants'] = list(tenants)
|
||||
self.update_user(user_id, user_ref)
|
||||
|
||||
def get_tenants_for_user(self, user_id):
|
||||
user_ref = self.get_user(user_id)
|
||||
return user_ref.get('tenants', [])
|
||||
|
||||
def get_roles_for_user_and_tenant(self, user_id, tenant_id):
|
||||
extras_ref = self.get_extras(user_id, tenant_id)
|
||||
if not extras_ref:
|
||||
extras_ref = {}
|
||||
return extras_ref.get('roles', [])
|
||||
|
||||
def add_role_to_user_and_tenant(self, user_id, tenant_id, role_id):
|
||||
extras_ref = self.get_extras(user_id, tenant_id)
|
||||
if not extras_ref:
|
||||
extras_ref = {}
|
||||
roles = set(extras_ref.get('roles', []))
|
||||
roles.add(role_id)
|
||||
extras_ref['roles'] = list(roles)
|
||||
self.update_extras(user_id, tenant_id, extras_ref)
|
||||
|
||||
def remove_role_from_user_and_tenant(self, user_id, tenant_id, role_id):
|
||||
extras_ref = self.get_extras(user_id, tenant_id)
|
||||
if not extras_ref:
|
||||
extras_ref = {}
|
||||
roles = set(extras_ref.get('roles', []))
|
||||
roles.remove(role_id)
|
||||
extras_ref['roles'] = list(roles)
|
||||
self.update_extras(user_id, tenant_id, extras_ref)
|
||||
|
||||
|
||||
|
||||
# CRUD
|
||||
def create_user(self, id, user):
|
||||
self.db.set('user-%s' % id, user)
|
||||
self.db.set('user_name-%s' % user['name'], user)
|
||||
|
@ -101,6 +147,7 @@ class KvsIdentity(object):
|
|||
self.db.delete('tenant-%s' % id)
|
||||
return None
|
||||
|
||||
|
||||
def create_extras(self, user_id, tenant_id, extras):
|
||||
self.db.set('extras-%s-%s' % (tenant_id, user_id), extras)
|
||||
return extras
|
||||
|
|
|
@ -37,6 +37,27 @@ class Manager(object):
|
|||
def get_role(self, context, role_id):
|
||||
return self.driver.get_role(role_id)
|
||||
|
||||
# These should probably be the high-level API calls
|
||||
def add_user_to_tenant(self, context, user_id, tenant_id):
|
||||
self.driver.add_user_to_tenant(user_id, tenant_id)
|
||||
|
||||
def remove_user_from_tenant(self, context, user_id, tenant_id):
|
||||
self.driver.remove_user_from_tenant(user_id, tenant_id)
|
||||
|
||||
def get_tenants_for_user(self, context, user_id):
|
||||
return self.driver.get_tenants_for_user(user_id)
|
||||
|
||||
def get_roles_for_user_and_tenant(self, context, user_id, tenant_id):
|
||||
return self.driver.get_roles_for_user_and_tenant(user_id, tenant_id)
|
||||
|
||||
def add_role_to_user_and_tenant(self, context, user_id, tenant_id, role_id):
|
||||
return self.driver.add_role_to_user_and_tenant(user_id, tenant_id, role_id)
|
||||
|
||||
def remove_role_from_user_and_tenant(self, context, user_id,
|
||||
tenant_id, role_id):
|
||||
return self.driver.remove_role_from_user_and_tenant(
|
||||
user_id, tenant_id, role_id)
|
||||
|
||||
# CRUD operations
|
||||
def create_user(self, context, user_id, data):
|
||||
return self.driver.create_user(user_id, data)
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
# this is the web service frontend that emulates keystone
|
||||
import logging
|
||||
import urllib
|
||||
import urlparse
|
||||
import uuid
|
||||
|
||||
import routes
|
||||
|
@ -196,6 +198,17 @@ class KeystoneAdminCrudExtension(wsgi.ExtensionRouter):
|
|||
controller=role_controller, action="delete_role_from_user",
|
||||
conditions=dict(method=["DELETE"]))
|
||||
|
||||
# COMPAT(diablo): User Roles
|
||||
mapper.connect("/users/{user_id}/roleRefs",
|
||||
controller=role_controller, action="get_role_refs",
|
||||
conditions=dict(method=["GET"]))
|
||||
mapper.connect("/users/{user_id}/roleRefs",
|
||||
controller=role_controller, action="create_role_ref",
|
||||
conditions=dict(method=["POST"]))
|
||||
mapper.connect("/users/{user_id}/roleRefs/{role_ref_id}",
|
||||
controller=role_controller, action="delete_role_ref",
|
||||
conditions=dict(method=["DELETE"]))
|
||||
|
||||
# User-Tenant Roles
|
||||
mapper.connect(
|
||||
"/tenants/{tenant_id}/users/{user_id}/roles/OS-KSADM/{role_id}",
|
||||
|
@ -533,7 +546,7 @@ class KeystoneTenantController(service.BaseApplication):
|
|||
|
||||
def get_tenant_users(self, context, **kw):
|
||||
self.assert_admin(context)
|
||||
pass
|
||||
raise NotImplementedError()
|
||||
|
||||
def _format_tenants_for_token(self, tenant_refs):
|
||||
for x in tenant_refs:
|
||||
|
@ -562,11 +575,81 @@ class KeystoneUserController(service.BaseApplication):
|
|||
class KeystoneRoleController(service.BaseApplication):
|
||||
def __init__(self, options):
|
||||
self.options = options
|
||||
self.identity_api = identity.Manager(options)
|
||||
self.token_api = token.Manager(options)
|
||||
self.policy_api = policy.Manager(options)
|
||||
super(KeystoneRoleController, self).__init__()
|
||||
|
||||
def get_user_roles(self, context, user_id, tenant_id=None):
|
||||
raise NotImplemented()
|
||||
|
||||
# COMPAT(diablo): CRUD extension
|
||||
def get_role_refs(self, context, user_id):
|
||||
"""Ultimate hack to get around having to make role_refs first-class.
|
||||
|
||||
This will basically iterate over the various roles the user has in
|
||||
all tenants the user is a member of and create fake role_refs where
|
||||
the id encodes the user-tenant-role information so we can look
|
||||
up the appropriate data when we need to delete them.
|
||||
|
||||
"""
|
||||
self.assert_admin(context)
|
||||
user_ref = self.identity_api.get_user(context, user_id)
|
||||
tenant_ids = self.identity_api.get_tenants_for_user(context, user_id)
|
||||
o = []
|
||||
for tenant_id in tenant_ids:
|
||||
role_ids = self.identity_api.get_roles_for_user_and_tenant(
|
||||
context, user_id, tenant_id)
|
||||
for role_id in role_ids:
|
||||
ref = {'roleId': role_id,
|
||||
'tenantId': tenant_id,
|
||||
'userId': user_id}
|
||||
ref['id'] = urllib.urlencode(ref)
|
||||
o.append(ref)
|
||||
return {'roles': o}
|
||||
|
||||
def create_role_ref(self, context, user_id, role):
|
||||
"""This is actually used for adding a user to a tenant.
|
||||
|
||||
In the legacy data model adding a user to a tenant required setting
|
||||
a role.
|
||||
|
||||
"""
|
||||
self.assert_admin(context)
|
||||
# TODO(termie): for now we're ignoring the actual role
|
||||
tenant_id = role.get('tenantId')
|
||||
role_id = role.get('roleId')
|
||||
self.identity_api.add_user_to_tenant(context, tenant_id, user_id)
|
||||
self.identity_api.add_role_to_user_and_tenant(
|
||||
context, user_id, tenant_id, role_id)
|
||||
role_ref = self.identity_api.get_role(context, role_id)
|
||||
return {'role': role_ref}
|
||||
|
||||
def delete_role_ref(self, context, user_id, role_ref_id):
|
||||
"""This is actually used for deleting a user from a tenant.
|
||||
|
||||
In the legacy data model removing a user from a tenant required
|
||||
deleting a role.
|
||||
|
||||
To emulate this, we encode the tenant and role in the role_ref_id,
|
||||
and if this happens to be the last role for the user-tenant pair,
|
||||
we remove the user from the tenant.
|
||||
|
||||
"""
|
||||
self.assert_admin(context)
|
||||
# TODO(termie): for now we're ignoring the actual role
|
||||
role_ref_ref = urlparse.parse_qs(role_ref_id)
|
||||
tenant_id = role_ref_ref.get('tenantId')[0]
|
||||
role_id = role_ref_ref.get('roleId')[0]
|
||||
self.identity_api.remove_role_from_user_and_tenant(
|
||||
context, user_id, tenant_id, role_id)
|
||||
roles = self.identity_api.get_roles_for_user_and_tenant(
|
||||
context, user_id, tenant_id)
|
||||
if not roles:
|
||||
self.identity_api.remove_user_from_tenant(
|
||||
context, tenant_id, user_id)
|
||||
|
||||
|
||||
|
||||
class KeystoneServiceController(service.BaseApplication):
|
||||
def __init__(self, options):
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
TENANTS = [
|
||||
{'id': 'bar', 'name': 'BAR'},
|
||||
{'id': 'baz', 'name': 'BAZ'},
|
||||
]
|
||||
|
||||
USERS = [
|
||||
|
@ -12,4 +13,5 @@ EXTRAS = [
|
|||
|
||||
ROLES = [
|
||||
{'id': 'keystone_admin', 'name': 'Keystone Admin'},
|
||||
{'id': 'useless', 'name': 'Useless'},
|
||||
]
|
||||
|
|
|
@ -118,13 +118,32 @@ class MasterCompatTestCase(CompatTestCase):
|
|||
tenants = client.tenants.list()
|
||||
self.assertEquals(len(tenants), 1)
|
||||
|
||||
def test_tenant_add_user(self):
|
||||
raise NotImplementedError()
|
||||
#client.roles.add_user_to_tenant(tenant_id, user_id, role_id)
|
||||
def test_tenant_add_and_remove_user(self):
|
||||
client = self.foo_client()
|
||||
client.roles.add_user_to_tenant(self.tenant_baz['id'],
|
||||
self.user_foo['id'],
|
||||
self.role_useless['id'])
|
||||
tenant_refs = client.tenants.list()
|
||||
self.assert_(self.tenant_baz['id'] in
|
||||
[x.id for x in tenant_refs])
|
||||
|
||||
def test_tenant_remove_user(self):
|
||||
raise NotImplementedError()
|
||||
#client.roles.remove_user_from_tenant(tenant_id, user_id, role_id)
|
||||
# get the "role_refs" so we get the proper id, this is how the clients
|
||||
# do it
|
||||
roleref_refs = client.roles.get_user_role_refs(self.user_foo['id'])
|
||||
for roleref_ref in roleref_refs:
|
||||
if (roleref_ref.roleId == self.role_useless['id'] and
|
||||
roleref_ref.tenantId == self.tenant_baz['id']):
|
||||
# use python's scope fall through to leave roleref_ref set
|
||||
break
|
||||
|
||||
|
||||
client.roles.remove_user_from_tenant(self.tenant_baz['id'],
|
||||
self.user_foo['id'],
|
||||
roleref_ref.id)
|
||||
|
||||
tenant_refs = client.tenants.list()
|
||||
self.assert_(self.tenant_baz['id'] not in
|
||||
[x.id for x in tenant_refs])
|
||||
|
||||
def test_user_create_update_delete(self):
|
||||
from keystoneclient import exceptions as client_exceptions
|
||||
|
|
Loading…
Reference in New Issue