Massive refactor of users.py

Split users.py into manager.py and ldpadriver.py
Added tons of docstrings
Cleaned up public methods
Simplified manager singleton handling
This commit is contained in:
Vishvananda Ishaya 2010-07-19 13:19:26 -05:00
parent b09e69c557
commit a3ca587654
22 changed files with 1231 additions and 1036 deletions

View File

@ -29,7 +29,7 @@ from nova import flags
from nova import rpc
from nova import server
from nova import utils
from nova.auth import users
from nova.auth import manager
from nova.compute import model
from nova.endpoint import admin
from nova.endpoint import api

View File

@ -27,7 +27,7 @@ import time
from nova import flags
from nova import utils
from nova.auth import users
from nova.auth import manager
from nova.compute import model
from nova.compute import network
from nova.cloudpipe import pipelib
@ -42,7 +42,7 @@ class NetworkCommands(object):
class VpnCommands(object):
def __init__(self):
self.manager = users.UserManager.instance()
self.manager = manager.AuthManager()
self.instdir = model.InstanceDirectory()
self.pipe = pipelib.CloudPipe(cloud.CloudController())
@ -90,7 +90,7 @@ class VpnCommands(object):
class RoleCommands(object):
def __init__(self):
self.manager = users.UserManager.instance()
self.manager = manager.AuthManager()
def add(self, user, role, project=None):
"""adds role to user
@ -113,7 +113,7 @@ class RoleCommands(object):
class UserCommands(object):
def __init__(self):
self.manager = users.UserManager.instance()
self.manager = manager.AuthManager()
def __print_export(self, user):
print 'export EC2_ACCESS_KEY=%s' % user.access
@ -153,7 +153,7 @@ class UserCommands(object):
class ProjectCommands(object):
def __init__(self):
self.manager = users.UserManager.instance()
self.manager = manager.AuthManager()
def add(self, project, user):
"""adds user to project

View File

@ -18,7 +18,7 @@
# under the License.
"""
Tornado daemon for nova objectstore. Supports S3 API.
Tornado daemon for nova objectstore. Supports S3 API.
"""
import logging
@ -28,7 +28,7 @@ from tornado import ioloop
from nova import flags
from nova import server
from nova import utils
from nova.auth import users
from nova.auth import manager
from nova.objectstore import handler
@ -39,7 +39,7 @@ def main(argv):
# FIXME: if this log statement isn't here, no logging
# appears from other files and app won't start daemonized
logging.debug('Started HTTP server on %s' % (FLAGS.s3_internal_port))
app = handler.Application(users.UserManager())
app = handler.Application(manager.AuthManager())
server = httpserver.HTTPServer(app)
server.listen(FLAGS.s3_internal_port)
ioloop.IOLoop.instance().start()

View File

