From 1100c66ce03a059ebe7ece9734e799b49b3a5a9e Mon Sep 17 00:00:00 2001 From: WuKong Date: Sat, 23 Dec 2017 21:49:35 +0100 Subject: moonv4 cleanup Change-Id: Icef927f3236d985ac13ff7376f6ce6314b2b39b0 Signed-off-by: WuKong --- moon_manager/Dockerfile | 12 + moon_manager/LICENSE | 202 ++++++++++ moon_manager/MANIFEST.in | 9 + moon_manager/README.rst | 9 + moon_manager/moon_manager/__init__.py | 6 + moon_manager/moon_manager/__main__.py | 4 + moon_manager/moon_manager/api/__init__.py | 0 moon_manager/moon_manager/api/assignments.py | 334 +++++++++++++++ moon_manager/moon_manager/api/containers.py | 178 ++++++++ moon_manager/moon_manager/api/data.py | 335 +++++++++++++++ moon_manager/moon_manager/api/generic.py | 131 ++++++ moon_manager/moon_manager/api/meta_data.py | 267 ++++++++++++ moon_manager/moon_manager/api/meta_rules.py | 164 ++++++++ moon_manager/moon_manager/api/models.py | 127 ++++++ moon_manager/moon_manager/api/pdp.py | 181 +++++++++ moon_manager/moon_manager/api/perimeter.py | 447 +++++++++++++++++++++ moon_manager/moon_manager/api/policies.py | 132 ++++++ moon_manager/moon_manager/api/rules.py | 140 +++++++ moon_manager/moon_manager/http_server.py | 157 ++++++++ moon_manager/moon_manager/server.py | 38 ++ moon_manager/requirements.txt | 6 + moon_manager/setup.py | 47 +++ moon_manager/tests/unit_python/__init__.py | 0 moon_manager/tests/unit_python/api/__init__.py | 0 .../tests/unit_python/api/test_perimeter.py | 59 +++ moon_manager/tests/unit_python/conftest.py | 195 +++++++++ moon_manager/tests/unit_python/requirements.txt | 5 + 27 files changed, 3185 insertions(+) create mode 100644 moon_manager/Dockerfile create mode 100644 moon_manager/LICENSE create mode 100644 moon_manager/MANIFEST.in create mode 100644 moon_manager/README.rst create mode 100644 moon_manager/moon_manager/__init__.py create mode 100644 moon_manager/moon_manager/__main__.py create mode 100644 moon_manager/moon_manager/api/__init__.py create mode 100644 moon_manager/moon_manager/api/assignments.py create mode 100644 moon_manager/moon_manager/api/containers.py create mode 100644 moon_manager/moon_manager/api/data.py create mode 100644 moon_manager/moon_manager/api/generic.py create mode 100644 moon_manager/moon_manager/api/meta_data.py create mode 100644 moon_manager/moon_manager/api/meta_rules.py create mode 100644 moon_manager/moon_manager/api/models.py create mode 100644 moon_manager/moon_manager/api/pdp.py create mode 100644 moon_manager/moon_manager/api/perimeter.py create mode 100644 moon_manager/moon_manager/api/policies.py create mode 100644 moon_manager/moon_manager/api/rules.py create mode 100644 moon_manager/moon_manager/http_server.py create mode 100644 moon_manager/moon_manager/server.py create mode 100644 moon_manager/requirements.txt create mode 100644 moon_manager/setup.py create mode 100644 moon_manager/tests/unit_python/__init__.py create mode 100644 moon_manager/tests/unit_python/api/__init__.py create mode 100644 moon_manager/tests/unit_python/api/test_perimeter.py create mode 100644 moon_manager/tests/unit_python/conftest.py create mode 100644 moon_manager/tests/unit_python/requirements.txt (limited to 'moon_manager') diff --git a/moon_manager/Dockerfile b/moon_manager/Dockerfile new file mode 100644 index 00000000..873e3aa2 --- /dev/null +++ b/moon_manager/Dockerfile @@ -0,0 +1,12 @@ +FROM ubuntu:latest + +RUN apt update && apt install python3.5 python3-pip -y +RUN pip3 install pip --upgrade + +ADD . /root +WORKDIR /root/ +RUN pip3 install -r requirements.txt +#RUN pip3 install /root/dist/* --upgrade +RUN pip3 install . + +CMD ["python3", "-m", "moon_manager"] \ No newline at end of file diff --git a/moon_manager/LICENSE b/moon_manager/LICENSE new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/moon_manager/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/moon_manager/MANIFEST.in b/moon_manager/MANIFEST.in new file mode 100644 index 00000000..1f674d50 --- /dev/null +++ b/moon_manager/MANIFEST.in @@ -0,0 +1,9 @@ +# 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'. + +include README.rst +include LICENSE +include setup.py +include requirements.txt diff --git a/moon_manager/README.rst b/moon_manager/README.rst new file mode 100644 index 00000000..ded4e99a --- /dev/null +++ b/moon_manager/README.rst @@ -0,0 +1,9 @@ +Core module for the Moon project +================================ + +This package contains the core module for the Moon project +It is designed to provide authorization features to all OpenStack components. + +For any other information, refer to the parent project: + + https://git.opnfv.org/moon diff --git a/moon_manager/moon_manager/__init__.py b/moon_manager/moon_manager/__init__.py new file mode 100644 index 00000000..903c6518 --- /dev/null +++ b/moon_manager/moon_manager/__init__.py @@ -0,0 +1,6 @@ +# 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'. + +__version__ = "0.1.0" diff --git a/moon_manager/moon_manager/__main__.py b/moon_manager/moon_manager/__main__.py new file mode 100644 index 00000000..7d97f003 --- /dev/null +++ b/moon_manager/moon_manager/__main__.py @@ -0,0 +1,4 @@ +from moon_manager.server import main + +server = main() +server.run() diff --git a/moon_manager/moon_manager/api/__init__.py b/moon_manager/moon_manager/api/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/moon_manager/moon_manager/api/assignments.py b/moon_manager/moon_manager/api/assignments.py new file mode 100644 index 00000000..c3ac45c8 --- /dev/null +++ b/moon_manager/moon_manager/api/assignments.py @@ -0,0 +1,334 @@ +# 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'. +""" +Assignments allow to connect data with elements of perimeter + +""" + +from flask import request +from flask_restful import Resource +from oslo_log import log as logging +from python_moonutilities.security_functions import check_auth +from python_moondb.core import PolicyManager + +__version__ = "0.2.0" + +LOG = logging.getLogger("moon.manager.api." + __name__) + + +class SubjectAssignments(Resource): + """ + Endpoint for subject assignment requests + """ + + __urls__ = ( + "/policies//subject_assignments", + "/policies//subject_assignments/", + "/policies//subject_assignments/", + "/policies//subject_assignments//", + "/policies//subject_assignments///", + ) + + @check_auth + def get(self, uuid=None, perimeter_id=None, category_id=None, data_id=None, user_id=None): + """Retrieve all subject assignments or a specific one for a given policy + + :param uuid: uuid of the policy + :param perimeter_id: uuid of the subject + :param category_id: uuid of the subject category + :param data_id: uuid of the subject scope + :param user_id: user ID who do the request + :return: { + "subject_data_id": { + "policy_id": "ID of the policy", + "subject_id": "ID of the subject", + "category_id": "ID of the category", + "assignments": "Assignments list (list of data_id)", + } + } + :internal_api: get_subject_assignments + """ + # return call(ctx={"id": uuid, "method": "get_subject_assignments", "perimeter_id": perimeter_id, "category_id": category_id, "user_id": user_id}, + # args={"data_id": data_id}) + try: + # if "perimeter_name" in ctx: + # ctx["perimeter_id"] = self.__get_subject_id(ctx, ctx['perimeter_name']) + data = PolicyManager.get_subject_assignments(user_id=user_id, policy_id=uuid, + subject_id=perimeter_id, category_id=category_id) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"subject_assignments": data} + + @check_auth + def post(self, uuid=None, perimeter_id=None, category_id=None, data_id=None, user_id=None): + """Create a subject assignment. + + :param uuid: uuid of the policy + :param perimeter_id: uuid of the subject (not used here) + :param category_id: uuid of the subject category (not used here) + :param data_id: uuid of the subject scope (not used here) + :param user_id: user ID who do the request + :request body: { + "id": "UUID of the subject", + "category_id": "UUID of the category" + "data_id": "UUID of the scope" + } + :return: { + "subject_data_id": { + "policy_id": "ID of the policy", + "subject_id": "ID of the subject", + "category_id": "ID of the category", + "assignments": "Assignments list (list of data_id)", + } + } + :internal_api: update_subject_assignment + """ + try: + data_id = request.json.get("data_id") + category_id = request.json.get("category_id") + perimeter_id = request.json.get("id") + data = PolicyManager.add_subject_assignment(user_id=user_id, policy_id=uuid, + subject_id=perimeter_id, category_id=category_id, + data_id=data_id) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"subject_assignments": data} + + @check_auth + def delete(self, uuid=None, perimeter_id=None, category_id=None, data_id=None, user_id=None): + """Delete a subject assignment for a given policy + + :param uuid: uuid of the policy + :param perimeter_id: uuid of the subject + :param category_id: uuid of the subject category + :param data_id: uuid of the subject scope + :param user_id: user ID who do the request + :return: { + "result": "True or False", + "message": "optional message" + } + :internal_api: delete_subject_assignment + """ + try: + data = PolicyManager.delete_subject_assignment(user_id=user_id, policy_id=uuid, + subject_id=perimeter_id, category_id=category_id, + data_id=data_id) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"result": True} + + +class ObjectAssignments(Resource): + """ + Endpoint for object assignment requests + """ + + __urls__ = ( + "/policies//object_assignments", + "/policies//object_assignments/", + "/policies//object_assignments/", + "/policies//object_assignments//", + "/policies//object_assignments///", + ) + + @check_auth + def get(self, uuid=None, perimeter_id=None, category_id=None, data_id=None, user_id=None): + """Retrieve all object assignment or a specific one for a given policy + + :param uuid: uuid of the policy + :param perimeter_id: uuid of the object + :param category_id: uuid of the object category + :param data_id: uuid of the object scope + :param user_id: user ID who do the request + :return: { + "object_data_id": { + "policy_id": "ID of the policy", + "object_id": "ID of the object", + "category_id": "ID of the category", + "assignments": "Assignments list (list of data_id)", + } + } + :internal_api: get_object_assignments + """ + try: + data = PolicyManager.get_object_assignments(user_id=user_id, policy_id=uuid, + object_id=perimeter_id, category_id=category_id) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"object_assignments": data} + + @check_auth + def post(self, uuid=None, perimeter_id=None, category_id=None, data_id=None, user_id=None): + """Create an object assignment. + + :param uuid: uuid of the policy + :param perimeter_id: uuid of the object (not used here) + :param category_id: uuid of the object category (not used here) + :param data_id: uuid of the object scope (not used here) + :param user_id: user ID who do the request + :request body: { + "id": "UUID of the action", + "category_id": "UUID of the category" + "data_id": "UUID of the scope" + } + :return: { + "object_data_id": { + "policy_id": "ID of the policy", + "object_id": "ID of the object", + "category_id": "ID of the category", + "assignments": "Assignments list (list of data_id)", + } + } + :internal_api: update_object_assignment + """ + try: + data_id = request.json.get("data_id") + category_id = request.json.get("category_id") + perimeter_id = request.json.get("id") + data = PolicyManager.add_object_assignment(user_id=user_id, policy_id=uuid, + object_id=perimeter_id, category_id=category_id, + data_id=data_id) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"object_assignments": data} + + @check_auth + def delete(self, uuid=None, perimeter_id=None, category_id=None, data_id=None, user_id=None): + """Delete a object assignment for a given policy + + :param uuid: uuid of the policy + :param perimeter_id: uuid of the object + :param category_id: uuid of the object category + :param data_id: uuid of the object scope + :param user_id: user ID who do the request + :return: { + "result": "True or False", + "message": "optional message" + } + :internal_api: delete_object_assignment + """ + try: + data = PolicyManager.delete_object_assignment(user_id=user_id, policy_id=uuid, + object_id=perimeter_id, category_id=category_id, + data_id=data_id) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"result": True} + + +class ActionAssignments(Resource): + """ + Endpoint for action assignment requests + """ + + __urls__ = ( + "/policies//action_assignments", + "/policies//action_assignments/", + "/policies//action_assignments/", + "/policies//action_assignments//", + "/policies//action_assignments///", + ) + + @check_auth + def get(self, uuid=None, perimeter_id=None, category_id=None, data_id=None, user_id=None): + """Retrieve all action assignment or a specific one for a given policy + + :param uuid: uuid of the policy + :param perimeter_id: uuid of the action + :param category_id: uuid of the action category + :param data_id: uuid of the action scope + :param user_id: user ID who do the request + :return: { + "action_data_id": { + "policy_id": "ID of the policy", + "object_id": "ID of the action", + "category_id": "ID of the category", + "assignments": "Assignments list (list of data_id)", + } + } + :internal_api: get_action_assignments + """ + try: + data = PolicyManager.get_action_assignments(user_id=user_id, policy_id=uuid, + action_id=perimeter_id, category_id=category_id) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"action_assignments": data} + + @check_auth + def post(self, uuid=None, perimeter_id=None, category_id=None, data_id=None, user_id=None): + """Create an action assignment. + + :param uuid: uuid of the policy + :param perimeter_id: uuid of the action (not used here) + :param category_id: uuid of the action category (not used here) + :param data_id: uuid of the action scope (not used here) + :param user_id: user ID who do the request + :request body: { + "id": "UUID of the action", + "category_id": "UUID of the category", + "data_id": "UUID of the scope" + } + :return: { + "action_data_id": { + "policy_id": "ID of the policy", + "object_id": "ID of the action", + "category_id": "ID of the category", + "assignments": "Assignments list (list of data_id)", + } + } + :internal_api: update_action_assignment + """ + try: + data_id = request.json.get("data_id") + category_id = request.json.get("category_id") + perimeter_id = request.json.get("id") + data = PolicyManager.add_action_assignment(user_id=user_id, policy_id=uuid, + action_id=perimeter_id, category_id=category_id, + data_id=data_id) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"action_assignments": data} + + @check_auth + def delete(self, uuid=None, perimeter_id=None, category_id=None, data_id=None, user_id=None): + """Delete a action assignment for a given policy + + :param uuid: uuid of the policy + :param perimeter_id: uuid of the action + :param category_id: uuid of the action category + :param data_id: uuid of the action scope + :param user_id: user ID who do the request + :return: { + "result": "True or False", + "message": "optional message" + } + :internal_api: delete_action_assignment + """ + try: + data = PolicyManager.delete_action_assignment(user_id=user_id, policy_id=uuid, + action_id=perimeter_id, category_id=category_id, + data_id=data_id) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"result": True} diff --git a/moon_manager/moon_manager/api/containers.py b/moon_manager/moon_manager/api/containers.py new file mode 100644 index 00000000..6dc50ea5 --- /dev/null +++ b/moon_manager/moon_manager/api/containers.py @@ -0,0 +1,178 @@ +# 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'. +""" +PDP are Policy Decision Point. + +""" + +import copy +from docker import Client +from flask import request +from flask_restful import Resource +from oslo_log import log as logging +from python_moonutilities.security_functions import check_auth +from python_moonutilities import configuration + +docker_conf = configuration.get_configuration("docker")['docker'] +docker = Client(base_url=docker_conf['url']) + +__version__ = "0.1.0" + +LOG = logging.getLogger("moon.manager.api." + __name__) + + +class Container(Resource): + """ + Endpoint for container requests + """ + + __urls__ = ( + "/containers", + "/containers/", + "/containers/", + "/containers//", + ) + + def __init__(self): + self.containers = {} + self.update() + + def update(self): + for _container in docker.containers(): + if _container['Id'] not in self.containers: + self.containers[_container['Id']] = { + "name": _container["Names"], + "port": _container["Ports"], + } + + @check_auth + def get(self, uuid=None, user_id=None): + """Retrieve all containers + + :param uuid: uuid of the container + :param user_id: user ID who do the request + :return: { + "containers": { + "da0fd80fc1dc146e1b...a2e07d240cde09f0a": { + "name": [ + "/wrapper" + ], + "port": [ + { + "PrivatePort": 8080, + "Type": "tcp", + "IP": "0.0.0.0", + "PublicPort": 8080 + } + ] + }, + } + } + :internal_api: get_containers + """ + # try: + # data = [{"name": item["Names"], "port": item["Ports"], } for item in docker.containers()] + # except Exception as e: + # LOG.error(e, exc_info=True) + # return {"result": False, + # "error": str(e)} + return {"containers": self.containers} + + @check_auth + def post(self, uuid=None, user_id=None): + """Add a new container. + + :param uuid: uuid of the pdp (not used here) + :param user_id: user ID who do the request + :request body: { + "id": "id of the new container", + "name": "name of the new container", + "hostname": "hostname of the new container", + "port": { + "PrivatePort": 8080, + "Type": "tcp", + "IP": "0.0.0.0", + "PublicPort": 8080 + }, + "keystone_project_id": "keystone_project_id1", + "pdp_id": "PDP UUID", + "container_name": "wukongsun/moon_authz:v4.1" + } + :return: { + "containers": { + "da0fd80fc1dc146e1b...a2e07d240cde09f0a": { + "name": [ + "/wrapper" + ], + "port": [ + { + "PrivatePort": 8080, + "Type": "tcp", + "IP": "0.0.0.0", + "PublicPort": 8080 + } + ] + }, + } + } + :internal_api: add_container + """ + try: + self.update() + self.containers[request.json.get('id')] = copy.deepcopy(request.json) + LOG.info("Added a new container {}".format(request.json.get('name'))) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"containers": self.containers} + + @check_auth + def delete(self, uuid=None, user_id=None): + """Delete a pdp + + :param uuid: uuid of the pdp to delete + :param user_id: user ID who do the request + :return: { + "result": "True or False", + "message": "optional message" + } + :internal_api: delete_pdp + """ + # try: + # data = PDPManager.delete_pdp(user_id=user_id, pdp_id=uuid) + # except Exception as e: + # LOG.error(e, exc_info=True) + # return {"result": False, + # "error": str(e)} + # return {"result": True} + raise NotImplementedError + + @check_auth + def patch(self, uuid=None, user_id=None): + """Update a pdp + + :param uuid: uuid of the pdp to update + :param user_id: user ID who do the request + :return: { + "pdp_id1": { + "name": "...", + "security_pipeline": [...], + "keystone_project_id": "keystone_project_id1", + "description": "...", + } + } + :internal_api: update_pdp + """ + # try: + # data = PDPManager.update_pdp(user_id=user_id, pdp_id=uuid, value=request.json) + # add_container(uuid=uuid, pipeline=data[uuid]['security_pipeline']) + # except Exception as e: + # LOG.error(e, exc_info=True) + # return {"result": False, + # "error": str(e)} + # return {"pdps": data} + raise NotImplementedError + diff --git a/moon_manager/moon_manager/api/data.py b/moon_manager/moon_manager/api/data.py new file mode 100644 index 00000000..61fe92bf --- /dev/null +++ b/moon_manager/moon_manager/api/data.py @@ -0,0 +1,335 @@ +# 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'. +""" +Data are elements used to create rules + +""" + +from flask import request +from flask_restful import Resource +from oslo_log import log as logging +from python_moonutilities.security_functions import check_auth +from python_moondb.core import PolicyManager + +__version__ = "0.2.0" + +LOG = logging.getLogger("moon.manager.api." + __name__) + + +class SubjectData(Resource): + """ + Endpoint for subject data requests + """ + + __urls__ = ( + "/policies//subject_data", + "/policies//subject_data/", + "/policies//subject_data/", + "/policies//subject_data//" + "", + ) + + @check_auth + def get(self, uuid=None, category_id=None, data_id=None, user_id=None): + """Retrieve all subject categories or a specific one if sid is given + for a given policy + + :param uuid: uuid of the policy + :param category_id: uuid of the subject category + :param data_id: uuid of the subject data + :param user_id: user ID who do the request + :return: [{ + "policy_id": "policy_id1", + "category_id": "category_id1", + "data": { + "subject_data_id": { + "name": "name of the data", + "description": "description of the data" + } + } + }] + :internal_api: get_subject_data + """ + try: + data = PolicyManager.get_subject_data(user_id=user_id, + policy_id=uuid, + category_id=category_id, + data_id=data_id) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"subject_data": data} + + @check_auth + def post(self, uuid=None, category_id=None, data_id=None, user_id=None): + """Create or update a subject. + + :param uuid: uuid of the policy + :param category_id: uuid of the subject category + :param data_id: uuid of the subject data + :param user_id: user ID who do the request + :request body: { + "name": "name of the data", + "description": "description of the data" + } + :return: { + "policy_id": "policy_id1", + "category_id": "category_id1", + "data": { + "subject_data_id": { + "name": "name of the data", + "description": "description of the data" + } + } + } + :internal_api: add_subject_data + """ + try: + data = PolicyManager.set_subject_data(user_id=user_id, + policy_id=uuid, + category_id=category_id, + value=request.json) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"subject_data": data} + + @check_auth + def delete(self, uuid=None, category_id=None, data_id=None, user_id=None): + """Delete a subject for a given policy + + :param uuid: uuid of the policy + :param category_id: uuid of the subject category + :param data_id: uuid of the subject data + :param user_id: user ID who do the request + :return: [{ + "result": "True or False", + "message": "optional message" + }] + :internal_api: delete_subject_data + """ + try: + data = PolicyManager.delete_subject_data(user_id=user_id, + policy_id=uuid, + data_id=data_id) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"result": True} + + +class ObjectData(Resource): + """ + Endpoint for object data requests + """ + + __urls__ = ( + "/policies//object_data", + "/policies//object_data/", + "/policies//object_data/", + "/policies//object_data//" + "", + ) + + @check_auth + def get(self, uuid=None, category_id=None, data_id=None, user_id=None): + """Retrieve all object categories or a specific one if sid is given + for a given policy + + :param uuid: uuid of the policy + :param category_id: uuid of the object category + :param data_id: uuid of the object data + :param user_id: user ID who do the request + :return: [{ + "policy_id": "policy_id1", + "category_id": "category_id1", + "data": { + "object_data_id": { + "name": "name of the data", + "description": "description of the data" + } + } + }] + :internal_api: get_object_data + """ + try: + data = PolicyManager.get_object_data(user_id=user_id, + policy_id=uuid, + category_id=category_id, + data_id=data_id) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"object_data": data} + + @check_auth + def post(self, uuid=None, category_id=None, data_id=None, user_id=None): + """Create or update a object. + + :param uuid: uuid of the policy + :param category_id: uuid of the object category + :param data_id: uuid of the object data + :param user_id: user ID who do the request + :request body: { + "name": "name of the data", + "description": "description of the data" + } + :return: { + "policy_id": "policy_id1", + "category_id": "category_id1", + "data": { + "object_data_id": { + "name": "name of the data", + "description": "description of the data" + } + } + } + :internal_api: add_object_data + """ + try: + data = PolicyManager.add_object_data(user_id=user_id, + policy_id=uuid, + category_id=category_id, + value=request.json) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"object_data": data} + + @check_auth + def delete(self, uuid=None, category_id=None, data_id=None, user_id=None): + """Delete a object for a given policy + + :param uuid: uuid of the policy + :param category_id: uuid of the object category + :param data_id: uuid of the object data + :param user_id: user ID who do the request + :return: { + "result": "True or False", + "message": "optional message" + } + :internal_api: delete_object_data + """ + try: + data = PolicyManager.delete_object_data(user_id=user_id, + policy_id=uuid, + data_id=data_id) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"result": True} + + +class ActionData(Resource): + """ + Endpoint for action data requests + """ + + __urls__ = ( + "/policies//action_data", + "/policies//action_data/", + "/policies//action_data/", + "/policies//action_data//" + "", + ) + + @check_auth + def get(self, uuid=None, category_id=None, data_id=None, user_id=None): + """Retrieve all action categories or a specific one if sid is given + for a given policy + + :param uuid: uuid of the policy + :param category_id: uuid of the action category + :param data_id: uuid of the action data + :param user_id: user ID who do the request + :return: [{ + "policy_id": "policy_id1", + "category_id": "category_id1", + "data": { + "action_data_id": { + "name": "name of the data", + "description": "description of the data" + } + } + }] + :internal_api: get_action_data + """ + try: + data = PolicyManager.get_action_data(user_id=user_id, + policy_id=uuid, + category_id=category_id, + data_id=data_id) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"action_data": data} + + @check_auth + def post(self, uuid=None, category_id=None, data_id=None, user_id=None): + """Create or update a action. + + :param uuid: uuid of the policy + :param category_id: uuid of the action category + :param data_id: uuid of the action data + :param user_id: user ID who do the request + :request body: { + "name": "name of the data", + "description": "description of the data" + } + :return: { + "policy_id": "policy_id1", + "category_id": "category_id1", + "data": { + "action_data_id": { + "name": "name of the data", + "description": "description of the data" + } + } + } + :internal_api: add_action_data + """ + try: + data = PolicyManager.add_action_data(user_id=user_id, + policy_id=uuid, + category_id=category_id, + value=request.json) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"action_data": data} + + @check_auth + def delete(self, uuid=None, category_id=None, data_id=None, user_id=None): + """Delete a action for a given policy + + :param uuid: uuid of the policy + :param category_id: uuid of the action category + :param data_id: uuid of the action data + :param user_id: user ID who do the request + :return: { + "result": "True or False", + "message": "optional message" + } + :internal_api: delete_action_data + """ + try: + data = PolicyManager.delete_action_data(user_id=user_id, + policy_id=uuid, + data_id=data_id) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"result": True} + + diff --git a/moon_manager/moon_manager/api/generic.py b/moon_manager/moon_manager/api/generic.py new file mode 100644 index 00000000..bd7dcdac --- /dev/null +++ b/moon_manager/moon_manager/api/generic.py @@ -0,0 +1,131 @@ +# 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'. +""" +Those API are helping API used to manage the Moon platform. +""" + +from flask_restful import Resource, request +from oslo_log import log as logging +import moon_manager.api +from python_moonutilities.security_functions import check_auth + +__version__ = "0.1.0" + +LOG = logging.getLogger("moon.manager.api." + __name__) + + +class Status(Resource): + """ + Endpoint for status requests + """ + + __urls__ = ("/status", "/status/", "/status/") + + def get(self, component_id=None): + """Retrieve status of all components + + :return: { + "orchestrator": { + "status": "Running" + }, + "security_router": { + "status": "Running" + } + } + """ + raise NotImplemented + + +class Logs(Resource): + """ + Endpoint for logs requests + """ + + __urls__ = ("/logs", "/logs/", "/logs/") + + def get(self, component_id=None): + """Get logs from the Moon platform + + :param component_id: the ID of the component your are looking for (optional) + :return: [ + "2015-04-15-13:45:20 + "2015-04-15-13:45:21 + "2015-04-15-13:45:22 + "2015-04-15-13:45:23 + ] + """ + filter_str = request.args.get('filter', '') + from_str = request.args.get('from', '') + to_str = request.args.get('to', '') + event_number = request.args.get('event_number', '') + try: + event_number = int(event_number) + except ValueError: + event_number = None + args = dict() + args["filter"] = filter_str + args["from"] = from_str + args["to"] = to_str + args["event_number"] = event_number + + raise NotImplemented + + +class API(Resource): + """ + Endpoint for API requests + """ + + __urls__ = ( + "/api", + "/api/", + "/api/", + "/api//", + "/api//") + + @check_auth + def get(self, group_id="", endpoint_id="", user_id=""): + """Retrieve all API endpoints or a specific endpoint if endpoint_id is given + + :param group_id: the name of one existing group (ie generic, ...) + :param endpoint_id: the name of one existing component (ie Logs, Status, ...) + :return: { + "group_name": { + "endpoint_name": { + "description": "a description", + "methods": { + "get": "description of the HTTP method" + }, + "urls": ('/api', '/api/', '/api/') + } + } + """ + __methods = ("get", "post", "put", "delete", "options", "patch") + api_list = filter(lambda x: "__" not in x, dir(moon_manager.api)) + api_desc = dict() + for api_name in api_list: + api_desc[api_name] = {} + group_api_obj = eval("moon_manager.api.{}".format(api_name)) + api_desc[api_name]["description"] = group_api_obj.__doc__ + if "__version__" in dir(group_api_obj): + api_desc[api_name]["version"] = group_api_obj.__version__ + object_list = list(filter(lambda x: "__" not in x, dir(group_api_obj))) + for obj in map(lambda x: eval("moon_manager.api.{}.{}".format(api_name, x)), object_list): + if "__urls__" in dir(obj): + api_desc[api_name][obj.__name__] = dict() + api_desc[api_name][obj.__name__]["urls"] = obj.__urls__ + api_desc[api_name][obj.__name__]["methods"] = dict() + for _method in filter(lambda x: x in __methods, dir(obj)): + docstring = eval("moon_manager.api.{}.{}.{}.__doc__".format(api_name, obj.__name__, _method)) + api_desc[api_name][obj.__name__]["methods"][_method] = docstring + api_desc[api_name][obj.__name__]["description"] = str(obj.__doc__) + if group_id in api_desc: + if endpoint_id in api_desc[group_id]: + return {group_id: {endpoint_id: api_desc[group_id][endpoint_id]}} + elif len(endpoint_id) > 0: + LOG.error("Unknown endpoint_id {}".format(endpoint_id)) + return {"error": "Unknown endpoint_id {}".format(endpoint_id)} + return {group_id: api_desc[group_id]} + return api_desc diff --git a/moon_manager/moon_manager/api/meta_data.py b/moon_manager/moon_manager/api/meta_data.py new file mode 100644 index 00000000..9dc04cc7 --- /dev/null +++ b/moon_manager/moon_manager/api/meta_data.py @@ -0,0 +1,267 @@ +# 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'. +""" +Meta Data are elements used to create Meta data (skeleton of security policies) + +""" + +from flask import request +from flask_restful import Resource +from oslo_log import log as logging +from python_moonutilities.security_functions import check_auth +from python_moondb.core import ModelManager + +__version__ = "0.2.0" + +LOG = logging.getLogger("moon.manager.api." + __name__) + + +class SubjectCategories(Resource): + """ + Endpoint for subject categories requests + """ + + __urls__ = ( + "/subject_categories", + "/subject_categories/", + "/subject_categories/", + ) + + @check_auth + def get(self, category_id=None, user_id=None): + """Retrieve all subject categories or a specific one + + :param category_id: uuid of the subject category + :param user_id: user ID who do the request + :return: { + "subject_category_id": { + "name": "name of the category", + "description": "description of the category" + } + } + :internal_api: get_subject_categories + """ + try: + data = ModelManager.get_subject_categories( + user_id=user_id, category_id=category_id) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"subject_categories": data} + + @check_auth + def post(self, category_id=None, user_id=None): + """Create or update a subject category. + + :param category_id: must not be used here + :param user_id: user ID who do the request + :request body: { + "name": "name of the category", + "description": "description of the category" + } + :return: { + "subject_category_id": { + "name": "name of the category", + "description": "description of the category" + } + } + :internal_api: add_subject_category + """ + try: + data = ModelManager.add_subject_category( + user_id=user_id, value=request.json) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"subject_categories": data} + + @check_auth + def delete(self, category_id=None, user_id=None): + """Delete a subject category + + :param category_id: uuid of the subject category to delete + :param user_id: user ID who do the request + :return: { + "result": "True or False", + "message": "optional message" + } + :internal_api: delete_subject_category + """ + try: + data = ModelManager.delete_subject_category( + user_id=user_id, category_id=category_id) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"result": True} + + +class ObjectCategories(Resource): + """ + Endpoint for object categories requests + """ + + __urls__ = ( + "/object_categories", + "/object_categories/", + "/object_categories/", + ) + + @check_auth + def get(self, category_id=None, user_id=None): + """Retrieve all object categories or a specific one + + :param category_id: uuid of the object category + :param user_id: user ID who do the request + :return: { + "object_category_id": { + "name": "name of the category", + "description": "description of the category" + } + } + :internal_api: get_object_categories + """ + try: + data = ModelManager.get_object_categories( + user_id=user_id, category_id=category_id) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"object_categories": data} + + @check_auth + def post(self, category_id=None, user_id=None): + """Create or update a object category. + + :param category_id: must not be used here + :param user_id: user ID who do the request + :request body: { + "name": "name of the category", + "description": "description of the category" + } + :return: { + "object_category_id": { + "name": "name of the category", + "description": "description of the category" + } + } + :internal_api: add_object_category + """ + try: + data = ModelManager.add_object_category( + user_id=user_id, value=request.json) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"object_categories": data} + + @check_auth + def delete(self, category_id=None, user_id=None): + """Delete an object category + + :param category_id: uuid of the object category to delete + :param user_id: user ID who do the request + :return: { + "result": "True or False", + "message": "optional message" + } + :internal_api: delete_object_category + """ + try: + data = ModelManager.delete_object_category( + user_id=user_id, category_id=category_id) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"result": True} + + +class ActionCategories(Resource): + """ + Endpoint for action categories requests + """ + + __urls__ = ( + "/action_categories", + "/action_categories/", + "/action_categories/", + ) + + @check_auth + def get(self, category_id=None, user_id=None): + """Retrieve all action categories or a specific one + + :param category_id: uuid of the action category + :param user_id: user ID who do the request + :return: { + "action_category_id": { + "name": "name of the category", + "description": "description of the category" + } + } + :internal_api: get_action_categories + """ + try: + data = ModelManager.get_action_categories( + user_id=user_id, category_id=category_id) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"action_categories": data} + + @check_auth + def post(self, category_id=None, user_id=None): + """Create or update an action category. + + :param category_id: must not be used here + :param user_id: user ID who do the request + :request body: { + "name": "name of the category", + "description": "description of the category" + } + :return: { + "action_category_id": { + "name": "name of the category", + "description": "description of the category" + } + } + :internal_api: add_action_category + """ + try: + data = ModelManager.add_action_category( + user_id=user_id, value=request.json) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"action_categories": data} + + @check_auth + def delete(self, category_id=None, user_id=None): + """Delete an action + + :param category_id: uuid of the action category to delete + :param user_id: user ID who do the request + :return: { + "result": "True or False", + "message": "optional message" + } + :internal_api: delete_action_category + """ + try: + data = ModelManager.delete_action_category( + user_id=user_id, category_id=category_id) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"result": True} diff --git a/moon_manager/moon_manager/api/meta_rules.py b/moon_manager/moon_manager/api/meta_rules.py new file mode 100644 index 00000000..ceba0ffb --- /dev/null +++ b/moon_manager/moon_manager/api/meta_rules.py @@ -0,0 +1,164 @@ +# 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'. +""" +Meta rules are skeleton for security policies + +""" + +from flask import request +from flask_restful import Resource +from oslo_log import log as logging +from python_moonutilities.security_functions import check_auth +from python_moondb.core import ModelManager + +__version__ = "0.1.0" + +LOG = logging.getLogger("moon.manager.api." + __name__) + + +class MetaRules(Resource): + """ + Endpoint for meta rules requests + """ + + __urls__ = ("/meta_rules", + "/meta_rules/", + "/meta_rules/", + "/meta_rules//") + + @check_auth + def get(self, meta_rule_id=None, user_id=None): + """Retrieve all sub meta rules + + :param meta_rule_id: Meta rule algorithm ID + :param user_id: user ID who do the request + :return: { + "meta_rules": { + "meta_rule_id1": { + "name": "name of the meta rule", + "algorithm": "name of the meta rule algorithm", + "subject_categories": ["subject_category_id1", + "subject_category_id2"], + "object_categories": ["object_category_id1"], + "action_categories": ["action_category_id1"] + }, + } + } + :internal_api: get_meta_rules + """ + try: + data = ModelManager.get_meta_rules( + user_id=user_id, meta_rule_id=meta_rule_id) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"meta_rules": data} + + @check_auth + def post(self, meta_rule_id=None, user_id=None): + """Add a meta rule + + :param meta_rule_id: Meta rule ID + :param user_id: user ID who do the request + :request body: post = { + "name": "name of the meta rule", + "subject_categories": ["subject_category_id1", + "subject_category_id2"], + "object_categories": ["object_category_id1"], + "action_categories": ["action_category_id1"] + } + :return: { + "meta_rules": { + "meta_rule_id1": { + "name": "name of the meta rule", + "subject_categories": ["subject_category_id1", + "subject_category_id2"], + "object_categories": ["object_category_id1"], + "action_categories": ["action_category_id1"] + }, + } + } + :internal_api: add_meta_rules + """ + try: + data = ModelManager.add_meta_rule( + user_id=user_id, meta_rule_id=None, value=request.json) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"meta_rules": data} + + @check_auth + def patch(self, meta_rule_id=None, user_id=None): + """Update a meta rule + + :param meta_rule_id: Meta rule ID + :param user_id: user ID who do the request + :request body: patch = { + "name": "name of the meta rule", + "subject_categories": ["subject_category_id1", + "subject_category_id2"], + "object_categories": ["object_category_id1"], + "action_categories": ["action_category_id1"] + } + :return: { + "meta_rules": { + "meta_rule_id1": { + "name": "name of the meta rule", + "subject_categories": ["subject_category_id1", + "subject_category_id2"], + "object_categories": ["object_category_id1"], + "action_categories": ["action_category_id1"] + }, + } + } + :internal_api: set_meta_rules + """ + try: + data = ModelManager.set_meta_rule( + user_id=user_id, meta_rule_id=meta_rule_id, value=request.json) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"meta_rules": data} + + @check_auth + def delete(self, meta_rule_id=None, user_id=None): + """Delete a meta rule + + :param meta_rule_id: Meta rule ID + :param user_id: user ID who do the request + :request body: delete = { + "name": "name of the meta rule", + "subject_categories": ["subject_category_id1", + "subject_category_id2"], + "object_categories": ["object_category_id1"], + "action_categories": ["action_category_id1"] + } + :return: { + "meta_rules": { + "meta_rule_id1": { + "name": "name of the meta rule", + "subject_categories": ["subject_category_id1", + "subject_category_id2"], + "object_categories": ["object_category_id1"], + "action_categories": ["action_category_id1"] + }, + } + } + :internal_api: delete_meta_rules + """ + try: + data = ModelManager.delete_meta_rule( + user_id=user_id, meta_rule_id=meta_rule_id) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"result": True} + diff --git a/moon_manager/moon_manager/api/models.py b/moon_manager/moon_manager/api/models.py new file mode 100644 index 00000000..62866191 --- /dev/null +++ b/moon_manager/moon_manager/api/models.py @@ -0,0 +1,127 @@ +# 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'. +""" +Models aggregate multiple meta rules +""" + +from flask import request +from flask_restful import Resource +from oslo_log import log as logging +from python_moonutilities.security_functions import check_auth +from python_moondb.core import ModelManager + +__version__ = "0.1.0" + +LOG = logging.getLogger("moon.manager.api." + __name__) + + +class Models(Resource): + """ + Endpoint for model requests + """ + + __urls__ = ( + "/models", + "/models/", + "/models/", + "/models//", + ) + + @check_auth + def get(self, uuid=None, user_id=None): + """Retrieve all models + + :param uuid: uuid of the model + :param user_id: user ID who do the request + :return: { + "model_id1": { + "name": "...", + "description": "...", + "meta_rules": ["meta_rule_id1", ] + } + } + :internal_api: get_models + """ + try: + data = ModelManager.get_models(user_id=user_id, model_id=uuid) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"models": data} + + @check_auth + def post(self, uuid=None, user_id=None): + """Create model. + + :param uuid: uuid of the model (not used here) + :param user_id: user ID who do the request + :request body: { + "name": "...", + "description": "...", + "meta_rules": ["meta_rule_id1", ] + } + :return: { + "model_id1": { + "name": "...", + "description": "...", + "meta_rules": ["meta_rule_id1", ] + } + } + :internal_api: add_model + """ + try: + data = ModelManager.add_model( + user_id=user_id, model_id=uuid, value=request.json) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"models": data} + + @check_auth + def delete(self, uuid=None, user_id=None): + """Delete a model + + :param uuid: uuid of the model to delete + :param user_id: user ID who do the request + :return: { + "result": "True or False", + "message": "optional message" + } + :internal_api: delete_model + """ + try: + data = ModelManager.delete_model(user_id=user_id, model_id=uuid) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"result": True} + + @check_auth + def patch(self, uuid=None, user_id=None): + """Update a model + + :param uuid: uuid of the model to update + :param user_id: user ID who do the request + :return: { + "model_id1": { + "name": "...", + "description": "...", + "meta_rules": ["meta_rule_id1", ] + } + } + :internal_api: update_model + """ + try: + data = ModelManager.update_model( + user_id=user_id, model_id=uuid, value=request.json) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"models": data} + diff --git a/moon_manager/moon_manager/api/pdp.py b/moon_manager/moon_manager/api/pdp.py new file mode 100644 index 00000000..9183c25d --- /dev/null +++ b/moon_manager/moon_manager/api/pdp.py @@ -0,0 +1,181 @@ +# 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'. +""" +PDP are Policy Decision Point. + +""" + +from flask import request +from flask_restful import Resource +import logging +import requests +import time +from python_moonutilities.security_functions import check_auth +from python_moondb.core import PDPManager +from python_moondb.core import PolicyManager +from python_moondb.core import ModelManager +from python_moonutilities import configuration + +__version__ = "0.1.0" + +LOG = logging.getLogger("moon.manager.api." + __name__) + + +def delete_pod(uuid): + raise NotImplementedError + + +def add_pod(uuid, data): + if not data.get("keystone_project_id"): + return + LOG.info("Add a new pod {}".format(data)) + if "pdp_id" not in data: + data["pdp_id"] = uuid + data['policies'] = PolicyManager.get_policies(user_id="admin") + data['models'] = ModelManager.get_models(user_id="admin") + conf = configuration.get_configuration("components/orchestrator") + hostname = conf["components/orchestrator"].get("hostname", "orchestrator") + port = conf["components/orchestrator"].get("port", 80) + proto = conf["components/orchestrator"].get("protocol", "http") + while True: + try: + req = requests.post( + "{}://{}:{}/pods".format(proto, hostname, port), + json=data, + headers={"content-type": "application/json"}) + except requests.exceptions.ConnectionError: + LOG.warning("Orchestrator is not ready, standby...") + time.sleep(1) + else: + break + LOG.info(req.text) + + +class PDP(Resource): + """ + Endpoint for pdp requests + """ + + __urls__ = ( + "/pdp", + "/pdp/", + "/pdp/", + "/pdp//", + ) + + @check_auth + def get(self, uuid=None, user_id=None): + """Retrieve all pdp + + :param uuid: uuid of the pdp + :param user_id: user ID who do the request + :return: { + "pdp_id1": { + "name": "...", + "security_pipeline": [...], + "keystone_project_id": "keystone_project_id1", + "description": "...", + } + } + :internal_api: get_pdp + """ + try: + data = PDPManager.get_pdp(user_id=user_id, pdp_id=uuid) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"pdps": data} + + @check_auth + def post(self, uuid=None, user_id=None): + """Create pdp. + + :param uuid: uuid of the pdp (not used here) + :param user_id: user ID who do the request + :request body: { + "name": "...", + "security_pipeline": [...], + "keystone_project_id": "keystone_project_id1", + "description": "...", + } + :return: { + "pdp_id1": { + "name": "...", + "security_pipeline": [...], + "keystone_project_id": "keystone_project_id1", + "description": "...", + } + } + :internal_api: add_pdp + """ + try: + data = dict(request.json) + if not data.get("keystone_project_id"): + data["keystone_project_id"] = None + data = PDPManager.add_pdp( + user_id=user_id, pdp_id=None, value=request.json) + uuid = list(data.keys())[0] + LOG.info("data={}".format(data)) + LOG.info("uuid={}".format(uuid)) + add_pod(uuid=uuid, data=data[uuid]) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"pdps": data} + + @check_auth + def delete(self, uuid=None, user_id=None): + """Delete a pdp + + :param uuid: uuid of the pdp to delete + :param user_id: user ID who do the request + :return: { + "result": "True or False", + "message": "optional message" + } + :internal_api: delete_pdp + """ + try: + data = PDPManager.delete_pdp(user_id=user_id, pdp_id=uuid) + delete_pod(uuid) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"result": True} + + @check_auth + def patch(self, uuid=None, user_id=None): + """Update a pdp + + :param uuid: uuid of the pdp to update + :param user_id: user ID who do the request + :return: { + "pdp_id1": { + "name": "...", + "security_pipeline": [...], + "keystone_project_id": "keystone_project_id1", + "description": "...", + } + } + :internal_api: update_pdp + """ + try: + _data = dict(request.json) + if not _data.get("keystone_project_id"): + _data["keystone_project_id"] = None + data = PDPManager.update_pdp( + user_id=user_id, pdp_id=uuid, value=_data) + LOG.info("data={}".format(data)) + LOG.info("uuid={}".format(uuid)) + add_pod(uuid=uuid, data=data[uuid]) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"pdps": data} + diff --git a/moon_manager/moon_manager/api/perimeter.py b/moon_manager/moon_manager/api/perimeter.py new file mode 100644 index 00000000..8196e627 --- /dev/null +++ b/moon_manager/moon_manager/api/perimeter.py @@ -0,0 +1,447 @@ +# 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'. +""" +* Subjects are the source of an action on an object + (examples : users, virtual machines) +* Objects are the destination of an action + (examples virtual machines, virtual Routers) +* Actions are what subject wants to do on an object +""" + +from flask import request +from flask_restful import Resource +from oslo_log import log as logging +from python_moonutilities.security_functions import check_auth +from python_moondb.core import PolicyManager + +__version__ = "0.2.0" + +LOG = logging.getLogger("moon.manager.api." + __name__) + + +class Subjects(Resource): + """ + Endpoint for subjects requests + """ + + __urls__ = ( + "/subjects", + "/subjects/", + "/subjects/", + "/policies//subjects", + "/policies//subjects/", + "/policies//subjects/", + ) + + @check_auth + def get(self, uuid=None, perimeter_id=None, user_id=None): + """Retrieve all subjects or a specific one if perimeter_id is + given for a given policy + + :param uuid: uuid of the policy + :param perimeter_id: uuid of the subject + :param user_id: user ID who do the request + :return: { + "subject_id": { + "name": "name of the subject", + "keystone_id": "keystone id of the subject", + "description": "a description" + } + } + :internal_api: get_subjects + """ + try: + data = PolicyManager.get_subjects( + user_id=user_id, + policy_id=uuid, + perimeter_id=perimeter_id + ) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"subjects": data} + + @check_auth + def post(self, uuid=None, perimeter_id=None, user_id=None): + """Create or update a subject. + + :param uuid: uuid of the policy + :param perimeter_id: must not be used here + :param user_id: user ID who do the request + :request body: { + "name": "name of the subject", + "description": "description of the subject", + "password": "password for the subject", + "email": "email address of the subject" + } + :return: { + "subject_id": { + "name": "name of the subject", + "keystone_id": "keystone id of the subject", + "description": "description of the subject", + "password": "password for the subject", + "email": "email address of the subject" + } + } + :internal_api: set_subject + """ + try: + if not perimeter_id: + data = PolicyManager.get_subjects(user_id=user_id, + policy_id=None) + if 'name' in request.json: + for data_id, data_value in data.items(): + if data_value['name'] == request.json['name']: + perimeter_id = data_id + break + data = PolicyManager.add_subject( + user_id=user_id, policy_id=uuid, + perimeter_id=perimeter_id, value=request.json) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"subjects": data} + + @check_auth + def patch(self, uuid=None, perimeter_id=None, user_id=None): + """Create or update a subject. + + :param uuid: uuid of the policy + :param perimeter_id: must not be used here + :param user_id: user ID who do the request + :request body: { + "name": "name of the subject", + "description": "description of the subject", + "password": "password for the subject", + "email": "email address of the subject" + } + :return: { + "subject_id": { + "name": "name of the subject", + "keystone_id": "keystone id of the subject", + "description": "description of the subject", + "password": "password for the subject", + "email": "email address of the subject" + } + } + :internal_api: set_subject + """ + try: + if not perimeter_id: + data = PolicyManager.get_subjects(user_id=user_id, + policy_id=None) + if 'name' in request.json: + for data_id, data_value in data.items(): + if data_value['name'] == request.json['name']: + perimeter_id = data_id + break + data = PolicyManager.add_subject( + user_id=user_id, policy_id=uuid, + perimeter_id=perimeter_id, value=request.json) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"subjects": data} + + @check_auth + def delete(self, uuid=None, perimeter_id=None, user_id=None): + """Delete a subject for a given policy + + :param uuid: uuid of the policy + :param perimeter_id: uuid of the subject + :param user_id: user ID who do the request + :return: { + "subject_id": { + "name": "name of the subject", + "keystone_id": "keystone id of the subject", + "description": "description of the subject", + "password": "password for the subject", + "email": "email address of the subject" + } + } + :internal_api: delete_subject + """ + try: + data = PolicyManager.delete_subject( + user_id=user_id, policy_id=uuid, perimeter_id=perimeter_id) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"result": True} + + +class Objects(Resource): + """ + Endpoint for objects requests + """ + + __urls__ = ( + "/objects", + "/objects/", + "/objects/", + "/policies//objects", + "/policies//objects/", + "/policies//objects/", + ) + + @check_auth + def get(self, uuid=None, perimeter_id=None, user_id=None): + """Retrieve all objects or a specific one if perimeter_id is + given for a given policy + + :param uuid: uuid of the policy + :param perimeter_id: uuid of the object + :param user_id: user ID who do the request + :return: { + "object_id": { + "name": "name of the object", + "description": "description of the object" + } + } + :internal_api: get_objects + """ + try: + data = PolicyManager.get_objects( + user_id=user_id, + policy_id=uuid, + perimeter_id=perimeter_id + ) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"objects": data} + + @check_auth + def post(self, uuid=None, perimeter_id=None, user_id=None): + """Create or update a object. + + :param uuid: uuid of the policy + :param perimeter_id: must not be used here + :param user_id: user ID who do the request + :request body: { + "object_name": "name of the object", + "object_description": "description of the object" + } + :return: { + "object_id": { + "name": "name of the object", + "description": "description of the object" + } + } + :internal_api: set_object + """ + try: + data = PolicyManager.get_objects(user_id=user_id, policy_id=None) + if 'name' in request.json: + for data_id, data_value in data.items(): + if data_value['name'] == request.json['name']: + perimeter_id = data_id + break + data = PolicyManager.add_object( + user_id=user_id, policy_id=uuid, + perimeter_id=perimeter_id, value=request.json) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"objects": data} + + @check_auth + def patch(self, uuid=None, perimeter_id=None, user_id=None): + """Create or update a object. + + :param uuid: uuid of the policy + :param perimeter_id: must not be used here + :param user_id: user ID who do the request + :request body: { + "object_name": "name of the object", + "object_description": "description of the object" + } + :return: { + "object_id": { + "name": "name of the object", + "description": "description of the object" + } + } + :internal_api: set_object + """ + try: + data = PolicyManager.get_objects(user_id=user_id, policy_id=None) + if 'name' in request.json: + for data_id, data_value in data.items(): + if data_value['name'] == request.json['name']: + perimeter_id = data_id + break + data = PolicyManager.add_object( + user_id=user_id, policy_id=uuid, + perimeter_id=perimeter_id, value=request.json) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"objects": data} + + @check_auth + def delete(self, uuid=None, perimeter_id=None, user_id=None): + """Delete a object for a given policy + + :param uuid: uuid of the policy + :param perimeter_id: uuid of the object + :param user_id: user ID who do the request + :return: { + "object_id": { + "name": "name of the object", + "description": "description of the object" + } + } + :internal_api: delete_object + """ + try: + data = PolicyManager.delete_object( + user_id=user_id, policy_id=uuid, perimeter_id=perimeter_id) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"result": True} + + +class Actions(Resource): + """ + Endpoint for actions requests + """ + + __urls__ = ( + "/actions", + "/actions/", + "/actions/", + "/policies//actions", + "/policies//actions/", + "/policies//actions/", + ) + + @check_auth + def get(self, uuid=None, perimeter_id=None, user_id=None): + """Retrieve all actions or a specific one if perimeter_id + is given for a given policy + + :param uuid: uuid of the policy + :param perimeter_id: uuid of the action + :param user_id: user ID who do the request + :return: { + "action_id": { + "name": "name of the action", + "description": "description of the action" + } + } + :internal_api: get_actions + """ + try: + data = PolicyManager.get_actions( + user_id=user_id, policy_id=uuid, perimeter_id=perimeter_id) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"actions": data} + + @check_auth + def post(self, uuid=None, perimeter_id=None, user_id=None): + """Create or update a action. + + :param uuid: uuid of the policy + :param perimeter_id: must not be used here + :param user_id: user ID who do the request + :request body: { + "name": "name of the action", + "description": "description of the action" + } + :return: { + "action_id": { + "name": "name of the action", + "description": "description of the action" + } + } + :internal_api: set_action + """ + try: + data = PolicyManager.get_actions(user_id=user_id, policy_id=None) + if 'name' in request.json: + for data_id, data_value in data.items(): + if data_value['name'] == request.json['name']: + perimeter_id = data_id + break + data = PolicyManager.add_action( + user_id=user_id, policy_id=uuid, + perimeter_id=perimeter_id, value=request.json) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"actions": data} + + @check_auth + def patch(self, uuid=None, perimeter_id=None, user_id=None): + """Create or update a action. + + :param uuid: uuid of the policy + :param perimeter_id: must not be used here + :param user_id: user ID who do the request + :request body: { + "name": "name of the action", + "description": "description of the action" + } + :return: { + "action_id": { + "name": "name of the action", + "description": "description of the action" + } + } + :internal_api: set_action + """ + try: + data = PolicyManager.get_actions(user_id=user_id, policy_id=None) + if 'name' in request.json: + for data_id, data_value in data.items(): + if data_value['name'] == request.json['name']: + perimeter_id = data_id + break + data = PolicyManager.add_action( + user_id=user_id, policy_id=uuid, + perimeter_id=perimeter_id, value=request.json) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"actions": data} + + @check_auth + def delete(self, uuid=None, perimeter_id=None, user_id=None): + """Delete a action for a given policy + + :param uuid: uuid of the policy + :param perimeter_id: uuid of the action + :param user_id: user ID who do the request + :return: { + "action_id": { + "name": "name of the action", + "description": "description of the action" + } + } + :internal_api: delete_action + """ + try: + data = PolicyManager.delete_action( + user_id=user_id, policy_id=uuid, perimeter_id=perimeter_id) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"result": True} diff --git a/moon_manager/moon_manager/api/policies.py b/moon_manager/moon_manager/api/policies.py new file mode 100644 index 00000000..f34276bb --- /dev/null +++ b/moon_manager/moon_manager/api/policies.py @@ -0,0 +1,132 @@ +# 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'. +""" +Policies are instances of security models and implement security policies + +""" + +from flask import request +from flask_restful import Resource +from oslo_log import log as logging +from python_moonutilities.security_functions import check_auth +from python_moondb.core import PolicyManager + +__version__ = "0.1.0" + +LOG = logging.getLogger("moon.manager.api." + __name__) + + +class Policies(Resource): + """ + Endpoint for policy requests + """ + + __urls__ = ( + "/policies", + "/policies/", + "/policies/", + "/policies//", + ) + + @check_auth + def get(self, uuid=None, user_id=None): + """Retrieve all policies + + :param uuid: uuid of the policy + :param user_id: user ID who do the request + :return: { + "policy_id1": { + "name": "...", + "model_id": "...", + "genre": "...", + "description": "...", + } + } + :internal_api: get_policies + """ + try: + data = PolicyManager.get_policies(user_id=user_id, policy_id=uuid) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"policies": data} + + @check_auth + def post(self, uuid=None, user_id=None): + """Create policy. + + :param uuid: uuid of the policy (not used here) + :param user_id: user ID who do the request + :request body: { + "name": "...", + "model_id": "...", + "genre": "...", + "description": "...", + } + :return: { + "policy_id1": { + "name": "...", + "model_id": "...", + "genre": "...", + "description": "...", + } + } + :internal_api: add_policy + """ + try: + data = PolicyManager.add_policy( + user_id=user_id, policy_id=uuid, value=request.json) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"policies": data} + + @check_auth + def delete(self, uuid=None, user_id=None): + """Delete a policy + + :param uuid: uuid of the policy to delete + :param user_id: user ID who do the request + :return: { + "result": "True or False", + "message": "optional message" + } + :internal_api: delete_policy + """ + try: + data = PolicyManager.delete_policy(user_id=user_id, policy_id=uuid) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"result": True} + + @check_auth + def patch(self, uuid=None, user_id=None): + """Update a policy + + :param uuid: uuid of the policy to update + :param user_id: user ID who do the request + :return: { + "policy_id1": { + "name": "...", + "model_id": "...", + "genre": "...", + "description": "...", + } + } + :internal_api: update_policy + """ + try: + data = PolicyManager.update_policy( + user_id=user_id, policy_id=uuid, value=request.json) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"policies": data} + diff --git a/moon_manager/moon_manager/api/rules.py b/moon_manager/moon_manager/api/rules.py new file mode 100644 index 00000000..b25365df --- /dev/null +++ b/moon_manager/moon_manager/api/rules.py @@ -0,0 +1,140 @@ +# 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'. +""" +Rules (TODO) +""" + +from flask import request +from flask_restful import Resource +from oslo_log import log as logging +from python_moonutilities.security_functions import check_auth +from python_moondb.core import PolicyManager + +__version__ = "0.1.0" + +LOG = logging.getLogger("moon.manager.api." + __name__) + + +class Rules(Resource): + """ + Endpoint for rules requests + """ + + __urls__ = ("/policies//rules", + "/policies//rules/", + "/policies//rules/", + "/policies//rules//", + ) + + @check_auth + def get(self, uuid=None, rule_id=None, user_id=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 + :return: { + "rules": [ + "policy_id": "policy_id1", + "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"], + ] + } + :internal_api: get_rules + """ + try: + data = PolicyManager.get_rules(user_id=user_id, + policy_id=uuid, + rule_id=rule_id) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"rules": data} + + @check_auth + def post(self, uuid=None, rule_id=None, user_id=None): + """Add a rule to a meta rule + + :param uuid: policy ID + :param rule_id: rule ID + :param user_id: user ID who do the request + :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": { + "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 + """ + args = request.json + try: + data = PolicyManager.add_rule(user_id=user_id, + policy_id=uuid, + meta_rule_id=args['meta_rule_id'], + value=args) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"rules": data} + + @check_auth + def delete(self, uuid=None, rule_id=None, user_id=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 + :return: { "result": true } + :internal_api: delete_rule + """ + try: + data = PolicyManager.delete_rule( + user_id=user_id, policy_id=uuid, rule_id=rule_id) + except Exception as e: + LOG.error(e, exc_info=True) + return {"result": False, + "error": str(e)}, 500 + return {"result": True} + diff --git a/moon_manager/moon_manager/http_server.py b/moon_manager/moon_manager/http_server.py new file mode 100644 index 00000000..584e71a2 --- /dev/null +++ b/moon_manager/moon_manager/http_server.py @@ -0,0 +1,157 @@ +# 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'. + +from flask import Flask, jsonify +from flask_cors import CORS, cross_origin +from flask_restful import Resource, Api +import logging +import sqlalchemy.exc +import time +from moon_manager import __version__ +from moon_manager.api.generic import Status, Logs, API +from moon_manager.api.models import Models +from moon_manager.api.policies import Policies +from moon_manager.api.pdp import PDP +from moon_manager.api.meta_rules import MetaRules +from moon_manager.api.meta_data import SubjectCategories, ObjectCategories, ActionCategories +from moon_manager.api.perimeter import Subjects, Objects, Actions +from moon_manager.api.data import SubjectData, ObjectData, ActionData +from moon_manager.api.assignments import SubjectAssignments, ObjectAssignments, ActionAssignments +from moon_manager.api.rules import Rules +# from moon_manager.api.containers import Container +from python_moonutilities import configuration, exceptions +from python_moondb.core import PDPManager + + +LOG = logging.getLogger("moon.manager.http") + + +class Server: + """Base class for HTTP server""" + + def __init__(self, host="localhost", port=80, api=None, **kwargs): + """Run a server + + :param host: hostname of the server + :param port: port for the running server + :param kwargs: optional parameters + :return: a running server + """ + self._host = host + self._port = port + self._api = api + self._extra = kwargs + + @property + def host(self): + return self._host + + @host.setter + def host(self, name): + self._host = name + + @host.deleter + def host(self): + self._host = "" + + @property + def port(self): + return self._port + + @port.setter + def port(self, number): + self._port = number + + @port.deleter + def port(self): + self._port = 80 + + def run(self): + raise NotImplementedError() + +__API__ = ( + Status, Logs, API, + MetaRules, SubjectCategories, ObjectCategories, ActionCategories, + Subjects, Objects, Actions, + SubjectAssignments, ObjectAssignments, ActionAssignments, + SubjectData, ObjectData, ActionData, + Rules, #Container, + Models, Policies, PDP + ) + + +class Root(Resource): + """ + The root of the web service + """ + __urls__ = ("/", ) + __methods = ("get", "post", "put", "delete", "options") + + def get(self): + tree = {"/": {"methods": ("get",), "description": "List all methods for that service."}} + for item in __API__: + tree[item.__name__] = {"urls": item.__urls__} + _methods = [] + for _method in self.__methods: + if _method in dir(item): + _methods.append(_method) + tree[item.__name__]["methods"] = _methods + tree[item.__name__]["description"] = item.__doc__.strip() + return { + "version": __version__, + "tree": tree + } + + +class HTTPServer(Server): + + def __init__(self, host="localhost", port=80, **kwargs): + super(HTTPServer, self).__init__(host=host, port=port, **kwargs) + self.app = Flask(__name__) + conf = configuration.get_configuration("components/manager") + self.manager_hostname = conf["components/manager"].get("hostname", "manager") + self.manager_port = conf["components/manager"].get("port", 80) + #Todo : specify only few urls instead of * + CORS(self.app) + self.api = Api(self.app) + self.__set_route() + self.__hook_errors() + + def __hook_errors(self): + + def get_404_json(e): + return jsonify({"result": False, "code": 404, "description": str(e)}), 404 + self.app.register_error_handler(404, get_404_json) + + def get_400_json(e): + return jsonify({"result": False, "code": 400, "description": str(e)}), 400 + self.app.register_error_handler(400, lambda e: get_400_json) + self.app.register_error_handler(403, exceptions.AuthException) + + def __set_route(self): + self.api.add_resource(Root, '/') + + for api in __API__: + self.api.add_resource(api, *api.__urls__) + + @staticmethod + def __check_if_db_is_up(): + first = True + while True: + try: + PDPManager.get_pdp(user_id="admin", pdp_id=None) + except sqlalchemy.exc.ProgrammingError: + time.sleep(1) + if first: + LOG.warning("Waiting for the database...") + first = False + else: + LOG.warning("Database is up, resuming operations...") + break + + def run(self): + self.__check_if_db_is_up() + self.app.run(debug=True, host=self._host, port=self._port) # nosec + diff --git a/moon_manager/moon_manager/server.py b/moon_manager/moon_manager/server.py new file mode 100644 index 00000000..bcc52cb3 --- /dev/null +++ b/moon_manager/moon_manager/server.py @@ -0,0 +1,38 @@ +# 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 +from oslo_config import cfg +from oslo_log import log as logging +from python_moonutilities import configuration, exceptions +from moon_manager.http_server import HTTPServer + +LOG = logging.getLogger("moon.manager") +CONF = cfg.CONF +DOMAIN = "moon_manager" + +__CWD__ = os.path.dirname(os.path.abspath(__file__)) + + +def main(): + configuration.init_logging() + try: + conf = configuration.get_configuration("components/manager") + hostname = conf["components/manager"].get("hostname", "manager") + port = conf["components/manager"].get("port", 80) + bind = conf["components/manager"].get("bind", "127.0.0.1") + except exceptions.ConsulComponentNotFound: + hostname = "manager" + bind = "127.0.0.1" + port = 80 + configuration.add_component(uuid="manager", name=hostname, port=port, bind=bind) + LOG.info("Starting server with IP {} on port {} bind to {}".format(hostname, port, bind)) + server = HTTPServer(host=bind, port=port) + return server + + +if __name__ == '__main__': + server = main() + server.run() diff --git a/moon_manager/requirements.txt b/moon_manager/requirements.txt new file mode 100644 index 00000000..15ba715b --- /dev/null +++ b/moon_manager/requirements.txt @@ -0,0 +1,6 @@ +flask +flask_restful +flask_cors +python_moonutilities +python_moondb +docker-py diff --git a/moon_manager/setup.py b/moon_manager/setup.py new file mode 100644 index 00000000..a6fc5fc7 --- /dev/null +++ b/moon_manager/setup.py @@ -0,0 +1,47 @@ +# 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'. + +from setuptools import setup, find_packages +import moon_manager + + +setup( + + name='moon_manager', + + version=moon_manager.__version__, + + packages=find_packages(), + + author="Thomas Duval", + + author_email="thomas.duval@orange.com", + + description="", + + long_description=open('README.rst').read(), + + # install_requires= , + + include_package_data=True, + + url='https://git.opnfv.org/cgit/moon', + + classifiers=[ + "Programming Language :: Python", + "Development Status :: 1 - Planning", + "License :: OSI Approved", + "Natural Language :: French", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3", + ], + + entry_points={ + 'console_scripts': [ + 'moon_manager = moon_manager.server:main', + ], + } + +) diff --git a/moon_manager/tests/unit_python/__init__.py b/moon_manager/tests/unit_python/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/moon_manager/tests/unit_python/api/__init__.py b/moon_manager/tests/unit_python/api/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/moon_manager/tests/unit_python/api/test_perimeter.py b/moon_manager/tests/unit_python/api/test_perimeter.py new file mode 100644 index 00000000..18d3837a --- /dev/null +++ b/moon_manager/tests/unit_python/api/test_perimeter.py @@ -0,0 +1,59 @@ +# import moon_manager +# import moon_manager.api +import json + + +def get_json(data): + return json.loads(data.decode("utf-8")) + + +def get_subjects(client): + req = client.get("/subjects") + assert req.status_code == 200 + subjects = get_json(req.data) + assert isinstance(subjects, dict) + assert "subjects" in subjects + return subjects + + +def add_subjects(client, name): + data = { + "name": name, + "description": "description of {}".format(name), + "password": "password for {}".format(name), + "email": "{}@moon".format(name) + } + req = client.post("/subjects", data=json.dumps(data), + headers={'Content-Type': 'application/json'}) + assert req.status_code == 200 + subjects = get_json(req.data) + assert isinstance(subjects, dict) + key = list(subjects["subjects"].keys())[0] + value = list(subjects["subjects"].values())[0] + assert "subjects" in subjects + assert key == "1111111111111" + assert value['id'] == "1111111111111" + assert value['name'] == name + assert value["description"] == "description of {}".format(name) + assert value["email"] == "{}@moon".format(name) + return subjects + + +def delete_subject(client, name): + subjects = get_subjects(client) + for key, value in subjects['subjects'].items(): + if value['name'] == name: + req = client.delete("/subjects/{}".format(key)) + assert req.status_code == 200 + break + subjects = get_subjects(client) + assert name not in [x['name'] for x in subjects["subjects"].values()] + + +def test_subject(): + import moon_manager.server + server = moon_manager.server.main() + client = server.app.test_client() + get_subjects(client) + add_subjects(client, "testuser") + delete_subject(client, "testuser") diff --git a/moon_manager/tests/unit_python/conftest.py b/moon_manager/tests/unit_python/conftest.py new file mode 100644 index 00000000..c59fae40 --- /dev/null +++ b/moon_manager/tests/unit_python/conftest.py @@ -0,0 +1,195 @@ +import base64 +import json +import logging +import pytest +import requests_mock + +CONF = { + "openstack": { + "keystone": { + "url": "http://keystone:5000/v3", + "user": "admin", + "check_token": False, + "password": "p4ssw0rd", + "domain": "default", + "certificate": False, + "project": "admin" + } + }, + "components": { + "wrapper": { + "bind": "0.0.0.0", + "port": 8080, + "container": "wukongsun/moon_wrapper:v4.3", + "timeout": 5, + "hostname": "wrapper" + }, + "manager": { + "bind": "0.0.0.0", + "port": 8082, + "container": "wukongsun/moon_manager:v4.3", + "hostname": "manager" + }, + "port_start": 31001, + "orchestrator": { + "bind": "0.0.0.0", + "port": 8083, + "container": "wukongsun/moon_orchestrator:v4.3", + "hostname": "interface" + }, + "interface": { + "bind": "0.0.0.0", + "port": 8080, + "container": "wukongsun/moon_interface:v4.3", + "hostname": "interface" + } + }, + "plugins": { + "session": { + "port": 8082, + "container": "asteroide/session:latest" + }, + "authz": { + "port": 8081, + "container": "wukongsun/moon_authz:v4.3" + } + }, + "logging": { + "handlers": { + "file": { + "filename": "/tmp/moon.log", + "class": "logging.handlers.RotatingFileHandler", + "level": "DEBUG", + "formatter": "custom", + "backupCount": 3, + "maxBytes": 1048576 + }, + "console": { + "class": "logging.StreamHandler", + "formatter": "brief", + "level": "INFO", + "stream": "ext://sys.stdout" + } + }, + "formatters": { + "brief": { + "format": "%(levelname)s %(name)s %(message)-30s" + }, + "custom": { + "format": "%(asctime)-15s %(levelname)s %(name)s %(message)s" + } + }, + "root": { + "handlers": [ + "console" + ], + "level": "ERROR" + }, + "version": 1, + "loggers": { + "moon": { + "handlers": [ + "console", + "file" + ], + "propagate": False, + "level": "DEBUG" + } + } + }, + "slave": { + "name": None, + "master": { + "url": None, + "login": None, + "password": None + } + }, + "docker": { + "url": "tcp://172.88.88.1:2376", + "network": "moon" + }, + "database": { + "url": "sqlite:///database.db", + # "url": "mysql+pymysql://moon:p4sswOrd1@db/moon", + "driver": "sql" + }, + "messenger": { + "url": "rabbit://moon:p4sswOrd1@messenger:5672/moon" + } +} + +COMPONENTS = ( + "logging", + "openstack/keystone", + "database", + "slave", + "components/manager", +) + + +def get_b64_conf(component=None): + if component in CONF: + return base64.b64encode( + json.dumps( + CONF[component]).encode('utf-8')+b"\n").decode('utf-8') + elif "/" in component: + key1, _, key2 = component.partition("/") + return base64.b64encode( + json.dumps( + CONF[key1][key2]).encode('utf-8')+b"\n").decode('utf-8') + else: + return base64.b64encode( + json.dumps(CONF).encode('utf-8')+b"\n").decode('utf-8') + + +@pytest.fixture(autouse=True) +def no_requests(monkeypatch): + """ Modify the response from Requests module + """ + with requests_mock.Mocker(real_http=True) as m: + for component in COMPONENTS: + m.register_uri( + 'GET', 'http://consul:8500/v1/kv/{}'.format(component), + json=[{'Key': component, 'Value': get_b64_conf(component)}] + ) + m.register_uri( + 'POST', 'http://keystone:5000/v3/auth/tokens', + headers={'X-Subject-Token': "111111111"} + ) + m.register_uri( + 'DELETE', 'http://keystone:5000/v3/auth/tokens', + headers={'X-Subject-Token': "111111111"} + ) + m.register_uri( + 'POST', 'http://keystone:5000/v3/users?name=testuser&domain_id=default', + json={"users": {}} + ) + m.register_uri( + 'GET', 'http://keystone:5000/v3/users?name=testuser&domain_id=default', + json={"users": {}} + ) + m.register_uri( + 'POST', 'http://keystone:5000/v3/users/', + json={"users": [{ + "id": "1111111111111" + }]} + ) + print("Start populating the DB.") + from python_moondb.db_manager import init_engine, main + engine = init_engine() + print("engine={}".format(engine)) + main("upgrade", logging.getLogger("db_manager"), engine) + print("End populating the DB.") + yield m + + +# @pytest.fixture(autouse=True, scope="session") +# def manage_database(): +# from moon_db.db_manager import init_engine, run +# engine = init_engine() +# run("upgrade", logging.getLogger("db_manager"), engine) +# yield +# print("Will close the DB") + + diff --git a/moon_manager/tests/unit_python/requirements.txt b/moon_manager/tests/unit_python/requirements.txt new file mode 100644 index 00000000..21975ce3 --- /dev/null +++ b/moon_manager/tests/unit_python/requirements.txt @@ -0,0 +1,5 @@ +flask +flask_cors +flask_restful +python_moondb +python_moonutilities \ No newline at end of file -- cgit 1.2.3-korg