summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZiad Sawalha <github@highbridgellc.com>2011-07-19 18:08:06 -0500
committerZiad Sawalha <github@highbridgellc.com>2011-07-19 18:08:06 -0500
commit25380b0eb367fa2cb5fa5dbb075d6f4016ffc60f (patch)
tree0cb9d345700ac58a531f44961182f2a5eac0742a
parent6b9e4b4fbff741a672cbdc9e7f7feafc583cd7a0 (diff)
parent39b944eefbc3a84b6277d8002d6a6a42289c4ffd (diff)
downloadkeystone-25380b0eb367fa2cb5fa5dbb075d6f4016ffc60f.tar.gz
keystone-25380b0eb367fa2cb5fa5dbb075d6f4016ffc60f.tar.xz
keystone-25380b0eb367fa2cb5fa5dbb075d6f4016ffc60f.zip
Merge LDAP changes
-rw-r--r--.gitignore1
-rwxr-xr-xbin/keystone-manage69
-rwxr-xr-xkeystone/backends/api.py311
-rw-r--r--keystone/backends/ldap/api/__init__.py25
-rw-r--r--keystone/backends/ldap/api/base.py150
-rw-r--r--keystone/backends/ldap/api/role.py154
-rw-r--r--keystone/backends/ldap/api/tenant.py53
-rw-r--r--keystone/backends/ldap/api/user.py97
-rw-r--r--keystone/backends/ldap/fakeldap.py278
-rw-r--r--keystone/backends/ldap/models.py48
-rwxr-xr-xkeystone/backends/sqlalchemy/api/user.py3
-rw-r--r--keystone/frontends/legacy_token_auth.py2
-rwxr-xr-xkeystone/test/unit/test_common.py16
-rwxr-xr-xkeystone/utils.py8
14 files changed, 1018 insertions, 197 deletions
diff --git a/.gitignore b/.gitignore
index c4dff7bb..a08c9b54 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,7 @@
.pydevproject/
.settings/
keystone.db
+ldap.db
keystone.token.db
.*.swp
*.log
diff --git a/bin/keystone-manage b/bin/keystone-manage
index 2f3b0679..fde72d18 100755
--- a/bin/keystone-manage
+++ b/bin/keystone-manage
@@ -23,6 +23,7 @@ Keystone Identity Server - CLI Management Interface
"""
import datetime
+import logging
import optparse
import os
import sys
@@ -40,7 +41,7 @@ import keystone
from keystone.common import config
import keystone.backends as db
import keystone.backends.api as db_api
-import keystone.backends.sqlalchemy.models as db_models
+import keystone.backends.models as db_models
def Main():
@@ -127,7 +128,7 @@ def Main():
db_api.user.create(object)
print "SUCCESS: User %s created." % object.id
except Exception as exc:
- print "ERROR: Failed to create user %s: %s" % (object_id, exc)
+ raise Exception("Failed to create user %s" % (object_id,), sys.exc_info())
return
elif command == "disable":
try:
@@ -138,7 +139,7 @@ def Main():
db_api.user.update(object_id, object)
print "SUCCESS: User %s disabled." % object.id
except Exception as exc:
- print "ERROR: Failed to disable user %s: %s" % (object_id, exc)
+ raise Exception("Failed to disable user %s" % (object_id,), sys.exc_info())
return
elif command == "list":
try:
@@ -160,7 +161,7 @@ def Main():
for row in objects:
print row.id, row.enabled, row.tenant_id
except Exception, e:
- print 'Error getting all users:', str(e)
+ raise Exception("Error getting all users", sys.exc_info())
return
elif object_type == "tenant":
if command == "add":
@@ -172,9 +173,7 @@ def Main():
print "SUCCESS: Tenant %s created." % object.id
return
except Exception as exc:
- print "ERROR: Failed to create tenant %s: %s" % (
- object_id, exc)
- return
+ raise Exception("Failed to create tenant %s" % (object_id,), sys.exc_info())
elif command == "list":
try:
objects = db_api.tenant.get_all()
@@ -184,8 +183,8 @@ def Main():
print '-' * 20
for row in objects:
print row.id, row.enabled
- except Exception, e:
- print 'Error getting all users: %s', str(e)
+ except Exception, exc:
+ raise Exception("Error getting all tenants", sys.exc_info())
return
elif command == "disable":
try:
@@ -196,8 +195,7 @@ def Main():
db_api.tenant.update(object_id, object)
print "SUCCESS: Tenant %s disabled." % object.id
except Exception as exc:
- print "ERROR: Failed to disable tenant %s: %s" % (
- object_id, exc)
+ raise Exception("Failed to disable tenant %s" % (object_id,), sys.exc_info())
return
elif object_type == "role":
if command == "add":
@@ -208,8 +206,7 @@ def Main():
print "SUCCESS: Role %s created successfully." % object.id
return
except Exception as exc:
- print "ERROR: Failed to create role %s: %s" % (object_id, exc)
- return
+ raise Exception("Failed to create role %s" % (object_id,), sys.exc_info())
elif command == "list":
if len(args) == 3:
tenant = args[2]
@@ -223,8 +220,9 @@ def Main():
for row in objects:
print row.user_id, row.role_id
except Exception, e:
- print 'Error getting all role assignments for %s:' % \
- tenant, str(e)
+ raise Exception( \
+ "Error getting all role assignments for %s" % (tenant,),
+ sys.exc_info())
return
else:
tenant = None
@@ -238,7 +236,7 @@ def Main():
for row in objects:
print row.id
except Exception, e:
- print 'Error getting all roles:', str(e)
+ raise Exception("Error getting all roles", sys.exc_info())
return
elif command == "grant":
if len(args) < 4:
@@ -259,8 +257,8 @@ def Main():
print "SUCCESS: Granted %s the %s role on %s." % \
(object.user_id, object.role_id, object.tenant_id)
except Exception as exc:
- print "ERROR: Failed to grant role %s to %s on %s: %s" % (
- object_id, user, tenant, exc)
+ raise Exception("Failed to grant role %s to %s on %s" % \
+ (object_id, user, tenant), sys.exc_info())
return
elif object_type == "endpointTemplates":
if command == "add":
@@ -290,9 +288,8 @@ def Main():
"to %s." % (object.service, object.public_url)
return
except Exception as exc:
- print "ERROR: Failed to create EndpointTemplates for " \
- "%s: %s" % (service, exc)
- return
+ raise Exception("Failed to create EndpointTemplates for %s" % \
+ (service,), sys.exc_info())
elif command == "list":
if len(args) == 3:
tenant = args[2]
@@ -307,8 +304,8 @@ def Main():
for row in objects:
print row.service, row.region, row.public_url
except Exception, e:
- print 'Error getting all endpoints for %s:' % \
- tenant, str(e)
+ raise Exception("Error getting all endpoints for %s" % \
+ (tenant,), sys.exc_info())
return
else:
tenant = None
@@ -322,7 +319,7 @@ def Main():
for row in objects:
print row.service, row.region, row.public_url
except Exception, e:
- print 'Error getting all EndpointTemplates:', str(e)
+ raise Exception("Error getting all EndpointTemplates", sys.exc_info())
return
elif object_type == "endpoint":
if command == "add":
@@ -341,8 +338,7 @@ def Main():
(endpoint_template_id, tenant_id)
return
except Exception as exc:
- print "ERROR: Failed to create Endpoint: %s" % exc
- return
+ raise Exception("Failed to create Endpoint", sys.exc_info())
elif object_type == "token":
if command == "add":
if len(args) < 6:
@@ -361,8 +357,7 @@ def Main():
print "SUCCESS: Token %s created." % object.id
return
except Exception as exc:
- print "ERROR: Failed to create token %s: %s" % (object_id, exc)
- return
+ raise Exception("Failed to create token %s" % (object_id,), sys.exc_info())
elif command == "list":
try:
objects = db_api.token.get_all()
@@ -373,7 +368,7 @@ def Main():
for row in objects:
print row.id, row.user_id, row.expires, row.tenant_id
except Exception, e:
- print 'Error getting all tokens:', str(e)
+ raise Exception("Error getting all tokens", sys.exc_info())
return
elif command == "delete":
try:
@@ -384,12 +379,22 @@ def Main():
db_api.token.delete(object_id)
print 'SUCCESS: Token %s deleted.' % object_id
except Exception, e:
- print 'ERROR: Failed to delete token %s: %s' % \
- object_id, str(e)
+ raise Exception("Failed to delete token %s" % (object_id,), sys.exc_info())
return
# Command not handled
print ("ERROR: %s %s not yet supported" % (object_type, command))
if __name__ == '__main__':
- Main()
+ try:
+ Main()
+ except Exception as exc:
+ try:
+ info = exc.args[1]
+ except IndexError:
+ print "ERROR: %s" % (exc,)
+ logging.error(str(exc))
+ else:
+ print "ERROR: %s: %s" % (exc.args[0], info[1].message)
+ logging.error(exc.args[0], exc_info=info)
+ sys.exit(1)
diff --git a/keystone/backends/api.py b/keystone/backends/api.py
index c75dff11..65dc286f 100755
--- a/keystone/backends/api.py
+++ b/keystone/backends/api.py
@@ -15,264 +15,287 @@
#API
#TODO(Yogi) Refactor all API to separate classes specific to models.
+# Function to dynamically set module references.
+def set_value(variable_name, value):
+ if variable_name == 'endpoint_template':
+ global endpoint_template
+ endpoint_template = value
+ elif variable_name == 'group':
+ global group
+ group = value
+ elif variable_name == 'role':
+ global role
+ role = value
+ elif variable_name == 'tenant_group':
+ global tenant_group
+ tenant_group = value
+ elif variable_name == 'tenant':
+ global tenant
+ tenant = value
+ elif variable_name == 'token':
+ global token
+ token = value
+ elif variable_name == 'user':
+ global user
+ user = value
+
#Base APIs
class BaseUserAPI(object):
def get_all(self):
- pass
+ raise NotImplementedError
def get_by_group(self, user_id, group_id):
- pass
+ raise NotImplementedError
def tenant_group(self, values):
- pass
+ raise NotImplementedError
def tenant_group_delete(self, id, group_id):
- pass
+ raise NotImplementedError
def create(self, values):
- pass
+ raise NotImplementedError
def get(self, id):
- pass
+ raise NotImplementedError
def get_page(self, marker, limit):
- pass
+ raise NotImplementedError
def get_page_markers(self, marker, limit):
- pass
+ raise NotImplementedError
def get_by_email(self, email):
- pass
+ raise NotImplementedError
def get_groups(self, id):
- pass
+ raise NotImplementedError
def user_roles_by_tenant(self, user_id, tenant_id):
- pass
+ raise NotImplementedError
def update(self, id, values):
- pass
+ raise NotImplementedError
- def users_tenant_group_get_page(self, group_id, marker):
- pass
+ def users_tenant_group_get_page(self, group_id, marker, limit):
+ raise NotImplementedError
def users_tenant_group_get_page_markers(self, group_id, marker, limit):
- pass
+ raise NotImplementedError
def delete(self, id):
- pass
+ raise NotImplementedError
def get_by_tenant(self, id, tenant_id):
- pass
+ raise NotImplementedError
def get_group_by_tenant(self, id):
- pass
+ raise NotImplementedError
def delete_tenant_user(self, id, tenant_id):
- pass
+ raise NotImplementedError
def users_get_by_tenant(self, user_id, tenant_id):
- pass
+ raise NotImplementedError
def user_role_add(self, values):
- pass
+ raise NotImplementedError
def user_get_update(self, id):
- pass
+ raise NotImplementedError
def users_get_page(self, marker, limit):
- pass
+ raise NotImplementedError
def users_get_page_markers(self, marker, limit):
- pass
+ raise NotImplementedError
def users_get_by_tenant_get_page(self, tenant_id, marker, limit):
- pass
+ raise NotImplementedError
def users_get_by_tenant_get_page_markers(self, tenant_id, marker, limit):
- pass
+ raise NotImplementedError
def user_groups_get_all(self, user_id):
- pass
+ raise NotImplementedError
class BaseTokenAPI(object):
def create(self, values):
- pass
-
+ raise NotImplementedError
+
def get(self, id):
- pass
-
+ raise NotImplementedError
+
def delete(self, id):
- pass
-
+ raise NotImplementedError
+
def get_for_user(self, user_id):
- pass
-
+ raise NotImplementedError
+
def get_for_user_by_tenant(self, user_id, tenant_id):
- pass
+ raise NotImplementedError
def get_all(self):
- pass
-
+ raise NotImplementedError
+
class BaseTenantGroupAPI(object):
def create(self, values):
- pass
-
+ raise NotImplementedError
+
def is_empty(self, id):
- pass
-
+ raise NotImplementedError
+
def get(self, id, tenant):
- pass
-
+ raise NotImplementedError
+
def get_page(self, tenantId, marker, limit):
- pass
-
+ raise NotImplementedError
+
def get_page_markers(self, tenantId, marker, limit):
- pass
-
+ raise NotImplementedError
+
def update(self, id, tenant_id, values):
- pass
-
+ raise NotImplementedError
+
def delete(self, id, tenant_id):
- pass
-
+ raise NotImplementedError
+
class BaseTenantAPI(object):
-
def create(self, values):
- pass
-
+ raise NotImplementedError
+
def get(self, id):
- pass
-
+ raise NotImplementedError
+
def get_all(self):
- pass
-
+ raise NotImplementedError
+
def tenants_for_user_get_page(self, user, marker, limit):
- pass
-
+ raise NotImplementedError
+
def tenants_for_user_get_page_markers(self, user, marker, limit):
- pass
-
+ raise NotImplementedError
+
def get_page(self, marker, limit):
- pass
-
+ raise NotImplementedError
+
def get_page_markers(self, marker, limit):
- pass
-
+ raise NotImplementedError
+
def is_empty(self, id):
- pass
-
+ raise NotImplementedError
+
def update(self, id, values):
- pass
-
+ raise NotImplementedError
+
def delete(self, id):
- pass
-
+ raise NotImplementedError
+
def get_all_endpoints(self, tenant_id):
- pass
+ raise NotImplementedError
def get_role_assignments(self, tenant_id):
- pass
+ raise NotImplementedError
class BaseRoleAPI(object):
def create(self, values):
- pass
-
+ raise NotImplementedError
+
def get(self, id):
- pass
-
+ raise NotImplementedError
+
def get_all(self):
- pass
-
+ raise NotImplementedError
+
def get_page(self, marker, limit):
- pass
-
+ raise NotImplementedError
+
def ref_get_page(self, marker, limit, user_id):
- pass
-
+ raise NotImplementedError
+
def ref_get_all_global_roles(self, user_id):
- pass
-
+ raise NotImplementedError
+
def ref_get_all_tenant_roles(self, user_id, tenant_id):
- pass
-
+ raise NotImplementedError
+
def ref_get(self, id):
- pass
-
+ raise NotImplementedError
+
def ref_delete(self, id):
- pass
-
+ raise NotImplementedError
+
def get_page_markers(self, marker, limit):
- pass
+ raise NotImplementedError
def ref_get_page_markers(self, user_id, marker, limit):
- pass
+ raise NotImplementedError
class BaseGroupAPI(object):
def get(self, id):
- pass
-
+ raise NotImplementedError
+
def get_users(self, id):
- pass
-
+ raise NotImplementedError
+
def get_all(self):
- pass
-
+ raise NotImplementedError
+
def get_page(self, marker, limit):
- pass
-
+ raise NotImplementedError
+
def get_page_markers(self, marker, limit):
- pass
-
+ raise NotImplementedError
+
def delete(self, id):
- pass
-
+ raise NotImplementedError
+
def get_by_user_get_page(self, user_id, marker, limit):
- pass
-
+ raise NotImplementedError
+
def get_by_user_get_page_markers(self, user_id, marker, limit):
- pass
-
+ raise NotImplementedError
+
class BaseEndpointTemplateAPI(object):
def create(self, values):
- pass
-
+ raise NotImplementedError
+
def get(self, id):
- pass
-
+ raise NotImplementedError
+
def get_all(self):
- pass
-
+ raise NotImplementedError
+
def get_page(self, marker, limit):
- pass
-
+ raise NotImplementedError
+
def get_page_markers(self, marker, limit):
- pass
-
+ raise NotImplementedError
+
def endpoint_get_by_tenant_get_page(self, tenant_id, marker, limit):
- pass
-
+ raise NotImplementedError
+
def endpoint_get_by_tenant_get_page_markers(self, tenant_id, marker,
limit):
- pass
-
+ raise NotImplementedError
+
def endpoint_add(self, values):
- pass
-
+ raise NotImplementedError
+
def endpoint_get(self, id):
- pass
-
+ raise NotImplementedError
+
def endpoint_get_by_tenant(self, tenant_id):
- pass
-
+ raise NotImplementedError
+
def endpoint_delete(self, id):
- pass
+ raise NotImplementedError
endpoint_template = BaseEndpointTemplateAPI()
group = BaseGroupAPI()
@@ -281,27 +304,3 @@ tenant_group = BaseTenantGroupAPI()
tenant = BaseTenantAPI()
token = BaseTokenAPI()
user = BaseUserAPI()
-
-# Function to dynamically set module references.
-def set_value(variable_name, value):
- if variable_name == 'endpoint_template':
- global endpoint_template
- endpoint_template = value
- elif variable_name == 'group':
- global group
- group = value
- elif variable_name == 'role':
- global role
- role = value
- elif variable_name == 'tenant_group':
- global tenant_group
- tenant_group = value
- elif variable_name == 'tenant':
- global tenant
- tenant = value
- elif variable_name == 'token':
- global token
- token = value
- elif variable_name == 'user':
- global user
- user = value
diff --git a/keystone/backends/ldap/api/__init__.py b/keystone/backends/ldap/api/__init__.py
new file mode 100644
index 00000000..9244fdbb
--- /dev/null
+++ b/keystone/backends/ldap/api/__init__.py
@@ -0,0 +1,25 @@
+import ldap
+
+from .. import fakeldap
+from .tenant import TenantAPI
+from .user import UserAPI
+from .role import RoleAPI
+
+class API(object):
+ apis = ['tenant', 'user', 'role']
+
+ def __init__(self, options):
+ self.LDAP_URL = options['ldap_url']
+ self.LDAP_USER = options['ldap_user']
+ self.LDAP_PASSWORD = options['ldap_password']
+ self.tenant = TenantAPI(self, options)
+ self.user = UserAPI(self, options)
+ self.role = RoleAPI(self, options)
+
+ def get_connection(self):
+ if self.LDAP_URL.startswith('fake://'):
+ conn = fakeldap.initialize(self.LDAP_URL)
+ else:
+ conn = ldap.initialize(self.LDAP_URL)
+ conn.simple_bind_s(self.LDAP_USER, self.LDAP_PASSWORD)
+ return conn
diff --git a/keystone/backends/ldap/api/base.py b/keystone/backends/ldap/api/base.py
new file mode 100644
index 00000000..0018b436
--- /dev/null
+++ b/keystone/backends/ldap/api/base.py
@@ -0,0 +1,150 @@
+import ldap
+
+
+def _get_redirect(cls, method):
+ def inner(self, *args):
+ return getattr(cls(), method)(*args)
+ return inner
+
+
+def add_redirects(loc, cls, methods):
+ for method in methods:
+ loc[method] = _get_redirect(cls, method)
+
+
+class BaseLdapAPI(object):
+ DEFAULT_TREE_DN = None
+ options_name = None
+ object_class = 'top'
+ model = None
+ attribute_mapping = {}
+ attribute_ignore = []
+
+ def __init__(self, api, options):
+ self.api = api
+ self.tree_dn = options.get(self.options_name, self.DEFAULT_TREE_DN)
+
+ def _id_to_dn(self, id):
+ return 'cn=%s,%s' % (ldap.dn.escape_dn_chars(str(id)), self.tree_dn)
+
+ def _ldap_res_to_model(self, res):
+ obj = self.model(id=ldap.dn.str2dn(res[0])[0][0][1])
+ for k in obj:
+ if k in self.attribute_ignore:
+ continue
+ try:
+ v = res[1][self.attribute_mapping.get(k, k)]
+ except KeyError:
+ pass
+ else:
+ obj[k] = v[0]
+ return obj
+
+ def create(self, values):
+ conn = self.api.get_connection()
+ attrs = [('objectClass', [self.object_class])]
+ for k, v in values.iteritems():
+ if k == 'id' or k in self.attribute_ignore:
+ continue
+ if v is not None:
+ attr_type = self.attribute_mapping.get(k, k)
+ attrs.append((attr_type, [v]))
+ conn.add_s(self._id_to_dn(values['id']), attrs)
+ return self.model(values)
+
+ def _ldap_get(self, id, filter=None):
+ conn = self.api.get_connection()
+ query = '(objectClass=%s)' % (self.object_class,)
+ if filter is not None:
+ query = '(&%s%s)' % (filter, query)
+ try:
+ res = conn.search_s(self._id_to_dn(id), ldap.SCOPE_BASE, query)
+ except ldap.NO_SUCH_OBJECT:
+ return None
+ try:
+ return res[0]
+ except IndexError:
+ return None
+
+ def _ldap_get_all(self, filter=None):
+ conn = self.api.get_connection()
+ query = '(objectClass=%s)' % (self.object_class,)
+ if filter is not None:
+ query = '(&%s%s)' % (filter, query)
+ try:
+ return conn.search_s(self.tree_dn, ldap.SCOPE_ONELEVEL, query)
+ except ldap.NO_SUCH_OBJECT:
+ return []
+
+ def get(self, id, filter=None):
+ res = self._ldap_get(id, filter)
+ if res is None:
+ return None
+ else:
+ return self._ldap_res_to_model(res)
+
+ def get_all(self, filter=None):
+ return map(self._ldap_res_to_model, self._ldap_get_all(filter))
+
+ def get_page(self, marker, limit):
+ return self._get_page(marker, limit, self.get_all())
+
+ def get_page_markers(self, marker, limit):
+ return self._get_page_markers(marker, limit, self.get_all())
+
+ def _get_page(self, marker, limit, lst, key=lambda e:e.id):
+ lst.sort(key=key)
+ if not marker:
+ return lst[:limit]
+ else:
+ return filter(lambda e: key(e) > marker, lst)[:limit]
+
+ def _get_page_markers(self, marker, limit, lst, key=lambda e:e.id):
+ if len(lst) < limit:
+ return (None, None)
+ lst.sort(key=key)
+ if marker is None:
+ if len(lst) <= limit + 1:
+ nxt = None
+ else:
+ nxt = key(lst[limit])
+ return (None, nxt)
+ for i, item in izip(count(), lst):
+ k = key(item)
+ if k >= marker:
+ exact = k == marker
+ break
+ if i <= limit:
+ prv = None
+ else:
+ prv = key(lst[i-limit])
+ if i + limit >= len(lst) - 1:
+ nxt = None
+ else:
+ nxt = key(lst[i+limit])
+ return (prv, nxt)
+
+ def update(self, id, values, old_obj=None):
+ if old_obj is None:
+ old_obj = self.get(id)
+ modlist = []
+ for k, v in values.iteritems():
+ if k == 'id' or k in self.attribute_ignore:
+ continue
+ if v is None:
+ if old_obj[k] is not None:
+ modlist.append((ldap.MOD_DELETE,
+ self.attribute_mapping.get(k, k), None))
+ else:
+ if old_obj[k] != v:
+ if old_obj[k] is None:
+ op = ldap.MOD_ADD
+ else:
+ op = ldap.MOD_REPLACE
+ modlist.append((op, self.attribute_mapping.get(k, k), [v]))
+ conn = self.api.get_connection()
+ conn.modify_s(self._id_to_dn(id), modlist)
+
+ def delete(self, id):
+ conn = self.api.get_connection()
+ conn.delete_s(self._id_to_dn(id))
diff --git a/keystone/backends/ldap/api/role.py b/keystone/backends/ldap/api/role.py
new file mode 100644
index 00000000..b1bd7661
--- /dev/null
+++ b/keystone/backends/ldap/api/role.py
@@ -0,0 +1,154 @@
+import ldap
+
+from keystone.backends.api import BaseTenantAPI
+from keystone.common import exception
+
+from .. import models
+from .base import BaseLdapAPI
+
+class RoleAPI(BaseLdapAPI, BaseTenantAPI):
+ DEFAULT_TREE_DN = 'ou=Groups,dc=example,dc=com'
+ options_name = 'role_tree_dn'
+ object_class = 'keystoneRole'
+ model = models.Role
+ attribute_mapping = { 'desc': 'description' }
+
+ @staticmethod
+ def _create_ref(role_id, tenant_id, user_id):
+ role_id = '' if role_id is None else str(role_id)
+ tenant_id = '' if tenant_id is None else str(tenant_id)
+ user_id = '' if user_id is None else str(user_id)
+ return '%d-%d-%s%s%s' % (len(role_id), len(tenant_id),
+ role_id, tenant_id, user_id)
+ @staticmethod
+ def _explode_ref(role_ref):
+ a = role_ref.split('-', 2)
+ len_role = int(a[0])
+ len_tenant = int(a[1])
+ role_id = a[2][:len_role]
+ role_id = None if len(role_id) == 0 else str(role_id)
+ tenant_id = a[2][len_role:len_tenant+len_role]
+ tenant_id = None if len(tenant_id) == 0 else str(tenant_id)
+ user_id = a[2][len_tenant+len_role:]
+ user_id = None if len(user_id) == 0 else str(user_id)
+ return role_id, tenant_id, user_id
+
+ def _subrole_id_to_dn(self, role_id, tenant_id):
+ if tenant_id is None:
+ return self._id_to_dn(role_id)
+ else:
+ return "cn=%s,%s" % (ldap.dn.escape_dn_chars(role_id),
+ self.api.tenant._id_to_dn(tenant_id))
+
+ def add_user(self, role_id, user_id, tenant_id=None):
+ user = self.api.user.get(user_id)
+ if user is None:
+ raise exception.NotFound("User %s not found" % (user_id,))
+ role_dn = self._subrole_id_to_dn(role_id, tenant_id)
+ conn = self.api.get_connection()
+ user_dn = self.api.user._id_to_dn(user_id)
+ try:
+ conn.modify_s(role_dn, [(ldap.MOD_ADD, 'member', user_dn)])
+ except ldap.TYPE_OR_VALUE_EXISTS:
+ raise exception.Duplicate(
+ "User %s already has role %s in tenant %s" % (user_id,
+ role_id, tenant_id))
+ except ldap.NO_SUCH_OBJECT:
+ if tenant_id is None or self.get(role_id) is None:
+ raise exception.NotFound("Role %s not found" % (role_id,))
+ attrs = [
+ ('objectClass', 'keystoneTenantRole'),
+ ('member', user_dn),
+ ('role', self._id_to_dn(role_id)),
+ ]
+ conn.add_s(role_dn, attrs)
+ return models.UserRoleAssociation(
+ id=self._create_ref(role_id, tenant_id, user_id),
+ role_id=role_id, user_id=user_id, tenant_id=tenant_id)
+
+ def get_role_assignments(self, tenant_id):
+ conn = self.api.get_connection()
+ query = '(objectClass=keystoneTenantRole)'
+ tenant_dn = self.api.tenant._id_to_dn(tenant_id)
+ try:
+ roles = conn.search_s(tenant_dn, ldap.SCOPE_ONELEVEL, query)
+ except ldap.NO_SUCH_OBJECT:
+ return []
+ res = []
+ for role_dn, attrs in roles:
+ try:
+ user_dns = attrs['member']
+ except KeyError:
+ continue
+ for user_dn in user_dns:
+ user_id=ldap.dn.str2dn(user_dn)[0][0][1]
+ role_id=ldap.dn.str2dn(role_dn)[0][0][1]
+ res.append(models.UserRoleAssociation(
+ id=self._create_ref(role_id, tenant_id, user_id),
+ user_id=user_id,
+ role_id=role_id,
+ tenant_id=tenant_id))
+ return res
+
+ def ref_get_all_global_roles(self, user_id):
+ user_dn = self.api.user._id_to_dn(user_id)
+ roles = self.get_all('(member=%s)' % (user_dn,))
+ return [models.UserRoleAssociation(
+ id=self._create_ref(role.id, None, user_id),
+ role_id=role.id,
+ user_id=user_id) for role in roles]
+
+ def ref_get_all_tenant_roles(self, user_id, tenant_id):
+ conn = self.api.get_connection()
+ user_dn = self.api.user._id_to_dn(user_id)
+ tenant_dn = self.api.tenant._id_to_dn(tenant_id)
+ query = '(&(objectClass=keystoneTenantRole)(member=%s))' % (user_dn,)
+ try:
+ roles = conn.search_s(tenant_dn, ldap.SCOPE_ONELEVEL, query)
+ except ldap.NO_SUCH_OBJECT:
+ return []
+ res = []
+ for role_dn, _ in roles:
+ role_id = ldap.dn.str2dn(role_dn)[0][0][1]
+ res.append(models.UserRoleAssociation(
+ id=self._create_ref(role_id, tenant_id, user_id),
+ user_id=user_id,
+ role_id=role_id,
+ tenant_id=tenant_id))
+ return res
+
+ def ref_get(self, id):
+ role_id, tenant_id, user_id = self._explode_ref(id)
+ user_dn = self.api.user._id_to_dn(user_id)
+ role_dn = self._subrole_id_to_dn(role_id, tenant_id)
+ query = '(&(objectClass=keystoneTenantRole)(member=%s))' % (user_dn,)
+ try:
+ res = search_s(role_dn, ldap.SCOPE_BASE, query)
+ except ldap.NO_SUCH_OBJECT:
+ return None
+ if len(res) == 0:
+ return None
+ return models.UserRoleAssociation(id=id, role_id=role_id,
+ tenant_id=tenant_id, user_id=user_id)
+
+ def ref_delete(self, id):
+ role_id, tenant_id, user_id = self._explode_ref(id)
+ user_dn = self.api.user._id_to_dn(user_id)
+ role_dn = self._subrole_id_to_dn(role_id, tenant_id)
+ conn = self.api.get_connection()
+ try:
+ conn.modify_s(role_dn, [(ldap.MOD_DELETE, 'member', [user_dn])])
+ except ldap.NO_SUCH_ATTRIBUTE:
+ raise exception.NotFound("No such user in role")
+
+ def ref_get_page(self, marker, limit, user_id):
+ all_roles = self.ref_get_all_global_roles(user_id)
+ for tenant in self.api.tenant.get_all():
+ all_roles += self.ref_get_all_tenant_roles(user_id, tenant.id)
+ return self._get_page(marker, limit, all_roles)
+
+ def ref_get_page_markers(self, user_id, marker, limit):
+ all_roles = self.ref_get_all_global_roles(user_id)
+ for tenant in self.api.tenant.get_all():
+ all_roles += self.ref_get_all_tenant_roles(user_id, tenant.id)
+ return self._get_page_markers(marker, limit, all_roles)
diff --git a/keystone/backends/ldap/api/tenant.py b/keystone/backends/ldap/api/tenant.py
new file mode 100644
index 00000000..3b1204ea
--- /dev/null
+++ b/keystone/backends/ldap/api/tenant.py
@@ -0,0 +1,53 @@
+import ldap
+
+from keystone.backends.api import BaseTenantAPI
+from keystone.backends.sqlalchemy.api.tenant import TenantAPI as SQLTenantAPI
+
+from .. import models
+from .base import BaseLdapAPI, add_redirects
+
+class TenantAPI(BaseLdapAPI, BaseTenantAPI):
+ DEFAULT_TREE_DN = 'ou=Groups,dc=example,dc=com'
+ options_name = 'tenant_tree_dn'
+ object_class = 'keystoneTenant'
+ model = models.Tenant
+ attribute_mapping = { 'desc': 'description' }
+
+ def get_user_tenants(self, user_id):
+ user_dn = self.api.user._id_to_dn(user_id)
+ query = '(member=%s)' % (user_dn,)
+ return self.get_all(query)
+
+ def tenants_for_user_get_page(self, user, marker, limit):
+ return self._get_page(marker, limit, self.get_user_tenants(user.id))
+
+ def tenants_for_user_get_page_markers(self, user, marker, limit):
+ return self._get_page_markers(marker, limit,
+ self.get_user_tenants(user.id))
+
+ def is_empty(self, id):
+ tenant = self._ldap_get(id)
+ empty = len(tenant[1].get('member', [])) == 0
+ return empty and len(self.api.role.get_role_assignments(id)) == 0
+
+ def get_role_assignments(self, tenant_id):
+ return self.api.role.get_role_assignments(tenant_id)
+
+ def add_user(self, tenant_id, user_id):
+ conn = self.api.get_connection()
+ conn.modify_s(self._id_to_dn(tenant_id),
+ [(ldap.MOD_ADD, 'member', self.api.user._id_to_dn(user_id))])
+
+ def remove_user(self, tenant_id, user_id):
+ conn = self.api.get_connection()
+ conn.modify_s(self._id_to_dn(tenant_id),
+ [(ldap.MOD_DELETE, 'member', self.api.user._id_to_dn(user_id))])
+
+ def get_users(self, tenant_id):
+ tenant = self._ldap_get(tenant_id)
+ res = []
+ for user_dn in tenant[1].get('member',[]):
+ res.append(self.api.user.get(ldap.dn.str2dn(user_dn)[0][0][1]))
+ return res
+
+ add_redirects(locals(), SQLTenantAPI, ['get_all_endpoints'])
diff --git a/keystone/backends/ldap/api/user.py b/keystone/backends/ldap/api/user.py
new file mode 100644
index 00000000..cb9c82a2
--- /dev/null
+++ b/keystone/backends/ldap/api/user.py
@@ -0,0 +1,97 @@
+import ldap
+
+from keystone import utils
+from keystone.backends.api import BaseUserAPI
+from keystone.backends.sqlalchemy.api.user import UserAPI as SQLUserAPI
+
+from .. import models
+from .base import BaseLdapAPI, add_redirects
+
+class UserAPI(BaseLdapAPI, BaseUserAPI):
+ DEFAULT_TREE_DN = 'ou=Users,dc=example,dc=com'
+ options_name = 'user_tree_dn'
+ object_class = 'keystoneUser'
+ model = models.User
+ attribute_mapping = { 'password': 'userPassword', 'email': 'mail' }
+ attribute_ignore = ['tenant_id']
+
+ def __check_and_use_hashed_password(self, values):
+ if type(values) is dict and 'password' in values.keys():
+ values['password'] = utils.get_hashed_password(values['password'])
+ elif type(values) is models.User:
+ values.password = utils.get_hashed_password(values.password)
+
+ def _ldap_res_to_model(self, res):
+ obj = super(UserAPI, self)._ldap_res_to_model(res)
+ tenants = self.api.tenant.get_user_tenants(obj.id)
+ if len(tenants) > 0:
+ obj.tenant_id = tenants[0].id
+ return obj
+
+ def create(self, values):
+ self.__check_and_use_hashed_password(values)
+ super(UserAPI, self).create(values)
+ if values['tenant_id'] is not None:
+ self.api.tenant.add_user(values['tenant_id'], values['id'])
+
+ def update(self, id, values):
+ old_obj = self.get(id)
+ try:
+ new_tenant = values['tenant_id']
+ except KeyError:
+ pass
+ else:
+ if old_obj.tenant_id != new_tenant:
+ self.api.tenant.remove_user(old_obj.tenant_id, id)
+ self.api.tenant.add_user(new_tenant, id)
+ super(UserAPI, self).update(id, values, old_obj)
+
+ def get_by_email(self, email):
+ users = self.get_all('(mail=%s)' % \
+ (ldap.filter.escape_filter_chars(email),))
+ try:
+ return users[0]
+ except IndexError:
+ return None
+
+ def user_roles_by_tenant(self, user_id, tenant_id):
+ return self.api.role.ref_get_all_tenant_roles(user_id, tenant_id)
+
+ def get_by_tenant(self, id, tenant_id):
+ user_dn = self._id_to_dn(id)
+ user = self.get(id)
+ tenant = self.api.tenant._ldap_get(tenant_id,
+ '(member=%s)' % (user_dn,))
+ if tenant is not None:
+ return user
+ else:
+ return None
+
+ def delete_tenant_user(self, id, tenant_id):
+ self.api.tenant.remove_user(tenant_id, id)
+ self.delete(id)
+
+ def user_role_add(self, values):
+ return self.api.role.add_user(values.role_id, values.user_id,
+ values.tenant_id)
+
+ def user_get_update(self, id):
+ return self.get(id)
+
+ def users_get_page(self, marker, limit):
+ return self.get_page(marker, limit)
+
+ def users_get_page_markers(self, marker, limit):
+ return self.get_page_markers(marker, limit)
+
+ def users_get_by_tenant_get_page(self, tenant_id, marker, limit):
+ return self._get_page(marker, limit,
+ self.api.tenant.get_users(tenant_id))
+
+ def users_get_by_tenant_get_page_markers(self, tenant_id, marker, limit):
+ return self._get_page_markers(marker, limit,
+ self.api.tenant.get_users(tenant_id))
+
+ add_redirects(locals(), SQLUserAPI, ['get_by_group', 'tenant_group',
+ 'tenant_group_delete', 'user_groups_get_all',
+ 'users_tenant_group_get_page', 'users_tenant_group_get_page_markers'])
diff --git a/keystone/backends/ldap/fakeldap.py b/keystone/backends/ldap/fakeldap.py
new file mode 100644
index 00000000..44d34e48
--- /dev/null
+++ b/keystone/backends/ldap/fakeldap.py
@@ -0,0 +1,278 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# 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.
+"""Fake LDAP server for test harness.
+
+This class does very little error checking, and knows nothing about ldap
+class definitions. It implements the minimum emulation of the python ldap
+library to work with nova.
+
+"""
+
+import logging
+import re
+import shelve
+
+from ldap import (dn, filter, modlist,
+ SCOPE_BASE, SCOPE_ONELEVEL, SCOPE_SUBTREE, MOD_ADD, MOD_DELETE, MOD_REPLACE,
+ NO_SUCH_OBJECT, OBJECT_CLASS_VIOLATION, SERVER_DOWN, NO_SUCH_ATTRIBUTE,
+ ALREADY_EXISTS)
+
+
+scope_names = {
+ SCOPE_BASE: 'SCOPE_BASE',
+ SCOPE_ONELEVEL: 'SCOPE_ONELEVEL',
+ SCOPE_SUBTREE: 'SCOPE_SUBTREE',
+}
+
+
+LOG = logging.getLogger('keystone.backends.ldap.fakeldap')
+
+
+def initialize(uri):
+ """Opens a fake connection with an LDAP server."""
+ return FakeLDAP(uri)
+
+
+def _match_query(query, attrs):
+ """Match an ldap query to an attribute dictionary.
+
+ The characters &, |, and ! are supported in the query. No syntax checking
+ is performed, so malformed querys will not work correctly.
+ """
+ # cut off the parentheses
+ inner = query[1:-1]
+ if inner.startswith('&'):
+ # cut off the &
+ l, r = _paren_groups(inner[1:])
+ return _match_query(l, attrs) and _match_query(r, attrs)
+ if inner.startswith('|'):
+ # cut off the |
+ l, r = _paren_groups(inner[1:])
+ return _match_query(l, attrs) or _match_query(r, attrs)
+ if inner.startswith('!'):
+ # cut off the ! and the nested parentheses
+ return not _match_query(query[2:-1], attrs)
+
+ (k, _sep, v) = inner.partition('=')
+ return _match(k, v, attrs)
+
+
+def _paren_groups(source):
+ """Split a string into parenthesized groups."""
+ count = 0
+ start = 0
+ result = []
+ for pos in xrange(len(source)):
+ if source[pos] == '(':
+ if count == 0:
+ start = pos
+ count += 1
+ if source[pos] == ')':
+ count -= 1
+ if count == 0:
+ result.append(source[start:pos + 1])
+ return result
+
+
+def _match(key, value, attrs):
+ """Match a given key and value against an attribute list."""
+ if key not in attrs:
+ return False
+ # This is a wild card search. Implemented as all or nothing for now.
+ if value == "*":
+ return True
+ if key != "objectclass":
+ return value in attrs[key]
+ # it is an objectclass check, so check subclasses
+ values = _subs(value)
+ for v in values:
+ if v in attrs[key]:
+ return True
+ return False
+
+
+def _subs(value):
+ """Returns a list of subclass strings.
+
+ The strings represent the ldap objectclass plus any subclasses that
+ inherit from it. Fakeldap doesn't know about the ldap object structure,
+ so subclasses need to be defined manually in the dictionary below.
+
+ """
+ subs = {'groupOfNames': ['keystoneTenant', 'keystoneRole', 'keystoneTenantRole']}
+ if value in subs:
+ return [value] + subs[value]
+ return [value]
+
+
+server_fail = False
+
+
+class FakeLDAP(object):
+ """Fake LDAP connection."""
+
+ def __init__(self, url):
+ LOG.debug("FakeLDAP initialize url=%s" % (url,))
+ self.db = shelve.open(url[7:])
+
+ def simple_bind_s(self, dn, password):
+ """This method is ignored, but provided for compatibility."""
+ if server_fail:
+ raise SERVER_DOWN
+ LOG.debug("FakeLDAP bind dn=%s" % (dn,))
+
+ def unbind_s(self):
+ """This method is ignored, but provided for compatibility."""
+ if server_fail:
+ raise SERVER_DOWN
+ pass
+
+ def add_s(self, dn, attrs):
+ """Add an object with the specified attributes at dn."""
+ if server_fail:
+ raise SERVER_DOWN
+
+ key = "%s%s" % (self.__prefix, dn)
+ LOG.debug("FakeLDAP add item: dn=%s, attrs=%s" % (dn, attrs))
+ if self.db.has_key(key):
+ LOG.error("FakeLDAP add item failed: dn '%s' is already in store." %
+ (dn,))
+ raise ALREADY_EXISTS
+ self.db[key] = dict([(k, v if isinstance(v, list) else [v])
+ for k, v in attrs])
+ self.db.sync()
+
+ def delete_s(self, dn):
+ """Remove the ldap object at specified dn."""
+ if server_fail:
+ raise SERVER_DOWN
+
+ key = "%s%s" % (self.__prefix, dn)
+ LOG.debug("FakeLDAP delete item: dn=%s" % (dn,))
+ try:
+ del self.db[key]
+ except KeyError:
+ LOG.error("FakeLDAP delete item failed: dn '%s' not found." % (dn,))
+ raise NO_SUCH_OBJECT
+ self.db.sync()
+
+ def modify_s(self, dn, attrs):
+ """Modify the object at dn using the attribute list.
+
+ Args:
+ dn -- a dn
+ attrs -- a list of tuples in the following form:
+ ([MOD_ADD | MOD_DELETE | MOD_REPACE], attribute, value)
+
+ """
+ if server_fail:
+ raise SERVER_DOWN
+
+ key = "%s%s" % (self.__prefix, dn)
+ LOG.debug("FakeLDAP modify item: dn=%s attrs=%s" % (dn, attrs))
+ try:
+ entry = self.db[key]
+ except KeyError:
+ LOG.error("FakeLDAP modify item failed: dn '%s' not found." % (dn,))
+ raise NO_SUCH_OBJECT
+
+ for cmd, k, v in attrs:
+ values = entry.setdefault(k, [])
+ if cmd == MOD_ADD:
+ if isinstance(v, list):
+ values += v
+ else:
+ values.append(v)
+ elif cmd == MOD_REPLACE:
+ values[:] = v if isinstance(v, list) else [v]
+ elif cmd == MOD_DELETE:
+ if v is None:
+ if len(values) == 0:
+ LOG.error("FakeLDAP modify item failed: "
+ "item has no attribute '%s' to delete" % (k,))
+ raise NO_SUCH_ATTRIBUTE
+ values[:] = []
+ else:
+ if not isinstance(v,list):
+ v = [v]
+ for val in v:
+ try:
+ values.remove(val)
+ except ValueError:
+ LOG.error("FakeLDAP modify item failed: "
+ "item has no attribute '%s' with value '%s'"
+ " to delete" % (k, val))
+ raise NO_SUCH_ATTRIBUTE
+ else:
+ LOG.error("FakeLDAP modify item failed: unknown command %s" % (cmd,))
+ raise NotImplementedError( \
+ "modify_s action %s not implemented" % (cmd,))
+ self.db[key] = entry
+ self.db.sync()
+
+ def search_s(self, dn, scope, query=None, fields=None):
+ """Search for all matching objects under dn using the query.
+
+ Args:
+ dn -- dn to search under
+ scope -- only SCOPE_BASE and SCOPE_SUBTREE are supported
+ query -- query to filter objects by
+ fields -- fields to return. Returns all fields if not specified
+
+ """
+ if server_fail:
+ raise SERVER_DOWN
+
+ LOG.debug("FakeLDAP search at dn=%s scope=%s query='%s'" %
+ (dn, scope_names.get(scope, scope), query))
+ if scope == SCOPE_BASE:
+ try:
+ item_dict = self.db["%s%s" % (self.__prefix, dn)]
+ except KeyError:
+ LOG.debug("FakeLDAP search fail: dn not found for SCOPE_BASE")
+ raise NO_SUCH_OBJECT
+ results = [(dn, item_dict)]
+ elif scope == SCOPE_SUBTREE:
+ results = [(k[len(self.__prefix):], v)
+ for k, v in self.db.iteritems()
+ if re.match("%s.*,%s" % (self.__prefix, dn), k)]
+ elif scope == SCOPE_ONELEVEL:
+ results = [(k[len(self.__prefix):], v)
+ for k, v in self.db.iteritems()
+ if re.match("%s\w+=[^,]+,%s" % (self.__prefix, dn), k)]
+ else:
+ LOG.error("FakeLDAP search fail: unknown scope %s" % (scope,))
+ raise NotImplementedError("Search scope %s not implemented." %
+ (scope,))
+
+ objects = []
+ for dn, attrs in results:
+ # filter the objects by query
+ if not query or _match_query(query, attrs):
+ # filter the attributes by fields
+ attrs = dict([(k, v) for k, v in attrs.iteritems()
+ if not fields or k in fields])
+ objects.append((dn, attrs))
+ # pylint: enable=E1103
+ LOG.debug("FakeLDAP search result: %s" % (objects,))
+ return objects
+
+ @property
+ def __prefix(self): # pylint: disable=R0201
+ """Get the prefix to use for all keys."""
+ return 'ldap:'
diff --git a/keystone/backends/ldap/models.py b/keystone/backends/ldap/models.py
new file mode 100644
index 00000000..c2d86da3
--- /dev/null
+++ b/keystone/backends/ldap/models.py
@@ -0,0 +1,48 @@
+from collections import Mapping
+
+__all__ = ['UserRoleAssociation', 'Endpoints', 'Role', 'Tenant', 'User',
+ 'Credentials']
+
+
+def create_model(name, attrs):
+ class C(Mapping):
+ __slots__ = attrs
+ def __init__(self, arg=None, **kwargs):
+ if arg is None:
+ arg = kwargs
+ if isinstance(arg, dict):
+ missed_attrs = set(attrs)
+ for k, v in kwargs.iteritems():
+ setattr(self, k, v)
+ missed_attrs.remove(k)
+ for name in missed_attrs:
+ setattr(self, name, None)
+ elif isinstance(arg, C):
+ for name in attrs:
+ setattr(self, name, getattr(arg, name))
+ else:
+ raise ValueError
+
+ def __getitem__(self, name):
+ return getattr(self, name)
+
+ def __setitem__(self, name, value):
+ return setattr(self, name, value)
+
+ def __iter__(self):
+ return iter(attrs)
+
+ def __len__(self):
+ return len(attrs)
+ C.__name__ = name
+ return C
+
+
+UserRoleAssociation = create_model('UserRoleAssociation',
+ ['id', 'user_id', 'role_id', 'tenant_id'])
+Endpoints = create_model('Endpoints', ['tenant_id', 'endpoint_template_id']) #?
+Role = create_model('Role', ['id', 'desc'])
+Tenant = create_model('Tenant', ['id', 'desc', 'enabled'])
+User = create_model('User', ['id', 'password', 'email', 'enabled', 'tenant_id'])
+Credentials = create_model('Credentials', ['user_id', 'type', 'key', 'secret'])
+
diff --git a/keystone/backends/sqlalchemy/api/user.py b/keystone/backends/sqlalchemy/api/user.py
index 304ba204..891161f4 100755
--- a/keystone/backends/sqlalchemy/api/user.py
+++ b/keystone/backends/sqlalchemy/api/user.py
@@ -47,7 +47,8 @@ class UserAPI(BaseUserAPI):
session = get_session()
with session.begin():
usertenantgroup_ref = self.get_by_group(id, group_id, session)
- session.delete(usertenantgroup_ref)
+ if usertenantgroup_ref is not None:
+ session.delete(usertenantgroup_ref)
def create(self, values):
diff --git a/keystone/frontends/legacy_token_auth.py b/keystone/frontends/legacy_token_auth.py
index 02c413b3..1d7cfc64 100644
--- a/keystone/frontends/legacy_token_auth.py
+++ b/keystone/frontends/legacy_token_auth.py
@@ -72,9 +72,9 @@ class AuthProtocol(object):
"password": utils.get_auth_key(self.request)}}
#Make request to keystone
new_request = Request.blank('/v2.0/tokens')
+ new_request.method = 'POST'
new_request.headers['Content-type'] = 'application/json'
new_request.accept = 'text/json'
- new_request.method = 'POST'
new_request.body = json.dumps(params)
response = new_request.get_response(self.app)
#Handle failures.
diff --git a/keystone/test/unit/test_common.py b/keystone/test/unit/test_common.py
index 706d59f7..819e35fb 100755
--- a/keystone/test/unit/test_common.py
+++ b/keystone/test/unit/test_common.py
@@ -817,12 +817,16 @@ def delete_all_endpoint(tenant_id, auth_token):
#verify content
obj = json.loads(content)
- endpoints = obj["endpoints"]["values"]
- for endpoint in endpoints:
- url = '%stenants/%s/endpoints/%s' % (URL, tenant_id, endpoint["id"])
- header.request(url, "DELETE", body='',
- headers={"Content-Type": "application/json",
- "X-Auth-Token": str(auth_token)})
+ try:
+ endpoints = obj["endpoints"]["values"]
+ except KeyError:
+ pass
+ else:
+ for endpoint in endpoints:
+ url = '%stenants/%s/endpoints/%s' % (URL, tenant_id, endpoint["id"])
+ header.request(url, "DELETE", body='',
+ headers={"Content-Type": "application/json",
+ "X-Auth-Token": str(auth_token)})
if __name__ == '__main__':
unittest.main()
diff --git a/keystone/utils.py b/keystone/utils.py
index 321381ff..176affc2 100755
--- a/keystone/utils.py
+++ b/keystone/utils.py
@@ -151,7 +151,13 @@ def import_module(module_name, class_name=None):
module and options. If no class_name is given, it is assumed to
be the last part of the module_name string.'''
if class_name is None:
- module_name, _separator, class_name = module_name.rpartition('.')
+ try:
+ __import__(module_name)
+ return sys.modules[module_name]
+ except ImportError as exc:
+ module_name, _separator, class_name = module_name.rpartition('.')
+ if not exc.message.startswith('No module named %s' % (class_name,)):
+ raise
try:
__import__(module_name)
return getattr(sys.modules[module_name], class_name)