@ -4,20 +4,20 @@
# 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.
"""
WSGI daemon for the main API endpoint.
WSGI daemon for the main API endpoint.
"""
import logging
@ -28,14 +28,14 @@ from nova import flags
from nova import rpc
from nova import server
from nova import utils
from nova.auth import users
from nova.auth import manager
from nova.endpoint import rackspace
FLAGS = flags.FLAGS
flags.DEFINE_integer('cc_port', 8773, 'cloud controller port')
def main(_argv):
user_manager = users.UserManager()
user_manager = manager.AuthManager()
api_instance = rackspace.Api(user_manager)
conn = rpc.Connection.instance()
rpc_consumer = rpc.AdapterConsumer(connection=conn,

428
nova/auth/ldapdriver.py Normal file
View File

@ -0,0 +1,428 @@
# 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.
"""
Auth driver for ldap
It should be easy to create a replacement for this driver supporting
other backends by creating another class that exposes the same
public methods.
"""
import logging
from nova import exception
from nova import flags
from nova.auth import manager
try:
import ldap
except Exception, e:
from nova.auth import fakeldap as ldap
# NOTE(vish): this import is so we can use fakeldap even when real ldap
# is installed.
from nova.auth import fakeldap
FLAGS = flags.FLAGS
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_unit', 'Users', 'OID for Users')
flags.DEFINE_string('ldap_user_subtree', 'ou=Users,dc=example,dc=com',
'OU for Users')
flags.DEFINE_string('ldap_project_subtree', 'ou=Groups,dc=example,dc=com',
'OU for Projects')
flags.DEFINE_string('role_project_subtree', 'ou=Groups,dc=example,dc=com',
'OU for Roles')
# NOTE(vish): mapping with these flags is necessary because we're going
# to tie in to an existing ldap schema
flags.DEFINE_string('ldap_cloudadmin',
'cn=cloudadmins,ou=Groups,dc=example,dc=com', 'cn for Cloud Admins')
flags.DEFINE_string('ldap_itsec',
'cn=itsec,ou=Groups,dc=example,dc=com', 'cn for ItSec')
flags.DEFINE_string('ldap_sysadmin',
'cn=sysadmins,ou=Groups,dc=example,dc=com', 'cn for Sysadmins')
flags.DEFINE_string('ldap_netadmin',
'cn=netadmins,ou=Groups,dc=example,dc=com', 'cn for NetAdmins')
flags.DEFINE_string('ldap_developer',
'cn=developers,ou=Groups,dc=example,dc=com', 'cn for Developers')
class LdapDriver(object):
def __enter__(self):
"""Creates the connection to LDAP"""
if FLAGS.fake_users:
self.NO_SUCH_OBJECT = fakeldap.NO_SUCH_OBJECT
self.OBJECT_CLASS_VIOLATION = fakeldap.OBJECT_CLASS_VIOLATION
self.conn = fakeldap.initialize(FLAGS.ldap_url)
else:
self.NO_SUCH_OBJECT = ldap.NO_SUCH_OBJECT
self.OBJECT_CLASS_VIOLATION = ldap.OBJECT_CLASS_VIOLATION
self.conn = ldap.initialize(FLAGS.ldap_url)
self.conn.simple_bind_s(FLAGS.ldap_user_dn, FLAGS.ldap_password)
return self
def __exit__(self, type, value, traceback):
"""Destroys the connection to LDAP"""
self.conn.unbind_s()
return False
def get_user(self, uid):
attr = self.__find_object(self.__uid_to_dn(uid),
'(objectclass=novaUser)')
return self.__to_user(attr)
def get_user_from_access_key(self, access):
query = '(accessKey=%s)' % access
dn = FLAGS.ldap_user_subtree
return self.__to_user(self.__find_object(dn, query))
def get_key_pair(self, uid, key_name):
dn = 'cn=%s,%s' % (key_name,
self.__uid_to_dn(uid))
attr = self.__find_object(dn, '(objectclass=novaKeyPair)')
return self.__to_key_pair(uid, attr)
def get_project(self, name):
dn = 'cn=%s,%s' % (name,
FLAGS.ldap_project_subtree)
attr = self.__find_object(dn, '(objectclass=novaProject)')
return self.__to_project(attr)
def get_users(self):
attrs = self.__find_objects(FLAGS.ldap_user_subtree,
'(objectclass=novaUser)')
return [self.__to_user(attr) for attr in attrs]
def get_key_pairs(self, uid):
attrs = self.__find_objects(self.__uid_to_dn(uid),
'(objectclass=novaKeyPair)')
return [self.__to_key_pair(uid, attr) for attr in attrs]
def get_projects(self):
attrs = self.__find_objects(FLAGS.ldap_project_subtree,
'(objectclass=novaProject)')
return [self.__to_project(attr) for attr in attrs]
def create_user(self, name, access_key, secret_key, is_admin):
if self.__user_exists(name):
raise exception.Duplicate("LDAP user %s already exists" % name)
attr = [
('objectclass', ['person',
'organizationalPerson',
'inetOrgPerson',
'novaUser']),
('ou', [FLAGS.ldap_user_unit]),
('uid', [name]),
('sn', [name]),
('cn', [name]),
('secretKey', [secret_key]),
('accessKey', [access_key]),
('isAdmin', [str(is_admin).upper()]),
]
self.conn.add_s(self.__uid_to_dn(name), attr)
return self.__to_user(dict(attr))
def create_key_pair(self, uid, key_name, public_key, fingerprint):
"""create's a public key in the directory underneath the user"""
# TODO(vish): possibly refactor this to store keys in their own ou
# and put dn reference in the user object
attr = [
('objectclass', ['novaKeyPair']),
('cn', [key_name]),
('sshPublicKey', [public_key]),
('keyFingerprint', [fingerprint]),
]
self.conn.add_s('cn=%s,%s' % (key_name,
self.__uid_to_dn(uid)),
attr)
return self.__to_key_pair(uid, dict(attr))
def create_project(self, name, manager_uid,
description=None, member_uids=None):
if self.__project_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)
manager_dn = self.__uid_to_dn(manager_uid)
# description is a required attribute
if description is None:
description = name
members = []
if member_uids != 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" % 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']),
('cn', [name]),
('description', [description]),
('projectManager', [manager_dn]),
('member', members)
]
self.conn.add_s('cn=%s,%s' % (name, FLAGS.ldap_project_subtree), attr)
return self.__to_project(dict(attr))
def add_to_project(self, uid, project_id):
dn = 'cn=%s,%s' % (project_id, FLAGS.ldap_project_subtree)
return self.__add_to_group(uid, dn)
def remove_from_project(self, uid, project_id):
dn = 'cn=%s,%s' % (project_id, FLAGS.ldap_project_subtree)
return self.__remove_from_group(uid, dn)
def is_in_project(self, uid, project_id):
dn = 'cn=%s,%s' % (project_id, FLAGS.ldap_project_subtree)
return self.__is_in_group(uid, dn)
def has_role(self, uid, role, project_id=None):
role_dn = self.__role_to_dn(role, project_id)
return self.__is_in_group(uid, role_dn)
def add_role(self, uid, role, project_id=None):
role_dn = self.__role_to_dn(role, project_id)
if not self.__group_exists(role_dn):
# create the role if it doesn't exist
description = '%s role for %s' % (role, project_id)
self.__create_group(role_dn, role, uid, description)
else:
return self.__add_to_group(uid, role_dn)
def remove_role(self, uid, role, project_id=None):
role_dn = self.__role_to_dn(role, project_id)
return self.__remove_from_group(uid, role_dn)
def delete_user(self, uid):
if not self.__user_exists(uid):
raise exception.NotFound("User %s doesn't exist" % uid)
self.__delete_key_pairs(uid)
self.__remove_from_all(uid)
self.conn.delete_s('uid=%s,%s' % (uid,
FLAGS.ldap_user_subtree))
def delete_key_pair(self, uid, key_name):
if not self.__key_pair_exists(uid, key_name):
raise exception.NotFound("Key Pair %s doesn't exist for user %s" %
(key_name, uid))
self.conn.delete_s('cn=%s,uid=%s,%s' % (key_name, uid,
FLAGS.ldap_user_subtree))
def delete_project(self, name):
project_dn = 'cn=%s,%s' % (name, FLAGS.ldap_project_subtree)
self.__delete_roles(project_dn)
self.__delete_group(project_dn)
def __user_exists(self, name):
return self.get_user(name) != None
def __key_pair_exists(self, uid, key_name):
return self.get_key_pair(uid, key_name) != None
def __project_exists(self, name):
return self.get_project(name) != None
def __find_object(self, dn, query = None):
objects = self.__find_objects(dn, query)
if len(objects) == 0:
return None
return objects[0]
def __find_dns(self, dn, query=None):
try:
res = self.conn.search_s(dn, ldap.SCOPE_SUBTREE, query)
except self.NO_SUCH_OBJECT:
return []
# just return the DNs
return [dn for dn, attributes in res]
def __find_objects(self, dn, query = None):
try:
res = self.conn.search_s(dn, ldap.SCOPE_SUBTREE, query)
except self.NO_SUCH_OBJECT:
return []
# just return the attributes
return [attributes for dn, attributes in res]
def __find_role_dns(self, tree):
return self.__find_dns(tree,
'(&(objectclass=groupOfNames)(!(objectclass=novaProject)))')
def __find_group_dns_with_member(self, tree, uid):
dns = self.__find_dns(tree,
'(&(objectclass=groupOfNames)(member=%s))' %
self.__uid_to_dn(uid))
return dns
def __group_exists(self, dn):
return self.__find_object(dn, '(objectclass=groupOfNames)') != None
def __delete_key_pairs(self, uid):
keys = self.get_key_pairs(uid)
if keys != None:
for key in keys:
self.delete_key_pair(uid, key.name)
def __role_to_dn(self, role, project_id=None):
if project_id == None:
return FLAGS.__getitem__("ldap_%s" % role).value
else:
return 'cn=%s,cn=%s,%s' % (role,
project_id,
FLAGS.ldap_project_subtree)
def __create_group(self, group_dn, name, uid,
description, member_uids = None):
if self.__group_exists(group_dn):
raise exception.Duplicate("Group can't be created because "
"group %s already exists" % name)
members = []
if member_uids != None:
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)
members.append(self.__uid_to_dn(member_uid))
dn = self.__uid_to_dn(uid)
if not dn in members:
members.append(dn)
attr = [
('objectclass', ['groupOfNames']),
('cn', [name]),
('description', [description]),
('member', members)
]
self.conn.add_s(group_dn, attr)
def __is_in_group(self, uid, group_dn):
if not self.__user_exists(uid):
raise exception.NotFound("User %s can't be searched in group "
"becuase the user doesn't exist" % (uid,))
if not self.__group_exists(group_dn):
return False
res = self.__find_object(group_dn,
'(member=%s)' % self.__uid_to_dn(uid))
return res != None
def __add_to_group(self, uid, group_dn):
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,))
if not self.__group_exists(group_dn):
raise exception.NotFound("The group at dn %s doesn't exist" %
(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))
attr = [
(ldap.MOD_ADD, 'member', self.__uid_to_dn(uid))
]
self.conn.modify_s(group_dn, attr)
def __remove_from_group(self, uid, group_dn):
if not self.__group_exists(group_dn):
raise exception.NotFound("The group at dn %s doesn't exist" %
(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,))
if not self.__is_in_group(uid, group_dn):
raise exception.NotFound("User %s is not a member of the group" %
(uid,))
self.__safe_remove_from_group(group_dn, uid)
def __safe_remove_from_group(self, group_dn, uid):
# FIXME(vish): what if deleted user is a project manager?
attr = [(ldap.MOD_DELETE, 'member', self.__uid_to_dn(uid))]
try:
self.conn.modify_s(group_dn, attr)
except self.OBJECT_CLASS_VIOLATION:
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):
if not self.__user_exists(uid):
raise exception.NotFound("User %s can't be removed from all "
"because the user doesn't exist" % (uid,))
dn = self.__uid_to_dn(uid)
role_dns = self.__find_group_dns_with_member(
FLAGS.role_project_subtree, uid)
for role_dn in role_dns:
self.__safe_remove_from_group(role_dn, uid)
project_dns = self.__find_group_dns_with_member(
FLAGS.ldap_project_subtree, uid)
for project_dn in project_dns:
self.__safe_remove_from_group(project_dn, uid)
def __delete_group(self, group_dn):
if not self.__group_exists(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):
for role_dn in self.__find_role_dns(project_dn):
self.__delete_group(role_dn)
def __to_user(self, attr):
if attr == None:
return None
return manager.User(
id = attr['uid'][0],
name = attr['cn'][0],
access = attr['accessKey'][0],
secret = attr['secretKey'][0],
admin = (attr['isAdmin'][0] == 'TRUE')
)
def __to_key_pair(self, owner, attr):
if attr == None:
return None
return manager.KeyPair(
id = attr['cn'][0],
owner_id = owner,
public_key = attr['sshPublicKey'][0],
fingerprint = attr['keyFingerprint'][0],
)
def __to_project(self, attr):
if attr == None:
return None
member_dns = attr.get('member', [])
return manager.Project(
id = attr['cn'][0],
project_manager_id = self.__dn_to_uid(attr['projectManager'][0]),
description = attr.get('description', [None])[0],
member_ids = [self.__dn_to_uid(x) for x in member_dns]
)
def __dn_to_uid(self, dn):
return dn.split(',')[0].split('=')[1]
def __uid_to_dn(self, dn):
return 'uid=%s,%s' % (dn, FLAGS.ldap_user_subtree)

741
nova/auth/manager.py Normal file
View File

