aboutsummaryrefslogtreecommitdiffstats
path: root/moon_manager/moon_manager/api/rules.py
diff options
context:
space:
mode:
Diffstat (limited to 'moon_manager/moon_manager/api/rules.py')
-rw-r--r--moon_manager/moon_manager/api/rules.py319
1 files changed, 270 insertions, 49 deletions
diff --git a/moon_manager/moon_manager/api/rules.py b/moon_manager/moon_manager/api/rules.py
index cbd39969..e984ee93 100644
--- a/moon_manager/moon_manager/api/rules.py
+++ b/moon_manager/moon_manager/api/rules.py
@@ -1,42 +1,63 @@
-# 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'.
+# Software Name: MOON
+
+# Version: 5.4
+
+# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors
+# SPDX-License-Identifier: Apache-2.0
+
+# This software is distributed under the 'Apache License 2.0',
+# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt'
+# or see the "LICENSE" file for more details.
+
"""
-Rules (TODO)
+Rules
"""
-from flask import request
-from flask_restful import Resource
+import hug
+import json
import logging
-from python_moonutilities.security_functions import check_auth
-from python_moondb.core import PolicyManager
-from python_moonutilities.security_functions import validate_input
+import requests
+from moon_manager import db_driver as driver
+from moon_utilities.security_functions import validate_input
+from moon_utilities.invalided_functions import invalidate_rules_in_slaves
+from moon_manager.api import configuration
+from moon_utilities.auth_functions import init_db, api_key_authentication, connect_from_env
+from moon_manager.api import slave as slave_class
+from moon_manager.api import policy, meta_rules, data
-__version__ = "4.3.2"
+LOGGER = logging.getLogger("moon.manager.api." + __name__)
-logger = logging.getLogger("moon.manager.api." + __name__)
-
-class Rules(Resource):
+class Rules(object):
"""
Endpoint for rules requests
"""
- __urls__ = ("/policies/<string:uuid>/rules",
- "/policies/<string:uuid>/rules/",
- "/policies/<string:uuid>/rules/<string:rule_id>",
- "/policies/<string:uuid>/rules/<string:rule_id>/",
- )
+ @staticmethod
+ def _get_data_name(user, rule_data, policy_id):
+ global_data = driver.PolicyManager.get_subject_data(moon_user_id=user, policy_id=policy_id) +\
+ driver.PolicyManager.get_object_data(moon_user_id=user, policy_id=policy_id) +\
+ driver.PolicyManager.get_action_data(moon_user_id=user, policy_id=policy_id)
+ _rule_names = list()
+ for rule_id in rule_data:
+ for _data in global_data:
+ if rule_id in _data.get("data"):
+ _rule_names.append(_data.get("data")[rule_id].get("name"))
+ break
+ else:
+ _rule_names.append(rule_id)
+ return _rule_names
- @validate_input("get", kwargs_state=[False, False, False])
- @check_auth
- def get(self, uuid=None, rule_id=None, user_id=None):
+ @staticmethod
+ @hug.local()
+ @hug.get("/policies/{uuid}/rules", requires=api_key_authentication)
+ @hug.get("/policies/{uuid}/rules/{rule_id}", requires=api_key_authentication)
+ def get(uuid: hug.types.text, rule_id: hug.types.text = None, moon_user_id: hug.directives.user = None):
"""Retrieve all rules or a specific one
:param uuid: policy ID
:param rule_id: rule ID
- :param user_id: user ID who do the request
+ :param moon_user_id: user ID who do the request
:return: {
"rules": [
"policy_id": "policy_id1",
@@ -50,27 +71,28 @@ class Rules(Resource):
:internal_api: get_rules
"""
- data = PolicyManager.get_rules(user_id=user_id,
- policy_id=uuid,
- rule_id=rule_id)
+ data = driver.PolicyManager.get_rules(moon_user_id=moon_user_id, policy_id=uuid,
+ rule_id=rule_id)
return {"rules": data}
- @validate_input("post", kwargs_state=[True, False, False],
- body_state={"meta_rule_id": True, "rule": True, "instructions": True})
- @check_auth
- def post(self, uuid=None, rule_id=None, user_id=None):
+ @staticmethod
+ @hug.local()
+ @hug.post("/policies/{uuid}/rules", requires=api_key_authentication)
+ def post(body: validate_input("meta_rule_id", "rule", "instructions"),
+ uuid: hug.types.text,
+ moon_user_id: hug.directives.user = None):
"""Add a rule to a meta rule
:param uuid: policy ID
- :param rule_id: rule ID (not used here)
- :param user_id: user ID who do the request
+ :param body: body of the request
+ :param moon_user_id: user ID who do the request
:request body: post = {
"meta_rule_id": "meta_rule_id1", # mandatory
"rule": ["subject_data_id2", "object_data_id2", "action_data_id2"], # mandatory
- "instructions": ( # mandatory
+ "instructions": [ # mandatory
{"decision": "grant"},
- )
+ ]
"enabled": True
}
:return: {
@@ -80,18 +102,18 @@ class Rules(Resource):
"rule": ["subject_data_id1",
"object_data_id1",
"action_data_id1"],
- "instructions": (
+ "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": (
+ "instructions": [
{
"update": {
"operation": "add",
@@ -102,34 +124,233 @@ class Rules(Resource):
},
{"chain": {"name": "rbac"}}
# chain with the policy named rbac
- )
+ ]
}
]
}
:internal_api: add_rule
"""
- args = request.json
- data = PolicyManager.add_rule(user_id=user_id,
- policy_id=uuid,
- meta_rule_id=args['meta_rule_id'],
- value=args)
+ data = driver.PolicyManager.add_rule(moon_user_id=moon_user_id, policy_id=uuid,
+ meta_rule_id=body['meta_rule_id'], value=body)
+
+ subject, object_, *action = Rules._get_data_name(moon_user_id, body['rule'], uuid)
+ instruction = body['instructions'][0]['decision']
+ LOGGER.info(f"The user <{moon_user_id}> added the rule <{subject}, {object_}, {action}: {instruction}>")
+
+ slaves = slave_class.Slaves.get().get("slaves")
+ invalidate_rules_in_slaves(slaves=slaves, policy_id=uuid, rule_id=None)
return {"rules": data}
- @validate_input("delete", kwargs_state=[True, True, False])
- @check_auth
- def delete(self, uuid=None, rule_id=None, user_id=None):
+ @staticmethod
+ @hug.local()
+ @hug.patch("/policies/{uuid}/rules/{rule_id}", requires=api_key_authentication)
+ def patch(uuid: hug.types.text, rule_id: hug.types.text, body: validate_input("instructions"),
+ moon_user_id: hug.directives.user = None):
+ """Updates a rule (only its instructions)
+
+ :param uuid: policy ID
+ :param body: body of the request
+ :param rule_id: the id of the rule to patch
+ :param moon_user_id: user ID who do the request
+ :request body: patch = {
+ "instructions": [ # mandatory
+ {"decision": "grant"},
+ ]
+ }
+ :return: {
+ "rules": [
+ "meta_rule_id": "meta_rule_id1",
+ "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 (not yet supported)
+ # "deny" to deny the request
+ ]
+ }
+ ]
+ }
+ :internal_api: update_rule
+ """
+ prev_data = driver.PolicyManager.get_rules(moon_user_id=moon_user_id, policy_id=uuid, rule_id=rule_id)[rule_id]
+ subject, object_, *action = Rules._get_data_name(moon_user_id, prev_data['rule'], prev_data['policy_id'])
+ prev_inst = prev_data['instructions'][0]['decision']
+
+ data = driver.PolicyManager.update_rule(moon_user_id=moon_user_id, rule_id=rule_id, value=body)
+
+ new_inst = data[rule_id]['instructions'][0]['decision']
+ LOGGER.info(f"The user <{moon_user_id}> updated the rule <{subject}, {object_}, {action}> from {prev_inst} to {new_inst}")
+
+ slaves = slave_class.Slaves.get().get("slaves")
+ invalidate_rules_in_slaves(slaves=slaves, policy_id=uuid, rule_id=rule_id)
+
+ return {"rules": data}
+
+ @staticmethod
+ @hug.local()
+ @hug.delete("/policies/{uuid}/rules/{rule_id}", requires=api_key_authentication)
+ def delete(uuid: hug.types.text, rule_id: hug.types.text, moon_user_id: hug.directives.user = None):
"""Delete one rule linked to a specific sub meta rule
:param uuid: policy ID
:param rule_id: rule ID
- :param user_id: user ID who do the request
+ :param moon_user_id: user ID who do the request
:return: { "result": true }
:internal_api: delete_rule
"""
+ prev_data = driver.PolicyManager.get_rules(moon_user_id=moon_user_id, policy_id=uuid, rule_id=rule_id)[rule_id]
+ subject, object_, *action = Rules._get_data_name(moon_user_id, prev_data['rule'], prev_data['policy_id'])
+ prev_inst = prev_data['instructions'][0]['decision']
+
+ driver.PolicyManager.delete_rule(moon_user_id=moon_user_id, policy_id=uuid, rule_id=rule_id)
- data = PolicyManager.delete_rule(
- user_id=user_id, policy_id=uuid, rule_id=rule_id)
+ LOGGER.info(f"The user <{moon_user_id}> deleted the rule <{subject}, {object_}, {action}: {prev_inst}>")
+
+ slaves = slave_class.Slaves.get().get("slaves")
+ invalidate_rules_in_slaves(slaves=slaves, policy_id=uuid, rule_id=rule_id)
return {"result": True}
+
+
+RulesAPI = hug.API(name='rules', doc=Rules.__doc__)
+db_conf = configuration.get_configuration(key='management')
+init_db(db_conf.get("token_file"))
+
+
+@hug.object(name='rules', version='1.0.0', api=RulesAPI)
+class RulesCLI(object):
+ """An example of command like calls via an Object"""
+
+ __global_data = None
+
+ @staticmethod
+ def get_data_name(rule_data, policy_id):
+ if not RulesCLI.__global_data:
+ RulesCLI.__global_data = data.SubjectDataCLI.list(policy_id).get("subject_data") + \
+ data.ObjectDataCLI.list(policy_id).get("object_data") + \
+ data.ActionDataCLI.list(policy_id).get("action_data")
+ _rule_names = list()
+ for rule_id in rule_data:
+ for _data in RulesCLI.__global_data:
+ if rule_id in _data.get("data"):
+ _rule_names.append(_data.get("data")[rule_id].get("name"))
+ break
+ else:
+ _rule_names.append(rule_id)
+ return _rule_names
+
+ @staticmethod
+ def get_data_id(rule_data, policy_id):
+ _global_data = data.SubjectDataCLI.list(policy_id).get("subject_data") + \
+ data.ObjectDataCLI.list(policy_id).get("object_data") + \
+ data.ActionDataCLI.list(policy_id).get("action_data")
+ _rule_ids = list()
+ for rule_id_or_name in rule_data:
+ _id = None
+ for _data in _global_data:
+ if rule_id_or_name in _data.get("data"):
+ _id = _data.get("data")[rule_id_or_name].get("name")
+ break
+ else:
+ for _data_key in _data.get("data"):
+ if _data.get("data")[_data_key]['name'] == rule_id_or_name:
+ _id = _data_key
+ break
+ if _id:
+ _rule_ids.append(_id)
+ break
+ else:
+ raise Exception("Cannot find data for {}".format(rule_id_or_name))
+ return _rule_ids
+
+ @staticmethod
+ @hug.object.cli
+ def list(policy_name_or_id, human: bool = False, instructions: bool = False):
+ db_conf = configuration.get_configuration(key='management')
+ manager_api_key = connect_from_env()
+ policy_id = list(policy.PoliciesCLI.list(policy_name_or_id).get("policies").keys())[0]
+ _rules = requests.get("{}/policies/{}/rules".format(db_conf.get("url"), policy_id),
+ headers={"x-api-key": manager_api_key}
+ )
+ if _rules.status_code == 200:
+ if human:
+ for value in _rules.json().get("rules", {}).get("rules"):
+ if value.get("enabled"):
+ _rule_names = RulesCLI.get_data_name(value.get("rule"), policy_id)
+ output = value.get("id") + " | "
+ output += "{:30}".format(" ".join(_rule_names))
+ if instructions:
+ output += " " + json.dumps(value.get("instructions"))
+ print(output)
+ else:
+ return _rules.json()
+ else:
+ raise Exception("Got a {} response ({})".format(_rules.status_code, _rules.text))
+
+ @staticmethod
+ @hug.object.cli
+ def add(policy_name_or_id, meta_rule_id_or_name, rule_items,
+ instructions: hug.types.one_of(("grant", "deny")) = None, enabled: bool = True):
+ if not instructions:
+ instructions = [{'decision': 'grant'}]
+ else:
+ instructions = [{'decision': instructions}]
+ rules_list = []
+ for item in rule_items.split(","):
+ rules_list.append(item.strip())
+ db_conf = configuration.get_configuration(key='management')
+ manager_api_key = connect_from_env()
+ policy_id = list(policy.PoliciesCLI.list(policy_name_or_id).get("policies").keys())[0]
+ meta_rule_id = list(meta_rules.MetaRulesCLI.list(meta_rule_id_or_name).
+ get("meta_rules").keys())[0]
+
+ _rules = requests.post("{}/policies/{}/rules".format(db_conf.get("url"), policy_id),
+ headers={"x-api-key": manager_api_key},
+ json={
+ "meta_rule_id": meta_rule_id,
+ "rule": RulesCLI.get_data_id(rules_list, policy_id),
+ "instructions": instructions,
+ "enabled": enabled
+ })
+ if _rules.status_code == 200:
+ return _rules.json()
+ else:
+ raise Exception("Got a {} response ({})".format(_rules.status_code, _rules.text))
+
+ @staticmethod
+ @hug.object.cli
+ def update(policy_name_or_id, rule_id, instructions: hug.types.one_of(('grant', 'deny'))):
+ instructions = [{'decision': instructions}]
+ db_conf = configuration.get_configuration(key='management')
+ manager_api_key = connect_from_env()
+ policy_id = list(policy.PoliciesCLI.list(policy_name_or_id).get("policies").keys())[0]
+
+ _rules = requests.patch("{}/policies/{}/rules/{}".format(db_conf.get("url"), policy_id, rule_id),
+ headers={"x-api-key": manager_api_key},
+ json={
+ "instructions": instructions
+ })
+ if _rules.status_code == 200:
+ return _rules.json()
+ else:
+ raise Exception("Got a {} response ({})".format(_rules.status_code, _rules.text))
+
+ @staticmethod
+ @hug.object.cli
+ def delete(policy_name_or_id, rule_id):
+ db_conf = configuration.get_configuration(key='management')
+ manager_api_key = connect_from_env()
+ policy_id = list(policy.PoliciesCLI.list(policy_name_or_id).get("policies").keys())[0]
+
+ _rules = requests.delete("{}/policies/{}/rules/{}".format(
+ db_conf.get("url"), policy_id, rule_id),
+ headers={"x-api-key": manager_api_key})
+ if _rules.status_code == 200:
+ return _rules.json()
+ else:
+ raise Exception("Got a {} response ({})".format(_rules.status_code, _rules.text))