Making / and /v2 URLs allowed without auth
Closes-Bug: #1473963 Change-Id: I7170121a1216d9d72a43e552db1864a58e4c6237
This commit is contained in:
parent
e3bcac8e84
commit
e523f7537c
@ -15,7 +15,7 @@
|
|||||||
# How many seconds to wait for the API to be responding before giving up
|
# How many seconds to wait for the API to be responding before giving up
|
||||||
API_RESPONDING_TIMEOUT=20
|
API_RESPONDING_TIMEOUT=20
|
||||||
|
|
||||||
if ! timeout ${API_RESPONDING_TIMEOUT} sh -c "while ! curl -s http://127.0.0.1:8989/v2/ 2>/dev/null | grep -q 'Authentication required' ; do sleep 1; done"; then
|
if ! timeout ${API_RESPONDING_TIMEOUT} sh -c "until curl --output /dev/null --silent --head --fail http://localhost:8989; do sleep 1; done"; then
|
||||||
echo "Mistral API failed to respond within ${API_RESPONDING_TIMEOUT} seconds"
|
echo "Mistral API failed to respond within ${API_RESPONDING_TIMEOUT} seconds"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
@ -25,7 +25,12 @@ _ENFORCER = None
|
|||||||
|
|
||||||
def setup(app):
|
def setup(app):
|
||||||
if cfg.CONF.pecan.auth_enable:
|
if cfg.CONF.pecan.auth_enable:
|
||||||
return auth_token.AuthProtocol(app, dict(cfg.CONF.keystone_authtoken))
|
conf = dict(cfg.CONF.keystone_authtoken)
|
||||||
|
|
||||||
|
# Change auth decisions of requests to the app itself.
|
||||||
|
conf.update({'delay_auth_decision': True})
|
||||||
|
|
||||||
|
return auth_token.AuthProtocol(app, conf)
|
||||||
else:
|
else:
|
||||||
return app
|
return app
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ def setup_app(config=None):
|
|||||||
|
|
||||||
app = pecan.make_app(
|
app = pecan.make_app(
|
||||||
app_conf.pop('root'),
|
app_conf.pop('root'),
|
||||||
hooks=lambda: [ctx.ContextHook()],
|
hooks=lambda: [ctx.ContextHook(), ctx.AuthHook()],
|
||||||
logging=getattr(config, 'logging', {}),
|
logging=getattr(config, 'logging', {}),
|
||||||
**app_conf
|
**app_conf
|
||||||
)
|
)
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
#
|
#
|
||||||
# Copyright 2013 - Mirantis, Inc.
|
# Copyright 2013 - Mirantis, Inc.
|
||||||
#
|
#
|
||||||
@ -19,6 +18,7 @@ from keystoneclient.v3 import client as keystone_client
|
|||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
import oslo_messaging as messaging
|
import oslo_messaging as messaging
|
||||||
from oslo_serialization import jsonutils
|
from oslo_serialization import jsonutils
|
||||||
|
import pecan
|
||||||
from pecan import hooks
|
from pecan import hooks
|
||||||
|
|
||||||
from mistral import exceptions as exc
|
from mistral import exceptions as exc
|
||||||
@ -28,6 +28,7 @@ from mistral import utils
|
|||||||
CONF = cfg.CONF
|
CONF = cfg.CONF
|
||||||
|
|
||||||
_CTX_THREAD_LOCAL_NAME = "MISTRAL_APP_CTX_THREAD_LOCAL"
|
_CTX_THREAD_LOCAL_NAME = "MISTRAL_APP_CTX_THREAD_LOCAL"
|
||||||
|
ALLOWED_WITHOUT_AUTH = ['/', '/v2/']
|
||||||
|
|
||||||
|
|
||||||
class BaseContext(object):
|
class BaseContext(object):
|
||||||
@ -157,7 +158,6 @@ class JsonPayloadSerializer(messaging.NoOpSerializer):
|
|||||||
|
|
||||||
|
|
||||||
class RpcContextSerializer(messaging.Serializer):
|
class RpcContextSerializer(messaging.Serializer):
|
||||||
|
|
||||||
def __init__(self, base=None):
|
def __init__(self, base=None):
|
||||||
self._base = base or messaging.NoOpSerializer()
|
self._base = base or messaging.NoOpSerializer()
|
||||||
|
|
||||||
@ -183,6 +183,33 @@ class RpcContextSerializer(messaging.Serializer):
|
|||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
|
|
||||||
|
class AuthHook(hooks.PecanHook):
|
||||||
|
def before(self, state):
|
||||||
|
if state.request.path in ALLOWED_WITHOUT_AUTH:
|
||||||
|
return
|
||||||
|
|
||||||
|
if CONF.pecan.auth_enable:
|
||||||
|
# Note(nmakhotkin): Since we have deferred authentication,
|
||||||
|
# need to check for auth manually (check for corresponding
|
||||||
|
# headers according to keystonemiddleware docs.
|
||||||
|
identity_status = state.request.headers.get('X-Identity-Status')
|
||||||
|
service_identity_status = state.request.headers.get(
|
||||||
|
'X-Service-Identity-Status'
|
||||||
|
)
|
||||||
|
|
||||||
|
if (identity_status == 'Confirmed'
|
||||||
|
or service_identity_status == 'Confirmed'):
|
||||||
|
return
|
||||||
|
|
||||||
|
if state.request.headers.get('X-Auth-Token'):
|
||||||
|
msg = ("Auth token is invalid: %s"
|
||||||
|
% state.request.headers['X-Auth-Token'])
|
||||||
|
else:
|
||||||
|
msg = 'Authentication required'
|
||||||
|
|
||||||
|
pecan.abort(status_code=401, detail=msg)
|
||||||
|
|
||||||
|
|
||||||
class ContextHook(hooks.PecanHook):
|
class ContextHook(hooks.PecanHook):
|
||||||
def before(self, state):
|
def before(self, state):
|
||||||
set_ctx(context_from_headers(state.request.headers))
|
set_ctx(context_from_headers(state.request.headers))
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
from oslo_serialization import jsonutils
|
from oslo_serialization import jsonutils
|
||||||
|
|
||||||
from mistral.tests.unit.api import base
|
from mistral.tests.unit.api import base
|
||||||
|
from mistral.tests.unit.api import test_auth
|
||||||
|
|
||||||
|
|
||||||
class TestRootController(base.FunctionalTest):
|
class TestRootController(base.FunctionalTest):
|
||||||
@ -32,3 +33,43 @@ class TestRootController(base.FunctionalTest):
|
|||||||
data[0]['link'],
|
data[0]['link'],
|
||||||
{'href': 'http://localhost/v2', 'target': 'v2'}
|
{'href': 'http://localhost/v2', 'target': 'v2'}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_v2_root(self):
|
||||||
|
resp = self.app.get('/v2/', headers={'Accept': 'application/json'})
|
||||||
|
|
||||||
|
self.assertEqual(resp.status_int, 200)
|
||||||
|
|
||||||
|
data = jsonutils.loads(resp.body.decode())
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
'http://localhost/v2',
|
||||||
|
data['uri']
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TestRootControllerWithAuth(test_auth.TestKeystoneMiddleware):
|
||||||
|
def test_index(self):
|
||||||
|
resp = self.app.get('/', headers={'Accept': 'application/json'})
|
||||||
|
|
||||||
|
self.assertEqual(resp.status_int, 200)
|
||||||
|
|
||||||
|
data = jsonutils.loads(resp.body.decode())
|
||||||
|
|
||||||
|
self.assertEqual(data[0]['id'], 'v2.0')
|
||||||
|
self.assertEqual(data[0]['status'], 'CURRENT')
|
||||||
|
self.assertEqual(
|
||||||
|
data[0]['link'],
|
||||||
|
{'href': 'http://localhost/v2', 'target': 'v2'}
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_v2_root(self):
|
||||||
|
resp = self.app.get('/v2/', headers={'Accept': 'application/json'})
|
||||||
|
|
||||||
|
self.assertEqual(resp.status_int, 200)
|
||||||
|
|
||||||
|
data = jsonutils.loads(resp.body.decode())
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
'http://localhost/v2',
|
||||||
|
data['uri']
|
||||||
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user