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
This commit is contained in:
wanghao 2021-02-02 15:14:26 +08:00
parent 6b6d90c3b7
commit 9b6edcf6ca
11 changed files with 85 additions and 6 deletions

View File

@ -22,7 +22,7 @@ os-client-config==1.28.0
oslo.cache==1.26.0 oslo.cache==1.26.0
oslo.config==6.8.0 oslo.config==6.8.0
oslo.context==2.19.2 oslo.context==2.19.2
oslo.db==6.0.0 oslo.db==8.4.0
oslo.i18n==3.15.3 oslo.i18n==3.15.3
oslo.log==3.36.0 oslo.log==3.36.0
oslo.messaging==5.29.0 oslo.messaging==5.29.0

View File

@ -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.

View File

@ -18,7 +18,7 @@ stevedore>=1.20.0 # Apache-2.0
oslo.cache>=1.26.0 # Apache-2.0 oslo.cache>=1.26.0 # Apache-2.0
oslo.config>=6.8.0 # Apache-2.0 oslo.config>=6.8.0 # Apache-2.0
oslo.context>=2.19.2 # 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.i18n>=3.15.3 # Apache-2.0
oslo.log>=3.36.0 # Apache-2.0 oslo.log>=3.36.0 # Apache-2.0
oslo.messaging>=5.29.0 # Apache-2.0 oslo.messaging>=5.29.0 # Apache-2.0

View File

@ -77,6 +77,9 @@ zaqar.notification.tasks =
trust+http = zaqar.notification.tasks.trust:TrustTask trust+http = zaqar.notification.tasks.trust:TrustTask
trust+https = zaqar.notification.tasks.trust:TrustTask trust+https = zaqar.notification.tasks.trust:TrustTask
zaqar.extraspec.tasks =
messagecode = zaqar.extraspec.tasks.messagecode:MessageCodeAuthentication
oslo.policy.policies = oslo.policy.policies =
zaqar = zaqar.common.policies:list_rules zaqar = zaqar.common.policies:list_rules

View File

@ -17,6 +17,7 @@
from distutils import version from distutils import version
import re import re
from stevedore import driver
import uuid import uuid
import falcon import falcon
@ -313,3 +314,31 @@ def validate_topic_identification(validate, req, resp, params):
raise falcon.HTTPBadRequest(_(u'Invalid topic identification'), raise falcon.HTTPBadRequest(_(u'Invalid topic identification'),
_(u'The format of the submitted topic ' _(u'The format of the submitted topic '
u'name or project id is not valid.')) 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)

View File

View File

View File

@ -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

View File

@ -443,3 +443,14 @@ class TestSubscriptionsMongoDB(base.V2Base):
doc = '{"confirmed": true}' doc = '{"confirmed": true}'
self.simulate_put(self.confirm_path, body=doc, headers=self.headers) self.simulate_put(self.confirm_path, body=doc, headers=self.headers)
self.assertEqual(falcon.HTTP_404, self.srmock.status) 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)

View File

@ -24,7 +24,7 @@ STRATEGIES = {}
LOG = log.getLogger(__name__) LOG = log.getLogger(__name__)
class SignedHeadersAuth(object): class SignedAndExtraSpecHeadersAuth(object):
def __init__(self, app, auth_app): def __init__(self, app, auth_app):
self._app = app self._app = app
@ -32,6 +32,7 @@ class SignedHeadersAuth(object):
def __call__(self, environ, start_response): def __call__(self, environ, start_response):
path = environ.get('PATH_INFO') path = environ.get('PATH_INFO')
extra_spec = environ.get('HTTP_EXTRA_SPEC')
# NOTE(flwang): The root path of Zaqar service shouldn't require any # NOTE(flwang): The root path of Zaqar service shouldn't require any
# auth. # auth.
if path == '/': if path == '/':
@ -39,7 +40,8 @@ class SignedHeadersAuth(object):
signature = environ.get('HTTP_URL_SIGNATURE') 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._auth_app(environ, start_response)
return self._app(environ, start_response) return self._app(environ, start_response)

View File

@ -100,7 +100,10 @@ class Driver(transport.DriverBase):
self._validate_queue_identification, self._validate_queue_identification,
# NOTE(kgriffs): Depends on project_id being extracted, above # 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): def _init_routes(self):
@ -156,7 +159,7 @@ class Driver(transport.DriverBase):
strategy = auth.strategy(self._conf.auth_strategy) strategy = auth.strategy(self._conf.auth_strategy)
auth_app = strategy.install(self.app, self._conf) 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 # NOTE(wangxiyuan): Install CORS, this middleware should be called
# before Keystone auth. # before Keystone auth.