Merge branch 'master' of github.com:termie/keystonelight
This commit is contained in:
commit
c2ac84e4ca
11
README.rst
11
README.rst
|
@ -91,8 +91,9 @@ Diagram: keystone_compat_flows.sdx_
|
||||||
Still To Do
|
Still To Do
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
* Dev and testing setups would do well with some user/tenant/etc CRUD, for the
|
* Dev and testing setups would do well with some user/tenant/etc CRUD, for the
|
||||||
KVS backends at least.
|
KVS backends at least.
|
||||||
* Fixture loading functionality would also be killer tests and dev.
|
* Fixture loading functionality would also be killer tests and dev.
|
||||||
* LDAP backend.
|
* LDAP backend.
|
||||||
* Keystone import.
|
* Keystone import.
|
||||||
|
* Admin-only interface
|
||||||
|
|
|
@ -6,25 +6,36 @@ class DictKvs(dict):
|
||||||
def delete(self, key):
|
def delete(self, key):
|
||||||
del self[key]
|
del self[key]
|
||||||
|
|
||||||
|
|
||||||
INMEMDB = DictKvs()
|
INMEMDB = DictKvs()
|
||||||
|
|
||||||
|
|
||||||
class KvsIdentity(object):
|
class KvsIdentity(object):
|
||||||
def __init__(self, options, db=None):
|
def __init__(self, options, db=None):
|
||||||
if db is None:
|
if db is None:
|
||||||
db = INMEMDB
|
db = INMEMDB
|
||||||
|
elif type(db) is type({}):
|
||||||
|
db = DictKvs(db)
|
||||||
self.db = db
|
self.db = db
|
||||||
|
|
||||||
# Public interface
|
# Public interface
|
||||||
def authenticate(self, user_id=None, tenant_id=None, password=None):
|
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)
|
user_ref = self.get_user(user_id)
|
||||||
tenant_ref = None
|
tenant_ref = None
|
||||||
extras_ref = None
|
extras_ref = None
|
||||||
if user_ref['password'] != password:
|
if not user_ref or user_ref.get('password') != password:
|
||||||
raise AssertionError('Invalid user / password')
|
raise AssertionError('Invalid user / password')
|
||||||
|
if tenant_id and tenant_id not in user_ref['tenants']:
|
||||||
|
raise AssertionError('Invalid tenant')
|
||||||
|
|
||||||
if tenant_id and tenant_id in user_ref['tenants']:
|
tenant_ref = self.get_tenant(tenant_id)
|
||||||
tenant_ref = self.get_tenant(tenant_id)
|
extras_ref = self.get_extras(user_id, tenant_id)
|
||||||
extras_ref = self.get_extras(user_id, tenant_id)
|
|
||||||
return (user_ref, tenant_ref, extras_ref)
|
return (user_ref, tenant_ref, extras_ref)
|
||||||
|
|
||||||
def get_tenant(self, tenant_id):
|
def get_tenant(self, tenant_id):
|
||||||
|
@ -61,6 +72,8 @@ class KvsToken(object):
|
||||||
def __init__(self, options, db=None):
|
def __init__(self, options, db=None):
|
||||||
if db is None:
|
if db is None:
|
||||||
db = INMEMDB
|
db = INMEMDB
|
||||||
|
elif type(db) is type({}):
|
||||||
|
db = DictKvs(db)
|
||||||
self.db = db
|
self.db = db
|
||||||
|
|
||||||
# Public interface
|
# Public interface
|
||||||
|
@ -79,12 +92,15 @@ class KvsCatalog(object):
|
||||||
def __init__(self, options, db=None):
|
def __init__(self, options, db=None):
|
||||||
if db is None:
|
if db is None:
|
||||||
db = INMEMDB
|
db = INMEMDB
|
||||||
|
elif type(db) is type({}):
|
||||||
|
db = DictKvs(db)
|
||||||
self.db = db
|
self.db = db
|
||||||
|
|
||||||
# Public interface
|
# Public interface
|
||||||
def get_catalog(self, user_id, tenant_id, extras=None):
|
def get_catalog(self, user_id, tenant_id, extras=None):
|
||||||
return self.db.get('catalog-%s' % tenant_id)
|
return self.db.get('catalog-%s-%s' % (tenant_id, user_id))
|
||||||
|
|
||||||
# Private interface
|
# Private interface
|
||||||
def _create_catalog(self, user_id, tenant_id, data):
|
def _create_catalog(self, user_id, tenant_id, data):
|
||||||
self.db.set('catalog-%s' % tenant_id, data)
|
self.db.set('catalog-%s-%s' % (tenant_id, user_id), data)
|
||||||
|
return data
|
||||||
|
|
|
@ -17,7 +17,6 @@ class KeystoneRouter(wsgi.Router):
|
||||||
self.options = options
|
self.options = options
|
||||||
self.keystone_controller = KeystoneController(options)
|
self.keystone_controller = KeystoneController(options)
|
||||||
|
|
||||||
|
|
||||||
mapper = routes.Mapper()
|
mapper = routes.Mapper()
|
||||||
mapper.connect('/v2.0/tokens',
|
mapper.connect('/v2.0/tokens',
|
||||||
controller=self.keystone_controller,
|
controller=self.keystone_controller,
|
||||||
|
|
|
@ -198,3 +198,8 @@ def identity_app_factory(global_conf, **local_conf):
|
||||||
conf.update(local_conf)
|
conf.update(local_conf)
|
||||||
return Router(conf)
|
return Router(conf)
|
||||||
|
|
||||||
|
|
||||||
|
def app_factory(global_conf, **local_conf):
|
||||||
|
conf = global_conf.copy()
|
||||||
|
conf.update(local_conf)
|
||||||
|
return Router(conf)
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import ConfigParser
|
import ConfigParser
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import unittest
|
import unittest
|
||||||
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from paste import deploy
|
from paste import deploy
|
||||||
|
@ -24,13 +26,16 @@ def checkout_vendor(repo, rev):
|
||||||
name = name[:-4]
|
name = name[:-4]
|
||||||
|
|
||||||
revdir = os.path.join(VENDOR, '%s-%s' % (name, rev.replace('/', '_')))
|
revdir = os.path.join(VENDOR, '%s-%s' % (name, rev.replace('/', '_')))
|
||||||
|
try:
|
||||||
|
if not os.path.exists(revdir):
|
||||||
|
utils.git('clone', repo, revdir)
|
||||||
|
|
||||||
if not os.path.exists(revdir):
|
cd(revdir)
|
||||||
utils.git('clone', repo, revdir)
|
utils.git('pull')
|
||||||
|
utils.git('checkout', '-q', rev)
|
||||||
cd(revdir)
|
except subprocess.CalledProcessError as e:
|
||||||
utils.git('pull')
|
logging.warning('Failed to checkout %s', repo)
|
||||||
utils.git('checkout', '-q', rev)
|
pass
|
||||||
return revdir
|
return revdir
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
[DEFAULT]
|
||||||
|
catalog_driver = keystonelight.backends.kvs.KvsCatalog
|
||||||
|
identity_driver = keystonelight.backends.kvs.KvsIdentity
|
||||||
|
token_driver = keystonelight.backends.kvs.KvsToken
|
||||||
|
|
||||||
|
[filter:debug]
|
||||||
|
paste.filter_factory = keystonelight.wsgi:Debug.factory
|
||||||
|
|
||||||
|
[filter:token_auth]
|
||||||
|
paste.filter_factory = keystonelight.service:TokenAuthMiddleware.factory
|
||||||
|
|
||||||
|
[filter:json_body]
|
||||||
|
paste.filter_factory = keystonelight.service:JsonBodyMiddleware.factory
|
||||||
|
|
||||||
|
[app:keystonelight]
|
||||||
|
paste.app_factory = keystonelight.service:app_factory
|
||||||
|
|
||||||
|
[pipeline:main]
|
||||||
|
pipeline = token_auth json_body debug keystonelight
|
|
@ -0,0 +1,157 @@
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
from keystonelight import models
|
||||||
|
from keystonelight import test
|
||||||
|
from keystonelight.backends import kvs
|
||||||
|
|
||||||
|
|
||||||
|
class KvsIdentity(test.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super(KvsIdentity, self).setUp()
|
||||||
|
options = self.appconfig('default')
|
||||||
|
self.identity_api = kvs.KvsIdentity(options=options, db={})
|
||||||
|
self._load_fixtures()
|
||||||
|
|
||||||
|
def _load_fixtures(self):
|
||||||
|
self.tenant_bar = self.identity_api._create_tenant(
|
||||||
|
'bar',
|
||||||
|
models.Tenant(id='bar', name='BAR'))
|
||||||
|
self.user_foo = self.identity_api._create_user(
|
||||||
|
'foo',
|
||||||
|
models.User(id='foo',
|
||||||
|
name='FOO',
|
||||||
|
password='foo2',
|
||||||
|
tenants=[self.tenant_bar['id']]))
|
||||||
|
self.extras_foobar = self.identity_api._create_extras(
|
||||||
|
'foo', 'bar',
|
||||||
|
{'extra': 'extra'})
|
||||||
|
|
||||||
|
def test_authenticate_bad_user(self):
|
||||||
|
self.assertRaises(AssertionError,
|
||||||
|
self.identity_api.authenticate,
|
||||||
|
user_id=self.user_foo['id'] + 'WRONG',
|
||||||
|
tenant_id=self.tenant_bar['id'],
|
||||||
|
password=self.user_foo['password'])
|
||||||
|
|
||||||
|
def test_authenticate_bad_password(self):
|
||||||
|
self.assertRaises(AssertionError,
|
||||||
|
self.identity_api.authenticate,
|
||||||
|
user_id=self.user_foo['id'],
|
||||||
|
tenant_id=self.tenant_bar['id'],
|
||||||
|
password=self.user_foo['password'] + 'WRONG')
|
||||||
|
|
||||||
|
def test_authenticate_invalid_tenant(self):
|
||||||
|
self.assertRaises(AssertionError,
|
||||||
|
self.identity_api.authenticate,
|
||||||
|
user_id=self.user_foo['id'],
|
||||||
|
tenant_id=self.tenant_bar['id'] + 'WRONG',
|
||||||
|
password=self.user_foo['password'])
|
||||||
|
|
||||||
|
def test_authenticate_no_tenant(self):
|
||||||
|
user_ref, tenant_ref, extras_ref = self.identity_api.authenticate(
|
||||||
|
user_id=self.user_foo['id'],
|
||||||
|
password=self.user_foo['password'])
|
||||||
|
self.assertDictEquals(user_ref, self.user_foo)
|
||||||
|
self.assert_(tenant_ref is None)
|
||||||
|
self.assert_(extras_ref is None)
|
||||||
|
|
||||||
|
def test_authenticate(self):
|
||||||
|
user_ref, tenant_ref, extras_ref = self.identity_api.authenticate(
|
||||||
|
user_id=self.user_foo['id'],
|
||||||
|
tenant_id=self.tenant_bar['id'],
|
||||||
|
password=self.user_foo['password'])
|
||||||
|
self.assertDictEquals(user_ref, self.user_foo)
|
||||||
|
self.assertDictEquals(tenant_ref, self.tenant_bar)
|
||||||
|
self.assertDictEquals(extras_ref, self.extras_foobar)
|
||||||
|
|
||||||
|
def test_get_tenant_bad_tenant(self):
|
||||||
|
tenant_ref = self.identity_api.get_tenant(
|
||||||
|
tenant_id=self.tenant_bar['id'] + 'WRONG')
|
||||||
|
self.assert_(tenant_ref is None)
|
||||||
|
|
||||||
|
def test_get_tenant(self):
|
||||||
|
tenant_ref = self.identity_api.get_tenant(tenant_id=self.tenant_bar['id'])
|
||||||
|
self.assertDictEquals(tenant_ref, self.tenant_bar)
|
||||||
|
|
||||||
|
def test_get_tenant_by_name_bad_tenant(self):
|
||||||
|
tenant_ref = self.identity_api.get_tenant(
|
||||||
|
tenant_id=self.tenant_bar['name'] + 'WRONG')
|
||||||
|
self.assert_(tenant_ref is None)
|
||||||
|
|
||||||
|
def test_get_tenant_by_name(self):
|
||||||
|
tenant_ref = self.identity_api.get_tenant_by_name(
|
||||||
|
tenant_name=self.tenant_bar['name'])
|
||||||
|
self.assertDictEquals(tenant_ref, self.tenant_bar)
|
||||||
|
|
||||||
|
def test_get_user_bad_user(self):
|
||||||
|
user_ref = self.identity_api.get_user(
|
||||||
|
user_id=self.user_foo['id'] + 'WRONG')
|
||||||
|
self.assert_(user_ref is None)
|
||||||
|
|
||||||
|
def test_get_user(self):
|
||||||
|
user_ref = self.identity_api.get_user(user_id=self.user_foo['id'])
|
||||||
|
self.assertDictEquals(user_ref, self.user_foo)
|
||||||
|
|
||||||
|
def test_get_extras_bad_user(self):
|
||||||
|
extras_ref = self.identity_api.get_extras(
|
||||||
|
user_id=self.user_foo['id'] + 'WRONG',
|
||||||
|
tenant_id=self.tenant_bar['id'])
|
||||||
|
self.assert_(extras_ref is None)
|
||||||
|
|
||||||
|
def test_get_extras_bad_tenant(self):
|
||||||
|
extras_ref = self.identity_api.get_extras(
|
||||||
|
user_id=self.user_foo['id'],
|
||||||
|
tenant_id=self.tenant_bar['id'] + 'WRONG')
|
||||||
|
self.assert_(extras_ref is None)
|
||||||
|
|
||||||
|
def test_get_extras(self):
|
||||||
|
extras_ref = self.identity_api.get_extras(
|
||||||
|
user_id=self.user_foo['id'],
|
||||||
|
tenant_id=self.tenant_bar['id'])
|
||||||
|
self.assertDictEquals(extras_ref, self.extras_foobar)
|
||||||
|
|
||||||
|
|
||||||
|
class KvsToken(test.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super(KvsToken, self).setUp()
|
||||||
|
options = self.appconfig('default')
|
||||||
|
self.token_api = kvs.KvsToken(options=options, db={})
|
||||||
|
|
||||||
|
def test_token_crud(self):
|
||||||
|
token_id = uuid.uuid4().hex
|
||||||
|
data = {'id': token_id,
|
||||||
|
'a': 'b'}
|
||||||
|
data_ref = self.token_api.create_token(token_id, data)
|
||||||
|
self.assertDictEquals(data_ref, data)
|
||||||
|
|
||||||
|
new_data_ref = self.token_api.get_token(token_id)
|
||||||
|
self.assertEquals(new_data_ref, data)
|
||||||
|
|
||||||
|
self.token_api.delete_token(token_id)
|
||||||
|
deleted_data_ref = self.token_api.get_token(token_id)
|
||||||
|
self.assert_(deleted_data_ref is None)
|
||||||
|
|
||||||
|
|
||||||
|
class KvsCatalog(test.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super(KvsCatalog, self).setUp()
|
||||||
|
options = self.appconfig('default')
|
||||||
|
self.catalog_api = kvs.KvsCatalog(options=options, db={})
|
||||||
|
self._load_fixtures()
|
||||||
|
|
||||||
|
def _load_fixtures(self):
|
||||||
|
self.catalog_foobar = self.catalog_api._create_catalog(
|
||||||
|
'foo', 'bar',
|
||||||
|
{'RegionFoo': {'service_bar': {'foo': 'bar'}}})
|
||||||
|
|
||||||
|
def test_get_catalog_bad_user(self):
|
||||||
|
catalog_ref = self.catalog_api.get_catalog('foo' + 'WRONG', 'bar')
|
||||||
|
self.assert_(catalog_ref is None)
|
||||||
|
|
||||||
|
def test_get_catalog_bad_tenant(self):
|
||||||
|
catalog_ref = self.catalog_api.get_catalog('foo', 'bar' + 'WRONG')
|
||||||
|
self.assert_(catalog_ref is None)
|
||||||
|
|
||||||
|
def test_get_catalog(self):
|
||||||
|
catalog_ref = self.catalog_api.get_catalog('foo', 'bar')
|
||||||
|
self.assertDictEquals(catalog_ref, self.catalog_foobar)
|
Loading…
Reference in New Issue