Access control support

Change-Id: Ic842885c7bcef0e9dc7728837b6cd396ccf52fbe
Implements: blueprint access-control-master-node
This commit is contained in:
Łukasz Oleś 2014-06-27 08:30:33 +02:00
parent ff01812bb9
commit 8ffe730af6
8 changed files with 110 additions and 2 deletions

View File

@ -57,6 +57,11 @@ def load_run_parsers(subparsers):
'--fake-tasks-tick-interval', action='store', type=int,
help='Fake tasks tick interval in seconds'
)
run_parser.add_argument(
'--authentication-method', action='store', type=str,
help='Choose authentication type',
choices=['none', 'fake', 'keystone'],
)
def load_db_parsers(subparsers):
@ -230,6 +235,11 @@ def action_run(params):
param = getattr(params, attr.lower())
if param is not None:
settings.update({attr: param})
if params.authentication_method:
auth_method = params.authentication_method
settings.AUTH.update({'AUTHENTICATION_METHOD' : auth_method})
if params.config_file:
settings.update_from_file(params.config_file)
from nailgun.app import appstart

View File

@ -32,4 +32,7 @@ class VersionHandler(BaseHandler):
""":returns: FUEL/FUELWeb commit SHA, release version.
:http: * 200 (OK)
"""
return settings.VERSION
version = settings.VERSION
method = settings.AUTH['AUTHENTICATION_METHOD']
version['auth_required'] = method in ['fake', 'keystone']
return version

View File

@ -196,3 +196,10 @@ _locals = locals()
def app():
return web.application(urls, _locals)
def public_urls():
return {r'/nodes/?$': ['POST'],
r'/nodes/agent/?$': ['PUT'],
r'/version/?$': ['GET']
}

View File

@ -28,6 +28,7 @@ from nailgun.logger import HTTPLoggerMiddleware
from nailgun.logger import logger
from nailgun.middleware.http_method_override import \
HTTPMethodOverrideMiddleware
from nailgun.middleware.keystone import NailgunAuthProtocol
from nailgun.middleware.static import StaticMiddleware
from nailgun.settings import settings
from nailgun.urls import urls
@ -53,6 +54,9 @@ def build_middleware(app):
if settings.DEVELOPMENT:
middleware_list.append(StaticMiddleware)
if settings.AUTH['AUTHENTICATION_METHOD'] == 'keystone':
middleware_list.append(NailgunAuthProtocol)
logger.debug('Initialize middleware: %s' %
(map(lambda x: x.__name__, middleware_list)))

View File

@ -0,0 +1,71 @@
# -*- coding: utf-8 -*-
# Copyright 2014 Mirantis, Inc.
#
# 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 re
from nailgun.api.v1 import urls as api_urls
from nailgun.settings import settings
from keystoneclient.middleware import auth_token
def public_urls():
urls = {}
for url, methods in api_urls.public_urls().iteritems():
urls['{0}{1}'.format('/api/v1', url)] = methods
urls['{0}{1}'.format('/api', url)] = methods
urls["/$"] = ['GET']
urls["/static"] = ['GET']
return urls
class NailgunAuthProtocol(auth_token.AuthProtocol):
"""A wrapper on Keystone auth_token middleware.
Does not perform verification of authentication tokens
for public routes in the API.
"""
def __init__(self, app):
self.public_api_routes = {}
try:
for route_tpl, methods in public_urls().iteritems():
self.public_api_routes[re.compile(route_tpl)] = methods
except re.error as e:
msg = 'Cannot compile public API routes: {0}'.format(e)
auth_token.LOG.error(msg)
raise Exception(error_msg=msg)
super(NailgunAuthProtocol, self).__init__(app, settings.AUTH)
def __call__(self, env, start_response):
path = env.get('PATH_INFO', '/')
method = env.get('REQUEST_METHOD')
# The information whether the API call is being performed against the
# public API may be useful. Saving it to the
# WSGI environment is reasonable thereby.
env['is_public_api'] = False
for pattern, methods in self.public_api_routes.iteritems():
if re.match(pattern, path):
if method in methods:
env['is_public_api'] = True
break
if env['is_public_api']:
return self.app(env, start_response)
return super(NailgunAuthProtocol, self).__call__(env, start_response)

View File

@ -1,6 +1,17 @@
LISTEN_ADDRESS: "0.0.0.0"
LISTEN_PORT: "8000"
DEVELOPMENT: 1
AUTH:
# Possible options:
# - none - authentication is disabled
# - fake - no keystone required, credentials: admin/admin
# - keystone - authentication enabled.
AUTHENTICATION_METHOD: "none"
# use only if AUTHENTICATION_METHOD is set to "keystone"
admin_token: "ADMIN"
auth_host: "127.0.0.1"
auth_protocol: "http"
auth_version: "v2.0"
VERSION:
release: "5.0"

View File

@ -43,6 +43,7 @@ class TestVersionHandler(BaseIntegrationTest):
"nailgun_sha": "12345",
"astute_sha": "Unknown build",
"fuellib_sha": "Unknown build",
"ostf_sha": "Unknown build"
"ostf_sha": "Unknown build",
"auth_required": False
}
)

View File

@ -24,3 +24,4 @@ simplejson==3.3.0
web.py==0.37
wsgilog==0.3
wsgiref==0.1.2
python-keystoneclient>=0.7.1