move around middleware

This commit is contained in:
termie 2011-11-10 11:17:07 -08:00
parent 716c450fbf
commit d7f364e209
4 changed files with 275 additions and 119 deletions

View File

@ -0,0 +1,96 @@
import json
from keystonelight import wsgi
# Header used to transmit the auth token
AUTH_TOKEN_HEADER = 'X-Auth-Token'
# Environment variable used to pass the request context
CONTEXT_ENV = 'openstack.context'
# Environment variable used to pass the request params
PARAMS_ENV = 'openstack.params'
class TokenAuthMiddleware(wsgi.Middleware):
def process_request(self, request):
token = request.headers.get(AUTH_TOKEN_HEADER)
context = request.environ.get(CONTEXT_ENV, {})
context['token_id'] = token
request.environ[CONTEXT_ENV] = context
class AdminTokenAuthMiddleware(wsgi.Middleware):
"""A trivial filter that checks for a pre-defined admin token.
Sets 'is_admin' to true in the context, expected to be checked by
methods that are admin-only.
"""
def process_request(self, request):
token = request.headers.get(AUTH_TOKEN_HEADER)
context = request.environ.get(CONTEXT_ENV, {})
context['is_admin'] = (token == self.options['admin_token'])
request.environ[CONTEXT_ENV] = context
class PostParamsMiddleware(wsgi.Middleware):
"""Middleware to allow method arguments to be passed as POST parameters.
Filters out the parameters `self`, `context` and anything beginning with
an underscore.
"""
def process_request(self, request):
params_parsed = request.params
params = {}
for k, v in params_parsed.iteritems():
if k in ('self', 'context'):
continue
if k.startswith('_'):
continue
params[k] = v
request.environ[PARAMS_ENV] = params
class JsonBodyMiddleware(wsgi.Middleware):
"""Middleware to allow method arguments to be passed as serialized JSON.
Accepting arguments as JSON is useful for accepting data that may be more
complex than simple primitives.
In this case we accept it as urlencoded data under the key 'json' as in
json=<urlencoded_json> but this could be extended to accept raw JSON
in the POST body.
Filters out the parameters `self`, `context` and anything beginning with
an underscore.
"""
def process_request(self, request):
#if 'json' not in request.params:
# return
params_json = request.body
if not params_json:
return
params_parsed = json.loads(params_json)
params = {}
for k, v in params_parsed.iteritems():
if k in ('self', 'context'):
continue
if k.startswith('_'):
continue
params[k] = v
request.environ[PARAMS_ENV] = params

View File

