diff options
author | Thomas Duval <thomas.duval@orange.com> | 2020-06-03 10:06:52 +0200 |
---|---|---|
committer | Thomas Duval <thomas.duval@orange.com> | 2020-06-03 10:06:52 +0200 |
commit | 7bb53c64da2dcf88894bfd31503accdd81498f3d (patch) | |
tree | 4310e12366818af27947b5e2c80cb162da93a4b5 /old/moon_interface/moon_interface | |
parent | cbea4e360e9bfaa9698cf7c61c83c96a1ba89b8c (diff) |
Update to new version 5.4HEADstable/jermamaster
Signed-off-by: Thomas Duval <thomas.duval@orange.com>
Change-Id: Idcd868133d75928a1ffd74d749ce98503e0555ea
Diffstat (limited to 'old/moon_interface/moon_interface')
-rw-r--r-- | old/moon_interface/moon_interface/__init__.py | 6 | ||||
-rw-r--r-- | old/moon_interface/moon_interface/__main__.py | 4 | ||||
-rw-r--r-- | old/moon_interface/moon_interface/api/__init__.py | 0 | ||||
-rw-r--r-- | old/moon_interface/moon_interface/api/authz.py | 162 | ||||
-rw-r--r-- | old/moon_interface/moon_interface/api/generic.py | 96 | ||||
-rw-r--r-- | old/moon_interface/moon_interface/api/update.py | 49 | ||||
-rw-r--r-- | old/moon_interface/moon_interface/authz_requests.py | 163 | ||||
-rw-r--r-- | old/moon_interface/moon_interface/http_server.py | 146 | ||||
-rw-r--r-- | old/moon_interface/moon_interface/server.py | 43 |
9 files changed, 669 insertions, 0 deletions
diff --git a/old/moon_interface/moon_interface/__init__.py b/old/moon_interface/moon_interface/__init__.py new file mode 100644 index 00000000..85c245e0 --- /dev/null +++ b/old/moon_interface/moon_interface/__init__.py @@ -0,0 +1,6 @@ +# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors +# This software is distributed under the terms and conditions of the 'Apache-2.0' +# license which can be found in the file 'LICENSE' in this package distribution +# or at 'http://www.apache.org/licenses/LICENSE-2.0'. + +__version__ = "4.4.0" diff --git a/old/moon_interface/moon_interface/__main__.py b/old/moon_interface/moon_interface/__main__.py new file mode 100644 index 00000000..9ad7bf2a --- /dev/null +++ b/old/moon_interface/moon_interface/__main__.py @@ -0,0 +1,4 @@ +from moon_interface.server import create_server + +server = create_server() +server.run() diff --git a/old/moon_interface/moon_interface/api/__init__.py b/old/moon_interface/moon_interface/api/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/old/moon_interface/moon_interface/api/__init__.py diff --git a/old/moon_interface/moon_interface/api/authz.py b/old/moon_interface/moon_interface/api/authz.py new file mode 100644 index 00000000..b82a14f1 --- /dev/null +++ b/old/moon_interface/moon_interface/api/authz.py @@ -0,0 +1,162 @@ +# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors +# This software is distributed under the terms and conditions of the 'Apache-2.0' +# license which can be found in the file 'LICENSE' in this package distribution +# or at 'http://www.apache.org/licenses/LICENSE-2.0'. +""" +Authz is the endpoint to get authorization response +""" + +from flask import request +from flask_restful import Resource +import logging +import pickle +import time +from uuid import uuid4 +from python_moonutilities import exceptions + +from moon_interface.authz_requests import AuthzRequest + +__version__ = "4.3.1" + +logger = logging.getLogger("moon.interface.api.authz." + __name__) + + +def get_pdp_from_cache(cache, uuid): + """Check if a PDP exist with this ID in the cache of this component + + :param cache: Cache to use + :param uuid: Keystone Project ID + :return: True or False + """ + if uuid in cache.pdp: + return cache.pdp.get(uuid) + + cache.update() + + if uuid in cache.pdp: + return cache.pdp.get(uuid) + + raise exceptions.PdpUnknown + + +def create_authz_request(cache, interface_name, manager_url, pdp_id, subject_name, object_name, action_name): + """Create the authorization request and make the first call to the Authz function + + :param cache: Cache to use + :param interface_name: hostname of the interface + :param manager_url: URL of the manager + :param pdp_id: Keystone Project ID + :param subject_name: name of the subject + :param object_name: name of the object + :param action_name: name of the action + :return: Authorisation request + """ + req_id = uuid4().hex + keystone_project_id = cache.get_keystone_project_id_from_pdp_id(pdp_id) + logger.info("keystone_project_id={}".format(keystone_project_id)) + ctx = { + "project_id": keystone_project_id, + "subject_name": subject_name, + "object_name": object_name, + "action_name": action_name, + "request_id": req_id, + "interface_name": interface_name, + "manager_url": manager_url, + "cookie": uuid4().hex + } + cache.authz_requests[req_id] = AuthzRequest(ctx) + return cache.authz_requests[req_id] + + +def delete_authz_request(cache, req_id): + cache.authz_requests.pop(req_id) + + +class Authz(Resource): + """ + Endpoint for authz requests + """ + + __urls__ = ( + "/authz/<string:pdp_id>", + "/authz/<string:pdp_id>/<string:subject_name>/<string:object_name>/<string:action_name>", + ) + + def __init__(self, **kwargs): + self.CACHE = kwargs.get("cache") + self.INTERFACE_NAME = kwargs.get("interface_name", "interface") + self.MANAGER_URL = kwargs.get("manager_url", "http://manager:8080") + self.TIMEOUT = 5 + + def get(self, pdp_id, subject_name=None, object_name=None, action_name=None): + """Get a response on an authorization request + + :param pdp_id: uuid of a tenant or an intra_extension + :param subject_name: name of the subject or the request + :param object_name: name of the object + :param action_name: name of the action + :return: { + "args": {}, + "ctx": { + "action_name": "4567", + "id": "123456", + "method": "authz", + "object_name": "234567", + "subject_name": "123456", + "user_id": "admin" + }, + "error": { + "code": 500, + "description": "", + "title": "Moon Error" + }, + "intra_extension_id": "123456", + "result": false + } + :internal_api: authz + """ + try: + get_pdp_from_cache(self.CACHE, pdp_id) + except exceptions.PdpUnknown: + return { + "result": False, + "message": "Unknown PDP ID."}, 403 + + authz_request = create_authz_request( + cache=self.CACHE, + pdp_id=pdp_id, + interface_name=self.INTERFACE_NAME, + manager_url=self.MANAGER_URL, + subject_name=subject_name, + object_name=object_name, + action_name=action_name) + cpt = 0 + while True: + if cpt > self.TIMEOUT*10: + delete_authz_request(self.CACHE, authz_request.request_id) + return {"result": False, + "message": "Authz request had timed out."}, 500 + if authz_request.is_authz(): + if authz_request.final_result == "Grant": + delete_authz_request(self.CACHE, authz_request.request_id) + return {"result": True, "message": ""}, 200 + delete_authz_request(self.CACHE, authz_request.request_id) + return {"result": False, "message": ""}, 401 + cpt += 1 + time.sleep(0.1) + + def patch(self, uuid=None, subject_name=None, object_name=None, action_name=None): + """Get a response on an authorization request + + :param uuid: uuid of the authorization request + :param subject_name: not used + :param object_name: not used + :param action_name: not used + :request body: a Context object + :return: {} + :internal_api: authz + """ + if uuid in self.CACHE.authz_requests: + self.CACHE.authz_requests[uuid].set_result(pickle.loads(request.data)) + return "", 201 + return {"result": False, "message": "The request ID is unknown"}, 500 diff --git a/old/moon_interface/moon_interface/api/generic.py b/old/moon_interface/moon_interface/api/generic.py new file mode 100644 index 00000000..dadac259 --- /dev/null +++ b/old/moon_interface/moon_interface/api/generic.py @@ -0,0 +1,96 @@ +# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors +# This software is distributed under the terms and conditions of the 'Apache-2.0' +# license which can be found in the file 'LICENSE' in this package distribution +# or at 'http://www.apache.org/licenses/LICENSE-2.0'. +""" +Those API are helping API used to manage the Moon platform. +""" + +from flask_restful import Resource +import logging +import moon_interface.api +from python_moonutilities.security_functions import check_auth + +__version__ = "4.3.1" + +logger = logging.getLogger("moon.interface.api." + __name__) + + +class Status(Resource): + """ + Endpoint for status requests + """ + + __urls__ = ("/status", "/status/", "/status/<string:component_id>") + + def get(self, component_id=None): + """Retrieve status of all components + + :return: { + "orchestrator": { + "status": "Running" + }, + "security_router": { + "status": "Running" + } + } + """ + return {"result": True, "message": ""} + + +class API(Resource): + """ + Endpoint for API requests + """ + + __urls__ = ( + "/api", + "/api/", + "/api/<string:group_id>", + "/api/<string:group_id>/", + "/api/<string:group_id>/<string:endpoint_id>") + + @check_auth + def get(self, group_id="", endpoint_id="", user_id=""): + """Retrieve all API endpoints or a specific endpoint if endpoint_id is given + + :param group_id: the name of one existing group (ie generic, ...) + :param endpoint_id: the name of one existing component (ie Logs, Status, ...) + :return: { + "group_name": { + "endpoint_name": { + "description": "a description", + "methods": { + "get": "description of the HTTP method" + }, + "urls": ('/api', '/api/', '/api/<string:endpoint_id>') + } + } + """ + __methods = ("get", "post", "put", "delete", "options", "patch") + api_list = filter(lambda x: "__" not in x, dir(moon_interface.api)) + api_desc = dict() + for api_name in api_list: + api_desc[api_name] = {} + group_api_obj = eval("moon_interface.api.{}".format(api_name)) + api_desc[api_name]["description"] = group_api_obj.__doc__ + if "__version__" in dir(group_api_obj): + api_desc[api_name]["version"] = group_api_obj.__version__ + object_list = list(filter(lambda x: "__" not in x, dir(group_api_obj))) + for obj in map(lambda x: eval("moon_interface.api.{}.{}".format(api_name, x)), object_list): + if "__urls__" in dir(obj): + api_desc[api_name][obj.__name__] = dict() + api_desc[api_name][obj.__name__]["urls"] = obj.__urls__ + api_desc[api_name][obj.__name__]["methods"] = dict() + for _method in filter(lambda x: x in __methods, dir(obj)): + docstring = eval("moon_interface.api.{}.{}.{}.__doc__".format(api_name, obj.__name__, _method)) + api_desc[api_name][obj.__name__]["methods"][_method] = docstring + api_desc[api_name][obj.__name__]["description"] = str(obj.__doc__) + if group_id in api_desc: + if endpoint_id in api_desc[group_id]: + return {group_id: {endpoint_id: api_desc[group_id][endpoint_id]}} + elif len(endpoint_id) > 0: + logger.error("Unknown endpoint_id {}".format(endpoint_id)) + return {"error": "Unknown endpoint_id {}".format(endpoint_id)} + return {group_id: api_desc[group_id]} + return api_desc diff --git a/old/moon_interface/moon_interface/api/update.py b/old/moon_interface/moon_interface/api/update.py new file mode 100644 index 00000000..e798059c --- /dev/null +++ b/old/moon_interface/moon_interface/api/update.py @@ -0,0 +1,49 @@ +# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors +# This software is distributed under the terms and conditions of the 'Apache-2.0' +# license which can be found in the file 'LICENSE' in this package distribution +# or at 'http://www.apache.org/licenses/LICENSE-2.0'. +""" +Authz is the endpoint to get authorization response +""" + +from flask import request +from flask_restful import Resource +import requests +import logging + +__version__ = "4.3.1" + +logger = logging.getLogger("moon.interface.api." + __name__) + + +class Update(Resource): + """ + Endpoint for update requests + """ + + __urls__ = ( + "/update", + ) + + def __init__(self, **kwargs): + self.CACHE = kwargs.get("cache") + self.INTERFACE_NAME = kwargs.get("interface_name", "interface") + self.MANAGER_URL = kwargs.get("manager_url", "http://manager:8080") + self.TIMEOUT = 5 + + def put(self): + try: + self.CACHE.update_assignments( + request.form.get("policy_id", None), + request.form.get("perimeter_id", None), + ) + for project_id in self.CACHE.container_chaining: + hostname = self.CACHE.container_chaining[project_id][0]["hostip"] + port = self.CACHE.container_chaining[project_id][0]["port"] + req = requests.put("http://{}:{}/update".format(hostname, port), request.form) + if req.status_code != 200: + logger.error("Cannot connect to {} on port {}".format(hostname, port)) + except Exception as e: + logger.exception(e) + return {"result": False, "reason": str(e)} + return {"result": True} diff --git a/old/moon_interface/moon_interface/authz_requests.py b/old/moon_interface/moon_interface/authz_requests.py new file mode 100644 index 00000000..cf50dfe5 --- /dev/null +++ b/old/moon_interface/moon_interface/authz_requests.py @@ -0,0 +1,163 @@ +# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors +# This software is distributed under the terms and conditions of the 'Apache-2.0' +# license which can be found in the file 'LICENSE' in this package distribution +# or at 'http://www.apache.org/licenses/LICENSE-2.0'. + +import logging +import itertools +import pickle +import requests +import sys +from python_moonutilities import exceptions +from python_moonutilities.context import Context +from python_moonutilities.cache import Cache + +logger = logging.getLogger("moon.interface.authz_requests") + + +CACHE = Cache() +CACHE.update() + + +class AuthzRequest: + + result = None + final_result = "Deny" + req_max_delay = 2 + + def __init__(self, ctx, args=None): + self.context = Context(ctx, CACHE) + self.args = args + self.request_id = ctx["request_id"] + if ctx['project_id'] not in CACHE.container_chaining: + raise exceptions.KeystoneProjectError("Unknown Project ID {}".format(ctx['project_id'])) + self.container_chaining = CACHE.container_chaining[ctx['project_id']] + + if len(self.container_chaining) == 0 or not all(k in self.container_chaining[0] for k in ("container_id", "hostname", "hostip", "port")): + raise exceptions.MoonError('Void container chaining') + + self.pdp_container = self.container_chaining[0]["container_id"] + self.run() + + def run(self): + self.context.delete_cache() + req = None + tries = 0 + success = False + + if "hostip" in self.container_chaining[0]: + hostname = self.container_chaining[0]["hostip"] + elif "hostname" in self.container_chaining[0]: + hostname = self.container_chaining[0]["hostname"] + else: + raise exceptions.AuthzException( + "error in address no hostname or hostip" + ) + tried_hostnames = [] + while tries < 2: + tried_hostnames.append(hostname) + try: + req = requests.post("http://{}:{}/authz".format( + hostname, + self.container_chaining[0]["port"], + ), data=pickle.dumps(self.context)) + if req.status_code != 200: + raise exceptions.AuthzException( + "Receive bad response from Authz function " + "(with {} -> {})".format(hostname, req.status_code) + ) + success = True + except requests.exceptions.ConnectionError: + if tries > 1: + logger.error("Cannot connect to {}".format( + "http://[{}]:{}/authz".format( + ", ".join(tried_hostnames), + self.container_chaining[0]["port"] + ))) + except Exception as e: + logger.exception(e) + else: + break + hostname = self.container_chaining[0]["hostname"], + tries += 1 + + if not success: + raise exceptions.AuthzException("Cannot connect to Authz function") + + self.context.set_cache(CACHE) + if req and len(self.container_chaining) == 1: + self.result = pickle.loads(req.content) + + # def __exec_next_state(self, rule_found): + # index = self.context.index + # current_meta_rule = self.context.headers[index] + # current_container = self.__get_container_from_meta_rule(current_meta_rule) + # current_container_genre = current_container["genre"] + # try: + # next_meta_rule = self.context.headers[index + 1] + # except IndexError: + # next_meta_rule = None + # if current_container_genre == "authz": + # if rule_found: + # return True + # pass + # if next_meta_rule: + # # next will be session if current is deny and session is unset + # if self.payload["authz_context"]['pdp_set'][next_meta_rule]['effect'] == "unset": + # return notify( + # request_id=self.payload["authz_context"]["request_id"], + # container_id=self.__get_container_from_meta_rule(next_meta_rule)['container_id'], + # payload=self.payload) + # # next will be delegation if current is deny and session is passed or deny and delegation is unset + # else: + # LOG.error("Delegation is not developed!") + # + # else: + # # else next will be None and the request is sent to router + # return self.__return_to_router() + # elif current_container_genre == "session": + # pass + # # next will be next container in headers if current is passed + # if self.payload["authz_context"]['pdp_set'][current_meta_rule]['effect'] == "passed": + # return notify( + # request_id=self.payload["authz_context"]["request_id"], + # container_id=self.__get_container_from_meta_rule(next_meta_rule)['container_id'], + # payload=self.payload) + # # next will be None if current is grant and the request is sent to router + # else: + # return self.__return_to_router() + # elif current_container_genre == "delegation": + # LOG.error("Delegation is not developed!") + # # next will be authz if current is deny + # # next will be None if current is grant and the request is sent to router + + def set_result(self, result): + self.result = result + + def is_authz(self): + if not self.result: + return False + authz_results = [] + for key in self.result.pdp_set: + if "effect" in self.result.pdp_set[key]: + + if self.result.pdp_set[key]["effect"] == "grant": + # the pdp is a authorization PDP and grant the request + authz_results.append(True) + elif self.result.pdp_set[key]["effect"] == "passed": + # the pdp is not a authorization PDP (session or delegation) and had run normally + authz_results.append(True) + elif self.result.pdp_set[key]["effect"] == "unset": + # the pdp is not a authorization PDP (session or delegation) and had not yep run + authz_results.append(True) + else: + # the pdp is (or not) a authorization PDP and had run badly + authz_results.append(False) + if list(itertools.accumulate(authz_results, lambda x, y: x & y))[-1]: + self.result.pdp_set["effect"] = "grant" + if self.result: + if self.result.pdp_set["effect"] == "grant": + self.final_result = "Grant" + return True + self.final_result = "Deny" + return True diff --git a/old/moon_interface/moon_interface/http_server.py b/old/moon_interface/moon_interface/http_server.py new file mode 100644 index 00000000..50bf2a62 --- /dev/null +++ b/old/moon_interface/moon_interface/http_server.py @@ -0,0 +1,146 @@ +# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors +# This software is distributed under the terms and conditions of the 'Apache-2.0' +# license which can be found in the file 'LICENSE' in this package distribution +# or at 'http://www.apache.org/licenses/LICENSE-2.0'. + +from flask import Flask, jsonify +from flask_restful import Resource, Api +import logging +from moon_interface import __version__ +from moon_interface.api.generic import Status, API +from moon_interface.api.authz import Authz +from moon_interface.api.update import Update +from moon_interface.authz_requests import CACHE +from python_moonutilities import configuration, exceptions + +logger = logging.getLogger("moon.interface.http_server") + +__API__ = ( + Status, API + ) + + +class Server: + """Base class for HTTP server""" + + def __init__(self, host="localhost", port=80, api=None, **kwargs): + """Run a server + + :param host: hostname of the server + :param port: port for the running server + :param kwargs: optional parameters + :return: a running server + """ + self._host = host + self._port = port + self._api = api + self._extra = kwargs + + @property + def host(self): + return self._host + + @host.setter + def host(self, name): + self._host = name + + @host.deleter + def host(self): + self._host = "" + + @property + def port(self): + return self._port + + @port.setter + def port(self, number): + self._port = number + + @port.deleter + def port(self): + self._port = 80 + + def run(self): + raise NotImplementedError() + + +class Root(Resource): + """ + The root of the web service + """ + __urls__ = ("/", ) + __methods = ("get", "post", "put", "delete", "options") + + def get(self): + tree = {"/": {"methods": ("get",), + "description": "List all methods for that service."}} + for item in __API__: + tree[item.__name__] = {"urls": item.__urls__} + _methods = [] + for _method in self.__methods: + if _method in dir(item): + _methods.append(_method) + tree[item.__name__]["methods"] = _methods + tree[item.__name__]["description"] = item.__doc__.strip() + return { + "version": __version__, + "tree": tree + } + + +class HTTPServer(Server): + + def __init__(self, host="localhost", port=80, **kwargs): + super(HTTPServer, self).__init__(host=host, port=port, **kwargs) + self.app = Flask(__name__) + self.port = port + conf = configuration.get_configuration("components/manager") + self.manager_hostname = conf["components/manager"].get("hostname", + "manager") + self.manager_port = conf["components/manager"].get("port", 80) + self.api = Api(self.app) + self.__set_route() + self.__hook_errors() + + # @self.app.errorhandler(exceptions.AuthException) + # def _auth_exception(error): + # return {"error": "Unauthorized"}, 401 + + def __hook_errors(self): + + def get_404_json(e): + return jsonify({"result": False, "code": 404, "description": str(e)}), 404 + self.app.register_error_handler(404, get_404_json) + + def get_400_json(e): + return jsonify({"result": False, "code": 400, "description": str(e)}), 400 + + self.app.register_error_handler(400, lambda e: get_400_json) + self.app.register_error_handler(403, exceptions.AuthException) + + def __set_route(self): + self.api.add_resource(Root, '/') + + for api in __API__: + self.api.add_resource(api, *api.__urls__) + self.api.add_resource(Authz, *Authz.__urls__, + resource_class_kwargs={ + "cache": CACHE, + "interface_name": self.host, + "manager_url": "http://{}:{}".format( + self.manager_hostname, + self.manager_port), + } + ) + self.api.add_resource(Update, *Update.__urls__, + resource_class_kwargs={ + "cache": CACHE, + "interface_name": self.host, + "manager_url": "http://{}:{}".format( + self.manager_hostname, + self.manager_port), + } + ) + + def run(self): + self.app.run(host=self._host, port=self._port, threaded=True) # nosec diff --git a/old/moon_interface/moon_interface/server.py b/old/moon_interface/moon_interface/server.py new file mode 100644 index 00000000..29403a6b --- /dev/null +++ b/old/moon_interface/moon_interface/server.py @@ -0,0 +1,43 @@ +# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors +# This software is distributed under the terms and conditions of the 'Apache-2.0' +# license which can be found in the file 'LICENSE' in this package distribution +# or at 'http://www.apache.org/licenses/LICENSE-2.0'. + +import logging +from python_moonutilities import configuration, exceptions +from moon_interface.http_server import HTTPServer + +logger = logging.getLogger("moon.interface.server") + + +def create_server(): + configuration.init_logging() + try: + + conf = configuration.get_configuration("components/pipeline").get( + "components/pipeline", {}).get("interface", {}) + + hostname = conf.get("hostname", "pipeline") + port = conf.get("port", 80) + bind = conf.get("bind", "127.0.0.1") + except exceptions.ConsulComponentNotFound: + hostname = "interface" + bind = "127.0.0.1" + port = 80 + + configuration.add_component(uuid="pipeline", + name=hostname, + port=port, + bind=bind) + logger.info("Starting server with IP {} on port {} bind to {}".format( + hostname, port, bind)) + return HTTPServer(host=bind, port=port) + + +def run(): + server = create_server() + server.run() + + +if __name__ == '__main__': + run() |