@ -0,0 +1,741 @@
# 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.
"""
Nova authentication management
"""
import logging
import os
import shutil
import string
import tempfile
import uuid
import zipfile
from nova import crypto
from nova import datastore
from nova import exception
from nova import flags
from nova import objectstore # for flags
from nova import signer
from nova import utils
from nova.auth import ldapdriver
FLAGS = flags.FLAGS
# NOTE(vish): a user with one of these roles will be a superuser and
# have access to all api commands
flags.DEFINE_list('superuser_roles', ['cloudadmin'],
'roles that ignore rbac checking completely')
# NOTE(vish): a user with one of these roles will have it for every
# project, even if he or she is not a member of the project
flags.DEFINE_list('global_roles', ['cloudadmin', 'itsec'],
'roles that apply to all projects')
flags.DEFINE_string('credentials_template',
utils.abspath('auth/novarc.template'),
'Template for creating users rc file')
flags.DEFINE_string('vpn_client_template',
utils.abspath('cloudpipe/client.ovpn.template'),
'Template for creating users vpn file')
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_integer('vpn_start_port', 1000,
'Start port for the cloudpipe VPN servers')
flags.DEFINE_integer('vpn_end_port', 2000,
'End port for the cloudpipe VPN servers')
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('vpn_ip', '127.0.0.1',
'Public IP for the cloudpipe VPN servers')
class AuthBase(object):
"""Base class for objects relating to auth
Objects derived from this class should be stupid data objects with
an id member. They may optionally contain methods that delegate to
AuthManager, but should not implement logic themselves.
"""
@classmethod
def safe_id(cls, obj):
"""Safe get object id
This method will return the id of the object if the object
is of this class, otherwise it will return the original object.
This allows methods to accept objects or ids as paramaters.
"""
if isinstance(obj, cls):
return obj.id
else:
return obj
class User(AuthBase):
"""Object representing a user"""
def __init__(self, id, name, access, secret, admin):
self.id = id
self.name = name
self.access = access
self.secret = secret
self.admin = admin
def is_superuser(self):
return AuthManager().is_superuser(self)
def is_admin(self):
return AuthManager().is_admin(self)
def has_role(self, role):
return AuthManager().has_role(self, role)
def add_role(self, role):
return AuthManager().add_role(self, role)
def remove_role(self, role):
return AuthManager().remove_role(self, role)
def is_project_member(self, project):
return AuthManager().is_project_member(self, project)
def is_project_manager(self, project):
return AuthManager().is_project_manager(self, project)
def generate_key_pair(self, name):
return AuthManager().generate_key_pair(self.id, name)
def create_key_pair(self, name, public_key, fingerprint):
return AuthManager().create_key_pair(self.id,
name,
public_key,
fingerprint)
def get_key_pair(self, name):
return AuthManager().get_key_pair(self.id, name)
def delete_key_pair(self, name):
return AuthManager().delete_key_pair(self.id, name)
def get_key_pairs(self):
return AuthManager().get_key_pairs(self.id)
def __repr__(self):
return "User('%s', '%s', '%s', '%s', %s)" % (self.id,
self.name,
self.access,
self.secret,
self.admin)
class KeyPair(AuthBase):
"""Represents an ssh key returned from the datastore
Even though this object is named KeyPair, only the public key and
fingerprint is stored. The user's private key is not saved.
"""
def __init__(self, id, owner_id, public_key, fingerprint):
self.id = id
self.name = id
self.owner_id = owner_id
self.public_key = public_key
self.fingerprint = fingerprint
def __repr__(self):
return "KeyPair('%s', '%s', '%s', '%s')" % (self.id,
self.owner_id,
self.public_key,
self.fingerprint)
class Project(AuthBase):
"""Represents a Project returned from the datastore"""
def __init__(self, id, project_manager_id, description, member_ids):
self.project_manager_id = project_manager_id
self.id = id
self.name = id
self.description = description
self.member_ids = member_ids
@property
def project_manager(self):
return AuthManager().get_user(self.project_manager_id)
def has_manager(self, user):
return AuthManager().is_project_manager(user, self)
def has_member(self, user):
return AuthManager().is_project_member(user, self)
def add_role(self, user, role):
return AuthManager().add_role(user, role, self)
def remove_role(self, user, role):
return AuthManager().remove_role(user, role, self)
def has_role(self, user, role):
return AuthManager().has_role(user, role, self)
def get_credentials(self, user):
return AuthManager().get_credentials(user, self)
def __repr__(self):
return "Project('%s', '%s', '%s', %s)" % (self.id,
self.project_manager_id,
self.description,
self.member_ids)
class NoMorePorts(exception.Error):
pass
class Vpn(datastore.BasicModel):
"""Manages vpn ips and ports for projects"""
def __init__(self, project_id):
self.project_id = project_id
super(Vpn, self).__init__()
@property
def identifier(self):
return self.project_id
@classmethod
def create(cls, project_id):
# TODO(vish): get list of vpn ips from redis
port = cls.find_free_port_for_ip(FLAGS.vpn_ip)
vpn = cls(project_id)
# save ip for project
vpn['project'] = project_id
vpn['ip'] = FLAGS.vpn_ip
vpn['port'] = port
vpn.save()
return vpn
@classmethod
def find_free_port_for_ip(cls, ip):
# TODO(vish): these redis commands should be generalized and
# placed into a base class. Conceptually, it is
# similar to an association, but we are just
# storing a set of values instead of keys that
# should be turned into objects.
redis = datastore.Redis.instance()
key = 'ip:%s:ports' % ip
# TODO(vish): these ports should be allocated through an admin
# command instead of a flag
if (not redis.exists(key) and
not redis.exists(cls._redis_association_name('ip', ip))):
for i in range(FLAGS.vpn_start_port, FLAGS.vpn_end_port + 1):
redis.sadd(key, i)
port = redis.spop(key)
if not port:
raise NoMorePorts()
return port
@classmethod
def num_ports_for_ip(cls, ip):
return datastore.Redis.instance().scard('ip:%s:ports' % ip)
@property
def ip(self):
return self['ip']
@property
def port(self):
return int(self['port'])
def save(self):
self.associate_with('ip', self.ip)
super(Vpn, self).save()
def destroy(self):
self.unassociate_with('ip', self.ip)
datastore.Redis.instance().sadd('ip:%s:ports' % self.ip, self.port)
super(Vpn, self).destroy()
class AuthManager(object):
"""Manager Singleton for dealing with Users, Projects, and Keypairs
Methods accept objects or ids.
AuthManager uses a driver object to make requests to the data backend.
See ldapdriver.LdapDriver for reference.
AuthManager also manages associated data related to Auth objects that
need to be more accessible, such as vpn ips and ports.
"""
_instance=None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super(AuthManager, cls).__new__(
cls, *args, **kwargs)
return cls._instance
def __init__(self, *args, **kwargs):
self.driver_class = kwargs.get('driver_class', ldapdriver.LdapDriver)
if FLAGS.fake_tests:
try:
self.create_user('fake', 'fake', 'fake')
except: pass
try:
self.create_user('user', 'user', 'user')
except: pass
try:
self.create_user('admin', 'admin', 'admin', True)
except: pass
def authenticate(self, access, signature, params, verb='GET',
server_string='127.0.0.1:8773', path='/',
verify_signature=True):
"""Authenticates AWS request using access key and signature
If the project is not specified, attempts to authenticate to
a project with the same name as the user. This way, older tools
that have no project knowledge will still work.
@type access: str
@param access: Access key for user in the form "access:project".
@type signature: str
@param signature: Signature of the request.
@type params: list of str
@param params: Web paramaters used for the signature.
@type verb: str
@param verb: Web request verb ('GET' or 'POST').
@type server_string: str
@param server_string: Web request server string.
@type path: str
@param path: Web request path.
@type verify_signature: bool
@param verify_signature: Whether to verify the signature.
@rtype: tuple (User, Project)
@return: User and project that the request represents.
"""
# TODO(vish): check for valid timestamp
(access_key, sep, project_name) = access.partition(':')
user = self.get_user_from_access_key(access_key)
if user == None:
raise exception.NotFound('No user found for access key %s' %
access_key)
if project_name is '':
project_name = user.name
project = self.get_project(project_name)
if project == None:
raise exception.NotFound('No project called %s could be found' %
project_name)
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))
if verify_signature:
# NOTE(vish): hmac can't handle unicode, so encode ensures that
# secret isn't unicode
expected_signature = signer.Signer(user.secret.encode()).generate(
params, verb, server_string, path)
logging.debug('user.secret: %s', user.secret)
logging.debug('expected_signature: %s', expected_signature)
logging.debug('signature: %s', signature)
if signature != expected_signature:
raise exception.NotAuthorized('Signature does not match')
return (user, project)
def is_superuser(self, user):
"""Checks for superuser status, allowing user to bypass rbac
@type user: User or uid
@param user: User to check.
@rtype: bool
@return: True for superuser.
"""
if not isinstance(user, User):
user = self.get_user(user)
# NOTE(vish): admin flag on user represents superuser
if user.admin:
return True
for role in FLAGS.superuser_roles:
if self.has_role(user, role):
return True
def is_admin(self, user):
"""Checks for admin status, allowing user to access all projects
@type user: User or uid
@param user: User to check.
@rtype: bool
@return: True for admin.
"""
if not isinstance(user, User):
user = self.get_user(user)
if self.is_superuser(user):
return True
for role in FLAGS.global_roles:
if self.has_role(user, role):
return True
def has_role(self, user, role, project=None):
"""Checks existence of role for user
If project is not specified, checks for a global role. If project
is specified, checks for the union of the global role and the
project role.
Role 'projectmanager' only works for projects and simply checks to
see if the user is the project_manager of the specified project. It
is the same as calling is_project_manager(user, project).
@type user: User or uid
@param user: User to check.
@type role: str
@param role: Role to check.
@type project: Project or project_id
@param project: Project in which to look for local role.
@rtype: bool
@return: True if the user has the role.
"""
with self.driver_class() as drv:
if role == 'projectmanager':
if not project:
raise exception.Error("Must specify project")
return self.is_project_manager(user, project)
global_role = drv.has_role(User.safe_id(user),
role,
None)
if not global_role:
return global_role
if not project or role in FLAGS.global_roles:
return global_role
return drv.has_role(User.safe_id(user),
role,
Project.safe_id(project))
def add_role(self, user, role, project=None):
"""Adds role for user
If project is not specified, adds a global role. If project
is specified, adds a local role.
The 'projectmanager' role is special and can't be added or removed.
@type user: User or uid
@param user: User to which to add role.
@type role: str
@param role: Role to add.
@type project: Project or project_id
@param project: Project in which to add local role.
"""
with self.driver_class() as drv:
drv.add_role(User.safe_id(user), role, Project.safe_id(project))
def remove_role(self, user, role, project=None):
"""Removes role for user
If project is not specified, removes a global role. If project
is specified, removes a local role.
The 'projectmanager' role is special and can't be added or removed.
@type user: User or uid
@param user: User from which to remove role.
@type role: str
@param role: Role to remove.
@type project: Project or project_id
@param project: Project in which to remove local role.
"""
with self.driver_class() as drv:
drv.remove_role(User.safe_id(user), role, Project.safe_id(project))
def create_project(self, name, manager_user,
description=None, member_users=None):
"""Create a project
@type name: str
@param name: Name of the project to create. The name will also be
used as the project id.
@type manager_user: User or uid
@param manager_user: This user will be the project manager.
@type description: str
@param project: Description of the project. If no description is
specified, the name of the project will be used.
@type member_users: list of User or uid
@param: Initial project members. The project manager will always be
added as a member, even if he isn't specified in this list.
@rtype: Project
@return: The new project.
"""
if member_users:
member_users = [User.safe_id(u) for u in member_users]
# NOTE(vish): try to associate a vpn ip and port first because
# if it throws an exception, we save having to
# create and destroy a project
Vpn.create(name)
with self.driver_class() as drv:
return drv.create_project(name,
User.safe_id(manager_user),
description,
member_users)
def get_projects(self):
"""Retrieves list of all projects"""
with self.driver_class() as drv:
return drv.get_projects()
def get_project(self, project):
"""Get project object by id"""
with self.driver_class() as drv:
return drv.get_project(Project.safe_id(project))
def add_to_project(self, user, project):
"""Add user to project"""
with self.driver_class() as drv:
return drv.add_to_project(User.safe_id(user),
Project.safe_id(project))
def is_project_manager(self, user, project):
"""Checks if user is project manager"""
if not isinstance(project, Project):
project = self.get_project(project)
return User.safe_id(user) == project.project_manager_id
def is_project_member(self, user, project):
"""Checks to see if user is a member of project"""
if not isinstance(project, Project):
project = self.get_project(project)
return User.safe_id(user) in project.member_ids
def remove_from_project(self, user, project):
"""Removes a user from a project"""
with self.driver_class() as drv:
return drv.remove_from_project(User.safe_id(user),
Project.safe_id(project))
def delete_project(self, project):
"""Deletes a project"""
with self.driver_class() as drv:
return drv.delete_project(Project.safe_id(project))
def get_user(self, uid):
"""Retrieves a user by id"""
with self.driver_class() as drv:
return drv.get_user(uid)
def get_user_from_access_key(self, access_key):
"""Retrieves a user by access key"""
with self.driver_class() as drv:
return drv.get_user_from_access_key(access_key)
def get_users(self):
"""Retrieves a list of all users"""
with self.driver_class() as drv:
return drv.get_users()
def create_user(self, user, access=None, secret=None,
admin=False, create_project=True):
"""Creates a user
@type user: str
@param name: Name of the user to create. The name will also be
used as the user id.
@type access: str
@param access: Access Key (defaults to a random uuid)
@type secret: str
@param secret: Secret Key (defaults to a random uuid)
@type admin: bool
@param admin: Whether to set the admin flag. The admin flag gives
superuser status regardless of roles specifed for the user.
@type create_project: bool
@param: Whether to create a project for the user with the same name.
@rtype: User
@return: The new user.
"""
if access == None: access = str(uuid.uuid4())
if secret == None: secret = str(uuid.uuid4())
with self.driver_class() as drv:
user = User.safe_id(user)
result = drv.create_user(user, access, secret, admin)
if create_project:
# NOTE(vish): if the project creation fails, we delete
# the user and return an exception
try:
drv.create_project(user, user, user)
except Exception:
with self.driver_class() as drv:
drv.delete_user(user)
raise
return result
def delete_user(self, user, delete_project=True):
"""Deletes a user"""
with self.driver_class() as drv:
user = User.safe_id(user)
if delete_project:
try:
drv.delete_project(user)
except exception.NotFound:
pass
drv.delete_user(user)
def generate_key_pair(self, user, key_name):
"""Generates a key pair for a user
Generates a public and private key, stores the public key using the
key_name, and returns the private key and fingerprint.
@type user: User or uid
@param user: User for which to create key pair.
@type key_name: str
@param key_name: Name to use for the generated KeyPair.
@rtype: tuple (private_key, fingerprint)
@return: A tuple containing the private_key and fingerprint.
"""
# NOTE(vish): generating key pair is slow so check for legal
# creation before creating keypair
uid = User.safe_id(user)
with self.driver_class() as drv:
if not drv.get_user(uid):
raise exception.NotFound("User %s doesn't exist" % user)
if drv.get_key_pair(uid, key_name):
raise exception.Duplicate("The keypair %s already exists"
% key_name)
private_key, public_key, fingerprint = crypto.generate_key_pair()
self.create_key_pair(uid, key_name, public_key, fingerprint)
return private_key, fingerprint
def create_key_pair(self, user, key_name, public_key, fingerprint):
"""Creates a key pair for user"""
with self.driver_class() as drv:
return drv.create_key_pair(User.safe_id(user), key_name,
public_key, fingerprint)
def get_key_pair(self, user, key_name):
"""Retrieves a key pair for user"""
with self.driver_class() as drv:
return drv.get_key_pair(User.safe_id(user), key_name)
def get_key_pairs(self, user):
"""Retrieves all key pairs for user"""
with self.driver_class() as drv:
return drv.get_key_pairs(User.safe_id(user))
def delete_key_pair(self, user, key_name):
"""Deletes a key pair for user"""
with self.driver_class() as drv:
drv.delete_key_pair(User.safe_id(user), key_name)
def get_credentials(self, user, project=None):
"""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)
vpn = Vpn(pid)
configfile = open(FLAGS.vpn_client_template,"r")
s = string.Template(configfile.read())
configfile.close()
config = s.substitute(keyfile=FLAGS.credential_key_file,
certfile=FLAGS.credential_cert_file,
ip=vpn.ip,
port=vpn.port)
tmpdir = tempfile.mkdtemp()
zf = os.path.join(tmpdir, "temp.zip")
zippy = zipfile.ZipFile(zf, 'w')
zippy.writestr(FLAGS.credential_rc_file, rc)
zippy.writestr(FLAGS.credential_key_file, private_key)
zippy.writestr(FLAGS.credential_cert_file, signed_cert)
zippy.writestr("nebula-client.conf", config)
zippy.writestr(FLAGS.ca_file, crypto.fetch_ca(user.id))
zippy.close()
with open(zf, 'rb') as f:
buffer = f.read()
shutil.rmtree(tmpdir)
return buffer
def __generate_rc(self, access, secret, pid):
"""Generate rc file for user"""
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),
'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)
def __cert_subject(self, uid):
"""Helper to generate cert subject"""
return FLAGS.credential_cert_subject % (uid, utils.isotime())

View File

@ -17,7 +17,7 @@
# under the License.
from nova import exception
from nova.auth import users
from nova.auth import manager
def allow(*roles):

View File

@ -1,974 +0,0 @@
# 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.
"""
Nova users and user management, including RBAC hooks.
"""
import datetime
import logging
import os
import shutil
import signer
import string
import tempfile
import uuid
import zipfile
try:
import ldap
except Exception, e:
import fakeldap as ldap
import fakeldap
# TODO(termie): clean up these imports
from nova import datastore
from nova import exception
from nova import flags
from nova import crypto
from nova import utils
from nova import objectstore # for flags
FLAGS = flags.FLAGS
flags.DEFINE_string('ldap_url', 'ldap://localhost',
'Point this at your ldap server')
flags.DEFINE_string('ldap_password', 'changeme', 'LDAP password')
flags.DEFINE_string('user_dn', 'cn=Manager,dc=example,dc=com',
'DN of admin user')
flags.DEFINE_string('user_unit', 'Users', 'OID for Users')
flags.DEFINE_string('user_ldap_subtree', 'ou=Users,dc=example,dc=com',
'OU for Users')
flags.DEFINE_string('project_ldap_subtree', 'ou=Groups,dc=example,dc=com',
'OU for Projects')
flags.DEFINE_string('role_ldap_subtree', 'ou=Groups,dc=example,dc=com',
'OU for Roles')
# NOTE(vish): mapping with these flags is necessary because we're going
# to tie in to an existing ldap schema
flags.DEFINE_string('ldap_cloudadmin',
'cn=cloudadmins,ou=Groups,dc=example,dc=com', 'cn for Cloud Admins')
flags.DEFINE_string('ldap_itsec',
'cn=itsec,ou=Groups,dc=example,dc=com', 'cn for ItSec')
flags.DEFINE_string('ldap_sysadmin',
'cn=sysadmins,ou=Groups,dc=example,dc=com', 'cn for Sysadmins')
flags.DEFINE_string('ldap_netadmin',
'cn=netadmins,ou=Groups,dc=example,dc=com', 'cn for NetAdmins')
flags.DEFINE_string('ldap_developer',
'cn=developers,ou=Groups,dc=example,dc=com', 'cn for Developers')
# NOTE(vish): a user with one of these roles will be a superuser and
# have access to all api commands
flags.DEFINE_list('superuser_roles', ['cloudadmin'],
'roles that ignore rbac checking completely')
# NOTE(vish): a user with one of these roles will have it for every
# project, even if he or she is not a member of the project
flags.DEFINE_list('global_roles', ['cloudadmin', 'itsec'],
'roles that apply to all projects')
flags.DEFINE_string('credentials_template',
utils.abspath('auth/novarc.template'),
'Template for creating users rc file')
flags.DEFINE_string('vpn_client_template',
utils.abspath('cloudpipe/client.ovpn.template'),
'Template for creating users vpn file')
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_integer('vpn_start_port', 1000,
'Start port for the cloudpipe VPN servers')
flags.DEFINE_integer('vpn_end_port', 2000,
'End port for the cloudpipe VPN servers')
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('vpn_ip', '127.0.0.1',
'Public IP for the cloudpipe VPN servers')
class AuthBase(object):
@classmethod
def safe_id(cls, obj):
"""Safe get object id.
This method will return the id of the object if the object
is of this class, otherwise it will return the original object.
This allows methods to accept objects or ids as paramaters.
"""
if isinstance(obj, cls):
return obj.id
else:
return obj
class User(AuthBase):
"""id and name are currently the same"""
def __init__(self, id, name, access, secret, admin):
self.id = id
self.name = name
self.access = access
self.secret = secret
self.admin = admin
def is_superuser(self):
"""allows user to bypass rbac completely"""
if self.admin:
return True
for role in FLAGS.superuser_roles:
if self.has_role(role):
return True
def is_admin(self):
"""allows user to see objects from all projects"""
if self.is_superuser():
return True
for role in FLAGS.global_roles:
if self.has_role(role):
return True
def has_role(self, role):
return UserManager.instance().has_role(self, role)
def add_role(self, role):
return UserManager.instance().add_role(self, role)
def remove_role(self, role):
return UserManager.instance().remove_role(self, role)
def is_project_member(self, project):
return UserManager.instance().is_project_member(self, project)
def is_project_manager(self, project):
return UserManager.instance().is_project_manager(self, project)
def generate_rc(self, project=None):
if project is None:
project = self.id
rc = open(FLAGS.credentials_template).read()
rc = rc % { 'access': self.access,
'project': project,
'secret': self.secret,
'ec2': FLAGS.ec2_url,
's3': 'http://%s:%s' % (FLAGS.s3_host, FLAGS.s3_port),
'nova': FLAGS.ca_file,
'cert': FLAGS.credential_cert_file,
'key': FLAGS.credential_key_file,
}
return rc
def generate_key_pair(self, name):
return UserManager.instance().generate_key_pair(self.id, name)
def create_key_pair(self, name, public_key, fingerprint):
return UserManager.instance().create_key_pair(self.id,
name,
public_key,
fingerprint)
def get_key_pair(self, name):
return UserManager.instance().get_key_pair(self.id, name)
def delete_key_pair(self, name):
return UserManager.instance().delete_key_pair(self.id, name)
def get_key_pairs(self):
return UserManager.instance().get_key_pairs(self.id)
def __repr__(self):
return "User('%s', '%s', '%s', '%s', %s)" % (
self.id, self.name, self.access, self.secret, self.admin)
class KeyPair(AuthBase):
def __init__(self, id, owner_id, public_key, fingerprint):
self.id = id
self.name = id
self.owner_id = owner_id
self.public_key = public_key
self.fingerprint = fingerprint
def delete(self):
return UserManager.instance().delete_key_pair(self.owner, self.name)
def __repr__(self):
return "KeyPair('%s', '%s', '%s', '%s')" % (
self.id, self.owner_id, self.public_key, self.fingerprint)
class Group(AuthBase):
"""id and name are currently the same"""
def __init__(self, id, description = None, member_ids = None):
self.id = id
self.name = id
self.description = description
self.member_ids = member_ids
def has_member(self, user):
return User.safe_id(user) in self.member_ids
def __repr__(self):
return "Group('%s', '%s', %s)" % (
self.id, self.description, self.member_ids)
class Project(Group):
def __init__(self, id, project_manager_id, description, member_ids):
self.project_manager_id = project_manager_id
super(Project, self).__init__(id, description, member_ids)
@property
def project_manager(self):
return UserManager.instance().get_user(self.project_manager_id)
def has_manager(self, user):
return User.safe_id(user) == self.project_manager_id
def add_role(self, user, role):
return UserManager.instance().add_role(user, role, self)
def remove_role(self, user, role):
return UserManager.instance().remove_role(user, role, self)
def has_role(self, user, role):
return UserManager.instance().has_role(user, role, self)
@property
def vpn_ip(self):
return Vpn(self.id).ip
@property
def vpn_port(self):
return Vpn(self.id).port
def get_credentials(self, user):
if not isinstance(user, User):
user = UserManager.instance().get_user(user)
rc = user.generate_rc(self.id)
private_key, signed_cert = self.generate_x509_cert(user)
configfile = open(FLAGS.vpn_client_template,"r")
s = string.Template(configfile.read())
configfile.close()
config = s.substitute(keyfile=FLAGS.credential_key_file,
certfile=FLAGS.credential_cert_file,
ip=self.vpn_ip,
port=self.vpn_port)
tmpdir = tempfile.mkdtemp()
zf = os.path.join(tmpdir, "temp.zip")
zippy = zipfile.ZipFile(zf, 'w')
zippy.writestr(FLAGS.credential_rc_file, rc)
zippy.writestr(FLAGS.credential_key_file, private_key)
zippy.writestr(FLAGS.credential_cert_file, signed_cert)
zippy.writestr("nebula-client.conf", config)
zippy.writestr(FLAGS.ca_file, crypto.fetch_ca(self.id))
zippy.close()
with open(zf, 'rb') as f:
buffer = f.read()
shutil.rmtree(tmpdir)
return buffer
def generate_x509_cert(self, user):
return UserManager.instance().generate_x509_cert(user, self)
def __repr__(self):
return "Project('%s', '%s', '%s', %s)" % (
self.id, self.project_manager_id,
self.description, self.member_ids)
class NoMorePorts(exception.Error):
pass
class Vpn(datastore.BasicModel):
def __init__(self, project_id):
self.project_id = project_id
super(Vpn, self).__init__()
@property
def identifier(self):
return self.project_id
@classmethod
def create(cls, project_id):
# TODO(vish): get list of vpn ips from redis
port = cls.find_free_port_for_ip(FLAGS.vpn_ip)
vpn = cls(project_id)
# save ip for project
vpn['project'] = project_id
vpn['ip'] = FLAGS.vpn_ip
vpn['port'] = port
vpn.save()
return vpn
@classmethod
def find_free_port_for_ip(cls, ip):
# TODO(vish): these redis commands should be generalized and
# placed into a base class. Conceptually, it is
# similar to an association, but we are just
# storing a set of values instead of keys that
# should be turned into objects.
redis = datastore.Redis.instance()
key = 'ip:%s:ports' % ip
# TODO(vish): these ports should be allocated through an admin
# command instead of a flag
if (not redis.exists(key) and
not redis.exists(cls._redis_association_name('ip', ip))):
for i in range(FLAGS.vpn_start_port, FLAGS.vpn_end_port + 1):
redis.sadd(key, i)
port = redis.spop(key)
if not port:
raise NoMorePorts()
return port
@classmethod
def num_ports_for_ip(cls, ip):
return datastore.Redis.instance().scard('ip:%s:ports' % ip)
@property
def ip(self):
return self['ip']
@property
def port(self):
return int(self['port'])
def save(self):
self.associate_with('ip', self.ip)
super(Vpn, self).save()
def destroy(self):
self.unassociate_with('ip', self.ip)
datastore.Redis.instance().sadd('ip:%s:ports' % self.ip, self.port)
super(Vpn, self).destroy()
class UserManager(object):
def __init__(self):
if hasattr(self.__class__, '_instance'):
raise Exception('Attempted to instantiate singleton')
@classmethod
def instance(cls):
if not hasattr(cls, '_instance'):
inst = UserManager()
cls._instance = inst
if FLAGS.fake_users:
try:
inst.create_user('fake', 'fake', 'fake')
except: pass
try:
inst.create_user('user', 'user', 'user')
except: pass
try:
inst.create_user('admin', 'admin', 'admin', True)
except: pass
return cls._instance
def authenticate(self, access, signature, params, verb='GET',
server_string='127.0.0.1:8773', path='/',
verify_signature=True):
# TODO: Check for valid timestamp
(access_key, sep, project_name) = access.partition(':')
user = self.get_user_from_access_key(access_key)
if user == None:
raise exception.NotFound('No user found for access key %s' %
access_key)
if project_name is '':
project_name = user.name
project = self.get_project(project_name)
if project == None:
raise exception.NotFound('No project called %s could be found' %
project_name)
if not user.is_admin() and not project.has_member(user):
raise exception.NotFound('User %s is not a member of project %s' %
(user.id, project.id))
if verify_signature:
# NOTE(vish): hmac can't handle unicode, so encode ensures that
# secret isn't unicode
expected_signature = signer.Signer(user.secret.encode()).generate(
params, verb, server_string, path)
logging.debug('user.secret: %s', user.secret)
logging.debug('expected_signature: %s', expected_signature)
logging.debug('signature: %s', signature)
if signature != expected_signature:
raise exception.NotAuthorized('Signature does not match')
return (user, project)
def has_role(self, user, role, project=None):
with LDAPWrapper() as conn:
if role == 'projectmanager':
if not project:
raise exception.Error("Must specify project")
return self.is_project_manager(user, project)
global_role = conn.has_role(User.safe_id(user),
role,
None)
if not global_role:
return global_role
if not project or role in FLAGS.global_roles:
return global_role
return conn.has_role(User.safe_id(user),
role,
Project.safe_id(project))
def add_role(self, user, role, project=None):
with LDAPWrapper() as conn:
return conn.add_role(User.safe_id(user), role,
Project.safe_id(project))
def remove_role(self, user, role, project=None):
with LDAPWrapper() as conn:
return conn.remove_role(User.safe_id(user), role,
Project.safe_id(project))
def create_project(self, name, manager_user,
description=None, member_users=None):
if member_users:
member_users = [User.safe_id(u) for u in member_users]
# NOTE(vish): try to associate a vpn ip and port first because
# if it throws an exception, we save having to
# create and destroy a project
Vpn.create(name)
with LDAPWrapper() as conn:
return conn.create_project(name,
User.safe_id(manager_user),
description,
member_users)
def get_projects(self):
with LDAPWrapper() as conn:
return conn.find_projects()
def get_project(self, project):
with LDAPWrapper() as conn:
return conn.find_project(Project.safe_id(project))
def add_to_project(self, user, project):
with LDAPWrapper() as conn:
return conn.add_to_project(User.safe_id(user),
Project.safe_id(project))
def is_project_manager(self, user, project):
if not isinstance(project, Project):
project = self.get_project(project)
return project.has_manager(user)
def is_project_member(self, user, project):
if isinstance(project, Project):
return project.has_member(user)
else:
with LDAPWrapper() as conn:
return conn.is_in_project(User.safe_id(user), project)
def remove_from_project(self, user, project):
with LDAPWrapper() as conn:
return conn.remove_from_project(User.safe_id(user),
Project.safe_id(project))
def delete_project(self, project):
with LDAPWrapper() as conn:
return conn.delete_project(Project.safe_id(project))
def get_user(self, uid):
with LDAPWrapper() as conn:
return conn.find_user(uid)
def get_user_from_access_key(self, access_key):
with LDAPWrapper() as conn:
return conn.find_user_by_access_key(access_key)
def get_users(self):
with LDAPWrapper() as conn:
return conn.find_users()
def create_user(self, user, access=None, secret=None,
admin=False, create_project=True):
if access == None: access = str(uuid.uuid4())
if secret == None: secret = str(uuid.uuid4())
with LDAPWrapper() as conn:
user = User.safe_id(user)
result = conn.create_user(user, access, secret, admin)
if create_project:
# NOTE(vish): if the project creation fails, we delete
# the user and return an exception
try:
conn.create_project(user, user, user)
except Exception:
with LDAPWrapper() as conn:
conn.delete_user(user)
raise
return result
def delete_user(self, user, delete_project=True):
with LDAPWrapper() as conn:
user = User.safe_id(user)
if delete_project:
try:
conn.delete_project(user)
except exception.NotFound:
pass
conn.delete_user(user)
def generate_key_pair(self, user, key_name):
# generating key pair is slow so delay generation
# until after check
user = User.safe_id(user)
with LDAPWrapper() as conn:
if not conn.user_exists(user):
raise exception.NotFound("User %s doesn't exist" % user)
if conn.key_pair_exists(user, key_name):
raise exception.Duplicate("The keypair %s already exists"
% key_name)
private_key, public_key, fingerprint = crypto.generate_key_pair()
self.create_key_pair(User.safe_id(user), key_name,
public_key, fingerprint)
return private_key, fingerprint
def create_key_pair(self, user, key_name, public_key, fingerprint):
with LDAPWrapper() as conn:
return conn.create_key_pair(User.safe_id(user), key_name,
public_key, fingerprint)
def get_key_pair(self, user, key_name):
with LDAPWrapper() as conn:
return conn.find_key_pair(User.safe_id(user), key_name)
def get_key_pairs(self, user):
with LDAPWrapper() as conn:
return conn.find_key_pairs(User.safe_id(user))
def delete_key_pair(self, user, key_name):
with LDAPWrapper() as conn:
conn.delete_key_pair(User.safe_id(user), key_name)
def generate_x509_cert(self, user, project):
(private_key, csr) = crypto.generate_x509_cert(
self.__cert_subject(User.safe_id(user)))
# TODO - This should be async call back to the cloud controller
signed_cert = crypto.sign_csr(csr, Project.safe_id(project))
return (private_key, signed_cert)
def __cert_subject(self, uid):
# FIXME(ja) - this should be pulled from a global configuration
return FLAGS.credential_cert_subject % (uid, utils.isotime())
class LDAPWrapper(object):
def __init__(self):
self.user = FLAGS.user_dn
self.passwd = FLAGS.ldap_password
def __enter__(self):
self.connect()
return self
def __exit__(self, type, value, traceback):
self.conn.unbind_s()
return False
def connect(self):
""" connect to ldap as admin user """
if FLAGS.fake_users:
self.NO_SUCH_OBJECT = fakeldap.NO_SUCH_OBJECT
self.OBJECT_CLASS_VIOLATION = fakeldap.OBJECT_CLASS_VIOLATION
self.conn = fakeldap.initialize(FLAGS.ldap_url)
else:
self.NO_SUCH_OBJECT = ldap.NO_SUCH_OBJECT
self.OBJECT_CLASS_VIOLATION = ldap.OBJECT_CLASS_VIOLATION
self.conn = ldap.initialize(FLAGS.ldap_url)
self.conn.simple_bind_s(self.user, self.passwd)
def find_object(self, dn, query = None):
objects = self.find_objects(dn, query)
if len(objects) == 0:
return None
return objects[0]
def find_dns(self, dn, query=None):
try:
res = self.conn.search_s(dn, ldap.SCOPE_SUBTREE, query)
except self.NO_SUCH_OBJECT:
return []
# just return the DNs
return [dn for dn, attributes in res]
def find_objects(self, dn, query = None):
try:
res = self.conn.search_s(dn, ldap.SCOPE_SUBTREE, query)
except self.NO_SUCH_OBJECT:
return []
# just return the attributes
return [attributes for dn, attributes in res]
def find_users(self):
attrs = self.find_objects(FLAGS.user_ldap_subtree,
'(objectclass=novaUser)')
return [self.__to_user(attr) for attr in attrs]
def find_key_pairs(self, uid):
attrs = self.find_objects(self.__uid_to_dn(uid),
'(objectclass=novaKeyPair)')
return [self.__to_key_pair(uid, attr) for attr in attrs]
def find_projects(self):
attrs = self.find_objects(FLAGS.project_ldap_subtree,
'(objectclass=novaProject)')
return [self.__to_project(attr) for attr in attrs]
def find_roles(self, tree):
attrs = self.find_objects(tree,
'(&(objectclass=groupOfNames)(!(objectclass=novaProject)))')
return [self.__to_group(attr) for attr in attrs]
def find_group_dns_with_member(self, tree, uid):
dns = self.find_dns(tree,
'(&(objectclass=groupOfNames)(member=%s))' %
self.__uid_to_dn(uid))
return dns
def find_user(self, uid):
attr = self.find_object(self.__uid_to_dn(uid),
'(objectclass=novaUser)')
return self.__to_user(attr)
def find_key_pair(self, uid, key_name):
dn = 'cn=%s,%s' % (key_name,
self.__uid_to_dn(uid))
attr = self.find_object(dn, '(objectclass=novaKeyPair)')
return self.__to_key_pair(uid, attr)
def find_group(self, dn):
"""uses dn directly instead of custructing it from name"""
attr = self.find_object(dn, '(objectclass=groupOfNames)')
return self.__to_group(attr)
def find_project(self, name):
dn = 'cn=%s,%s' % (name,
FLAGS.project_ldap_subtree)
attr = self.find_object(dn, '(objectclass=novaProject)')
return self.__to_project(attr)
def user_exists(self, name):
return self.find_user(name) != None
def key_pair_exists(self, uid, key_name):
return self.find_key_pair(uid, key_name) != None
def project_exists(self, name):
return self.find_project(name) != None
def group_exists(self, dn):
return self.find_group(dn) != None
def delete_key_pairs(self, uid):
keys = self.find_key_pairs(uid)
if keys != None:
for key in keys:
self.delete_key_pair(uid, key.name)
def create_user(self, name, access_key, secret_key, is_admin):
if self.user_exists(name):
raise exception.Duplicate("LDAP user %s already exists" % name)
attr = [
('objectclass', ['person',
'organizationalPerson',
'inetOrgPerson',
'novaUser']),
('ou', [FLAGS.user_unit]),
('uid', [name]),
('sn', [name]),
('cn', [name]),
('secretKey', [secret_key]),
('accessKey', [access_key]),
('isAdmin', [str(is_admin).upper()]),
]
self.conn.add_s(self.__uid_to_dn(name), attr)
return self.__to_user(dict(attr))
def create_project(self, name, manager_uid,
description=None, member_uids=None):
if self.project_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)
manager_dn = self.__uid_to_dn(manager_uid)
# description is a required attribute
if description is None:
description = name
members = []
if member_uids != 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" % 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']),
('cn', [name]),
('description', [description]),
('projectManager', [manager_dn]),
('member', members)
]
self.conn.add_s('cn=%s,%s' % (name, FLAGS.project_ldap_subtree), attr)
return self.__to_project(dict(attr))
def add_to_project(self, uid, project_id):
dn = 'cn=%s,%s' % (project_id, FLAGS.project_ldap_subtree)
return self.add_to_group(uid, dn)
def remove_from_project(self, uid, project_id):
dn = 'cn=%s,%s' % (project_id, FLAGS.project_ldap_subtree)
return self.remove_from_group(uid, dn)
def is_in_project(self, uid, project_id):
dn = 'cn=%s,%s' % (project_id, FLAGS.project_ldap_subtree)
return self.is_in_group(uid, dn)
def __role_to_dn(self, role, project_id=None):
if project_id == None:
return FLAGS.__getitem__("ldap_%s" % role).value
else:
return 'cn=%s,cn=%s,%s' % (role,
project_id,
FLAGS.project_ldap_subtree)
def __create_group(self, group_dn, name, uid,
description, member_uids = None):
if self.group_exists(group_dn):
raise exception.Duplicate("Group can't be created because "
"group %s already exists" % name)
members = []
if member_uids != None:
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)
members.append(self.__uid_to_dn(member_uid))
dn = self.__uid_to_dn(uid)
if not dn in members:
members.append(dn)
attr = [
('objectclass', ['groupOfNames']),
('cn', [name]),
('description', [description]),
('member', members)
]
self.conn.add_s(group_dn, attr)
return self.__to_group(dict(attr))
def has_role(self, uid, role, project_id=None):
role_dn = self.__role_to_dn(role, project_id)
return self.is_in_group(uid, role_dn)
def add_role(self, uid, role, project_id=None):
role_dn = self.__role_to_dn(role, project_id)
if not self.group_exists(role_dn):
# create the role if it doesn't exist
description = '%s role for %s' % (role, project_id)
self.__create_group(role_dn, role, uid, description)
else:
return self.add_to_group(uid, role_dn)
def remove_role(self, uid, role, project_id=None):
role_dn = self.__role_to_dn(role, project_id)
return self.remove_from_group(uid, role_dn)
def is_in_group(self, uid, group_dn):
if not self.user_exists(uid):
raise exception.NotFound("User %s can't be searched in group "
"becuase the user doesn't exist" % (uid,))
if not self.group_exists(group_dn):
return False
res = self.find_object(group_dn,
'(member=%s)' % self.__uid_to_dn(uid))
return res != None
def add_to_group(self, uid, group_dn):
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,))
if not self.group_exists(group_dn):
raise exception.NotFound("The group at dn %s doesn't exist" %
(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))
attr = [
(ldap.MOD_ADD, 'member', self.__uid_to_dn(uid))
]
self.conn.modify_s(group_dn, attr)
def remove_from_group(self, uid, group_dn):
if not self.group_exists(group_dn):
raise exception.NotFound("The group at dn %s doesn't exist" %
(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,))
if not self.is_in_group(uid, group_dn):
raise exception.NotFound("User %s is not a member of the group" %
(uid,))
self._safe_remove_from_group(group_dn, uid)
def _safe_remove_from_group(self, group_dn, uid):
# FIXME(vish): what if deleted user is a project manager?
attr = [(ldap.MOD_DELETE, 'member', self.__uid_to_dn(uid))]
try:
self.conn.modify_s(group_dn, attr)
except self.OBJECT_CLASS_VIOLATION:
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):
if not self.user_exists(uid):
raise exception.NotFound("User %s can't be removed from all "
"because the user doesn't exist" % (uid,))
dn = self.__uid_to_dn(uid)
role_dns = self.find_group_dns_with_member(
FLAGS.role_ldap_subtree, uid)
for role_dn in role_dns:
self._safe_remove_from_group(role_dn, uid)
project_dns = self.find_group_dns_with_member(
FLAGS.project_ldap_subtree, uid)
for project_dn in project_dns:
self._safe_remove_from_group(project_dn, uid)
def create_key_pair(self, uid, key_name, public_key, fingerprint):
"""create's a public key in the directory underneath the user"""
# TODO(vish): possibly refactor this to store keys in their own ou
# and put dn reference in the user object
attr = [
('objectclass', ['novaKeyPair']),
('cn', [key_name]),
('sshPublicKey', [public_key]),
('keyFingerprint', [fingerprint]),
]
self.conn.add_s('cn=%s,%s' % (key_name,
self.__uid_to_dn(uid)),
attr)
return self.__to_key_pair(uid, dict(attr))
def find_user_by_access_key(self, access):
query = '(accessKey=%s)' % access
dn = FLAGS.user_ldap_subtree
return self.__to_user(self.find_object(dn, query))
def delete_user(self, uid):
if not self.user_exists(uid):
raise exception.NotFound("User %s doesn't exist" % uid)
self.delete_key_pairs(uid)
self.remove_from_all(uid)
self.conn.delete_s('uid=%s,%s' % (uid,
FLAGS.user_ldap_subtree))
def delete_key_pair(self, uid, key_name):
if not self.key_pair_exists(uid, key_name):
raise exception.NotFound("Key Pair %s doesn't exist for user %s" %
(key_name, uid))
self.conn.delete_s('cn=%s,uid=%s,%s' % (key_name, uid,
FLAGS.user_ldap_subtree))
def delete_group(self, group_dn):
if not self.group_exists(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):
roles = self.find_roles(project_dn)
for role in roles:
self.delete_group('cn=%s,%s' % (role.id, project_dn))
def delete_project(self, name):
project_dn = 'cn=%s,%s' % (name, FLAGS.project_ldap_subtree)
self.delete_roles(project_dn)
self.delete_group(project_dn)
def __to_user(self, attr):
if attr == None:
return None
return User(
id = attr['uid'][0],
name = attr['cn'][0],
access = attr['accessKey'][0],
secret = attr['secretKey'][0],
admin = (attr['isAdmin'][0] == 'TRUE')
)
def __to_key_pair(self, owner, attr):
if attr == None:
return None
return KeyPair(
id = attr['cn'][0],
owner_id = owner,
public_key = attr['sshPublicKey'][0],
fingerprint = attr['keyFingerprint'][0],
)
def __to_group(self, attr):
if attr == None:
return None
member_dns = attr.get('member', [])
return Group(
id = attr['cn'][0],
description = attr.get('description', [None])[0],
member_ids = [self.__dn_to_uid(x) for x in member_dns]
)
def __to_project(self, attr):
if attr == None:
return None
member_dns = attr.get('member', [])
return Project(
id = attr['cn'][0],
project_manager_id = self.__dn_to_uid(attr['projectManager'][0]),
description = attr.get('description', [None])[0],
member_ids = [self.__dn_to_uid(x) for x in member_dns]
)
def __dn_to_uid(self, dn):
return dn.split(',')[0].split('=')[1]
def __uid_to_dn(self, dn):
return 'uid=%s,%s' % (dn, FLAGS.user_ldap_subtree)

