From 2e35a7e46f0929438c1c206e3116caa829f07dc6 Mon Sep 17 00:00:00 2001 From: Thomas Duval Date: Fri, 5 Oct 2018 16:54:37 +0200 Subject: Update code to 4.6 official version Change-Id: Ibd0da0e476e24b2685f54693efc11f7a58d40a62 --- moon_authz/Changelog | 9 ++ moon_authz/moon_authz/__init__.py | 2 +- moon_authz/moon_authz/__main__.py | 4 +- moon_authz/moon_authz/api/authorization.py | 151 ++++++++++++++++------------- moon_authz/moon_authz/api/update.py | 42 ++++++++ moon_authz/moon_authz/http_server.py | 16 +-- moon_authz/moon_authz/server.py | 6 +- moon_authz/tests/unit_python/mock_pods.py | 12 +-- 8 files changed, 157 insertions(+), 85 deletions(-) create mode 100644 moon_authz/moon_authz/api/update.py (limited to 'moon_authz') diff --git a/moon_authz/Changelog b/moon_authz/Changelog index 59d7f8e4..ae1ec4d1 100644 --- a/moon_authz/Changelog +++ b/moon_authz/Changelog @@ -28,3 +28,12 @@ CHANGES - use the threading capability of Flask app - set the number of manager to 1 - update to the latest version of the python-moondb library + +4.3.4 +----- +- apply PyLint rules +- fix a bug in instructions management + +4.4.0 +----- +- add the update API diff --git a/moon_authz/moon_authz/__init__.py b/moon_authz/moon_authz/__init__.py index 0fb32055..85c245e0 100644 --- a/moon_authz/moon_authz/__init__.py +++ b/moon_authz/moon_authz/__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__ = "4.3.3" +__version__ = "4.4.0" diff --git a/moon_authz/moon_authz/__main__.py b/moon_authz/moon_authz/__main__.py index 2693f687..6f1f9807 100644 --- a/moon_authz/moon_authz/__main__.py +++ b/moon_authz/moon_authz/__main__.py @@ -1,4 +1,4 @@ from moon_authz.server import create_server -server = create_server() -server.run() +SERVER = create_server() +SERVER.run() diff --git a/moon_authz/moon_authz/api/authorization.py b/moon_authz/moon_authz/api/authorization.py index 84114466..59af295d 100644 --- a/moon_authz/moon_authz/api/authorization.py +++ b/moon_authz/moon_authz/api/authorization.py @@ -11,7 +11,7 @@ from flask import request from flask_restful import Resource from python_moonutilities import exceptions -logger = logging.getLogger("moon.authz.api." + __name__) +LOGGER = logging.getLogger("moon.authz.api." + __name__) class Authz(Resource): @@ -67,19 +67,23 @@ class Authz(Resource): self.context = pickle.loads(request.data) self.context.set_cache(self.cache) self.context.increment_index() - self.run() + self.context.update_target() + # FIXME (asteroide): force the update but we should not do that + # a better way is to build the bilateral link between Master and Slaves + self.cache.update() + if not self.run(): + raise exceptions.MoonError("Error in the request status={}".format( + self.context.current_state)) self.context.delete_cache() response = flask.make_response(pickle.dumps(self.context)) response.headers['content-type'] = 'application/octet-stream' return response def run(self): - logger.debug("self.context.pdp_set={}".format(self.context.pdp_set)) result, message = self.__check_rules() if result: return self.__exec_instructions(result) - else: - self.context.current_state = "deny" + self.context.current_state = "deny" # self.__exec_next_state(result) return @@ -105,6 +109,9 @@ class Authz(Resource): raise exceptions.PdpContentError for category in category_list: scope = list(current_pdp['target'][category]) + if not scope: + LOGGER.warning("Scope in category {} is empty".format(category)) + raise exceptions.AuthzException 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: @@ -114,58 +121,59 @@ class Authz(Resource): for item in itertools.product(*scopes_list): req = list(item) for rule in self.cache.rules[self.context.current_policy_id]["rules"]: - logger.info("rule={}".format(rule)) if req == rule['rule']: return rule['instructions'], "" - logger.warning("No rule match the request...") + LOGGER.warning("No rule match the request...") return False, "No rule match the request..." def __update_subject_category_in_policy(self, operation, target): result = False - try: - policy_name, category_name, data_name = target.split(":") - except ValueError: - logger.error("Cannot understand value in instruction ({})".format(target)) - return False - # pdp_set = self.payload["authz_context"]['pdp_set'] - for meta_rule_id in self.context.pdp_set: - if meta_rule_id == "effect": - continue - if self.context.pdp_set[meta_rule_id]["meta_rules"]["name"] == policy_name: - for category_id, category_value in self.cache.subject_categories.items(): - if category_value["name"] == "role": - subject_category_id = category_id - break - else: - logger.error("Cannot understand category in instruction ({})".format(target)) - return False - subject_data_id = None - for data in PolicyManager.get_subject_data("admin", policy_id, category_id=subject_category_id): - for data_id, data_value in data['data'].items(): - if data_value["name"] == data_name: - subject_data_id = data_id - break - if subject_data_id: - break - else: - logger.error("Cannot understand data in instruction ({})".format(target)) - return False - if operation == "add": - self.payload["authz_context"]['pdp_set'][meta_rule_id]['target'][subject_category_id].append( - subject_data_id) - elif operation == "delete": - try: - self.payload["authz_context"]['pdp_set'][meta_rule_id]['target'][subject_category_id].remove( - subject_data_id) - except ValueError: - logger.warning("Cannot remove role {} from target".format(data_name)) - result = True - break + # try: + # policy_name, category_name, data_name = target.split(":") + # except ValueError: + # LOGGER.error("Cannot understand value in instruction ({})".format(target)) + # return False + # # pdp_set = self.payload["authz_context"]['pdp_set'] + # for meta_rule_id in self.context.pdp_set: + # if meta_rule_id == "effect": + # continue + # if self.context.pdp_set[meta_rule_id]["meta_rules"]["name"] == policy_name: + # for category_id, category_value in self.cache.subject_categories.items(): + # if category_value["name"] == "role": + # subject_category_id = category_id + # break + # else: + # LOGGER.error("Cannot understand category in instruction ({})".format(target)) + # return False + # subject_data_id = None + # for data in PolicyManager.get_subject_data("admin", policy_id, + # category_id=subject_category_id): + # for data_id, data_value in data['data'].items(): + # if data_value["name"] == data_name: + # subject_data_id = data_id + # break + # if subject_data_id: + # break + # else: + # LOGGER.error("Cannot understand data in instruction ({})".format(target)) + # return False + # if operation == "add": + # self.payload["authz_context"]['pdp_set'][meta_rule_id]['target'][ + # subject_category_id].append(subject_data_id) + # elif operation == "delete": + # try: + # self.payload["authz_context"]['pdp_set'][meta_rule_id]['target'][ + # subject_category_id].remove(subject_data_id) + # except ValueError: + # LOGGER.warning("Cannot remove role {} from target".format(data_name)) + # result = True + # break return result def __update_container_chaining(self): for index in range(len(self.payload["authz_context"]['headers'])): - self.payload["container_chaining"][index]["meta_rule_id"] = self.payload["authz_context"]['headers'][index] + self.payload["container_chaining"][index]["meta_rule_id"] = \ + self.payload["authz_context"]['headers'][index] def __get_container_from_meta_rule(self, meta_rule_id): for index in range(len(self.payload["authz_context"]['headers'])): @@ -200,9 +208,10 @@ class Authz(Resource): # if self.payload["authz_context"]['pdp_set'][next_meta_rule]['effect'] == "unset": # return notify( # request_id=self.payload["authz_context"]["request_id"], - # container_id=self.__get_container_from_meta_rule(next_meta_rule)['container_id'], - # payload=self.payload) - # # next will be delegation if current is deny and session is passed or deny and delegation is unset + # container_id=self.__get_container_from_meta_rule(next_meta_rule)[ + # 'container_id'],payload=self.payload) + # # next will be delegation if current is deny and session is passed or deny and + # delegation is unset # else: # LOG.error("Delegation is not developed!") # @@ -215,8 +224,8 @@ class Authz(Resource): # if self.payload["authz_context"]['pdp_set'][current_meta_rule]['effect'] == "passed": # return notify( # request_id=self.payload["authz_context"]["request_id"], - # container_id=self.__get_container_from_meta_rule(next_meta_rule)['container_id'], - # payload=self.payload) + # container_id=self.__get_container_from_meta_rule(next_meta_rule)[ + # 'container_id'],payload=self.payload) # # next will be None if current is grant and the request is sent to router # else: # return self.__return_to_router() @@ -235,16 +244,19 @@ class Authz(Resource): # args=self.payload["authz_context"]) def __exec_instructions(self, instructions): + if type(instructions) is dict: + instructions = [instructions, ] + if type(instructions) not in (list, tuple): + raise exceptions.RuleContentError("Bad instructions format") for instruction in instructions: for key in instruction: if key == "decision": if instruction["decision"] == "grant": self.context.current_state = "grant" - logger.info("__exec_instructions True {}".format( - self.context.current_state)) + LOGGER.info("__exec_instructions True %s" % self.context.current_state) return True - else: - self.context.current_state = instruction["decision"].lower() + + self.context.current_state = instruction["decision"].lower() elif key == "chain": result = self.__update_headers(**instruction["chain"]) if not result: @@ -257,7 +269,7 @@ class Authz(Resource): self.context.current_state = "deny" else: self.context.current_state = "passed" - logger.info("__exec_instructions False {}".format(self.context.current_state)) + LOGGER.info("__exec_instructions False %s" % self.context.current_state) # def __update_current_request(self): # index = self.payload["authz_context"]["index"] @@ -266,7 +278,8 @@ class Authz(Resource): # current_policy_id = PolicyManager.get_policy_from_meta_rules("admin", current_header_id) # previous_policy_id = PolicyManager.get_policy_from_meta_rules("admin", previous_header_id) # # FIXME (asteroide): must change those lines to be ubiquitous against any type of policy - # if self.payload["authz_context"]['pdp_set'][current_header_id]['meta_rules']['name'] == "session": + # if self.payload["authz_context"]['pdp_set'][current_header_id]['meta_rules'][ + # 'name'] == "session": # subject = self.payload["authz_context"]['current_request'].get("subject") # subject_category_id = None # role_names = [] @@ -277,17 +290,20 @@ class Authz(Resource): # for assignment_id, assignment_value in PolicyManager.get_subject_assignments( # "admin", previous_policy_id, subject, subject_category_id).items(): # for data_id in assignment_value["assignments"]: - # data = PolicyManager.get_subject_data("admin", previous_policy_id, data_id, subject_category_id) + # data = PolicyManager.get_subject_data( + # "admin", previous_policy_id, data_id, subject_category_id) # for _data in data: # for key, value in _data["data"].items(): # role_names.append(value["name"]) # new_role_ids = [] - # for perimeter_id, perimeter_value in PolicyManager.get_objects("admin", current_policy_id).items(): + # for perimeter_id, perimeter_value in PolicyManager.get_objects( + # "admin", current_policy_id).items(): # if perimeter_value["name"] in role_names: # new_role_ids.append(perimeter_id) # break # perimeter_id = None - # for perimeter_id, perimeter_value in PolicyManager.get_actions("admin", current_policy_id).items(): + # for perimeter_id, perimeter_value in PolicyManager.get_actions( + # "admin", current_policy_id).items(): # if perimeter_value["name"] == "*": # break # @@ -353,8 +369,9 @@ class Authz(Resource): # else: # self.payload["authz_context"]["index"] += 1 # self.__update_current_request() - result, message = self.__check_rules(self.payload["authz_context"]) - current_header_id = self.payload["authz_context"]['headers'][self.payload["authz_context"]['index']] + result, message = self.__check_rules() + current_header_id = self.payload["authz_context"]['headers'][ + self.payload["authz_context"]['index']] if result: self.__exec_instructions(result) else: @@ -366,15 +383,15 @@ class Authz(Resource): "args": self.payload} except Exception as e: try: - logger.error(self.payload["authz_context"]) + LOGGER.error(self.payload["authz_context"]) except KeyError: - logger.error("Cannot find \"authz_context\" in context") - logger.error(e, exc_info=True) + LOGGER.error("Cannot find \"authz_context\" in context") + LOGGER.error(e, exc_info=True) return {"authz": False, "error": str(e), "pdp_id": self.pdp_id, "args": self.payload} def head(self, uuid=None, subject_name=None, object_name=None, action_name=None): - logger.info("HEAD request") + LOGGER.info("HEAD request") return "", 200 diff --git a/moon_authz/moon_authz/api/update.py b/moon_authz/moon_authz/api/update.py new file mode 100644 index 00000000..68b7f0ce --- /dev/null +++ b/moon_authz/moon_authz/api/update.py @@ -0,0 +1,42 @@ +# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors +# This software is distributed under the terms and conditions of the 'Apache-2.0' +# license which can be found in the file 'LICENSE' in this package distribution +# or at 'http://www.apache.org/licenses/LICENSE-2.0'. +""" +Authz is the endpoint to get authorization response +""" + +from flask import request +from flask_restful import Resource +import logging + +__version__ = "4.4.0" + +LOGGER = logging.getLogger("moon.authz.api." + __name__) + + +class Update(Resource): + """ + Endpoint for update requests + """ + + __urls__ = ( + "/update", + ) + + def __init__(self, **kwargs): + self.CACHE = kwargs.get("cache") + self.INTERFACE_NAME = kwargs.get("interface_name", "interface") + self.MANAGER_URL = kwargs.get("manager_url", "http://manager:8080") + self.TIMEOUT = 5 + + def put(self): + try: + self.CACHE.update_assignments( + request.form.get("policy_id", None), + request.form.get("perimeter_id", None), + ) + except Exception as e: + LOGGER.exception(e) + return {"result": False, "reason": str(e)} + return {"result": True} diff --git a/moon_authz/moon_authz/http_server.py b/moon_authz/moon_authz/http_server.py index 7d3b1ec3..86d8a914 100644 --- a/moon_authz/moon_authz/http_server.py +++ b/moon_authz/moon_authz/http_server.py @@ -3,15 +3,16 @@ # license which can be found in the file 'LICENSE' in this package distribution # or at 'http://www.apache.org/licenses/LICENSE-2.0'. +import logging from flask import Flask from flask_restful import Resource, Api -import logging from moon_authz import __version__ from moon_authz.api.authorization import Authz +from moon_authz.api.update import Update from python_moonutilities.cache import Cache from python_moonutilities import exceptions -logger = logging.getLogger("moon.authz.http_server") +LOGGER = logging.getLogger("moon.authz.http_server") CACHE = Cache() CACHE.update() @@ -62,15 +63,15 @@ class Server: __API__ = ( - Authz, - ) + Authz, Update +) class Root(Resource): """ The root of the web service """ - __urls__ = ("/", ) + __urls__ = ("/",) __methods = ("get", "post", "put", "delete", "options") def get(self): @@ -97,7 +98,7 @@ class HTTPServer(Server): def __init__(self, host="localhost", port=38001, **kwargs): super(HTTPServer, self).__init__(host=host, port=port, **kwargs) self.component_data = kwargs.get("component_data", {}) - logger.info("HTTPServer port={} {}".format(port, kwargs)) + LOGGER.info("HTTPServer port={} {}".format(port, kwargs)) self.app = Flask(__name__) self._port = port self._host = host @@ -106,6 +107,7 @@ class HTTPServer(Server): self.container_chaining = kwargs.get("container_chaining") self.api = Api(self.app) self.__set_route() + # self.__hook_errors() @self.app.errorhandler(exceptions.AuthException) @@ -116,10 +118,12 @@ class HTTPServer(Server): # FIXME (dthom): it doesn't work def get_404_json(e): return {"error": "Error", "code": 404, "description": e} + self.app.register_error_handler(404, get_404_json) def get_400_json(e): return {"error": "Error", "code": 400, "description": e} + self.app.register_error_handler(400, lambda e: get_400_json) self.app.register_error_handler(403, exceptions.AuthException) diff --git a/moon_authz/moon_authz/server.py b/moon_authz/moon_authz/server.py index 0cc5f6fc..d1b5a59b 100644 --- a/moon_authz/moon_authz/server.py +++ b/moon_authz/moon_authz/server.py @@ -8,7 +8,7 @@ import logging from moon_authz.http_server import HTTPServer as Server from python_moonutilities import configuration, exceptions -logger = logging.getLogger("moon.authz.server") +LOGGER = logging.getLogger("moon.authz.server") def create_server(): @@ -20,7 +20,7 @@ def create_server(): pdp_id = os.getenv("PDP_ID") meta_rule_id = os.getenv("META_RULE_ID") keystone_project_id = os.getenv("KEYSTONE_PROJECT_ID") - logger.info("component_type={}".format(component_type)) + LOGGER.info("component_type={}".format(component_type)) conf = configuration.get_plugins() # conf = configuration.get_configuration("plugins/{}".format(component_type)) # conf["plugins/{}".format(component_type)]['id'] = component_id @@ -31,7 +31,7 @@ def create_server(): port = conf[component_type].get('port', tcp_port) bind = conf[component_type].get('bind', "0.0.0.0") - logger.info("Starting server with IP {} on port {} bind to {}".format( + LOGGER.info("Starting server with IP {} on port {} bind to {}".format( hostname, port, bind)) server = Server( host=bind, diff --git a/moon_authz/tests/unit_python/mock_pods.py b/moon_authz/tests/unit_python/mock_pods.py index 9e05e335..39223a57 100644 --- a/moon_authz/tests/unit_python/mock_pods.py +++ b/moon_authz/tests/unit_python/mock_pods.py @@ -338,16 +338,16 @@ def register_pods(m): register_policy_action(m, "f8f49a779ceb47b3ac810f01ef71b4e0") # register_policy_action(m, "policy_id_2") register_policy_subject_assignment(m, "f8f49a779ceb47b3ac810f01ef71b4e0", "89ba91c18dd54abfbfde7a66936c51a6") - # register_policy_subject_assignment_list(m, "f8f49a779ceb47b3ac810f01ef71b4e0") - # register_policy_subject_assignment(m, "policy_id_2", "subject_id") + register_policy_subject_assignment_list(m, "f8f49a779ceb47b3ac810f01ef71b4e0") + register_policy_subject_assignment(m, "policy_id_2", "subject_id") # register_policy_subject_assignment_list(m1, "policy_id_2") register_policy_object_assignment(m, "f8f49a779ceb47b3ac810f01ef71b4e0", "9089b3d2ce5b4e929ffc7e35b55eba1a") - # register_policy_object_assignment_list(m, "f8f49a779ceb47b3ac810f01ef71b4e0") - # register_policy_object_assignment(m, "policy_id_2", "object_id") + register_policy_object_assignment_list(m, "f8f49a779ceb47b3ac810f01ef71b4e0") + register_policy_object_assignment(m, "policy_id_2", "object_id") # register_policy_object_assignment_list(m1, "policy_id_2") register_policy_action_assignment(m, "f8f49a779ceb47b3ac810f01ef71b4e0", "cdb3df220dc05a6ea3334b994827b068") - # register_policy_action_assignment_list(m, "f8f49a779ceb47b3ac810f01ef71b4e0") - # register_policy_action_assignment(m, "policy_id_2", "action_id") + register_policy_action_assignment_list(m, "f8f49a779ceb47b3ac810f01ef71b4e0") + register_policy_action_assignment(m, "policy_id_2", "action_id") # register_policy_action_assignment_list(m1, "policy_id_2") register_rules(m, "f8f49a779ceb47b3ac810f01ef71b4e0") register_rules(m, "policy_id_1") -- cgit 1.2.3-korg