aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--moonv4/moon_authz/moon_authz/api/authorization.py437
-rw-r--r--moonv4/moon_authz/moon_authz/messenger.py37
-rw-r--r--moonv4/moon_db/moon_db/api/policy.py9
-rw-r--r--moonv4/moon_interface/moon_interface/tools.py1
-rw-r--r--moonv4/moon_interface/tests/apitests/scenario/mls.py1
-rw-r--r--moonv4/moon_interface/tests/apitests/scenario/rbac.py7
-rw-r--r--moonv4/moon_interface/tests/apitests/set_authz.py9
-rw-r--r--moonv4/moon_orchestrator/conf/plugins/authz.py17
-rw-r--r--moonv4/moon_secrouter/moon_secrouter/api/route.py192
-rw-r--r--moonv4/moon_utilities/moon_utilities/security_functions.py120
10 files changed, 328 insertions, 502 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()
+
diff --git a/moonv4/moon_db/moon_db/api/policy.py b/moonv4/moon_db/moon_db/api/policy.py
index 73889b85..0beaf78f 100644
--- a/moonv4/moon_db/moon_db/api/policy.py
+++ b/moonv4/moon_db/moon_db/api/policy.py
@@ -28,6 +28,15 @@ class PolicyManager(Managers):
self.driver = connector.driver
Managers.PolicyManager = self
+ def get_policy_from_meta_rules(self, user_id, meta_rule_id):
+ policies = self.PolicyManager.get_policies("admin")
+ models = self.ModelManager.get_models("admin")
+ for pdp_key, pdp_value in self.PDPManager.get_pdp(user_id).items():
+ for policy_id in pdp_value["security_pipeline"]:
+ model_id = policies[policy_id]["model_id"]
+ if meta_rule_id in models[model_id]["meta_rules"]:
+ return policy_id
+
@enforce(("read", "write"), "policies")
def update_policy(self, user_id, policy_id, value):
return self.driver.update_policy(policy_id=policy_id, value=value)
diff --git a/moonv4/moon_interface/moon_interface/tools.py b/moonv4/moon_interface/moon_interface/tools.py
index 3c0fffa5..443519ac 100644
--- a/moonv4/moon_interface/moon_interface/tools.py
+++ b/moonv4/moon_interface/moon_interface/tools.py
@@ -29,7 +29,6 @@ def timeit(function):
return wrapper
-@timeit
def call(topic="security_router", ctx=None, method="route", **kwargs):
if not ctx:
ctx = dict()
diff --git a/moonv4/moon_interface/tests/apitests/scenario/mls.py b/moonv4/moon_interface/tests/apitests/scenario/mls.py
index fab1d528..e36a86bc 100644
--- a/moonv4/moon_interface/tests/apitests/scenario/mls.py
+++ b/moonv4/moon_interface/tests/apitests/scenario/mls.py
@@ -39,6 +39,7 @@ meta_rule = {
rules = {
"mls": (
("high", "medium", "vm-action"),
+ ("high", "low", "vm-action"),
("medium", "low", "vm-action"),
)
}
diff --git a/moonv4/moon_interface/tests/apitests/scenario/rbac.py b/moonv4/moon_interface/tests/apitests/scenario/rbac.py
index 073f1d65..cd08308e 100644
--- a/moonv4/moon_interface/tests/apitests/scenario/rbac.py
+++ b/moonv4/moon_interface/tests/apitests/scenario/rbac.py
@@ -4,7 +4,7 @@ policy_name = "RBAC policy example"
model_name = "RBAC"
subjects = {"user0": "", "user1": "", }
-objects = {"vm0": "", }
+objects = {"vm0": "", "vm1": "", }
actions = {"start": "", "stop": ""}
subject_categories = {"role": "", }
@@ -12,11 +12,11 @@ object_categories = {"id": "", }
action_categories = {"action-type": "", }
subject_data = {"role": {"admin": "", "employee": ""}}
-object_data = {"id": {"vm1": "", "vm2": ""}}
+object_data = {"id": {"vm0": "", "vm1": ""}}
action_data = {"action-type": {"vm-action": "", }}
subject_assignments = {"user0": {"role": "admin"}, "user1": {"role": "employee"}, }
-object_assignments = {"vm0": {"id": "vm1"}}
+object_assignments = {"vm0": {"id": "vm0"}, "vm1": {"id": "vm1"}}
action_assignments = {"start": {"action-type": "vm-action"}, "stop": {"action-type": "vm-action"}}
meta_rule = {
@@ -25,6 +25,7 @@ meta_rule = {
rules = {
"rbac": (
+ ("admin", "vm0", "vm-action"),
("admin", "vm1", "vm-action"),
)
}
diff --git a/moonv4/moon_interface/tests/apitests/set_authz.py b/moonv4/moon_interface/tests/apitests/set_authz.py
index 7d0d5069..38b63509 100644
--- a/moonv4/moon_interface/tests/apitests/set_authz.py
+++ b/moonv4/moon_interface/tests/apitests/set_authz.py
@@ -40,4 +40,11 @@ if not keystone_project_id:
for rule in rules:
url = "http://172.18.0.11:38001/authz/{}/{}".format(keystone_project_id, "/".join(rule))
req = requests.get(url)
- print(url, req.status_code)
+ 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", "")))
+ else:
+ print("\t\033[31m{}\033[m {}".format(j.get("authz"), j.get("error", "")))
+
diff --git a/moonv4/moon_orchestrator/conf/plugins/authz.py b/moonv4/moon_orchestrator/conf/plugins/authz.py
index c472b36a..4a1441c9 100644
--- a/moonv4/moon_orchestrator/conf/plugins/authz.py
+++ b/moonv4/moon_orchestrator/conf/plugins/authz.py
@@ -47,16 +47,17 @@ RUN pip3 install .
)
# note(asteroide): time to let the new docker boot
time.sleep(3)
- self.get_status()
+ # self.get_status()
def get_status(self):
- 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
+ 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):
diff --git a/moonv4/moon_secrouter/moon_secrouter/api/route.py b/moonv4/moon_secrouter/moon_secrouter/api/route.py
index ec79d96b..ccdff08b 100644
--- a/moonv4/moon_secrouter/moon_secrouter/api/route.py
+++ b/moonv4/moon_secrouter/moon_secrouter/api/route.py
@@ -5,8 +5,10 @@
import copy
import time
+import itertools
+from uuid import uuid4
from oslo_log import log as logging
-from moon_utilities.security_functions import call
+from moon_utilities.security_functions import call, notify
from oslo_config import cfg
from moon_secrouter.api.generic import Status, Logs
@@ -90,6 +92,7 @@ API = {
),
"function": (
"authz",
+ "return_authz",
),
}
@@ -97,18 +100,109 @@ API = {
class Cache(object):
# TODO (asteroide): set cache integer in CONF file
- __UPDATE_INTERVAL = 300
+ __UPDATE_INTERVAL = 10
+
__CONTAINERS = {}
- __LAST_UPDATE = 0
+ __CONTAINERS_UPDATE = 0
+
+ __CONTAINER_CHAINING_UPDATE = 0
+ __CONTAINER_CHAINING = {}
+
+ __PDP = {}
+ __PDP_UPDATE = 0
+
+ __POLICIES = {}
+ __POLICIES_UPDATE = 0
+
+ __MODELS = {}
+ __MODELS_UPDATE = 0
+
+ __AUTHZ_REQUESTS = {}
+
+ def update(self, component=None):
+ self.__update_container()
+ self.__update_pdp()
+ self.__update_policies()
+ self.__update_models()
+ for key, value in self.__PDP.items():
+ self.__update_container_chaining(value["keystone_project_id"])
+
+ @property
+ def authz_requests(self):
+ return self.__AUTHZ_REQUESTS
+
+ def __update_pdp(self):
+ pdp = call("moon_manager", method="get_pdp", ctx={"user_id": "admin"}, args={})
+ for _pdp in pdp["pdps"].values():
+ if _pdp['keystone_project_id'] not in self.__CONTAINER_CHAINING:
+ self.__CONTAINER_CHAINING[_pdp['keystone_project_id']] = {}
+ # Note (asteroide): force update of chaining
+ self.__update_container_chaining(_pdp['keystone_project_id'])
+ for key, value in pdp["pdps"].items():
+ self.__PDP[key] = value
+
+ @property
+ def pdp(self):
+ current_time = time.time()
+ if self.__PDP_UPDATE + self.__UPDATE_INTERVAL < current_time:
+ self.__update_pdp()
+ self.__PDP_UPDATE = current_time
+ return self.__PDP
+
+ def __update_policies(self):
+ policies = call("moon_manager", method="get_policies", ctx={"user_id": "admin"}, args={})
+ for key, value in policies["policies"].items():
+ self.__POLICIES[key] = value
+
+ @property
+ def policies(self):
+ current_time = time.time()
+ if self.__POLICIES_UPDATE + self.__UPDATE_INTERVAL < current_time:
+ self.__update_policies()
+ self.__POLICIES_UPDATE = current_time
+ return self.__POLICIES
+
+ def __update_models(self):
+ models = call("moon_manager", method="get_models", ctx={"user_id": "admin"}, args={})
+ for key, value in models["models"].items():
+ self.__MODELS[key] = value
+
+ @property
+ def models(self):
+ current_time = time.time()
+ if self.__MODELS_UPDATE + self.__UPDATE_INTERVAL < current_time:
+ self.__update_models()
+ self.__MODELS_UPDATE = current_time
+ return self.__MODELS
def __update_container(self):
containers = call("orchestrator", method="get_container", ctx={}, args={})
- LOG.info("container={}".format(containers))
for key, value in containers["containers"].items():
self.__CONTAINERS[key] = value
- def update(self, component=None):
- self.__update_container()
+ @property
+ def container_chaining(self):
+ current_time = time.time()
+ if self.__CONTAINER_CHAINING_UPDATE + self.__UPDATE_INTERVAL < current_time:
+ for key, value in self.pdp.items():
+ self.__update_container_chaining(value["keystone_project_id"])
+ self.__CONTAINER_CHAINING_UPDATE = current_time
+ return self.__CONTAINER_CHAINING
+
+ def __update_container_chaining(self, keystone_project_id):
+ container_ids = []
+ for pdp_id, pdp_value, in CACHE.pdp.items():
+ if pdp_value:
+ if pdp_value["keystone_project_id"] == keystone_project_id:
+ for policy_id in pdp_value["security_pipeline"]:
+ model_id = CACHE.policies[policy_id]['model_id']
+ for meta_rule_id in CACHE.models[model_id]["meta_rules"]:
+ 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"])
+ break
+ self.__CONTAINER_CHAINING[keystone_project_id] = container_ids
@property
def containers(self):
@@ -121,21 +215,65 @@ class Cache(object):
:return:
"""
current_time = time.time()
- if self.__LAST_UPDATE + self.__UPDATE_INTERVAL < current_time:
+ if self.__CONTAINERS_UPDATE + self.__UPDATE_INTERVAL < current_time:
self.__update_container()
- self.__LAST_UPDATE = current_time
+ self.__CONTAINERS_UPDATE = current_time
return self.__CONTAINERS
CACHE = Cache()
+class AuthzRequest:
+
+ result = None
+ req_max_delay = 5
+
+ def __init__(self, ctx, args):
+ self.ctx = ctx
+ self.args = args
+ 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.run()
+
+ def run(self):
+ notify(request_id=self.request_id, container_id=self.pdp_container, payload=self.ctx)
+ cpt = 0
+ while cpt < self.req_max_delay*10:
+ time.sleep(0.1)
+ cpt += 1
+ if CACHE.authz_requests[self.request_id]:
+ self.result = CACHE.authz_requests[self.request_id]
+ return
+ LOG.warning("Request {} has timed out".format(self.request_id))
+
+ def is_authz(self):
+ if not self.result:
+ return False
+ authz_results = []
+ for key in self.result["pdp_set"]:
+ if "effect" in self.result["pdp_set"][key]:
+ if self.result["pdp_set"][key]["effect"] == "grant":
+ authz_results.append(True)
+ else:
+ authz_results.append(False)
+ if list(itertools.accumulate(authz_results, lambda x, y: x & y))[-1]:
+ self.result["pdp_set"]["effect"] = "grant"
+ if self.result:
+ if "pdp_set" in self.result and self.result["pdp_set"]["effect"] == "grant":
+ return True
+ return False
+
+
class Router(object):
"""
Route requests to all components.
"""
__version__ = "0.1.0"
+ cache_requests = {}
def __init__(self, add_master_cnx):
if CONF.slave.slave_name and add_master_cnx:
@@ -179,13 +317,6 @@ class Router(object):
LOG.info(result)
@staticmethod
- def __get_first_container(keystone_project_id):
- for container_id, container_value, in CACHE.containers.items():
- if container_value:
- if container_value[0]["keystone_project_id"] == keystone_project_id:
- return container_value[0]["container_id"]
-
- @staticmethod
def check_pdp(ctx):
_ctx = copy.deepcopy(ctx)
if CONF.slave.slave_name:
@@ -228,21 +359,32 @@ class Router(object):
if component == "orchestrator":
return call(component, method=ctx["method"], ctx=ctx, args=args)
if component == "manager":
- LOG.info("Call Manager {}".format(ctx))
result = call("moon_manager", method=ctx["method"], ctx=ctx, args=args)
self.send_update(api=ctx["method"], ctx=ctx, args=args)
return result
if component == "function":
- if self.check_pdp(ctx):
- LOG.info("Tenant ID={}".format(ctx['id']))
- pdp_container = self.__get_first_container(ctx['id'])
- LOG.info("pdp_container={}".format(pdp_container))
- # TODO (asteroide): call the first security function through a notification
- # and not an RPC call (need to play with ID in context)
- result = call(pdp_container, method=ctx["method"], ctx=ctx, args=args)
- return result
+ if ctx["method"] == "return_authz":
+ request_id = ctx["request_id"]
+ CACHE.authz_requests[request_id] = args
+ return args
+ elif self.check_pdp(ctx):
+ req_id = uuid4().hex
+ CACHE.authz_requests[req_id] = {}
+ ctx["request_id"] = req_id
+ req = AuthzRequest(ctx, args)
+ # result = copy.deepcopy(req.result)
+ if req.is_authz():
+ return {"authz": True,
+ "pdp_id": ctx["id"],
+ "ctx": ctx, "args": args}
+ return {"authz": False,
+ "error": {'code': 403, 'title': 'Authz Error',
+ 'description': "The authz request is refused."},
+ "pdp_id": ctx["id"],
+ "ctx": ctx, "args": args}
return {"result": False,
- "error": {'code': 500, 'title': 'Moon Error', 'description': "Function component not found."},
+ "error": {'code': 500, 'title': 'Moon Error',
+ 'description': "Function component not found."},
"pdp_id": ctx["id"],
"ctx": ctx, "args": args}
diff --git a/moonv4/moon_utilities/moon_utilities/security_functions.py b/moonv4/moon_utilities/moon_utilities/security_functions.py
index 2ad52a4c..f7cbdf2c 100644
--- a/moonv4/moon_utilities/moon_utilities/security_functions.py
+++ b/moonv4/moon_utilities/moon_utilities/security_functions.py
@@ -8,13 +8,10 @@ import copy
import re
import types
import requests
-from uuid import uuid4
from oslo_log import log as logging
from oslo_config import cfg
import oslo_messaging
from moon_utilities import exceptions
-from oslo_config.cfg import ConfigOpts
-# from moon_db.core import PDPManager, ModelManager, PolicyManager
LOG = logging.getLogger(__name__)
CONF = cfg.CONF
@@ -158,6 +155,22 @@ def logout(headers, url=None):
__transport_master = oslo_messaging.get_transport(cfg.CONF, CONF.slave.master_url)
__transport = oslo_messaging.get_transport(CONF)
+__n_transport = oslo_messaging.get_notification_transport(CONF)
+__n_notifier = oslo_messaging.Notifier(__n_transport,
+ 'router.host',
+ driver='messagingv2',
+ topics=['authz-workers'])
+__n_notifier = __n_notifier.prepare(publisher_id='router')
+
+
+def notify(request_id, container_id, payload, event_type="authz"):
+ ctxt = {
+ 'request_id': request_id,
+ 'container_id': container_id
+ }
+ result = __n_notifier.critical(ctxt, event_type, payload=payload)
+ return result
+
def call(endpoint, ctx=None, method="get_status", **kwargs):
if not ctx:
@@ -183,13 +196,11 @@ class Context:
self.__keystone_project_id = _keystone_project_id
self.__pdp_id = None
self.__pdp_value = None
- LOG.info("Context pdp={}".format(PDPManager.get_pdp("admin")))
for _pdp_key, _pdp_value in PDPManager.get_pdp("admin").items():
if _pdp_value["keystone_project_id"] == _keystone_project_id:
self.__pdp_id = _pdp_key
self.__pdp_value = copy.deepcopy(_pdp_value)
break
- LOG.info("Context pdp_value={}".format(self.__pdp_value))
self.__subject = _subject
self.__object = _object
self.__action = _action
@@ -200,29 +211,11 @@ class Context:
self.__headers = []
policies = PolicyManager.get_policies("admin")
models = ModelManager.get_models("admin")
- LOG.info("Context policies={}".format(policies))
- LOG.info("Context models={}".format(models))
for policy_id in self.__pdp_value["security_pipeline"]:
model_id = policies[policy_id]["model_id"]
for meta_rule in models[model_id]["meta_rules"]:
self.__headers.append(meta_rule)
self.__meta_rules = ModelManager.get_meta_rules("admin")
- LOG.info("Context meta_rules={}".format(self.__meta_rules))
- LOG.info("Context headers={}".format(self.__headers))
- # call("moon_manager",
- # method="get_meta_rules",
- # ctx={"id": self.__intra_extension_id,
- # "user_id": "admin",
- # "method": "get_sub_meta_rules"},
- # args={})["sub_meta_rules"]
- # for key in self.__intra_extension["pdp_pipeline"]:
- # LOG.info("__meta_rules={}".format(self.__meta_rules))
- # for meta_rule_key in self.__meta_rules:
- # if self.__meta_rules[meta_rule_key]['name'] == key.split(":", maxsplit=1)[-1]:
- # self.__headers.append({"name": self.__meta_rules[meta_rule_key]['name'], "id": meta_rule_key})
- # break
- # else:
- # LOG.warning("Cannot find meta_rule_key {}".format(key))
self.__pdp_set = {}
self.__init_pdp_set()
@@ -254,59 +247,36 @@ class Context:
for header in self.__headers:
self.__pdp_set[header] = dict()
self.__pdp_set[header]["meta_rules"] = self.__meta_rules[header]
- self.__pdp_set[header]["target"] = self.__add_target()
+ 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"] = "grant"
- self.__pdp_set["effect"] = "grant"
+ self.__pdp_set[header]["effect"] = "deny"
+ self.__pdp_set["effect"] = "deny"
- def __add_target(self):
+ def __add_target(self, meta_rule_id):
result = dict()
_subject = self.__current_request["subject"]
_object = self.__current_request["object"]
_action = self.__current_request["action"]
- categories = self.ModelManager.get_subject_categories("admin")
- # TODO (asteroide): end the dev of that part
- # for category in categories:
- # result[category] = list()
- # assignments = call("moon_secpolicy_{}".format(self.__intra_extension_id),
- # method="get_subject_assignments",
- # ctx={"id": self.__intra_extension_id,
- # "sid": _subject,
- # "scid": category,
- # "user_id": "admin"},
- # args={})["subject_assignments"]
- # result[category].extend(assignments[_subject][category])
- # categories = call("moon_secpolicy_{}".format(self.__intra_extension_id),
- # method="get_object_categories",
- # ctx={"id": self.__intra_extension_id,
- # "user_id": "admin"},
- # args={})["object_categories"]
- # for category in categories:
- # result[category] = list()
- # assignments = call("moon_secpolicy_{}".format(self.__intra_extension_id),
- # method="get_object_assignments",
- # ctx={"id": self.__intra_extension_id,
- # "sid": _object,
- # "scid": category,
- # "user_id": "admin"},
- # args={})["object_assignments"]
- # result[category].extend(assignments[_object][category])
- # categories = call("moon_secpolicy_{}".format(self.__intra_extension_id),
- # method="get_action_categories",
- # ctx={"id": self.__intra_extension_id,
- # "user_id": "admin"},
- # args={})["action_categories"]
- # for category in categories:
- # result[category] = list()
- # assignments = call("moon_secpolicy_{}".format(self.__intra_extension_id),
- # method="get_action_assignments",
- # ctx={"id": self.__intra_extension_id,
- # "sid": _action,
- # "scid": category,
- # "user_id": "admin"},
- # args={})["action_assignments"]
- # result[category].extend(assignments[_action][category])
+ 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"])
return result
def __repr__(self):
@@ -336,6 +306,18 @@ pdp_set: {pdp_set}
}
@property
+ def request_id(self):
+ return self.__request_id
+
+ @request_id.setter
+ def request_id(self, value):
+ raise Exception("You cannot update the request_id")
+
+ @request_id.deleter
+ def request_id(self):
+ raise Exception("You cannot update the request_id")
+
+ @property
def initial_request(self):
return {
"subject": self.__subject,