Split webhook middleware from webhooks module
Change-Id: I3c7ff59ea1d22fd9b5ee6e4d96b5a56f1b26e58c
This commit is contained in:
parent
69e39f6b8b
commit
f4ae261d89
|
@ -1,7 +1,7 @@
|
|||
|
||||
# senlin-api pipeline
|
||||
[pipeline:senlin-api]
|
||||
pipeline = request_id faultwrap ssl versionnegotiation authtoken context trust apiv1app
|
||||
pipeline = request_id faultwrap ssl versionnegotiation webhook authtoken context trust apiv1app
|
||||
|
||||
[app:apiv1app]
|
||||
paste.app_factory = senlin.common.wsgi:app_factory
|
||||
|
@ -31,6 +31,10 @@ senlin.filter_factory = senlin.api.openstack:version_negotiation_filter
|
|||
paste.filter_factory = senlin.common.wsgi:filter_factory
|
||||
senlin.filter_factory = senlin.api.openstack:trustmiddleware_filter
|
||||
|
||||
[filter:webhook]
|
||||
paste.filter_factory = senlin.common.wsgi:filter_factory
|
||||
senlin.filter_factory = senlin.api.openstack:webhookmiddleware_filter
|
||||
|
||||
# Auth middleware that validates token against keystone
|
||||
[filter:authtoken]
|
||||
paste.filter_factory = keystonemiddleware.auth_token:filter_factory
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
# 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
|
||||
|
||||
from senlin.common import context
|
||||
from senlin.common import exception
|
||||
from senlin.common.i18n import _
|
||||
from senlin.common import utils
|
||||
from senlin.common import wsgi
|
||||
from senlin.drivers.openstack import sdk
|
||||
from senlin.webhooks import webhooks
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class WebhookMiddleware(wsgi.Middleware):
|
||||
'''Middleware to do authentication for webhook triggering
|
||||
|
||||
This middleware gets authentication for request to a webhook
|
||||
based on information embedded inside url and then rebuild the
|
||||
request header.
|
||||
'''
|
||||
def process_request(self, req):
|
||||
self._authenticate(req)
|
||||
|
||||
def _authenticate(self, req):
|
||||
LOG.debug("Checking credentials of webhook request")
|
||||
credential = self._get_credential(req)
|
||||
if not credential:
|
||||
return
|
||||
|
||||
# Get a valid token based on credential
|
||||
# and fill into the request header
|
||||
token_id = self._get_token(credential)
|
||||
req.headers['X-Auth-Token'] = token_id
|
||||
|
||||
def _get_credential(self, req):
|
||||
try:
|
||||
url_bottom = req.url.rsplit('webhooks')[1]
|
||||
webhook_id = url_bottom.rsplit('/')[1]
|
||||
trigger = url_bottom.rsplit('/')[2].startswith('trigger')
|
||||
if trigger is not True or 'key' not in req.params:
|
||||
raise Exception()
|
||||
except Exception:
|
||||
LOG.debug(_("%(url)s is not a webhook trigger url,"
|
||||
" pass."), {'url': req.url})
|
||||
return
|
||||
|
||||
if req.method != 'POST':
|
||||
LOG.debug(_("Not a post request to webhook trigger url"
|
||||
" %(url)s, pass."), {'url': req.url})
|
||||
return
|
||||
|
||||
# This is a webhook triggering, we need to fill in valid
|
||||
# credential info into the http headers to ensure this
|
||||
# request can pass keystone auth_token validation.
|
||||
#
|
||||
# Get the credential stored in DB based on webhook ID.
|
||||
# TODO(Anyone): Use Barbican to store these credential.
|
||||
LOG.debug(_("Get credential of webhook %(id)s"), webhook_id)
|
||||
senlin_context = context.RequestContext.get_service_context()
|
||||
webhook_obj = webhooks.Webhook.load(senlin_context, webhook_id)
|
||||
credential = webhook_obj.credential
|
||||
credential['webhook_id'] = webhook_id
|
||||
|
||||
# Decrypt the credential password with key embedded in req params
|
||||
try:
|
||||
password = utils.decrypt(credential['password'],
|
||||
req.params['key'])
|
||||
credential['password'] = password
|
||||
except Exception:
|
||||
msg = 'Invalid key for webhook(%s) credential decryption' % \
|
||||
webhook_id
|
||||
LOG.error(msg)
|
||||
raise exception.SenlinBadRequest(msg=msg)
|
||||
|
||||
return credential
|
||||
|
||||
def _get_token(self, credential):
|
||||
'''Get a valid token based on credential'''
|
||||
|
||||
try:
|
||||
access_info = sdk.authenticate(**credential)
|
||||
token_id = access_info.auth_token
|
||||
except Exception as ex:
|
||||
msg = 'Webhook get token failed: %s' % ex.message
|
||||
LOG.error(msg)
|
||||
raise exception.WebhookCredentialInvalid(
|
||||
webhook=credential['webhook_id'])
|
||||
|
||||
# Get token successfully!
|
||||
return token_id
|
|
@ -16,6 +16,7 @@ from senlin.api.middleware import fault
|
|||
from senlin.api.middleware import ssl
|
||||
from senlin.api.middleware import trust
|
||||
from senlin.api.middleware import version_negotiation as vn
|
||||
from senlin.api.middleware import webhook
|
||||
from senlin.api.openstack import versions
|
||||
|
||||
|
||||
|
@ -38,3 +39,7 @@ def contextmiddleware_filter(app, conf, **local_conf):
|
|||
|
||||
def trustmiddleware_filter(app, conf, **local_conf):
|
||||
return trust.TrustMiddleware(app)
|
||||
|
||||
|
||||
def webhookmiddleware_filter(app, conf, **local_conf):
|
||||
return webhook.WebhookMiddleware(app)
|
||||
|
|
|
@ -15,15 +15,11 @@ import datetime
|
|||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
|
||||
from senlin.common import context
|
||||
from senlin.common import exception
|
||||
from senlin.common.i18n import _
|
||||
from senlin.common.i18n import _LE
|
||||
from senlin.common.i18n import _LI
|
||||
from senlin.common import utils
|
||||
from senlin.common import wsgi
|
||||
from senlin.db import api as db_api
|
||||
from senlin.drivers.openstack import sdk
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
@ -180,94 +176,3 @@ class Webhook(object):
|
|||
@classmethod
|
||||
def delete(cls, context, webhook_id):
|
||||
db_api.webhook_delete(context, webhook_id)
|
||||
|
||||
|
||||
class WebhookMiddleware(wsgi.Middleware):
|
||||
'''Middleware to do authentication for webhook triggering
|
||||
|
||||
This middleware gets authentication for request to a webhook
|
||||
based on information embedded inside url and then rebuild the
|
||||
request header.
|
||||
'''
|
||||
def process_request(self, req):
|
||||
self._authenticate(req)
|
||||
|
||||
def _authenticate(self, req):
|
||||
LOG.debug("Checking credentials of webhook request")
|
||||
credential = self._get_credential(req)
|
||||
if not credential:
|
||||
return
|
||||
|
||||
# Get a valid token based on credential
|
||||
# and fill into the request header
|
||||
token_id = self._get_token(credential)
|
||||
req.headers['X-Auth-Token'] = token_id
|
||||
|
||||
def _get_credential(self, req):
|
||||
try:
|
||||
url_bottom = req.url.rsplit('webhooks')[1]
|
||||
webhook_id = url_bottom.rsplit('/')[1]
|
||||
trigger = url_bottom.rsplit('/')[2].startswith('trigger')
|
||||
if trigger is not True or 'key' not in req.params:
|
||||
raise Exception()
|
||||
except Exception:
|
||||
LOG.debug(_("%(url)s is not a webhook trigger url,"
|
||||
" pass."), {'url': req.url})
|
||||
return
|
||||
|
||||
if req.method != 'POST':
|
||||
LOG.debug(_("Not a post request to webhook trigger url"
|
||||
" %(url)s, pass."), {'url': req.url})
|
||||
return
|
||||
|
||||
# This is a webhook triggering, we need to fill in valid
|
||||
# credential info into the http headers to ensure this
|
||||
# request can pass keystone auth_token validation.
|
||||
#
|
||||
# Get the credential stored in DB based on webhook ID.
|
||||
# TODO(Anyone): Use Barbican to store these credential.
|
||||
LOG.debug(_("Get credential of webhook %(id)s"), webhook_id)
|
||||
senlin_context = context.RequestContext.get_service_context()
|
||||
webhook_obj = Webhook.load(senlin_context, webhook_id)
|
||||
credential = webhook_obj.credential
|
||||
credential['webhook_id'] = webhook_id
|
||||
|
||||
# Decrypt the credential password with key embedded in req params
|
||||
try:
|
||||
password = utils.decrypt(credential['password'],
|
||||
req.params['key'])
|
||||
credential['password'] = password
|
||||
except Exception:
|
||||
msg = 'Invalid key for webhook(%s) credential decryption' % \
|
||||
webhook_id
|
||||
LOG.error(msg)
|
||||
raise exception.SenlinBadRequest(msg=msg)
|
||||
|
||||
return credential
|
||||
|
||||
def _get_token(self, credential):
|
||||
'''Get a valid token based on credential'''
|
||||
|
||||
try:
|
||||
access_info = sdk.authenticate(**credential)
|
||||
token_id = access_info.auth_token
|
||||
except Exception as ex:
|
||||
msg = 'Webhook get token failed: %s' % ex.message
|
||||
LOG.error(msg)
|
||||
raise exception.WebhookCredentialInvalid(
|
||||
webhook=credential['webhook_id'])
|
||||
|
||||
# Get token successfully!
|
||||
return token_id
|
||||
|
||||
|
||||
def WebhookMiddleware_filter_factory(global_conf, **local_conf):
|
||||
'''Factory method for paste.deploy.'''
|
||||
|
||||
conf = global_conf.copy()
|
||||
conf.update(local_conf)
|
||||
|
||||
def filter(app):
|
||||
return WebhookMiddleware(app)
|
||||
|
||||
return filter
|
||||
|
|
Loading…
Reference in New Issue