Merge "Integrating monasca-api with keystonemiddleware"
This commit is contained in:
commit
4c54a95d54
@ -18,7 +18,7 @@ dispatcher = v2_ref_notifications
|
||||
|
||||
[security]
|
||||
# The roles that are allowed full access to the API.
|
||||
default_authorized_roles = admin
|
||||
default_authorized_roles = admin,monasca-user
|
||||
|
||||
# The roles that are allowed to only POST metrics to the API. This role would be used by the Monasca Agent.
|
||||
agent_authorized_roles = agent
|
||||
@ -113,4 +113,15 @@ database_name = mon
|
||||
database_name = mon
|
||||
hostname = 192.168.10.4
|
||||
username = monapi
|
||||
password = password
|
||||
password = password
|
||||
|
||||
[keystone_authtoken]
|
||||
identity_uri = http://192.168.10.5:35357
|
||||
auth_uri = http://192.168.10.5:5000
|
||||
admin_password = admin
|
||||
admin_user = admin
|
||||
admin_tenant_name = admin
|
||||
cafile =
|
||||
certfile =
|
||||
keyfile =
|
||||
insecure = false
|
||||
|
@ -3,7 +3,7 @@ name = monasca
|
||||
|
||||
[pipeline:main]
|
||||
# Add validator in the pipeline so the metrics messages can be validated.
|
||||
pipeline = auth api
|
||||
pipeline = auth keystonecontext api
|
||||
|
||||
[app:api]
|
||||
paste.app_factory = monasca.api.server:api_app
|
||||
@ -18,11 +18,14 @@ use = egg: monasca_api#inspector
|
||||
use = egg: monasca_api#metric_validator
|
||||
|
||||
[filter:auth]
|
||||
use = egg: monasca_api#mock_auth_filter
|
||||
paste.filter_factory = keystonemiddleware.auth_token:filter_factory
|
||||
|
||||
[filter:keystonecontext]
|
||||
paste.filter_factory = monasca.middleware.keystone_context_filter:filter_factory
|
||||
|
||||
[server:main]
|
||||
use = egg:gunicorn#main
|
||||
host = 0.0.0.0
|
||||
port = 9000
|
||||
workers = 1
|
||||
proc_name = monasca
|
||||
proc_name = monasca
|
||||
|
84
monasca/middleware/context.py
Normal file
84
monasca/middleware/context.py
Normal file
@ -0,0 +1,84 @@
|
||||
# Copyright (c) 2015 OpenStack Foundation
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""RequestContext: context for requests that persist through monasca."""
|
||||
|
||||
import uuid
|
||||
|
||||
from oslo.utils import timeutils
|
||||
|
||||
from monasca.openstack.common import log
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class RequestContext(object):
|
||||
"""Security context and request information.
|
||||
|
||||
Represents the user taking a given action within the system.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, user_id, project_id, domain_id=None, domain_name=None,
|
||||
roles=None, timestamp=None, request_id=None,
|
||||
auth_token=None, user_name=None, project_name=None,
|
||||
service_catalog=None, user_auth_plugin=None, **kwargs):
|
||||
"""Creates the Keystone Context. Supports additional parameters:
|
||||
|
||||
:param user_auth_plugin:
|
||||
The auth plugin for the current request's authentication data.
|
||||
:param kwargs:
|
||||
Extra arguments that might be present
|
||||
"""
|
||||
if kwargs:
|
||||
LOG.warning(
|
||||
'Arguments dropped when creating context: %s') % str(kwargs)
|
||||
|
||||
self._roles = roles or []
|
||||
self.timestamp = timeutils.utcnow()
|
||||
|
||||
if not request_id:
|
||||
request_id = self.generate_request_id()
|
||||
self._request_id = request_id
|
||||
self._auth_token = auth_token
|
||||
|
||||
self._service_catalog = service_catalog
|
||||
|
||||
self._domain_id = domain_id
|
||||
self._domain_name = domain_name
|
||||
|
||||
self._user_id = user_id
|
||||
self._user_name = user_name
|
||||
|
||||
self._project_id = project_id
|
||||
self._project_name = project_name
|
||||
|
||||
self._user_auth_plugin = user_auth_plugin
|
||||
|
||||
def to_dict(self):
|
||||
return {'user_id': self._user_id,
|
||||
'project_id': self._project_id,
|
||||
'domain_id': self._domain_id,
|
||||
'domain_name': self._domain_name,
|
||||
'roles': self._roles,
|
||||
'timestamp': timeutils.strtime(self._timestamp),
|
||||
'request_id': self._request_id,
|
||||
'auth_token': self._auth_token,
|
||||
'user_name': self._user_name,
|
||||
'service_catalog': self._service_catalog,
|
||||
'project_name': self._project_name,
|
||||
'user': self._user}
|
||||
|
||||
def generate_request_id(self):
|
||||
return b'req-' + str(uuid.uuid4()).encode('ascii')
|
111
monasca/middleware/keystone_context_filter.py
Normal file
111
monasca/middleware/keystone_context_filter.py
Normal file
@ -0,0 +1,111 @@
|
||||
# Copyright (c) 2015 OpenStack Foundation
|
||||
#
|
||||
# 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.
|
||||
|
||||
import falcon
|
||||
|
||||
from monasca.middleware import context
|
||||
from monasca.openstack.common import log
|
||||
|
||||
from oslo.middleware import request_id
|
||||
from oslo.serialization import jsonutils
|
||||
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
def filter_factory(global_conf, **local_conf):
|
||||
|
||||
def validator_filter(app):
|
||||
return KeystoneContextFilter(app, local_conf)
|
||||
return validator_filter
|
||||
|
||||
|
||||
class KeystoneContextFilter(object):
|
||||
"""Make a request context from keystone headers."""
|
||||
|
||||
def __init__(self, app, conf):
|
||||
self._app = app
|
||||
self._conf = conf
|
||||
|
||||
def __call__(self, env, start_response):
|
||||
|
||||
LOG.debug("Creating Keystone Context Object.")
|
||||
|
||||
user_id = env.get('HTTP_X_USER_ID', env.get('HTTP_X_USER'))
|
||||
if user_id is None:
|
||||
msg = "Neither X_USER_ID nor X_USER found in request"
|
||||
LOG.error(msg)
|
||||
raise falcon.HTTPUnauthorized(title='Forbidden', description=msg)
|
||||
|
||||
roles = self._get_roles(env)
|
||||
|
||||
project_id = env.get('HTTP_X_PROJECT_ID')
|
||||
project_name = env.get('HTTP_X_PROJECT_NAME')
|
||||
|
||||
domain_id = env.get('HTTP_X_DOMAIN_ID')
|
||||
domain_name = env.get('HTTP_X_DOMAIN_NAME')
|
||||
|
||||
user_name = env.get('HTTP_X_USER_NAME')
|
||||
|
||||
req_id = env.get(request_id.ENV_REQUEST_ID)
|
||||
|
||||
# Get the auth token
|
||||
auth_token = env.get('HTTP_X_AUTH_TOKEN',
|
||||
env.get('HTTP_X_STORAGE_TOKEN'))
|
||||
|
||||
service_catalog = None
|
||||
if env.get('HTTP_X_SERVICE_CATALOG') is not None:
|
||||
try:
|
||||
catalog_header = env.get('HTTP_X_SERVICE_CATALOG')
|
||||
service_catalog = jsonutils.loads(catalog_header)
|
||||
except ValueError:
|
||||
msg = "Invalid service catalog json."
|
||||
LOG.error(msg)
|
||||
raise falcon.HTTPInternalServerError(msg)
|
||||
|
||||
# NOTE(jamielennox): This is a full auth plugin set by auth_token
|
||||
# middleware in newer versions.
|
||||
user_auth_plugin = env.get('keystone.token_auth')
|
||||
|
||||
# Build a context
|
||||
ctx = context.RequestContext(user_id,
|
||||
project_id,
|
||||
user_name=user_name,
|
||||
project_name=project_name,
|
||||
domain_id=domain_id,
|
||||
domain_name=domain_name,
|
||||
roles=roles,
|
||||
auth_token=auth_token,
|
||||
service_catalog=service_catalog,
|
||||
request_id=req_id,
|
||||
user_auth_plugin=user_auth_plugin)
|
||||
|
||||
env['monasca.context'] = ctx
|
||||
|
||||
LOG.debug("Keystone Context succesfully created.")
|
||||
|
||||
return self._app(env, start_response)
|
||||
|
||||
def _get_roles(self, env):
|
||||
"""Get the list of roles."""
|
||||
|
||||
if 'HTTP_X_ROLES' in env:
|
||||
roles = env.get('HTTP_X_ROLES', '')
|
||||
else:
|
||||
# Fallback to deprecated role header:
|
||||
roles = env.get('HTTP_X_ROLE', '')
|
||||
if roles:
|
||||
LOG.warning(
|
||||
'Sourcing roles from deprecated X-Role HTTP header')
|
||||
return [r.strip() for r in roles.split(',')]
|
@ -80,14 +80,14 @@ def validate_authorization(req, authorized_roles):
|
||||
str_roles = req.get_header('X-ROLES')
|
||||
if str_roles is None:
|
||||
raise falcon.HTTPUnauthorized('Forbidden',
|
||||
'Tenant does not have any roles', '')
|
||||
'Tenant does not have any roles')
|
||||
roles = str_roles.lower().split(',')
|
||||
for role in roles:
|
||||
if role in authorized_roles:
|
||||
return
|
||||
raise falcon.HTTPUnauthorized('Forbidden',
|
||||
'Tenant ID is missing a required role to '
|
||||
'access this service', '')
|
||||
'access this service')
|
||||
|
||||
|
||||
def get_tenant_id(req):
|
||||
|
@ -22,7 +22,10 @@
|
||||
|
||||
falcon>=0.1.9
|
||||
gunicorn>=19.1.0
|
||||
keystonemiddleware
|
||||
oslo.config>=1.2.1
|
||||
oslo.middleware
|
||||
oslo.serialization
|
||||
pastedeploy>=1.3.3
|
||||
pbr>=0.6,!=0.7,<1.0
|
||||
python-dateutil>=1.5
|
||||
|
Loading…
Reference in New Issue
Block a user