diff options
49 files changed, 1236 insertions, 568 deletions
diff --git a/moon_authz/moon_authz/api/authorization.py b/moon_authz/moon_authz/api/authorization.py index ea177d81..84114466 100644 --- a/moon_authz/moon_authz/api/authorization.py +++ b/moon_authz/moon_authz/api/authorization.py @@ -9,6 +9,7 @@ import logging import flask from flask import request from flask_restful import Resource +from python_moonutilities import exceptions logger = logging.getLogger("moon.authz.api." + __name__) @@ -86,16 +87,30 @@ class Authz(Resource): scopes_list = list() current_header_id = self.context.headers[self.context.index] # Context.update_target(context) + if not self.context.pdp_set: + raise exceptions.PdpUnknown + if current_header_id not in self.context.pdp_set: + raise Exception('Invalid index') current_pdp = self.context.pdp_set[current_header_id] category_list = list() - category_list.extend(current_pdp["meta_rules"]["subject_categories"]) - category_list.extend(current_pdp["meta_rules"]["object_categories"]) - category_list.extend(current_pdp["meta_rules"]["action_categories"]) + if 'meta_rules' not in current_pdp: + raise exceptions.PdpContentError + try: + category_list.extend(current_pdp["meta_rules"]["subject_categories"]) + category_list.extend(current_pdp["meta_rules"]["object_categories"]) + category_list.extend(current_pdp["meta_rules"]["action_categories"]) + except Exception: + raise exceptions.MetaRuleContentError + if 'target' not in current_pdp: + raise exceptions.PdpContentError for category in category_list: scope = list(current_pdp['target'][category]) scopes_list.append(scope) # policy_id = self.cache.get_policy_from_meta_rules("admin", current_header_id) - + if self.context.current_policy_id not in self.cache.rules: + raise exceptions.PolicyUnknown + if 'rules' not in self.cache.rules[self.context.current_policy_id]: + raise exceptions.RuleUnknown for item in itertools.product(*scopes_list): req = list(item) for rule in self.cache.rules[self.context.current_policy_id]["rules"]: @@ -362,4 +377,4 @@ class Authz(Resource): def head(self, uuid=None, subject_name=None, object_name=None, action_name=None): logger.info("HEAD request") - return "", 200
\ No newline at end of file + return "", 200 diff --git a/moon_authz/tests/unit_python/test_authz.py b/moon_authz/tests/unit_python/test_authz.py index 50493c9f..2352fe06 100644 --- a/moon_authz/tests/unit_python/test_authz.py +++ b/moon_authz/tests/unit_python/test_authz.py @@ -1,5 +1,6 @@ import json import pickle +import pytest def get_data(data): @@ -10,6 +11,13 @@ def get_json(data): return json.loads(data.decode("utf-8")) +def run(component_data, cache, context): + from moon_authz.api.authorization import Authz + authz = Authz(component_data=component_data, cache=cache) + authz.context = context + authz.run() + + def test_authz_true(context): import moon_authz.server from python_moonutilities.context import Context @@ -48,3 +56,61 @@ def test_user_not_allowed(context): assert isinstance(data, dict) assert "message" in data assert data["message"] == "Cannot find subject user_not_allowed" + + +def test_object_not_allowed(context): + import moon_authz.server + from python_moonutilities.context import Context + from python_moonutilities.cache import Cache + server = moon_authz.server.create_server() + client = server.app.test_client() + CACHE = Cache() + CACHE.update() + context['subject_name'] = "testuser" + context['object_name'] = "invalid" + _context = Context(context, CACHE) + req = client.post("/authz", data=pickle.dumps(_context)) + assert req.status_code == 400 + data = get_json(req.data) + assert data + assert isinstance(data, dict) + assert "message" in data + assert data["message"] == "Cannot find object invalid" + + +def test_action_not_allowed(context): + import moon_authz.server + from python_moonutilities.context import Context + from python_moonutilities.cache import Cache + server = moon_authz.server.create_server() + client = server.app.test_client() + CACHE = Cache() + CACHE.update() + context['subject_name'] = "testuser" + context['object_name'] = "vm1" + context['action_name'] = "invalid" + _context = Context(context, CACHE) + req = client.post("/authz", data=pickle.dumps(_context)) + assert req.status_code == 400 + data = get_json(req.data) + assert data + assert isinstance(data, dict) + assert "message" in data + assert data["message"] == "Cannot find action invalid" + + +def test_authz_with_empty_pdp_set(context): + from python_moonutilities.context import Context + from python_moonutilities.cache import Cache + CACHE = Cache() + CACHE.update() + _context = Context(context, CACHE) + component_data = { + 'component_id': 'component_id1', + 'pdp_id': 'pdp_id1', + 'meta_rule_id': 'meta_rule_id1', + 'keystone_project_id': 'keystone_project_id1', + } + with pytest.raises(Exception) as exception_info: + run(component_data, CACHE, _context) + assert str(exception_info.value) == '400: Pdp Unknown' diff --git a/moon_authz/tests/unit_python/utilities.py b/moon_authz/tests/unit_python/utilities.py index 19b9354c..e3a111bd 100644 --- a/moon_authz/tests/unit_python/utilities.py +++ b/moon_authz/tests/unit_python/utilities.py @@ -37,11 +37,19 @@ CONF = { "container": "wukongsun/moon_orchestrator:v4.3", "hostname": "orchestrator" }, - "interface": { - "bind": "0.0.0.0", - "port": 8080, - "container": "wukongsun/moon_interface:v4.3", - "hostname": "interface" + "pipeline": { + "interface": { + "bind": "0.0.0.0", + "port": 8080, + "container": "wukongsun/moon_interface:v4.3", + "hostname": "interface" + }, + "authz": { + "bind": "0.0.0.0", + "port": 8081, + "container": "wukongsun/moon_authz:v4.3", + "hostname": "authz" + } } }, "plugins": { @@ -144,7 +152,8 @@ COMPONENTS = ( "slave", "components/manager", "components/orchestrator", - "components/interface", + "components/pipeline", + "components/wrapper", ) diff --git a/moon_interface/moon_interface/api/authz.py b/moon_interface/moon_interface/api/authz.py index 5739027d..b82a14f1 100644 --- a/moon_interface/moon_interface/api/authz.py +++ b/moon_interface/moon_interface/api/authz.py @@ -12,6 +12,7 @@ import logging import pickle import time from uuid import uuid4 +from python_moonutilities import exceptions from moon_interface.authz_requests import AuthzRequest @@ -20,45 +21,41 @@ __version__ = "4.3.1" logger = logging.getLogger("moon.interface.api.authz." + __name__) -def pdp_in_cache(cache, uuid): - """Check if a PDP exist with this Keystone Project ID in the cache of this component +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 """ - for item_uuid, item_value in cache.pdp.items(): - if uuid == item_value['keystone_project_id']: - return item_uuid, item_value - return None, None + if uuid in cache.pdp: + return cache.pdp.get(uuid) + cache.update() -def pdp_in_manager(cache, uuid): - """Check if a PDP exist with this Keystone Project ID in the Manager component + if uuid in cache.pdp: + return cache.pdp.get(uuid) - :param cache: Cache to use - :param uuid: Keystone Project ID - :return: True or False - """ - cache.update() - return pdp_in_cache(cache, uuid) + raise exceptions.PdpUnknown -def create_authz_request(cache, interface_name, manager_url, uuid, subject_name, object_name, action_name): +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 uuid: Keystone Project ID + :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": uuid, + "project_id": keystone_project_id, "subject_name": subject_name, "object_name": object_name, "action_name": action_name, @@ -81,8 +78,8 @@ class Authz(Resource): """ __urls__ = ( - "/authz/<string:uuid>", - "/authz/<string:uuid>/<string:subject_name>/<string:object_name>/<string:action_name>", + "/authz/<string:pdp_id>", + "/authz/<string:pdp_id>/<string:subject_name>/<string:object_name>/<string:action_name>", ) def __init__(self, **kwargs): @@ -91,10 +88,10 @@ class Authz(Resource): self.MANAGER_URL = kwargs.get("manager_url", "http://manager:8080") self.TIMEOUT = 5 - def get(self, uuid=None, subject_name=None, object_name=None, action_name=None): + def get(self, pdp_id, subject_name=None, object_name=None, action_name=None): """Get a response on an authorization request - :param uuid: uuid of a tenant or an intra_extension + :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 @@ -118,17 +115,16 @@ class Authz(Resource): } :internal_api: authz """ - pdp_id, pdp_value = pdp_in_cache(self.CACHE, uuid) - if not pdp_id: - pdp_id, pdp_value = pdp_in_manager(self.CACHE, uuid) - if not pdp_id: - return { - "result": False, - "message": "Unknown Project ID or " - "Project ID is not bind to a PDP."}, 403 + 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, - uuid=uuid, + pdp_id=pdp_id, interface_name=self.INTERFACE_NAME, manager_url=self.MANAGER_URL, subject_name=subject_name, diff --git a/moon_interface/moon_interface/authz_requests.py b/moon_interface/moon_interface/authz_requests.py index 87e21152..12c190c7 100644 --- a/moon_interface/moon_interface/authz_requests.py +++ b/moon_interface/moon_interface/authz_requests.py @@ -7,6 +7,7 @@ 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 @@ -31,51 +32,53 @@ class AuthzRequest: 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: + + if len(self.container_chaining) == 0 or not all(k in self.container_data 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 - try: - req = requests.post("http://{}:{}/authz".format( - self.container_chaining[0]["hostip"], - 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 IP address - {})".format( - req.status_code - )) - except requests.exceptions.ConnectionError: - logger.error("Cannot connect to {}".format( - "http://{}:{}/authz".format( - self.container_chaining[0]["hostip"], - self.container_chaining[0]["port"] - ))) - except ValueError: + 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" + ) + while tries < 2: try: req = requests.post("http://{}:{}/authz".format( - self.container_chaining[0]["hostname"], + 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 hostname - {})".format( - req.status_code - )) + "(with address - {})".format(req.status_code) + ) + success = True except requests.exceptions.ConnectionError: logger.error("Cannot connect to {}".format( "http://{}:{}/authz".format( - self.container_chaining[0]["hostname"], + hostname, self.container_chaining[0]["port"] ))) - raise exceptions.AuthzException( - "Cannot connect to Authz function") + except: + logger.error("Unexpected error:", sys.exc_info()[0]) + 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) @@ -132,6 +135,7 @@ class AuthzRequest: 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) diff --git a/moon_interface/moon_interface/http_server.py b/moon_interface/moon_interface/http_server.py index 57170985..82ee5d91 100644 --- a/moon_interface/moon_interface/http_server.py +++ b/moon_interface/moon_interface/http_server.py @@ -113,6 +113,13 @@ class HTTPServer(Server): def get_400_json(e): return jsonify({"result": False, "code": 400, "description": str(e)}), 400 + + ''' + [Note] i have tried to simulate authz post request (authz_Requests/run) to return 500 response code + and an AuthzException thrown from their [Line 63] and catched here , then the server here return response + with 403 code [Forbidden] , is it correct if so why sometime at authz [from Line 137] return a response + with error code , i think we can do it in the same way as the one mentioned? + ''' self.app.register_error_handler(400, lambda e: get_400_json) self.app.register_error_handler(403, exceptions.AuthException) diff --git a/moon_interface/moon_interface/server.py b/moon_interface/moon_interface/server.py index 0af1fd06..d38dae28 100644 --- a/moon_interface/moon_interface/server.py +++ b/moon_interface/moon_interface/server.py @@ -13,8 +13,12 @@ logger = logging.getLogger("moon.interface.server") def create_server(): configuration.init_logging() try: + conf = configuration.get_configuration("components/pipeline").get( "components/pipeline", {}).get("interface", {}) + ''' + [Note] i think pipeline should be changed to interface + ''' hostname = conf.get("hostname", "pipeline") port = conf.get("port", 80) bind = conf.get("bind", "127.0.0.1") @@ -22,6 +26,9 @@ def create_server(): hostname = "interface" bind = "127.0.0.1" port = 80 + ''' + [Note] i think pipeline should be changed to interface + ''' configuration.add_component(uuid="pipeline", name=hostname, port=port, diff --git a/moon_interface/tests/unit_python/api/test_authz.py b/moon_interface/tests/unit_python/api/test_authz.py index 84605203..052bc9c9 100644 --- a/moon_interface/tests/unit_python/api/test_authz.py +++ b/moon_interface/tests/unit_python/api/test_authz.py @@ -1,4 +1,5 @@ import json +import conftest def get_json(data): @@ -6,11 +7,12 @@ def get_json(data): def test_authz_true(context): + import moon_interface.server server = moon_interface.server.create_server() client = server.app.test_client() req = client.get("/authz/{p_id}/{s_id}/{o_id}/{a_id}".format( - p_id=context["project_id"], + p_id=context["pdp_id"], s_id=context["subject_name"], o_id=context["object_name"], a_id=context["action_name"], @@ -19,5 +21,61 @@ def test_authz_true(context): data = get_json(req.data) assert data assert "result" in data - assert data['result'] == True + assert data['result'] is True + +def test_authz_False(context): + import moon_interface.server + server = moon_interface.server.create_server() + client = server.app.test_client() + + req = client.get("/authz/{p_id}/{s_id}/{o_id}/{a_id}".format( + p_id=None, + s_id=context["subject_name"], + o_id=context["object_name"], + a_id=context["action_name"], + )) + assert req.status_code == 403 + data = get_json(req.data) + assert data + assert "result" in data + assert data['result'] is False + + +def test_authz_effect_unset(context, set_consul_and_db): + import moon_interface.server + server = moon_interface.server.create_server() + client = server.app.test_client() + + set_consul_and_db.register_uri( + 'POST', 'http://127.0.0.1:8081/authz', + content = conftest.get_pickled_context_invalid() + ) + req = client.get("/authz/{p_id}/{s_id}/{o_id}/{a_id}".format( + p_id=context["pdp_id"], + s_id=context["subject_name"], + o_id=context["object_name"], + a_id=context["action_name"], + )) + assert req.status_code == 401 + data = get_json(req.data) + assert data + assert "result" in data + assert data['result'] is False + +def test_authz_invalid_ip(context, set_consul_and_db): + import moon_interface.server + server = moon_interface.server.create_server() + client = server.app.test_client() + + set_consul_and_db.register_uri( + 'POST', 'http://127.0.0.1:8081/authz', status_code=500 + ) + + req = client.get("/authz/{p_id}/{s_id}/{o_id}/{a_id}".format( + p_id=context["pdp_id"], + s_id=context["subject_name"], + o_id=context["object_name"], + a_id=context["action_name"], + )) + assert req.status_code == 403 diff --git a/moon_interface/tests/unit_python/conftest.py b/moon_interface/tests/unit_python/conftest.py index 35ee19d7..893a8637 100644 --- a/moon_interface/tests/unit_python/conftest.py +++ b/moon_interface/tests/unit_python/conftest.py @@ -39,21 +39,19 @@ CONF = { "container": "wukongsun/moon_orchestrator:v4.3", "hostname": "orchestrator" }, - "interface": { - "bind": "0.0.0.0", - "port": 8080, - "container": "wukongsun/moon_interface:v4.3", - "hostname": "interface" - } - }, - "plugins": { - "session": { - "port": 8082, - "container": "asteroide/session:latest" - }, - "authz": { - "port": 8081, - "container": "wukongsun/moon_authz:v4.3" + "pipeline": { + "interface": { + "bind": "0.0.0.0", + "port": 8080, + "container": "wukongsun/moon_interface:v4.3", + "hostname": "interface" + }, + "authz": { + "bind": "0.0.0.0", + "port": 8081, + "container": "wukongsun/moon_authz:v4.3", + "hostname": "authz" + }, } }, "logging": { @@ -128,10 +126,11 @@ COMPONENTS = ( "slave", "components/manager", "components/orchestrator", - "components/interface", + "components/pipeline", ) CONTEXT = { + "pdp_id": "b3d3e18abf3340e8b635fd49e6634ccd", "project_id": "a64beb1cc224474fb4badd43173e7101", "subject_name": "testuser", "object_name": "vm1", @@ -215,6 +214,19 @@ def get_pickled_context(): print(_context.pdp_set) return pickle.dumps(_context) +def get_pickled_context_invalid(): + from python_moonutilities.context import Context + from python_moonutilities.cache import Cache + CACHE = Cache() + CACHE.update() + _context = Context(context(), CACHE) + _context.increment_index() + _context.pdp_set['effect'] = 'invalid' + _context.pdp_set[os.environ['META_RULE_ID']]['effect'] = 'invalid' + print(_context.pdp_set) + return pickle.dumps(_context) + + @pytest.fixture(autouse=True) def set_consul_and_db(monkeypatch): diff --git a/moon_manager/moon_manager/__init__.py b/moon_manager/moon_manager/__init__.py index 903c6518..6f964a63 100644 --- a/moon_manager/moon_manager/__init__.py +++ b/moon_manager/moon_manager/__init__.py @@ -3,4 +3,4 @@ # license which can be found in the file 'LICENSE' in this package distribution # or at 'http://www.apache.org/licenses/LICENSE-2.0'. -__version__ = "0.1.0" +__version__ = "4.3.2" diff --git a/moon_manager/moon_manager/__main__.py b/moon_manager/moon_manager/__main__.py index 7d97f003..4fed8d10 100644 --- a/moon_manager/moon_manager/__main__.py +++ b/moon_manager/moon_manager/__main__.py @@ -1,4 +1,4 @@ -from moon_manager.server import main +from moon_manager.server import create_server -server = main() +server = create_server() server.run() diff --git a/moon_manager/moon_manager/api/assignments.py b/moon_manager/moon_manager/api/assignments.py index c3ac45c8..0b2cd20b 100644 --- a/moon_manager/moon_manager/api/assignments.py +++ b/moon_manager/moon_manager/api/assignments.py @@ -9,13 +9,13 @@ Assignments allow to connect data with elements of perimeter from flask import request from flask_restful import Resource -from oslo_log import log as logging +import logging from python_moonutilities.security_functions import check_auth from python_moondb.core import PolicyManager -__version__ = "0.2.0" +__version__ = "4.3.2" -LOG = logging.getLogger("moon.manager.api." + __name__) +logger = logging.getLogger("moon.manager.api." + __name__) class SubjectAssignments(Resource): @@ -32,7 +32,8 @@ class SubjectAssignments(Resource): ) @check_auth - def get(self, uuid=None, perimeter_id=None, category_id=None, data_id=None, user_id=None): + def get(self, uuid=None, perimeter_id=None, category_id=None, + data_id=None, user_id=None): """Retrieve all subject assignments or a specific one for a given policy :param uuid: uuid of the policy @@ -50,21 +51,19 @@ class SubjectAssignments(Resource): } :internal_api: get_subject_assignments """ - # return call(ctx={"id": uuid, "method": "get_subject_assignments", "perimeter_id": perimeter_id, "category_id": category_id, "user_id": user_id}, - # args={"data_id": data_id}) try: - # if "perimeter_name" in ctx: - # ctx["perimeter_id"] = self.__get_subject_id(ctx, ctx['perimeter_name']) - data = PolicyManager.get_subject_assignments(user_id=user_id, policy_id=uuid, - subject_id=perimeter_id, category_id=category_id) + data = PolicyManager.get_subject_assignments( + user_id=user_id, policy_id=uuid, + subject_id=perimeter_id, category_id=category_id) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"subject_assignments": data} @check_auth - def post(self, uuid=None, perimeter_id=None, category_id=None, data_id=None, user_id=None): + def post(self, uuid=None, perimeter_id=None, category_id=None, + data_id=None, user_id=None): """Create a subject assignment. :param uuid: uuid of the policy @@ -91,17 +90,19 @@ class SubjectAssignments(Resource): data_id = request.json.get("data_id") category_id = request.json.get("category_id") perimeter_id = request.json.get("id") - data = PolicyManager.add_subject_assignment(user_id=user_id, policy_id=uuid, - subject_id=perimeter_id, category_id=category_id, - data_id=data_id) + data = PolicyManager.add_subject_assignment( + user_id=user_id, policy_id=uuid, + subject_id=perimeter_id, category_id=category_id, + data_id=data_id) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"subject_assignments": data} @check_auth - def delete(self, uuid=None, perimeter_id=None, category_id=None, data_id=None, user_id=None): + def delete(self, uuid=None, perimeter_id=None, category_id=None, + data_id=None, user_id=None): """Delete a subject assignment for a given policy :param uuid: uuid of the policy @@ -116,11 +117,12 @@ class SubjectAssignments(Resource): :internal_api: delete_subject_assignment """ try: - data = PolicyManager.delete_subject_assignment(user_id=user_id, policy_id=uuid, - subject_id=perimeter_id, category_id=category_id, - data_id=data_id) + data = PolicyManager.delete_subject_assignment( + user_id=user_id, policy_id=uuid, + subject_id=perimeter_id, category_id=category_id, + data_id=data_id) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"result": True} @@ -140,7 +142,8 @@ class ObjectAssignments(Resource): ) @check_auth - def get(self, uuid=None, perimeter_id=None, category_id=None, data_id=None, user_id=None): + def get(self, uuid=None, perimeter_id=None, category_id=None, + data_id=None, user_id=None): """Retrieve all object assignment or a specific one for a given policy :param uuid: uuid of the policy @@ -159,16 +162,18 @@ class ObjectAssignments(Resource): :internal_api: get_object_assignments """ try: - data = PolicyManager.get_object_assignments(user_id=user_id, policy_id=uuid, - object_id=perimeter_id, category_id=category_id) + data = PolicyManager.get_object_assignments( + user_id=user_id, policy_id=uuid, + object_id=perimeter_id, category_id=category_id) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"object_assignments": data} @check_auth - def post(self, uuid=None, perimeter_id=None, category_id=None, data_id=None, user_id=None): + def post(self, uuid=None, perimeter_id=None, category_id=None, + data_id=None, user_id=None): """Create an object assignment. :param uuid: uuid of the policy @@ -195,17 +200,19 @@ class ObjectAssignments(Resource): data_id = request.json.get("data_id") category_id = request.json.get("category_id") perimeter_id = request.json.get("id") - data = PolicyManager.add_object_assignment(user_id=user_id, policy_id=uuid, - object_id=perimeter_id, category_id=category_id, - data_id=data_id) + data = PolicyManager.add_object_assignment( + user_id=user_id, policy_id=uuid, + object_id=perimeter_id, category_id=category_id, + data_id=data_id) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"object_assignments": data} @check_auth - def delete(self, uuid=None, perimeter_id=None, category_id=None, data_id=None, user_id=None): + def delete(self, uuid=None, perimeter_id=None, category_id=None, + data_id=None, user_id=None): """Delete a object assignment for a given policy :param uuid: uuid of the policy @@ -220,11 +227,12 @@ class ObjectAssignments(Resource): :internal_api: delete_object_assignment """ try: - data = PolicyManager.delete_object_assignment(user_id=user_id, policy_id=uuid, - object_id=perimeter_id, category_id=category_id, - data_id=data_id) + data = PolicyManager.delete_object_assignment( + user_id=user_id, policy_id=uuid, + object_id=perimeter_id, category_id=category_id, + data_id=data_id) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"result": True} @@ -244,7 +252,8 @@ class ActionAssignments(Resource): ) @check_auth - def get(self, uuid=None, perimeter_id=None, category_id=None, data_id=None, user_id=None): + def get(self, uuid=None, perimeter_id=None, category_id=None, + data_id=None, user_id=None): """Retrieve all action assignment or a specific one for a given policy :param uuid: uuid of the policy @@ -263,16 +272,18 @@ class ActionAssignments(Resource): :internal_api: get_action_assignments """ try: - data = PolicyManager.get_action_assignments(user_id=user_id, policy_id=uuid, - action_id=perimeter_id, category_id=category_id) + data = PolicyManager.get_action_assignments( + user_id=user_id, policy_id=uuid, + action_id=perimeter_id, category_id=category_id) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"action_assignments": data} @check_auth - def post(self, uuid=None, perimeter_id=None, category_id=None, data_id=None, user_id=None): + def post(self, uuid=None, perimeter_id=None, category_id=None, + data_id=None, user_id=None): """Create an action assignment. :param uuid: uuid of the policy @@ -299,17 +310,19 @@ class ActionAssignments(Resource): data_id = request.json.get("data_id") category_id = request.json.get("category_id") perimeter_id = request.json.get("id") - data = PolicyManager.add_action_assignment(user_id=user_id, policy_id=uuid, - action_id=perimeter_id, category_id=category_id, - data_id=data_id) + data = PolicyManager.add_action_assignment( + user_id=user_id, policy_id=uuid, + action_id=perimeter_id, category_id=category_id, + data_id=data_id) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"action_assignments": data} @check_auth - def delete(self, uuid=None, perimeter_id=None, category_id=None, data_id=None, user_id=None): + def delete(self, uuid=None, perimeter_id=None, category_id=None, + data_id=None, user_id=None): """Delete a action assignment for a given policy :param uuid: uuid of the policy @@ -324,11 +337,12 @@ class ActionAssignments(Resource): :internal_api: delete_action_assignment """ try: - data = PolicyManager.delete_action_assignment(user_id=user_id, policy_id=uuid, - action_id=perimeter_id, category_id=category_id, - data_id=data_id) + data = PolicyManager.delete_action_assignment( + user_id=user_id, policy_id=uuid, + action_id=perimeter_id, category_id=category_id, + data_id=data_id) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"result": True} diff --git a/moon_manager/moon_manager/api/data.py b/moon_manager/moon_manager/api/data.py index 61fe92bf..b74ca385 100644 --- a/moon_manager/moon_manager/api/data.py +++ b/moon_manager/moon_manager/api/data.py @@ -9,13 +9,13 @@ Data are elements used to create rules from flask import request from flask_restful import Resource -from oslo_log import log as logging +import logging from python_moonutilities.security_functions import check_auth from python_moondb.core import PolicyManager -__version__ = "0.2.0" +__version__ = "4.3.2" -LOG = logging.getLogger("moon.manager.api." + __name__) +logger = logging.getLogger("moon.manager.api." + __name__) class SubjectData(Resource): @@ -58,7 +58,7 @@ class SubjectData(Resource): category_id=category_id, data_id=data_id) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"subject_data": data} @@ -93,7 +93,7 @@ class SubjectData(Resource): category_id=category_id, value=request.json) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"subject_data": data} @@ -117,7 +117,7 @@ class SubjectData(Resource): policy_id=uuid, data_id=data_id) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"result": True} @@ -163,7 +163,7 @@ class ObjectData(Resource): category_id=category_id, data_id=data_id) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"object_data": data} @@ -198,7 +198,7 @@ class ObjectData(Resource): category_id=category_id, value=request.json) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"object_data": data} @@ -222,7 +222,7 @@ class ObjectData(Resource): policy_id=uuid, data_id=data_id) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"result": True} @@ -268,7 +268,7 @@ class ActionData(Resource): category_id=category_id, data_id=data_id) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"action_data": data} @@ -303,7 +303,7 @@ class ActionData(Resource): category_id=category_id, value=request.json) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"action_data": data} @@ -327,7 +327,7 @@ class ActionData(Resource): policy_id=uuid, data_id=data_id) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"result": True} diff --git a/moon_manager/moon_manager/api/generic.py b/moon_manager/moon_manager/api/generic.py index f46bfd35..c79520f7 100644 --- a/moon_manager/moon_manager/api/generic.py +++ b/moon_manager/moon_manager/api/generic.py @@ -7,13 +7,13 @@ Those API are helping API used to manage the Moon platform. """ from flask_restful import Resource, request -from oslo_log import log as logging +import logging import moon_manager.api from python_moonutilities.security_functions import check_auth -__version__ = "0.1.0" +__version__ = "4.3.2" -LOG = logging.getLogger("moon.manager.api." + __name__) +logger = logging.getLogger("moon.manager.api." + __name__) class Status(Resource): @@ -120,7 +120,8 @@ class API(Resource): 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))) + object_list = list(filter(lambda x: "__" not in x, + dir(group_api_obj))) for obj in map(lambda x: eval("moon_manager.api.{}.{}".format(api_name, x)), object_list): if "__urls__" in dir(obj): api_desc[api_name][obj.__name__] = dict() @@ -134,7 +135,7 @@ class API(Resource): if endpoint_id in api_desc[group_id]: return {group_id: {endpoint_id: api_desc[group_id][endpoint_id]}} elif len(endpoint_id) > 0: - LOG.error("Unknown endpoint_id {}".format(endpoint_id)) + 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/moon_manager/moon_manager/api/meta_data.py b/moon_manager/moon_manager/api/meta_data.py index 9dc04cc7..28aab445 100644 --- a/moon_manager/moon_manager/api/meta_data.py +++ b/moon_manager/moon_manager/api/meta_data.py @@ -9,13 +9,13 @@ Meta Data are elements used to create Meta data (skeleton of security policies) from flask import request from flask_restful import Resource -from oslo_log import log as logging +import logging from python_moonutilities.security_functions import check_auth from python_moondb.core import ModelManager -__version__ = "0.2.0" +__version__ = "4.3.2" -LOG = logging.getLogger("moon.manager.api." + __name__) +logger = logging.getLogger("moon.manager.api." + __name__) class SubjectCategories(Resource): @@ -47,7 +47,7 @@ class SubjectCategories(Resource): data = ModelManager.get_subject_categories( user_id=user_id, category_id=category_id) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"subject_categories": data} @@ -74,7 +74,7 @@ class SubjectCategories(Resource): data = ModelManager.add_subject_category( user_id=user_id, value=request.json) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"subject_categories": data} @@ -95,7 +95,7 @@ class SubjectCategories(Resource): data = ModelManager.delete_subject_category( user_id=user_id, category_id=category_id) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"result": True} @@ -130,7 +130,7 @@ class ObjectCategories(Resource): data = ModelManager.get_object_categories( user_id=user_id, category_id=category_id) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"object_categories": data} @@ -157,7 +157,7 @@ class ObjectCategories(Resource): data = ModelManager.add_object_category( user_id=user_id, value=request.json) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"object_categories": data} @@ -178,7 +178,7 @@ class ObjectCategories(Resource): data = ModelManager.delete_object_category( user_id=user_id, category_id=category_id) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"result": True} @@ -213,7 +213,7 @@ class ActionCategories(Resource): data = ModelManager.get_action_categories( user_id=user_id, category_id=category_id) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"action_categories": data} @@ -240,7 +240,7 @@ class ActionCategories(Resource): data = ModelManager.add_action_category( user_id=user_id, value=request.json) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"action_categories": data} @@ -261,7 +261,7 @@ class ActionCategories(Resource): data = ModelManager.delete_action_category( user_id=user_id, category_id=category_id) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"result": True} diff --git a/moon_manager/moon_manager/api/meta_rules.py b/moon_manager/moon_manager/api/meta_rules.py index 21552dd7..25ae5aac 100644 --- a/moon_manager/moon_manager/api/meta_rules.py +++ b/moon_manager/moon_manager/api/meta_rules.py @@ -9,13 +9,13 @@ Meta rules are skeleton for security policies from flask import request from flask_restful import Resource -from oslo_log import log as logging +import logging from python_moonutilities.security_functions import check_auth from python_moondb.core import ModelManager -__version__ = "0.1.0" +__version__ = "4.3.2" -LOG = logging.getLogger("moon.manager.api." + __name__) +logger = logging.getLogger("moon.manager.api." + __name__) class MetaRules(Resource): @@ -54,7 +54,7 @@ class MetaRules(Resource): data = ModelManager.get_meta_rules( user_id=user_id, meta_rule_id=meta_rule_id) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"meta_rules": data} @@ -89,7 +89,7 @@ class MetaRules(Resource): data = ModelManager.add_meta_rule( user_id=user_id, meta_rule_id=None, value=request.json) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"meta_rules": data} @@ -124,7 +124,7 @@ class MetaRules(Resource): data = ModelManager.set_meta_rule( user_id=user_id, meta_rule_id=meta_rule_id, value=request.json) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"meta_rules": data} @@ -159,7 +159,7 @@ class MetaRules(Resource): data = ModelManager.delete_meta_rule( user_id=user_id, meta_rule_id=meta_rule_id) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"result": True} diff --git a/moon_manager/moon_manager/api/models.py b/moon_manager/moon_manager/api/models.py index 62866191..07b10d90 100644 --- a/moon_manager/moon_manager/api/models.py +++ b/moon_manager/moon_manager/api/models.py @@ -8,13 +8,13 @@ Models aggregate multiple meta rules from flask import request from flask_restful import Resource -from oslo_log import log as logging +import logging from python_moonutilities.security_functions import check_auth from python_moondb.core import ModelManager -__version__ = "0.1.0" +__version__ = "4.3.2" -LOG = logging.getLogger("moon.manager.api." + __name__) +logger = logging.getLogger("moon.manager.api." + __name__) class Models(Resource): @@ -47,7 +47,7 @@ class Models(Resource): try: data = ModelManager.get_models(user_id=user_id, model_id=uuid) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"models": data} @@ -76,7 +76,7 @@ class Models(Resource): data = ModelManager.add_model( user_id=user_id, model_id=uuid, value=request.json) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"models": data} @@ -96,7 +96,7 @@ class Models(Resource): try: data = ModelManager.delete_model(user_id=user_id, model_id=uuid) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"result": True} @@ -120,7 +120,7 @@ class Models(Resource): data = ModelManager.update_model( user_id=user_id, model_id=uuid, value=request.json) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"models": data} diff --git a/moon_manager/moon_manager/api/pdp.py b/moon_manager/moon_manager/api/pdp.py index 9183c25d..4f11135e 100644 --- a/moon_manager/moon_manager/api/pdp.py +++ b/moon_manager/moon_manager/api/pdp.py @@ -16,21 +16,43 @@ from python_moonutilities.security_functions import check_auth from python_moondb.core import PDPManager from python_moondb.core import PolicyManager from python_moondb.core import ModelManager -from python_moonutilities import configuration +from python_moonutilities import configuration, exceptions -__version__ = "0.1.0" +__version__ = "4.3.2" -LOG = logging.getLogger("moon.manager.api." + __name__) +logger = logging.getLogger("moon.manager.api." + __name__) def delete_pod(uuid): - raise NotImplementedError + conf = configuration.get_configuration("components/orchestrator") + hostname = conf["components/orchestrator"].get("hostname", "orchestrator") + port = conf["components/orchestrator"].get("port", 80) + proto = conf["components/orchestrator"].get("protocol", "http") + # while True: + # try: + url = "{}://{}:{}/pods".format(proto, hostname, port) + req = requests.get(url) + # except requests.exceptions.ConnectionError: + # logger.warning("Orchestrator is not ready, standby... {}".format(url)) + # time.sleep(1) + # else: + # break + for pod_key, pod_list in req.json().get("pods", {}).items(): + for pod_value in pod_list: + if "pdp_id" in pod_value: + if pod_value["pdp_id"] == uuid: + req = requests.delete("{}://{}:{}/pods/{}".format(proto, hostname, port, pod_key)) + if req.status_code != 200: + logger.warning("Cannot delete pod {} - {}".format(pod_key, pod_value['name'])) + logger.debug(req.content) + # Note (Asteroide): no need to go further if one match + break def add_pod(uuid, data): if not data.get("keystone_project_id"): return - LOG.info("Add a new pod {}".format(data)) + logger.info("Add a new pod {}".format(data)) if "pdp_id" not in data: data["pdp_id"] = uuid data['policies'] = PolicyManager.get_policies(user_id="admin") @@ -45,12 +67,21 @@ def add_pod(uuid, data): "{}://{}:{}/pods".format(proto, hostname, port), json=data, headers={"content-type": "application/json"}) - except requests.exceptions.ConnectionError: - LOG.warning("Orchestrator is not ready, standby...") + except requests.exceptions.ConnectionError as e: + logger.warning("add_pod: Orchestrator is not ready, standby...") + logger.exception(e) time.sleep(1) else: break - LOG.info(req.text) + logger.info(req.text) + + +def check_keystone_pid(k_pid): + data = PDPManager.get_pdp(user_id="admin") + for pdp_key, pdp_value in data.items(): + logger.info("pdp={}".format(pdp_value)) + if pdp_value["keystone_project_id"] == k_pid: + return True class PDP(Resource): @@ -84,7 +115,7 @@ class PDP(Resource): try: data = PDPManager.get_pdp(user_id=user_id, pdp_id=uuid) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"pdps": data} @@ -115,14 +146,17 @@ class PDP(Resource): data = dict(request.json) if not data.get("keystone_project_id"): data["keystone_project_id"] = None + else: + if check_keystone_pid(data.get("keystone_project_id")): + raise exceptions.PdpKeystoneMappingConflict data = PDPManager.add_pdp( user_id=user_id, pdp_id=None, value=request.json) uuid = list(data.keys())[0] - LOG.info("data={}".format(data)) - LOG.info("uuid={}".format(uuid)) + logger.debug("data={}".format(data)) + logger.debug("uuid={}".format(uuid)) add_pod(uuid=uuid, data=data[uuid]) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"pdps": data} @@ -143,7 +177,7 @@ class PDP(Resource): data = PDPManager.delete_pdp(user_id=user_id, pdp_id=uuid) delete_pod(uuid) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"result": True} @@ -168,13 +202,16 @@ class PDP(Resource): _data = dict(request.json) if not _data.get("keystone_project_id"): _data["keystone_project_id"] = None + else: + if check_keystone_pid(_data.get("keystone_project_id")): + raise exceptions.PdpKeystoneMappingConflict data = PDPManager.update_pdp( user_id=user_id, pdp_id=uuid, value=_data) - LOG.info("data={}".format(data)) - LOG.info("uuid={}".format(uuid)) + logger.debug("data={}".format(data)) + logger.debug("uuid={}".format(uuid)) add_pod(uuid=uuid, data=data[uuid]) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"pdps": data} diff --git a/moon_manager/moon_manager/api/perimeter.py b/moon_manager/moon_manager/api/perimeter.py index 8196e627..d3948bc1 100644 --- a/moon_manager/moon_manager/api/perimeter.py +++ b/moon_manager/moon_manager/api/perimeter.py @@ -12,13 +12,13 @@ from flask import request from flask_restful import Resource -from oslo_log import log as logging +import logging from python_moonutilities.security_functions import check_auth from python_moondb.core import PolicyManager -__version__ = "0.2.0" +__version__ = "4.3.2" -LOG = logging.getLogger("moon.manager.api." + __name__) +logger = logging.getLogger("moon.manager.api." + __name__) class Subjects(Resource): @@ -59,7 +59,7 @@ class Subjects(Resource): perimeter_id=perimeter_id ) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"subjects": data} @@ -101,7 +101,7 @@ class Subjects(Resource): user_id=user_id, policy_id=uuid, perimeter_id=perimeter_id, value=request.json) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"subjects": data} @@ -143,7 +143,7 @@ class Subjects(Resource): user_id=user_id, policy_id=uuid, perimeter_id=perimeter_id, value=request.json) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"subjects": data} @@ -170,7 +170,7 @@ class Subjects(Resource): data = PolicyManager.delete_subject( user_id=user_id, policy_id=uuid, perimeter_id=perimeter_id) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"result": True} @@ -213,7 +213,7 @@ class Objects(Resource): perimeter_id=perimeter_id ) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"objects": data} @@ -248,7 +248,7 @@ class Objects(Resource): user_id=user_id, policy_id=uuid, perimeter_id=perimeter_id, value=request.json) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"objects": data} @@ -283,7 +283,7 @@ class Objects(Resource): user_id=user_id, policy_id=uuid, perimeter_id=perimeter_id, value=request.json) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"objects": data} @@ -307,7 +307,7 @@ class Objects(Resource): data = PolicyManager.delete_object( user_id=user_id, policy_id=uuid, perimeter_id=perimeter_id) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"result": True} @@ -347,7 +347,7 @@ class Actions(Resource): data = PolicyManager.get_actions( user_id=user_id, policy_id=uuid, perimeter_id=perimeter_id) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"actions": data} @@ -382,7 +382,7 @@ class Actions(Resource): user_id=user_id, policy_id=uuid, perimeter_id=perimeter_id, value=request.json) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"actions": data} @@ -417,7 +417,7 @@ class Actions(Resource): user_id=user_id, policy_id=uuid, perimeter_id=perimeter_id, value=request.json) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"actions": data} @@ -441,7 +441,7 @@ class Actions(Resource): data = PolicyManager.delete_action( user_id=user_id, policy_id=uuid, perimeter_id=perimeter_id) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"result": True} diff --git a/moon_manager/moon_manager/api/policies.py b/moon_manager/moon_manager/api/policies.py index f34276bb..0d7a52a9 100644 --- a/moon_manager/moon_manager/api/policies.py +++ b/moon_manager/moon_manager/api/policies.py @@ -9,13 +9,13 @@ Policies are instances of security models and implement security policies from flask import request from flask_restful import Resource -from oslo_log import log as logging +import logging from python_moonutilities.security_functions import check_auth from python_moondb.core import PolicyManager -__version__ = "0.1.0" +__version__ = "4.3.2" -LOG = logging.getLogger("moon.manager.api." + __name__) +logger = logging.getLogger("moon.manager.api." + __name__) class Policies(Resource): @@ -49,7 +49,7 @@ class Policies(Resource): try: data = PolicyManager.get_policies(user_id=user_id, policy_id=uuid) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"policies": data} @@ -80,7 +80,7 @@ class Policies(Resource): data = PolicyManager.add_policy( user_id=user_id, policy_id=uuid, value=request.json) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"policies": data} @@ -100,7 +100,7 @@ class Policies(Resource): try: data = PolicyManager.delete_policy(user_id=user_id, policy_id=uuid) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"result": True} @@ -125,7 +125,7 @@ class Policies(Resource): data = PolicyManager.update_policy( user_id=user_id, policy_id=uuid, value=request.json) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"policies": data} diff --git a/moon_manager/moon_manager/api/rules.py b/moon_manager/moon_manager/api/rules.py index b25365df..e6c46bf4 100644 --- a/moon_manager/moon_manager/api/rules.py +++ b/moon_manager/moon_manager/api/rules.py @@ -8,13 +8,13 @@ Rules (TODO) from flask import request from flask_restful import Resource -from oslo_log import log as logging +import logging from python_moonutilities.security_functions import check_auth from python_moondb.core import PolicyManager -__version__ = "0.1.0" +__version__ = "4.3.2" -LOG = logging.getLogger("moon.manager.api." + __name__) +logger = logging.getLogger("moon.manager.api." + __name__) class Rules(Resource): @@ -52,7 +52,7 @@ class Rules(Resource): policy_id=uuid, rule_id=rule_id) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"rules": data} @@ -114,7 +114,7 @@ class Rules(Resource): meta_rule_id=args['meta_rule_id'], value=args) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"rules": data} @@ -133,7 +133,7 @@ class Rules(Resource): data = PolicyManager.delete_rule( user_id=user_id, policy_id=uuid, rule_id=rule_id) except Exception as e: - LOG.error(e, exc_info=True) + logger.error(e, exc_info=True) return {"result": False, "error": str(e)}, 500 return {"result": True} diff --git a/moon_manager/moon_manager/http_server.py b/moon_manager/moon_manager/http_server.py index 6aa2cd44..d67e1121 100644 --- a/moon_manager/moon_manager/http_server.py +++ b/moon_manager/moon_manager/http_server.py @@ -24,7 +24,7 @@ from python_moonutilities import configuration, exceptions from python_moondb.core import PDPManager -LOG = logging.getLogger("moon.manager.http_server") +logger = logging.getLogger("moon.manager.http_server") __API__ = ( Status, Logs, API, @@ -88,7 +88,8 @@ class Root(Resource): __methods = ("get", "post", "put", "delete", "options") def get(self): - tree = {"/": {"methods": ("get",), "description": "List all methods for that service."}} + tree = {"/": {"methods": ("get",), + "description": "List all methods for that service."}} for item in __API__: tree[item.__name__] = {"urls": item.__urls__} _methods = [] @@ -109,7 +110,8 @@ class HTTPServer(Server): super(HTTPServer, self).__init__(host=host, port=port, **kwargs) self.app = Flask(__name__) conf = configuration.get_configuration("components/manager") - self.manager_hostname = conf["components/manager"].get("hostname", "manager") + self.manager_hostname = conf["components/manager"].get("hostname", + "manager") self.manager_port = conf["components/manager"].get("port", 80) # TODO : specify only few urls instead of * CORS(self.app) @@ -143,10 +145,10 @@ class HTTPServer(Server): except sqlalchemy.exc.ProgrammingError: time.sleep(1) if first: - LOG.warning("Waiting for the database...") + logger.warning("Waiting for the database...") first = False else: - LOG.warning("Database is up, resuming operations...") + logger.warning("Database is up, resuming operations...") break def run(self): diff --git a/moon_manager/moon_manager/server.py b/moon_manager/moon_manager/server.py index f4c01611..70ddaee0 100644 --- a/moon_manager/moon_manager/server.py +++ b/moon_manager/moon_manager/server.py @@ -3,17 +3,14 @@ # license which can be found in the file 'LICENSE' in this package distribution # or at 'http://www.apache.org/licenses/LICENSE-2.0'. -from oslo_config import cfg -from oslo_log import log as logging +import logging from python_moonutilities import configuration, exceptions from moon_manager.http_server import HTTPServer -LOG = logging.getLogger("moon.manager.server") -CONF = cfg.CONF -DOMAIN = "moon_manager" +logger = logging.getLogger("moon.manager.server") -def main(): +def create_server(): configuration.init_logging() try: conf = configuration.get_configuration("components/manager") @@ -24,11 +21,19 @@ def main(): hostname = "manager" bind = "127.0.0.1" port = 80 - configuration.add_component(uuid="manager", name=hostname, port=port, bind=bind) - LOG.info("Starting server with IP {} on port {} bind to {}".format(hostname, port, bind)) + configuration.add_component(uuid="manager", + 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) -if __name__ == '__main__': - server = main() +def run(): + server = create_server() server.run() + + +if __name__ == '__main__': + run() diff --git a/moon_manager/setup.py b/moon_manager/setup.py index bd8a70f0..35c944c3 100644 --- a/moon_manager/setup.py +++ b/moon_manager/setup.py @@ -40,7 +40,7 @@ setup( entry_points={ 'console_scripts': [ - 'moon_manager = moon_manager.server:main', + 'moon_manager = moon_manager.server:create_server', ], } diff --git a/moon_manager/tests/unit_python/api/meta_data_test.py b/moon_manager/tests/unit_python/api/meta_data_test.py new file mode 100644 index 00000000..8fb39ae1 --- /dev/null +++ b/moon_manager/tests/unit_python/api/meta_data_test.py @@ -0,0 +1,196 @@ +import json +import api.utilities as utilities + +#subject_categories_test + + +def get_subject_categories(client): + req = client.get("/subject_categories") + subject_categories = utilities.get_json(req.data) + return req, subject_categories + + +def add_subject_categories(client, name): + data = { + "name": name, + "description": "description of {}".format(name) + } + req = client.post("/subject_categories", data=json.dumps(data), + headers={'Content-Type': 'application/json'}) + subject_categories = utilities.get_json(req.data) + return req, subject_categories + + +def delete_subject_categories(client, name): + request, subject_categories = get_subject_categories(client) + for key, value in subject_categories['subject_categories'].items(): + if value['name'] == name: + req = client.delete("/subject_categories/{}".format(key)) + break + return req + + +def delete_subject_categories_without_id(client): + req = client.delete("/subject_categories/{}".format("")) + return req + + +def test_get_subject_categories(): + client = utilities.register_client() + req, subject_categories = get_subject_categories(client) + assert req.status_code == 200 + assert isinstance(subject_categories, dict) + assert "subject_categories" in subject_categories + + +def test_add_subject_categories(): + client = utilities.register_client() + req, subject_categories = add_subject_categories(client, "testuser") + assert req.status_code == 200 + assert isinstance(subject_categories, dict) + value = list(subject_categories["subject_categories"].values())[0] + assert "subject_categories" in subject_categories + assert value['name'] == "testuser" + assert value['description'] == "description of {}".format("testuser") + + +def test_delete_subject_categories(): + client = utilities.register_client() + req = delete_subject_categories(client, "testuser") + assert req.status_code == 200 + + +def test_delete_subject_categories_without_id(): + client = utilities.register_client() + req = delete_subject_categories_without_id(client) + assert req.status_code == 500 + + +#--------------------------------------------------------------------------- +#object_categories_test + +def get_object_categories(client): + req = client.get("/object_categories") + object_categories = utilities.get_json(req.data) + return req, object_categories + + +def add_object_categories(client, name): + data = { + "name": name, + "description": "description of {}".format(name) + } + req = client.post("/object_categories", data=json.dumps(data), + headers={'Content-Type': 'application/json'}) + object_categories = utilities.get_json(req.data) + return req, object_categories + + +def delete_object_categories(client, name): + request, object_categories = get_object_categories(client) + for key, value in object_categories['object_categories'].items(): + if value['name'] == name: + req = client.delete("/object_categories/{}".format(key)) + break + return req + + +def delete_object_categories_without_id(client): + req = client.delete("/object_categories/{}".format("")) + return req + + +def test_get_object_categories(): + client = utilities.register_client() + req, object_categories = get_object_categories(client) + assert req.status_code == 200 + assert isinstance(object_categories, dict) + assert "object_categories" in object_categories + + +def test_add_object_categories(): + client = utilities.register_client() + req, object_categories = add_object_categories(client, "testuser") + assert req.status_code == 200 + assert isinstance(object_categories, dict) + value = list(object_categories["object_categories"].values())[0] + assert "object_categories" in object_categories + assert value['name'] == "testuser" + assert value['description'] == "description of {}".format("testuser") + + +def test_delete_object_categories(): + client = utilities.register_client() + req = delete_object_categories(client, "testuser") + assert req.status_code == 200 + + +def test_delete_object_categories_without_id(): + client = utilities.register_client() + req = delete_object_categories_without_id(client) + assert req.status_code == 500 + + +#--------------------------------------------------------------------------- +#action_categories_test + +def get_action_categories(client): + req = client.get("/action_categories") + action_categories = utilities.get_json(req.data) + return req, action_categories + + +def add_action_categories(client, name): + data = { + "name": name, + "description": "description of {}".format(name) + } + req = client.post("/action_categories", data=json.dumps(data), + headers={'Content-Type': 'application/json'}) + action_categories = utilities.get_json(req.data) + return req, action_categories + + +def delete_action_categories(client, name): + request, action_categories = get_action_categories(client) + for key, value in action_categories['action_categories'].items(): + if value['name'] == name: + req = client.delete("/action_categories/{}".format(key)) + break + return req + + +def delete_action_categories_without_id(client): + req = client.delete("/action_categories/{}".format("")) + return req + + +def test_get_action_categories(): + client = utilities.register_client() + req, action_categories = get_action_categories(client) + assert req.status_code == 200 + assert isinstance(action_categories, dict) + assert "action_categories" in action_categories + + +def test_add_action_categories(): + client = utilities.register_client() + req, action_categories = add_action_categories(client, "testuser") + assert req.status_code == 200 + assert isinstance(action_categories, dict) + value = list(action_categories["action_categories"].values())[0] + assert "action_categories" in action_categories + assert value['name'] == "testuser" + assert value['description'] == "description of {}".format("testuser") + + +def test_delete_action_categories(): + client = utilities.register_client() + req = delete_action_categories(client, "testuser") + assert req.status_code == 200 + + +def test_delete_action_categories_without_id(): + client = utilities.register_client() + req = delete_action_categories_without_id(client) + assert req.status_code == 500
\ No newline at end of file diff --git a/moon_manager/tests/unit_python/api/test_pdp.py b/moon_manager/tests/unit_python/api/test_pdp.py new file mode 100644 index 00000000..a2d0cb5a --- /dev/null +++ b/moon_manager/tests/unit_python/api/test_pdp.py @@ -0,0 +1,62 @@ +import json +import api.utilities as utilities +import pytest + + +def get_pdp(client): + req = client.get("/pdp") + pdp = utilities.get_json(req.data) + return req, pdp + + +def add_pdp(client, data): + req = client.post("/pdp", data=json.dumps(data), + headers={'Content-Type': 'application/json'}) + pdp = utilities.get_json(req.data) + return req, pdp + + +def delete_pdp(client, key): + req = client.delete("/pdp/{}".format(key)) + return req + + +def delete_pdp_without_id(client): + req = client.delete("/pdp/{}".format("")) + return req + + +def test_get_pdp(): + client = utilities.register_client() + req, pdp = get_pdp(client) + assert req.status_code == 200 + assert isinstance(pdp, dict) + assert "pdps" in pdp + + +def test_add_pdp(): + data = { + "name": "testuser", + "security_pipeline": ["policy_id_1", "policy_id_2"], + "keystone_project_id": "keystone_project_id", + "description": "description of testuser" + } + client = utilities.register_client() + req, pdp = add_pdp(client, data) + assert req.status_code == 200 + assert isinstance(pdp, dict) + value = list(pdp["pdps"].values())[0] + assert "pdps" in pdp + assert value['name'] == "testuser" + assert value["description"] == "description of {}".format("testuser") + assert value["keystone_project_id"] == "keystone_project_id" + + +def test_delete_pdp(): + client = utilities.register_client() + request, pdp = get_pdp(client) + for key, value in pdp['pdps'].items(): + if value['name'] == "testuser": + success_req = delete_pdp(client, key) + break + assert success_req.status_code == 200 diff --git a/moon_manager/tests/unit_python/api/utilities.py b/moon_manager/tests/unit_python/api/utilities.py index 1c055da5..a2b0689b 100644 --- a/moon_manager/tests/unit_python/api/utilities.py +++ b/moon_manager/tests/unit_python/api/utilities.py @@ -7,6 +7,6 @@ def get_json(data): def register_client(): import moon_manager.server - server = moon_manager.server.main() + server = moon_manager.server.create_server() client = server.app.test_client() return client
\ No newline at end of file diff --git a/moon_manager/tests/unit_python/conftest.py b/moon_manager/tests/unit_python/conftest.py index c59fae40..902a41a2 100644 --- a/moon_manager/tests/unit_python/conftest.py +++ b/moon_manager/tests/unit_python/conftest.py @@ -35,23 +35,21 @@ CONF = { "bind": "0.0.0.0", "port": 8083, "container": "wukongsun/moon_orchestrator:v4.3", - "hostname": "interface" + "hostname": "orchestrator" }, - "interface": { - "bind": "0.0.0.0", - "port": 8080, - "container": "wukongsun/moon_interface:v4.3", - "hostname": "interface" - } - }, - "plugins": { - "session": { - "port": 8082, - "container": "asteroide/session:latest" - }, - "authz": { - "port": 8081, - "container": "wukongsun/moon_authz:v4.3" + "pipeline": { + "interface": { + "bind": "0.0.0.0", + "port": 8080, + "container": "wukongsun/moon_interface:v4.3", + "hostname": "interface" + }, + "authz": { + "bind": "0.0.0.0", + "port": 8081, + "container": "wukongsun/moon_authz:v4.3", + "hostname": "authz" + }, } }, "logging": { @@ -116,7 +114,7 @@ CONF = { }, "messenger": { "url": "rabbit://moon:p4sswOrd1@messenger:5672/moon" - } + }, } COMPONENTS = ( @@ -125,22 +123,50 @@ COMPONENTS = ( "database", "slave", "components/manager", + "components/orchestrator" ) +PODS = { + "pods": { + "721760dd-de5f-11e7-8001-3863bbb766f3": [ + { + "pdp_id": "b3d3e18abf3340e8b635fd49e6634ccd", + "port": 8080, + "genre": "interface", + "name": "interface-paltry", + "keystone_project_id": "a64beb1cc224474fb4badd43173e7101", + "namespace": "moon", + "container": "wukongsun/moon_interface:v4.3" + }, + { + "pdp_id": "b3d3e18abf3340e8b635fd49e6634ccd", + "meta_rule_id": "f8f49a779ceb47b3ac810f01ef71b4e0", + "port": 8081, + "genre": "authz", + "name": "authz-economic", + "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0", + "keystone_project_id": "a64beb1cc224474fb4badd43173e7101", + "namespace": "moon", + "container": "wukongsun/moon_authz:v4.3" + } + ] + } +} + def get_b64_conf(component=None): if component in CONF: return base64.b64encode( json.dumps( - CONF[component]).encode('utf-8')+b"\n").decode('utf-8') + CONF[component]).encode('utf-8') + b"\n").decode('utf-8') elif "/" in component: key1, _, key2 = component.partition("/") return base64.b64encode( json.dumps( - CONF[key1][key2]).encode('utf-8')+b"\n").decode('utf-8') + CONF[key1][key2]).encode('utf-8') + b"\n").decode('utf-8') else: return base64.b64encode( - json.dumps(CONF).encode('utf-8')+b"\n").decode('utf-8') + json.dumps(CONF).encode('utf-8') + b"\n").decode('utf-8') @pytest.fixture(autouse=True) @@ -152,7 +178,7 @@ def no_requests(monkeypatch): m.register_uri( 'GET', 'http://consul:8500/v1/kv/{}'.format(component), json=[{'Key': component, 'Value': get_b64_conf(component)}] - ) + ) m.register_uri( 'POST', 'http://keystone:5000/v3/auth/tokens', headers={'X-Subject-Token': "111111111"} @@ -171,10 +197,22 @@ def no_requests(monkeypatch): ) m.register_uri( 'POST', 'http://keystone:5000/v3/users/', - json={"users": [{ - "id": "1111111111111" - }]} + json={"users": [{"id": "1111111111111"}]} + ) + m.register_uri( + 'POST', 'http://orchestrator:8083/pods', + json=PODS, + headers={"content-type": "application/json"} + ) + m.register_uri( + 'GET', 'http://orchestrator:8083/pods', + json=PODS ) + m.register_uri( + 'DELETE', 'http://orchestrator:8083/pods/{}'.format(list([PODS['pods'].keys()])[0]), + headers={"content-type": "application/json"} + ) + print("Start populating the DB.") from python_moondb.db_manager import init_engine, main engine = init_engine() @@ -183,7 +221,6 @@ def no_requests(monkeypatch): print("End populating the DB.") yield m - # @pytest.fixture(autouse=True, scope="session") # def manage_database(): # from moon_db.db_manager import init_engine, run @@ -191,5 +228,3 @@ def no_requests(monkeypatch): # run("upgrade", logging.getLogger("db_manager"), engine) # yield # print("Will close the DB") - - diff --git a/moon_orchestrator/moon_orchestrator/api/pods.py b/moon_orchestrator/moon_orchestrator/api/pods.py index 7b89372e..a83ca9ae 100644 --- a/moon_orchestrator/moon_orchestrator/api/pods.py +++ b/moon_orchestrator/moon_orchestrator/api/pods.py @@ -27,7 +27,6 @@ class Pods(Resource): def __init__(self, **kwargs): self.driver = kwargs.get("driver") - self.create_pipeline = kwargs.get("create_pipeline_hook") @check_auth def get(self, uuid=None, user_id=None): @@ -75,7 +74,7 @@ class Pods(Resource): } """ logger.debug("POST param={}".format(request.json)) - self.create_pipeline( + self.driver.create_pipeline( request.json.get("keystone_project_id"), request.json.get("pdp_id"), request.json.get("security_pipeline"), @@ -102,7 +101,11 @@ class Pods(Resource): "message": "optional message" } """ - return {"result": True} + try: + self.driver.delete_pipeline(uuid) + return {'result': True} + except Exception as e: + return {"result": False, "message": str(e)}, 500 @check_auth def patch(self, uuid=None, user_id=None): diff --git a/moon_orchestrator/moon_orchestrator/drivers.py b/moon_orchestrator/moon_orchestrator/drivers.py index 07f012aa..b21f2639 100644 --- a/moon_orchestrator/moon_orchestrator/drivers.py +++ b/moon_orchestrator/moon_orchestrator/drivers.py @@ -5,8 +5,10 @@ from kubernetes import client, config import logging +import requests import urllib3.exceptions -from python_moonutilities import configuration +from python_moonutilities import configuration, exceptions +from python_moonutilities.misc import get_random_name logger = logging.getLogger("moon.orchestrator.drivers") @@ -36,16 +38,24 @@ class Driver: # } # } - def get_pods(self, namespace=None): + def get_slaves(self): raise NotImplementedError - def load_pod(self, data, api_client=None, ext_client=None): + def create_wrappers(self): raise NotImplementedError - def delete_pod(self, uuid=None, name=None): + def delete_wrapper(self, name): raise NotImplementedError - def get_slaves(self): + def create_pipeline(self, keystone_project_id, + pdp_id, policy_ids, manager_data=None, + active_context=None, + active_context_name=None): + raise NotImplementedError + + def delete_pipeline(self, uuid=None, name=None, namespace="moon", + active_context=None, + active_context_name=None): raise NotImplementedError @@ -55,6 +65,12 @@ class K8S(Driver): super(K8S, self).__init__() config.load_kube_config() self.client = client.CoreV1Api() + conf = configuration.get_configuration("components/orchestrator") + self.orchestrator_hostname = conf["components/orchestrator"].get("hostname", "orchestrator") + self.orchestrator_port = conf["components/orchestrator"].get("port", 80) + conf = configuration.get_configuration("components/manager") + self.manager_hostname = conf["components/manager"].get("hostname", "manager") + self.manager_port = conf["components/manager"].get("port", 80) def get_pods(self, name=None): if name: @@ -69,7 +85,7 @@ class K8S(Driver): return self.cache @staticmethod - def __create_pod(client, data): + def __create_deployment(client, data): pod_manifest = { 'apiVersion': 'extensions/v1beta1', 'kind': 'Deployment', @@ -145,29 +161,231 @@ class K8S(Driver): logger.info("Service {} created!".format(data.get('name'))) return resp - def load_pod(self, data, api_client=None, ext_client=None, expose=False): + def load_deployment_and_service(self, data, api_client=None, ext_client=None, expose=False): _client = api_client if api_client else self.client - pod = self.__create_pod(client=ext_client, data=data) + pod = self.__create_deployment(client=ext_client, data=data) self.__create_service(client=_client, data=data[0], - expose=expose) + expose=expose) self.cache[pod.metadata.uid] = data - def delete_pod(self, uuid=None, name=None): - logger.info("Deleting pod {}".format(uuid)) - # TODO: delete_namespaced_deployment - # https://github.com/kubernetes-incubator/client-python/blob/master/kubernetes/client/apis/extensions_v1beta1_api.py + @staticmethod + def delete_deployment(name=None, namespace="moon", ext_client=None): + logger.info("Deleting deployment {}".format(name)) + body = client.V1DeleteOptions(propagation_policy='Foreground') + ret = ext_client.delete_namespaced_deployment( + name=name, + namespace=namespace, + body=body + ) + logger.info(ret) + + def delete_service(self, name, namespace="moon", api_client=None): + if not api_client: + api_client = self.client + ret = api_client.delete_namespaced_service(name=name, namespace=namespace) + logger.debug("delete_service {}".format(ret)) def get_slaves(self): contexts, active_context = config.list_kube_config_contexts() return contexts, active_context + def create_wrappers(self): + contexts, active_context = self.get_slaves() + logger.debug("contexts: {}".format(contexts)) + logger.debug("active_context: {}".format(active_context)) + conf = configuration.get_configuration("components/wrapper") + hostname = conf["components/wrapper"].get( + "hostname", "wrapper") + port = conf["components/wrapper"].get("port", 80) + container = conf["components/wrapper"].get( + "container", + "wukongsun/moon_wrapper:v4.3") + for _ctx in contexts: + _config = config.new_client_from_config(context=_ctx['name']) + logger.debug("_config={}".format(_config)) + api_client = client.CoreV1Api(_config) + ext_client = client.ExtensionsV1beta1Api(_config) + data = [{ + "name": hostname + "-" + get_random_name(), + "container": container, + "port": port, + "namespace": "moon" + }, ] + self.load_deployment_and_service(data, api_client, ext_client, expose=True) + + def create_pipeline(self, keystone_project_id, + pdp_id, policy_ids, manager_data=None, + active_context=None, + active_context_name=None): + """ Create security functions + + :param keystone_project_id: the Keystone project id + :param pdp_id: the PDP ID mapped to this pipeline + :param policy_ids: the policy IDs mapped to this pipeline + :param manager_data: data needed to create pods + :param active_context: if present, add the security function in this + context + :param active_context_name: if present, add the security function in + this context name + if active_context_name and active_context are not present, add the + security function in all context (ie, in all slaves) + :return: None + """ + if not manager_data: + manager_data = dict() + for key, value in self.get_pods().items(): + for _pod in value: + if _pod.get('keystone_project_id') == keystone_project_id: + logger.warning("A pod for this Keystone project {} " + "already exists.".format(keystone_project_id)) + return + + plugins = configuration.get_plugins() + conf = configuration.get_configuration("components/pipeline") + # i_hostname = conf["components/pipeline"].get("interface").get("hostname", "interface") + i_port = conf["components/pipeline"].get("interface").get("port", 80) + i_container = conf["components/pipeline"].get("interface").get( + "container", + "wukongsun/moon_interface:v4.3") + data = [ + { + "name": "pipeline-" + get_random_name(), + "container": i_container, + "port": i_port, + 'pdp_id': pdp_id, + 'genre': "interface", + 'keystone_project_id': keystone_project_id, + "namespace": "moon" + }, + ] + logger.debug("data={}".format(data)) + policies = manager_data.get('policies') + if not policies: + logger.info("No policy data from Manager, trying to get them") + policies = requests.get("http://{}:{}/policies".format( + self.manager_hostname, self.manager_port)).json().get( + "policies", dict()) + logger.debug("policies={}".format(policies)) + models = manager_data.get('models') + if not models: + logger.info("No models data from Manager, trying to get them") + models = requests.get("http://{}:{}/models".format( + self.manager_hostname, self.manager_port)).json().get( + "models", dict()) + logger.debug("models={}".format(models)) + + for policy_id in policy_ids: + if policy_id in policies: + genre = policies[policy_id].get("genre", "authz") + if genre in plugins: + for meta_rule in models[policies[policy_id]['model_id']]['meta_rules']: + data.append({ + "name": genre + "-" + get_random_name(), + "container": plugins[genre]['container'], + 'pdp_id': pdp_id, + "port": plugins[genre].get('port', 8080), + 'genre': genre, + 'policy_id': policy_id, + 'meta_rule_id': meta_rule, + 'keystone_project_id': keystone_project_id, + "namespace": "moon" + }) + logger.debug("data={}".format(data)) + contexts, _active_context = self.get_slaves() + logger.debug("active_context_name={}".format(active_context_name)) + logger.debug("active_context={}".format(active_context)) + if active_context_name: + for _context in contexts: + if _context["name"] == active_context_name: + active_context = _context + break + if active_context: + active_context = _active_context + _config = config.new_client_from_config( + context=active_context['name']) + logger.debug("_config={}".format(_config)) + api_client = client.CoreV1Api(_config) + ext_client = client.ExtensionsV1beta1Api(_config) + self.load_deployment_and_service(data, api_client, ext_client, expose=False) + return + logger.debug("contexts={}".format(contexts)) + for _ctx in contexts: + _config = config.new_client_from_config(context=_ctx['name']) + logger.debug("_config={}".format(_config)) + api_client = client.CoreV1Api(_config) + ext_client = client.ExtensionsV1beta1Api(_config) + self.load_deployment_and_service(data, api_client, ext_client, expose=False) + + def delete_pipeline(self, uuid=None, name=None, namespace="moon", + active_context=None, + active_context_name=None): + """Delete a pipeline + + :param uuid: + :param name: + :param namespace: + :param active_context: + :param active_context_name: + :return: + """ + name_to_delete = None + if uuid and uuid in self.get_pods(): + name_to_delete = self.get_pods()[uuid][0]['name'] + elif name: + for pod_key, pod_list in self.get_pods().items(): + for pod_value in pod_list: + if pod_value.get("name") == name: + name_to_delete = pod_value.get("name") + break + if not name_to_delete: + raise exceptions.MoonError("Cannot find pipeline") + logger.info("Will delete deployment and service named {}".format(name_to_delete)) + contexts, _active_context = self.get_slaves() + if active_context_name: + for _context in contexts: + if _context["name"] == active_context_name: + active_context = _context + break + if active_context: + active_context = _active_context + _config = config.new_client_from_config( + context=active_context['name']) + logger.debug("_config={}".format(_config)) + api_client = client.CoreV1Api(_config) + ext_client = client.ExtensionsV1beta1Api(_config) + self.delete_deployment(name=name_to_delete, namespace=namespace, + ext_client=ext_client) + self.delete_service(name=name_to_delete, api_client=api_client) + return + logger.debug("contexts={}".format(contexts)) + for _ctx in contexts: + _config = config.new_client_from_config(context=_ctx['name']) + logger.debug("_config={}".format(_config)) + api_client = client.CoreV1Api(_config) + ext_client = client.ExtensionsV1beta1Api(_config) + self.delete_deployment(name=name_to_delete, namespace=namespace, + ext_client=ext_client) + self.delete_service(name=name_to_delete, api_client=api_client) + class Docker(Driver): - def load_pod(self, data, api_client=None, ext_client=None): - logger.info("Creating pod {}".format(data[0].get('name'))) + def get_slaves(self): + raise NotImplementedError + + def create_wrappers(self): + raise NotImplementedError + + def delete_wrapper(self, name): + raise NotImplementedError + + def create_pipeline(self, keystone_project_id, + pdp_id, policy_ids, manager_data=None, + active_context=None, + active_context_name=None): raise NotImplementedError - def delete_pod(self, uuid=None, name=None): - logger.info("Deleting pod {}".format(uuid)) + def delete_pipeline(self, uuid=None, name=None, namespace="moon", + active_context=None, + active_context_name=None): raise NotImplementedError diff --git a/moon_orchestrator/moon_orchestrator/http_server.py b/moon_orchestrator/moon_orchestrator/http_server.py index 00be0335..fa5308d0 100644 --- a/moon_orchestrator/moon_orchestrator/http_server.py +++ b/moon_orchestrator/moon_orchestrator/http_server.py @@ -5,7 +5,6 @@ from flask import Flask, jsonify from flask_restful import Resource, Api -from kubernetes import client, config import logging import requests import time @@ -14,7 +13,6 @@ from moon_orchestrator.api.pods import Pods from moon_orchestrator.api.generic import Status from moon_orchestrator.drivers import get_driver from python_moonutilities import configuration, exceptions -from python_moonutilities.misc import get_random_name logger = logging.getLogger("moon.orchestrator.http_server") @@ -124,11 +122,11 @@ class HTTPServer(Server): if "pdps" in pdp.json(): break logger.debug("pdp={}".format(pdp)) - self.create_wrappers() + self.driver.create_wrappers() for _pdp_key, _pdp_value in pdp.json()['pdps'].items(): if _pdp_value.get('keystone_project_id'): # TODO: select context to add security function - self.create_pipeline( + self.driver.create_pipeline( keystone_project_id=_pdp_value.get('keystone_project_id'), pdp_id=_pdp_key, policy_ids=_pdp_value.get('security_pipeline', [])) @@ -151,9 +149,7 @@ class HTTPServer(Server): self.api.add_resource(api, *api.__urls__) self.api.add_resource(Pods, *Pods.__urls__, resource_class_kwargs={ - "driver": self.driver, - "create_pipeline_hook": - self.create_pipeline, + "driver": self.driver }) def run(self): @@ -163,132 +159,3 @@ class HTTPServer(Server): def __filter_str(data): return data.replace("@", "-") - def create_wrappers(self): - contexts, active_context = self.driver.get_slaves() - logger.debug("contexts: {}".format(contexts)) - logger.debug("active_context: {}".format(active_context)) - conf = configuration.get_configuration("components/wrapper") - hostname = conf["components/wrapper"].get( - "hostname", "wrapper") - port = conf["components/wrapper"].get("port", 80) - container = conf["components/wrapper"].get( - "container", - "wukongsun/moon_wrapper:v4.3") - for _ctx in contexts: - _config = config.new_client_from_config(context=_ctx['name']) - logger.debug("_config={}".format(_config)) - api_client = client.CoreV1Api(_config) - ext_client = client.ExtensionsV1beta1Api(_config) - data = [{ - "name": hostname + "-" + get_random_name(), - "container": container, - "port": port, - "namespace": "moon" - }, ] - pod = self.driver.load_pod(data, api_client, ext_client, expose=True) - logger.debug('wrapper pod={}'.format(pod)) - - def create_pipeline(self, keystone_project_id, - pdp_id, policy_ids, manager_data=None, - active_context=None, - active_context_name=None): - """ Create security functions - - :param keystone_project_id: the Keystone project id - :param pdp_id: the PDP ID mapped to this pipeline - :param policy_ids: the policy IDs mapped to this pipeline - :param manager_data: data needed to create pods - :param active_context: if present, add the security function in this - context - :param active_context_name: if present, add the security function in - this context name - if active_context_name and active_context are not present, add the - security function in all context (ie, in all slaves) - :return: None - """ - if not manager_data: - manager_data = dict() - for key, value in self.driver.get_pods().items(): - for _pod in value: - if _pod.get('keystone_project_id') == keystone_project_id: - logger.warning("A pod for this Keystone project {} " - "already exists.".format(keystone_project_id)) - return - - plugins = configuration.get_plugins() - conf = configuration.get_configuration("components/pipeline") - # i_hostname = conf["components/pipeline"].get("interface").get("hostname", "interface") - i_port = conf["components/pipeline"].get("interface").get("port", 80) - i_container = conf["components/pipeline"].get("interface").get( - "container", - "wukongsun/moon_interface:v4.3") - data = [ - { - "name": "pipeline-" + get_random_name(), - "container": i_container, - "port": i_port, - 'pdp_id': pdp_id, - 'genre': "interface", - 'keystone_project_id': keystone_project_id, - "namespace": "moon" - }, - ] - logger.debug("data={}".format(data)) - policies = manager_data.get('policies') - if not policies: - logger.info("No policy data from Manager, trying to get them") - policies = requests.get("http://{}:{}/policies".format( - self.manager_hostname, self.manager_port)).json().get( - "policies", dict()) - logger.debug("policies={}".format(policies)) - models = manager_data.get('models') - if not models: - logger.info("No models data from Manager, trying to get them") - models = requests.get("http://{}:{}/models".format( - self.manager_hostname, self.manager_port)).json().get( - "models", dict()) - logger.debug("models={}".format(models)) - - for policy_id in policy_ids: - if policy_id in policies: - genre = policies[policy_id].get("genre", "authz") - if genre in plugins: - for meta_rule in models[policies[policy_id]['model_id']]['meta_rules']: - data.append({ - "name": genre + "-" + get_random_name(), - "container": plugins[genre]['container'], - 'pdp_id': pdp_id, - "port": plugins[genre].get('port', 8080), - 'genre': genre, - 'policy_id': policy_id, - 'meta_rule_id': meta_rule, - 'keystone_project_id': keystone_project_id, - "namespace": "moon" - }) - logger.debug("data={}".format(data)) - contexts, _active_context = self.driver.get_slaves() - logger.debug("active_context_name={}".format(active_context_name)) - logger.debug("active_context={}".format(active_context)) - if active_context_name: - for _context in contexts: - if _context["name"] == active_context_name: - active_context = _context - break - if active_context: - active_context = _active_context - _config = config.new_client_from_config( - context=active_context['name']) - logger.debug("_config={}".format(_config)) - api_client = client.CoreV1Api(_config) - ext_client = client.ExtensionsV1beta1Api(_config) - self.driver.load_pod(data, api_client, ext_client, expose=False) - return - logger.debug("contexts={}".format(contexts)) - for _ctx in contexts: - _config = config.new_client_from_config(context=_ctx['name']) - logger.debug("_config={}".format(_config)) - api_client = client.CoreV1Api(_config) - ext_client = client.ExtensionsV1beta1Api(_config) - self.driver.load_pod(data, api_client, ext_client, expose=False) - - diff --git a/moon_orchestrator/setup.py b/moon_orchestrator/setup.py index 624dba94..494bd131 100644 --- a/moon_orchestrator/setup.py +++ b/moon_orchestrator/setup.py @@ -43,7 +43,7 @@ setup( entry_points={ 'console_scripts': [ - 'moon_orchestrator = moon_orchestrator.server:main', + 'moon_orchestrator = moon_orchestrator.server:run', ], } diff --git a/moon_orchestrator/tests/unit_python/mock_pods.py b/moon_orchestrator/tests/unit_python/mock_pods.py index c5633152..84e6c7ea 100644 --- a/moon_orchestrator/tests/unit_python/mock_pods.py +++ b/moon_orchestrator/tests/unit_python/mock_pods.py @@ -251,11 +251,11 @@ def register_consul(m): json=[{'Key': component, 'Value': get_b64_conf(component)}] ) m.register_uri( - 'GET', 'http://consul:8500/v1/kv/components_port_start', + 'GET', 'http://consul:8500/v1/kv/components/port_start', json=[ { "LockIndex": 0, - "Key": "components_port_start", + "Key": "components/port_start", "Flags": 0, "Value": "MzEwMDE=", "CreateIndex": 9, @@ -264,22 +264,22 @@ def register_consul(m): ], ) m.register_uri( - 'PUT', 'http://consul:8500/v1/kv/components_port_start', + 'PUT', 'http://consul:8500/v1/kv/components/port_start', json=[], ) - m.register_uri( - 'GET', 'http://consul:8500/v1/kv/plugins?recurse=true', - json=[ - { - "LockIndex": 0, - "Key": "plugins/authz", - "Flags": 0, - "Value": "eyJjb250YWluZXIiOiAid3Vrb25nc3VuL21vb25fYXV0aHo6djQuMyIsICJwb3J0IjogODA4MX0=", - "CreateIndex": 14, - "ModifyIndex": 656 - } - ], - ) + # m.register_uri( + # 'GET', 'http://consul:8500/v1/kv/plugins?recurse=true', + # json=[ + # { + # "LockIndex": 0, + # "Key": "plugins/authz", + # "Flags": 0, + # "Value": "eyJjb250YWluZXIiOiAid3Vrb25nc3VuL21vb25fYXV0aHo6djQuMyIsICJwb3J0IjogODA4MX0=", + # "CreateIndex": 14, + # "ModifyIndex": 656 + # } + # ], + # ) def register_pdp(m): diff --git a/moon_orchestrator/tests/unit_python/utilities.py b/moon_orchestrator/tests/unit_python/utilities.py index d64e4c7b..bc4aebcc 100644 --- a/moon_orchestrator/tests/unit_python/utilities.py +++ b/moon_orchestrator/tests/unit_python/utilities.py @@ -37,21 +37,19 @@ CONF = { "container": "wukongsun/moon_orchestrator:v4.3", "hostname": "interface" }, - "interface": { - "bind": "0.0.0.0", - "port": 8080, - "container": "wukongsun/moon_interface:v4.3", - "hostname": "interface" - } - }, - "plugins": { - "session": { - "port": 8082, - "container": "asteroide/session:latest" - }, - "authz": { - "port": 8081, - "container": "wukongsun/moon_authz:v4.3" + "pipeline": { + "interface": { + "bind": "0.0.0.0", + "port": 8080, + "container": "wukongsun/moon_interface:v4.3", + "hostname": "interface" + }, + "authz": { + "bind": "0.0.0.0", + "port": 8081, + "container": "wukongsun/moon_authz:v4.3", + "hostname": "authz" + }, } }, "logging": { diff --git a/moon_wrapper/moon_wrapper/api/oslowrapper.py b/moon_wrapper/moon_wrapper/api/oslowrapper.py index 03bdfc69..ad9e430a 100644 --- a/moon_wrapper/moon_wrapper/api/oslowrapper.py +++ b/moon_wrapper/moon_wrapper/api/oslowrapper.py @@ -71,7 +71,7 @@ class OsloWrapper(Resource): logger.info("containers {}".format(containers)) for container in containers: if container.get("keystone_project_id") == project_id: - if "pipeline" in container['name']: + if "interface" in container['name']: return "http://{}:{}".format( container['name'], container['port']) @@ -80,7 +80,7 @@ class OsloWrapper(Resource): for containers in self.CACHE.containers.values(): for container in containers: if container.get("keystone_project_id") == project_id: - if "pipeline" in container['name']: + if "interface" in container['name']: return "http://{}:{}".format( container['name'], container['port']) @@ -99,18 +99,19 @@ class OsloWrapper(Resource): _object = self.__get_object(target, credentials) _action = rule _project_id = self.__get_project_id(target, credentials) - logger.debug("POST with args project={} / " - "subject={} - object={} - action={}".format( - _project_id, _subject, _object, rule)) + _pdp_id = self.CACHE.get_pdp_from_keystone_project(_project_id) interface_url = self.get_interface_url(_project_id) logger.debug("interface_url={}".format(interface_url)) req = requests.get("{}/authz/{}/{}/{}/{}".format( interface_url, - _project_id, + _pdp_id, _subject, _object, _action )) + ''' + [Note] i think here if status != 200, should raise an exception + ''' logger.debug("Get interface {}".format(req.text)) if req.status_code == 200: if req.json().get("result", False): diff --git a/moon_wrapper/setup.py b/moon_wrapper/setup.py index 6aaa343f..b6190c80 100644 --- a/moon_wrapper/setup.py +++ b/moon_wrapper/setup.py @@ -40,7 +40,7 @@ setup( entry_points={ 'console_scripts': [ - 'moon_wrapper = moon_wrapper.server:main', + 'moon_wrapper = moon_wrapper.server:run', ], } diff --git a/moon_wrapper/tests/unit_python/api/test_wrapper.py b/moon_wrapper/tests/unit_python/api/test_wrapper.py index 7e9a7421..be3e8576 100644 --- a/moon_wrapper/tests/unit_python/api/test_wrapper.py +++ b/moon_wrapper/tests/unit_python/api/test_wrapper.py @@ -1,3 +1,8 @@ +# 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 json @@ -20,9 +25,47 @@ def test_authz_true(context): 'rule': context.get('action_name'), 'target': json.dumps(_target), 'credentials': 'null'} - req = client.post("/authz", data=json.dumps(authz_data)) - assert req.status_code == 200 + req = client.post("/authz/oslo", data=json.dumps(authz_data)) + assert req.status_code is 200 assert req.data assert isinstance(req.data, bytes) assert req.data == b"True" +def test_authz_error_response_code(context): + import moon_wrapper.server + server = moon_wrapper.server.main() + client = server.app.test_client() + _target = { + 'target': { + "name": context.get('object_name'), + }, + "project_id": context.get('invalid_project_id'), + "user_id": context.get('subject_name') + } + authz_data = { + 'rule': context.get('action_name'), + 'target': json.dumps(_target), + 'credentials': 'null'} + req = client.post("/authz/oslo", data=json.dumps(authz_data)) + assert req.status_code is 200 + assert req.data + assert isinstance(req.data, bytes) + assert req.data == b"False" + +def test_authz_error_no_interface_key(context): + import moon_wrapper.server + server = moon_wrapper.server.main() + client = server.app.test_client() + _target = { + 'target': { + "name": context.get('object_name'), + }, + "project_id": context.get('project_with_no_interface_key'), + "user_id": context.get('subject_name') + } + authz_data = { + 'rule': context.get('action_name'), + 'target': json.dumps(_target), + 'credentials': 'null'} + req = client.post("/authz/oslo", data=json.dumps(authz_data)) + assert req.status_code == 403
\ No newline at end of file diff --git a/moon_wrapper/tests/unit_python/conftest.py b/moon_wrapper/tests/unit_python/conftest.py index b160ebf6..621c2014 100644 --- a/moon_wrapper/tests/unit_python/conftest.py +++ b/moon_wrapper/tests/unit_python/conftest.py @@ -1,3 +1,8 @@ +# 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 base64 import json import os @@ -5,7 +10,6 @@ import pickle import pytest import requests_mock from uuid import uuid4 -from requests.packages.urllib3.response import HTTPResponse CONF = { "openstack": { @@ -13,7 +17,7 @@ CONF = { "url": "http://keystone:5000/v3", "user": "admin", "check_token": False, - "password": "p4ssw0rd", + "password": "p4ssw0rd", # nosec "domain": "default", "certificate": False, "project": "admin" @@ -21,21 +25,21 @@ CONF = { }, "components": { "wrapper": { - "bind": "0.0.0.0", + "bind": "0.0.0.0", # nosec "port": 8080, "container": "wukongsun/moon_wrapper:v4.3", "timeout": 5, "hostname": "wrapper" }, "manager": { - "bind": "0.0.0.0", + "bind": "0.0.0.0", # nosec "port": 8082, "container": "wukongsun/moon_manager:v4.3", "hostname": "manager" }, "port_start": 31001, "orchestrator": { - "bind": "0.0.0.0", + "bind": "0.0.0.0", # nosec "port": 8083, "container": "wukongsun/moon_orchestrator:v4.3", "hostname": "orchestrator" @@ -60,7 +64,7 @@ CONF = { "logging": { "handlers": { "file": { - "filename": "/tmp/moon.log", + "filename": "/tmp/moon.log", # nosec "class": "logging.handlers.RotatingFileHandler", "level": "DEBUG", "formatter": "custom", @@ -105,7 +109,7 @@ CONF = { "master": { "url": None, "login": None, - "password": None + "password": None # nosec } }, "docker": { @@ -135,6 +139,10 @@ COMPONENTS = ( CONTEXT = { "project_id": "a64beb1cc224474fb4badd43173e7101", + "pdp_id": "b3d3e18abf3340e8b635fd49e6634ccd", + "invalid_project_id" : "invalid_project_id", + "invalid_pdp_id": "invalid_pdp_id", + "project_with_no_interface_key" : "232399a4-de5f-11e7-8001-3863bbb766f3", "subject_name": "testuser", "object_name": "vm1", "action_name": "boot", @@ -206,7 +214,7 @@ def set_env_variables(): def get_pickled_context(): - from python_moonutilities.security_functions import Context + from python_moonutilities.context import Context from python_moonutilities.cache import Cache CACHE = Cache() CACHE.update() @@ -295,6 +303,15 @@ def set_consul_and_db(monkeypatch): "keystone_project_id": "a64beb1cc224474fb4badd43173e7101", "namespace": "moon", "container": "wukongsun/moon_authz:v4.3" + }, + { + "pdp_id": "invalid_pdp_id", + "port": 8080, + "genre": "interface", + "name": "interface-paltry", + "keystone_project_id": "invalid_project_id", + "namespace": "moon", + "container": "wukongsun/moon_authz:v4.3" } ], "232399a4-de5f-11e7-8001-3863bbb766f3": [ @@ -325,6 +342,15 @@ def set_consul_and_db(monkeypatch): ], "name": "pdp_rbac", "keystone_project_id": "a64beb1cc224474fb4badd43173e7101" + }, + "invalid_pdp_id":{ + + "description": "test", + "security_pipeline": [ + "f8f49a779ceb47b3ac810f01ef71b4e0" + ], + "name": "pdp_rbac", + "keystone_project_id": "invalid_project_id" } } } @@ -671,13 +697,22 @@ def set_consul_and_db(monkeypatch): ) m.register_uri( 'GET', 'http://interface-paltry:8080/authz/{}/{}/{}/{}'.format( - CONTEXT.get("project_id"), + CONTEXT.get("pdp_id"), CONTEXT.get("subject_name"), CONTEXT.get("object_name"), CONTEXT.get("action_name"), ), json={"result": True, "message": "================"} ) + m.register_uri( + 'GET', 'http://interface-paltry:8080/authz/{}/{}/{}/{}'.format( + CONTEXT.get("invalid_pdp_id"), + CONTEXT.get("subject_name"), + CONTEXT.get("object_name"), + CONTEXT.get("action_name"), + ), + status_code=500 + ) # from moon_db.db_manager import init_engine, run # engine = init_engine() # run("upgrade", logging.getLogger("db_manager"), engine) diff --git a/python_moonutilities/Changelog b/python_moonutilities/Changelog index 91f09cbf..2c4c02a8 100644 --- a/python_moonutilities/Changelog +++ b/python_moonutilities/Changelog @@ -74,3 +74,7 @@ CHANGES 1.4.4 ----- - Code cleaning + +1.4.5 +----- +- Add PdpKeystoneMappingConflict exception diff --git a/python_moonutilities/python_moonutilities/__init__.py b/python_moonutilities/python_moonutilities/__init__.py index 6d1ac746..bcd7e545 100644 --- a/python_moonutilities/python_moonutilities/__init__.py +++ b/python_moonutilities/python_moonutilities/__init__.py @@ -3,6 +3,6 @@ # license which can be found in the file 'LICENSE' in this package distribution # or at 'http://www.apache.org/licenses/LICENSE-2.0'. -__version__ = "1.4.4" +__version__ = "1.4.5" diff --git a/python_moonutilities/python_moonutilities/cache.py b/python_moonutilities/python_moonutilities/cache.py index 851c5489..1ea59d3a 100644 --- a/python_moonutilities/python_moonutilities/cache.py +++ b/python_moonutilities/python_moonutilities/cache.py @@ -503,10 +503,14 @@ class Cache(object): else: logger.warning(" 'security_pipeline','keystone_project_id' " "key not in pdp {}".format(pdp_value)) - # for policy_id in pdp_value["security_pipeline"]: - # model_id = self.policies[policy_id]["model_id"] - # if meta_rule_id in self.models[model_id]["meta_rules"]: - # return pdp_value["keystone_project_id"] + + def get_keystone_project_id_from_pdp_id(self, pdp_id): + if pdp_id in self.pdp: + pdp_value = self.pdp.get(pdp_id) + if "security_pipeline" in pdp_value and \ + "keystone_project_id" in pdp_value: + return pdp_value["keystone_project_id"] + logger.warning("Unknown PDP ID".format(pdp_id)) def get_containers_from_keystone_project_id(self, keystone_project_id, meta_rule_id=None): diff --git a/python_moonutilities/python_moonutilities/exceptions.py b/python_moonutilities/python_moonutilities/exceptions.py index 5b9ff340..6db7bf01 100644 --- a/python_moonutilities/python_moonutilities/exceptions.py +++ b/python_moonutilities/python_moonutilities/exceptions.py @@ -443,6 +443,13 @@ class MetaRuleExisting(AdminMetaRule): logger = "ERROR" +class MetaRuleContentError(AdminMetaRule): + description = _("Invalid content of pdp.") + code = 400 + title = 'Meta Rule Error' + logger = "ERROR" + + class RuleExisting(AdminRule): description = _("The rule already exists.") code = 400 @@ -504,6 +511,7 @@ class ConsulComponentNotFound(ConsulError): title = 'Consul error' logger = "WARNING" + class ConsulComponentContentError(ConsulError): description = _("invalid content of component .") code = 500 @@ -541,6 +549,20 @@ class PdpExisting(MoonError): logger = "Error" +class PdpContentError(MoonError): + description = _("Invalid content of pdp.") + code = 409 + title = 'Pdp Error' + logger = "Error" + + +class PdpKeystoneMappingConflict(MoonError): + description = _("A pdp is already mapped to that Keystone project.") + code = 409 + title = 'Pdp Mapping Error' + logger = "Error" + + class PolicyUnknown(MoonError): description = _("The policy is unknown.") code = 400 @@ -553,4 +575,3 @@ class PolicyExisting(MoonError): code = 409 title = 'Policy Error' logger = "Error" - diff --git a/python_moonutilities/tests/unit_python/mock_repo/components_utilities.py b/python_moonutilities/tests/unit_python/mock_repo/components_utilities.py index 53c51343..11686ce4 100644 --- a/python_moonutilities/tests/unit_python/mock_repo/components_utilities.py +++ b/python_moonutilities/tests/unit_python/mock_repo/components_utilities.py @@ -35,21 +35,19 @@ CONF = { "container": "wukongsun/moon_orchestrator:v4.3", "hostname": "interface" }, - "interface": { - "bind": "0.0.0.0", - "port": 8080, - "container": "wukongsun/moon_interface:v4.3", - "hostname": "interface" - } - }, - "plugins": { - "session": { - "port": 8082, - "container": "asteroide/session:latest" - }, - "authz": { - "port": 8081, - "container": "wukongsun/moon_authz:v4.3" + "pipeline": { + "interface": { + "bind": "0.0.0.0", + "port": 8080, + "container": "wukongsun/moon_interface:v4.3", + "hostname": "interface" + }, + "authz": { + "bind": "0.0.0.0", + "port": 8081, + "container": "wukongsun/moon_authz:v4.3", + "hostname": "authz" + }, } }, "logging": { diff --git a/python_moonutilities/tests/unit_python/mock_repo/data.py b/python_moonutilities/tests/unit_python/mock_repo/data.py index d6f2613a..0e772e2c 100644 --- a/python_moonutilities/tests/unit_python/mock_repo/data.py +++ b/python_moonutilities/tests/unit_python/mock_repo/data.py @@ -5,7 +5,7 @@ components = ( "slave", "components/manager", "components/orchestrator", - "components/interface", + "components/pipeline", "components/port_start" ) diff --git a/python_moonutilities/tests/unit_python/mock_repo/urls.py b/python_moonutilities/tests/unit_python/mock_repo/urls.py index 4170213c..634f07b1 100644 --- a/python_moonutilities/tests/unit_python/mock_repo/urls.py +++ b/python_moonutilities/tests/unit_python/mock_repo/urls.py @@ -10,20 +10,7 @@ def register_components(m): ) m.register_uri( 'GET', 'http://consul:8500/v1/kv/components/port_start', - json=[{'Key': 'port_start', 'Value': comp_util.get_b64_conf("components/port_start")}] - ) - m.register_uri( - 'GET', 'http://consul:8500/v1/kv/plugins?recurse=true', - json=[ - { - "LockIndex": 0, - "Key": "plugins/authz", - "Flags": 0, - "Value": "eyJjb250YWluZXIiOiAid3Vrb25nc3VuL21vb25fYXV0aHo6djQuMyIsICJwb3J0IjogODA4MX0=", - "CreateIndex": 14, - "ModifyIndex": 656 - } - ], + json=[{'Key': 'components/port_start', 'Value': comp_util.get_b64_conf("components/port_start")}] ) m.register_uri( 'PUT', 'http://consul:8500/v1/kv/components/port_start', diff --git a/python_moonutilities/tests/unit_python/test_configuration.py b/python_moonutilities/tests/unit_python/test_configuration.py index 87ebb534..5267179e 100644 --- a/python_moonutilities/tests/unit_python/test_configuration.py +++ b/python_moonutilities/tests/unit_python/test_configuration.py @@ -5,7 +5,8 @@ import requests_mock def test_get_configuration_success(): from python_moonutilities import configuration - assert configuration.get_configuration("components/port_start")["port_start"] == comp_util.CONF["components"]["port_start"] + assert configuration.get_configuration("components/port_start")["components/port_start"] == comp_util.CONF["components"]["port_start"] + @requests_mock.Mocker(kw='mock') def test_get_configuration_mutliple_list_success(**kwargs): @@ -20,6 +21,7 @@ def test_get_configuration_mutliple_list_success(**kwargs): assert len(configuration.get_configuration("components/port_start")) == 2 + @requests_mock.Mocker(kw='mock') def test_get_configuration_mutliple_list_failure(**kwargs): from python_moonutilities import configuration @@ -34,6 +36,7 @@ def test_get_configuration_mutliple_list_failure(**kwargs): configuration.get_configuration("components/port_start") assert str(exception_info.value) == '500: Consul Content error' + @requests_mock.Mocker(kw='mock') def test_get_configuration_not_found(**kwargs): from python_moonutilities import configuration @@ -44,6 +47,7 @@ def test_get_configuration_not_found(**kwargs): configuration.get_configuration("components/port_start_wrong") assert str(exception_info.value) == '500: Consul error' + @requests_mock.Mocker(kw='mock') def test_get_configuration_invalid_response(**kwargs): from python_moonutilities import configuration @@ -55,6 +59,7 @@ def test_get_configuration_invalid_response(**kwargs): configuration.get_configuration("components/port_start") assert str(exception_info.value) == '500: Consul Content error' + ################################ increment_port #################################### @requests_mock.Mocker(kw='mock') def test_put_increment_port_invalidkey_failure(**kwargs): @@ -67,6 +72,7 @@ def test_put_increment_port_invalidkey_failure(**kwargs): configuration.increment_port() assert str(exception_info.value) == '500: Consul Content error' + @requests_mock.Mocker(kw='mock') def test_put_increment_port_failure(**kwargs): from python_moonutilities import configuration @@ -76,14 +82,15 @@ def test_put_increment_port_failure(**kwargs): ], status_code=200) with pytest.raises(Exception) as exception_info: configuration.increment_port() - assert str(exception_info.value) == '400: Consul error' + assert str(exception_info.value) == '500: Consul Content error' def test_increment_port_success(): from python_moonutilities import configuration cur_port = comp_util.CONF["components"]["port_start"] incremented_port = configuration.increment_port() - assert incremented_port == cur_port + 1 + assert incremented_port == cur_port + 1 + ################################ plugin #################################### def test_get_plugins_success(): @@ -91,60 +98,13 @@ def test_get_plugins_success(): plugin = configuration.get_plugins() assert plugin is not None -@requests_mock.Mocker(kw='mock') -def test_get_plugins_mutliple_list_success(**kwargs): - from python_moonutilities import configuration - - kwargs['mock'].get('http://consul:8500/v1/kv/plugins?recurse=true', - json=[ - {'Key': 'plugins/authz', 'Value': 'eyJjb250YWluZXIiOiAid3Vrb25nc3VuL21vb25fYXV0aHo6djQuMyIsICJwb3J0IjogODA4MX0='}, - {'Key': 'plugins/authz', 'Value': 'eyJjb250YWluZXIiOiAid3Vrb25nc3VuL21vb25fYXV0aHo6djQuMyIsICJwb3J0IjogODA4MX0='} - ] - ) - - res = configuration.get_plugins() - assert bool(res) - -@requests_mock.Mocker(kw='mock') -def test_get_plugins_mutliple_list_failure(**kwargs): - from python_moonutilities import configuration - - kwargs['mock'].get('http://consul:8500/v1/kv/plugins?recurse=true', - json=[ - {'Key': 'plugins/authz', 'Value': "eyJjb250YWluZXIiOiAid3Vrb25"}, - {'invalidKey': 'plugins/authz', 'Value': "eyJjb250YWluZXIiOiAid3Vrb25"} - ] - ) - with pytest.raises(Exception) as exception_info: - configuration.get_plugins() - assert str(exception_info.value) == '500: Consul Content error' - -@requests_mock.Mocker(kw='mock') -def test_get_plugins_not_found(**kwargs): - from python_moonutilities import configuration - - kwargs['mock'].get('http://consul:8500/v1/kv/plugins?recurse=true', json=[ - ], status_code=500) - with pytest.raises(Exception) as exception_info: - configuration.get_plugins() - assert str(exception_info.value) == '400: Consul error' - -@requests_mock.Mocker(kw='mock') -def test_get_plugins_invalid_response(**kwargs): - from python_moonutilities import configuration - - kwargs['mock'].get('http://consul:8500/v1/kv/plugins?recurse=true', json=[ - {"invalidKey":'invalid', 'Value': "jb250"} - ]) - with pytest.raises(Exception) as exception_info: - configuration.get_plugins() - assert str(exception_info.value) == '500: Consul Content error' ################################ component #################################### def test_get_components(): from python_moonutilities import configuration assert isinstance(configuration.get_components(), dict) + @requests_mock.Mocker(kw='mock') def test_get_components_mutliple_list_success(**kwargs): from python_moonutilities import configuration @@ -159,6 +119,7 @@ def test_get_components_mutliple_list_success(**kwargs): res = configuration.get_components() assert bool(res) + @requests_mock.Mocker(kw='mock') def test_get_components_mutliple_list_failure(**kwargs): from python_moonutilities import configuration @@ -173,6 +134,7 @@ def test_get_components_mutliple_list_failure(**kwargs): configuration.get_components() assert str(exception_info.value) == '500: Consul Content error' + @requests_mock.Mocker(kw='mock') def test_get_components_not_found(**kwargs): from python_moonutilities import configuration @@ -183,6 +145,7 @@ def test_get_components_not_found(**kwargs): configuration.get_components() assert str(exception_info.value) == '400: Consul error' + @requests_mock.Mocker(kw='mock') def test_get_components_invalid_response(**kwargs): from python_moonutilities import configuration diff --git a/tools/moon_kubernetes/conf/moon.conf b/tools/moon_kubernetes/conf/moon.conf index cf3f5c58..28ad7a8e 100644 --- a/tools/moon_kubernetes/conf/moon.conf +++ b/tools/moon_kubernetes/conf/moon.conf @@ -22,12 +22,12 @@ components: port: 8080 bind: 0.0.0.0 hostname: interface - container: wukongsun/moon_interface:v4.3 + container: wukongsun/moon_interface:latest authz: port: 8081 bind: 0.0.0.0 hostname: interface - container: wukongsun/moon_authz:v4.3 + container: wukongsun/moon_authz:latest session: container: asteroide/session:latest port: 8082 @@ -35,7 +35,7 @@ components: port: 8083 bind: 0.0.0.0 hostname: orchestrator - container: wukongsun/moon_orchestrator:v4.3 + container: wukongsun/moon_orchestrator:latest external: port: 30003 hostname: orchestrator @@ -43,13 +43,13 @@ components: port: 8080 bind: 0.0.0.0 hostname: wrapper - container: wukongsun/moon_wrapper:v4.3.1 + container: wukongsun/moon_wrapper:latest timeout: 5 manager: port: 8082 bind: 0.0.0.0 hostname: manager - container: wukongsun/moon_manager:v4.3.1 + container: wukongsun/moon_manager:latest external: port: 30001 hostname: manager diff --git a/tools/moon_kubernetes/templates/moon_manager.yaml b/tools/moon_kubernetes/templates/moon_manager.yaml index 9d4a09a8..28913f48 100644 --- a/tools/moon_kubernetes/templates/moon_manager.yaml +++ b/tools/moon_kubernetes/templates/moon_manager.yaml @@ -13,7 +13,7 @@ spec: hostname: manager containers: - name: manager - image: wukongsun/moon_manager:v4.3.1 + image: wukongsun/moon_manager:latest ports: - containerPort: 8082 --- diff --git a/tools/moon_kubernetes/templates/moon_orchestrator.yaml b/tools/moon_kubernetes/templates/moon_orchestrator.yaml index 419f2d52..9c34a60b 100644 --- a/tools/moon_kubernetes/templates/moon_orchestrator.yaml +++ b/tools/moon_kubernetes/templates/moon_orchestrator.yaml @@ -13,7 +13,7 @@ spec: hostname: orchestrator containers: - name: orchestrator - image: wukongsun/moon_orchestrator:v4.3 + image: wukongsun/moon_orchestrator:latest ports: - containerPort: 8083 volumeMounts: |