OpenStack Identity (Keystone)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

236 lines
8.5 KiB

# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 OpenStack LLC
#
# 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.
from keystone import identity
from keystone.common import kvs
from keystone.common import utils
def _filter_user(user_ref):
if user_ref:
user_ref = user_ref.copy()
user_ref.pop('password', None)
user_ref.pop('tenants', None)
return user_ref
def _ensure_hashed_password(user_ref):
pw = user_ref.get('password', None)
if pw is not None:
user_ref['password'] = utils.hash_password(pw)
return user_ref
class Identity(kvs.Base, identity.Driver):
# Public interface
def authenticate(self, user_id=None, tenant_id=None, password=None):
"""Authenticate based on a user, tenant and password.
Expects the user object to have a password field and the tenant to be
in the list of tenants on the user.
"""
user_ref = self._get_user(user_id)
tenant_ref = None
metadata_ref = None
if (not user_ref
or not utils.check_password(password, user_ref.get('password'))):
raise AssertionError('Invalid user / password')
if tenant_id and tenant_id not in user_ref['tenants']:
raise AssertionError('Invalid tenant')
tenant_ref = self.get_tenant(tenant_id)
if tenant_ref:
metadata_ref = self.get_metadata(user_id, tenant_id)
else:
metadata_ref = {}
return (_filter_user(user_ref), tenant_ref, metadata_ref)
def get_tenant(self, tenant_id):
tenant_ref = self.db.get('tenant-%s' % tenant_id)
return tenant_ref
def get_tenant_by_name(self, tenant_name):
tenant_ref = self.db.get('tenant_name-%s' % tenant_name)
return tenant_ref
def _get_user(self, user_id):
user_ref = self.db.get('user-%s' % user_id)
return user_ref
def _get_user_by_name(self, user_name):
user_ref = self.db.get('user_name-%s' % user_name)
return user_ref
def get_user(self, user_id):
return _filter_user(self._get_user(user_id))
def get_user_by_name(self, user_name):
return _filter_user(self._get_user_by_name(user_name))
def get_metadata(self, user_id, tenant_id):
return self.db.get('metadata-%s-%s' % (tenant_id, user_id))
def get_role(self, role_id):
role_ref = self.db.get('role-%s' % role_id)
return role_ref
def list_users(self):
user_ids = self.db.get('user_list', [])
return [self.get_user(x) for x in user_ids]
def list_roles(self):
role_ids = self.db.get('role_list', [])
return [self.get_role(x) for x in role_ids]
# These should probably be part of the high-level API
def add_user_to_tenant(self, tenant_id, user_id):
user_ref = self._get_user(user_id)
tenants = set(user_ref.get('tenants', []))
tenants.add(tenant_id)
self.update_user(user_id, {'tenants': list(tenants)})
def remove_user_from_tenant(self, tenant_id, user_id):
user_ref = self._get_user(user_id)
tenants = set(user_ref.get('tenants', []))
tenants.remove(tenant_id)
self.update_user(user_id, {'tenants': list(tenants)})
def get_tenants_for_user(self, user_id):
user_ref = self._get_user(user_id)
return user_ref.get('tenants', [])
def get_roles_for_user_and_tenant(self, user_id, tenant_id):
metadata_ref = self.get_metadata(user_id, tenant_id)
if not metadata_ref:
metadata_ref = {}
return metadata_ref.get('roles', [])
def add_role_to_user_and_tenant(self, user_id, tenant_id, role_id):
metadata_ref = self.get_metadata(user_id, tenant_id)
if not metadata_ref:
metadata_ref = {}
roles = set(metadata_ref.get('roles', []))
roles.add(role_id)
metadata_ref['roles'] = list(roles)
self.update_metadata(user_id, tenant_id, metadata_ref)
def remove_role_from_user_and_tenant(self, user_id, tenant_id, role_id):
metadata_ref = self.get_metadata(user_id, tenant_id)
if not metadata_ref:
metadata_ref = {}
roles = set(metadata_ref.get('roles', []))
roles.remove(role_id)
metadata_ref['roles'] = list(roles)
self.update_metadata(user_id, tenant_id, metadata_ref)
# CRUD
def create_user(self, user_id, user):
if self.get_user(user_id):
raise Exception('Duplicate id')
if self.get_user_by_name(user['name']):
raise Exception('Duplicate name')
user = _ensure_hashed_password(user)
self.db.set('user-%s' % user_id, user)
self.db.set('user_name-%s' % user['name'], user)
user_list = set(self.db.get('user_list', []))
user_list.add(user_id)
self.db.set('user_list', list(user_list))
return user
def update_user(self, user_id, user):
if 'name' in user:
existing = self.db.get('user_name-%s' % user['name'])
if existing and user_id != existing['id']:
raise Exception('Duplicate name')
# get the old name and delete it too
old_user = self.db.get('user-%s' % user_id)
new_user = old_user.copy()
user = _ensure_hashed_password(user)
new_user.update(user)
new_user['id'] = user_id
self.db.delete('user_name-%s' % old_user['name'])
self.db.set('user-%s' % user_id, new_user)
self.db.set('user_name-%s' % new_user['name'], new_user)
return new_user
def delete_user(self, user_id):
old_user = self.db.get('user-%s' % user_id)
self.db.delete('user_name-%s' % old_user['name'])
self.db.delete('user-%s' % user_id)
user_list = set(self.db.get('user_list', []))
user_list.remove(user_id)
self.db.set('user_list', list(user_list))
return None
def create_tenant(self, tenant_id, tenant):
if self.get_tenant(tenant_id):
raise Exception('Duplicate id')
if self.get_tenant_by_name(tenant['name']):
raise Exception('Duplicate name')
self.db.set('tenant-%s' % tenant_id, tenant)
self.db.set('tenant_name-%s' % tenant['name'], tenant)
return tenant
def update_tenant(self, tenant_id, tenant):
if 'name' in tenant:
existing = self.db.get('tenant_name-%s' % tenant['name'])
if existing and tenant_id != existing['id']:
raise Exception('Duplicate name')
# get the old name and delete it too
old_tenant = self.db.get('tenant-%s' % tenant_id)
new_tenant = old_tenant.copy()
new_tenant['id'] = tenant_id
self.db.delete('tenant_name-%s' % old_tenant['name'])
self.db.set('tenant-%s' % tenant_id, new_tenant)
self.db.set('tenant_name-%s' % new_tenant['name'], new_tenant)
return tenant
def delete_tenant(self, tenant_id):
old_tenant = self.db.get('tenant-%s' % tenant_id)
self.db.delete('tenant_name-%s' % old_tenant['name'])
self.db.delete('tenant-%s' % tenant_id)
return None
def create_metadata(self, user_id, tenant_id, metadata):
self.db.set('metadata-%s-%s' % (tenant_id, user_id), metadata)
return metadata
def update_metadata(self, user_id, tenant_id, metadata):
self.db.set('metadata-%s-%s' % (tenant_id, user_id), metadata)
return metadata
def delete_metadata(self, user_id, tenant_id):
self.db.delete('metadata-%s-%s' % (tenant_id, user_id))
return None
def create_role(self, role_id, role):
self.db.set('role-%s' % role_id, role)
role_list = set(self.db.get('role_list', []))
role_list.add(role_id)
self.db.set('role_list', list(role_list))
return role
def update_role(self, role_id, role):
self.db.set('role-%s' % role_id, role)
return role
def delete_role(self, role_id):
self.db.delete('role-%s' % role_id)
role_list = set(self.db.get('role_list', []))
role_list.remove(role_id)
self.db.set('role_list', list(role_list))
return None