summaryrefslogtreecommitdiffstats
path: root/nova/auth
diff options
context:
space:
mode:
authorTrey Morris <trey.morris@rackspace.com>2010-12-23 21:53:33 +0000
committerTrey Morris <trey.morris@rackspace.com>2010-12-23 21:53:33 +0000
commit5f8d02b39fb8917b34b68bbbf450656e1b68211c (patch)
tree4a8489e10fecea511e3fffece42de81c9fdc7837 /nova/auth
parent1c26d2b2ce824dbc64525eea699efbfa8bf04617 (diff)
parent75e2cbec9eb5132a49446f1b6d563d5f43d007de (diff)
downloadnova-5f8d02b39fb8917b34b68bbbf450656e1b68211c.tar.gz
nova-5f8d02b39fb8917b34b68bbbf450656e1b68211c.tar.xz
nova-5f8d02b39fb8917b34b68bbbf450656e1b68211c.zip
fixed merge conflict
Diffstat (limited to 'nova/auth')
-rw-r--r--nova/auth/dbdriver.py20
-rw-r--r--nova/auth/fakeldap.py104
-rw-r--r--nova/auth/ldapdriver.py172
-rw-r--r--nova/auth/manager.py106
-rw-r--r--nova/auth/nova_openldap.schema46
-rw-r--r--nova/auth/nova_sun.schema13
-rwxr-xr-xnova/auth/opendj.sh1
-rwxr-xr-xnova/auth/slap.sh3
8 files changed, 245 insertions, 220 deletions
diff --git a/nova/auth/dbdriver.py b/nova/auth/dbdriver.py
index a1584322b..47e435cb6 100644
--- a/nova/auth/dbdriver.py
+++ b/nova/auth/dbdriver.py
@@ -37,7 +37,6 @@ class DbDriver(object):
def __init__(self):
"""Imports the LDAP module"""
pass
- db
def __enter__(self):
return self
@@ -83,7 +82,7 @@ class DbDriver(object):
user_ref = db.user_create(context.get_admin_context(), values)
return self._db_user_to_auth_user(user_ref)
except exception.Duplicate, e:
- raise exception.Duplicate('User %s already exists' % name)
+ raise exception.Duplicate(_('User %s already exists') % name)
def _db_user_to_auth_user(self, user_ref):
return {'id': user_ref['id'],
@@ -105,8 +104,9 @@ class DbDriver(object):
"""Create a project"""
manager = db.user_get(context.get_admin_context(), manager_uid)
if not manager:
- raise exception.NotFound("Project can't be created because "
- "manager %s doesn't exist" % manager_uid)
+ raise exception.NotFound(_("Project can't be created because "
+ "manager %s doesn't exist")
+ % manager_uid)
# description is a required attribute
if description is None:
@@ -133,8 +133,8 @@ class DbDriver(object):
try:
project = db.project_create(context.get_admin_context(), values)
except exception.Duplicate:
- raise exception.Duplicate("Project can't be created because "
- "project %s already exists" % name)
+ raise exception.Duplicate(_("Project can't be created because "
+ "project %s already exists") % name)
for member in members:
db.project_add_member(context.get_admin_context(),
@@ -155,8 +155,8 @@ class DbDriver(object):
if manager_uid:
manager = db.user_get(context.get_admin_context(), manager_uid)
if not manager:
- raise exception.NotFound("Project can't be modified because "
- "manager %s doesn't exist" %
+ raise exception.NotFound(_("Project can't be modified because "
+ "manager %s doesn't exist") %
manager_uid)
values['project_manager'] = manager['id']
if description:
@@ -243,8 +243,8 @@ class DbDriver(object):
def _validate_user_and_project(self, user_id, project_id):
user = db.user_get(context.get_admin_context(), user_id)
if not user:
- raise exception.NotFound('User "%s" not found' % user_id)
+ raise exception.NotFound(_('User "%s" not found') % user_id)
project = db.project_get(context.get_admin_context(), project_id)
if not project:
- raise exception.NotFound('Project "%s" not found' % project_id)
+ raise exception.NotFound(_('Project "%s" not found') % project_id)
return user, project
diff --git a/nova/auth/fakeldap.py b/nova/auth/fakeldap.py
index 46e0135b4..4466051f0 100644
--- a/nova/auth/fakeldap.py
+++ b/nova/auth/fakeldap.py
@@ -15,7 +15,7 @@
# 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, backs to ReDIS.
+"""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
@@ -23,34 +23,65 @@ library to work with nova.
"""
+import fnmatch
import json
-import redis
-from nova import flags
-FLAGS = flags.FLAGS
-flags.DEFINE_string('redis_host', '127.0.0.1',
- 'Host that redis is running on.')
-flags.DEFINE_integer('redis_port', 6379,
- 'Port that redis is running on.')
-flags.DEFINE_integer('redis_db', 0, 'Multiple DB keeps tests away')
-
-
-class Redis(object):
+class Store(object):
def __init__(self):
if hasattr(self.__class__, '_instance'):
- raise Exception('Attempted to instantiate singleton')
+ raise Exception(_('Attempted to instantiate singleton'))
@classmethod
def instance(cls):
if not hasattr(cls, '_instance'):
- inst = redis.Redis(host=FLAGS.redis_host,
- port=FLAGS.redis_port,
- db=FLAGS.redis_db)
- cls._instance = inst
+ cls._instance = _StorageDict()
return cls._instance
+class _StorageDict(dict):
+ def keys(self, pat=None):
+ ret = super(_StorageDict, self).keys()
+ if pat is not None:
+ ret = fnmatch.filter(ret, pat)
+ return ret
+
+ def delete(self, key):
+ try:
+ del self[key]
+ except KeyError:
+ pass
+
+ def flushdb(self):
+ self.clear()
+
+ def hgetall(self, key):
+ """Returns the hash for the given key; creates
+ the hash if the key doesn't exist."""
+ try:
+ return self[key]
+ except KeyError:
+ self[key] = {}
+ return self[key]
+
+ def hget(self, key, field):
+ hashdict = self.hgetall(key)
+ try:
+ return hashdict[field]
+ except KeyError:
+ hashdict[field] = {}
+ return hashdict[field]
+
+ def hset(self, key, field, val):
+ hashdict = self.hgetall(key)
+ hashdict[field] = val
+
+ def hmset(self, key, value_dict):
+ hashdict = self.hgetall(key)
+ for field, val in value_dict.items():
+ hashdict[field] = val
+
+
SCOPE_BASE = 0
SCOPE_ONELEVEL = 1 # Not implemented
SCOPE_SUBTREE = 2
@@ -119,6 +150,9 @@ 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
@@ -169,8 +203,6 @@ def _to_json(unencoded):
class FakeLDAP(object):
- #TODO(vish): refactor this class to use a wrapper instead of accessing
- # redis directly
"""Fake LDAP connection."""
def simple_bind_s(self, dn, password):
@@ -183,14 +215,13 @@ class FakeLDAP(object):
def add_s(self, dn, attr):
"""Add an object with the specified attributes at dn."""
- key = "%s%s" % (self.__redis_prefix, dn)
-
+ key = "%s%s" % (self.__prefix, dn)
value_dict = dict([(k, _to_json(v)) for k, v in attr])
- Redis.instance().hmset(key, value_dict)
+ Store.instance().hmset(key, value_dict)
def delete_s(self, dn):
"""Remove the ldap object at specified dn."""
- Redis.instance().delete("%s%s" % (self.__redis_prefix, dn))
+ Store.instance().delete("%s%s" % (self.__prefix, dn))
def modify_s(self, dn, attrs):
"""Modify the object at dn using the attribute list.
@@ -201,18 +232,18 @@ class FakeLDAP(object):
([MOD_ADD | MOD_DELETE | MOD_REPACE], attribute, value)
"""
- redis = Redis.instance()
- key = "%s%s" % (self.__redis_prefix, dn)
+ store = Store.instance()
+ key = "%s%s" % (self.__prefix, dn)
for cmd, k, v in attrs:
- values = _from_json(redis.hget(key, k))
+ values = _from_json(store.hget(key, k))
if cmd == MOD_ADD:
values.append(v)
elif cmd == MOD_REPLACE:
values = [v]
else:
values.remove(v)
- values = redis.hset(key, k, _to_json(values))
+ values = store.hset(key, k, _to_json(values))
def search_s(self, dn, scope, query=None, fields=None):
"""Search for all matching objects under dn using the query.
@@ -226,16 +257,17 @@ class FakeLDAP(object):
"""
if scope != SCOPE_BASE and scope != SCOPE_SUBTREE:
raise NotImplementedError(str(scope))
- redis = Redis.instance()
+ store = Store.instance()
if scope == SCOPE_BASE:
- keys = ["%s%s" % (self.__redis_prefix, dn)]
+ keys = ["%s%s" % (self.__prefix, dn)]
else:
- keys = redis.keys("%s*%s" % (self.__redis_prefix, dn))
+ keys = store.keys("%s*%s" % (self.__prefix, dn))
+
objects = []
for key in keys:
- # get the attributes from redis
- attrs = redis.hgetall(key)
- # turn the values from redis into lists
+ # get the attributes from the store
+ attrs = store.hgetall(key)
+ # turn the values from the store into lists
# pylint: disable-msg=E1103
attrs = dict([(k, _from_json(v))
for k, v in attrs.iteritems()])
@@ -244,13 +276,13 @@ class FakeLDAP(object):
# filter the attributes by fields
attrs = dict([(k, v) for k, v in attrs.iteritems()
if not fields or k in fields])
- objects.append((key[len(self.__redis_prefix):], attrs))
+ objects.append((key[len(self.__prefix):], attrs))
# pylint: enable-msg=E1103
if objects == []:
raise NO_SUCH_OBJECT()
return objects
@property
- def __redis_prefix(self): # pylint: disable-msg=R0201
- """Get the prefix to use for all redis keys."""
+ def __prefix(self): # pylint: disable-msg=R0201
+ """Get the prefix to use for all keys."""
return 'ldap:'
diff --git a/nova/auth/ldapdriver.py b/nova/auth/ldapdriver.py
index c10939d74..7616ff112 100644
--- a/nova/auth/ldapdriver.py
+++ b/nova/auth/ldapdriver.py
@@ -32,11 +32,16 @@ from nova import flags
FLAGS = flags.FLAGS
+flags.DEFINE_integer('ldap_schema_version', 2,
+ 'Current version of the LDAP schema')
flags.DEFINE_string('ldap_url', 'ldap://localhost',
'Point this at your ldap server')
flags.DEFINE_string('ldap_password', 'changeme', 'LDAP password')
flags.DEFINE_string('ldap_user_dn', 'cn=Manager,dc=example,dc=com',
'DN of admin user')
+flags.DEFINE_string('ldap_user_id_attribute', 'uid', 'Attribute to use as id')
+flags.DEFINE_string('ldap_user_name_attribute', 'cn',
+ 'Attribute to use as name')
flags.DEFINE_string('ldap_user_unit', 'Users', 'OID for Users')
flags.DEFINE_string('ldap_user_subtree', 'ou=Users,dc=example,dc=com',
'OU for Users')
@@ -73,10 +78,20 @@ class LdapDriver(object):
Defines enter and exit and therefore supports the with/as syntax.
"""
+ project_pattern = '(owner=*)'
+ isadmin_attribute = 'isNovaAdmin'
+ project_attribute = 'owner'
+ project_objectclass = 'groupOfNames'
+
def __init__(self):
"""Imports the LDAP module"""
self.ldap = __import__('ldap')
self.conn = None
+ if FLAGS.ldap_schema_version == 1:
+ LdapDriver.project_pattern = '(objectclass=novaProject)'
+ LdapDriver.isadmin_attribute = 'isAdmin'
+ LdapDriver.project_attribute = 'projectManager'
+ LdapDriver.project_objectclass = 'novaProject'
def __enter__(self):
"""Creates the connection to LDAP"""
@@ -104,13 +119,13 @@ class LdapDriver(object):
"""Retrieve project by id"""
dn = 'cn=%s,%s' % (pid,
FLAGS.ldap_project_subtree)
- attr = self.__find_object(dn, '(objectclass=novaProject)')
+ attr = self.__find_object(dn, LdapDriver.project_pattern)
return self.__to_project(attr)
def get_users(self):
"""Retrieve list of users"""
attrs = self.__find_objects(FLAGS.ldap_user_subtree,
- '(objectclass=novaUser)')
+ '(objectclass=novaUser)')
users = []
for attr in attrs:
user = self.__to_user(attr)
@@ -120,7 +135,7 @@ class LdapDriver(object):
def get_projects(self, uid=None):
"""Retrieve list of projects"""
- pattern = '(objectclass=novaProject)'
+ pattern = LdapDriver.project_pattern
if uid:
pattern = "(&%s(member=%s))" % (pattern, self.__uid_to_dn(uid))
attrs = self.__find_objects(FLAGS.ldap_project_subtree,
@@ -139,27 +154,29 @@ class LdapDriver(object):
# Malformed entries are useless, replace attributes found.
attr = []
if 'secretKey' in user.keys():
- attr.append((self.ldap.MOD_REPLACE, 'secretKey', \
- [secret_key]))
+ attr.append((self.ldap.MOD_REPLACE, 'secretKey',
+ [secret_key]))
else:
- attr.append((self.ldap.MOD_ADD, 'secretKey', \
- [secret_key]))
+ attr.append((self.ldap.MOD_ADD, 'secretKey',
+ [secret_key]))
if 'accessKey' in user.keys():
- attr.append((self.ldap.MOD_REPLACE, 'accessKey', \
- [access_key]))
+ attr.append((self.ldap.MOD_REPLACE, 'accessKey',
+ [access_key]))
else:
- attr.append((self.ldap.MOD_ADD, 'accessKey', \
- [access_key]))
- if 'isAdmin' in user.keys():
- attr.append((self.ldap.MOD_REPLACE, 'isAdmin', \
- [str(is_admin).upper()]))
+ attr.append((self.ldap.MOD_ADD, 'accessKey',
+ [access_key]))
+ if LdapDriver.isadmin_attribute in user.keys():
+ attr.append((self.ldap.MOD_REPLACE,
+ LdapDriver.isadmin_attribute,
+ [str(is_admin).upper()]))
else:
- attr.append((self.ldap.MOD_ADD, 'isAdmin', \
- [str(is_admin).upper()]))
+ attr.append((self.ldap.MOD_ADD,
+ LdapDriver.isadmin_attribute,
+ [str(is_admin).upper()]))
self.conn.modify_s(self.__uid_to_dn(name), attr)
return self.get_user(name)
else:
- raise exception.NotFound("LDAP object for %s doesn't exist"
+ raise exception.NotFound(_("LDAP object for %s doesn't exist")
% name)
else:
attr = [
@@ -168,12 +185,12 @@ class LdapDriver(object):
'inetOrgPerson',
'novaUser']),
('ou', [FLAGS.ldap_user_unit]),
- ('uid', [name]),
+ (FLAGS.ldap_user_id_attribute, [name]),
('sn', [name]),
- ('cn', [name]),
+ (FLAGS.ldap_user_name_attribute, [name]),
('secretKey', [secret_key]),
('accessKey', [access_key]),
- ('isAdmin', [str(is_admin).upper()]),
+ (LdapDriver.isadmin_attribute, [str(is_admin).upper()]),
]
self.conn.add_s(self.__uid_to_dn(name), attr)
return self.__to_user(dict(attr))
@@ -182,11 +199,12 @@ class LdapDriver(object):
description=None, member_uids=None):
"""Create a project"""
if self.__project_exists(name):
- raise exception.Duplicate("Project can't be created because "
- "project %s already exists" % name)
+ raise exception.Duplicate(_("Project can't be created because "
+ "project %s already exists") % name)
if not self.__user_exists(manager_uid):
- raise exception.NotFound("Project can't be created because "
- "manager %s doesn't exist" % manager_uid)
+ raise exception.NotFound(_("Project can't be created because "
+ "manager %s doesn't exist")
+ % manager_uid)
manager_dn = self.__uid_to_dn(manager_uid)
# description is a required attribute
if description is None:
@@ -195,18 +213,18 @@ class LdapDriver(object):
if member_uids is not None:
for member_uid in member_uids:
if not self.__user_exists(member_uid):
- raise exception.NotFound("Project can't be created "
- "because user %s doesn't exist"
+ raise exception.NotFound(_("Project can't be created "
+ "because user %s doesn't exist")
% member_uid)
members.append(self.__uid_to_dn(member_uid))
# always add the manager as a member because members is required
if not manager_dn in members:
members.append(manager_dn)
attr = [
- ('objectclass', ['novaProject']),
+ ('objectclass', [LdapDriver.project_objectclass]),
('cn', [name]),
('description', [description]),
- ('projectManager', [manager_dn]),
+ (LdapDriver.project_attribute, [manager_dn]),
('member', members)]
self.conn.add_s('cn=%s,%s' % (name, FLAGS.ldap_project_subtree), attr)
return self.__to_project(dict(attr))
@@ -218,11 +236,12 @@ class LdapDriver(object):
attr = []
if manager_uid:
if not self.__user_exists(manager_uid):
- raise exception.NotFound("Project can't be modified because "
- "manager %s doesn't exist" %
- manager_uid)
+ raise exception.NotFound(_("Project can't be modified because "
+ "manager %s doesn't exist")
+ % manager_uid)
manager_dn = self.__uid_to_dn(manager_uid)
- attr.append((self.ldap.MOD_REPLACE, 'projectManager', manager_dn))
+ attr.append((self.ldap.MOD_REPLACE, LdapDriver.project_attribute,
+ manager_dn))
if description:
attr.append((self.ldap.MOD_REPLACE, 'description', description))
self.conn.modify_s('cn=%s,%s' % (project_id,
@@ -282,10 +301,9 @@ class LdapDriver(object):
return roles
else:
project_dn = 'cn=%s,%s' % (project_id, FLAGS.ldap_project_subtree)
- roles = self.__find_objects(project_dn,
- '(&(&(objectclass=groupOfNames)'
- '(!(objectclass=novaProject)))'
- '(member=%s))' % self.__uid_to_dn(uid))
+ query = ('(&(&(objectclass=groupOfNames)(!%s))(member=%s))' %
+ (LdapDriver.project_pattern, self.__uid_to_dn(uid)))
+ roles = self.__find_objects(project_dn, query)
return [role['cn'][0] for role in roles]
def delete_user(self, uid):
@@ -299,14 +317,15 @@ class LdapDriver(object):
# Retrieve user by name
user = self.__get_ldap_user(uid)
if 'secretKey' in user.keys():
- attr.append((self.ldap.MOD_DELETE, 'secretKey', \
- user['secretKey']))
+ attr.append((self.ldap.MOD_DELETE, 'secretKey',
+ user['secretKey']))
if 'accessKey' in user.keys():
- attr.append((self.ldap.MOD_DELETE, 'accessKey', \
- user['accessKey']))
- if 'isAdmin' in user.keys():
- attr.append((self.ldap.MOD_DELETE, 'isAdmin', \
- user['isAdmin']))
+ attr.append((self.ldap.MOD_DELETE, 'accessKey',
+ user['accessKey']))
+ if LdapDriver.isadmin_attribute in user.keys():
+ attr.append((self.ldap.MOD_DELETE,
+ LdapDriver.isadmin_attribute,
+ user[LdapDriver.isadmin_attribute]))
self.conn.modify_s(self.__uid_to_dn(uid), attr)
else:
# Delete entry
@@ -328,7 +347,8 @@ class LdapDriver(object):
if secret_key:
attr.append((self.ldap.MOD_REPLACE, 'secretKey', secret_key))
if admin is not None:
- attr.append((self.ldap.MOD_REPLACE, 'isAdmin', str(admin).upper()))
+ attr.append((self.ldap.MOD_REPLACE, LdapDriver.isadmin_attribute,
+ str(admin).upper()))
self.conn.modify_s(self.__uid_to_dn(uid), attr)
def __user_exists(self, uid):
@@ -346,7 +366,7 @@ class LdapDriver(object):
def __get_ldap_user(self, uid):
"""Retrieve LDAP user entry by id"""
attr = self.__find_object(self.__uid_to_dn(uid),
- '(objectclass=novaUser)')
+ '(objectclass=novaUser)')
return attr
def __find_object(self, dn, query=None, scope=None):
@@ -382,19 +402,21 @@ class LdapDriver(object):
def __find_role_dns(self, tree):
"""Find dns of role objects in given tree"""
- return self.__find_dns(tree,
- '(&(objectclass=groupOfNames)(!(objectclass=novaProject)))')
+ query = ('(&(objectclass=groupOfNames)(!%s))' %
+ LdapDriver.project_pattern)
+ return self.__find_dns(tree, query)
def __find_group_dns_with_member(self, tree, uid):
"""Find dns of group objects in a given tree that contain member"""
- dns = self.__find_dns(tree,
- '(&(objectclass=groupOfNames)(member=%s))' %
- self.__uid_to_dn(uid))
+ query = ('(&(objectclass=groupOfNames)(member=%s))' %
+ self.__uid_to_dn(uid))
+ dns = self.__find_dns(tree, query)
return dns
def __group_exists(self, dn):
"""Check if group exists"""
- return self.__find_object(dn, '(objectclass=groupOfNames)') is not None
+ query = '(objectclass=groupOfNames)'
+ return self.__find_object(dn, query) is not None
@staticmethod
def __role_to_dn(role, project_id=None):
@@ -417,7 +439,8 @@ class LdapDriver(object):
for member_uid in member_uids:
if not self.__user_exists(member_uid):
raise exception.NotFound("Group can't be created "
- "because user %s doesn't exist" % member_uid)
+ "because user %s doesn't exist" %
+ member_uid)
members.append(self.__uid_to_dn(member_uid))
dn = self.__uid_to_dn(uid)
if not dn in members:
@@ -433,7 +456,7 @@ class LdapDriver(object):
"""Check if user is in group"""
if not self.__user_exists(uid):
raise exception.NotFound("User %s can't be searched in group "
- "becuase the user doesn't exist" % (uid,))
+ "because the user doesn't exist" % uid)
if not self.__group_exists(group_dn):
return False
res = self.__find_object(group_dn,
@@ -445,13 +468,13 @@ class LdapDriver(object):
"""Add user to group"""
if not self.__user_exists(uid):
raise exception.NotFound("User %s can't be added to the group "
- "becuase the user doesn't exist" % (uid,))
+ "because the user doesn't exist" % uid)
if not self.__group_exists(group_dn):
raise exception.NotFound("The group at dn %s doesn't exist" %
- (group_dn,))
+ group_dn)
if self.__is_in_group(uid, group_dn):
- raise exception.Duplicate("User %s is already a member of "
- "the group %s" % (uid, group_dn))
+ raise exception.Duplicate(_("User %s is already a member of "
+ "the group %s") % (uid, group_dn))
attr = [(self.ldap.MOD_ADD, 'member', self.__uid_to_dn(uid))]
self.conn.modify_s(group_dn, attr)
@@ -459,16 +482,16 @@ class LdapDriver(object):
"""Remove user from group"""
if not self.__group_exists(group_dn):
raise exception.NotFound("The group at dn %s doesn't exist" %
- (group_dn,))
+ group_dn)
if not self.__user_exists(uid):
raise exception.NotFound("User %s can't be removed from the "
- "group because the user doesn't exist" % (uid,))
+ "group because the user doesn't exist" %
+ uid)
if not self.__is_in_group(uid, group_dn):
raise exception.NotFound("User %s is not a member of the group" %
- (uid,))
+ uid)
# NOTE(vish): remove user from group and any sub_groups
- sub_dns = self.__find_group_dns_with_member(
- group_dn, uid)
+ sub_dns = self.__find_group_dns_with_member(group_dn, uid)
for sub_dn in sub_dns:
self.__safe_remove_from_group(uid, sub_dn)
@@ -479,15 +502,15 @@ class LdapDriver(object):
try:
self.conn.modify_s(group_dn, attr)
except self.ldap.OBJECT_CLASS_VIOLATION:
- logging.debug("Attempted to remove the last member of a group. "
- "Deleting the group at %s instead.", group_dn)
+ logging.debug(_("Attempted to remove the last member of a group. "
+ "Deleting the group at %s instead."), group_dn)
self.__delete_group(group_dn)
def __remove_from_all(self, uid):
"""Remove user from all roles and projects"""
if not self.__user_exists(uid):
raise exception.NotFound("User %s can't be removed from all "
- "because the user doesn't exist" % (uid,))
+ "because the user doesn't exist" % uid)
role_dns = self.__find_group_dns_with_member(
FLAGS.role_project_subtree, uid)
for role_dn in role_dns:
@@ -500,7 +523,8 @@ class LdapDriver(object):
def __delete_group(self, group_dn):
"""Delete Group"""
if not self.__group_exists(group_dn):
- raise exception.NotFound("Group at dn %s doesn't exist" % group_dn)
+ raise exception.NotFound(_("Group at dn %s doesn't exist")
+ % group_dn)
self.conn.delete_s(group_dn)
def __delete_roles(self, project_dn):
@@ -514,13 +538,13 @@ class LdapDriver(object):
if attr is None:
return None
if ('accessKey' in attr.keys() and 'secretKey' in attr.keys() \
- and 'isAdmin' in attr.keys()):
+ and LdapDriver.isadmin_attribute in attr.keys()):
return {
- 'id': attr['uid'][0],
- 'name': attr['cn'][0],
+ 'id': attr[FLAGS.ldap_user_id_attribute][0],
+ 'name': attr[FLAGS.ldap_user_name_attribute][0],
'access': attr['accessKey'][0],
'secret': attr['secretKey'][0],
- 'admin': (attr['isAdmin'][0] == 'TRUE')}
+ 'admin': (attr[LdapDriver.isadmin_attribute][0] == 'TRUE')}
else:
return None
@@ -532,7 +556,8 @@ class LdapDriver(object):
return {
'id': attr['cn'][0],
'name': attr['cn'][0],
- 'project_manager_id': self.__dn_to_uid(attr['projectManager'][0]),
+ 'project_manager_id':
+ self.__dn_to_uid(attr[LdapDriver.project_attribute][0]),
'description': attr.get('description', [None])[0],
'member_ids': [self.__dn_to_uid(x) for x in member_dns]}
@@ -542,9 +567,10 @@ class LdapDriver(object):
return dn.split(',')[0].split('=')[1]
@staticmethod
- def __uid_to_dn(dn):
+ def __uid_to_dn(uid):
"""Convert uid to dn"""
- return 'uid=%s,%s' % (dn, FLAGS.ldap_user_subtree)
+ return (FLAGS.ldap_user_id_attribute + '=%s,%s'
+ % (uid, FLAGS.ldap_user_subtree))
class FakeLdapDriver(LdapDriver):
diff --git a/nova/auth/manager.py b/nova/auth/manager.py
index 11c3bd6df..d3e266952 100644
--- a/nova/auth/manager.py
+++ b/nova/auth/manager.py
@@ -64,12 +64,9 @@ flags.DEFINE_string('credential_key_file', 'pk.pem',
'Filename of private key in credentials zip')
flags.DEFINE_string('credential_cert_file', 'cert.pem',
'Filename of certificate in credentials zip')
-flags.DEFINE_string('credential_rc_file', 'novarc',
- 'Filename of rc in credentials zip')
-flags.DEFINE_string('credential_cert_subject',
- '/C=US/ST=California/L=MountainView/O=AnsoLabs/'
- 'OU=NovaDev/CN=%s-%s',
- 'Subject for certificate for users')
+flags.DEFINE_string('credential_rc_file', '%src',
+ 'Filename of rc in credentials zip, %s will be '
+ 'replaced by name of the region (nova by default)')
flags.DEFINE_string('auth_driver', 'nova.auth.dbdriver.DbDriver',
'Driver that auth manager uses')
@@ -257,12 +254,12 @@ class AuthManager(object):
# TODO(vish): check for valid timestamp
(access_key, _sep, project_id) = access.partition(':')
- logging.info('Looking up user: %r', access_key)
+ logging.info(_('Looking up user: %r'), access_key)
user = self.get_user_from_access_key(access_key)
logging.info('user: %r', user)
if user == None:
- raise exception.NotFound('No user found for access key %s' %
- access_key)
+ raise exception.NotFound(_('No user found for access key %s')
+ % access_key)
# NOTE(vish): if we stop using project name as id we need better
# logic to find a default project for user
@@ -271,12 +268,12 @@ class AuthManager(object):
project = self.get_project(project_id)
if project == None:
- raise exception.NotFound('No project called %s could be found' %
- project_id)
+ raise exception.NotFound(_('No project called %s could be found')
+ % project_id)
if not self.is_admin(user) and not self.is_project_member(user,
project):
- raise exception.NotFound('User %s is not a member of project %s' %
- (user.id, project.id))
+ raise exception.NotFound(_('User %s is not a member of project %s')
+ % (user.id, project.id))
if check_type == 's3':
sign = signer.Signer(user.secret.encode())
expected_signature = sign.s3_authorization(headers, verb, path)
@@ -284,7 +281,7 @@ class AuthManager(object):
logging.debug('expected_signature: %s', expected_signature)
logging.debug('signature: %s', signature)
if signature != expected_signature:
- raise exception.NotAuthorized('Signature does not match')
+ raise exception.NotAuthorized(_('Signature does not match'))
elif check_type == 'ec2':
# NOTE(vish): hmac can't handle unicode, so encode ensures that
# secret isn't unicode
@@ -294,7 +291,7 @@ class AuthManager(object):
logging.debug('expected_signature: %s', expected_signature)
logging.debug('signature: %s', signature)
if signature != expected_signature:
- raise exception.NotAuthorized('Signature does not match')
+ raise exception.NotAuthorized(_('Signature does not match'))
return (user, project)
def get_access_key(self, user, project):
@@ -364,7 +361,7 @@ class AuthManager(object):
with self.driver() as drv:
if role == 'projectmanager':
if not project:
- raise exception.Error("Must specify project")
+ raise exception.Error(_("Must specify project"))
return self.is_project_manager(user, project)
global_role = drv.has_role(User.safe_id(user),
@@ -398,9 +395,9 @@ class AuthManager(object):
@param project: Project in which to add local role.
"""
if role not in FLAGS.allowed_roles:
- raise exception.NotFound("The %s role can not be found" % role)
+ raise exception.NotFound(_("The %s role can not be found") % role)
if project is not None and role in FLAGS.global_roles:
- raise exception.NotFound("The %s role is global only" % role)
+ raise exception.NotFound(_("The %s role is global only") % role)
with self.driver() as drv:
drv.add_role(User.safe_id(user), role, Project.safe_id(project))
@@ -543,10 +540,10 @@ class AuthManager(object):
"""
network_ref = db.project_get_network(context.get_admin_context(),
- Project.safe_id(project))
+ Project.safe_id(project), False)
- if not network_ref['vpn_public_port']:
- raise exception.NotFound('project network data has not been set')
+ if not network_ref:
+ return (None, None)
return (network_ref['vpn_public_address'],
network_ref['vpn_public_port'])
@@ -628,27 +625,37 @@ class AuthManager(object):
def get_key_pairs(context):
return db.key_pair_get_all_by_user(context.elevated(), context.user_id)
- def get_credentials(self, user, project=None):
+ def get_credentials(self, user, project=None, use_dmz=True):
"""Get credential zip for user in project"""
if not isinstance(user, User):
user = self.get_user(user)
if project is None:
project = user.id
pid = Project.safe_id(project)
- rc = self.__generate_rc(user.access, user.secret, pid)
- private_key, signed_cert = self._generate_x509_cert(user.id, pid)
+ private_key, signed_cert = crypto.generate_x509_cert(user.id, pid)
tmpdir = tempfile.mkdtemp()
zf = os.path.join(tmpdir, "temp.zip")
zippy = zipfile.ZipFile(zf, 'w')
- zippy.writestr(FLAGS.credential_rc_file, rc)
+ if use_dmz and FLAGS.region_list:
+ regions = {}
+ for item in FLAGS.region_list:
+ region, _sep, region_host = item.partition("=")
+ regions[region] = region_host
+ else:
+ regions = {'nova': FLAGS.cc_host}
+ for region, host in regions.iteritems():
+ rc = self.__generate_rc(user.access,
+ user.secret,
+ pid,
+ use_dmz,
+ host)
+ zippy.writestr(FLAGS.credential_rc_file % region, rc)
+
zippy.writestr(FLAGS.credential_key_file, private_key)
zippy.writestr(FLAGS.credential_cert_file, signed_cert)
- try:
- (vpn_ip, vpn_port) = self.get_project_vpn_data(project)
- except exception.NotFound:
- vpn_ip = None
+ (vpn_ip, vpn_port) = self.get_project_vpn_data(project)
if vpn_ip:
configfile = open(FLAGS.vpn_client_template, "r")
s = string.Template(configfile.read())
@@ -659,10 +666,9 @@ class AuthManager(object):
port=vpn_port)
zippy.writestr(FLAGS.credential_vpn_file, config)
else:
- logging.warn("No vpn data for project %s" %
- pid)
+ logging.warn(_("No vpn data for project %s"), pid)
- zippy.writestr(FLAGS.ca_file, crypto.fetch_ca(user.id))
+ zippy.writestr(FLAGS.ca_file, crypto.fetch_ca(pid))
zippy.close()
with open(zf, 'rb') as f:
read_buffer = f.read()
@@ -670,38 +676,38 @@ class AuthManager(object):
shutil.rmtree(tmpdir)
return read_buffer
- def get_environment_rc(self, user, project=None):
+ def get_environment_rc(self, user, project=None, use_dmz=True):
"""Get credential zip for user in project"""
if not isinstance(user, User):
user = self.get_user(user)
if project is None:
project = user.id
pid = Project.safe_id(project)
- return self.__generate_rc(user.access, user.secret, pid)
+ return self.__generate_rc(user.access, user.secret, pid, use_dmz)
@staticmethod
- def __generate_rc(access, secret, pid):
+ def __generate_rc(access, secret, pid, use_dmz=True, host=None):
"""Generate rc file for user"""
+ if use_dmz:
+ cc_host = FLAGS.cc_dmz
+ else:
+ cc_host = FLAGS.cc_host
+ # NOTE(vish): Always use the dmz since it is used from inside the
+ # instance
+ s3_host = FLAGS.s3_dmz
+ if host:
+ s3_host = host
+ cc_host = host
rc = open(FLAGS.credentials_template).read()
rc = rc % {'access': access,
'project': pid,
'secret': secret,
- 'ec2': FLAGS.ec2_url,
- 's3': 'http://%s:%s' % (FLAGS.s3_host, FLAGS.s3_port),
+ 'ec2': '%s://%s:%s%s' % (FLAGS.ec2_prefix,
+ cc_host,
+ FLAGS.cc_port,
+ FLAGS.ec2_suffix),
+ 's3': 'http://%s:%s' % (s3_host, FLAGS.s3_port),
'nova': FLAGS.ca_file,
'cert': FLAGS.credential_cert_file,
'key': FLAGS.credential_key_file}
return rc
-
- def _generate_x509_cert(self, uid, pid):
- """Generate x509 cert for user"""
- (private_key, csr) = crypto.generate_x509_cert(
- self.__cert_subject(uid))
- # TODO(joshua): This should be async call back to the cloud controller
- signed_cert = crypto.sign_csr(csr, pid)
- return (private_key, signed_cert)
-
- @staticmethod
- def __cert_subject(uid):
- """Helper to generate cert subject"""
- return FLAGS.credential_cert_subject % (uid, utils.isotime())
diff --git a/nova/auth/nova_openldap.schema b/nova/auth/nova_openldap.schema
index 4047361de..539a5c42d 100644
--- a/nova/auth/nova_openldap.schema
+++ b/nova/auth/nova_openldap.schema
@@ -1,7 +1,9 @@
#
# Person object for Nova
# inetorgperson with extra attributes
-# Author: Vishvananda Ishaya <vishvananda@yahoo.com>
+# Schema version: 2
+# Authors: Vishvananda Ishaya <vishvananda@gmail.com>
+# Ryan Lane <rlane@wikimedia.org>
#
#
@@ -31,54 +33,18 @@ attributetype (
)
attributetype (
- novaAttrs:3
- NAME 'keyFingerprint'
- DESC 'Fingerprint of private key'
- EQUALITY caseIgnoreMatch
- SUBSTR caseIgnoreSubstringsMatch
- SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
- SINGLE-VALUE
- )
-
-attributetype (
novaAttrs:4
- NAME 'isAdmin'
- DESC 'Is user an administrator?'
+ NAME 'isNovaAdmin'
+ DESC 'Is user an nova administrator?'
EQUALITY booleanMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
SINGLE-VALUE
)
-attributetype (
- novaAttrs:5
- NAME 'projectManager'
- DESC 'Project Managers of a project'
- SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
- )
-
objectClass (
novaOCs:1
NAME 'novaUser'
DESC 'access and secret keys'
AUXILIARY
- MUST ( uid )
- MAY ( accessKey $ secretKey $ isAdmin )
- )
-
-objectClass (
- novaOCs:2
- NAME 'novaKeyPair'
- DESC 'Key pair for User'
- SUP top
- STRUCTURAL
- MUST ( cn $ sshPublicKey $ keyFingerprint )
- )
-
-objectClass (
- novaOCs:3
- NAME 'novaProject'
- DESC 'Container for project'
- SUP groupOfNames
- STRUCTURAL
- MUST ( cn $ projectManager )
+ MAY ( accessKey $ secretKey $ isNovaAdmin )
)
diff --git a/nova/auth/nova_sun.schema b/nova/auth/nova_sun.schema
index e925e05e4..4a6a78839 100644
--- a/nova/auth/nova_sun.schema
+++ b/nova/auth/nova_sun.schema
@@ -1,16 +1,13 @@
#
# Person object for Nova
# inetorgperson with extra attributes
-# Author: Vishvananda Ishaya <vishvananda@yahoo.com>
-# Modified for strict RFC 4512 compatibility by: Ryan Lane <ryan@ryandlane.com>
+# Schema version: 2
+# Authors: Vishvananda Ishaya <vishvananda@gmail.com>
+# Ryan Lane <rlane@wikimedia.org>
#
# using internet experimental oid arc as per BP64 3.1
dn: cn=schema
attributeTypes: ( 1.3.6.1.3.1.666.666.3.1 NAME 'accessKey' DESC 'Key for accessing data' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
attributeTypes: ( 1.3.6.1.3.1.666.666.3.2 NAME 'secretKey' DESC 'Secret key' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
-attributeTypes: ( 1.3.6.1.3.1.666.666.3.3 NAME 'keyFingerprint' DESC 'Fingerprint of private key' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE)
-attributeTypes: ( 1.3.6.1.3.1.666.666.3.4 NAME 'isAdmin' DESC 'Is user an administrator?' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
-attributeTypes: ( 1.3.6.1.3.1.666.666.3.5 NAME 'projectManager' DESC 'Project Managers of a project' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )
-objectClasses: ( 1.3.6.1.3.1.666.666.4.1 NAME 'novaUser' DESC 'access and secret keys' SUP top AUXILIARY MUST ( uid ) MAY ( accessKey $ secretKey $ isAdmin ) )
-objectClasses: ( 1.3.6.1.3.1.666.666.4.2 NAME 'novaKeyPair' DESC 'Key pair for User' SUP top STRUCTURAL MUST ( cn $ sshPublicKey $ keyFingerprint ) )
-objectClasses: ( 1.3.6.1.3.1.666.666.4.3 NAME 'novaProject' DESC 'Container for project' SUP groupOfNames STRUCTURAL MUST ( cn $ projectManager ) )
+attributeTypes: ( 1.3.6.1.3.1.666.666.3.4 NAME 'isNovaAdmin' DESC 'Is user a nova administrator?' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
+objectClasses: ( 1.3.6.1.3.1.666.666.4.1 NAME 'novaUser' DESC 'access and secret keys' SUP top AUXILIARY MAY ( accessKey $ secretKey $ isNovaAdmin ) )
diff --git a/nova/auth/opendj.sh b/nova/auth/opendj.sh
index 8052c077d..1a280e5a8 100755
--- a/nova/auth/opendj.sh
+++ b/nova/auth/opendj.sh
@@ -32,7 +32,6 @@ abspath=`dirname "$(cd "${0%/*}" 2>/dev/null; echo "$PWD"/"${0##*/}")"`
schemapath='/var/opendj/instance/config/schema'
cp $abspath/openssh-lpk_sun.schema $schemapath/97-openssh-lpk_sun.ldif
cp $abspath/nova_sun.schema $schemapath/98-nova_sun.ldif
-chown opendj:opendj $schemapath/97-openssh-lpk_sun.ldif
chown opendj:opendj $schemapath/98-nova_sun.ldif
cat >/etc/ldap/ldap.conf <<LDAP_CONF_EOF
diff --git a/nova/auth/slap.sh b/nova/auth/slap.sh
index 797675d2e..95c61dafd 100755
--- a/nova/auth/slap.sh
+++ b/nova/auth/slap.sh
@@ -22,7 +22,7 @@ apt-get install -y slapd ldap-utils python-ldap
abspath=`dirname "$(cd "${0%/*}" 2>/dev/null; echo "$PWD"/"${0##*/}")"`
cp $abspath/openssh-lpk_openldap.schema /etc/ldap/schema/openssh-lpk_openldap.schema
-cp $abspath/nova_openldap.schema /etc/ldap/schema/nova_openldap.schema
+cp $abspath/nova_openldap.schema /etc/ldap/schema/nova.schema
mv /etc/ldap/slapd.conf /etc/ldap/slapd.conf.orig
cat >/etc/ldap/slapd.conf <<SLAPD_CONF_EOF
@@ -33,7 +33,6 @@ cat >/etc/ldap/slapd.conf <<SLAPD_CONF_EOF
include /etc/ldap/schema/core.schema
include /etc/ldap/schema/cosine.schema
include /etc/ldap/schema/inetorgperson.schema
-include /etc/ldap/schema/openssh-lpk_openldap.schema
include /etc/ldap/schema/nova.schema
pidfile /var/run/slapd/slapd.pid
argsfile /var/run/slapd/slapd.args