Wrap transport's app with keystoneclient's middleware

Instead of using paste and depending on the middleware chain, use
ceilomenter's strategy and wrap transport's app using the auth_token
middleware.

NOTE: Tests with successful auth are missing

Implements blueprint remove-paste
Change-Id: I61e7d1fae6b80114e22c0a43b4e391e2d5443123
This commit is contained in:
Flaper Fesp 2013-06-05 15:33:37 +02:00
parent 18f83cbc94
commit 60026a73ea
10 changed files with 165 additions and 20 deletions

View File

@ -1,6 +1,7 @@
[DEFAULT]
; debug = False
; verbose = False
; auth_strategy =
[drivers]
;transport = marconi.transport.wsgi, marconi.transport.zmq

View File

@ -1,14 +0,0 @@
[pipeline:main]
pipeline = authtoken marconi
[filter:authtoken]
paste.filter_factory = keystoneclient.middleware.auth_token:filter_factory
auth_host = 127.0.0.1
auth_port = 35357
auth_protocol = https
admin_tenant_name = %SERVICE_TENANT_NAME%
admin_user = %SERVICE_USER%
admin_password = %SERVICE_PASSWORD%
[app:marconi]
paste.app_factory = marconi.transport.wsgi.app:app

View File

@ -145,7 +145,7 @@ def _init():
else:
conf(args=args, default_config_files=[filename])
return Obj(from_options=from_options, load=load)
return Obj(from_options=from_options, load=load, conf=conf)
def opaque_type_of(base, postfix):
return type('%s of %s' % (base.__name__, postfix), (base,), {})

View File

@ -0,0 +1,11 @@
[DEFAULT]
auth_strategy = keystone
[drivers]
transport = marconi.transport.wsgi
storage = marconi.storage.sqlite
[drivers:transport:wsgi]
bind = 0.0.0.0:8888
workers = 20

View File

@ -0,0 +1,37 @@
# Copyright (c) 2013 Red Hat, Inc.
#
# 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.
"""Test Auth."""
from oslo.config import cfg
from marconi.common import config
from marconi.tests import util
from marconi.transport import auth
class TestTransportAuth(util.TestBase):
def setUp(self):
super(TestTransportAuth, self).setUp()
self.cfg = config.project('marconi')
def tearDown(self):
super(TestTransportAuth, self).tearDown()
self.cfg.conf = cfg.ConfigOpts()
def test_configs(self):
auth.strategy("keystone")._register_opts(self.cfg.conf)
self.assertIn("keystone_authtoken", self.cfg.conf)
self.assertIn("keystone_authtoken", dir(self.cfg.from_options()))

View File

@ -0,0 +1,42 @@
# Copyright (c) 2013 Red Hat, Inc.
#
# 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.
"""Test Auth."""
import falcon
from falcon import testing
from keystoneclient.middleware import auth_token
from marconi.tests.transport.wsgi import base
class TestWSGIAuth(base.TestBase):
config_filename = 'keystone_auth.conf'
def setUp(self):
super(TestWSGIAuth, self).setUp()
self.headers = {'Client-ID': '30387f00'}
def test_auth_install(self):
self.assertTrue(isinstance(self.app,
auth_token.AuthProtocol))
def test_non_authenticated(self):
env = testing.create_environ('/v1/480924/queues/',
method="GET",
headers=self.headers)
self.app(env, self.srmock)
self.assertEquals(self.srmock.status, falcon.HTTP_401)

View File

@ -1,7 +1,13 @@
"""Marconi Transport Drivers"""
from marconi.common import config
from marconi.transport import base
OPTIONS = {
"auth_strategy": ""
}
cfg = config.project('marconi').from_options(**OPTIONS)
MAX_QUEUE_METADATA_SIZE = 64 * 1024
"""Maximum metadata size per queue when serialized as JSON"""

55
marconi/transport/auth.py Normal file
View File

@ -0,0 +1,55 @@
# Copyright (c) 2013 Red Hat, Inc.
#
# 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.
"""Middleware for handling authorization and authentication."""
from keystoneclient.middleware import auth_token
STRATEGIES = {}
class KeystoneAuth(object):
OPT_GROUP_NAME = 'keystone_authtoken'
@classmethod
def _register_opts(cls, conf):
"""Register keystoneclient middleware options."""
if cls.OPT_GROUP_NAME not in conf:
conf.register_opts(auth_token.opts, group=cls.OPT_GROUP_NAME)
auth_token.CONF = conf
@classmethod
def install(cls, app, conf):
"""Install Auth check on application."""
cls._register_opts(conf)
conf = dict(conf.get(cls.OPT_GROUP_NAME))
return auth_token.AuthProtocol(app, conf=conf)
STRATEGIES["keystone"] = KeystoneAuth
def strategy(strategy):
"""Returns the Auth Strategy.
:param strategy: String representing
the strategy to use
"""
try:
return STRATEGIES[strategy]
except KeyError:
raise RuntimeError

View File

@ -19,6 +19,7 @@ from wsgiref import simple_server
from marconi.common import config
import marconi.openstack.common.log as logging
from marconi import transport
from marconi.transport import auth
from marconi.transport.wsgi import claims
from marconi.transport.wsgi import messages
from marconi.transport.wsgi import queues
@ -29,7 +30,9 @@ OPTIONS = {
'port': 8888
}
cfg = config.namespace('drivers:transport:wsgi').from_options(**OPTIONS)
pconfig = config.project('marconi')
gcfg = pconfig.from_options()
lcfg = config.namespace('drivers:transport:wsgi').from_options(**OPTIONS)
LOG = logging.getLogger(__name__)
@ -73,9 +76,14 @@ class Driver(transport.DriverBase):
self.app.add_route('/v1/{project_id}/queues/{queue_name}'
'/claims/{claim_id}', claim_item)
# NOTE(flaper87): Install Auth
if gcfg.auth_strategy:
strategy = auth.strategy(gcfg.auth_strategy)
self.app = strategy.install(self.app, pconfig.conf)
def listen(self):
msg = _("Serving on host %(bind)s:%(port)s") % {"bind": cfg.bind,
"port": cfg.port}
msg = _("Serving on host %(bind)s:%(port)s") % {"bind": lcfg.bind,
"port": lcfg.port}
LOG.debug(msg)
httpd = simple_server.make_server(cfg.bind, cfg.port, self.app)
httpd = simple_server.make_server(lcfg.bind, lcfg.port, self.app)
httpd.serve_forever()

View File

@ -4,7 +4,6 @@ falcon>=0.1.4
iso8601>=0.1.4
msgpack-python
oslo.config>=1.1.0
PasteDeploy
pymongo
python-keystoneclient
simplejson