View File

@ -25,7 +25,7 @@ import tornado.web
import urllib
from nova import crypto
from nova.auth import users
from nova.auth import manager
_log = logging.getLogger("api")

View File

@ -31,7 +31,7 @@ import zipfile
from nova import exception
from nova import flags
from nova import utils
from nova.auth import users
from nova.auth import manager
from nova.endpoint import api
@ -44,7 +44,7 @@ flags.DEFINE_string('boot_script_template',
class CloudPipe(object):
def __init__(self, cloud_controller):
self.controller = cloud_controller
self.manager = users.UserManager.instance()
self.manager = manager.AuthManager()
def launch_vpn_instance(self, project_id):
logging.debug( "Launching VPN for %s" % (project_id))

View File

@ -29,7 +29,7 @@ from nova import datastore
from nova import exception
from nova import flags
from nova import utils
from nova.auth import users
from nova.auth import manager
from nova.compute import exception as compute_exception
from nova.compute import linux_net
@ -209,11 +209,11 @@ class BaseNetwork(datastore.BasicModel):
@property
def user(self):
return users.UserManager.instance().get_user(self['user_id'])
return manager.AuthManager().get_user(self['user_id'])
@property
def project(self):
return users.UserManager.instance().get_project(self['project_id'])
return manager.AuthManager().get_project(self['project_id'])
@property
def _hosts_key(self):
@ -511,7 +511,7 @@ def get_vlan_for_project(project_id):
if not known_vlans.has_key(vstr):
return Vlan.create(project_id, vnum)
old_project_id = known_vlans[vstr]
if not users.UserManager.instance().get_project(old_project_id):
if not manager.AuthManager().get_project(old_project_id):
vlan = Vlan.lookup(old_project_id)
if vlan:
# NOTE(todd): This doesn't check for vlan id match, because
@ -537,7 +537,7 @@ def get_network_by_interface(iface, security_group='default'):
def get_network_by_address(address):
logging.debug("Get Network By Address: %s" % address)
for project in users.UserManager.instance().get_projects():
for project in manager.AuthManager().get_projects():
net = get_project_network(project.id)
if address in net.assigned:
logging.debug("Found %s in %s" % (address, project.id))
@ -577,7 +577,7 @@ def get_project_network(project_id, security_group='default'):
""" get a project's private network, allocating one if needed """
# TODO(todd): It looks goofy to get a project from a UserManager.
# Refactor to still use the LDAP backend, but not User specific.
project = users.UserManager.instance().get_project(project_id)
project = manager.AuthManager().get_project(project_id)
if not project:
raise exception.Error("Project %s doesn't exist, uhoh." %
project_id)
@ -587,5 +587,5 @@ def get_project_network(project_id, security_group='default'):
def restart_nets():
""" Ensure the network for each user is enabled"""
for project in users.UserManager.instance().get_projects():
for project in manager.AuthManager().get_projects():
get_project_network(project.id).express()

View File

@ -22,7 +22,7 @@ Admin API controller, exposed through http via the api worker.
import base64
from nova.auth import users
from nova.auth import manager
from nova.compute import model
def user_dict(user, base64_file=None):
@ -69,18 +69,18 @@ class AdminController(object):
@admin_only
def describe_user(self, _context, name, **_kwargs):
"""Returns user data, including access and secret keys."""
return user_dict(users.UserManager.instance().get_user(name))
return user_dict(manager.AuthManager().get_user(name))
@admin_only
def describe_users(self, _context, **_kwargs):
"""Returns all users - should be changed to deal with a list."""
return {'userSet':
[user_dict(u) for u in users.UserManager.instance().get_users()] }
[user_dict(u) for u in manager.AuthManager().get_users()] }
@admin_only
def register_user(self, _context, name, **_kwargs):
"""Creates a new user, and returns generated credentials."""
return user_dict(users.UserManager.instance().create_user(name))
return user_dict(manager.AuthManager().create_user(name))
@admin_only
def deregister_user(self, _context, name, **_kwargs):
@ -88,7 +88,7 @@ class AdminController(object):
Should throw an exception if the user has instances,
volumes, or buckets remaining.
"""
users.UserManager.instance().delete_user(name)
manager.AuthManager().delete_user(name)
return True
@ -100,8 +100,8 @@ class AdminController(object):
"""
if project is None:
project = name
project = users.UserManager.instance().get_project(project)
user = users.UserManager.instance().get_user(name)
project = manager.AuthManager().get_project(project)
user = manager.AuthManager().get_user(name)
return user_dict(user, base64.b64encode(project.get_credentials(user)))
@admin_only

