From 9b6edcf6ca5aca45536fb6f5038068e506c9c673 Mon Sep 17 00:00:00 2001 From: wanghao Date: Tue, 2 Feb 2021 15:14:26 +0800 Subject: [PATCH] Support extra specs to subscription confirming Introduce "EXTRA-SPEC" request header to handling the extra information when confirming subscription. Developer could extend the tasks to support more functions. User needs to specify the task name in value of "EXTRA-SPEC". Change-Id: I9bca9a772d0f5a37c0d780c320ea2307c745a1e8 Implements: blueprint support-extra-specs-to-subscription-confirming --- lower-constraints.txt | 2 +- ...scription-confirming-edbdbebbdcd0cd74.yaml | 6 ++++ requirements.txt | 2 +- setup.cfg | 3 ++ zaqar/common/transport/wsgi/helpers.py | 29 +++++++++++++++++++ zaqar/extraspec/__init__.py | 0 zaqar/extraspec/tasks/__init__.py | 0 zaqar/extraspec/tasks/messagecode.py | 25 ++++++++++++++++ .../transport/wsgi/v2_0/test_subscriptions.py | 11 +++++++ zaqar/transport/middleware/auth.py | 6 ++-- zaqar/transport/wsgi/driver.py | 7 +++-- 11 files changed, 85 insertions(+), 6 deletions(-) create mode 100644 releasenotes/notes/support-extra-specs-to-subscription-confirming-edbdbebbdcd0cd74.yaml create mode 100644 zaqar/extraspec/__init__.py create mode 100644 zaqar/extraspec/tasks/__init__.py create mode 100644 zaqar/extraspec/tasks/messagecode.py diff --git a/lower-constraints.txt b/lower-constraints.txt index 2daf9db96..703e55483 100644 --- a/lower-constraints.txt +++ b/lower-constraints.txt @@ -22,7 +22,7 @@ os-client-config==1.28.0 oslo.cache==1.26.0 oslo.config==6.8.0 oslo.context==2.19.2 -oslo.db==6.0.0 +oslo.db==8.4.0 oslo.i18n==3.15.3 oslo.log==3.36.0 oslo.messaging==5.29.0 diff --git a/releasenotes/notes/support-extra-specs-to-subscription-confirming-edbdbebbdcd0cd74.yaml b/releasenotes/notes/support-extra-specs-to-subscription-confirming-edbdbebbdcd0cd74.yaml new file mode 100644 index 000000000..34c6e4877 --- /dev/null +++ b/releasenotes/notes/support-extra-specs-to-subscription-confirming-edbdbebbdcd0cd74.yaml @@ -0,0 +1,6 @@ +--- +features: + - Introduce a new request header called "EXTRA-SPEC" and driver mechanism + with stevedore to let developers to implement the task about how to deal + with this informtaion. In Wallaby, there's just an empty handler by + default. diff --git a/requirements.txt b/requirements.txt index 8b85e4f4c..e847a88c6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -18,7 +18,7 @@ stevedore>=1.20.0 # Apache-2.0 oslo.cache>=1.26.0 # Apache-2.0 oslo.config>=6.8.0 # Apache-2.0 oslo.context>=2.19.2 # Apache-2.0 -oslo.db>=6.0.0 # Apache-2.0 +oslo.db>=8.4.0 # Apache-2.0 oslo.i18n>=3.15.3 # Apache-2.0 oslo.log>=3.36.0 # Apache-2.0 oslo.messaging>=5.29.0 # Apache-2.0 diff --git a/setup.cfg b/setup.cfg index 33ffa71c7..989300795 100644 --- a/setup.cfg +++ b/setup.cfg @@ -77,6 +77,9 @@ zaqar.notification.tasks = trust+http = zaqar.notification.tasks.trust:TrustTask trust+https = zaqar.notification.tasks.trust:TrustTask +zaqar.extraspec.tasks = + messagecode = zaqar.extraspec.tasks.messagecode:MessageCodeAuthentication + oslo.policy.policies = zaqar = zaqar.common.policies:list_rules diff --git a/zaqar/common/transport/wsgi/helpers.py b/zaqar/common/transport/wsgi/helpers.py index 8ffd3e55f..3f1f9523e 100644 --- a/zaqar/common/transport/wsgi/helpers.py +++ b/zaqar/common/transport/wsgi/helpers.py @@ -17,6 +17,7 @@ from distutils import version import re +from stevedore import driver import uuid import falcon @@ -313,3 +314,31 @@ def validate_topic_identification(validate, req, resp, params): raise falcon.HTTPBadRequest(_(u'Invalid topic identification'), _(u'The format of the submitted topic ' u'name or project id is not valid.')) + + +def verify_extra_spec(req, resp, params): + """Extract `extra_spec` from request and verify it. + + Meant to be used as a `before` hook. + + :param req: request sent + :type req: falcon.request.Request + :param resp: response object to return + :type resp: falcon.response.Response + :param params: additional parameters passed to responders + :type params: dict + :rtype: None + """ + extra_spec = req.get_header('EXTRA-SPEC') + if not extra_spec: + return + + if extra_spec == "": + raise falcon.HTTPBadRequest('Empty extra spec not allowed', + _(u'Extra spec cannot be an empty ' + u'if specify the header.')) + extra_spec_schema = extra_spec.split(':')[0] + if extra_spec_schema: + mgr = driver.DriverManager('zaqar.extraspec.tasks', extra_spec_schema, + invoke_on_load=True) + mgr.driver.execute(extra_spec) diff --git a/zaqar/extraspec/__init__.py b/zaqar/extraspec/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/zaqar/extraspec/tasks/__init__.py b/zaqar/extraspec/tasks/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/zaqar/extraspec/tasks/messagecode.py b/zaqar/extraspec/tasks/messagecode.py new file mode 100644 index 000000000..6f875253f --- /dev/null +++ b/zaqar/extraspec/tasks/messagecode.py @@ -0,0 +1,25 @@ +# Copyright (c) 2021 Fiberhome Ltd +# +# 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 oslo_log import log as logging + +LOG = logging.getLogger(__name__) + + +class MessageCodeAuthentication(object): + + def execute(self, extra_spec): + # NOTE(wanghao): There need an implement by developers. + pass diff --git a/zaqar/tests/unit/transport/wsgi/v2_0/test_subscriptions.py b/zaqar/tests/unit/transport/wsgi/v2_0/test_subscriptions.py index f65bbef91..77c7d82e7 100644 --- a/zaqar/tests/unit/transport/wsgi/v2_0/test_subscriptions.py +++ b/zaqar/tests/unit/transport/wsgi/v2_0/test_subscriptions.py @@ -443,3 +443,14 @@ class TestSubscriptionsMongoDB(base.V2Base): doc = '{"confirmed": true}' self.simulate_put(self.confirm_path, body=doc, headers=self.headers) self.assertEqual(falcon.HTTP_404, self.srmock.status) + + def test_confirm_with_extra_spec(self): + self.headers['EXTRA-SPEC'] = 'messagecode:123456' + doc = '{"confirmed": true}' + resp = self._create_subscription() + resp_doc = jsonutils.loads(resp[0]) + confirm_path = (self.url_prefix + '/queues/' + self.queue + + '/subscriptions/' + resp_doc['subscription_id'] + + '/confirm') + self.simulate_put(confirm_path, body=doc, headers=self.headers) + self.assertEqual(falcon.HTTP_204, self.srmock.status) diff --git a/zaqar/transport/middleware/auth.py b/zaqar/transport/middleware/auth.py index 009177cc6..ef990beca 100644 --- a/zaqar/transport/middleware/auth.py +++ b/zaqar/transport/middleware/auth.py @@ -24,7 +24,7 @@ STRATEGIES = {} LOG = log.getLogger(__name__) -class SignedHeadersAuth(object): +class SignedAndExtraSpecHeadersAuth(object): def __init__(self, app, auth_app): self._app = app @@ -32,6 +32,7 @@ class SignedHeadersAuth(object): def __call__(self, environ, start_response): path = environ.get('PATH_INFO') + extra_spec = environ.get('HTTP_EXTRA_SPEC') # NOTE(flwang): The root path of Zaqar service shouldn't require any # auth. if path == '/': @@ -39,7 +40,8 @@ class SignedHeadersAuth(object): signature = environ.get('HTTP_URL_SIGNATURE') - if signature is None or path.startswith('/v1'): + if (signature is None and extra_spec is None) or \ + path.startswith('/v1'): return self._auth_app(environ, start_response) return self._app(environ, start_response) diff --git a/zaqar/transport/wsgi/driver.py b/zaqar/transport/wsgi/driver.py index ad3c9a19f..2457e655e 100644 --- a/zaqar/transport/wsgi/driver.py +++ b/zaqar/transport/wsgi/driver.py @@ -100,7 +100,10 @@ class Driver(transport.DriverBase): self._validate_queue_identification, # NOTE(kgriffs): Depends on project_id being extracted, above - self._validate_topic_identification + self._validate_topic_identification, + + # NOTE(wanghao): verify the extra specs if it is existing + helpers.verify_extra_spec ] def _init_routes(self): @@ -156,7 +159,7 @@ class Driver(transport.DriverBase): strategy = auth.strategy(self._conf.auth_strategy) auth_app = strategy.install(self.app, self._conf) - self.app = auth.SignedHeadersAuth(self.app, auth_app) + self.app = auth.SignedAndExtraSpecHeadersAuth(self.app, auth_app) # NOTE(wangxiyuan): Install CORS, this middleware should be called # before Keystone auth.