diff options
author | 2017-05-05 11:16:38 +0200 | |
---|---|---|
committer | 2017-05-05 11:16:38 +0200 | |
commit | 94aa78ca23c4db13a0752fbdd0df96730b1e7288 (patch) | |
tree | 4e77ef8776d5f93b12eae84696f953faf7c3ea6e /moonv4/moon_authz | |
parent | 67369036badcb4ae84fb7c1c7d7dabfab27326e6 (diff) |
Code update for chaining policies.
Change-Id: If9f6c2640492f69d0f3af2118fade72700df47e6
Diffstat (limited to 'moonv4/moon_authz')
-rw-r--r-- | moonv4/moon_authz/moon_authz/api/authorization.py | 437 | ||||
-rw-r--r-- | moonv4/moon_authz/moon_authz/messenger.py | 37 |
2 files changed, 79 insertions, 395 deletions
diff --git a/moonv4/moon_authz/moon_authz/api/authorization.py b/moonv4/moon_authz/moon_authz/api/authorization.py index 248a9565..5968178e 100644 --- a/moonv4/moon_authz/moon_authz/api/authorization.py +++ b/moonv4/moon_authz/moon_authz/api/authorization.py @@ -3,11 +3,12 @@ # license which can be found in the file 'LICENSE' in this package distribution # or at 'http://www.apache.org/licenses/LICENSE-2.0'. -import copy +import hashlib import itertools from oslo_log import log as logging from oslo_config import cfg -from moon_utilities.security_functions import call, Context +import oslo_messaging +from moon_utilities.security_functions import call, Context, notify from moon_utilities.misc import get_uuid_from_name from moon_utilities import exceptions from moon_db.core import PDPManager @@ -40,11 +41,15 @@ class Authorization(object): meta_rule_id = None keystone_project_id = None - def __init__(self, component_id): - self.component_id = component_id - LOG.info("ext={}".format(component_id)) - for _id_value in component_id.split("_"): - LOG.info("_id_value={}".format(_id_value.split(":"))) + 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()} + ) + + for _id_value in component_desc.split("_"): _type, _id = _id_value.split(":") if _type == "pdp": self.pdp_id = _id @@ -52,388 +57,80 @@ class Authorization(object): self.meta_rule_id = _id elif _type == "project": self.keystone_project_id = _id - # self.manager = IntraExtensionAdminManager - # self.context = {"id": self.component_id, "user_id": "admin"} - # self.aggregation_algorithm_dict = ConfigurationManager.driver.get_aggregation_algorithms_dict() - # self.__subjects = None - # self.__objects = None - # self.__actions = None - # self.__subject_scopes = None - # self.__object_scopes = None - # self.__action_scopes = None - # self.__subject_categories = None - # self.__object_categories = None - # self.__action_categories = None - # self.__subject_assignments = None - # self.__object_assignments = None - # self.__action_assignments = None - # self.__sub_meta_rules = None - # self.__rules = None - # self.aggregation_algorithm_id = None - - # @property - # def subjects(self): - # if not self.__subjects: - # self.__subjects = call("moon_secpolicy_{}".format(self.intra_extension_id), ctx=self.context, - # method="get_subjects", args={}) - # if "subjects" in self.__subjects: - # return self.__subjects - # else: - # LOG.error("An error occurred {}".format(self.__subjects)) - # return self.__subjects - # - # @property - # def objects(self): - # if not self.__objects: - # self.__objects = call("moon_secpolicy_{}".format(self.intra_extension_id), ctx=self.context, - # method="get_objects", args={}) - # if "objects" in self.__objects: - # return self.__objects - # else: - # LOG.error("An error occurred {}".format(self.__objects)) - # return self.__objects - # - # @property - # def actions(self): - # if not self.__actions: - # self.__actions = call("moon_secpolicy_{}".format(self.intra_extension_id), ctx=self.context, - # method="get_actions", args={}) - # if "actions" in self.__actions: - # return self.__actions - # else: - # LOG.error("An error occurred {}".format(self.__actions)) - # return self.__actions - # - # @property - # def subject_scopes(self): - # if not self.__subject_scopes: - # self.__subject_scopes = call("moon_secpolicy_{}".format(self.intra_extension_id), ctx=self.context, - # method="get_subject_scopes", args={}) - # if "subject_scopes" in self.__subject_scopes: - # return self.__subject_scopes - # else: - # LOG.error("An error occurred {}".format(self.__subject_scopes)) - # return self.__subject_scopes - # - # @property - # def object_scopes(self): - # if not self.__object_scopes: - # self.__object_scopes = call("moon_secpolicy_{}".format(self.intra_extension_id), ctx=self.context, - # method="get_object_scopes", args={}) - # if "object_scopes" in self.__object_scopes: - # return self.__object_scopes - # else: - # LOG.error("An error occurred {}".format(self.__object_scopes)) - # return self.__object_scopes - # - # @property - # def action_scopes(self): - # if not self.__action_scopes: - # self.__action_scopes = call("moon_secpolicy_{}".format(self.intra_extension_id), ctx=self.context, - # method="get_action_scopes", args={}) - # if "action_scopes" in self.__action_scopes: - # return self.__action_scopes - # else: - # LOG.error("An error occurred {}".format(self.__action_scopes)) - # return self.__action_scopes - # - # @property - # def subject_categories(self): - # if not self.__subject_categories: - # self.__subject_categories = call("moon_secpolicy_{}".format(self.intra_extension_id), ctx=self.context, - # method="get_subject_categories", args={}) - # if "subject_categories" in self.__subject_categories: - # return self.__subject_categories - # else: - # LOG.error("An error occurred {}".format(self.__subject_categories)) - # return self.__subject_categories - # - # @property - # def object_categories(self): - # if not self.__object_categories: - # self.__object_categories = call("moon_secpolicy_{}".format(self.intra_extension_id), ctx=self.context, - # method="get_object_categories", args={}) - # if "object_categories" in self.__object_categories: - # return self.__object_categories - # else: - # LOG.error("An error occurred {}".format(self.__object_categories)) - # return self.__object_categories - # - # @property - # def action_categories(self): - # if not self.__action_categories: - # self.__action_categories = call("moon_secpolicy_{}".format(self.intra_extension_id), ctx=self.context, - # method="get_action_categories", args={}) - # if "action_categories" in self.__action_categories: - # return self.__action_categories - # else: - # LOG.error("An error occurred {}".format(self.__action_categories)) - # return self.__action_categories - # - # @property - # def subject_assignments(self): - # if not self.__subject_assignments: - # context = copy.deepcopy(self.context) - # context['sid'] = None - # context['scid'] = None - # args = {'ssid': None} - # self.__subject_assignments = call("moon_secpolicy_{}".format(self.intra_extension_id), ctx=context, - # method="get_subject_assignments", args=args) - # if "subject_assignments" in self.__subject_assignments: - # return self.__subject_assignments - # else: - # LOG.error("An error occurred {}".format(self.__subject_assignments)) - # return self.__subject_assignments - # - # @property - # def object_assignments(self): - # if not self.__object_assignments: - # context = copy.deepcopy(self.context) - # context['sid'] = None - # context['scid'] = None - # args = {'ssid': None} - # self.__object_assignments = call("moon_secpolicy_{}".format(self.intra_extension_id), ctx=context, - # method="get_object_assignments", args=args) - # if "object_assignments" in self.__object_assignments: - # return self.__object_assignments - # else: - # LOG.error("An error occurred {}".format(self.__object_assignments)) - # return self.__object_assignments - # - # @property - # def action_assignments(self): - # if not self.__action_assignments: - # context = copy.deepcopy(self.context) - # context['sid'] = None - # context['scid'] = None - # args = {'ssid': None} - # self.__action_assignments = call("moon_secpolicy_{}".format(self.intra_extension_id), ctx=context, - # method="get_action_assignments", args=args) - # if "action_assignments" in self.__action_assignments: - # return self.__action_assignments - # else: - # LOG.error("An error occurred {}".format(self.__action_assignments)) - # return self.__action_assignments - # - # @property - # def sub_meta_rules(self): - # if not self.__sub_meta_rules: - # self.__sub_meta_rules = call("moon_secfunction_{}".format(self.intra_extension_id), ctx=self.context, - # method="get_sub_meta_rules", args={}) - # if "sub_meta_rules" in self.__sub_meta_rules: - # return self.__sub_meta_rules - # else: - # LOG.error("An error occurred {}".format(self.__sub_meta_rules)) - # return self.__sub_meta_rules - # - # @property - # def rules(self): - # if not self.__rules: - # self.__rules = dict() - # for _id, _value in self.sub_meta_rules["sub_meta_rules"].items(): - # context = copy.deepcopy(self.context) - # context["sub_meta_rule_id"] = _id - # __elements = call("moon_secfunction_{}".format(self.intra_extension_id), ctx=context, - # method="get_rules", args={}) - # if "rules" in __elements: - # self.__rules[_id] = __elements - # else: - # LOG.error("An error occurred {}".format(__elements)) - # return self.__rules - - # def __get_authz_buffer(self, subject_id, object_id, action_id): - # """ - # :param intra_extension_id: - # :param subject_id: - # :param object_id: - # :param action_id: - # :return: authz_buffer = { - # 'subject_id': xxx, - # 'object_id': yyy, - # 'action_id': zzz, - # 'subject_assignments': { - # 'subject_category1': [], - # 'subject_category2': [], - # ... - # }, - # 'object_assignments': {}, - # 'action_assignments': {}, - # } - # """ - # authz_buffer = dict() - # # Sometimes it is not the subject ID but the User Keystone ID, so, we have to check - # subjects_dict = copy.deepcopy(self.subjects) - # if subject_id not in subjects_dict["subjects"].keys(): - # for _subject_id in subjects_dict["subjects"]: - # if subjects_dict["subjects"][_subject_id]['keystone_id']: - # subject_id = _subject_id - # break - # authz_buffer['subject_id'] = subject_id - # authz_buffer['object_id'] = object_id - # authz_buffer['action_id'] = action_id - # meta_data_dict = dict() - # meta_data_dict["subject_categories"] = copy.deepcopy(self.subject_categories["subject_categories"]) - # meta_data_dict["object_categories"] = copy.deepcopy(self.object_categories["object_categories"]) - # meta_data_dict["action_categories"] = copy.deepcopy(self.action_categories["action_categories"]) - # subject_assignment_dict = copy.deepcopy(self.subject_assignments['subject_assignments'][subject_id]) - # LOG.info("__get_authz_buffer self.object_assignments['object_assignments']={}".format(self.object_assignments['object_assignments'])) - # LOG.info("__get_authz_buffer object_id={}".format(object_id)) - # object_assignment_dict = copy.deepcopy(self.object_assignments['object_assignments'][object_id]) - # action_assignment_dict = copy.deepcopy(self.action_assignments['action_assignments'][action_id]) - # - # authz_buffer['subject_assignments'] = dict() - # authz_buffer['object_assignments'] = dict() - # authz_buffer['action_assignments'] = dict() - # - # for _subject_category in meta_data_dict['subject_categories']: - # authz_buffer['subject_assignments'][_subject_category] = list(subject_assignment_dict[_subject_category]) - # for _object_category in meta_data_dict['object_categories']: - # authz_buffer['object_assignments'][_object_category] = list(object_assignment_dict[_object_category]) - # for _action_category in meta_data_dict['action_categories']: - # authz_buffer['action_assignments'][_action_category] = list(action_assignment_dict[_action_category]) - # return authz_buffer - # - # def __get_decision_dict(self, subject_id, object_id, action_id): - # """Check authorization for a particular action. - # - # :param intra_extension_id: UUID of an IntraExtension - # :param subject_id: subject UUID of the request - # :param object_id: object UUID of the request - # :param action_id: action UUID of the request - # :return: True or False or raise an exception - # :raises: - # """ - # authz_buffer = self.__get_authz_buffer(subject_id, object_id, action_id) - # decision_buffer = dict() - # - # meta_rule_dict = copy.deepcopy(self.sub_meta_rules['sub_meta_rules']) - # rules_dict = copy.deepcopy(self.rules) - # for sub_meta_rule_id in meta_rule_dict: - # if meta_rule_dict[sub_meta_rule_id]['algorithm'] == 'inclusion': - # decision_buffer[sub_meta_rule_id] = algorithms.inclusion( - # authz_buffer, - # meta_rule_dict[sub_meta_rule_id], - # rules_dict[sub_meta_rule_id]['rules'].values()) - # elif meta_rule_dict[sub_meta_rule_id]['algorithm'] == 'comparison': - # decision_buffer[sub_meta_rule_id] = algorithms.comparison( - # authz_buffer, - # meta_rule_dict[sub_meta_rule_id], - # rules_dict[sub_meta_rule_id]['rules'].values()) - # - # return decision_buffer - # - # def __authz(self, subject_id, object_id, action_id): - # decision = False - # decision_dict = dict() - # try: - # decision_dict = self.__get_decision_dict(subject_id, object_id, action_id) - # except (exceptions.SubjectUnknown, exceptions.ObjectUnknown, exceptions.ActionUnknown) as e: - # # maybe we need to synchronize with the master - # pass - # # if CONF.slave.slave_name and CONF.slave.master_url: - # # self.get_data_from_master() - # # decision_dict = self.__get_decision_dict(subject_id, object_id, action_id) - # - # try: - # # aggregation_algorithm_id = IntraExtensionAdminManager.get_aggregation_algorithm_id( - # # "admin", - # # self.intra_extension_id)['aggregation_algorithm'] - # if not self.aggregation_algorithm_id: - # self.aggregation_algorithm_id = self.intra_extension['aggregation_algorithm'] - # except Exception as e: - # LOG.error(e, exc_info=True) - # LOG.error(self.intra_extension) - # return { - # 'authz': False, - # 'comment': "Aggregation algorithm not set" - # } - # if self.aggregation_algorithm_dict[self.aggregation_algorithm_id]['name'] == 'all_true': - # decision = algorithms.all_true(decision_dict) - # elif self.aggregation_algorithm_dict[self.aggregation_algorithm_id]['name'] == 'one_true': - # decision = algorithms.one_true(decision_dict) - # if not decision_dict or not decision: - # raise exceptions.AuthzException("{} {}-{}-{}".format(self.intra_extension['id'], subject_id, action_id, object_id)) - # return { - # 'authz': decision, - # 'comment': "{} {}-{}-{}".format(self.intra_extension['id'], subject_id, action_id, object_id) - # } - # - # def authz_bak(self, ctx, args): - # """Return the authorization for a specific request - # - # :param ctx: { - # "subject_name" : "string name", - # "action_name" : "string name", - # "object_name" : "string name" - # } - # :param args: {} - # :return: { - # "authz": "True or False", - # "message": "optional message" - # } - # """ - # intra_extension_id = ctx["id"] - # try: - # subject_id = get_uuid_from_name(ctx["subject_name"], self.subjects['subjects']) - # object_id = get_uuid_from_name(ctx["object_name"], self.objects['objects']) - # action_id = get_uuid_from_name(ctx["action_name"], self.actions['actions']) - # authz_result = self.__authz(subject_id, object_id, action_id) - # return authz_result - # except Exception as e: - # LOG.error(e, exc_info=True) - # return {"authz": False, - # "error": str(e), - # "intra_extension_id": intra_extension_id, - # "ctx": ctx, "args": args} - # - # return {"authz": False} def __check_rules(self, context): scopes_list = list() - current_header_id = context.headers[context.index]['id'] - current_pdp = context.pdp_set[current_header_id] + current_header_id = context['headers'][context['index']] + 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"]["action_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'])) - return False, "Empty assignment detected..." + # if not current_pdp['target'][category]: + # LOG.warning("Empty assignment detected: {} target={}".format(category, current_pdp['target'])) scopes_list.append(current_pdp['target'][category]) - scopes_list.append([True, ]) - rules = PolicyManager.get_rules_dict(user_id="admin", - policy_id=self.policy_id, - meta_rule_id=current_header_id).values() + 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): - if list(item) in rules: + req = list(item) + if req in rules: return True, "" LOG.warning("No rule match the request...") return False, "No rule match the request..." - def authz(self, ctx, args): - LOG.info("authz {}".format(ctx)) - keystone_project_id = ctx["id"] + 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" + + :param ctxt: context of the request + :param publisher_id: ID of the publisher + :param event_type: type of event ("authz" here) + :param payload: content of the authz request + :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"] try: - if "authz_context" not in ctx: - ctx["authz_context"] = Context(keystone_project_id, - ctx["subject_name"], - ctx["object_name"], - ctx["action_name"], - ctx["request_id"]).to_dict() - LOG.info("Context={}".format(ctx["authz_context"])) + 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() + 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] + 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) else: - ctx["authz_context"].index += 1 - result, message = self.__check_rules(ctx["authz_context"]) - # if ctx["authz_context"].index < len(ctx["authz_context"].headers): - del ctx["authz_context"] + 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"] return {"authz": result, "error": message, "pdp_id": self.pdp_id, - "ctx": ctx, "args": args} + "ctx": ctxt, "args": payload} except Exception as e: try: - LOG.error(ctx["authz_context"]) + LOG.error(payload["authz_context"]) # del ctx["authz_context"] except KeyError: LOG.error("Cannot find \"authz_context\" in context") @@ -441,5 +138,5 @@ class Authorization(object): return {"authz": False, "error": str(e), "pdp_id": self.pdp_id, - "ctx": ctx, "args": args} + "ctx": ctxt, "args": payload} diff --git a/moonv4/moon_authz/moon_authz/messenger.py b/moonv4/moon_authz/moon_authz/messenger.py index 8ebd1633..6fa34770 100644 --- a/moonv4/moon_authz/moon_authz/messenger.py +++ b/moonv4/moon_authz/moon_authz/messenger.py @@ -5,12 +5,10 @@ from oslo_config import cfg import oslo_messaging -import hashlib import time from oslo_log import log as logging from moon_authz.api.generic import Status, Logs from moon_authz.api.authorization import Authorization -from moon_utilities.security_functions import call from moon_utilities.api import APIList LOG = logging.getLogger(__name__) @@ -20,44 +18,33 @@ CONF = cfg.CONF class Server: def __init__(self, component_id, keystone_project_id): - self.TOPIC = "authz_"+hashlib.sha224(component_id.encode("utf-8")).hexdigest() - self.transport = oslo_messaging.get_transport(cfg.CONF) - self.target = oslo_messaging.Target(topic=self.TOPIC, server='moon_authz_server1') - # ctx = {'user_id': 'admin', 'id': component_id, 'method': 'get_intra_extensions'} - # if CONF.slave.slave_name: - # ctx['call_master'] = True - # intra_extension = call( - # endpoint="security_router", - # ctx=ctx, - # method='route', - # args={} - # ) - # if "intra_extensions" not in intra_extension: - # LOG.error("Error reading intra_extension from router") - # LOG.error("intra_extension: {}".format(intra_extension)) - # raise IntraExtensionUnknown - # component_id = list(intra_extension["intra_extensions"].keys())[0] - LOG.info("Starting MQ server with topic: {}".format(self.TOPIC)) + self.TOPIC = "authz-workers" + transport = oslo_messaging.get_notification_transport(cfg.CONF) + targets = [ + oslo_messaging.Target(topic=self.TOPIC), + ] self.endpoints = [ APIList((Status, Logs)), Status(), Logs(), Authorization(component_id) ] - self.server = oslo_messaging.get_rpc_server(self.transport, self.target, self.endpoints, - executor='threading', - access_policy=oslo_messaging.DefaultRPCAccessPolicy) + pool = "authz-workers" + self.server = oslo_messaging.get_notification_listener(transport, targets, + self.endpoints, executor='threading', + pool=pool) + LOG.info("Starting MQ notification server with topic: {}".format(self.TOPIC)) def run(self): try: self.server.start() while True: - time.sleep(1) + time.sleep(0.1) except KeyboardInterrupt: print("Stopping server by crtl+c") except SystemExit: print("Stopping server") self.server.stop() - self.server.wait() + |