From 019b10d95976bb80bcce60ee93099b0fd57fcab5 Mon Sep 17 00:00:00 2001 From: asteroide Date: Mon, 15 May 2017 14:19:43 +0200 Subject: Update Moon engine to allow a session policy Change-Id: I63a80597710f08a6641e159cc2306d3cc68b1240 --- moonv4/moon_authz/moon_authz/api/authorization.py | 248 +++++++++++++++++---- moonv4/moon_db/moon_db/backends/sql.py | 6 +- moonv4/moon_interface/moon_interface/api/rules.py | 25 ++- .../tests/apitests/populate_default_values.py | 61 +++-- .../moon_interface/tests/apitests/scenario/rbac.py | 19 +- .../tests/apitests/scenario/session.py | 23 +- moonv4/moon_interface/tests/apitests/set_authz.py | 13 +- .../tests/apitests/utils/policies.py | 3 +- moonv4/moon_orchestrator/conf/plugins/session.py | 67 ++++++ .../moon_orchestrator/api/containers.py | 2 +- .../moon_orchestrator/moon_orchestrator/server.py | 2 +- moonv4/moon_secrouter/moon_secrouter/api/route.py | 19 +- .../moon_utilities/security_functions.py | 78 +++++-- 13 files changed, 451 insertions(+), 115 deletions(-) create mode 100644 moonv4/moon_orchestrator/conf/plugins/session.py (limited to 'moonv4') diff --git a/moonv4/moon_authz/moon_authz/api/authorization.py b/moonv4/moon_authz/moon_authz/api/authorization.py index 5968178e..e4d7ad7c 100644 --- a/moonv4/moon_authz/moon_authz/api/authorization.py +++ b/moonv4/moon_authz/moon_authz/api/authorization.py @@ -25,12 +25,6 @@ LOG = logging.getLogger(__name__) CONF = cfg.CONF -class PDP: - - def __init__(self, context): - self.__context = context - - class Authorization(object): """ Retrieve the current status of all components. @@ -40,13 +34,14 @@ class Authorization(object): pdp_id = None meta_rule_id = None keystone_project_id = None + payload = None def __init__(self, component_desc): self.component_id = component_desc LOG.info("ext={}".format(component_desc)) self.filter_rule = oslo_messaging.NotificationFilter( event_type='^authz$', - context={'container_id': "authz_"+hashlib.sha224(component_desc.encode("utf-8")).hexdigest()} + context={'container_id': "\w+_"+hashlib.sha224(component_desc.encode("utf-8")).hexdigest()} ) for _id_value in component_desc.split("_"): @@ -61,27 +56,205 @@ class Authorization(object): def __check_rules(self, context): scopes_list = list() current_header_id = context['headers'][context['index']] + Context.update_target(context) current_pdp = 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"]) for category in category_list: - # if not current_pdp['target'][category]: - # LOG.warning("Empty assignment detected: {} target={}".format(category, current_pdp['target'])) - scopes_list.append(current_pdp['target'][category]) + scope = list(current_pdp['target'][category]) + scopes_list.append(scope) policy_id = PolicyManager.get_policy_from_meta_rules("admin", current_header_id) rules = PolicyManager.get_rules(user_id="admin", policy_id=policy_id, meta_rule_id=current_header_id) - rules = list(map(lambda x: x['rule'], rules['rules'])) for item in itertools.product(*scopes_list): req = list(item) - if req in rules: - return True, "" + for rule in rules['rules']: + if req == rule['rule']: + return rule['instructions'], "" LOG.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: + LOG.error("Cannot understand value in instruction ({})".format(target)) + return False + pdp_set = self.payload["authz_context"]['pdp_set'] + for meta_rule_id in self.payload["authz_context"]['pdp_set']: + policy_id = PolicyManager.get_policy_from_meta_rules("admin", meta_rule_id) + if meta_rule_id == "effect": + continue + if pdp_set[meta_rule_id]["meta_rules"]["name"] == policy_name: + for category_id, category_value in ModelManager.get_subject_categories("admin").items(): + if category_value["name"] == "role": + subject_category_id = category_id + break + else: + LOG.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: + LOG.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: + LOG.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] + + def __get_container_from_meta_rule(self, meta_rule_id): + for index in range(len(self.payload["authz_context"]['headers'])): + if self.payload["container_chaining"][index]["meta_rule_id"] == meta_rule_id: + return self.payload["container_chaining"][index] + + def __update_headers(self, name): + context = self.payload["authz_context"] + for meta_rule_id, meta_rule_value in context["pdp_set"].items(): + if meta_rule_id == "effect": + continue + if meta_rule_value["meta_rules"]["name"] == name: + self.payload["authz_context"]['headers'].append(meta_rule_id) + return True + return False + + def __exec_next_state(self, rule_found): + index = self.payload["authz_context"]['index'] + current_meta_rule = self.payload["authz_context"]['headers'][index] + current_container = self.__get_container_from_meta_rule(current_meta_rule) + current_container_genre = current_container["genre"] + try: + next_meta_rule = self.payload["authz_context"]['headers'][index+1] + except IndexError: + next_meta_rule = None + if current_container_genre == "authz": + if rule_found: + return self.__return_to_router() + pass + if next_meta_rule: + # next will be session if current is deny and session is unset + if self.payload["authz_context"]['pdp_set'][next_meta_rule]['effect'] == "unset": + return notify( + request_id=self.payload["authz_context"]["request_id"], + container_id=self.__get_container_from_meta_rule(next_meta_rule)['container_id'], + payload=self.payload) + # next will be delegation if current is deny and session is passed or deny and delegation is unset + else: + LOG.error("Delegation is not developed!") + + else: + # else next will be None and the request is sent to router + return self.__return_to_router() + elif current_container_genre == "session": + pass + # next will be next container in headers if current is passed + if self.payload["authz_context"]['pdp_set'][current_meta_rule]['effect'] == "passed": + return notify( + request_id=self.payload["authz_context"]["request_id"], + container_id=self.__get_container_from_meta_rule(next_meta_rule)['container_id'], + payload=self.payload) + # next will be None if current is grant and the request is sent to router + else: + return self.__return_to_router() + elif current_container_genre == "delegation": + LOG.error("Delegation is not developed!") + # next will be authz if current is deny + # next will be None if current is grant and the request is sent to router + + def __return_to_router(self): + call(endpoint="security_router", + ctx={"id": self.component_id, + "call_master": False, + "method": "return_authz", + "request_id": self.payload["authz_context"]["request_id"]}, + method="route", + args=self.payload["authz_context"]) + + def __exec_instructions(self, instructions): + current_header_id = self.payload["authz_context"]['headers'][self.payload["authz_context"]['index']] + for instruction in instructions: + for key in instruction: + if key == "decision": + if instruction["decision"] == "grant": + self.payload["authz_context"]['pdp_set'][current_header_id]["effect"] = "grant" + self.__return_to_router() + else: + self.payload["authz_context"]['pdp_set'][current_header_id]["effect"] = instruction["decision"] + elif key == "chain": + result = self.__update_headers(**instruction["chain"]) + if not result: + self.payload["authz_context"]['pdp_set'][current_header_id]["effect"] = "deny" + else: + self.payload["authz_context"]['pdp_set'][current_header_id]["effect"] = "passed" + elif key == "update": + result = self.__update_subject_category_in_policy(**instruction["update"]) + if not result: + self.payload["authz_context"]['pdp_set'][current_header_id]["effect"] = "deny" + else: + self.payload["authz_context"]['pdp_set'][current_header_id]["effect"] = "passed" + # LOG.info("__exec_instructions {}".format(self.payload["authz_context"])) + + def __update_current_request(self): + index = self.payload["authz_context"]["index"] + current_header_id = self.payload["authz_context"]['headers'][index] + previous_header_id = self.payload["authz_context"]['headers'][index-1] + 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": + subject = self.payload["authz_context"]['current_request'].get("subject") + subject_category_id = None + role_names = [] + for category_id, category_value in ModelManager.get_subject_categories("admin").items(): + if category_value["name"] == "role": + subject_category_id = category_id + break + 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) + 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(): + 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(): + if perimeter_value["name"] == "*": + break + + self.payload["authz_context"]['current_request']['object'] = new_role_ids[0] + self.payload["authz_context"]['current_request']['action'] = perimeter_id + elif self.payload["authz_context"]['pdp_set'][current_header_id]['meta_rules']['name'] == "rbac": + self.payload["authz_context"]['current_request']['subject'] = self.payload["authz_context"]['initial_request']['subject'] + self.payload["authz_context"]['current_request']['object'] = self.payload["authz_context"]['initial_request']['object'] + self.payload["authz_context"]['current_request']['action'] = self.payload["authz_context"]['initial_request']['action'] + def critical(self, ctxt, publisher_id, event_type, payload, metadata): """This is the authz endpoint but due to the oslo_messaging notification architecture, we must call it "critical" @@ -93,50 +266,39 @@ class Authorization(object): :param metadata: metadata of the notification :return: result of the authorization for the current component """ - LOG.info("authz {} {}".format(ctxt, payload)) - keystone_project_id = payload["id"] + LOG.info("calling authz {} {}".format(ctxt, payload)) + self.keystone_project_id = payload["id"] + self.payload = payload try: if "authz_context" not in payload: - payload["authz_context"] = Context(keystone_project_id, - payload["subject_name"], - payload["object_name"], - payload["action_name"], - payload["request_id"]).to_dict() + self.payload["authz_context"] = Context(self.keystone_project_id, + self.payload["subject_name"], + self.payload["object_name"], + self.payload["action_name"], + self.payload["request_id"]).to_dict() + self.__update_container_chaining() else: - payload["authz_context"]["index"] += 1 - result, message = self.__check_rules(payload["authz_context"]) - current_header_id = payload["authz_context"]['headers'][payload["authz_context"]['index']] - # current_pdp = payload["authz_context"]['pdp_set'][current_header_id] + 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']] if result: - payload["authz_context"]['pdp_set'][current_header_id]["effect"] = "grant" - if payload["authz_context"]["index"]+1 < len(payload["authz_context"]["headers"]): - next_index = payload["authz_context"]["index"]+1 - notify( - request_id=payload["authz_context"]["request_id"], - container_id=payload["container_chaining"][next_index], - payload=payload) + self.__exec_instructions(result) else: - ret = call(endpoint="security_router", - ctx={"id": self.component_id, - "call_master": False, - "method": "return_authz", - "request_id": payload["authz_context"]["request_id"]}, - method="route", - args=payload["authz_context"]) - del payload["authz_context"] + self.payload["authz_context"]['pdp_set'][current_header_id]["effect"] = "deny" + self.__exec_next_state(result) return {"authz": result, "error": message, "pdp_id": self.pdp_id, - "ctx": ctxt, "args": payload} + "ctx": ctxt, "args": self.payload} except Exception as e: try: - LOG.error(payload["authz_context"]) - # del ctx["authz_context"] + LOG.error(self.payload["authz_context"]) except KeyError: LOG.error("Cannot find \"authz_context\" in context") LOG.error(e, exc_info=True) return {"authz": False, "error": str(e), "pdp_id": self.pdp_id, - "ctx": ctxt, "args": payload} + "ctx": ctxt, "args": self.payload} diff --git a/moonv4/moon_db/moon_db/backends/sql.py b/moonv4/moon_db/moon_db/backends/sql.py index 5ab653a6..8cb6bb8e 100644 --- a/moonv4/moon_db/moon_db/backends/sql.py +++ b/moonv4/moon_db/moon_db/backends/sql.py @@ -328,6 +328,7 @@ class Rule(Base, DictBase): return { 'id': self.id, 'rule': self.rule["rule"], + 'instructions': self.rule["instructions"], 'enabled': self.rule["enabled"], 'policy_id': self.policy_id, 'meta_rule_id': self.meta_rule_id @@ -651,6 +652,7 @@ class PolicyConnector(BaseConnector, PolicyDriver): session.delete(_action) def get_subject_data(self, policy_id, data_id=None, category_id=None): + LOG.info("driver {} {} {}".format(policy_id, data_id, category_id)) with self.get_session_for_read() as session: query = session.query(SubjectData) if data_id: @@ -658,6 +660,7 @@ class PolicyConnector(BaseConnector, PolicyDriver): else: query = query.filter_by(policy_id=policy_id, category_id=category_id) ref_list = query.all() + LOG.info("ref_list={}".format(ref_list)) return { "policy_id": policy_id, "category_id": category_id, @@ -979,10 +982,7 @@ class PolicyConnector(BaseConnector, PolicyDriver): query = session.query(Rule) query = query.filter_by(policy_id=policy_id, meta_rule_id=meta_rule_id) ref_list = query.all() - LOG.info("add_rule {}".format(ref_list)) - LOG.info("add_rule {}".format(value)) rules = list(map(lambda x: x.rule, ref_list)) - LOG.info("add_rule rules={}".format(rules)) if not rules or value not in rules: LOG.info("add_rule IN IF") ref = Rule.from_dict( diff --git a/moonv4/moon_interface/moon_interface/api/rules.py b/moonv4/moon_interface/moon_interface/api/rules.py index 81639a37..7757d275 100644 --- a/moonv4/moon_interface/moon_interface/api/rules.py +++ b/moonv4/moon_interface/moon_interface/api/rules.py @@ -62,13 +62,34 @@ class Rules(Resource): :request body: post = { "meta_rule_id": "meta_rule_id1", "rule": ["subject_data_id2", "object_data_id2", "action_data_id2"], + "instructions": ( + {"decision": "grant"}, + ) "enabled": True } :return: { "rules": [ "meta_rule_id": "meta_rule_id1", - "rule_id1": ["subject_data_id1", "object_data_id1", "action_data_id1"], - "rule_id2": ["subject_data_id2", "object_data_id2", "action_data_id2"], + "rule_id1": { + "rule": ["subject_data_id1", "object_data_id1", "action_data_id1"], + "instructions": ( + {"decision": "grant"}, # "grant" to immediately exit, + # "continue" to wait for the result of next policy + # "deny" to deny the request + ) + } + "rule_id2": { + "rule": ["subject_data_id2", "object_data_id2", "action_data_id2"], + "instructions": ( + { + "update": { + "operation": "add", # operations may be "add" or "delete" + "target": "rbac:role:admin" # add the role admin to the current user + } + }, + {"chain": {"name": "rbac"}} # chain with the policy named rbac + ) + } ] } :internal_api: add_rule diff --git a/moonv4/moon_interface/tests/apitests/populate_default_values.py b/moonv4/moon_interface/tests/apitests/populate_default_values.py index 5ad6098f..0e3438db 100644 --- a/moonv4/moon_interface/tests/apitests/populate_default_values.py +++ b/moonv4/moon_interface/tests/apitests/populate_default_values.py @@ -56,7 +56,7 @@ def create_model(): def create_policy(model_id, meta_rule_list): if args.verbose: logger.warning("Creating policy {}".format(scenario.policy_name)) - policy_id = add_policy(name=scenario.policy_name) + policy_id = add_policy(name=scenario.policy_name, genre=scenario.policy_genre) update_policy(policy_id, model_id) @@ -90,23 +90,52 @@ def create_policy(model_id, meta_rule_list): scenario.actions[name] = add_action(policy_id, name=name) for subject_name in scenario.subject_assignments: - for subject_category_name in scenario.subject_assignments[subject_name]: - subject_id = scenario.subjects[subject_name] - subject_cat_id = scenario.subject_categories[subject_category_name] - subject_data_id = scenario.subject_data[subject_category_name][scenario.subject_assignments[subject_name][subject_category_name]] - add_subject_assignments(policy_id, subject_id, subject_cat_id, subject_data_id) + if type(scenario.subject_assignments[subject_name]) in (list, tuple): + for items in scenario.subject_assignments[subject_name]: + for subject_category_name in items: + subject_id = scenario.subjects[subject_name] + subject_cat_id = scenario.subject_categories[subject_category_name] + for data in scenario.subject_assignments[subject_name]: + subject_data_id = scenario.subject_data[subject_category_name][data[subject_category_name]] + add_subject_assignments(policy_id, subject_id, subject_cat_id, subject_data_id) + else: + for subject_category_name in scenario.subject_assignments[subject_name]: + subject_id = scenario.subjects[subject_name] + subject_cat_id = scenario.subject_categories[subject_category_name] + subject_data_id = scenario.subject_data[subject_category_name][scenario.subject_assignments[subject_name][subject_category_name]] + add_subject_assignments(policy_id, subject_id, subject_cat_id, subject_data_id) + for object_name in scenario.object_assignments: - for object_category_name in scenario.object_assignments[object_name]: - object_id = scenario.objects[object_name] - object_cat_id = scenario.object_categories[object_category_name] - object_data_id = scenario.object_data[object_category_name][scenario.object_assignments[object_name][object_category_name]] - add_object_assignments(policy_id, object_id, object_cat_id, object_data_id) + if type(scenario.object_assignments[object_name]) in (list, tuple): + for items in scenario.object_assignments[object_name]: + for object_category_name in items: + object_id = scenario.objects[object_name] + object_cat_id = scenario.object_categories[object_category_name] + for data in scenario.object_assignments[object_name]: + object_data_id = scenario.object_data[object_category_name][data[object_category_name]] + add_object_assignments(policy_id, object_id, object_cat_id, object_data_id) + else: + for object_category_name in scenario.object_assignments[object_name]: + object_id = scenario.objects[object_name] + object_cat_id = scenario.object_categories[object_category_name] + object_data_id = scenario.object_data[object_category_name][scenario.object_assignments[object_name][object_category_name]] + add_object_assignments(policy_id, object_id, object_cat_id, object_data_id) + for action_name in scenario.action_assignments: - for action_category_name in scenario.action_assignments[action_name]: - action_id = scenario.actions[action_name] - action_cat_id = scenario.action_categories[action_category_name] - action_data_id = scenario.action_data[action_category_name][scenario.action_assignments[action_name][action_category_name]] - add_action_assignments(policy_id, action_id, action_cat_id, action_data_id) + if type(scenario.action_assignments[action_name]) in (list, tuple): + for items in scenario.action_assignments[action_name]: + for action_category_name in items: + action_id = scenario.actions[action_name] + action_cat_id = scenario.action_categories[action_category_name] + for data in scenario.action_assignments[action_name]: + action_data_id = scenario.action_data[action_category_name][data[action_category_name]] + add_action_assignments(policy_id, action_id, action_cat_id, action_data_id) + else: + for action_category_name in scenario.action_assignments[action_name]: + action_id = scenario.actions[action_name] + action_cat_id = scenario.action_categories[action_category_name] + action_data_id = scenario.action_data[action_category_name][scenario.action_assignments[action_name][action_category_name]] + add_action_assignments(policy_id, action_id, action_cat_id, action_data_id) for meta_rule_name in scenario.rules: meta_rule_value = scenario.meta_rule[meta_rule_name] diff --git a/moonv4/moon_interface/tests/apitests/scenario/rbac.py b/moonv4/moon_interface/tests/apitests/scenario/rbac.py index a43bd1f4..89fd7de8 100644 --- a/moonv4/moon_interface/tests/apitests/scenario/rbac.py +++ b/moonv4/moon_interface/tests/apitests/scenario/rbac.py @@ -2,6 +2,7 @@ pdp_name = "pdp1" policy_name = "RBAC policy example" model_name = "RBAC" +policy_genre = "authz" subjects = {"user0": "", "user1": "", } objects = {"vm0": "", "vm1": "", } @@ -11,13 +12,13 @@ subject_categories = {"role": "", } object_categories = {"id": "", } action_categories = {"action-type": "", } -subject_data = {"role": {"admin": "", "employee": ""}} -object_data = {"id": {"vm0": "", "vm1": ""}} -action_data = {"action-type": {"vm-action": "", }} +subject_data = {"role": {"admin": "", "employee": "", "*": ""}} +object_data = {"id": {"vm0": "", "vm1": "", "*": ""}} +action_data = {"action-type": {"vm-action": "", "*": ""}} -subject_assignments = {"user0": {"role": "employee"}, "user1": {"role": "employee"}, } -object_assignments = {"vm0": {"id": "vm0"}, "vm1": {"id": "vm1"}} -action_assignments = {"start": {"action-type": "vm-action"}, "stop": {"action-type": "vm-action"}} +subject_assignments = {"user0": ({"role": "employee"}, {"role": "*"}), "user1": ({"role": "employee"}, {"role": "*"}), } +object_assignments = {"vm0": ({"id": "vm0"}, {"id": "*"}), "vm1": ({"id": "vm1"}, {"id": "*"})} +action_assignments = {"start": ({"action-type": "vm-action"}, {"action-type": "*"}), "stop": ({"action-type": "vm-action"}, {"action-type": "*"})} meta_rule = { "rbac": {"id": "", "value": ("role", "id", "action-type")}, @@ -28,13 +29,13 @@ rules = { { "rule": ("admin", "vm0", "vm-action"), "instructions": ( - {"decision": "grant"} # "grant" to immediately exit, "continue" to wait for the result of next policy + {"decision": "grant"}, # "grant" to immediately exit, "continue" to wait for the result of next policy ) }, { - "rule": ("admin", "vm1", "vm-action"), + "rule": ("employee", "vm1", "vm-action"), "instructions": ( - {"decision": "grant"} + {"decision": "grant"}, ) }, ) diff --git a/moonv4/moon_interface/tests/apitests/scenario/session.py b/moonv4/moon_interface/tests/apitests/scenario/session.py index 6b7e0f18..97d7aec3 100644 --- a/moonv4/moon_interface/tests/apitests/scenario/session.py +++ b/moonv4/moon_interface/tests/apitests/scenario/session.py @@ -2,6 +2,7 @@ pdp_name = "pdp1" policy_name = "Session policy example" model_name = "Session" +policy_genre = "session" subjects = {"user0": "", "user1": "", } objects = {"admin": "", "employee": "", } @@ -12,12 +13,16 @@ object_categories = {"role": "", } action_categories = {"session-action": "", } subject_data = {"subjectid": {"user0": "", "user1": ""}} -object_data = {"role": {"admin": "", "employee": ""}} -action_data = {"session-action": {"activate": "", "deactivate": ""}} +object_data = {"role": {"admin": "", "employee": "", "*": ""}} +action_data = {"session-action": {"activate": "", "deactivate": "", "*": ""}} -subject_assignments = {"user0": {"subjectid": "user0"}, "user1": {"subjectid": "user1"}, } -object_assignments = {"admin": {"role": "admin"}, "employee": {"role": "employee"}} -action_assignments = {"activate": {"session-action": "activate"}, "deactivate": {"session-action": "deactivate"}} +subject_assignments = {"user0": ({"subjectid": "user0"}, ), "user1": ({"subjectid": "user1"}, ), } +object_assignments = {"admin": ({"role": "admin"}, {"role": "*"}), + "employee": ({"role": "employee"}, {"role": "employee"}) + } +action_assignments = {"activate": ({"session-action": "activate"}, {"session-action": "*"}, ), + "deactivate": ({"session-action": "deactivate"}, {"session-action": "*"}, ) + } meta_rule = { "session": {"id": "", "value": ("subjectid", "role", "session-action")}, @@ -26,7 +31,7 @@ meta_rule = { rules = { "session": ( { - "rule": ("user0", "admin", "activate"), + "rule": ("user0", "employee", "*"), "instructions": ( { "update": { @@ -34,11 +39,11 @@ rules = { "target": "rbac:role:admin" # add the role admin to the current user } }, - {"chain": [{"security_pipeline": "rbac"}]} # chain with the meta_rule named rbac + {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac ) }, { - "rule": ("user1", "employee", "deactivate"), + "rule": ("user1", "employee", "*"), "instructions": ( { "update": { @@ -46,7 +51,7 @@ rules = { "target": "rbac:role:employee" # delete the role employee from the current user } }, - {"chain": [{"security_pipeline": "rbac"}]} # chain with the meta_rule named rbac + {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac ) }, ) diff --git a/moonv4/moon_interface/tests/apitests/set_authz.py b/moonv4/moon_interface/tests/apitests/set_authz.py index 38b63509..f515e4eb 100644 --- a/moonv4/moon_interface/tests/apitests/set_authz.py +++ b/moonv4/moon_interface/tests/apitests/set_authz.py @@ -41,10 +41,13 @@ for rule in rules: url = "http://172.18.0.11:38001/authz/{}/{}".format(keystone_project_id, "/".join(rule)) req = requests.get(url) print("\033[1m{}\033[m {}".format(url, req.status_code)) - j = req.json() - # print(j) - if j.get("authz"): - print("\t\033[32m{}\033[m {}".format(j.get("authz"), j.get("error", ""))) + try: + j = req.json() + except Exception as e: + print(req.text) else: - print("\t\033[31m{}\033[m {}".format(j.get("authz"), j.get("error", ""))) + if j.get("authz"): + print("\t\033[32m{}\033[m {}".format(j.get("authz"), j.get("error", ""))) + else: + print("\t\033[31m{}\033[m {}".format(j.get("authz"), j.get("error", ""))) diff --git a/moonv4/moon_interface/tests/apitests/utils/policies.py b/moonv4/moon_interface/tests/apitests/utils/policies.py index bf75734f..969ab70b 100644 --- a/moonv4/moon_interface/tests/apitests/utils/policies.py +++ b/moonv4/moon_interface/tests/apitests/utils/policies.py @@ -63,8 +63,9 @@ def check_policy(policy_id=None): assert policy_template["name"] == result['policies'][policy_id]["name"] -def add_policy(name="test_policy"): +def add_policy(name="test_policy", genre="authz"): policy_template["name"] = name + policy_template["genre"] = genre req = requests.post(URL.format("/policies"), json=policy_template, headers=HEADERS) assert req.status_code == 200 result = req.json() diff --git a/moonv4/moon_orchestrator/conf/plugins/session.py b/moonv4/moon_orchestrator/conf/plugins/session.py new file mode 100644 index 00000000..6fa2cfe2 --- /dev/null +++ b/moonv4/moon_orchestrator/conf/plugins/session.py @@ -0,0 +1,67 @@ +# 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 os +import time +import hashlib +from oslo_config import cfg +from oslo_log import log as logging +import oslo_messaging +from moon_orchestrator.dockers import DockerBase + +LOG = logging.getLogger(__name__) +CONF = cfg.CONF +DOMAIN = "moon_orchestrator" + +__CWD__ = os.path.dirname(os.path.abspath(__file__)) +# TODO (asteroide): select the right template folder +TEMPLATES_FOLDER = os.path.join(__CWD__, "..", "conf", "dockers") +# TODO (asteroide): add specific configuration options for that plugin + + +class AuthzFunction(DockerBase): + + id = "moon_session_function" + __build = """RUN mkdir -p /etc/moon/ +COPY conf /etc/moon/ +ADD dist/{py_pkg}.tar.gz /root +WORKDIR /root/{py_pkg} +RUN pip3 install -r requirements.txt +RUN pip3 install . +""" + + def __init__(self, uuid, conf_file="", docker=None, network_config=None): + self.id = "session_"+hashlib.sha224(uuid.encode("utf-8")).hexdigest() + super(AuthzFunction, self).__init__( + name="moon_authz", + run_cmd=["python3", "-m", "moon_authz", uuid], + conf_file=conf_file, + docker=docker, + network_config=network_config, + build_cmd=self.__build, + id=self.id, + tag="" + # tag=CONF.security_function.container + ) + # note(asteroide): time to let the new docker boot + time.sleep(3) + # self.get_status() + + def get_status(self): + return True + # transport = oslo_messaging.get_transport(CONF) + # target = oslo_messaging.Target(topic=self.id, version='1.0') + # client = oslo_messaging.RPCClient(transport, target) + # LOG.info("Calling Status on {}".format(self.id)) + # ret = client.call({"component_id": self.id}, 'get_status', args=None) + # LOG.info(ret) + # return ret + + +def run(uuid, conf_file="", docker=None, network_config=None): + return AuthzFunction(uuid, + conf_file=conf_file, + docker=docker, + network_config=network_config) diff --git a/moonv4/moon_orchestrator/moon_orchestrator/api/containers.py b/moonv4/moon_orchestrator/moon_orchestrator/api/containers.py index 3572d615..2ed5b266 100644 --- a/moonv4/moon_orchestrator/moon_orchestrator/api/containers.py +++ b/moonv4/moon_orchestrator/moon_orchestrator/api/containers.py @@ -109,7 +109,7 @@ class Containers(object): "meta_rule_id": meta_rule, "genre": policy_value['genre'], "keystone_project_id": keystone_project_id, - "container_id": "authz_"+hashlib.sha224(pre_container_id.encode("utf-8")).hexdigest() + "container_id": policy_value['genre']+"_"+hashlib.sha224(pre_container_id.encode("utf-8")).hexdigest() }) return {"containers": self.components[ctx["id"]]} # function_components = [] diff --git a/moonv4/moon_orchestrator/moon_orchestrator/server.py b/moonv4/moon_orchestrator/moon_orchestrator/server.py index 4fc9d5fd..e6d28c23 100644 --- a/moonv4/moon_orchestrator/moon_orchestrator/server.py +++ b/moonv4/moon_orchestrator/moon_orchestrator/server.py @@ -62,7 +62,7 @@ class DockerManager: :param uuid: the uuid of the intra_extension linked to that component :return: the created component """ - component_id = "authz_"+hashlib.sha224(uuid.encode("utf-8")).hexdigest() + component_id = component+"_"+hashlib.sha224(uuid.encode("utf-8")).hexdigest() if component_id not in CONTAINERS: plug = load_plugin(component) LOG.info("Creating {} with id {}".format(component, uuid)) diff --git a/moonv4/moon_secrouter/moon_secrouter/api/route.py b/moonv4/moon_secrouter/moon_secrouter/api/route.py index ccdff08b..7cce1353 100644 --- a/moonv4/moon_secrouter/moon_secrouter/api/route.py +++ b/moonv4/moon_secrouter/moon_secrouter/api/route.py @@ -200,7 +200,12 @@ class Cache(object): for container_id, container_values, in CACHE.containers.items(): for container_value in container_values: if container_value["meta_rule_id"] == meta_rule_id: - container_ids.append(container_value["container_id"]) + container_ids.append( + { + "container_id": container_value["container_id"], + "genre": container_value["genre"] + } + ) break self.__CONTAINER_CHAINING[keystone_project_id] = container_ids @@ -227,7 +232,7 @@ CACHE = Cache() class AuthzRequest: result = None - req_max_delay = 5 + req_max_delay = 2 def __init__(self, ctx, args): self.ctx = ctx @@ -235,7 +240,7 @@ class AuthzRequest: self.request_id = ctx["request_id"] self.container_chaining = CACHE.container_chaining[self.ctx['id']] ctx["container_chaining"] = copy.deepcopy(self.container_chaining) - self.pdp_container = str(self.container_chaining[0]) + self.pdp_container = self.container_chaining[0]["container_id"] self.run() def run(self): @@ -256,8 +261,16 @@ class AuthzRequest: for key in self.result["pdp_set"]: if "effect" in self.result["pdp_set"][key]: if self.result["pdp_set"][key]["effect"] == "grant": + # the pdp is a authorization PDP and grant the request + authz_results.append(True) + elif self.result["pdp_set"][key]["effect"] == "passed": + # the pdp is not a authorization PDP (session or delegation) and had run normally + authz_results.append(True) + elif self.result["pdp_set"][key]["effect"] == "unset": + # the pdp is not a authorization PDP (session or delegation) and had not yep run authz_results.append(True) else: + # the pdp is (or not) a authorization PDP and had run badly authz_results.append(False) if list(itertools.accumulate(authz_results, lambda x, y: x & y))[-1]: self.result["pdp_set"]["effect"] = "grant" diff --git a/moonv4/moon_utilities/moon_utilities/security_functions.py b/moonv4/moon_utilities/moon_utilities/security_functions.py index f7cbdf2c..5d66d927 100644 --- a/moonv4/moon_utilities/moon_utilities/security_functions.py +++ b/moonv4/moon_utilities/moon_utilities/security_functions.py @@ -168,8 +168,10 @@ def notify(request_id, container_id, payload, event_type="authz"): 'request_id': request_id, 'container_id': container_id } - result = __n_notifier.critical(ctxt, event_type, payload=payload) - return result + __n_notifier.critical(ctxt, event_type, payload=payload) + # FIXME (asteroide): the notification mus be done 2 times otherwise the notification + # may not be sent (need to search why) + __n_notifier.critical(ctxt, event_type, payload=payload) def call(endpoint, ctx=None, method="get_status", **kwargs): @@ -249,34 +251,66 @@ class Context: self.__pdp_set[header]["meta_rules"] = self.__meta_rules[header] self.__pdp_set[header]["target"] = self.__add_target(header) # TODO (asteroide): the following information must be retrieve somewhere - self.__pdp_set[header]["instruction"] = list() - self.__pdp_set[header]["effect"] = "deny" + self.__pdp_set[header]["effect"] = "unset" self.__pdp_set["effect"] = "deny" + @staticmethod + def update_target(context): + from moon_db.core import PDPManager, ModelManager, PolicyManager + # result = dict() + current_request = context['current_request'] + _subject = current_request.get("subject") + _object = current_request.get("object") + _action = current_request.get("action") + meta_rule_id = context['headers'][context['index']] + policy_id = PolicyManager.get_policy_from_meta_rules("admin", meta_rule_id) + meta_rules = ModelManager.get_meta_rules("admin") + # for meta_rule_id in meta_rules: + for sub_cat in meta_rules[meta_rule_id]['subject_categories']: + if sub_cat not in context["pdp_set"][meta_rule_id]["target"]: + context["pdp_set"][meta_rule_id]["target"][sub_cat] = [] + for assign in PolicyManager.get_subject_assignments("admin", policy_id, _subject, sub_cat).values(): + for assign in assign["assignments"]: + if assign not in context["pdp_set"][meta_rule_id]["target"][sub_cat]: + context["pdp_set"][meta_rule_id]["target"][sub_cat].append(assign) + for obj_cat in meta_rules[meta_rule_id]['object_categories']: + if obj_cat not in context["pdp_set"][meta_rule_id]["target"]: + context["pdp_set"][meta_rule_id]["target"][obj_cat] = [] + for assign in PolicyManager.get_object_assignments("admin", policy_id, _object, obj_cat).values(): + for assign in assign["assignments"]: + if assign not in context["pdp_set"][meta_rule_id]["target"][obj_cat]: + context["pdp_set"][meta_rule_id]["target"][obj_cat].append(assign) + for act_cat in meta_rules[meta_rule_id]['action_categories']: + if act_cat not in context["pdp_set"][meta_rule_id]["target"]: + context["pdp_set"][meta_rule_id]["target"][act_cat] = [] + for assign in PolicyManager.get_action_assignments("admin", policy_id, _action, act_cat).values(): + for assign in assign["assignments"]: + if assign not in context["pdp_set"][meta_rule_id]["target"][act_cat]: + context["pdp_set"][meta_rule_id]["target"][act_cat].append(assign) + # context["pdp_set"][meta_rule_id]["target"].update(result) + def __add_target(self, meta_rule_id): result = dict() _subject = self.__current_request["subject"] _object = self.__current_request["object"] _action = self.__current_request["action"] meta_rules = self.ModelManager.get_meta_rules("admin") - for header in self.__headers: - policy_id = self.PolicyManager.get_policy_from_meta_rules("admin", header) - for meta_rule_id in meta_rules: - for sub_cat in meta_rules[meta_rule_id]['subject_categories']: - if sub_cat not in result: - result[sub_cat] = [] - for assign in self.PolicyManager.get_subject_assignments("admin", policy_id, _subject, sub_cat).values(): - result[sub_cat].extend(assign["assignments"]) - for obj_cat in meta_rules[meta_rule_id]['object_categories']: - if obj_cat not in result: - result[obj_cat] = [] - for assign in self.PolicyManager.get_object_assignments("admin", policy_id, _object, obj_cat).values(): - result[obj_cat].extend(assign["assignments"]) - for act_cat in meta_rules[meta_rule_id]['action_categories']: - if act_cat not in result: - result[act_cat] = [] - for assign in self.PolicyManager.get_action_assignments("admin", policy_id, _action, act_cat).values(): - result[act_cat].extend(assign["assignments"]) + policy_id = self.PolicyManager.get_policy_from_meta_rules("admin", meta_rule_id) + for sub_cat in meta_rules[meta_rule_id]['subject_categories']: + if sub_cat not in result: + result[sub_cat] = [] + for assign in self.PolicyManager.get_subject_assignments("admin", policy_id, _subject, sub_cat).values(): + result[sub_cat].extend(assign["assignments"]) + for obj_cat in meta_rules[meta_rule_id]['object_categories']: + if obj_cat not in result: + result[obj_cat] = [] + for assign in self.PolicyManager.get_object_assignments("admin", policy_id, _object, obj_cat).values(): + result[obj_cat].extend(assign["assignments"]) + for act_cat in meta_rules[meta_rule_id]['action_categories']: + if act_cat not in result: + result[act_cat] = [] + for assign in self.PolicyManager.get_action_assignments("admin", policy_id, _action, act_cat).values(): + result[act_cat].extend(assign["assignments"]) return result def __repr__(self): -- cgit 1.2.3-korg