summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorandy <github@anarkystic.com>2010-08-19 11:12:44 +0200
committerandy <github@anarkystic.com>2010-08-19 11:12:44 +0200
commitf996ec188776ffcae62bcafc1925653a1602880f (patch)
tree24fef80bbedf83fd3054fd41fdec8bf347189521
parenta74f2a3ca4e26c451a002f9a89f3ba4ac4a083c4 (diff)
downloadnova-f996ec188776ffcae62bcafc1925653a1602880f.tar.gz
nova-f996ec188776ffcae62bcafc1925653a1602880f.tar.xz
nova-f996ec188776ffcae62bcafc1925653a1602880f.zip
this file isn't being used
-rw-r--r--nova/auth.py741
1 files changed, 0 insertions, 741 deletions
diff --git a/nova/auth.py b/nova/auth.py
deleted file mode 100644
index 199a887e1..000000000
--- a/nova/auth.py
+++ /dev/null
@@ -1,741 +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 authentication management
-"""
-
-import logging
-import os
-import shutil
-import string
-import tempfile
-import uuid
-import zipfile
-
-from nova import crypto
-from nova import exception
-from nova import flags
-from nova import utils
-from nova.auth import signer
-from nova.network import vpn
-from nova.models import User
-
-#unused imports
-#from nova import datastore
-#from nova.auth import ldapdriver # for flags
-#from nova import objectstore # for flags
-
-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_vpn_file', 'nova-vpn.conf',
- 'Filename of certificate in credentials zip')
-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('auth_driver', 'nova.auth.ldapdriver.FakeLdapDriver',
- 'Driver that auth manager uses')
-
-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
-
-
-# anthony - the User class has moved to nova.models
-#class User(AuthBase):
-# """Object representing a user"""
-# def __init__(self, id, name, access, secret, admin):
-# AuthBase.__init__(self)
-# 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, name, owner_id, public_key, fingerprint):
- AuthBase.__init__(self)
- self.id = id
- self.name = name
- self.owner_id = owner_id
- self.public_key = public_key
- self.fingerprint = fingerprint
-
- def __repr__(self):
- return "KeyPair('%s', '%s', '%s', '%s', '%s')" % (self.id,
- self.name,
- self.owner_id,
- self.public_key,
- self.fingerprint)
-
-
-class Project(AuthBase):
- """Represents a Project returned from the datastore"""
- def __init__(self, id, name, project_manager_id, description, member_ids):
- AuthBase.__init__(self)
- self.id = id
- self.name = name
- self.project_manager_id = project_manager_id
- self.description = description
- self.member_ids = member_ids
-
- @property
- def project_manager(self):
- return AuthManager().get_user(self.project_manager_id)
-
- @property
- def vpn_ip(self):
- ip, port = AuthManager().get_project_vpn_data(self)
- return ip
-
- @property
- def vpn_port(self):
- ip, port = AuthManager().get_project_vpn_data(self)
- return port
-
- 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', %s)" % (self.id,
- self.name,
- self.project_manager_id,
- self.description,
- self.member_ids)
-
-
-
-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 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):
- """Returns the AuthManager singleton"""
- if not cls._instance:
- cls._instance = super(AuthManager, cls).__new__(cls)
- return cls._instance
-
- def __init__(self, driver=None, *args, **kwargs):
- """Inits the driver from parameter or flag
-
- __init__ is run every time AuthManager() is called, so we only
- reset the driver if it is not set or a new driver is specified.
- """
- if driver or not getattr(self, 'driver', None):
- self.driver = utils.import_class(driver or FLAGS.auth_driver)
-
- def authenticate(self, access, signature, params, verb='GET',
- server_string='127.0.0.1:8773', path='/',
- check_type='ec2', headers=None):
- """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 check_type: str
- @param check_type: Type of signature to check. 'ec2' for EC2, 's3' for
- S3. Any other value will cause signature not to be
- checked.
-
- @type headers: list
- @param headers: HTTP headers passed with the request (only needed for
- s3 signature checks)
-
- @rtype: tuple (User, Project)
- @return: User and project that the request represents.
- """
- # TODO(vish): check for valid timestamp
- (access_key, sep, project_id) = access.partition(':')
-
- 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)
-
- # NOTE(vish): if we stop using project name as id we need better
- # logic to find a default project for user
- if project_id is '':
- project_id = user.name
-
- project = self.get_project(project_id)
- if project == None:
- 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))
- if check_type == 's3':
- expected_signature = signer.Signer(user.secret.encode()).s3_authorization(headers, verb, 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')
- elif check_type == 'ec2':
- # 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 get_access_key(self, user, project):
- """Get an access key that includes user and project"""
- if not isinstance(user, User):
- user = self.get_user(user)
- return "%s:%s" % (user.access, Project.safe_id(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() 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() 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() as drv:
- drv.remove_role(User.safe_id(user), role, Project.safe_id(project))
-
- def get_project(self, pid):
- """Get project object by id"""
- with self.driver() as drv:
- project_dict = drv.get_project(pid)
- if project_dict:
- return Project(**project_dict)
-
- def get_projects(self, user=None):
- """Retrieves list of projects, optionally filtered by user"""
- with self.driver() as drv:
- project_list = drv.get_projects(User.safe_id(user))
- if not project_list:
- return []
- return [Project(**project_dict) for project_dict in project_list]
-
- 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]
- with self.driver() as drv:
- project_dict = drv.create_project(name,
- User.safe_id(manager_user),
- description,
- member_users)
- if project_dict:
- return Project(**project_dict)
-
- def add_to_project(self, user, project):
- """Add user to project"""
- with self.driver() 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() as drv:
- return drv.remove_from_project(User.safe_id(user),
- Project.safe_id(project))
-
- def get_project_vpn_data(self, project):
- """Gets vpn ip and port for project
-
- @type project: Project or project_id
- @param project: Project from which to get associated vpn data
-
- @rvalue: tuple of (str, str)
- @return: A tuple containing (ip, port) or None, None if vpn has
- not been allocated for user.
- """
- network_data = vpn.NetworkData.lookup(Project.safe_id(project))
- if not network_data:
- raise exception.NotFound('project network data has not been set')
- return (network_data.ip, network_data.port)
-
- def delete_project(self, project):
- """Deletes a project"""
- with self.driver() as drv:
- return drv.delete_project(Project.safe_id(project))
-
- def get_user(self, uid):
- """Retrieves a user by id"""
- with self.driver() as drv:
- user_dict = drv.get_user(uid)
- if user_dict:
- return User(**user_dict)
-
- def get_user_from_access_key(self, access_key):
- """Retrieves a user by access key"""
- with self.driver() as drv:
- user_dict = drv.get_user_from_access_key(access_key)
- if user_dict:
- return User(**user_dict)
-
- def get_users(self):
- """Retrieves a list of all users"""
- with self.driver() as drv:
- user_list = drv.get_users()
- if not user_list:
- return []
- return [User(**user_dict) for user_dict in user_list]
-
- def create_user(self, name, access=None, secret=None, admin=False):
- """Creates a user
-
- @type name: str
- @param name: Name of the user to create.
-
- @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() as drv:
- user_dict = drv.create_user(name, access, secret, admin)
- if user_dict:
- return User(**user_dict)
-
- def delete_user(self, user):
- """Deletes a user"""
- with self.driver() as drv:
- drv.delete_user(User.safe_id(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() 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() as drv:
- kp_dict = drv.create_key_pair(User.safe_id(user),
- key_name,
- public_key,
- fingerprint)
- if kp_dict:
- return KeyPair(**kp_dict)
-
- def get_key_pair(self, user, key_name):
- """Retrieves a key pair for user"""
- with self.driver() as drv:
- kp_dict = drv.get_key_pair(User.safe_id(user), key_name)
- if kp_dict:
- return KeyPair(**kp_dict)
-
- def get_key_pairs(self, user):
- """Retrieves all key pairs for user"""
- with self.driver() as drv:
- kp_list = drv.get_key_pairs(User.safe_id(user))
- if not kp_list:
- return []
- return [KeyPair(**kp_dict) for kp_dict in kp_list]
-
- def delete_key_pair(self, user, key_name):
- """Deletes a key pair for user"""
- with self.driver() 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)
-
- 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)
-
- network_data = vpn.NetworkData.lookup(pid)
- if network_data:
- 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=network_data.ip,
- port=network_data.port)
- zippy.writestr(FLAGS.credential_vpn_file, config)
- else:
- logging.warn("No vpn data for project %s" %
- pid)
-
- 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 get_environment_rc(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)
- return self.__generate_rc(user.access, user.secret, pid)
-
- 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())