View File

@ -35,7 +35,7 @@ from nova import crypto
from nova import exception
from nova import flags
from nova import utils
from nova.auth import users
from nova.auth import manager
import nova.cloudpipe.api
from nova.endpoint import cloud
@ -266,7 +266,7 @@ class APIRequestHandler(tornado.web.RequestHandler):
# Authenticate the request.
try:
(user, project) = users.UserManager.instance().authenticate(
(user, project) = manager.AuthManager().authenticate(
access,
signature,
auth_params,

View File

@ -35,7 +35,7 @@ from nova import flags
from nova import rpc
from nova import utils
from nova.auth import rbac
from nova.auth import users
from nova.auth import manager
from nova.compute import model
from nova.compute import network
from nova.compute import node
@ -48,9 +48,9 @@ FLAGS = flags.FLAGS
flags.DEFINE_string('cloud_topic', 'cloud', 'the topic clouds listen on')
def _gen_key(user_id, key_name):
""" Tuck this into UserManager """
""" Tuck this into AuthManager """
try:
manager = users.UserManager.instance()
manager = manager.AuthManager()
private_key, fingerprint = manager.generate_key_pair(user_id, key_name)
except Exception as ex:
return {'exception': ex}

View File

@ -34,7 +34,7 @@ from nova import exception
from nova import flags
from nova import rpc
from nova import utils
from nova.auth import users
from nova.auth import manager
from nova.compute import model
from nova.compute import network
from nova.endpoint import images
@ -78,11 +78,11 @@ class Api(object):
def build_context(self, env):
rv = {}
if env.has_key("HTTP_X_AUTH_TOKEN"):
rv['user'] = users.UserManager.instance().get_user_from_access_key(
rv['user'] = manager.AuthManager().get_user_from_access_key(
env['HTTP_X_AUTH_TOKEN']
)
if rv['user']:
rv['project'] = users.UserManager.instance().get_project(
rv['project'] = manager.AuthManager().get_project(
rv['user'].name
)
return rv

View File

@ -22,7 +22,7 @@ import logging
from nova import exception
from nova import flags
from nova import test
from nova.auth.users import UserManager
from nova.auth import manager
from nova.auth import rbac
@ -35,7 +35,7 @@ class AccessTestCase(test.BaseTestCase):
super(AccessTestCase, self).setUp()
FLAGS.fake_libvirt = True
FLAGS.fake_storage = True
um = UserManager.instance()
um = manager.AuthManager()
# Make test users
try:
self.testadmin = um.create_user('testadmin')
@ -79,7 +79,7 @@ class AccessTestCase(test.BaseTestCase):
#user is set in each test
def tearDown(self):
um = UserManager.instance()
um = manager.AuthManager()
# Delete the test project
um.delete_project('testproj')
# Delete the test user

View File

@ -26,7 +26,7 @@ from twisted.internet import defer
from nova import flags
from nova import test
from nova.auth import users
from nova.auth import manager
from nova.endpoint import api
from nova.endpoint import cloud
@ -150,7 +150,7 @@ class ApiEc2TestCase(test.BaseTestCase):
def setUp(self):
super(ApiEc2TestCase, self).setUp()
self.users = users.UserManager.instance()
self.users = manager.AuthManager()
self.cloud = cloud.CloudController()
self.host = '127.0.0.1'

View File

@ -25,19 +25,19 @@ import unittest
from nova import crypto
from nova import flags
from nova import test
from nova.auth import users
from nova.auth import manager
from nova.endpoint import cloud
FLAGS = flags.FLAGS
class UserTestCase(test.BaseTestCase):
class AuthTestCase(test.BaseTestCase):
flush_db = False
def setUp(self):
super(UserTestCase, self).setUp()
super(AuthTestCase, self).setUp()
self.flags(fake_libvirt=True,
fake_storage=True)
self.users = users.UserManager.instance()
self.users = manager.AuthManager()
def test_001_can_create_users(self):
self.users.create_user('test1', 'access', 'secret')

View File

@ -27,7 +27,7 @@ from xml.etree import ElementTree
from nova import flags
from nova import rpc
from nova import test
from nova.auth import users
from nova.auth import manager
from nova.compute import node
from nova.endpoint import api
from nova.endpoint import cloud
@ -61,15 +61,15 @@ class CloudTestCase(test.BaseTestCase):
self.injected.append(self.node_consumer.attach_to_tornado(self.ioloop))
try:
users.UserManager.instance().create_user('admin', 'admin', 'admin')
manager.AuthManager().create_user('admin', 'admin', 'admin')
except: pass
admin = users.UserManager.instance().get_user('admin')
project = users.UserManager.instance().create_project('proj', 'admin', 'proj')
admin = manager.AuthManager().get_user('admin')
project = manager.AuthManager().create_project('proj', 'admin', 'proj')
self.context = api.APIRequestContext(handler=None,project=project,user=admin)
def tearDown(self):
users.UserManager.instance().delete_project('proj')
users.UserManager.instance().delete_user('admin')
manager.AuthManager().delete_project('proj')
manager.AuthManager().delete_user('admin')
def test_console_output(self):
if FLAGS.fake_libvirt:

View File

@ -26,7 +26,7 @@ from nova import test
from nova import exception
from nova.compute.exception import NoMoreAddresses
from nova.compute import network
from nova.auth import users
from nova.auth import manager
from nova import utils
@ -38,7 +38,7 @@ class NetworkTestCase(test.TrialTestCase):
fake_network=True,
network_size=32)
logging.getLogger().setLevel(logging.DEBUG)
self.manager = users.UserManager.instance()
self.manager = manager.AuthManager()
self.dnsmasq = FakeDNSMasq()
try:
self.manager.create_user('netuser', 'netuser', 'netuser')

View File

@ -26,7 +26,7 @@ import tempfile
from nova import flags
from nova import objectstore
from nova import test
from nova.auth import users
from nova.auth import manager
FLAGS = flags.FLAGS
@ -57,7 +57,7 @@ class ObjectStoreTestCase(test.BaseTestCase):
ca_path=os.path.join(os.path.dirname(__file__), 'CA'))
logging.getLogger().setLevel(logging.DEBUG)
self.um = users.UserManager.instance()
self.um = manager.AuthManager()
try:
self.um.create_user('user1')
except: pass
@ -177,7 +177,7 @@ class ObjectStoreTestCase(test.BaseTestCase):
# FLAGS.images_path = os.path.join(tempdir, 'images')
# FLAGS.ca_path = os.path.join(os.path.dirname(__file__), 'CA')
#
# self.users = users.UserManager.instance()
# self.users = manager.AuthManager()
# self.app = handler.Application(self.users)
#
# self.host = '127.0.0.1'

View File

@ -57,7 +57,7 @@ from nova.tests.node_unittest import *
from nova.tests.objectstore_unittest import *
from nova.tests.process_unittest import *
from nova.tests.storage_unittest import *
from nova.tests.users_unittest import *
from nova.tests.auth_unittest import *
from nova.tests.validator_unittest import *