@ -44,84 +44,6 @@ class BaseApplication(wsgi.Application):
return json.dumps(result)
class TokenAuthMiddleware(wsgi.Middleware):
def process_request(self, request):
token = request.headers.get('X-Auth-Token')
context = request.environ.get('openstack.context', {})
context['token_id'] = token
request.environ['openstack.context'] = context
class AdminTokenAuthMiddleware(wsgi.Middleware):
"""A trivial filter that checks for a pre-defined admin token.
Sets 'is_admin' to true in the context, expected to be checked by
methods that are admin-only.
"""
def process_request(self, request):
token = request.headers.get('X-Auth-Token')
context = request.environ.get('openstack.context', {})
context['is_admin'] = (token == self.options['admin_token'])
request.environ['openstack.context'] = context
class PostParamsMiddleware(wsgi.Middleware):
"""Middleware to allow method arguments to be passed as POST parameters.
Filters out the parameters `self`, `context` and anything beginning with
an underscore.
"""
def process_request(self, request):
params_parsed = request.params
params = {}
for k, v in params_parsed.iteritems():
if k in ('self', 'context'):
continue
if k.startswith('_'):
continue
params[k] = v
request.environ['openstack.params'] = params
class JsonBodyMiddleware(wsgi.Middleware):
"""Middleware to allow method arguments to be passed as serialized JSON.
Accepting arguments as JSON is useful for accepting data that may be more
complex than simple primitives.
In this case we accept it as urlencoded data under the key 'json' as in
json=<urlencoded_json> but this could be extended to accept raw JSON
in the POST body.
Filters out the parameters `self`, `context` and anything beginning with
an underscore.
"""
def process_request(self, request):
#if 'json' not in request.params:
# return
params_json = request.body
if not params_json:
return
params_parsed = json.loads(params_json)
params = {}
for k, v in params_parsed.iteritems():
if k in ('self', 'context'):
continue
if k.startswith('_'):
continue
params[k] = v
request.environ['openstack.params'] = params
class TokenController(BaseApplication):
"""Validate and pass through calls to TokenManager."""
@ -169,51 +91,23 @@ class IdentityController(BaseApplication):
class Router(wsgi.Router):
def __init__(self, options):
self.options = options
token_controller = utils.import_object(
options['token_controller'],
options=options)
identity_controller = utils.import_object(
options['identity_controller'],
options=options)
self.identity_controller = IdentityController(options)
self.token_controller = TokenController(options)
mapper = routes.Mapper()
mapper.connect('/v2.0/tokens', controller=identity_controller,
mapper.connect('/v2.0/tokens',
controller=self.identity_controller,
action='authenticate')
mapper.connect('/v2.0/tokens/{token_id}', controller=token_controller,
mapper.connect('/v2.0/tokens/{token_id}',
controller=self.token_controller,
action='revoke_token',
conditions=dict(method=['DELETE']))
mapper.connect("/v2.0/tenants", controller=identity_controller,
action="get_tenants", conditions=dict(method=["GET"]))
mapper.connect("/v2.0/tenants",
controller=self.identity_controller,
action="get_tenants",
conditions=dict(method=["GET"]))
super(Router, self).__init__(mapper)
class AdminRouter(wsgi.Router):
def __init__(self, options):
self.options = options
token_controller = utils.import_object(
options['token_controller'],
options=options)
identity_controller = utils.import_object(
options['identity_controller'],
options=options)
mapper = routes.Mapper()
mapper.connect('/v2.0/tokens', controller=identity_controller,
action='authenticate')
mapper.connect('/v2.0/tokens/{token_id}', controller=token_controller,
action='validate_token',
conditions=dict(method=['GET']))
mapper.connect('/v2.0/tokens/{token_id}', controller=token_controller,
action='revoke_token',
conditions=dict(method=['DELETE']))
super(AdminRouter, self).__init__(mapper)
def identity_app_factory(global_conf, **local_conf):
conf = global_conf.copy()
conf.update(local_conf)
return Router(conf)
def app_factory(global_conf, **local_conf):
conf = global_conf.copy()
conf.update(local_conf)

View File

@ -24,13 +24,13 @@ catalog.RegionOne.compute.name = 'Compute Service'
paste.filter_factory = keystonelight.wsgi:Debug.factory
[filter:token_auth]
paste.filter_factory = keystonelight.service:TokenAuthMiddleware.factory
paste.filter_factory = keystonelight.middleware:TokenAuthMiddleware.factory
[filter:admin_token_auth]
paste.filter_factory = keystonelight.service:AdminTokenAuthMiddleware.factory
paste.filter_factory = keystonelight.middleware:AdminTokenAuthMiddleware.factory
[filter:json_body]
paste.filter_factory = keystonelight.service:JsonBodyMiddleware.factory
paste.filter_factory = keystonelight.middleware:JsonBodyMiddleware.factory
[app:keystonelight]
paste.app_factory = keystonelight.service:app_factory

166
tests/test_identity_api.py Normal file
View File

@ -0,0 +1,166 @@
import uuid
from keystonelight import models
from keystonelight import test
from keystonelight import utils
from keystonelight.backends import kvs
class IdentityApi(test.TestCase):
def setUp(self):
super(IdentityApi, self).setUp()
self.options = self.appconfig('default')
app = self.loadapp('default')
self.app = app
self.identity_backend = utils.import_object(
self.options['identity_driver'], options=self.options)
self.token_backend = utils.import_object(
self.options['token_driver'], options=self.options)
self.catalog_backend = utils.import_object(
self.options['catalog_driver'], options=self.options)
self._load_fixtures()
def _load_fixtures(self):
self.tenant_bar = self.identity_backend._create_tenant(
'bar',
models.Tenant(id='bar', name='BAR'))
self.user_foo = self.identity_backend._create_user(
'foo',
models.User(id='foo',
name='FOO',
password='foo2',
tenants=[self.tenant_bar['id']]))
self.extras_foobar = self.identity_backend._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)