From 7bb53c64da2dcf88894bfd31503accdd81498f3d Mon Sep 17 00:00:00 2001 From: Thomas Duval Date: Wed, 3 Jun 2020 10:06:52 +0200 Subject: Update to new version 5.4 Signed-off-by: Thomas Duval Change-Id: Idcd868133d75928a1ffd74d749ce98503e0555ea --- moon_manager/.gitignore | 5 + moon_manager/Changelog | 150 +- moon_manager/Dockerfile | 15 - moon_manager/README.md | 124 +- moon_manager/conf/moon.yaml | 108 + moon_manager/docs/test.rst | 0 moon_manager/moon_manager/__init__.py | 20 +- moon_manager/moon_manager/__main__.py | 234 ++- moon_manager/moon_manager/api/__init__.py | 28 + moon_manager/moon_manager/api/assignments.py | 751 +++++-- moon_manager/moon_manager/api/attributes.py | 207 ++ moon_manager/moon_manager/api/auth.py | 42 + moon_manager/moon_manager/api/base_exception.py | 17 - moon_manager/moon_manager/api/checks.py | 211 ++ moon_manager/moon_manager/api/configuration.py | 237 +++ moon_manager/moon_manager/api/data.py | 649 ++++-- moon_manager/moon_manager/api/db/__init__.py | 12 + moon_manager/moon_manager/api/db/managers.py | 24 + .../moon_manager/api/db/migrations/__init__.py | 12 + .../moon_manager/api/db/migrations/moon_001.py | 336 ++++ moon_manager/moon_manager/api/db/model.py | 429 ++++ moon_manager/moon_manager/api/db/pdp.py | 115 ++ moon_manager/moon_manager/api/db/policy.py | 971 +++++++++ moon_manager/moon_manager/api/db/slave.py | 55 + moon_manager/moon_manager/api/generic.py | 144 -- .../moon_manager/api/information/__init__.py | 11 + .../moon_manager/api/information/global_attrs.py | 145 ++ .../moon_manager/api/information/information.py | 106 + .../moon_manager/api/information/managers.py | 19 + moon_manager/moon_manager/api/json_export.py | 282 +-- moon_manager/moon_manager/api/json_import.py | 600 +----- moon_manager/moon_manager/api/json_utils.py | 282 --- moon_manager/moon_manager/api/logs.py | 25 + moon_manager/moon_manager/api/meta_data.py | 526 ++++- moon_manager/moon_manager/api/meta_rules.py | 253 ++- moon_manager/moon_manager/api/models.py | 233 ++- .../moon_manager/api/orchestration/__init__.py | 12 + .../moon_manager/api/orchestration/managers.py | 21 + .../moon_manager/api/orchestration/pipeline.py | 44 + .../moon_manager/api/orchestration/slave.py | 44 + moon_manager/moon_manager/api/pdp.py | 468 +++-- moon_manager/moon_manager/api/perimeter.py | 838 ++++++-- moon_manager/moon_manager/api/policies.py | 125 -- moon_manager/moon_manager/api/policy.py | 293 +++ moon_manager/moon_manager/api/rules.py | 319 ++- moon_manager/moon_manager/api/slave.py | 341 ++++ moon_manager/moon_manager/api/slaves.py | 111 -- moon_manager/moon_manager/api/status.py | 127 ++ moon_manager/moon_manager/api/users.py | 95 + moon_manager/moon_manager/daemon.py | 183 ++ moon_manager/moon_manager/db_driver.py | 256 +++ moon_manager/moon_manager/http_server.py | 162 -- moon_manager/moon_manager/manager_setup.py | 31 + moon_manager/moon_manager/orchestration_driver.py | 81 + moon_manager/moon_manager/pip_driver.py | 350 ++++ moon_manager/moon_manager/plugins/__init__.py | 12 + moon_manager/moon_manager/plugins/global_attrs.py | 582 ++++++ .../moon_manager/plugins/moon_keystone_plugin.py | 77 + .../moon_manager/plugins/moon_nova_plugin.py | 71 + .../moon_manager/plugins/moon_openstack_plugin.py | 203 ++ .../moon_manager/plugins/pyorchestrator.py | 493 +++++ moon_manager/moon_manager/plugins/sql.py | 2085 ++++++++++++++++++++ moon_manager/moon_manager/server.py | 130 +- moon_manager/moonrc | 18 + moon_manager/requirements.txt | 14 +- moon_manager/setup.py | 76 +- moon_manager/tests/command_lines/test_complete.py | 764 +++++++ .../Import tests.postman_collection.json | 1476 ++++++++++++++ .../Test Manager.postman_collection.json | 916 +++++++++ moon_manager/tests/func_tests/Logs/test.txt | 0 moon_manager/tests/func_tests/__init__.py | 11 + moon_manager/tests/func_tests/features/README.md | 11 + moon_manager/tests/func_tests/features/__init__.py | 11 + .../tests/func_tests/features/assignments.feature | 290 +++ .../features/authorization_pipeline.feature | 388 ++++ .../features/authorization_wrapper.feature | 386 ++++ .../tests/func_tests/features/data.feature | 330 ++++ .../tests/func_tests/features/environment.py | 27 + .../tests/func_tests/features/meta_data.feature | 295 +++ .../tests/func_tests/features/meta_rules.feature | 234 +++ .../tests/func_tests/features/model.feature | 176 ++ .../tests/func_tests/features/partner.feature | 7 + moon_manager/tests/func_tests/features/pdp.feature | 141 ++ .../tests/func_tests/features/perimeter.feature | 465 +++++ .../tests/func_tests/features/policy.feature | 245 +++ .../tests/func_tests/features/rules.feature | 188 ++ .../func_tests/features/steps/Static_Variables.py | 89 + .../tests/func_tests/features/steps/__init__.py | 11 + .../tests/func_tests/features/steps/assignments.py | 858 ++++++++ .../func_tests/features/steps/authorization.py | 217 ++ .../func_tests/features/steps/common_functions.py | 279 +++ .../tests/func_tests/features/steps/data.py | 629 ++++++ .../tests/func_tests/features/steps/meta_data.py | 394 ++++ .../tests/func_tests/features/steps/meta_rules.py | 335 ++++ .../tests/func_tests/features/steps/model.py | 230 +++ .../tests/func_tests/features/steps/pdp.py | 248 +++ .../tests/func_tests/features/steps/perimeter.py | 727 +++++++ .../tests/func_tests/features/steps/policy.py | 219 ++ .../tests/func_tests/features/steps/rules.py | 495 +++++ moon_manager/tests/func_tests/run.sh | 25 + moon_manager/tests/functional_pod/conftest.py | 12 - moon_manager/tests/functional_pod/json/mls.json | 89 - moon_manager/tests/functional_pod/json/rbac.json | 85 - .../tests/functional_pod/run_functional_tests.sh | 11 - moon_manager/tests/functional_pod/test_manager.py | 116 -- moon_manager/tests/functional_pod/test_models.py | 79 - .../tests/performance_tests/authz_pipeline.py | 115 ++ moon_manager/tests/performance_tests/locustfile.py | 26 + .../tests/performance_tests/policy_rbac.json | 411 ++++ .../tests/performance_tests_policies/actions.py | 54 + .../tests/performance_tests_policies/locustfile.py | 32 + .../tests/performance_tests_policies/meta_rules.py | 80 + .../tests/performance_tests_policies/objects.py | 54 + .../tests/performance_tests_policies/subjects.py | 57 + .../tests/performance_tests_policies/utils.py | 45 + moon_manager/tests/unit_python/api/__init__.py | 12 + .../unit_python/api/import_export_utilities.py | 202 -- .../tests/unit_python/api/meta_data_test.py | 238 --- .../tests/unit_python/api/meta_rules_test.py | 162 -- .../tests/unit_python/api/test_assignement.py | 349 +++- .../tests/unit_python/api/test_assignemnt.py | 270 --- moon_manager/tests/unit_python/api/test_auth.py | 71 + moon_manager/tests/unit_python/api/test_data.py | 276 ++- moon_manager/tests/unit_python/api/test_export.py | 282 --- moon_manager/tests/unit_python/api/test_import.py | 510 ----- .../tests/unit_python/api/test_json_export.py | 321 +++ .../tests/unit_python/api/test_json_import.py | 832 ++++++++ .../tests/unit_python/api/test_keystone.py | 63 + .../tests/unit_python/api/test_meta_data.py | 381 ++-- .../tests/unit_python/api/test_meta_rules.py | 512 +++-- moon_manager/tests/unit_python/api/test_models.py | 475 +++++ moon_manager/tests/unit_python/api/test_nova.py | 58 + moon_manager/tests/unit_python/api/test_pdp.py | 513 ++++- .../tests/unit_python/api/test_perimeter.py | 936 +++++---- .../unit_python/api/test_perimeter_examples.py | 55 + .../tests/unit_python/api/test_policies.py | 444 +++-- moon_manager/tests/unit_python/api/test_rules.py | 314 ++- moon_manager/tests/unit_python/api/test_slaves.py | 90 + .../tests/unit_python/api/test_unit_models.py | 352 ---- moon_manager/tests/unit_python/api/utilities.py | 32 +- moon_manager/tests/unit_python/conftest.py | 396 ++-- moon_manager/tests/unit_python/helpers/__init__.py | 11 + .../tests/unit_python/helpers/assignment_helper.py | 34 +- .../tests/unit_python/helpers/category_helper.py | 39 +- .../tests/unit_python/helpers/data_builder.py | 71 +- .../tests/unit_python/helpers/data_helper.py | 91 +- .../unit_python/helpers/import_export_helper.py | 287 +++ .../tests/unit_python/helpers/meta_rule_helper.py | 73 +- .../tests/unit_python/helpers/model_helper.py | 61 +- .../tests/unit_python/helpers/pdp_helper.py | 24 +- .../tests/unit_python/helpers/policy_helper.py | 49 +- .../tests/unit_python/helpers/rules_helper.py | 18 + moon_manager/tests/unit_python/mock_engine.py | 19 + moon_manager/tests/unit_python/mock_keystone.py | 59 + moon_manager/tests/unit_python/mock_nova.py | 28 + moon_manager/tests/unit_python/mock_slaves.py | 38 + moon_manager/tests/unit_python/plugins/__init__.py | 12 + .../tests/unit_python/plugins/test_global_attrs.py | 148 ++ moon_manager/tests/unit_python/requirements.txt | 16 +- 159 files changed, 30085 insertions(+), 6562 deletions(-) delete mode 100644 moon_manager/Dockerfile create mode 100644 moon_manager/conf/moon.yaml create mode 100644 moon_manager/docs/test.rst create mode 100644 moon_manager/moon_manager/api/attributes.py create mode 100644 moon_manager/moon_manager/api/auth.py delete mode 100644 moon_manager/moon_manager/api/base_exception.py create mode 100644 moon_manager/moon_manager/api/checks.py create mode 100644 moon_manager/moon_manager/api/configuration.py create mode 100644 moon_manager/moon_manager/api/db/__init__.py create mode 100644 moon_manager/moon_manager/api/db/managers.py create mode 100644 moon_manager/moon_manager/api/db/migrations/__init__.py create mode 100644 moon_manager/moon_manager/api/db/migrations/moon_001.py create mode 100644 moon_manager/moon_manager/api/db/model.py create mode 100644 moon_manager/moon_manager/api/db/pdp.py create mode 100644 moon_manager/moon_manager/api/db/policy.py create mode 100644 moon_manager/moon_manager/api/db/slave.py delete mode 100644 moon_manager/moon_manager/api/generic.py create mode 100644 moon_manager/moon_manager/api/information/__init__.py create mode 100644 moon_manager/moon_manager/api/information/global_attrs.py create mode 100644 moon_manager/moon_manager/api/information/information.py create mode 100644 moon_manager/moon_manager/api/information/managers.py delete mode 100644 moon_manager/moon_manager/api/json_utils.py create mode 100644 moon_manager/moon_manager/api/logs.py create mode 100644 moon_manager/moon_manager/api/orchestration/__init__.py create mode 100644 moon_manager/moon_manager/api/orchestration/managers.py create mode 100644 moon_manager/moon_manager/api/orchestration/pipeline.py create mode 100644 moon_manager/moon_manager/api/orchestration/slave.py delete mode 100644 moon_manager/moon_manager/api/policies.py create mode 100644 moon_manager/moon_manager/api/policy.py create mode 100644 moon_manager/moon_manager/api/slave.py delete mode 100644 moon_manager/moon_manager/api/slaves.py create mode 100644 moon_manager/moon_manager/api/status.py create mode 100644 moon_manager/moon_manager/api/users.py create mode 100644 moon_manager/moon_manager/daemon.py create mode 100644 moon_manager/moon_manager/db_driver.py delete mode 100644 moon_manager/moon_manager/http_server.py create mode 100644 moon_manager/moon_manager/manager_setup.py create mode 100644 moon_manager/moon_manager/orchestration_driver.py create mode 100644 moon_manager/moon_manager/pip_driver.py create mode 100644 moon_manager/moon_manager/plugins/__init__.py create mode 100644 moon_manager/moon_manager/plugins/global_attrs.py create mode 100644 moon_manager/moon_manager/plugins/moon_keystone_plugin.py create mode 100644 moon_manager/moon_manager/plugins/moon_nova_plugin.py create mode 100644 moon_manager/moon_manager/plugins/moon_openstack_plugin.py create mode 100644 moon_manager/moon_manager/plugins/pyorchestrator.py create mode 100644 moon_manager/moon_manager/plugins/sql.py create mode 100644 moon_manager/moonrc create mode 100644 moon_manager/tests/command_lines/test_complete.py create mode 100644 moon_manager/tests/func_postman/Import tests.postman_collection.json create mode 100644 moon_manager/tests/func_postman/Test Manager.postman_collection.json create mode 100644 moon_manager/tests/func_tests/Logs/test.txt create mode 100644 moon_manager/tests/func_tests/__init__.py create mode 100644 moon_manager/tests/func_tests/features/README.md create mode 100644 moon_manager/tests/func_tests/features/__init__.py create mode 100644 moon_manager/tests/func_tests/features/assignments.feature create mode 100644 moon_manager/tests/func_tests/features/authorization_pipeline.feature create mode 100644 moon_manager/tests/func_tests/features/authorization_wrapper.feature create mode 100644 moon_manager/tests/func_tests/features/data.feature create mode 100644 moon_manager/tests/func_tests/features/environment.py create mode 100644 moon_manager/tests/func_tests/features/meta_data.feature create mode 100644 moon_manager/tests/func_tests/features/meta_rules.feature create mode 100644 moon_manager/tests/func_tests/features/model.feature create mode 100644 moon_manager/tests/func_tests/features/partner.feature create mode 100644 moon_manager/tests/func_tests/features/pdp.feature create mode 100644 moon_manager/tests/func_tests/features/perimeter.feature create mode 100644 moon_manager/tests/func_tests/features/policy.feature create mode 100644 moon_manager/tests/func_tests/features/rules.feature create mode 100644 moon_manager/tests/func_tests/features/steps/Static_Variables.py create mode 100644 moon_manager/tests/func_tests/features/steps/__init__.py create mode 100644 moon_manager/tests/func_tests/features/steps/assignments.py create mode 100644 moon_manager/tests/func_tests/features/steps/authorization.py create mode 100644 moon_manager/tests/func_tests/features/steps/common_functions.py create mode 100644 moon_manager/tests/func_tests/features/steps/data.py create mode 100644 moon_manager/tests/func_tests/features/steps/meta_data.py create mode 100644 moon_manager/tests/func_tests/features/steps/meta_rules.py create mode 100644 moon_manager/tests/func_tests/features/steps/model.py create mode 100644 moon_manager/tests/func_tests/features/steps/pdp.py create mode 100644 moon_manager/tests/func_tests/features/steps/perimeter.py create mode 100644 moon_manager/tests/func_tests/features/steps/policy.py create mode 100644 moon_manager/tests/func_tests/features/steps/rules.py create mode 100755 moon_manager/tests/func_tests/run.sh delete mode 100644 moon_manager/tests/functional_pod/conftest.py delete mode 100644 moon_manager/tests/functional_pod/json/mls.json delete mode 100644 moon_manager/tests/functional_pod/json/rbac.json delete mode 100644 moon_manager/tests/functional_pod/run_functional_tests.sh delete mode 100644 moon_manager/tests/functional_pod/test_manager.py delete mode 100644 moon_manager/tests/functional_pod/test_models.py create mode 100644 moon_manager/tests/performance_tests/authz_pipeline.py create mode 100644 moon_manager/tests/performance_tests/locustfile.py create mode 100644 moon_manager/tests/performance_tests/policy_rbac.json create mode 100644 moon_manager/tests/performance_tests_policies/actions.py create mode 100644 moon_manager/tests/performance_tests_policies/locustfile.py create mode 100644 moon_manager/tests/performance_tests_policies/meta_rules.py create mode 100644 moon_manager/tests/performance_tests_policies/objects.py create mode 100644 moon_manager/tests/performance_tests_policies/subjects.py create mode 100644 moon_manager/tests/performance_tests_policies/utils.py create mode 100644 moon_manager/tests/unit_python/api/__init__.py delete mode 100644 moon_manager/tests/unit_python/api/import_export_utilities.py delete mode 100644 moon_manager/tests/unit_python/api/meta_data_test.py delete mode 100644 moon_manager/tests/unit_python/api/meta_rules_test.py delete mode 100644 moon_manager/tests/unit_python/api/test_assignemnt.py create mode 100644 moon_manager/tests/unit_python/api/test_auth.py delete mode 100644 moon_manager/tests/unit_python/api/test_export.py delete mode 100644 moon_manager/tests/unit_python/api/test_import.py create mode 100644 moon_manager/tests/unit_python/api/test_json_export.py create mode 100644 moon_manager/tests/unit_python/api/test_json_import.py create mode 100644 moon_manager/tests/unit_python/api/test_keystone.py create mode 100644 moon_manager/tests/unit_python/api/test_models.py create mode 100644 moon_manager/tests/unit_python/api/test_nova.py create mode 100644 moon_manager/tests/unit_python/api/test_perimeter_examples.py create mode 100644 moon_manager/tests/unit_python/api/test_slaves.py delete mode 100644 moon_manager/tests/unit_python/api/test_unit_models.py create mode 100644 moon_manager/tests/unit_python/helpers/import_export_helper.py create mode 100644 moon_manager/tests/unit_python/helpers/rules_helper.py create mode 100644 moon_manager/tests/unit_python/mock_engine.py create mode 100644 moon_manager/tests/unit_python/mock_keystone.py create mode 100644 moon_manager/tests/unit_python/mock_nova.py create mode 100644 moon_manager/tests/unit_python/mock_slaves.py create mode 100644 moon_manager/tests/unit_python/plugins/__init__.py create mode 100644 moon_manager/tests/unit_python/plugins/test_global_attrs.py (limited to 'moon_manager') diff --git a/moon_manager/.gitignore b/moon_manager/.gitignore index 894a44cc..bcf3f6c1 100644 --- a/moon_manager/.gitignore +++ b/moon_manager/.gitignore @@ -102,3 +102,8 @@ venv.bak/ # mypy .mypy_cache/ + +# moon +*.pwd +/.idea +/tests/func_tests/reports diff --git a/moon_manager/Changelog b/moon_manager/Changelog index 1fb9ac08..5080934c 100644 --- a/moon_manager/Changelog +++ b/moon_manager/Changelog @@ -1,4 +1,4 @@ -# Copyright 2018 Open Platform for NFV Project, Inc. and its contributors +# Copyright 2018 Orange 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'. @@ -7,67 +7,105 @@ CHANGES ======= -1.0.0 ------ +0.1 +--- - First version of the manager -2.0.0 ------ -- Version built inside the Keystone component +0.2 +--- +- Add the PIP plugin architecture and the OpenStack plugin -3.0.0 ------ -- Version built outside the Keystone component +0.3 +--- +- Add the PDP API +- Add the Policy API +- Add the Perimeter API +- Add the Slave API +- Add the Meta Rule API +- moon_manager/moon_manager/plugins/sql.py: allow the vim_project_id to be empty +- Update Moon configuration file +- Fix some bugs in moon_manager.api +- Integrating with keystone plugin +- Fix requirements.txt yaml to pyyaml +- Add exception handler +- Add Assignment API +- Add authentication system +- Add Meta-Data API +- Add Data API +- Add Rules API +- Add Model API +- Add json_import API +- Add json_export API +- Integrate All APIs with auth +- removing base_exception, json_utils to moon_utilities -4.0.0 ------ -- First micro-architecture version +0.4 +--- +- Move the pipeline creation to the wrapper component +- Move the authentication functions to moon_utilities +- Add API key exchange functionality +- Update Wrapper process creation +- Update response from slave API +- Adding invalid_function for all api +- Fix the rule API bug +- Fix the different responses between Get and Post slave APIs +- Add the possibility to not use the pip plugin +- Add a logout API +- Add the re-authentication functionality +- Updating deleting perimeter_assignment functionality to delete successfully -4.5.2 ------ -- use the threading capability of Flask app -- set the number of manager to 1 -- update to the latest version of the python-moondb library +0.5 +--- +- Add command lines for managing the Manager -4.5.2-1 ------ -- integrating validation to send mandatory key names +0.6 +--- +- Force the use of Gunicorn as the production server -4.5.3 ------ -- Removing try catch from all requets to allow raised exception to be passed to http server, to send actual error to client side -- fixing test cases to assert on the expected exception after removing try-catch -- allow 404 to be catched from our side instead of flask itself -- revert the params in the get/post/patch/delete to be by default = None, so that we could catch the param if it was None -instead of having not found url if the param is mandatory +0.7 +--- +- Fix the configuration directory issue in the Wrapper and Pipeline servers +- Fix the import errors (multiple import of the same policy) +- Add performance tests +- Force Gunicorn to run as a daemon +- Add an endpoint for the dashboard: /static/index.html +- Move the import functionality to moon_utilities +- Fix the no deletion of the slave server when deleting the slave, the pid file is created in config_dir +- Add of CLI for pdp update +- Add a command to run tests given in policy file +- Fixing not to delete Perimeter when policy empty (except direct delete) +- Fixing rule ['instruction'] to be array instead of object +- Increase the speed of the rules command +- Add of CLI for status + human / quiet options +- Fix the perimeter gets while filtering on non string argument +- Add the global attribute functionality +- Can now create several models with empty meta rules +- Adaptation following the removal of the field database > pwd_file in moon.yaml +- Add of update CLI for the policies -4.5.4 ------ -- fixing test cases after validation dependencies added in moondb +0.8 +--- +- Manager now retrieves api key and other data about slaves after restarting +- Add cli to update the slaves +- Add the grant_if_unknown_project parameter +- Disallow to update model/meta-rule assigned to policy +- Fix the system accepts invalid decision value “not grant” +- Add plugin for nova +- Add daemon to retrieve periodically subjects and objects from openstack +- Add start/stop server and/or daemon in CLI +- Fix subject/object_assignment deletion CLI +- Fix Running moon_manager from another host +- Fix and check CLI help string +- Fix in models CLI : can now give the meta_rule at creation -4.5.5 ------ -- removing validation on meta_rule categories -- Update to python_moonutilities 1.4.17 and fix tests -- adding extra test cases for update requests -- adding None to requests ( to avoid request not found) -- removing validation on categories, meta_rules so that can be added empty - -4.5.5-1 -------- -- Update to python_moonutilities 1.4.18 - -4.5.5-2 -------- -- Update to python_moonutilities 1.4.19 - -4.5.6 ----- -apply pyLint -adding extra test cases for policy update -- separate perimeter add/update with validation - -4.6.0 ------ -- Add a connection to the Update endpoint in Wrapper ->>>>>>> Stashed changes +0.9 +--- +- Can now update the meta rules while their model is not linked to a policy +- Moon users can now change their password +- Add of the update decision of rule cli/api +- Now logs the user who adds / patches / deletes a rule +- Add the start/stop command for the web GUI +- Status of the web GUI now visible with the status command +- Fix the creation of slaves with -g option +- Can now update a slave +- CLIs now use env variables to authenticate the user diff --git a/moon_manager/Dockerfile b/moon_manager/Dockerfile deleted file mode 100644 index d264a113..00000000 --- a/moon_manager/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM python:3 - -LABEL Name=Manager -LABEL Description="Manager component for the Moon platform" -LABEL Maintainer="Thomas Duval" -LABEL Url="https://wiki.opnfv.org/display/moon/Moon+Project+Proposal" - -USER root - -ADD . /root -WORKDIR /root/ -RUN pip3 install --no-cache-dir -r requirements.txt -RUN pip3 install --no-cache-dir . - -CMD ["python3", "-m", "moon_manager"] \ No newline at end of file diff --git a/moon_manager/README.md b/moon_manager/README.md index c74ccc28..1881827f 100644 --- a/moon_manager/README.md +++ b/moon_manager/README.md @@ -1,8 +1,124 @@ # moon_manager -This package contains the core module for the Moon project -It is designed to provide authorization features to all OpenStack components. +## Installation -For any other information, refer to the parent project: +```bash +python -m pip install moon_manager +sudo moon_manager_setup +``` +If you want a development version: - https://git.opnfv.org/moon +```bash +ARTIFACTORY=https://artifactory-iva.si.francetelecom.fr/artifactory/api/pypi/python-virt-orange-product-devops/simple +sudo python -m pip install --pre moon_manager -i $ARTIFACTORY +``` +Use it at your own risk, this is an unstable version. + +If you want to be in development mode, and get the code, you can do the following steps: + +```bash +git clone git@gitlab.forge.orange-labs.fr:moon/moon_utilities.git +cd moon_utilities +sudo pip install -r requirements.txt +sudo pip install -e . +cd .. +git clone git@gitlab.forge.orange-labs.fr:moon/moon_manager.git +cd moon_manager +sudo pip install -e . +``` + +## Configuration + +A configuration file should be located in `/etc/moon/moon.yaml`, review it and update it to fit your needs. +You may need to change the following attributes: + +* `debug`: true to false +* `database: url`: either sqlite or mysql +* `pwd_file`: put this file in a secured directory, this file contains the users and passwords of all the system +* `openstack: url`: the URL of the Keystone server (if used) + +## Initialization + +To initialize the database, use: + +```bash +moon_manager db +``` + +You need to add a new user (for example admin): + +```bash +moon_manager users add admin [-p admin_password] +``` +If the password is not given, you will be prompt for one. + +## Web server execution + +For a development server, use: + +```bash +hug -m moon_manager.server +``` + +For a production server: + +If you use Information plugins, you must start the daemon (experimental): + +```bash +moon_manager start_daemon +``` + +Then, start the server and connect to the CLI with the `/etc/moon/moonrc` file: + +```bash +moon_manager start_manager +. /etc/moon/moonrc admin admin +# Check if the service is up and running +moon_manager status --human +``` + +## Connect to API + +* With a web browser + 1. go to http://127.0.0.1:8000/auth + 2. insert login and password (admin/admin for example) + 3. with "RestClient", "Postman" or an other Web API client add the "x-api-key" in headers with the key given by the previous step. +* With a console + 1. execute a basic auth to http://127.0.0.1:8000/auth + 2. use the received token to connect to API + +Example with httpie: + +```bash +sudo python -m pip install httpie +http -a admin:admin 127.0.0.1:8000/auth +# copy the Token in TOKEN +http 127.0.0.1:8000/subjects "x-api-key:$TOKEN" +``` + +## Connect to HTML UI +You need to have `serve` installed on your server. To install it: + +``` +sudo apt install npm +sudo npm install -g serve +``` + +Then, configure the dashboard part of the `/etc/moon/moon.yaml` file like this: + +``` +dashboard: +root: +pid_filename: +port: 8080 +``` + +and: + +```bash +moon_manager start_gui +``` + +Open your web browser and go to: http://127.0.0.1:8080/ + +The port can be changed in the conf file. diff --git a/moon_manager/conf/moon.yaml b/moon_manager/conf/moon.yaml new file mode 100644 index 00000000..6bf0ec14 --- /dev/null +++ b/moon_manager/conf/moon.yaml @@ -0,0 +1,108 @@ +debug: true + +database: + # url: mysql+pymysql://moon:p4sswOrd1@db/moon + url: sqlite:////tmp/database.db + driver: moon_manager.plugins.sql + migration_dir: moon_manager.api.db.migrations + # migration_dir: /home/tom/projets/moon/moon_manager/moon_manager/api/db/migrations/ + +dashboard: + root: ../dashboard/moon_ui/dist/ + pid_filename: /tmp/moon_web_ui.pid + port: 8080 + +management: + url: http://127.0.0.1:8000 + user: admin + password: admin + token_file: moon.pwd + pid_file: /tmp/moon.pid + +orchestration: + driver: moon_manager.plugins.pyorchestrator + connection: local + # driver: moon_manager.plugins.docker_compose + # connection: ssh://admin:admin@1.1.1.1 + # driver: moon_manager.plugins.kubernetes + # connection: ~/.kube/config + port: 10000...10100 + config_dir: /tmp + +information: + user: admin + password: p4ssw0rd + domain: default + project: admin + check_token: false + certificate: false + url: http://keystone:5000/v3 + subjects: + drivers: + moon_manager.plugins.moon_keystone_plugin: + url: http://keystone:5000/v3 + objects: + drivers: + moon_manager.plugins.moon_nova_plugin: + url: http://keystone:5000/compute/v2.1 + + daemon: + pid_file: /tmp/daemon.pid + log_file: /tmp/daemon.log + + global_attrs: + driver: moon_manager.plugins.global_attrs + attributes: + mode: + values: + - build + - run + default: build + url: file:/etc/moon/mode + #url: https://127.0.0.1:8080/mode + #url: mysql+pymysql://moon:p4sswOrd1@db/moon_mode + #url: sqlite:////tmp/database.db + #url: driver://moon_manager.plugins.my_plugin + +plugins: + directory: /var/moon/plugins + +components: + manager: + port: 8080 + bind: 0.0.0.0 + hostname: manager + +logging: + version: 1 + + formatters: + brief: + format: "%(levelname)s %(name)s %(message)-30s" + custom: + format: "%(asctime)-15s %(levelname)s %(name)s %(message)s" + + handlers: + console: + class : logging.StreamHandler + formatter: custom + level : INFO + stream : ext://sys.stdout + file: + class : logging.handlers.RotatingFileHandler + formatter: custom + level : DEBUG + filename: /tmp/moon.log + maxBytes: 1048576 + backupCount: 3 + + loggers: + moon: + level: DEBUG + handlers: [console, file] + propagate: no + + root: + level: ERROR + handlers: [console] + diff --git a/moon_manager/docs/test.rst b/moon_manager/docs/test.rst new file mode 100644 index 00000000..e69de29b diff --git a/moon_manager/moon_manager/__init__.py b/moon_manager/moon_manager/__init__.py index f0887748..0b23fdc3 100644 --- a/moon_manager/moon_manager/__init__.py +++ b/moon_manager/moon_manager/__init__.py @@ -1,6 +1,16 @@ -# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors -# This software is distributed under the terms and conditions of the 'Apache-2.0' -# license which can be found in the file 'LICENSE' in this package distribution -# or at 'http://www.apache.org/licenses/LICENSE-2.0'. +# Software Name: MOON -__version__ = "4.6.0" +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + +""" +Moon Manager is a component that manage the database of the platform. +""" + +__version__ = "0.9.1" diff --git a/moon_manager/moon_manager/__main__.py b/moon_manager/moon_manager/__main__.py index 4fed8d10..ee8ea46f 100644 --- a/moon_manager/moon_manager/__main__.py +++ b/moon_manager/moon_manager/__main__.py @@ -1,4 +1,232 @@ -from moon_manager.server import create_server +# Software Name: MOON -server = create_server() -server.run() +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +import logging +import sys +import os +import subprocess # nosec +from moon_utilities import auth_functions +from moon_manager.api import configuration +from moon_utilities.auth_functions import init_db +from moon_manager import daemon +import hug.interface + +LOGGER = logging.getLogger("moon.manager") +configuration.init_logging() + +_conf = configuration.get_configuration() +_conf["logging"]["loggers"]["moon"]["level"] = "WARNING" +configuration.set_configuration(_conf) + + +@hug.cli("start_manager") +def start_manager(): + """ start the manager """ + pid_filename = _conf["management"]["pid_file"] + _command = ["gunicorn", "moon_manager.server:__hug_wsgi__", "--threads", "5", + "--bind", "0.0.0.0:8000", "-D", "-p", pid_filename] + subprocess.Popen(_command, stdout=subprocess.PIPE, close_fds=True) # nosec + + +@hug.cli("stop_manager") +def stop_manager(): + """ stop the manager """ + pid_filename = _conf["management"]["pid_file"] + with open(pid_filename, 'r') as pid_file: + try: + pid = int(pid_file.read()) + except ValueError: + LOGGER.error("The pid found in {} is not valid".format(pid_filename)) + return + + os.kill(pid, 15) + + +@hug.cli("start_web") +def start_web(): + """ start the web gui """ + dist = _conf["dashboard"]["root"] + port = _conf["dashboard"]["port"] + pid_filename = _conf["dashboard"]["pid_filename"] + os.chdir(dist) + _command = ["serve", "-l", str(port)] + web_gui_proc = subprocess.Popen(_command, stdout=subprocess.PIPE, close_fds=True) # nosec + with open(pid_filename, 'w') as f: + f.write(str(web_gui_proc.pid)) + + +@hug.cli("stop_web") +def stop_web(): + """ stop the web gui """ + pid_filename = _conf["dashboard"]["pid_filename"] + with open(pid_filename, 'r') as pid_file: + try: + pid = int(pid_file.read()) + except ValueError: + LOGGER.error("The pid found in {} is not valid".format(pid_filename)) + return + + os.kill(pid, 15) + + +@hug.cli("start_all") +def start_all(): + """ start the manager and the auto-update service """ + start_manager() + daemon.run() + + +@hug.cli("stop_all") +def stop_all(): + """ stop the manager and the auto-update service """ + stop_manager() + daemon.stop() + + +def run(command=None): + if len(sys.argv) > 1: + if not command: + command = sys.argv[1] + # Note: delete the command argument because Hug CLI system read it + sys.argv.pop(1) + init_db(configuration.get_configuration("management").get("token_file")) + + if command == "conf": + configuration.get_configuration.interface.cli() + elif command == "db": + configuration.init_database.interface.cli() + elif command == "start_manager": + start_manager.interface.cli() + elif command == "stop_manager": + stop_manager.interface.cli() + elif command == "start_gui": + start_web.interface.cli() + elif command == "stop_gui": + stop_web.interface.cli() + elif command == "start_daemon": + daemon.run.interface.cli() + elif command == "stop_daemon": + daemon.stop.interface.cli() + elif command == "start_all": + start_all.interface.cli() + elif command == "stop_all": + stop_all.interface.cli() + elif command == "users": + from moon_manager.api import users + users.UsersAPI.cli() + elif command == "import": + configuration.import_json.interface.cli() + elif command == "slaves": + from moon_manager.api import slave + slave.SlavesAPI.cli() + elif command == "status": + from moon_manager.api import status + status.status.interface.cli() + elif command == "models": + from moon_manager.api import models + models.ModelsAPI.cli() + elif command == "pdp": + from moon_manager.api import pdp + pdp.PDPAPI.cli() + elif command == "policies": + from moon_manager.api import policy + policy.PoliciesAPI.cli() + elif command == "subjects": + from moon_manager.api import perimeter + perimeter.SubjectsAPI.cli() + elif command == "objects": + from moon_manager.api import perimeter + perimeter.ObjectsAPI.cli() + elif command == "actions": + from moon_manager.api import perimeter + perimeter.ActionsAPI.cli() + elif command == "subject_categories": + from moon_manager.api import meta_data + meta_data.SubjectCategoriesAPI.cli() + elif command == "object_categories": + from moon_manager.api import meta_data + meta_data.ObjectCategoriesAPI.cli() + elif command == "action_categories": + from moon_manager.api import meta_data + meta_data.ActionCategoriesAPI.cli() + elif command == "subject_data": + from moon_manager.api import data + data.SubjectDataAPI.cli() + elif command == "object_data": + from moon_manager.api import data + data.ObjectDataAPI.cli() + elif command == "action_data": + from moon_manager.api import data + data.ActionDataAPI.cli() + elif command == "subject_assignments": + from moon_manager.api import assignments + assignments.SubjectAssignmentsAPI.cli() + elif command == "object_assignments": + from moon_manager.api import assignments + assignments.ObjectAssignmentsAPI.cli() + elif command == "action_assignments": + from moon_manager.api import assignments + assignments.ActionAssignmentsAPI.cli() + elif command == "meta_rules": + from moon_manager.api import meta_rules + meta_rules.MetaRulesAPI.cli() + elif command == "rules": + from moon_manager.api import rules + rules.RulesAPI.cli() + elif command == "tests": + from moon_manager.api import checks + checks.ChecksAPI.cli() + elif command == "attrs": + from moon_manager.api import attributes + attributes.AttrsAPI.cli() + else: + LOGGER.critical("Unknown command {}".format(command)) + else: + # TODO: update the command management by using argparse + print("""Possible commands are: + - conf + - db + - start_manager + - stop_manager + - start_gui + - stop_gui + - start_daemon + - stop_daemon + - start_all + - stop_all + - users + - import + - slaves + - models + - pdp + - policies + - subject_data + - object_data + - action_data + - subjects + - objects + - actions + - subject_categories + - object_categories + - action_categories + - subject_assignments + - object_assignments + - action_assignments + - meta_rules + - rules + - tests + - attrs + """) + + +if __name__ == "__main__": + run() diff --git a/moon_manager/moon_manager/api/__init__.py b/moon_manager/moon_manager/api/__init__.py index e69de29b..bf70b330 100644 --- a/moon_manager/moon_manager/api/__init__.py +++ b/moon_manager/moon_manager/api/__init__.py @@ -0,0 +1,28 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +from falcon import HTTP_400, HTTP_401, HTTP_402, HTTP_403, HTTP_404, HTTP_405, \ + HTTP_406, HTTP_407, HTTP_408, HTTP_409, HTTP_500 + +ERROR_CODE = { + 400: HTTP_400, + 401: HTTP_401, + 402: HTTP_402, + 403: HTTP_403, + 404: HTTP_404, + 405: HTTP_405, + 406: HTTP_406, + 407: HTTP_407, + 408: HTTP_408, + 409: HTTP_409, + 500: HTTP_500 +} diff --git a/moon_manager/moon_manager/api/assignments.py b/moon_manager/moon_manager/api/assignments.py index 9bc54b2d..742a043b 100644 --- a/moon_manager/moon_manager/api/assignments.py +++ b/moon_manager/moon_manager/api/assignments.py @@ -1,78 +1,57 @@ -# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors -# This software is distributed under the terms and conditions of the 'Apache-2.0' -# license which can be found in the file 'LICENSE' in this package distribution -# or at 'http://www.apache.org/licenses/LICENSE-2.0'. +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + """ Assignments allow to connect data with elements of perimeter """ -import flask -from flask import request -from flask_restful import Resource +import hug import logging import requests -from python_moonutilities.security_functions import check_auth -from python_moondb.core import PolicyManager -from python_moonutilities.security_functions import validate_input - -__version__ = "4.3.2" - -logger = logging.getLogger("moon.manager.api." + __name__) - - -def invalidate_data_in_slaves( - policy_id, - perimeter_id, - category_id, - data_id): - slaves = requests.get("http://{}/slaves".format(request.host)).json().get("slaves") - for slave in slaves: - if not slave.get("configured", False): - continue - try: - update = requests.put("http://{}:{}/update".format( - slave.get("wrapper_name"), slave.get("internal_port")), - data={ - "policy_id": policy_id, - "perimeter_id": perimeter_id, - "category_id": category_id, - "data_id": data_id - }, - timeout=1 - ) - logger.info("result {} {}:{} = {}".format( - update.status_code, - slave.get("wrapper_name"), - slave.get("internal_port"), - update.text)) - except requests.exceptions.ConnectionError: - logger.warning("Cannot reach {}:{}".format(slave.get("wrapper_name"), slave.get("port"))) - - -class SubjectAssignments(Resource): +from moon_manager import db_driver as driver +from moon_utilities.security_functions import validate_input +from moon_manager.api import slave as slave_class +from moon_manager.api import configuration +from moon_manager.api import policy +from moon_manager.api import perimeter +from moon_manager.api import meta_data +from moon_manager.api import data +from moon_utilities.auth_functions import api_key_authentication, connect_from_env +from moon_utilities.invalided_functions import invalidate_assignment_in_slaves + +# from moon_manager.server import handle_exception, handle_custom_exceptions + +LOGGER = logging.getLogger("moon.manager.api." + __name__) + + +class SubjectAssignments(object): """ Endpoint for subject assignment requests """ - __urls__ = ( - "/policies//subject_assignments", - "/policies//subject_assignments/", - "/policies//subject_assignments/", - "/policies//subject_assignments//", - "/policies//subject_assignments///", - ) - - @validate_input("get", kwargs_state=[True, False, False, False, False]) - @check_auth - def get(self, uuid=None, perimeter_id=None, category_id=None, - data_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.get("/policies/{uuid}/subject_assignments", requires=api_key_authentication) + @hug.get("/policies/{uuid}/subject_assignments/{perimeter_id}", + requires=api_key_authentication) + @hug.get("/policies/{uuid}/subject_assignments/{perimeter_id}/{category_id}", + requires=api_key_authentication) + def get(uuid: hug.types.text, perimeter_id: hug.types.text = None, + category_id: hug.types.text = None, authed_user: hug.directives.user = 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 (not used here) - :param user_id: user ID who do the request + :param authed_user: user ID who do the request :return: { "subject_data_id": { "policy_id": "ID of the policy", @@ -84,24 +63,22 @@ class SubjectAssignments(Resource): :internal_api: get_subject_assignments """ - data = PolicyManager.get_subject_assignments( - user_id=user_id, policy_id=uuid, + data = driver.PolicyManager.get_subject_assignments( + moon_user_id=authed_user, policy_id=uuid, subject_id=perimeter_id, category_id=category_id) return {"subject_assignments": data} - @validate_input("post", kwargs_state=[True, False, False, False, False], - body_state={"id": True, "category_id": True, "data_id": True}) - @check_auth - def post(self, uuid=None, perimeter_id=None, category_id=None, - data_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.post("/policies/{uuid}/subject_assignments", requires=api_key_authentication) + def post(body: validate_input("id", "category_id", "data_id"), uuid: hug.types.text, + authed_user: hug.directives.user = None): """Create a subject assignment. + :param body: body of the request :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 + :param authed_user: user ID who do the request :request body: { "id": "UUID of the subject (mandatory)", "category_id": "UUID of the category (mandatory)" @@ -117,32 +94,35 @@ class SubjectAssignments(Resource): } :internal_api: update_subject_assignment """ - 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) - invalidate_data_in_slaves( - policy_id=uuid, - perimeter_id=perimeter_id, - category_id=category_id, - data_id=data_id) + data_id = body.get("data_id") + category_id = body.get("category_id") + perimeter_id = body.get("id") + + data = driver.PolicyManager.add_subject_assignment( + moon_user_id=authed_user, policy_id=uuid, + subject_id=perimeter_id, category_id=category_id, data_id=data_id) return {"subject_assignments": data} - @validate_input("delete", kwargs_state=[True, True, True, True, False]) - @check_auth - def delete(self, uuid=None, perimeter_id=None, category_id=None, - data_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.delete("/policies/{uuid}/subject_assignments", requires=api_key_authentication) + @hug.delete("/policies/{uuid}/subject_assignments/{perimeter_id}", + requires=api_key_authentication) + @hug.delete("/policies/{uuid}/subject_assignments/{perimeter_id}/{category_id}", + requires=api_key_authentication) + @hug.delete("/policies/{uuid}/subject_assignments/{perimeter_id}/{category_id}/{data_id}", + requires=api_key_authentication) + def delete(uuid: hug.types.text, perimeter_id: hug.types.text = None, + category_id: hug.types.text = None, data_id: hug.types.text = None, + authed_user: hug.directives.user = 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 + :param authed_user: user ID who do the request :return: { "result": "True or False", "message": "optional message" @@ -150,43 +130,36 @@ class SubjectAssignments(Resource): :internal_api: delete_subject_assignment """ - data = PolicyManager.delete_subject_assignment( - user_id=user_id, policy_id=uuid, + driver.PolicyManager.delete_subject_assignment( + moon_user_id=authed_user, policy_id=uuid, subject_id=perimeter_id, category_id=category_id, data_id=data_id) - invalidate_data_in_slaves( - policy_id=uuid, - perimeter_id=perimeter_id, - category_id=category_id, - data_id=data_id) + slaves = slave_class.Slaves.get().get("slaves") + invalidate_assignment_in_slaves(slaves=slaves, policy_id=uuid, perimeter_id=perimeter_id, + category_id=category_id, data_id=data_id, type="subject") return {"result": True} -class ObjectAssignments(Resource): +class ObjectAssignments(object): """ Endpoint for object assignment requests """ - __urls__ = ( - "/policies//object_assignments", - "/policies//object_assignments/", - "/policies//object_assignments/", - "/policies//object_assignments//", - "/policies//object_assignments///", - ) - - @validate_input("get", kwargs_state=[True, False, False, False, False]) - @check_auth - def get(self, uuid=None, perimeter_id=None, category_id=None, - data_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.get("/policies/{uuid}/object_assignments", requires=api_key_authentication) + @hug.get("/policies/{uuid}/object_assignments/{perimeter_id}", requires=api_key_authentication) + @hug.get("/policies/{uuid}/object_assignments/{perimeter_id}/{category_id}", + requires=api_key_authentication) + def get(uuid: hug.types.text, perimeter_id: hug.types.text = None, + category_id: hug.types.text = None, authed_user: hug.directives.user = 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 (not used here) - :param user_id: user ID who do the request + :param authed_user: user ID who do the request :return: { "object_data_id": { "policy_id": "ID of the policy", @@ -198,24 +171,22 @@ class ObjectAssignments(Resource): :internal_api: get_object_assignments """ - data = PolicyManager.get_object_assignments( - user_id=user_id, policy_id=uuid, + data = driver.PolicyManager.get_object_assignments( + moon_user_id=authed_user, policy_id=uuid, object_id=perimeter_id, category_id=category_id) return {"object_assignments": data} - @validate_input("post", kwargs_state=[True, False, False, False, False], - body_state={"id": True, "category_id": True, "data_id": True}) - @check_auth - def post(self, uuid=None, perimeter_id=None, category_id=None, - data_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.post("/policies/{uuid}/object_assignments", requires=api_key_authentication) + def post(body: validate_input("id", "category_id", "data_id"), uuid, + authed_user: hug.directives.user = None): """Create an object assignment. + :param body: body of the request :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 + :param authed_user: user ID who do the request :request body: { "id": "UUID of the action (mandatory)", "category_id": "UUID of the category (mandatory)", @@ -232,75 +203,70 @@ class ObjectAssignments(Resource): :internal_api: update_object_assignment """ - 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) - invalidate_data_in_slaves( - policy_id=uuid, - perimeter_id=perimeter_id, - category_id=category_id, - data_id=data_id) + data_id = body.get("data_id") + category_id = body.get("category_id") + perimeter_id = body.get("id") + data = driver.PolicyManager.add_object_assignment(moon_user_id=authed_user, policy_id=uuid, + object_id=perimeter_id, + category_id=category_id, data_id=data_id) return {"object_assignments": data} - @validate_input("delete", kwargs_state=[True, True, True, True, False]) - @check_auth - def delete(self, uuid=None, perimeter_id=None, category_id=None, - data_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.delete("/policies/{uuid}/object_assignments", requires=api_key_authentication) + @hug.delete("/policies/{uuid}/object_assignments/{perimeter_id}", + requires=api_key_authentication) + @hug.delete("/policies/{uuid}/object_assignments/{perimeter_id}/{category_id}", + requires=api_key_authentication) + @hug.delete("/policies/{uuid}/object_assignments/{perimeter_id}/{category_id}/{data_id}", + requires=api_key_authentication) + def delete(uuid: hug.types.text, perimeter_id: hug.types.text = None, + category_id: hug.types.text = None, data_id: hug.types.text = None, + authed_user: hug.directives.user = 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 + :param authed_user: user ID who do the request :return: { "result": "True or False", "message": "optional message" } :internal_api: delete_object_assignment """ - data = PolicyManager.delete_object_assignment( - user_id=user_id, policy_id=uuid, - object_id=perimeter_id, category_id=category_id, - data_id=data_id) - invalidate_data_in_slaves( - policy_id=uuid, - perimeter_id=perimeter_id, - category_id=category_id, - data_id=data_id) + driver.PolicyManager.delete_object_assignment( + moon_user_id=authed_user, policy_id=uuid, object_id=perimeter_id, + category_id=category_id, data_id=data_id) + + slaves = slave_class.Slaves.get().get("slaves") + invalidate_assignment_in_slaves(slaves=slaves, policy_id=uuid, perimeter_id=perimeter_id, + category_id=category_id, data_id=data_id, type="object") return {"result": True} -class ActionAssignments(Resource): +class ActionAssignments(object): """ Endpoint for action assignment requests """ - __urls__ = ( - "/policies//action_assignments", - "/policies//action_assignments/", - "/policies//action_assignments/", - "/policies//action_assignments//", - "/policies//action_assignments///", - ) - - @validate_input("get", kwargs_state=[True, False, False, False, False]) - @check_auth - def get(self, uuid=None, perimeter_id=None, category_id=None, - data_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.get("/policies/{uuid}/action_assignments", requires=api_key_authentication) + @hug.get("/policies/{uuid}/action_assignments/{perimeter_id}", requires=api_key_authentication) + @hug.get("/policies/{uuid}/action_assignments/{perimeter_id}/{category_id}", + requires=api_key_authentication) + def get(uuid: hug.types.text, perimeter_id: hug.types.text = None, + category_id: hug.types.text = None, authed_user: hug.directives.user = 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 + :param authed_user: user ID who do the request :return: { "action_data_id": { "policy_id": "ID of the policy", @@ -311,24 +277,22 @@ class ActionAssignments(Resource): } :internal_api: get_action_assignments """ - data = PolicyManager.get_action_assignments( - user_id=user_id, policy_id=uuid, + data = driver.PolicyManager.get_action_assignments( + moon_user_id=authed_user, policy_id=uuid, action_id=perimeter_id, category_id=category_id) return {"action_assignments": data} - @validate_input("post", kwargs_state=[True, False, False, False, False], - body_state={"id": True, "category_id": True, "data_id": True}) - @check_auth - def post(self, uuid=None, perimeter_id=None, category_id=None, - data_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.post("/policies/{uuid}/action_assignments", requires=api_key_authentication) + def post(body: validate_input("id", "category_id", "data_id"), uuid, + authed_user: hug.directives.user = None): """Create an action assignment. + :param body: body of the request :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 + :param authed_user: user ID who do the request :request body: { "id": "UUID of the action (mandatory)", "category_id": "UUID of the category (mandatory)", @@ -345,32 +309,34 @@ class ActionAssignments(Resource): :internal_api: update_action_assignment """ - 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) - invalidate_data_in_slaves( - policy_id=uuid, - perimeter_id=perimeter_id, - category_id=category_id, - data_id=data_id) + data_id = body.get("data_id") + category_id = body.get("category_id") + perimeter_id = body.get("id") + data = driver.PolicyManager.add_action_assignment( + moon_user_id=authed_user, policy_id=uuid, + action_id=perimeter_id, category_id=category_id, data_id=data_id) return {"action_assignments": data} - @validate_input("delete", kwargs_state=[True, True, True, True, False]) - @check_auth - def delete(self, uuid=None, perimeter_id=None, category_id=None, - data_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.delete("/policies/{uuid}/action_assignments", requires=api_key_authentication) + @hug.delete("/policies/{uuid}/action_assignments/{perimeter_id}", + requires=api_key_authentication) + @hug.delete("/policies/{uuid}/action_assignments/{perimeter_id}/{category_id}", + requires=api_key_authentication) + @hug.delete("/policies/{uuid}/action_assignments/{perimeter_id}/{category_id}/{data_id}", + requires=api_key_authentication) + def delete(uuid: hug.types.text, perimeter_id: hug.types.text = None, + category_id: hug.types.text = None, data_id: hug.types.text = None, + authed_user: hug.directives.user = 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 + :param authed_user: user ID who do the request :return: { "result": "True or False", "message": "optional message" @@ -378,14 +344,401 @@ class ActionAssignments(Resource): :internal_api: delete_action_assignment """ - data = PolicyManager.delete_action_assignment( - user_id=user_id, policy_id=uuid, - action_id=perimeter_id, category_id=category_id, - data_id=data_id) - invalidate_data_in_slaves( - policy_id=uuid, - perimeter_id=perimeter_id, - category_id=category_id, - data_id=data_id) + driver.PolicyManager.delete_action_assignment( + moon_user_id=authed_user, policy_id=uuid, + action_id=perimeter_id, category_id=category_id, data_id=data_id) + + slaves = slave_class.Slaves.get().get("slaves") + invalidate_assignment_in_slaves(slaves=slaves, policy_id=uuid, perimeter_id=perimeter_id, + category_id=category_id, data_id=data_id, type="action") return {"result": True} + + +SubjectAssignmentsAPI = hug.API(name='subject_assignments', doc=SubjectAssignments.__doc__) +ObjectAssignmentsAPI = hug.API(name='object_assignments', doc=ObjectAssignments.__doc__) +ActionAssignmentsAPI = hug.API(name='action_assignments', doc=ActionAssignments.__doc__) + + +@hug.object(name='subjects', version='1.0.0', api=SubjectAssignmentsAPI) +class SubjectAssignmentsCLI(object): + """An example of command like calls via an Object""" + + @staticmethod + @hug.object.cli + def list(policy_name_or_id, name_or_id="", human: bool = False): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + policy_id = list(policy.PoliciesCLI.list(policy_name_or_id).get("policies").keys())[0] + _assignments_req = requests.get("{}/policies/{}/subject_assignments".format( + db_conf.get("url"), policy_id), + headers={"x-api-key": manager_api_key} + ) + _assignment_key = None + if _assignments_req.status_code == 200: + _subject_assignments = _assignments_req.json().get("subject_assignments") + if name_or_id: + _assignments = None + if name_or_id in _subject_assignments: + _assignments = _subject_assignments.get(name_or_id) + _assignment_key = name_or_id + else: + for _key in _subject_assignments: + try: + _subject = perimeter.SubjectsCLI.list(name_or_id).get("subjects")[0] + _subject_key = list(_subject.keys())[0] + except Exception as e: + # FIXME: should upgrade this exception + LOGGER.exception(e) + continue + else: + if _subject_assignments.get(_key).get("subject_id") == _subject_key: + _assignments = _subject_assignments.get(_key) + _assignment_key = _key + break + if not _assignments: + raise Exception("Cannot find Subject Assignments with ID {}".format(name_or_id)) + result = {"subject_assignments": [{_assignment_key: _assignments}]} + else: + result = _assignments_req.json() + + if human: + return SubjectAssignmentsCLI.human_display(result) + else: + return result + LOGGER.error('Cannot list Subject Assignments {}'.format(_assignments_req.status_code)) + + @staticmethod + @hug.object.cli + def add(policy_name_or_id, perimeter_name_or_id, category_name_or_id, data_name_or_id, human: bool = False): + """ + Add subject assignment in database + :return: JSON status output + """ + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + policy_id = list(policy.PoliciesCLI.list(policy_name_or_id).get("policies").keys())[0] + perimeter_id = list(perimeter.SubjectsCLI.list(perimeter_name_or_id).get("subjects")[0].keys())[0] + category_id = list(meta_data.SubjectCategoriesCLI.list(category_name_or_id).get("subject_categories").keys())[0] + data_id = data.SubjectDataCLI.list(policy_id, data_name_or_id).get("subject_data").get("id") + _url = "{}/policies/{}/subject_assignments".format(db_conf.get("url"), policy_id) + + _assignments = requests.post( + _url, + json={ + "id": perimeter_id, + "category_id": category_id, + "data_id": data_id, + }, + headers={ + "x-api-key": manager_api_key, + "Content-Type": "application/json" + } + ) + if _assignments.status_code == 200: + LOGGER.warning('Create {}'.format(_assignments.content)) + if human: + return SubjectAssignmentsCLI.human_display(_assignments.json()) + else: + return _assignments.json() + LOGGER.error('Cannot create assignment for {}/{}/{} ({})'.format( + perimeter_name_or_id, category_name_or_id, data_name_or_id, _assignments.content[:40])) + LOGGER.error("{}/{}/{}".format(perimeter_id, category_id, data_id)) + + @staticmethod + @hug.object.cli + def delete(policy_name_or_id, perimeter_name_or_id, category_name_or_id, data_name_or_id): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + policy_id = list(policy.PoliciesCLI.list(policy_name_or_id).get("policies").keys())[0] + perimeter_id = list(perimeter.SubjectsCLI.list(perimeter_name_or_id).get("subjects")[0].keys())[0] + category_id = list(meta_data.SubjectCategoriesCLI.list(category_name_or_id).get("subject_categories").keys())[0] + data_id = data.SubjectDataCLI.list(policy_id, data_name_or_id).get("subject_data").get("id") + _url = "{}/policies/{}/subject_assignments/{}/{}/{}".format( + db_conf.get("url"), + policy_id, + perimeter_id, + category_id, + data_id) + req = requests.delete( + _url, + headers={"x-api-key": manager_api_key} + ) + if req.status_code == 200: + LOGGER.warning('Deleted {}-{}-{}-{}'.format( + policy_name_or_id, perimeter_name_or_id, category_name_or_id, data_name_or_id)) + return True + LOGGER.error("Cannot delete Assignment with {}-{}-{}-{}".format( + policy_name_or_id, perimeter_name_or_id, category_name_or_id, data_name_or_id + )) + return False + + @staticmethod + def human_display(subject_assigment_json): + human_result = "Subject Assignments" + for subject_assignment in subject_assigment_json.get("subject_assignments"): + human_result += "\n" + subject_assigment_json.get("subject_assignments").get(subject_assignment).get("id") + "\n" + human_result += "\tid : " + subject_assigment_json.get("subject_assignments").get(subject_assignment).get("id") + "\n" + human_result += "\tpolicy_id : " + subject_assigment_json.get("subject_assignments").get(subject_assignment).get("policy_id") + "\n" + human_result += "\tsubject_id : " + subject_assigment_json.get("subject_assignments").get(subject_assignment).get("subject_id") + "\n" + human_result += "\tcategory_id : " + subject_assigment_json.get("subject_assignments").get(subject_assignment).get("category_id") + "\n" + human_result += "\tassignments : \n" + for assignment in subject_assigment_json.get("subject_assignments").get(subject_assignment).get("assignments"): + human_result += "\t\t" + assignment + "\n" + return human_result + + +@hug.object(name='objects', version='1.0.0', api=ObjectAssignmentsAPI) +class ObjectAssignmentsCLI(object): + """An example of command like calls via an Object""" + + @staticmethod + @hug.object.cli + def list(policy_name_or_id, name_or_id="", human: bool = False): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + policy_id = list(policy.PoliciesCLI.list(policy_name_or_id).get("policies").keys())[0] + _assignments_req = requests.get("{}/policies/{}/object_assignments".format( + db_conf.get("url"), policy_id), + headers={"x-api-key": manager_api_key} + ) + _assignment_key = None + if _assignments_req.status_code == 200: + _object_assignments = _assignments_req.json().get("object_assignments") + if name_or_id: + _assignments = None + if name_or_id in _object_assignments: + _assignments = _object_assignments.get(name_or_id) + _assignment_key = name_or_id + else: + for _key in _object_assignments: + try: + _object = perimeter.ObjectsCLI.list(name_or_id).get("objects")[0] + _object_key = list(_object.keys())[0] + except Exception as e: + # FIXME: should upgrade this exception + LOGGER.exception(e) + continue + else: + if _object_assignments.get(_key).get("object_id") == _object_key: + _assignments = _object_assignments.get(_key) + _assignment_key = _key + break + if not _assignments: + raise Exception("Cannot find Object Assignments with ID {}".format(name_or_id)) + result = {"object_assignments": [{_assignment_key: _assignments}]} + else: + result = _assignments_req.json() + + if human: + return ObjectAssignmentsCLI.human_display(result) + else: + return result + LOGGER.error('Cannot list Object Assignments {}'.format(_assignments_req.status_code)) + + @staticmethod + @hug.object.cli + def add(policy_name_or_id, perimeter_name_or_id, category_name_or_id, data_name_or_id, human: bool = False): + """ + Add object assignment in database + :return: JSON status output + """ + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + policy_id = list(policy.PoliciesCLI.list(policy_name_or_id).get("policies").keys())[0] + perimeter_id = list(perimeter.ObjectsCLI.list(perimeter_name_or_id).get("objects")[0].keys())[0] + category_id = list(meta_data.ObjectCategoriesCLI.list(category_name_or_id).get("object_categories").keys())[0] + data_id = data.ObjectDataCLI.list(policy_id, data_name_or_id).get("object_data").get("id") + _url = "{}/policies/{}/object_assignments".format(db_conf.get("url"), policy_id) + + _assignments = requests.post( + _url, + json={ + "id": perimeter_id, + "category_id": category_id, + "data_id": data_id, + }, + headers={ + "x-api-key": manager_api_key, + "Content-Type": "application/json" + } + ) + if _assignments.status_code == 200: + LOGGER.warning('Create {}'.format(_assignments.content)) + if human: + return ObjectAssignmentsCLI.human_display(_assignments.json()) + else: + return _assignments.json() + LOGGER.error('Cannot create assignment for {}/{}/{} ({})'.format( + perimeter_name_or_id, category_name_or_id, data_name_or_id, _assignments.content[:40])) + LOGGER.error("{}/{}/{}".format(perimeter_id, category_id, data_id)) + + @staticmethod + @hug.object.cli + def delete(policy_name_or_id, perimeter_name_or_id, category_name_or_id, data_name_or_id): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + policy_id = list(policy.PoliciesCLI.list(policy_name_or_id).get("policies").keys())[0] + perimeter_id = list(perimeter.ObjectsCLI.list(perimeter_name_or_id).get("objects")[0].keys())[0] + category_id = list(meta_data.ObjectCategoriesCLI.list(category_name_or_id).get("object_categories").keys())[0] + data_id = data.ObjectDataCLI.list(policy_id, data_name_or_id).get("object_data").get("id") + _url = "{}/policies/{}/object_assignments/{}/{}/{}".format( + db_conf.get("url"), + policy_id, + perimeter_id, + category_id, + data_id) + req = requests.delete( + _url, + headers={"x-api-key": manager_api_key} + ) + if req.status_code == 200: + LOGGER.warning('Deleted {}-{}-{}-{}'.format( + policy_name_or_id, perimeter_name_or_id, category_name_or_id, data_name_or_id)) + return True + LOGGER.error("Cannot delete Assignment with {}-{}-{}-{}".format( + policy_name_or_id, perimeter_name_or_id, category_name_or_id, data_name_or_id + )) + return False + + @staticmethod + def human_display(object_assigment_json): + human_result = "Object Assignments" + for object_assignment in object_assigment_json.get("object_assignments"): + human_result += "\n" + object_assigment_json.get("object_assignments").get(object_assignment).get("id") + "\n" + human_result += "\tid : " + object_assigment_json.get("object_assignments").get(object_assignment).get("id") + "\n" + human_result += "\tpolicy_id : " + object_assigment_json.get("object_assignments").get(object_assignment).get("policy_id") + "\n" + human_result += "\tobject_id : " + object_assigment_json.get("object_assignments").get(object_assignment).get("object_id") + "\n" + human_result += "\tcategory_id : " + object_assigment_json.get("object_assignments").get(object_assignment).get("category_id") + "\n" + human_result += "\tassignments : \n" + for assignment in object_assigment_json.get("object_assignments").get(object_assignment).get("assignments"): + human_result += "\t\t" + assignment + "\n" + return human_result + + +@hug.object(name='actions', version='1.0.0', api=ActionAssignmentsAPI) +class ActionAssignmentsCLI(object): + """An example of command like calls via an Action""" + + @staticmethod + @hug.object.cli + def list(policy_name_or_id, name_or_id="", human: bool = False): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + policy_id = list(policy.PoliciesCLI.list(policy_name_or_id).get("policies").keys())[0] + _assignments_req = requests.get("{}/policies/{}/action_assignments".format( + db_conf.get("url"), policy_id), + headers={"x-api-key": manager_api_key} + ) + _assignment_key = None + if _assignments_req.status_code == 200: + _action_assignments = _assignments_req.json().get("action_assignments") + if name_or_id: + _assignments = None + if name_or_id in _action_assignments: + _assignments = _action_assignments.get(name_or_id) + _assignment_key = name_or_id + else: + for _key in _action_assignments: + try: + _action = perimeter.ActionsCLI.list(name_or_id).get("actions")[0] + _action_key = list(_action.keys())[0] + except Exception as e: + # FIXME: should upgrade this exception + LOGGER.exception(e) + continue + else: + if _action_assignments.get(_key).get("action_id") == _action_key: + _assignments = _action_assignments.get(_key) + _assignment_key = _key + break + if not _assignments: + raise Exception("Cannot find Action Assignments with ID {}".format(name_or_id)) + result = {"action_assignments": [{_assignment_key: _assignments}]} + else: + result = _assignments_req.json() + + if human: + return ActionAssignmentsCLI.human_display(result) + else: + return result + LOGGER.error('Cannot list Action Assignments {}'.format(_assignments_req.status_code)) + + @staticmethod + @hug.object.cli + def add(policy_name_or_id, perimeter_name_or_id, category_name_or_id, data_name_or_id, human: bool = False): + """ + Add action assignment in database + :return: JSON status output + """ + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + policy_id = list(policy.PoliciesCLI.list(policy_name_or_id).get("policies").keys())[0] + perimeter_id = list(perimeter.ActionsCLI.list(perimeter_name_or_id).get("actions")[0].keys())[0] + category_id = list(meta_data.ActionCategoriesCLI.list(category_name_or_id).get("action_categories").keys())[0] + data_id = data.ActionDataCLI.list(policy_id, data_name_or_id).get("action_data").get("id") + _url = "{}/policies/{}/action_assignments".format(db_conf.get("url"), policy_id) + + _assignments = requests.post( + _url, + json={ + "id": perimeter_id, + "category_id": category_id, + "data_id": data_id, + }, + headers={ + "x-api-key": manager_api_key, + "Content-Type": "application/json" + } + ) + if _assignments.status_code == 200: + LOGGER.warning('Create {}'.format(_assignments.content)) + if human: + return ActionAssignmentsCLI.human_display(_assignments.json()) + else: + return _assignments.json() + LOGGER.error('Cannot create assignment for {}/{}/{} ({})'.format( + perimeter_name_or_id, category_name_or_id, data_name_or_id, _assignments.content[:40])) + LOGGER.error("{}/{}/{}".format(perimeter_id, category_id, data_id)) + + @staticmethod + @hug.object.cli + def delete(policy_name_or_id, perimeter_name_or_id, category_name_or_id, data_name_or_id): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + policy_id = list(policy.PoliciesCLI.list(policy_name_or_id).get("policies").keys())[0] + perimeter_id = list(perimeter.ActionsCLI.list(perimeter_name_or_id).get("actions")[0].keys())[0] + category_id = list(meta_data.ActionCategoriesCLI.list(category_name_or_id).get("action_categories").keys())[0] + data_id = data.ActionDataCLI.list(policy_id, data_name_or_id).get("action_data").get("id") + _url = "{}/policies/{}/action_assignments/{}/{}/{}".format( + db_conf.get("url"), + policy_id, + perimeter_id, + category_id, + data_id) + req = requests.delete( + _url, + headers={"x-api-key": manager_api_key} + ) + if req.status_code == 200: + LOGGER.warning('Deleted {}-{}-{}-{}'.format( + policy_name_or_id, perimeter_name_or_id, category_name_or_id, data_name_or_id)) + return True + LOGGER.error("Cannot delete Assignment with {}-{}-{}-{}".format( + policy_name_or_id, perimeter_name_or_id, category_name_or_id, data_name_or_id + )) + return False + + @staticmethod + def human_display(action_assigment_json): + human_result = "Action Assignments" + for action_assignment in action_assigment_json.get("action_assignments"): + human_result += "\n" + action_assigment_json.get("action_assignments").get(action_assignment).get("id") + "\n" + human_result += "\tid : " + action_assigment_json.get("action_assignments").get(action_assignment).get("id") + "\n" + human_result += "\tpolicy_id : " + action_assigment_json.get("action_assignments").get(action_assignment).get("policy_id") + "\n" + human_result += "\taction_id : " + action_assigment_json.get("action_assignments").get(action_assignment).get("action_id") + "\n" + human_result += "\tcategory_id : " + action_assigment_json.get("action_assignments").get(action_assignment).get("category_id") + "\n" + human_result += "\tassignments : \n" + for assignment in action_assigment_json.get("action_assignments").get(action_assignment).get("assignments"): + human_result += "\t\t" + assignment + "\n" + return human_result diff --git a/moon_manager/moon_manager/api/attributes.py b/moon_manager/moon_manager/api/attributes.py new file mode 100644 index 00000000..4e5cb282 --- /dev/null +++ b/moon_manager/moon_manager/api/attributes.py @@ -0,0 +1,207 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + +""" +Global attributes allow to save a specific piece of information inside Moon + +""" + +import logging +import hug +import requests +from moon_manager.api import ERROR_CODE +# from moon_manager import db_driver +# from moon_manager import orchestration_driver +from moon_manager import pip_driver +from moon_manager.api import configuration +from moon_utilities import exceptions +from moon_utilities.auth_functions import init_db, api_key_authentication, connect_from_env +from moon_manager.api import slave as slave_class +from moon_utilities.invalided_functions import invalidate_attributes_in_slaves + +LOGGER = logging.getLogger("moon.manager.api." + __name__) + + +class Attributes(object): + """ + Endpoint for attributes requests + """ + + @staticmethod + @hug.local() + @hug.get("/attributes/", requires=api_key_authentication) + @hug.get("/attributes/{name}", requires=api_key_authentication) + def get(name: str = None, authed_user: hug.directives.user = None): + """Retrieve all attributes + + :param name: name of the attribute + :param authed_user: the name of the authenticated user + :return: { + "attributes": { + "id": "name", + "value": "value1", + "values": ["value1", "value2"], + "default": "value2" + }, + { + "id": "name2", + "value": "value4", + "values": ["value4", "value"3"], + "default": "value3" + } + } + } + """ + if not name: + data = pip_driver.AttrsManager.get_objects(moon_user_id=authed_user, object_type=name) + else: + data = pip_driver.AttrsManager.get_object(moon_user_id=authed_user, object_type=name) + return {"attributes": data} + + @staticmethod + @hug.local() + @hug.put("/attributes/{name}/{value}", requires=api_key_authentication) + def put(name: str, value: str, authed_user: hug.directives.user = None): + """Initialize an attribute. + + :param name: name of the attribute + :param value: value of the attribute + :param authed_user: the name of the authenticated user + :return: { + "attributes": { + "name": "value1" + "values": ["value1", "value2"], + "default": "value2" + }, + { + "name": "value3" + "values": ["value4", "value"3"], + "default": "value3" + } + } + } + """ + data = pip_driver.AttrsManager.update_object(moon_user_id=authed_user, + object_id=value, + object_type=name) + slaves = slave_class.Slaves.get().get("slaves") + ret = invalidate_attributes_in_slaves( + slaves, + name) + return {"attributes": data} + + @staticmethod + @hug.local() + @hug.delete("/attributes/{name}", requires=api_key_authentication) + def delete(name: str, authed_user: hug.directives.user = None): + """Re-initialize an attribute + + :param name: the name of the attribute + :param authed_user: the name of the authenticated user + :return: { + "result": "True or False", + "message": "optional message (optional)" + } + """ + data = pip_driver.AttrsManager.add_object(moon_user_id=authed_user, object_type=name) + return {"attributes": data} + + +AttrsAPI = hug.API(name='attributes', doc=Attributes.__doc__) +db_conf = configuration.get_configuration(key='management') +init_db(db_conf.get("token_file")) + + +@hug.object(name='attributes', version='1.0.0', api=AttrsAPI) +class AttributesCLI(object): + """An example of command like calls via an Object""" + + @staticmethod + @hug.object.cli + def get(name): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _attrs = requests.get("{}/attributes/{}".format(db_conf.get("url"), name), + headers={"x-api-key": manager_api_key} + ) + if _attrs.status_code == 200: + return _attrs.json() + else: + LOGGER.error("An error occurs ({}): {}...".format(_attrs.status_code, _attrs.text[:80])) + + @staticmethod + @hug.object.cli + def list(human: bool = False): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _attrs = requests.get("{}/attributes".format(db_conf.get("url")), + headers={"x-api-key": manager_api_key} + ) + if _attrs.status_code == 200: + if human: + return AttributesCLI.human_display(_attrs.json()) + else: + return _attrs.json() + else: + LOGGER.error("An error occurs ({}): {}...".format(_attrs.status_code, _attrs.text[:80])) + + @staticmethod + def human_display(attributes_json): + human_result = "Attributes" + for attribute in attributes_json.get("attributes"): + human_result += "\n" + attribute + "\n" + human_result += "\tid : " + attributes_json.get("attributes").get(attribute).get("id") + "\n" + human_result += "\tvalue :" + attributes_json.get("attributes").get(attribute).get("value") + "\n" + human_result += "\tvalues : \n" + for value in attributes_json.get("attributes").get(attribute).get("values"): + human_result += "\t\t" + value + "\n" + human_result += "\tdefault :" + attributes_json.get("attributes").get(attribute).get("default") + "\n" + return human_result + + @staticmethod + @hug.object.cli + def init(name): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _attrs = requests.delete("{}/attributes/{}".format(db_conf.get("url"), name), + headers={"x-api-key": manager_api_key} + ) + if _attrs.status_code == 200: + return _attrs.json() + else: + LOGGER.error("An error occurs ({}): {}...".format(_attrs.status_code, _attrs.text[:80])) + + @staticmethod + @hug.object.cli + def set(name, value): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _attrs = requests.put("{}/attributes/{}/{}".format(db_conf.get("url"), name, value), + headers={"x-api-key": manager_api_key} + ) + if _attrs.status_code == 200: + return _attrs.json() + else: + LOGGER.error("An error occurs ({}): {}...".format(_attrs.status_code, _attrs.text[:80])) + + @staticmethod + @hug.object.cli + def delete(name): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _attrs = requests.delete("{}/attributes/{}".format(db_conf.get("url"), name), + headers={"x-api-key": manager_api_key} + ) + if _attrs.status_code == 200: + return _attrs.json() + else: + LOGGER.error("An error occurs ({}): {}...".format(_attrs.status_code, _attrs.text[:80])) + diff --git a/moon_manager/moon_manager/api/auth.py b/moon_manager/moon_manager/api/auth.py new file mode 100644 index 00000000..a60fd727 --- /dev/null +++ b/moon_manager/moon_manager/api/auth.py @@ -0,0 +1,42 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +"""Auth API""" +from falcon import HTTP_204, HTTP_400 +import hug +import logging +from moon_utilities.auth_functions import basic_authentication, api_key_authentication +from moon_utilities.auth_functions import get_api_key_for_user, del_api_key_for_user + +logger = logging.getLogger("moon.manager.api.status") + + +@hug.get("/auth/", requires=basic_authentication) +def get_api_key(authed_user: hug.directives.user = None): + """ + Get API key + :return: API key + """ + return get_api_key_for_user(authed_user) + + +@hug.delete("/auth/", requires=api_key_authentication) +def del_api_key(response, authed_user: hug.directives.user = None): + """ + Delete API key + :return: None + """ + if del_api_key_for_user(authed_user): + response.status = HTTP_204 + else: + response.status = HTTP_400 + return diff --git a/moon_manager/moon_manager/api/base_exception.py b/moon_manager/moon_manager/api/base_exception.py deleted file mode 100644 index 0a414a59..00000000 --- a/moon_manager/moon_manager/api/base_exception.py +++ /dev/null @@ -1,17 +0,0 @@ -class BaseException(Exception): - def __init__(self, message): - self._code = 500 - self._message = message - # Call the base class constructor with the parameters it needs - super(BaseException, self).__init__(message) - - @property - def code(self): - return self._code - - @property - def message(self): - return self._message - - def __str__(self): - return "Error " + str(self._code) + " " + self.__class__.__name__ + ': ' + self.message diff --git a/moon_manager/moon_manager/api/checks.py b/moon_manager/moon_manager/api/checks.py new file mode 100644 index 00000000..bc44b905 --- /dev/null +++ b/moon_manager/moon_manager/api/checks.py @@ -0,0 +1,211 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + +""" +Run tests from a Moon policy file. +""" + +import json +import logging +import time +import requests +import hug +import sys +from moon_manager.api import configuration +from moon_manager.api import pdp + +LOGGER = logging.getLogger("moon.manager.api." + __name__) +ChecksAPI = hug.API(name='checks', doc=__doc__) +if sys.version_info[0] == 2: + raise Exception("Using Python2 is not secure enough!") + + +@hug.object(name='rules', version='1.0.0', api=ChecksAPI) +class ChecksCLI(object): + """An example of command like calls via an Object""" + + verbose = False + output_file = None + pipeline_data = {} + + @staticmethod + def launch_standalone_pipeline(endpoint, policy_file): + LOGGER.info("Launching Engine for a self test...") + from moon_engine.plugins import pyorchestrator + from uuid import uuid4 + import subprocess # nosec (command attribute is safe) + host = endpoint.replace("http://", "").split(":")[0] + port = endpoint.split(":")[2].split("/")[0] + _uuid = uuid4().hex + gunicorn_config = pyorchestrator.create_gunicorn_config( + host, port, server_type="pipeline", uuid=_uuid) + pyorchestrator.create_moon_config(_uuid, False, policy_file) + pid_file = _uuid + ".pid" + command = ["gunicorn", "moon_engine.server:__hug_wsgi__", "--threads", "10", + "-p", pid_file, "-D", "-c", gunicorn_config] + LOGGER.info("Executing {}".format(" ".join(command))) + subprocess.Popen(command, stdout=subprocess.PIPE, close_fds=True) # nosec + # (command attribute is safe) + ChecksCLI.pipeline_data["pid_file"] = pid_file + ChecksCLI.pipeline_data["gunicorn_config"] = gunicorn_config + time.sleep(2) + + @staticmethod + def kill_standalone_pipeline(): + import os + pid = int(open(ChecksCLI.pipeline_data["pid_file"]).read()) + os.kill(pid, 15) + + @staticmethod + def log(message, color="", force_console=False): + """ + Send application logs to conole and output file + :param message: the message to send + :param color: optionally the color in the console + :param force_console: if the message should be always send in the console + :return: None + """ + if ChecksCLI.verbose or force_console: + if color: + print("\033[" + color + "m" + message + "\033[m") + else: + print(message) + if ChecksCLI.output_file: + open(ChecksCLI.output_file, "a").write(message + "\n") + + @staticmethod + def run_tests(endpoint, vim_project_id, test_list, status_code, test_number): + """ + Run the tests given + :param endpoint: the endpoint to send the requests + :param vim_project_id: the tested project ID + :param test_list: the list of tests to run + :param status_code: the expected status code + :param test_number: the number of tests to run + :return: + """ + cpt = 0 + bad_response = 0 + good_response = 0 + start_time = time.time() + for test in test_list: + if test_number and cpt > test_number: + break + if vim_project_id: + url = "{endpoint}/{project_id}/{subject_name}/{object_name}/{action_name}".format( + endpoint=endpoint, + project_id=vim_project_id, + subject_name=test[0], + object_name=test[1], + action_name=test[2], + ) + else: + url = "{endpoint}/{subject_name}/{object_name}/{action_name}".format( + endpoint=endpoint, + subject_name=test[0], + object_name=test[1], + action_name=test[2], + ) + req = requests.get(url) + cpt += 1 + ChecksCLI.log("Contacting {}".format(url)) + if isinstance(status_code, str): + status_code = (int(status_code), ) + if isinstance(status_code, int): + status_code = (status_code, ) + if req.status_code in status_code: + ChecksCLI.log("{} OK".format(", ".join(test))) + good_response += 1 + else: + ChecksCLI.log("{} KO ({}: {})".format(", ".join(test), req.status_code, req.text[:80]), + force_console=True) + bad_response += 1 + end_time = time.time() + return "Run {} tests ({} OK and {} KO) in {:.2f} seconds ({:.2f} req/s)".format( + cpt, good_response, bad_response, + end_time - start_time, cpt / (end_time - start_time)) + + @staticmethod + @hug.object.cli + def run(policy_file, + endpoint: str = "", + test_number: int = None, + verbose: bool = False, + output_file: str = None, + dont_kill_server: bool = False): + """ + Run tests given in a policy file + :param policy_file: the policy file which contains the tests + :param endpoint: the endpoint to test + :param test_number: the number of tests to run + :param verbose: set the verbosity + :param output_file: the name of the output file to send logs + :param dont_kill_server: do we have to kill the engine before quitting + :return: None + """ + ChecksCLI.output_file = output_file + ChecksCLI.verbose = verbose + ChecksCLI.log("Tests run on " + time.strftime("%Y/%m/%d %H:%M:%S"), + force_console=True, color="1") + if not endpoint: + _conf = configuration.get_configuration(key='management') + endpoint = "http://{}:10000/authz".format( + _conf['url'].replace("http://", "").split(":")[0]) + need_standalone_pipeline = False + try: + requests.get(endpoint) + except requests.exceptions.ConnectionError: + need_standalone_pipeline = True + ChecksCLI.launch_standalone_pipeline(endpoint, policy_file) + try: + _pdps = pdp.PDPCLI.list().get("pdps") + vim_project_ids = [] + for _project in _pdps.values(): + if _project.get("vim_project_id", "").strip(): + vim_project_ids.append(_project.get("vim_project_id", "").strip()) + except (requests.exceptions.ConnectionError, AttributeError): + vim_project_id = "" + else: + if len(vim_project_ids) > 1: + ChecksCLI.log("VIM Project ID:", force_console=True) + for project in vim_project_ids: + ChecksCLI.log(" - {}".format(project), force_console=True) + response = input("Choose a project ID in list: ") # nosec + # (forbidden use of Python2) + vim_project_id = response + else: + vim_project_id = vim_project_ids[0] + vim_project_id = vim_project_id.replace("/", "") + ChecksCLI.log("Using '{}' as project ID".format(vim_project_id), force_console=True) + ChecksCLI.log("Endpoint: {}".format(endpoint), force_console=True) + policy = json.loads(open(policy_file).read()) + if "checks" not in policy: + raise Exception("Cannot find checks attribute in {}".format(policy_file)) + endpoint = endpoint.strip('/') + ChecksCLI.log("Run grant tests", color="32", force_console=True) + output = "" + output += ChecksCLI.run_tests(endpoint, + vim_project_id, + policy['checks'].get("granted", []), + (200, 204), + test_number) + output += "\n" + ChecksCLI.log("Run deny tests", color="32", force_console=True) + output += ChecksCLI.run_tests(endpoint, + vim_project_id, + policy['checks'].get("denied", []), + 403, + test_number) + ChecksCLI.log(output, force_console=True, color="1") + + if need_standalone_pipeline and not dont_kill_server: + ChecksCLI.kill_standalone_pipeline() + diff --git a/moon_manager/moon_manager/api/configuration.py b/moon_manager/moon_manager/api/configuration.py new file mode 100644 index 00000000..601b3d53 --- /dev/null +++ b/moon_manager/moon_manager/api/configuration.py @@ -0,0 +1,237 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +"""Configuration API""" +import glob +import hug.interface +import json +import logging +import logging.config +import os +import requests +import sys +import yaml +import importlib +from importlib.machinery import SourceFileLoader +from moon_utilities.auth_functions import init_db, get_api_key_for_user + +LOGGER = logging.getLogger("moon.manager.api.configuration") +__CONF = {} + + +def init_logging(): + """Initialize the logging system + + :return: nothing + """ + logging_conf = get_configuration(key='logging') + if get_configuration(key='debug', default=False): + logging_conf.get("handlers", {}).get("console", {})['level'] = logging.DEBUG + LOGGER.info("Setting debug to True!") + logging.config.dictConfig(logging_conf) + + +def load_plugin(plugname): + """Load a python module + + :param plugname: the name of the module to load + :return: a reference to the module + """ + plugins_dir = __CONF["plugins"]["directory"] + try: + return __import__(plugname, fromlist=["plugins", ]) + except ImportError as e: + LOGGER.warning("Cannot import module ({})".format(e)) + try: + m = SourceFileLoader("myplugs", os.path.join(plugins_dir, plugname+".py")) + return m.load_module() + except ImportError as e: + LOGGER.error("Error in importing plugin {} from {}".format(plugname, plugins_dir)) + LOGGER.exception(e) + + +def get_db_driver(): + """Load and check the plugin module + + :return: a reference to the module + """ + plug = load_plugin(__CONF["database"]["driver"]) + if plug.PLUGIN_TYPE != "db": + raise Exception("Trying to load a bad DB plugin (got {} plugin instead)".format( + plug.PLUGIN_TYPE)) + if "Connector" not in dir(plug): + raise Exception("Trying to load a bad DB plugin (cannot find Connector)") + return plug + + +def get_orchestration_driver(): + """Load and check the plugin module + + :return: a reference to the module + """ + plug = load_plugin(__CONF["orchestration"]["driver"]) + if plug.PLUGIN_TYPE != "orchestration": + raise Exception("Trying to load a bad Orchestration plugin (got {} plugin instead)".format( + plug.PLUGIN_TYPE)) + if "Connector" not in dir(plug): + raise Exception("Trying to load a bad Orchestration plugin (cannot find Connector)") + return plug + + +def get_information_driver(driver_name): + """Load and check the plugin module + + :return: a reference to the module + """ + plug = load_plugin(driver_name) + if plug.PLUGIN_TYPE != "information": + raise Exception("Trying to load a bad Information plugin (got {} plugin instead)".format( + plug.PLUGIN_TYPE)) + if "Connector" not in dir(plug): + raise Exception("Trying to load a bad Information plugin (cannot find Connector)") + return plug + + +def get_global_attrs_driver(): + """Load and check the plugin module + + :return: a reference to the module + """ + driver_name = __CONF["information"].get("global_attrs", {}).get("driver") + if not driver_name: + return + plug = load_plugin(driver_name) + if plug.PLUGIN_TYPE != "information": + raise Exception("Trying to load a bad Information plugin (got {} plugin instead)".format( + plug.PLUGIN_TYPE)) + if "Connector" not in dir(plug): + raise Exception("Trying to load a bad Information plugin (cannot find Connector)") + return plug + + +def search_config_file(filename): + """Look for the configuration file + + :param filename: a filename to search for + :return: the content of the configuration file + """ + data_config = None + for _dir in ( + "{}", + "/conf/{}", + "../{}", + "../conf/{}", + "/etc/moon/{}", + "conf/{}", + ): + for _filename in (filename, "moon.conf", "moon.yaml"): + _file = _dir.format(_filename) + try: + data_config = yaml.safe_load(open(_file)) + except FileNotFoundError: + data_config = None + continue + else: + break + if data_config: + LOGGER.warning("Using {} as configuration file".format(_file)) + break + if not data_config: + raise Exception("Configuration file not found...") + return data_config + + +def set_configuration(conf): + """ Force the configuration dictionary + + :param conf: the configuration dictionary + :return: nothing + """ + global __CONF + __CONF = conf + + +@hug.cli("get_conf") +@hug.local() +@hug.get("/conf") +@hug.get("/conf/{key}") +def get_configuration(key=None, default=None): + """ + List configuration attributes + :return: JSON configuration output + """ + global __CONF + if not __CONF: + __CONF = search_config_file("moon.yaml") + init_logging() + if not key: + # TODO: delete passwords! + return __CONF + else: + return __CONF.get(key, default) + + +@hug.cli("import_json") +def import_json(filename): + """ + Import data in json file + """ + LOGGER.info("Importing policy from {}".format(filename)) + db_conf = get_configuration(key='management') + init_db(db_conf.get("token_file")) + manager_api_key = get_api_key_for_user("admin") + try: + dict_to_import = json.loads(open(filename).read()) + except json.JSONDecodeError as e: + LOGGER.error("Error in decoding the input file") + LOGGER.exception(e) + else: + req = requests.post("{}/import".format(db_conf.get("url")), + data=json.dumps(dict_to_import), + headers={ + "x-api-key": manager_api_key, + "Content-Type": "application/json" + }) + if req.status_code == 200: + LOGGER.warning("Import OK!") + parsed = json.loads(req.content) + LOGGER.info("Response: {}".format(json.dumps(parsed, indent=4, sort_keys=True))) + else: + LOGGER.error("Error when importing data: {} {}".format(req.status_code, req.content)) + + +@hug.cli("init_db") +@hug.local() +def init_database(): + """Initialize the database + + :return: nothing + """ + LOGGER.info("Initialize the database") + cwd = os.getcwd() + db_conf = get_configuration(key='database') + migration_dir = db_conf.get("migration_dir", ".") + migration_files = glob.glob(os.path.join(migration_dir, "*[0-9][0-9][0-9].py")) + migration_files.sort() + if not migration_files: + # the migration_dir is a python module so we must find the files inside this dir + mod = __import__(migration_dir, fromlist=[migration_dir.split(".")[-1], ]) + migration_files = glob.glob(os.path.join(mod.__path__[0], "*[0-9][0-9][0-9].py")) + for filename in migration_files: + # we execute the upgrade/downgrade functions inside each file + os.chdir(os.path.dirname(filename)) + # we add the current directory in order to import the file + sys.path.append("") + mod = importlib.import_module(os.path.basename(filename.replace(".py", ""))) + # TODO: manage the downgrade function + mod.upgrade(db_conf.get("url")) + os.chdir(cwd) diff --git a/moon_manager/moon_manager/api/data.py b/moon_manager/moon_manager/api/data.py index 92d7b2c6..570bb9cd 100644 --- a/moon_manager/moon_manager/api/data.py +++ b/moon_manager/moon_manager/api/data.py @@ -1,46 +1,60 @@ -# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors -# This software is distributed under the terms and conditions of the 'Apache-2.0' -# license which can be found in the file 'LICENSE' in this package distribution -# or at 'http://www.apache.org/licenses/LICENSE-2.0'. +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + """ Data are elements used to create rules +* 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 +import hug import logging -from python_moonutilities.security_functions import check_auth -from python_moondb.core import PolicyManager -from python_moonutilities.security_functions import validate_input +import requests +from moon_manager import db_driver as driver +from moon_utilities.security_functions import validate_input +from moon_utilities.auth_functions import api_key_authentication, connect_from_env +from moon_utilities.invalided_functions import invalidate_data_in_slaves +from moon_manager.api import slave as slave_class +from moon_manager.api import configuration +from moon_manager.api import policy +from moon_manager.api import meta_data -__version__ = "4.3.2" +LOGGER = logging.getLogger("moon.manager.api." + __name__) -logger = logging.getLogger("moon.manager.api." + __name__) - -class SubjectData(Resource): +class SubjectData(object): """ Endpoint for subject data requests """ - __urls__ = ( - "/policies//subject_data", - "/policies//subject_data/", - "/policies//subject_data/", - "/policies//subject_data//", - ) - - @validate_input("get", kwargs_state=[True, False, False, False]) - @check_auth - def get(self, uuid=None, category_id=None, data_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.get("/policies/{uuid}/subject_data", requires=api_key_authentication) + @hug.get("/policies/{uuid}/subject_data/{category_id}", requires=api_key_authentication) + @hug.get("/policies/{uuid}/subject_data/{category_id}/{data_id}", + requires=api_key_authentication) + def get(uuid: hug.types.text, category_id: hug.types.text = None, + data_id: hug.types.text = None, authed_user: hug.directives.user = None): """Retrieve all subject categories or a specific one if data_id 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 + :param authed_user: user ID who do the request :return: [{ "policy_id": "policy_id1", "category_id": "category_id1", @@ -53,24 +67,22 @@ class SubjectData(Resource): }] :internal_api: get_subject_data """ - logger.info("api.get {} {} {}".format(uuid, category_id, data_id)) - data = PolicyManager.get_subject_data(user_id=user_id, - policy_id=uuid, - category_id=category_id, - data_id=data_id) - logger.info("api.get data = {}".format(data)) + data = driver.PolicyManager.get_subject_data(moon_user_id=authed_user, policy_id=uuid, + category_id=category_id, data_id=data_id) return {"subject_data": data} - @validate_input("post", kwargs_state=[True, True, False, False], body_state={"name": True}) - @check_auth - def post(self, uuid=None, category_id=None, data_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.post("/policies/{uuid}/subject_data/{category_id}", requires=api_key_authentication) + def post(body: validate_input("name"), uuid: hug.types.text, category_id: hug.types.text, + authed_user: hug.directives.user = None): """Create or update a subject. + :param body: body of the request :param uuid: uuid of the policy :param category_id: uuid of the subject category - :param data_id: uuid of the subject data (not used here) - :param user_id: user ID who do the request + :param authed_user: user ID who do the request :request body: { "name": "name of the data (mandatory)", "description": "description of the data (optional)" @@ -87,60 +99,64 @@ class SubjectData(Resource): } :internal_api: add_subject_data """ - data = PolicyManager.set_subject_data(user_id=user_id, - policy_id=uuid, - category_id=category_id, - value=request.json) + data = driver.PolicyManager.set_subject_data(moon_user_id=authed_user, policy_id=uuid, + category_id=category_id, value=body) + + slaves = slave_class.Slaves.get().get("slaves") + invalidate_data_in_slaves(slaves=slaves, policy_id=uuid, category_id=category_id, + data_id=None, type="subject") return {"subject_data": data} - @validate_input("delete", kwargs_state=[True, False, False, False]) - @check_auth - def delete(self, uuid=None, category_id=None, data_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.delete("/policies/{uuid}/subject_data/{category_id}/{data_id}", + requires=api_key_authentication) + def delete(uuid: hug.types.text, data_id: hug.types.text, + category_id: hug.types.text = None, authed_user: hug.directives.user = 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 + :param authed_user: user ID who do the request :return: [{ "result": "True or False", "message": "optional message (optional)" }] :internal_api: delete_subject_data """ - logger.info("api.delete {} {}".format(uuid, data_id)) - data = PolicyManager.delete_subject_data(user_id=user_id, - policy_id=uuid, - category_id=category_id, - data_id=data_id) + LOGGER.info("api.delete {} {}".format(uuid, data_id)) + driver.PolicyManager.delete_subject_data(moon_user_id=authed_user, policy_id=uuid, + category_id=category_id, data_id=data_id) + + slaves = slave_class.Slaves.get().get("slaves") + invalidate_data_in_slaves(slaves=slaves, policy_id=None, category_id=None, + data_id=data_id, type="subject") return {"result": True} -class ObjectData(Resource): +class ObjectData(object): """ Endpoint for object data requests """ - __urls__ = ( - "/policies//object_data", - "/policies//object_data/", - "/policies//object_data/", - "/policies//object_data//" - "", - ) - - @validate_input("get", kwargs_state=[True, False, False, False]) - @check_auth - def get(self, uuid=None, category_id=None, data_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.get("/policies/{uuid}/object_data", requires=api_key_authentication) + @hug.get("/policies/{uuid}/object_data/{category_id}", requires=api_key_authentication) + @hug.get("/policies/{uuid}/object_data/{category_id}/{data_id}", + requires=api_key_authentication) + def get(uuid: hug.types.text, category_id: hug.types.text = None, + data_id: hug.types.text = None, authed_user: hug.directives.user = 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 + :param authed_user: user ID who do the request :return: [{ "policy_id": "policy_id1", "category_id": "category_id1", @@ -153,22 +169,21 @@ class ObjectData(Resource): }] :internal_api: get_object_data """ - data = PolicyManager.get_object_data(user_id=user_id, - policy_id=uuid, - category_id=category_id, - data_id=data_id) - + data = driver.PolicyManager.get_object_data(moon_user_id=authed_user, policy_id=uuid, + category_id=category_id, data_id=data_id) return {"object_data": data} - @validate_input("post", kwargs_state=[True, True, False, False], body_state={"name": True}) - @check_auth - def post(self, uuid=None, category_id=None, data_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.post("/policies/{uuid}/object_data/{category_id}", requires=api_key_authentication) + def post(body: validate_input("name"), uuid: hug.types.text, category_id: hug.types.text, + authed_user: hug.directives.user = None): """Create or update a object. + :param body: body of the request :param uuid: uuid of the policy :param category_id: uuid of the object category - :param data_id: uuid of the object data (not used here) - :param user_id: user ID who do the request + :param authed_user: user ID who do the request :request body: { "name": "name of the data (mandatory)", "description": "description of the data (optional)" @@ -185,59 +200,65 @@ class ObjectData(Resource): } :internal_api: add_object_data """ - data = PolicyManager.add_object_data(user_id=user_id, - policy_id=uuid, - category_id=category_id, - value=request.json) + data = driver.PolicyManager.add_object_data(moon_user_id=authed_user, policy_id=uuid, + category_id=category_id, value=body) + + slaves = slave_class.Slaves.get().get("slaves") + invalidate_data_in_slaves(slaves=slaves, policy_id=uuid, category_id=category_id, + data_id=None, type="object") + return {"object_data": data} - @validate_input("delete", kwargs_state=[True, False, False, False]) - @check_auth - def delete(self, uuid=None, category_id=None, data_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.delete("/policies/{uuid}/object_data/{category_id}/{data_id}", + requires=api_key_authentication) + def delete(uuid: hug.types.text, data_id: hug.types.text, + category_id: hug.types.text = None, authed_user: hug.directives.user = 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 + :param authed_user: user ID who do the request :return: { "result": "True or False", "message": "optional message (optional)" } :internal_api: delete_object_data """ - data = PolicyManager.delete_object_data(user_id=user_id, - policy_id=uuid, - category_id=category_id, - data_id=data_id) + driver.PolicyManager.delete_object_data(moon_user_id=authed_user, policy_id=uuid, + category_id=category_id, data_id=data_id) + + slaves = slave_class.Slaves.get().get("slaves") + + invalidate_data_in_slaves(slaves=slaves, policy_id=None, category_id=None, + data_id=data_id, type="object") return {"result": True} -class ActionData(Resource): +class ActionData(object): """ Endpoint for action data requests """ - __urls__ = ( - "/policies//action_data", - "/policies//action_data/", - "/policies//action_data/", - "/policies//action_data//" - "", - ) - - @validate_input("get", kwargs_state=[True, False, False, False]) - @check_auth - def get(self, uuid=None, category_id=None, data_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.get("/policies/{uuid}/action_data", requires=api_key_authentication) + @hug.get("/policies/{uuid}/action_data/{category_id}", requires=api_key_authentication) + @hug.get("/policies/{uuid}/action_data/{category_id}/{data_id}", + requires=api_key_authentication) + def get(uuid: hug.types.text, category_id: hug.types.text = None, + data_id: hug.types.text = None, authed_user: hug.directives.user = 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 + :param authed_user: user ID who do the request :return: [{ "policy_id": "policy_id1", "category_id": "category_id1", @@ -250,22 +271,22 @@ class ActionData(Resource): }] :internal_api: get_action_data """ - data = PolicyManager.get_action_data(user_id=user_id, - policy_id=uuid, - category_id=category_id, - data_id=data_id) + data = driver.PolicyManager.get_action_data(moon_user_id=authed_user, policy_id=uuid, + category_id=category_id, data_id=data_id) return {"action_data": data} - @validate_input("post", kwargs_state=[True, True, False, False], body_state={"name": True}) - @check_auth - def post(self, uuid=None, category_id=None, data_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.post("/policies/{uuid}/action_data/{category_id}", requires=api_key_authentication) + def post(body: validate_input("name"), uuid: hug.types.text, category_id: hug.types.text, + authed_user: hug.directives.user = None): """Create or update a action. + :param body: body of the request :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 + :param authed_user: user ID who do the request :request body: { "name": "name of the data (mandatory)", "description": "description of the data (optional)" @@ -282,30 +303,424 @@ class ActionData(Resource): } :internal_api: add_action_data """ - data = PolicyManager.add_action_data(user_id=user_id, - policy_id=uuid, - category_id=category_id, - value=request.json) + data = driver.PolicyManager.add_action_data(moon_user_id=authed_user, policy_id=uuid, + category_id=category_id, value=body) + + slaves = slave_class.Slaves.get().get("slaves") + invalidate_data_in_slaves(slaves=slaves, policy_id=uuid, category_id=category_id, + data_id=None, type="action") + return {"action_data": data} - @validate_input("delete", kwargs_state=[True, False, False, False]) - @check_auth - def delete(self, uuid=None, category_id=None, data_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.delete("/policies/{uuid}/action_data/{category_id}/{data_id}", + requires=api_key_authentication) + def delete(uuid: hug.types.text, data_id: hug.types.text, + category_id: hug.types.text = None, authed_user: hug.directives.user = 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 + :param authed_user: user ID who do the request :return: { "result": "True or False", "message": "optional message (optional)" } :internal_api: delete_action_data """ - data = PolicyManager.delete_action_data(user_id=user_id, - policy_id=uuid, - category_id=category_id, - data_id=data_id) + driver.PolicyManager.delete_action_data(moon_user_id=authed_user, policy_id=uuid, + category_id=category_id, data_id=data_id) + slaves = slave_class.Slaves.get().get("slaves") + + invalidate_data_in_slaves(slaves=slaves, policy_id=None, category_id=None, + data_id=data_id, type="action") return {"result": True} + + +def human_display_entity_data(entity_data_json): + """ + Common static method for entity (subject, object) + :param entity_data_json: subject_data_json or object_data_json + :return: + """ + human_result = "Data\n" + human_result += "\tpolicy_id : " + entity_data_json.get("policy_id") + "\n" + human_result += "\tcategory_id : " + entity_data_json.get("category_id") + "\n" + human_result += "\tdata : \n" + for data in entity_data_json.get("data"): + human_result += "\t\t" + data + "\n" + human_result += human_display_data(entity_data_json.get("data").get(data)) + return human_result + +def human_display_data(data_json, tabulations: int = 3): + """ + :param data_json: + :param tabulations: nombre de caractères de tabulations + :return: + """ + tab = "" + for i in range(tabulations): + tab += "\t" + human_result = tab + "id:" + data_json.get("id") + "\n" + human_result += tab + "name:" + data_json.get("name") + "\n" + human_result += tab + "description:" + data_json.get("description") + "\n" + human_result += tab + "category_id:" + data_json.get("category_id") + "\n" + human_result += tab + "policy_id:" + data_json.get("policy_id") + "\n" + + return human_result + + +SubjectDataAPI = hug.API(name='subject_data', doc=SubjectData.__doc__) + + +@hug.object(name='subject_data', version='1.0.0', api=SubjectDataAPI) +class SubjectDataCLI(object): + """An example of command like calls via an Object""" + + @staticmethod + @hug.object.cli + def list(policy_name_or_id, name_or_id="", human: bool = False): + """Retrieve all subject categories or a specific one if data_id is give for a given policy""" + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + policy_id = list(policy.PoliciesCLI.list(policy_name_or_id).get("policies").keys())[0] + _data_req = requests.get( + "{}/policies/{}/subject_data".format(db_conf.get("url"), policy_id), + headers={"x-api-key": manager_api_key} + ) + _data_to_return = None + _data_list = _data_req.json().get("subject_data") + if _data_req.status_code == 200: + if name_or_id: + _data = None + for _data_item in _data_list: + if policy_id != _data_item["policy_id"]: + continue + for _data_key, _data_value in _data_item.get("data").items(): + if _data_value.get("name") == name_or_id: + _data_to_return = _data_value + break + elif _data_key == name_or_id: + _data_to_return = _data_value + break + if not _data_to_return: + raise Exception("Cannot find Subject Data with name or ID {}".format( + name_or_id)) + if human: + result = _data_to_return + else: + result = {"subject_data": _data_to_return} + else: + result = _data_req.json() + + if human: + if name_or_id: + return human_display_data(result, 1) + else: + return SubjectDataCLI.human_display(result) + else: + return result + LOGGER.error('Cannot list Subject Data {}'.format(_data_req.status_code)) + + @staticmethod + @hug.object.cli + def add(name, category_name_or_id, policy_name_or_id, description="", human: bool=False): + """ + Add an subject data in the database + :return: JSON status output + """ + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + category_id = list(meta_data.SubjectCategoriesCLI.list(category_name_or_id) + .get("subject_categories").keys())[0] + policy_id = list(policy.PoliciesCLI.list(policy_name_or_id).get("policies").keys())[0] + _url = "{}/policies/{}/subject_data/{}".format( + db_conf.get("url"), policy_id, category_id) + _data_req = requests.post( + _url, + json={ + "name": name, + "description": description, + }, + headers={ + "x-api-key": manager_api_key, + "Content-Type": "application/json" + } + ) + if _data_req.status_code == 200: + LOGGER.warning('Create {}'.format(_data_req.content)) + if human: + return human_display_entity_data(_data_req.json().get("subject_data")) + else: + return _data_req.json() + LOGGER.error('Cannot create {}'.format(name, _data_req.content[:40])) + + @staticmethod + @hug.object.cli + def delete(name_or_id, category_name_or_id, policy_name_or_id): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _subject_data = SubjectDataCLI.list(policy_name_or_id) + category_id = list(meta_data.SubjectCategoriesCLI.list(category_name_or_id) + .get("subject_categories").keys())[0] + for element in _subject_data.get("subject_data"): + for _data_id, _data_value in element.get("data").items(): + if _data_value.get("name") == name_or_id: + policy_id = list( + policy.PoliciesCLI.list(policy_name_or_id).get("policies").keys())[0] + _url = "{}/policies/{}/subject_data/{}/{}".format( + db_conf.get("url"), policy_id, category_id, _data_id) + req = requests.delete( + _url, + headers={"x-api-key": manager_api_key} + ) + if req.status_code == 200: + LOGGER.warning('Deleted {}'.format(name_or_id)) + continue + LOGGER.error("Cannot delete Subject Data with name {}".format(name_or_id)) + + @staticmethod + def human_display(subject_data_json): + human_result = "Subjects Data\n" + for subject_data in subject_data_json.get('subject_data'): + human_result += human_display_entity_data(subject_data) + return human_result + +ObjectDataAPI = hug.API(name='object_data', doc=ObjectData.__doc__) + + +@hug.object(name='object_data', version='1.0.0', api=ObjectDataAPI) +class ObjectDataCLI(object): + """An example of command like calls via an Object""" + + @staticmethod + @hug.object.cli + def list(policy_name_or_id, name_or_id="", human: bool = False): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + policy_id = list(policy.PoliciesCLI.list(policy_name_or_id).get("policies").keys())[0] + _data_req = requests.get( + "{}/policies/{}/object_data".format(db_conf.get("url"), policy_id), + headers={"x-api-key": manager_api_key} + ) + _data_to_return = None + _data_list = _data_req.json().get("object_data") + if _data_req.status_code == 200: + if name_or_id: + _data = None + for _data_item in _data_list: + if policy_id != _data_item["policy_id"]: + continue + for _data_key, _data_value in _data_item.get("data").items(): + if _data_value.get("name") == name_or_id: + _data_to_return = _data_value + break + elif _data_key == name_or_id: + _data_to_return = _data_value + break + if not _data_to_return: + raise Exception("Cannot find Object Data with name or ID {}".format( + name_or_id)) + if human: + result = _data_to_return + else: + result = {"object_data": _data_to_return} + else: + result = _data_req.json() + + if human: + if name_or_id: + return human_display_data(result, 1) + else: + return ObjectDataCLI.human_display(result) + else: + return result + LOGGER.error('Cannot list Object Data {}'.format(_data_req.status_code)) + + @staticmethod + @hug.object.cli + def add(name, category_name_or_id, policy_name_or_id, description="", human: bool = False): + """ + Add + :param name: + :param category_name_or_id: + :param policy_name_or_id: + :param description: + :param human: + :return: + """ + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + category_id = list(meta_data.ObjectCategoriesCLI.list(category_name_or_id) + .get("object_categories").keys())[0] + policy_id = list(policy.PoliciesCLI.list(policy_name_or_id).get("policies").keys())[0] + _url = "{}/policies/{}/object_data/{}".format( + db_conf.get("url"), policy_id, category_id) + _data_req = requests.post( + _url, + json={ + "name": name, + "description": description, + }, + headers={ + "x-api-key": manager_api_key, + "Content-Type": "application/json" + } + ) + if _data_req.status_code == 200: + LOGGER.warning('Create {}'.format(_data_req.content)) + if human: + return human_display_entity_data(_data_req.json().get("object_data")) + else: + return _data_req.json() + LOGGER.error('Cannot create {}'.format(name, _data_req.content[:40])) + + @staticmethod + @hug.object.cli + def delete(name_or_id, category_name_or_id, policy_name_or_id): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _object_data = ObjectDataCLI.list(policy_name_or_id) + category_id = list(meta_data.ObjectCategoriesCLI.list(category_name_or_id) + .get("object_categories").keys())[0] + for element in _object_data.get("object_data"): + for _data_id, _data_value in element.get("data").items(): + if _data_value.get("name") == name_or_id: + policy_id = list( + policy.PoliciesCLI.list(policy_name_or_id).get("policies").keys())[0] + _url = "{}/policies/{}/object_data/{}/{}".format( + db_conf.get("url"), policy_id, category_id, _data_id) + req = requests.delete( + _url, + headers={"x-api-key": manager_api_key} + ) + if req.status_code == 200: + LOGGER.warning('Deleted {}'.format(name_or_id)) + continue + LOGGER.error("Cannot delete Object Data with name {}".format(name_or_id)) + + @staticmethod + def human_display(object_data_json): + human_result = "Objects Data\n" + for object_data in object_data_json.get('object_data'): + human_result += human_display_entity_data(object_data) + return human_result + +ActionDataAPI = hug.API(name='action_data', doc=ActionData.__doc__) + + +@hug.object(name='action_data', version='1.0.0', api=ActionDataAPI) +class ActionDataCLI(object): + """An example of command like calls via an Action""" + + @staticmethod + @hug.object.cli + def list(policy_name_or_id, name_or_id="", human: bool = False): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + policy_id = list(policy.PoliciesCLI.list(policy_name_or_id).get("policies").keys())[0] + _data_req = requests.get( + "{}/policies/{}/action_data".format(db_conf.get("url"), policy_id), + headers={"x-api-key": manager_api_key} + ) + _data_to_return = None + _data_list = _data_req.json().get("action_data") + if _data_req.status_code == 200: + if name_or_id: + _data = None + for _data_item in _data_list: + if policy_id != _data_item["policy_id"]: + continue + for _data_key, _data_value in _data_item.get("data").items(): + if _data_value.get("name") == name_or_id: + _data_to_return = _data_value + break + elif _data_key == name_or_id: + _data_to_return = _data_value + break + if not _data_to_return: + raise Exception("Cannot find Action Data with name or ID {}".format( + name_or_id)) + if human: + result = _data_to_return + else: + result = {"action_data": _data_to_return} + else: + result = _data_req.json() + + if human: + if name_or_id: + return human_display_data(result, 1) + else: + return ActionDataCLI.human_display(result) + else: + return result + LOGGER.error('Cannot list Action Data {}'.format(_data_req.status_code)) + + @staticmethod + @hug.object.cli + def add(name, category_name_or_id, policy_name_or_id, description="", human:bool = False): + """ + Add an action data in the database + :return: JSON status output + """ + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + category_id = list(meta_data.ActionCategoriesCLI.list(category_name_or_id) + .get("action_categories").keys())[0] + policy_id = list(policy.PoliciesCLI.list(policy_name_or_id).get("policies").keys())[0] + _url = "{}/policies/{}/action_data/{}".format( + db_conf.get("url"), policy_id, category_id) + _data_req = requests.post( + _url, + json={ + "name": name, + "description": description, + }, + headers={ + "x-api-key": manager_api_key, + "Content-Type": "application/json" + } + ) + if _data_req.status_code == 200: + LOGGER.warning('Create {}'.format(_data_req.content)) + if human: + return human_display_entity_data(_data_req.json().get("action_data")) + else: + return _data_req.json() + LOGGER.error('Cannot create {}'.format(name, _data_req.content[:40])) + + + @staticmethod + def human_display(action_data_json): + human_result = "Actions Data\n" + for action_data in action_data_json.get('action_data'): + human_result += human_display_entity_data(action_data) + return human_result + + @staticmethod + @hug.object.cli + def delete(name_or_id, category_name_or_id, policy_name_or_id): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _action_data = ActionDataCLI.list(policy_name_or_id) + category_id = list(meta_data.ActionCategoriesCLI.list(category_name_or_id) + .get("action_categories").keys())[0] + for element in _action_data.get("action_data"): + for _data_id, _data_value in element.get("data").items(): + if _data_value.get("name") == name_or_id: + policy_id = list( + policy.PoliciesCLI.list(policy_name_or_id).get("policies").keys())[0] + _url = "{}/policies/{}/action_data/{}/{}".format( + db_conf.get("url"), policy_id, category_id, _data_id) + req = requests.delete( + _url, + headers={"x-api-key": manager_api_key} + ) + if req.status_code == 200: + LOGGER.warning('Deleted {}'.format(name_or_id)) + continue + LOGGER.error("Cannot delete Action Data with name {}".format(name_or_id)) diff --git a/moon_manager/moon_manager/api/db/__init__.py b/moon_manager/moon_manager/api/db/__init__.py new file mode 100644 index 00000000..1856aa2c --- /dev/null +++ b/moon_manager/moon_manager/api/db/__init__.py @@ -0,0 +1,12 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + diff --git a/moon_manager/moon_manager/api/db/managers.py b/moon_manager/moon_manager/api/db/managers.py new file mode 100644 index 00000000..23be03fc --- /dev/null +++ b/moon_manager/moon_manager/api/db/managers.py @@ -0,0 +1,24 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +import logging + +logger = logging.getLogger("moon.db.api.managers") + + +class Managers(object): + """Object that links managers together""" + ModelManager = None + KeystoneManager = None + PDPManager = None + PolicyManager = None + SlaveManager = None diff --git a/moon_manager/moon_manager/api/db/migrations/__init__.py b/moon_manager/moon_manager/api/db/migrations/__init__.py new file mode 100644 index 00000000..1856aa2c --- /dev/null +++ b/moon_manager/moon_manager/api/db/migrations/__init__.py @@ -0,0 +1,12 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + diff --git a/moon_manager/moon_manager/api/db/migrations/moon_001.py b/moon_manager/moon_manager/api/db/migrations/moon_001.py new file mode 100644 index 00000000..8e604d2b --- /dev/null +++ b/moon_manager/moon_manager/api/db/migrations/moon_001.py @@ -0,0 +1,336 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +import json +import sqlalchemy as sql +from sqlalchemy import types as sql_types +from sqlalchemy import create_engine +import sys + + +class JsonBlob(sql_types.TypeDecorator): + impl = sql.Text + + def process_bind_param(self, value, dialect): + return json.dumps(value) + + def process_result_value(self, value, dialect): + return json.loads(value) + + +def upgrade(migrate_engine): + if isinstance(migrate_engine, str): + migrate_engine = create_engine(migrate_engine) + meta = sql.MetaData() + meta.bind = migrate_engine + sys.stdout.write("Creating ") + sys.stdout.flush() + + table = sql.Table( + 'pdp', + meta, + sql.Column('id', sql.String(64), primary_key=True), + sql.Column('name', sql.String(256), nullable=False), + sql.Column('vim_project_id', sql.String(64), nullable=True, default=""), + sql.Column('value', JsonBlob(), nullable=True), + sql.UniqueConstraint('name', name='unique_constraint_models'), + mysql_engine='InnoDB', + mysql_charset='utf8') + table.create(migrate_engine, checkfirst=True) + sys.stdout.write(str(table) + " ") + sys.stdout.flush() + + table = sql.Table( + 'slaves', + meta, + sql.Column('id', sql.String(64), primary_key=True), + sql.Column('name', sql.String(256), nullable=False), + sql.Column('address', sql.String(256), nullable=True, default=""), + sql.Column('grant_if_unknown_project', sql.Boolean, nullable=True, default=""), + sql.Column('process', sql.String(256), nullable=False, default=""), + sql.Column('log', sql.String(256), nullable=False, default=""), + sql.Column('api_key', sql.String(256), nullable=False, default=""), + sql.Column('value', JsonBlob(), nullable=True), + sql.UniqueConstraint('name', name='unique_constraint_models'), + mysql_engine='InnoDB', + mysql_charset='utf8') + table.create(migrate_engine, checkfirst=True) + sys.stdout.write(str(table) + " ") + sys.stdout.flush() + + table = sql.Table( + 'policies', + meta, + sql.Column('id', sql.String(64), primary_key=True), + sql.Column('name', sql.String(256), nullable=False), + sql.Column('model_id', sql.String(64), nullable=True, default=""), + sql.Column('value', JsonBlob(), nullable=True), + sql.UniqueConstraint('name', 'model_id', name='unique_constraint_models'), + mysql_engine='InnoDB', + mysql_charset='utf8') + table.create(migrate_engine, checkfirst=True) + sys.stdout.write(str(table) + " ") + sys.stdout.flush() + + table = sql.Table( + 'models', + meta, + sql.Column('id', sql.String(64), primary_key=True), + sql.Column('name', sql.String(256), nullable=False), + sql.Column('value', JsonBlob(), nullable=True), + sql.UniqueConstraint('name', name='unique_constraint_models'), + mysql_engine='InnoDB', + mysql_charset='utf8') + table.create(migrate_engine, checkfirst=True) + sys.stdout.write(str(table) + " ") + sys.stdout.flush() + + subject_categories_table = sql.Table( + 'subject_categories', + meta, + sql.Column('id', sql.String(64), primary_key=True), + sql.Column('name', sql.String(256), nullable=False), + sql.Column('description', sql.String(256), nullable=True), + + sql.UniqueConstraint('name', name='unique_constraint_subject_categories'), + mysql_engine='InnoDB', + mysql_charset='utf8') + subject_categories_table.create(migrate_engine, checkfirst=True) + sys.stdout.write(str(subject_categories_table) + " ") + sys.stdout.flush() + + object_categories_table = sql.Table( + 'object_categories', + meta, + sql.Column('id', sql.String(64), primary_key=True), + sql.Column('name', sql.String(256), nullable=False), + sql.Column('description', sql.String(256), nullable=True), + + sql.UniqueConstraint('name', name='unique_constraint_object_categories'), + mysql_engine='InnoDB', + mysql_charset='utf8') + object_categories_table.create(migrate_engine, checkfirst=True) + sys.stdout.write(str(object_categories_table) + " ") + sys.stdout.flush() + + action_categories_table = sql.Table( + 'action_categories', + meta, + sql.Column('id', sql.String(64), primary_key=True), + sql.Column('name', sql.String(256), nullable=False), + sql.Column('description', sql.String(256), nullable=True), + + sql.UniqueConstraint('name', name='unique_constraint_action_categories'), + mysql_engine='InnoDB', + mysql_charset='utf8') + action_categories_table.create(migrate_engine, checkfirst=True) + sys.stdout.write(str(action_categories_table) + " ") + sys.stdout.flush() + + subjects_table = sql.Table( + 'subjects', + meta, + sql.Column('id', sql.String(64), primary_key=True), + sql.Column('name', sql.String(256), nullable=False), + sql.Column('value', JsonBlob(), nullable=True), + sql.UniqueConstraint('name', name='unique_constraint_subjects'), + mysql_engine='InnoDB', + mysql_charset='utf8') + subjects_table.create(migrate_engine, checkfirst=True) + sys.stdout.write(str(subjects_table) + " ") + sys.stdout.flush() + + objects_table = sql.Table( + 'objects', + meta, + sql.Column('id', sql.String(64), primary_key=True), + sql.Column('name', sql.String(256), nullable=False), + sql.Column('value', JsonBlob(), nullable=True), + sql.UniqueConstraint('name', name='unique_constraint_objects'), + mysql_engine='InnoDB', + mysql_charset='utf8') + objects_table.create(migrate_engine, checkfirst=True) + sys.stdout.write(str(objects_table) + " ") + sys.stdout.flush() + + actions_table = sql.Table( + 'actions', + meta, + sql.Column('id', sql.String(64), primary_key=True), + sql.Column('name', sql.String(256), nullable=False), + sql.Column('value', JsonBlob(), nullable=True), + sql.UniqueConstraint('name', name='unique_constraint_actions'), + mysql_engine='InnoDB', + mysql_charset='utf8') + actions_table.create(migrate_engine, checkfirst=True) + sys.stdout.write(str(actions_table) + " ") + sys.stdout.flush() + + subject_data_table = sql.Table( + 'subject_data', + meta, + sql.Column('id', sql.String(64), primary_key=True), + sql.Column('name', sql.String(256), nullable=False), + sql.Column('value', JsonBlob(), nullable=True), + sql.Column('category_id', sql.ForeignKey("subject_categories.id"), nullable=False), + sql.Column('policy_id', sql.ForeignKey("policies.id"), nullable=False), + sql.UniqueConstraint('name', 'category_id', 'policy_id', + name='unique_constraint_subject_data'), + mysql_engine='InnoDB', + mysql_charset='utf8') + subject_data_table.create(migrate_engine, checkfirst=True) + sys.stdout.write(str(subject_data_table) + " ") + sys.stdout.flush() + + object_data_table = sql.Table( + 'object_data', + meta, + sql.Column('id', sql.String(64), primary_key=True), + sql.Column('name', sql.String(256), nullable=False), + sql.Column('value', JsonBlob(), nullable=True), + sql.Column('category_id', sql.ForeignKey("object_categories.id"), nullable=False), + sql.Column('policy_id', sql.ForeignKey("policies.id"), nullable=False), + sql.UniqueConstraint('name', 'category_id', 'policy_id', + name='unique_constraint_object_data'), + mysql_engine='InnoDB', + mysql_charset='utf8') + object_data_table.create(migrate_engine, checkfirst=True) + sys.stdout.write(str(object_data_table) + " ") + sys.stdout.flush() + + action_data_table = sql.Table( + 'action_data', + meta, + sql.Column('id', sql.String(64), primary_key=True), + sql.Column('name', sql.String(256), nullable=False), + sql.Column('value', JsonBlob(), nullable=True), + sql.Column('category_id', sql.ForeignKey("action_categories.id"), nullable=False), + sql.Column('policy_id', sql.ForeignKey("policies.id"), nullable=False), + sql.UniqueConstraint('name', 'category_id', 'policy_id', + name='unique_constraint_action_data'), + mysql_engine='InnoDB', + mysql_charset='utf8') + action_data_table.create(migrate_engine, checkfirst=True) + sys.stdout.write(str(action_data_table) + " ") + sys.stdout.flush() + + subject_assignments_table = sql.Table( + 'subject_assignments', + meta, + sql.Column('id', sql.String(64), primary_key=True), + sql.Column('assignments', sql.String(256), nullable=True), + sql.Column('policy_id', sql.ForeignKey("policies.id"), nullable=False), + sql.Column('subject_id', sql.ForeignKey("subjects.id"), nullable=False), + sql.Column('category_id', sql.ForeignKey("subject_categories.id"), nullable=False), + sql.UniqueConstraint('policy_id', 'subject_id', 'category_id', + name='unique_constraint_subject_assignment'), + mysql_engine='InnoDB', + mysql_charset='utf8') + subject_assignments_table.create(migrate_engine, checkfirst=True) + sys.stdout.write(str(subject_assignments_table) + " ") + sys.stdout.flush() + + object_assignments_table = sql.Table( + 'object_assignments', + meta, + sql.Column('id', sql.String(64), primary_key=True), + sql.Column('assignments', sql.String(256), nullable=True), + sql.Column('policy_id', sql.ForeignKey("policies.id"), nullable=False), + sql.Column('object_id', sql.ForeignKey("objects.id"), nullable=False), + sql.Column('category_id', sql.ForeignKey("object_categories.id"), nullable=False), + sql.UniqueConstraint('policy_id', 'object_id', 'category_id', + name='unique_constraint_object_assignment'), + mysql_engine='InnoDB', + mysql_charset='utf8') + object_assignments_table.create(migrate_engine, checkfirst=True) + sys.stdout.write(str(object_assignments_table) + " ") + sys.stdout.flush() + + action_assignments_table = sql.Table( + 'action_assignments', + meta, + sql.Column('id', sql.String(64), primary_key=True), + sql.Column('assignments', sql.String(256), nullable=True), + sql.Column('policy_id', sql.ForeignKey("policies.id"), nullable=False), + sql.Column('action_id', sql.ForeignKey("actions.id"), nullable=False), + sql.Column('category_id', sql.ForeignKey("action_categories.id"), nullable=False), + sql.UniqueConstraint('policy_id', 'action_id', 'category_id', + name='unique_constraint_action_assignment'), + mysql_engine='InnoDB', + mysql_charset='utf8') + action_assignments_table.create(migrate_engine, checkfirst=True) + sys.stdout.write(str(action_assignments_table) + " ") + sys.stdout.flush() + + meta_rules_table = sql.Table( + 'meta_rules', + meta, + sql.Column('id', sql.String(64), primary_key=True), + sql.Column('name', sql.String(256), nullable=False), + sql.Column('subject_categories', JsonBlob(), nullable=False), + sql.Column('object_categories', JsonBlob(), nullable=False), + sql.Column('action_categories', JsonBlob(), nullable=False), + sql.Column('value', JsonBlob(), nullable=True), + sql.UniqueConstraint('name', name='unique_constraint_meta_rule_name'), + # sql.UniqueConstraint('subject_categories', 'object_categories', 'action_categories', name='unique_constraint_meta_rule_def'), + mysql_engine='InnoDB', + mysql_charset='utf8') + meta_rules_table.create(migrate_engine, checkfirst=True) + sys.stdout.write(str(meta_rules_table) + " ") + sys.stdout.flush() + + rules_table = sql.Table( + 'rules', + meta, + sql.Column('id', sql.String(64), primary_key=True), + sql.Column('rule', JsonBlob(), nullable=True), + sql.Column('policy_id', sql.ForeignKey("policies.id"), nullable=False), + sql.Column('meta_rule_id', sql.ForeignKey("meta_rules.id"), nullable=False), + mysql_engine='InnoDB', + mysql_charset='utf8') + rules_table.create(migrate_engine, checkfirst=True) + sys.stdout.write(str(rules_table) + " ") + sys.stdout.flush() + print("") + + +def downgrade(migrate_engine): + if isinstance(migrate_engine, str): + migrate_engine = create_engine(migrate_engine) + meta = sql.MetaData() + meta.bind = migrate_engine + + for _table in ( + 'rules', + 'meta_rules', + 'action_assignments', + 'object_assignments', + 'subject_assignments', + 'action_data', + 'object_data', + 'subject_data', + 'actions', + 'objects', + 'subjects', + 'action_categories', + 'object_categories', + 'subject_categories', + 'models', + 'policies', + 'pdp', + 'slaves' + ): + try: + table = sql.Table(_table, meta, autoload=True) + table.drop(migrate_engine, checkfirst=True) + except Exception as e: + print(e) diff --git a/moon_manager/moon_manager/api/db/model.py b/moon_manager/moon_manager/api/db/model.py new file mode 100644 index 00000000..9dc6273a --- /dev/null +++ b/moon_manager/moon_manager/api/db/model.py @@ -0,0 +1,429 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +from uuid import uuid4 +import logging +from moon_utilities import exceptions +from moon_utilities.security_functions import enforce +from moon_manager.api.db.managers import Managers +import copy +from moon_manager import pip_driver + +logger = logging.getLogger("moon.db.api.model") + + +class ModelManager(Managers): + + def __init__(self, connector=None): + self.driver = connector.driver + Managers.ModelManager = self + + @enforce(("read", "write"), "models") + def update_model(self, moon_user_id, model_id, value): + if model_id not in self.driver.get_models(model_id=model_id): + raise exceptions.ModelUnknown + + if not value['name'].strip(): + raise exceptions.ModelContentError('Model name invalid') + + if 'meta_rules' not in value: + raise exceptions.MetaRuleUnknown + + model = self.get_models(moon_user_id=moon_user_id, model_id=model_id) + model = model[next(iter(model))] + if ((model['meta_rules'] and value['meta_rules'] and model['meta_rules'] != value[ + 'meta_rules']) \ + or (model['meta_rules'] and not value['meta_rules'])): + policies = Managers.PolicyManager.get_policies(moon_user_id=moon_user_id) + for policy_id in policies: + if policies[policy_id]["model_id"] == model_id: + raise exceptions.DeleteModelWithPolicy + + if value and 'meta_rules' in value: + for meta_rule_id in value['meta_rules']: + if meta_rule_id: + meta_rule_tmp = self.driver.get_meta_rules(meta_rule_id=meta_rule_id) + if (not meta_rule_id) or (not meta_rule_tmp) : + raise exceptions.MetaRuleUnknown + + return self.driver.update_model(model_id=model_id, value=value) + + @enforce(("read", "write"), "models") + def delete_model(self, moon_user_id, model_id): + if model_id not in self.driver.get_models(model_id=model_id): + raise exceptions.ModelUnknown + # TODO (asteroide): check that no policy is connected to this model + policies = Managers.PolicyManager.get_policies(moon_user_id=moon_user_id) + for policy in policies: + if policies[policy]['model_id'] == model_id: + raise exceptions.DeleteModelWithPolicy + return self.driver.delete_model(model_id=model_id) + + @enforce(("read", "write"), "models") + def add_model(self, moon_user_id, model_id=None, value=None): + + if not value['name'].strip(): + raise exceptions.ModelContentError('Model name invalid') + + models = self.driver.get_models() + if model_id in models: + raise exceptions.ModelExisting + + if value.get('meta_rules', []): + for model in models: + if models[model]['name'] == value['name']: + raise exceptions.ModelExisting("Model Name Existed") + if sorted(models[model].get('meta_rules', [])) == sorted(value.get('meta_rules', [])): + raise exceptions.ModelExisting("Meta Rules List Existed in another Model") + + if not model_id: + model_id = uuid4().hex + if value and 'meta_rules' in value: + for meta_rule_id in value['meta_rules']: + if not meta_rule_id: + raise exceptions.MetaRuleUnknown + meta_rule = self.driver.get_meta_rules(meta_rule_id=meta_rule_id) + if not meta_rule: + raise exceptions.MetaRuleUnknown + + return self.driver.add_model(model_id=model_id, value=value) + + @enforce("read", "models") + def get_models(self, moon_user_id, model_id=None): + return self.driver.get_models(model_id=model_id) + + @enforce("read", "policies") + def get_policies(self, moon_user_id, policy_id=None): + return self.driver.get_policies(policy_id=policy_id) + + @enforce(("read", "write"), "meta_rules") + def update_meta_rule(self, moon_user_id, meta_rule_id, value): + meta_rules = self.driver.get_meta_rules() + if not meta_rule_id or meta_rule_id not in meta_rules: + raise exceptions.MetaRuleUnknown + self.__check_meta_rule_dependencies(moon_user_id=moon_user_id, meta_rule_id=meta_rule_id) + if value: + if not value['name'].strip(): + raise exceptions.MetaRuleContentError('Meta_rule name invalid') + + if 'subject_categories' in value: + if (len(value['subject_categories']) == 1 and (value['subject_categories'][0] is None or value[ + 'subject_categories'][0].strip() == "")): + value['subject_categories'] = []; + else: + for subject_category_id in value['subject_categories']: + if (not subject_category_id) or (not self.driver.get_subject_categories( + category_id=subject_category_id)): + raise exceptions.SubjectCategoryUnknown + if 'object_categories' in value: + if (len(value['object_categories']) == 1 and (value['object_categories'][0] is None or value[ + 'object_categories'][0].strip() == "")): + value['object_categories'] = []; + else: + for object_category_id in value['object_categories']: + if (not object_category_id) or (not self.driver.get_object_categories( + category_id=object_category_id)): + raise exceptions.ObjectCategoryUnknown + if 'action_categories' in value: + if (len(value['action_categories']) == 1 and (value['action_categories'][0] is None or value[ + 'action_categories'][0].strip() == "")): + value['action_categories'] = []; + else: + for action_category_id in value['action_categories']: + if (not action_category_id) or (not self.driver.get_action_categories( + category_id=action_category_id)): + raise exceptions.ActionCategoryUnknown + + for meta_rule_obj_id in meta_rules: + counter_matched_list = 0 + counter_matched_list += self.check_combination( + meta_rules[meta_rule_obj_id]['subject_categories'], + value['subject_categories']) + counter_matched_list += self.check_combination( + meta_rules[meta_rule_obj_id]['object_categories'], + value['object_categories']) + counter_matched_list += self.check_combination( + meta_rules[meta_rule_obj_id]['action_categories'], + value['action_categories']) + if counter_matched_list == 3 and meta_rule_obj_id != meta_rule_id: + raise exceptions.MetaRuleExisting("Same categories combination existed") + + return self.driver.set_meta_rule(meta_rule_id=meta_rule_id, value=value) + + def __check_meta_rule_dependencies(self, moon_user_id, meta_rule_id): + policies = self.get_policies(moon_user_id=moon_user_id) + for policy in policies: + model_id = policies[policy]["model_id"] + model = self.get_models(moon_user_id=moon_user_id, model_id=model_id)[model_id] + if meta_rule_id in model["meta_rules"]: + raise exceptions.MetaRuleUpdateError("This meta_rule is already in use in a policy") + + policies = Managers.PolicyManager.get_policies(moon_user_id=moon_user_id) + for policy_id in policies: + rules = Managers.PolicyManager.get_rules(moon_user_id=moon_user_id, policy_id=policy_id, + meta_rule_id=meta_rule_id) + if rules['rules']: + raise exceptions.MetaRuleUpdateError + + @enforce("read", "meta_rules") + def get_meta_rules(self, moon_user_id, meta_rule_id=None): + return self.driver.get_meta_rules(meta_rule_id=meta_rule_id) + + @enforce(("read", "write"), "meta_rules") + def add_meta_rule(self, moon_user_id, meta_rule_id=None, value=None): + + if not value['name'].strip(): + raise exceptions.MetaRuleContentError('Meta_rule name invalid') + + meta_rules = self.driver.get_meta_rules() + + if meta_rule_id in meta_rules: + raise exceptions.MetaRuleExisting + + if value: + if 'subject_categories' in value: + if (len(value['subject_categories']) == 1 and (value['subject_categories'][0] is None or value[ + 'subject_categories'][0].strip() == "")): + value['subject_categories'] = []; + else: + for subject_category_id in value['subject_categories']: + if ((not subject_category_id) or (not self.driver.get_subject_categories( + category_id=subject_category_id))): + if subject_category_id.startswith("attributes:"): + _attributes = pip_driver.AttrsManager.get_objects( + moon_user_id="admin", + object_type=subject_category_id.replace("attributes:", "") + ) + action_category_id = subject_category_id.replace("attributes:", "") + if action_category_id != _attributes['id']: + raise exceptions.SubjectCategoryUnknown + else: + raise exceptions.SubjectCategoryUnknown + if 'object_categories' in value: + if(len(value['object_categories']) == 1 and (value['object_categories'][0] is None or value[ + 'object_categories'][0].strip() == "")): + value['object_categories'] = []; + else: + for object_category_id in value['object_categories']: + if ((not object_category_id) or (not self.driver.get_object_categories( + category_id=object_category_id))): + if object_category_id.startswith("attributes:"): + _attributes = pip_driver.AttrsManager.get_objects( + moon_user_id="admin", + object_type=object_category_id.replace("attributes:", "") + ) + action_category_id = object_category_id.replace("attributes:", "") + if action_category_id != _attributes['id']: + raise exceptions.ObjectCategoryUnknown + else: + raise exceptions.ObjectCategoryUnknown + if 'action_categories' in value: + if (len(value['action_categories']) == 1 and (value['action_categories'][0] is None or value[ + 'action_categories'][0].strip() == "")): + value['action_categories'] = []; + else: + for action_category_id in value['action_categories']: + if ((not action_category_id) or (not self.driver.get_action_categories( + category_id=action_category_id))): + if action_category_id.startswith("attributes:"): + _attributes = pip_driver.AttrsManager.get_objects( + moon_user_id="admin", + object_type=action_category_id.replace("attributes:", "") + ) + action_category_id = action_category_id.replace("attributes:", "") + if action_category_id not in _attributes.keys(): + raise exceptions.ActionCategoryUnknown + else: + raise exceptions.ActionCategoryUnknown + + for meta_rule_obj_id in meta_rules: + counter_matched_list = 0 + + counter_matched_list += self.check_combination( + meta_rules[meta_rule_obj_id]['subject_categories'], value['subject_categories']) + + counter_matched_list += self.check_combination( + meta_rules[meta_rule_obj_id]['object_categories'], value['object_categories']) + + counter_matched_list += self.check_combination( + meta_rules[meta_rule_obj_id]['action_categories'], value['action_categories']) + + if counter_matched_list == 3: + raise exceptions.MetaRuleExisting("Same categories combination existed") + + return self.driver.set_meta_rule(meta_rule_id=meta_rule_id, value=value) + + # @enforce(("read", "write"), "meta_rules") + def check_combination(self, list_one, list_two): + counter_removed_items = 0 + temp_list_two = copy.deepcopy(list_two) + for item in list_one: + if item in temp_list_two: + temp_list_two.remove(item) + counter_removed_items += 1 + + if list_two and counter_removed_items == len(list_two) and len(list_two) == len(list_one): + return 1 + return 0 + + @enforce(("read", "write"), "meta_rules") + def delete_meta_rule(self, moon_user_id, meta_rule_id=None): + if meta_rule_id not in self.driver.get_meta_rules(meta_rule_id=meta_rule_id): + raise exceptions.MetaRuleUnknown + # TODO (asteroide): check and/or delete data and assignments and rules linked to that meta_rule + models = self.get_models(moon_user_id=moon_user_id) + for model_id in models: + for id in models[model_id]['meta_rules']: + if id == meta_rule_id: + raise exceptions.DeleteMetaRuleWithModel + return self.driver.delete_meta_rule(meta_rule_id=meta_rule_id) + + @enforce("read", "meta_data") + def get_subject_categories(self, moon_user_id, category_id=None): + return self.driver.get_subject_categories(category_id=category_id) + + @enforce(("read", "write"), "meta_data") + def add_subject_category(self, moon_user_id, category_id=None, value=None): + + if not value['name'].strip(): + raise exceptions.CategoryNameInvalid + + subject_categories = [] + if category_id is not None: + subject_categories = self.driver.get_subject_categories(category_id=category_id) + + subject_categories_names = self.driver.get_subject_categories(category_name=value['name'].strip()) + + if subject_categories_names or subject_categories: + raise exceptions.SubjectCategoryExisting + + + if not ('description' in value): + value['description'] = "" + return self.driver.add_subject_category(name=value["name"], + description=value["description"], uuid=category_id) + + @enforce(("read", "write"), "meta_data") + def delete_subject_category(self, moon_user_id, category_id): + # TODO (asteroide): delete all data linked to that category + # TODO (asteroide): delete all meta_rules linked to that category + if category_id not in self.driver.get_subject_categories(category_id=category_id): + raise exceptions.SubjectCategoryUnknown + meta_rules = self.get_meta_rules(moon_user_id=moon_user_id) + for meta_rule_id in meta_rules: + for subject_category_id in meta_rules[meta_rule_id]['subject_categories']: + logger.info( + "delete_subject_category {} {}".format(subject_category_id, meta_rule_id)) + logger.info("delete_subject_category {}".format(meta_rules[meta_rule_id])) + if subject_category_id == category_id: + # has_rules = self.driver.is_meta_rule_has_rules(meta_rule_id) + # if has_rules: + raise exceptions.DeleteSubjectCategoryWithMetaRule + + if self.driver.is_subject_category_has_assignment(category_id): + raise exceptions.DeleteCategoryWithAssignment + + if self.driver.is_subject_data_exist(category_id=category_id): + raise exceptions.DeleteCategoryWithData + + return self.driver.delete_subject_category(category_id=category_id) + + @enforce("read", "meta_data") + def get_object_categories(self, moon_user_id, category_id=None): + return self.driver.get_object_categories(category_id) + + @enforce(("read", "write"), "meta_data") + def add_object_category(self, moon_user_id, category_id=None, value=None): + if not value['name'].strip(): + raise exceptions.CategoryNameInvalid + + object_categories = [] + if category_id is not None: + object_categories = self.driver.get_object_categories(category_id=category_id) + + object_categories_names = self.driver.get_object_categories(category_name=value['name'].strip()) + if object_categories_names or object_categories: + raise exceptions.ObjectCategoryExisting + + if not ('description' in value): + value['description'] = "" + + return self.driver.add_object_category(name=value["name"], description=value["description"], + uuid=category_id) + + @enforce(("read", "write"), "meta_data") + def delete_object_category(self, moon_user_id, category_id): + # TODO (asteroide): delete all data linked to that category + # TODO (asteroide): delete all meta_rules linked to that category + if category_id not in self.driver.get_object_categories(category_id=category_id): + raise exceptions.ObjectCategoryUnknown + meta_rules = self.get_meta_rules(moon_user_id=moon_user_id) + for meta_rule_id in meta_rules: + for object_category_id in meta_rules[meta_rule_id]['object_categories']: + if object_category_id == category_id: + # has_rules = self.driver.is_meta_rule_has_rules(meta_rule_id) + # if has_rules: + raise exceptions.DeleteObjectCategoryWithMetaRule + + if self.driver.is_object_category_has_assignment(category_id): + raise exceptions.DeleteCategoryWithAssignment + + if self.driver.is_object_data_exist(category_id=category_id): + raise exceptions.DeleteCategoryWithData + + return self.driver.delete_object_category(category_id=category_id) + + @enforce("read", "meta_data") + def get_action_categories(self, moon_user_id, category_id=None): + return self.driver.get_action_categories(category_id=category_id) + + @enforce(("read", "write"), "meta_data") + def add_action_category(self, moon_user_id, category_id=None, value=None): + + if not value['name'].strip(): + raise exceptions.CategoryNameInvalid + + action_categories = [] + if category_id is not None: + action_categories = self.driver.get_action_categories(category_id=category_id) + + action_categories_names = self.driver.get_action_categories(category_name=value['name'].strip()) + if action_categories_names or action_categories: + raise exceptions.ActionCategoryExisting + + if not ('description' in value): + value['description'] = "" + + return self.driver.add_action_category(name=value["name"], description=value["description"], + uuid=category_id) + + @enforce(("read", "write"), "meta_data") + def delete_action_category(self, moon_user_id, category_id): + # TODO (asteroide): delete all data linked to that category + # TODO (asteroide): delete all meta_rules linked to that category + if category_id not in self.driver.get_action_categories(category_id=category_id): + raise exceptions.ActionCategoryUnknown + meta_rules = self.get_meta_rules(moon_user_id=moon_user_id) + for meta_rule_id in meta_rules: + for action_category_id in meta_rules[meta_rule_id]['action_categories']: + if action_category_id == category_id: + # has_rules = self.driver.is_meta_rule_has_rules(meta_rule_id) + # if has_rules: + raise exceptions.DeleteActionCategoryWithMetaRule + + if self.driver.is_action_category_has_assignment(category_id): + raise exceptions.DeleteCategoryWithAssignment + + if self.driver.is_action_data_exist(category_id=category_id): + raise exceptions.DeleteCategoryWithData + + return self.driver.delete_action_category(category_id=category_id) diff --git a/moon_manager/moon_manager/api/db/pdp.py b/moon_manager/moon_manager/api/db/pdp.py new file mode 100644 index 00000000..a4ca08f6 --- /dev/null +++ b/moon_manager/moon_manager/api/db/pdp.py @@ -0,0 +1,115 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +from uuid import uuid4 +import logging +from moon_utilities.security_functions import enforce +from moon_manager.api.db.managers import Managers +from moon_utilities import exceptions + +logger = logging.getLogger("moon.db.api.pdp") + + +class PDPManager(Managers): + + def __init__(self, connector=None): + self.driver = connector.driver + Managers.PDPManager = self + + @enforce(("read", "write"), "pdp") + def update_pdp(self, moon_user_id, pdp_id, value): + if not value or 'name' not in value or not value['name'].strip(): + raise exceptions.PdpContentError + + exists_security_pipeline = value and 'security_pipeline' in value and \ + len(value['security_pipeline']) > 0 + exists_vim_project_id = value and 'vim_project_id' in value and \ + value['vim_project_id'] != None and \ + value['vim_project_id'].strip() + if not exists_security_pipeline and exists_vim_project_id: + raise exceptions.PdpContentError + if exists_security_pipeline and not exists_vim_project_id: + raise exceptions.PdpContentError + + self.__pdp_validated_pipeline_name_id(pdp_id, value, "update") + + if value and 'security_pipeline' in value: + for policy_id in value['security_pipeline']: + if not policy_id or not policy_id.strip() or not \ + Managers.PolicyManager.get_policies(moon_user_id=moon_user_id, policy_id=policy_id): + raise exceptions.PolicyUnknown + + return self.driver.update_pdp(pdp_id=pdp_id, value=value) + + @enforce(("read", "write"), "pdp") + def delete_pdp(self, moon_user_id, pdp_id): + if pdp_id not in self.driver.get_pdp(pdp_id=pdp_id): + raise exceptions.PdpUnknown + return self.driver.delete_pdp(pdp_id=pdp_id) + + @enforce(("read", "write"), "pdp") + def add_pdp(self, moon_user_id, pdp_id=None, value=None): + if not value or 'name' not in value or not value['name'].strip(): + raise exceptions.PdpContentError + + exists_security_pipeline = value and 'security_pipeline' in value and \ + len(value['security_pipeline']) > 0 + exists_vim_project_id = value and 'vim_project_id' in value and \ + value['vim_project_id'] is not None and \ + value['vim_project_id'].strip() + if not exists_security_pipeline and exists_vim_project_id: + raise exceptions.PdpContentError + if exists_security_pipeline and not exists_vim_project_id: + raise exceptions.PdpContentError + + self.__pdp_validated_pipeline_name_id(pdp_id, value, "add") + + if value and 'security_pipeline' in value: + for policy_id in value['security_pipeline']: + if not policy_id or not policy_id.strip() or not \ + Managers.PolicyManager.get_policies(moon_user_id=moon_user_id, policy_id=policy_id): + raise exceptions.PolicyUnknown + + return self.driver.add_pdp(pdp_id=pdp_id, value=value) + + @enforce("read", "pdp") + def get_pdp(self, moon_user_id, pdp_id=None): + return self.driver.get_pdp(pdp_id=pdp_id) + + @enforce("read", "pdp") + def delete_policy_from_pdp(self, moon_user_id, pdp_id, policy_id): + + if pdp_id not in self.driver.get_pdp(pdp_id=pdp_id): + raise exceptions.PdpUnknown + if policy_id not in self.driver.get_policies(policy_id=policy_id): + raise exceptions.PolicyUnknown + x = self.driver.delete_policy_from_pdp(pdp_id=pdp_id, policy_id=policy_id) + return x + + def __pdp_validated_pipeline_name_id(self, pdp_id, value, method_type=None): + all_pdps = self.driver.get_pdp() + if method_type == 'update': + if pdp_id not in all_pdps: + raise exceptions.PdpUnknown + else: + if pdp_id in all_pdps: + raise exceptions.PdpExisting + if not pdp_id: + pdp_id = uuid4().hex + + for key in all_pdps: + if pdp_id != key: + if all_pdps[key]['name'] == value['name']: + raise exceptions.PdpExisting + for policy_id in value['security_pipeline']: + if policy_id in all_pdps[key]['security_pipeline']: + raise exceptions.PdpInUse diff --git a/moon_manager/moon_manager/api/db/policy.py b/moon_manager/moon_manager/api/db/policy.py new file mode 100644 index 00000000..e736aca7 --- /dev/null +++ b/moon_manager/moon_manager/api/db/policy.py @@ -0,0 +1,971 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +import logging +from uuid import uuid4 +from moon_manager.api.db.managers import Managers +from moon_manager.pip_driver import InformationManager +from moon_utilities.security_functions import enforce +from moon_utilities import exceptions +from moon_manager import pip_driver + + +logger = logging.getLogger("moon.db.api.policy") + + +class PolicyManager(Managers): + + def __init__(self, connector=None): + self.driver = connector.driver + Managers.PolicyManager = self + + def get_policy_from_meta_rules(self, moon_user_id, meta_rule_id): + policies = self.PolicyManager.get_policies("admin") + models = self.ModelManager.get_models("admin") + for pdp_key, pdp_value in self.PDPManager.get_pdp(moon_user_id=moon_user_id).items(): + if 'security_pipeline' not in pdp_value: + raise exceptions.PdpContentError + for policy_id in pdp_value["security_pipeline"]: + if not policies or policy_id not in policies: + raise exceptions.PolicyUnknown + model_id = policies[policy_id]["model_id"] + if not models: + raise exceptions.ModelUnknown + if model_id not in models: + raise exceptions.ModelUnknown + if meta_rule_id in models[model_id]["meta_rules"]: + return policy_id + + @enforce(("read", "write"), "policies") + def update_policy(self, moon_user_id, policy_id, value): + + if not value or not value['name'].strip(): + raise exceptions.PolicyContentError + + policy_list = self.driver.get_policies(policy_id=policy_id) + if not policy_id or policy_id not in policy_list: + raise exceptions.PolicyUnknown + + policies = self.driver.get_policies(policy_name=value['name']) + if policies and not (policy_id in policies): + raise exceptions.PolicyExisting("Policy name Existed") + + if 'model_id' in value and value['model_id']: + if not value['model_id'].strip() or not Managers.ModelManager.get_models( + moon_user_id=moon_user_id, model_id=value['model_id']): + raise exceptions.ModelUnknown + + policy_obj = policy_list[policy_id] + if policy_obj["model_id"] and policy_obj["model_id"] != value['model_id']: + raise exceptions.PolicyUpdateError("Model is not empty") + + return self.driver.update_policy(policy_id=policy_id, value=value) + + @enforce(("read", "write"), "policies") + def delete_policy(self, moon_user_id, policy_id): + # TODO (asteroide): unmap PDP linked to that policy + if policy_id not in self.driver.get_policies(policy_id=policy_id): + raise exceptions.PolicyUnknown + pdps = self.PDPManager.get_pdp(moon_user_id=moon_user_id) + for pdp in pdps: + if policy_id in pdps[pdp]['security_pipeline']: + self.PDPManager.delete_policy_from_pdp(moon_user_id=moon_user_id, + pdp_id=pdp, + policy_id=policy_id) + + subject_data = self.get_subject_data(moon_user_id=moon_user_id, policy_id=policy_id) + if subject_data: + for subject_data_obj in subject_data: + if subject_data_obj and subject_data_obj["data"]: + for subject_data_id in subject_data_obj['data']: + self.delete_subject_data(moon_user_id=moon_user_id, policy_id=policy_id, + data_id=subject_data_id) + + object_data = self.get_object_data(moon_user_id=moon_user_id, policy_id=policy_id) + if object_data: + for object_data_obj in object_data: + if object_data_obj and object_data_obj["data"]: + for object_data_id in object_data_obj['data']: + self.delete_object_data(moon_user_id=moon_user_id, policy_id=policy_id, + data_id=object_data_id) + action_data = self.get_action_data(moon_user_id=moon_user_id, policy_id=policy_id) + if action_data: + for action_data_obj in action_data: + if action_data_obj and action_data_obj["data"]: + for action_data_id in action_data_obj['data']: + self.delete_action_data(moon_user_id=moon_user_id, policy_id=policy_id, + data_id=action_data_id) + + subjects = self.driver.get_subjects(policy_id=policy_id) + if subjects: + for subject_id in subjects: + self.delete_subject(moon_user_id=moon_user_id, policy_id=policy_id, + perimeter_id=subject_id) + objects = self.driver.get_objects(policy_id=policy_id) + if objects: + for object_id in objects: + self.delete_object(moon_user_id=moon_user_id, policy_id=policy_id, + perimeter_id=object_id) + actions = self.driver.get_actions(policy_id=policy_id) + if actions: + for action_id in actions: + self.delete_action(moon_user_id=moon_user_id, policy_id=policy_id, + perimeter_id=action_id) + + # rules = self.driver.get_rules(policy_id=policy_id)["rules"] + # if rules: + # for rule_id in rules: + # self.delete_rule(moon_user_id=moon_user_id, policy_id=policy_id, rules=rule_id) + + return self.driver.delete_policy(policy_id=policy_id) + + @enforce(("read", "write"), "policies") + def add_policy(self, moon_user_id, policy_id=None, value=None): + + if not value or not value['name'].strip(): + raise exceptions.PolicyContentError + if policy_id in self.driver.get_policies(policy_id=policy_id): + raise exceptions.PolicyExisting + + if self.driver.get_policies(policy_name=value['name']): + raise exceptions.PolicyExisting("Policy name Existed") + + if not policy_id: + policy_id = uuid4().hex + if 'model_id' in value and value['model_id'] != "": + model_id = value['model_id'] + if model_id is None: + raise exceptions.ModelUnknown + else: + model_list = Managers.ModelManager.get_models(moon_user_id=moon_user_id, + model_id=model_id) + if not model_list: + raise exceptions.ModelUnknown + + self.__check_blank_model(model_list[model_id]) + + return self.driver.add_policy(policy_id=policy_id, value=value) + + @enforce("read", "policies") + def get_policies(self, moon_user_id, policy_id=None): + return self.driver.get_policies(policy_id=policy_id) + + @enforce("read", "perimeter") + def get_subjects(self, moon_user_id, policy_id, perimeter_id=None): + # if not policy_id: + # raise exceptions.PolicyUnknown + if policy_id and (not self.get_policies(moon_user_id=moon_user_id, policy_id=policy_id)): + raise exceptions.PolicyUnknown + return self.driver.get_subjects(policy_id=policy_id, perimeter_id=perimeter_id) + + @enforce(("read", "write"), "perimeter") + def add_subject(self, moon_user_id, policy_id=None, perimeter_id=None, value=None): + + logger.debug("add_subject {}".format(policy_id)) + if not value or "name" not in value or not value["name"].strip(): + raise exceptions.PerimeterContentError('invalid name') + + if 'policy_list' in value: + raise exceptions.PerimeterContentError("body should not contain policy_list") + + if policy_id and (not self.get_policies(moon_user_id=moon_user_id, policy_id=policy_id)): + raise exceptions.PolicyUnknown + + if perimeter_id: + subjects = self.driver.get_subjects(policy_id=None, perimeter_id=perimeter_id) + if subjects and subjects[perimeter_id]['name'] != value['name']: + raise exceptions.PerimeterContentError + + if not perimeter_id: + subject_per = self.driver.get_subject_by_name(value['name']) + if subject_per: + perimeter_id = next(iter(subject_per)) + + # should get k_user = {'users':[{"id":"11111"}]} from Keystone + # FIXME: need to check other input + # k_user = InformationManager.get_users(username=value.get('name')) + # + # if not k_user.get('users', {}): + # k_user = InformationManager.add_user(**value) + # if k_user: + # if not perimeter_id: + # try: + # logger.info("k_user={}".format(k_user)) + # perimeter_id = k_user['users'][0].get('id', uuid4().hex) + # except IndexError: + # k_user = InformationManager.get_users(value.get('name')) + # perimeter_id = uuid4().hex + # except KeyError: + # k_user = InformationManager.get_users(value.get('name')) + # perimeter_id = uuid4().hex + # + # try: + # value.update(k_user['users'][0]) + # except IndexError: + # logger.error("Cannot update user from external server data, got {}".format(k_user)) + + return self.driver.set_subject(policy_id=policy_id, perimeter_id=perimeter_id, value=value) + + @enforce(("read", "write"), "perimeter") + def update_subject(self, moon_user_id, perimeter_id, value): + logger.debug("update_subject perimeter_id = {}".format(perimeter_id)) + + if not perimeter_id: + raise exceptions.SubjectUnknown + + subjects = self.driver.get_subjects(policy_id=None, perimeter_id=perimeter_id) + if not subjects or not (perimeter_id in subjects): + raise exceptions.PerimeterContentError + + if 'policy_list' in value or ('name' in value and not value['name']): + raise exceptions.PerimeterContentError + + return self.driver.update_subject(perimeter_id=perimeter_id, value=value) + + @enforce(("read", "write"), "perimeter") + def delete_subject(self, moon_user_id, policy_id, perimeter_id): + + if not perimeter_id: + raise exceptions.SubjectUnknown + + # if not policy_id: + # raise exceptions.PolicyUnknown + + if not self.get_subjects(moon_user_id=moon_user_id, policy_id=policy_id, + perimeter_id=perimeter_id): + raise exceptions.SubjectUnknown + + if policy_id: + if not self.get_policies(moon_user_id=moon_user_id, policy_id=policy_id): + raise exceptions.PolicyUnknown + + subj_assig = self.driver.get_subject_assignments(policy_id=policy_id, + subject_id=perimeter_id) + if subj_assig: + assign_id = next(iter(subj_assig)) + for data_id in subj_assig[assign_id]['assignments']: + self.delete_subject_assignment(moon_user_id=moon_user_id, + policy_id=policy_id, + subject_id=perimeter_id, + category_id=subj_assig[assign_id]['category_id'], + data_id=data_id) + + return self.driver.delete_subject(policy_id=policy_id, perimeter_id=perimeter_id) + + @enforce("read", "perimeter") + def get_objects(self, moon_user_id, policy_id, perimeter_id=None): + # if not policy_id: + # pass + if policy_id and (not self.get_policies(moon_user_id=moon_user_id, policy_id=policy_id)): + raise exceptions.PolicyUnknown + return self.driver.get_objects(policy_id=policy_id, perimeter_id=perimeter_id) + + @enforce(("read", "write"), "perimeter") + def add_object(self, moon_user_id, policy_id, perimeter_id=None, value=None): + logger.debug("add_object {}".format(policy_id)) + + if not value or "name" not in value or not value["name"].strip(): + raise exceptions.PerimeterContentError('invalid name') + + if 'policy_list' in value: + raise exceptions.PerimeterContentError("body should not contain policy_list") + + if policy_id and (not self.get_policies(moon_user_id=moon_user_id, policy_id=policy_id)): + raise exceptions.PolicyUnknown + + # object_perimeter = {} + # if perimeter_id: + # object_perimeter = self.driver.get_objects(policy_id=None, perimeter_id=perimeter_id) + # if not object_perimeter: + # raise exceptions.PerimeterContentError + # empeche l'ajout d'un objet avec un id prédéterminé + + if not perimeter_id: + object_perimeter = self.driver.get_object_by_name(value['name']) + if object_perimeter: + perimeter_id = next(iter(object_perimeter)) + + if perimeter_id: + objects = self.driver.get_objects(policy_id=None, perimeter_id=perimeter_id) + if objects and objects[perimeter_id]['name'] != value['name']: + raise exceptions.PerimeterContentError + + if not perimeter_id: + perimeter_id = uuid4().hex + return self.driver.set_object(policy_id=policy_id, perimeter_id=perimeter_id, value=value) + + @enforce(("read", "write"), "perimeter") + def update_object(self, moon_user_id, perimeter_id, value): + logger.debug("update_object perimeter_id = {}".format(perimeter_id)) + + if not perimeter_id: + raise exceptions.ObjectUnknown + + objects = self.driver.get_objects(policy_id=None, perimeter_id=perimeter_id) + if not objects or not (perimeter_id in objects): + raise exceptions.PerimeterContentError + + if 'policy_list' in value or ('name' in value and not value['name']): + raise exceptions.PerimeterContentError + + return self.driver.update_object(perimeter_id=perimeter_id, value=value) + + @enforce(("read", "write"), "perimeter") + def delete_object(self, moon_user_id, policy_id, perimeter_id): + + if not perimeter_id: + raise exceptions.ObjectUnknown + + # if not policy_id: + # raise exceptions.PolicyUnknown + + if not self.get_objects(moon_user_id=moon_user_id, policy_id=policy_id, + perimeter_id=perimeter_id): + raise exceptions.ObjectUnknown + + if policy_id: + + if not self.get_policies(moon_user_id=moon_user_id, policy_id=policy_id): + raise exceptions.PolicyUnknown + + obj_assig = self.driver.get_object_assignments(policy_id=policy_id, object_id=perimeter_id) + + if obj_assig: + assign_id = next(iter(obj_assig)) + for data_id in obj_assig[assign_id]['assignments']: + self.delete_object_assignment(moon_user_id, + policy_id=policy_id, + object_id=perimeter_id, + category_id=obj_assig[assign_id]['category_id'], + data_id=data_id) + + return self.driver.delete_object(policy_id=policy_id, perimeter_id=perimeter_id) + + @enforce("read", "perimeter") + def get_actions(self, moon_user_id, policy_id, perimeter_id=None): + + if policy_id and (not self.get_policies(moon_user_id=moon_user_id, policy_id=policy_id)): + raise exceptions.PolicyUnknown + return self.driver.get_actions(policy_id=policy_id, perimeter_id=perimeter_id) + + @enforce(("read", "write"), "perimeter") + def add_action(self, moon_user_id, policy_id, perimeter_id=None, value=None): + logger.debug("add_action {}".format(policy_id)) + + if not value or "name" not in value or not value["name"].strip(): + raise exceptions.PerimeterContentError('invalid name') + + if 'policy_list' in value: + raise exceptions.PerimeterContentError("body should not contain policy_list") + + if policy_id and (not self.get_policies(moon_user_id=moon_user_id, policy_id=policy_id)): + raise exceptions.PolicyUnknown + + action_perimeter = {} + if perimeter_id: + action_perimeter = self.driver.get_actions(policy_id=None, perimeter_id=perimeter_id) + if not action_perimeter: + raise exceptions.PerimeterContentError + + if not perimeter_id: + action_perimeter = self.driver.get_action_by_name(value['name']) + if action_perimeter: + perimeter_id = next(iter(action_perimeter)) + + if perimeter_id and action_perimeter[perimeter_id]['name'] != value['name']: + raise exceptions.PerimeterContentError + + if not perimeter_id: + perimeter_id = uuid4().hex + + return self.driver.set_action(policy_id=policy_id, perimeter_id=perimeter_id, value=value) + + @enforce(("read", "write"), "perimeter") + def update_action(self, moon_user_id, perimeter_id, value): + logger.debug("update_action perimeter_id = {}".format(perimeter_id)) + + if not perimeter_id: + raise exceptions.ActionUnknown + + actions = self.driver.get_actions(policy_id=None, perimeter_id=perimeter_id) + if not actions or not (perimeter_id in actions): + raise exceptions.PerimeterContentError + + if 'policy_list' in value or ('name' in value and not value['name'].strip()): + raise exceptions.PerimeterContentError + + return self.driver.update_action(perimeter_id=perimeter_id, value=value) + + @enforce(("read", "write"), "perimeter") + def delete_action(self, moon_user_id, policy_id, perimeter_id): + + if not perimeter_id: + raise exceptions.ActionUnknown + + # if not policy_id: + # raise exceptions.PolicyUnknown + + if not self.get_actions(moon_user_id=moon_user_id, policy_id=policy_id, + perimeter_id=perimeter_id): + raise exceptions.ActionUnknown + + logger.debug("delete_action {} {} {}".format(policy_id, perimeter_id, + self.get_policies(moon_user_id=moon_user_id, + policy_id=policy_id))) + if policy_id: + if not self.get_policies(moon_user_id=moon_user_id, policy_id=policy_id): + raise exceptions.PolicyUnknown + + act_assig = self.driver.get_action_assignments(policy_id=policy_id, action_id=perimeter_id) + + if act_assig: + assign_id = next(iter(act_assig)) + for data_id in act_assig[assign_id]['assignments']: + self.delete_action_assignment(moon_user_id=moon_user_id, + policy_id=policy_id, + action_id=perimeter_id, + category_id=act_assig[assign_id]['category_id'], + data_id=data_id) + + return self.driver.delete_action(policy_id=policy_id, perimeter_id=perimeter_id) + + @enforce("read", "data") + def get_subject_data(self, moon_user_id, policy_id, data_id=None, category_id=None): + available_metadata = self.get_available_metadata(moon_user_id=moon_user_id, + policy_id=policy_id) + results = [] + if not category_id: + for cat in available_metadata["subject"]: + _value = self.driver.get_subject_data(policy_id=policy_id, data_id=data_id, + category_id=cat) + results.append(_value) + if category_id and category_id in available_metadata["subject"]: + results.append(self.driver.get_subject_data(policy_id=policy_id, data_id=data_id, + category_id=category_id)) + return results + + @enforce(("read", "write"), "data") + def set_subject_data(self, moon_user_id, policy_id, data_id=None, category_id=None, value=None): + + logger.debug("set_subject_data policyID {}".format(policy_id)) + + if not value or 'name' not in value or not value['name'].strip(): + raise exceptions.DataContentError + + if not policy_id or not self.get_policies(moon_user_id=moon_user_id, policy_id=policy_id): + raise exceptions.PolicyUnknown + + if not category_id or ( + not Managers.ModelManager.get_subject_categories(moon_user_id=moon_user_id, + category_id=category_id)): + raise exceptions.SubjectCategoryUnknown + + self.__category_dependency_validation(moon_user_id, policy_id, category_id, + 'subject_categories') + + if not data_id: + data_id = uuid4().hex + return self.driver.set_subject_data(policy_id=policy_id, data_id=data_id, + category_id=category_id, value=value) + + @enforce(("read", "write"), "data") + def delete_subject_data(self, moon_user_id, policy_id, data_id, category_id=None): + # TODO (asteroide): check and/or delete assignments linked to that data + subject_assignments = self.get_subject_assignments(moon_user_id=moon_user_id, + policy_id=policy_id, + category_id=category_id) + if subject_assignments: + for assign_id in subject_assignments: + self.driver.delete_subject_assignment( + policy_id=subject_assignments[assign_id]['policy_id'], + subject_id=subject_assignments[assign_id]['subject_id'], + category_id=subject_assignments[assign_id]['category_id'], + data_id=subject_assignments[assign_id]['id']) + + rules = self.driver.get_rules(policy_id=policy_id) + if rules['rules']: + for rule in rules['rules']: + if data_id in rule['rule']: + self.driver.delete_rule(policy_id, rule['id']) + + return self.driver.delete_subject_data(policy_id=policy_id, category_id=category_id, + data_id=data_id) + + @enforce("read", "data") + def get_object_data(self, moon_user_id, policy_id, data_id=None, category_id=None): + available_metadata = self.get_available_metadata(moon_user_id=moon_user_id, + policy_id=policy_id) + results = [] + if not category_id: + for cat in available_metadata["object"]: + results.append(self.driver.get_object_data(policy_id=policy_id, data_id=data_id, + category_id=cat)) + if category_id and category_id in available_metadata["object"]: + results.append(self.driver.get_object_data(policy_id=policy_id, data_id=data_id, + category_id=category_id)) + return results + + @enforce(("read", "write"), "data") + def add_object_data(self, moon_user_id, policy_id, data_id=None, category_id=None, value=None): + logger.debug("add_object_data policyID {}".format(policy_id)) + + if not value or 'name' not in value or not value['name'].strip(): + raise exceptions.DataContentError + + if not policy_id or not self.get_policies(moon_user_id=moon_user_id, policy_id=policy_id): + raise exceptions.PolicyUnknown + + if not category_id or ( + not Managers.ModelManager.get_object_categories(moon_user_id=moon_user_id, + category_id=category_id)): + raise exceptions.ObjectCategoryUnknown + + self.__category_dependency_validation(moon_user_id, policy_id, category_id, + 'object_categories') + + if not data_id: + data_id = uuid4().hex + return self.driver.set_object_data(policy_id=policy_id, data_id=data_id, + category_id=category_id, value=value) + + @enforce(("read", "write"), "data") + def delete_object_data(self, moon_user_id, policy_id, data_id, category_id=None): + # TODO (asteroide): check and/or delete assignments linked to that data + object_assignments = self.get_object_assignments(moon_user_id=moon_user_id, + policy_id=policy_id, + category_id=category_id) + + if object_assignments: + for assign_id in object_assignments: + self.driver.delete_object_assignment( + policy_id=object_assignments[assign_id]['policy_id'], + object_id=object_assignments[assign_id]['object_id'], + category_id=object_assignments[assign_id]['category_id'], + data_id=object_assignments[assign_id]['id']) + + rules = self.driver.get_rules(policy_id=policy_id) + if rules['rules']: + for rule in rules['rules']: + if data_id in rule['rule']: + self.driver.delete_rule(policy_id, rule['id']) + + return self.driver.delete_object_data(policy_id=policy_id, category_id=category_id, + data_id=data_id) + + @enforce("read", "data") + def get_action_data(self, moon_user_id, policy_id, data_id=None, category_id=None): + available_metadata = self.get_available_metadata(moon_user_id=moon_user_id, + policy_id=policy_id) + results = [] + if not category_id: + for cat in available_metadata["action"]: + results.append(self.driver.get_action_data(policy_id=policy_id, data_id=data_id, + category_id=cat)) + if category_id and category_id in available_metadata["action"]: + if category_id.startswith("attributes:"): + data = {} + attrs = pip_driver.AttrsManager.get_objects( + moon_user_id="admin", + object_type=category_id.replace("attributes:", "")) + for item in attrs.keys(): + data[item] = {"id": item, "name": item, "description": item} + results.append( + { + "policy_id": policy_id, + "category_id": category_id, + "data": data, + } + ) + else: + results.append(self.driver.get_action_data(policy_id=policy_id, + data_id=data_id, + category_id=category_id)) + return results + + @enforce(("read", "write"), "data") + def add_action_data(self, moon_user_id, policy_id, data_id=None, category_id=None, value=None): + + logger.debug("add_action_data policyID {}".format(policy_id)) + + if not value or 'name' not in value or not value['name'].strip(): + raise exceptions.DataContentError + + if not policy_id or not self.get_policies(moon_user_id=moon_user_id, policy_id=policy_id): + raise exceptions.PolicyUnknown + + if not category_id or ( + not Managers.ModelManager.get_action_categories(moon_user_id=moon_user_id, + category_id=category_id)): + raise exceptions.ActionCategoryUnknown + + self.__category_dependency_validation(moon_user_id, policy_id, category_id, + 'action_categories') + + if not data_id: + data_id = uuid4().hex + return self.driver.set_action_data(policy_id=policy_id, data_id=data_id, + category_id=category_id, value=value) + + @enforce(("read", "write"), "data") + def delete_action_data(self, moon_user_id, policy_id, data_id, category_id=None): + # TODO (asteroide): check and/or delete assignments linked to that data + action_assignments = self.get_action_assignments(moon_user_id=moon_user_id, + policy_id=policy_id, + category_id=category_id) + if action_assignments: + for assign_id in action_assignments: + self.driver.delete_action_assignment( + policy_id=action_assignments[assign_id]['policy_id'], + action_id=action_assignments[assign_id]['action_id'], + category_id=action_assignments[assign_id]['category_id'], + data_id=action_assignments[assign_id]['id']) + + rules = self.driver.get_rules(policy_id=policy_id) + if rules['rules']: + for rule in rules['rules']: + if data_id in rule['rule']: + self.driver.delete_rule(policy_id, rule['id']) + + return self.driver.delete_action_data(policy_id=policy_id, category_id=category_id, + data_id=data_id) + + @enforce("read", "assignments") + def get_subject_assignments(self, moon_user_id, policy_id, subject_id=None, category_id=None): + return self.driver.get_subject_assignments(policy_id=policy_id, subject_id=subject_id, + category_id=category_id) + + @enforce(("read", "write"), "assignments") + def add_subject_assignment(self, moon_user_id, policy_id, subject_id, category_id, data_id): + + logger.debug("add_subject_assignment policyID {}".format(policy_id)) + if not category_id or ( + not Managers.ModelManager.get_subject_categories(moon_user_id=moon_user_id, + category_id=category_id)): + raise exceptions.SubjectCategoryUnknown + + self.__category_dependency_validation(moon_user_id, policy_id, category_id, + 'subject_categories') + + if not subject_id or ( + not self.get_subjects(moon_user_id=moon_user_id, policy_id=policy_id, + perimeter_id=subject_id)): + raise exceptions.SubjectUnknown + subjects_data = self.get_subject_data(moon_user_id=moon_user_id, policy_id=policy_id, + data_id=data_id, category_id=category_id) + if not data_id or not subjects_data or data_id not in subjects_data[0]['data']: + raise exceptions.DataUnknown + + return self.driver.add_subject_assignment(policy_id=policy_id, subject_id=subject_id, + category_id=category_id, data_id=data_id) + + @enforce(("read", "write"), "assignments") + def delete_subject_assignment(self, moon_user_id, policy_id, subject_id, category_id, data_id): + if policy_id: + return self.driver.delete_subject_assignment( + policy_id=policy_id, subject_id=subject_id, + category_id=category_id, data_id=data_id) + raise exceptions.PolicyUnknown + + @enforce("read", "assignments") + def get_object_assignments(self, moon_user_id, policy_id, object_id=None, category_id=None): + return self.driver.get_object_assignments(policy_id=policy_id, object_id=object_id, + category_id=category_id) + + @enforce(("read", "write"), "assignments") + def add_object_assignment(self, moon_user_id, policy_id, object_id, category_id, data_id): + + logger.debug("add_object_assignment policyID {}".format(policy_id)) + if not category_id or ( + not Managers.ModelManager.get_object_categories(moon_user_id=moon_user_id, + category_id=category_id)): + raise exceptions.ObjectCategoryUnknown + + self.__category_dependency_validation(moon_user_id, policy_id, category_id, + 'object_categories') + + if not object_id or ( + not self.get_objects(moon_user_id=moon_user_id, policy_id=policy_id, + perimeter_id=object_id)): + raise exceptions.ObjectUnknown + objects_data = self.get_object_data(moon_user_id=moon_user_id, policy_id=policy_id, + data_id=data_id, category_id=category_id) + if not data_id or not objects_data or data_id not in objects_data[0]['data']: + raise exceptions.DataUnknown + + return self.driver.add_object_assignment(policy_id=policy_id, object_id=object_id, + category_id=category_id, data_id=data_id) + + @enforce(("read", "write"), "assignments") + def delete_object_assignment(self, moon_user_id, policy_id, object_id, category_id, data_id): + if policy_id: + return self.driver.delete_object_assignment(policy_id=policy_id, object_id=object_id, + category_id=category_id, data_id=data_id) + raise exceptions.PolicyUnknown + + @enforce("read", "assignments") + def get_action_assignments(self, moon_user_id, policy_id, action_id=None, category_id=None): + return self.driver.get_action_assignments(policy_id=policy_id, action_id=action_id, + category_id=category_id) + + @enforce(("read", "write"), "assignments") + def add_action_assignment(self, moon_user_id, policy_id, action_id, category_id, data_id): + + logger.debug("add_action_assignment policyID {}".format(policy_id)) + + if not category_id or ( + not Managers.ModelManager.get_action_categories(moon_user_id=moon_user_id, + category_id=category_id)): + raise exceptions.ActionCategoryUnknown + + self.__category_dependency_validation(moon_user_id, policy_id, category_id, + 'action_categories') + + if not action_id or ( + not self.get_actions(moon_user_id=moon_user_id, policy_id=policy_id, + perimeter_id=action_id)): + raise exceptions.ActionUnknown + actions_data = self.get_action_data(moon_user_id=moon_user_id, policy_id=policy_id, + data_id=data_id, category_id=category_id) + if not data_id or not actions_data or data_id not in actions_data[0]['data']: + raise exceptions.DataUnknown + + return self.driver.add_action_assignment(policy_id=policy_id, action_id=action_id, + category_id=category_id, data_id=data_id) + + @enforce(("read", "write"), "assignments") + def delete_action_assignment(self, moon_user_id, policy_id, action_id, category_id, data_id): + if policy_id: + return self.driver.delete_action_assignment(policy_id=policy_id, action_id=action_id, + category_id=category_id, data_id=data_id) + raise exceptions.PolicyUnknown + + @enforce("read", "rules") + def get_rules(self, moon_user_id, policy_id, meta_rule_id=None, rule_id=None): + return self.driver.get_rules(policy_id=policy_id, meta_rule_id=meta_rule_id, + rule_id=rule_id) + + @enforce(("read", "write"), "policies") + def update_rule(self, moon_user_id, rule_id, value): + if not value or 'instructions' not in value: + raise exceptions.RuleContentError + + rule_list = self.driver.get_rules(policy_id=None, rule_id=rule_id) + if not rule_id or rule_id not in rule_list: + raise exceptions.RuleUnknown + + return self.driver.update_rule(rule_id=rule_id, value=value) + + @enforce(("read", "write"), "rules") + def add_rule(self, moon_user_id, policy_id, meta_rule_id, value): + + if not meta_rule_id or ( + not self.ModelManager.get_meta_rules(moon_user_id=moon_user_id, + meta_rule_id=meta_rule_id)): + raise exceptions.MetaRuleUnknown + + if not value or 'instructions' not in value: # TODO or not value['instructions']: + raise exceptions.MetaRuleContentError + + decision_exist = False + default_instruction = {"decision": "grant"} + + for instruction in value['instructions']: + if 'decision' in instruction: + decision_exist = True + if not instruction['decision']: + instruction['decision'] = default_instruction['decision'] + elif instruction['decision'].lower() not in ['grant', 'deny', 'continue']: + raise exceptions.RuleContentError("Invalid Decision") + + if not decision_exist: + value['instructions'].append(default_instruction) + + self.__dependencies_validation(moon_user_id, policy_id, meta_rule_id) + + self.__check_existing_rule(policy_id=policy_id, meta_rule_id=meta_rule_id, + moon_user_id=moon_user_id, rule_value=value) + + return self.driver.add_rule(policy_id=policy_id, meta_rule_id=meta_rule_id, value=value) + + def __check_existing_rule(self, moon_user_id, policy_id, meta_rule_id, rule_value): + + if not meta_rule_id: + raise exceptions.MetaRuleUnknown + + meta_rule = self.ModelManager.get_meta_rules(moon_user_id=moon_user_id, + meta_rule_id=meta_rule_id) + if not meta_rule: + raise exceptions.MetaRuleUnknown + + if len(meta_rule[meta_rule_id]['subject_categories']) + len( + meta_rule[meta_rule_id]['object_categories']) \ + + len(meta_rule[meta_rule_id]['action_categories']) > len(rule_value['rule']): + raise exceptions.RuleContentError(message="Missing Data") + + if len(meta_rule[meta_rule_id]['subject_categories']) + len( + meta_rule[meta_rule_id]['object_categories']) \ + + len(meta_rule[meta_rule_id]['action_categories']) < len(rule_value['rule']): + raise exceptions.MetaRuleContentError(message="Missing Data") + + temp_rule_data = list( + rule_value['rule'][0:len(meta_rule[meta_rule_id]['subject_categories'])]) + found_data_counter = 0 + start_sub = len(meta_rule[meta_rule_id]['subject_categories']) + + for sub_cat_id in meta_rule[meta_rule_id]['subject_categories']: + subjects_data = self.get_subject_data(moon_user_id=moon_user_id, + category_id=sub_cat_id, policy_id=policy_id) + if subjects_data: + found_data_counter = self.__validate_data_id(sub_cat_id, subjects_data[0]['data'], + temp_rule_data, + "Missing Subject_category " + , found_data_counter) + + if found_data_counter != len(meta_rule[meta_rule_id]['subject_categories']): + raise exceptions.RuleContentError(message="Missing Data") + + _index = start_sub + len(meta_rule[meta_rule_id]['object_categories']) + temp_rule_data = list(rule_value['rule'][start_sub:_index]) + found_data_counter = 0 + start_sub = start_sub + len(meta_rule[meta_rule_id]['object_categories']) + + for ob_cat_id in meta_rule[meta_rule_id]['object_categories']: + object_data = self.get_object_data(moon_user_id=moon_user_id, + category_id=ob_cat_id, policy_id=policy_id) + if object_data: + found_data_counter = self.__validate_data_id(ob_cat_id, object_data[0]['data'], + temp_rule_data, + "Missing Object_category ", + found_data_counter) + + if found_data_counter != len(meta_rule[meta_rule_id]['object_categories']): + raise exceptions.RuleContentError(message="Missing Data") + + _index = start_sub + len(meta_rule[meta_rule_id]['action_categories']) + temp_rule_data = list(rule_value['rule'][start_sub:_index]) + found_data_counter = 0 + + for act_cat_id in meta_rule[meta_rule_id]['action_categories']: + action_data = self.get_action_data(moon_user_id=moon_user_id, category_id=act_cat_id, + policy_id=policy_id) + if action_data: + found_data_counter = self.__validate_data_id(act_cat_id, action_data[0]['data'], + temp_rule_data, + "Missing Action_category ", + found_data_counter) + + # Note: adding count of data linked to a global attribute + found_data_counter += len(list(filter(lambda x: "attributes:" in x, temp_rule_data))) + if found_data_counter != len(meta_rule[meta_rule_id]['action_categories']): + raise exceptions.RuleContentError(message="Missing Data") + + @staticmethod + def __validate_data_id(cat_id, data_ids, temp_rule_data, error_msg, found_data_counter): + for ID in data_ids: + if ID in temp_rule_data: + temp_rule_data.remove(ID) + found_data_counter += 1 + # if no data id found in the rule, so rule not valid + if found_data_counter < 1: + raise exceptions.RuleContentError(message=error_msg + cat_id) + return found_data_counter + + @enforce(("read", "write"), "rules") + def delete_rule(self, moon_user_id, policy_id, rule_id): + return self.driver.delete_rule(policy_id=policy_id, rule_id=rule_id) + + @enforce("read", "meta_data") + def get_available_metadata(self, moon_user_id, policy_id): + categories = { + "subject": [], + "object": [], + "action": [] + } + policy = self.driver.get_policies(policy_id=policy_id) + if not policy: + raise exceptions.PolicyUnknown + model_id = policy[policy_id]["model_id"] + model = Managers.ModelManager.get_models(moon_user_id=moon_user_id, model_id=model_id) + try: + meta_rule_list = model[model_id]["meta_rules"] + for meta_rule_id in meta_rule_list: + meta_rule = Managers.ModelManager.get_meta_rules(moon_user_id=moon_user_id, + meta_rule_id=meta_rule_id) + categories["subject"].extend(meta_rule[meta_rule_id]["subject_categories"]) + categories["object"].extend(meta_rule[meta_rule_id]["object_categories"]) + categories["action"].extend(meta_rule[meta_rule_id]["action_categories"]) + finally: + return categories + + def __dependencies_validation(self, moon_user_id, policy_id, meta_rule_id=None): + + policies = self.get_policies(moon_user_id=moon_user_id, policy_id=policy_id) + if not policy_id or (not policies): + raise exceptions.PolicyUnknown + + policy_content = policies[next(iter(policies))] + model_id = policy_content['model_id'] + models = Managers.ModelManager.get_models(moon_user_id=moon_user_id, model_id=model_id) + if not model_id or not models: + raise exceptions.ModelUnknown + + model_content = models[next(iter(models))] + if meta_rule_id: + meta_rule_exists = False + + for model_meta_rule_id in model_content['meta_rules']: + if model_meta_rule_id == meta_rule_id: + meta_rule_exists = True + break + + if not meta_rule_exists: + raise exceptions.MetaRuleNotLinkedWithPolicyModel + + meta_rule = self.ModelManager.get_meta_rules(moon_user_id=moon_user_id, + meta_rule_id=meta_rule_id) + meta_rule_content = meta_rule[next(iter(meta_rule))] + if (not meta_rule_content['subject_categories']) or \ + (not meta_rule_content['object_categories']) or \ + (not meta_rule_content['action_categories']): + raise exceptions.MetaRuleContentError + return model_content + + def __category_dependency_validation(self, moon_user_id, policy_id, category_id, category_key): + model = self.__dependencies_validation(moon_user_id=moon_user_id, policy_id=policy_id) + category_found = False + for model_meta_rule_id in model['meta_rules']: + meta_rule = self.ModelManager.get_meta_rules(moon_user_id=moon_user_id, + meta_rule_id=model_meta_rule_id) + meta_rule_content = meta_rule[next(iter(meta_rule))] + if meta_rule_content[category_key] and category_id in meta_rule_content[category_key]: + category_found = True + break + + if not category_found: + raise exceptions.CategoryNotAssignedMetaRule + + def __check_blank_model(self, model): + if 'meta_rules' not in model or not model['meta_rules']: + raise exceptions.MetaRuleUnknown + for meta_rule_id in model['meta_rules']: + self.__check_blank_meta_rule(meta_rule_id) + + def __check_blank_meta_rule(self, meta_rule_id): + meta_rule = self.driver.get_meta_rules(meta_rule_id=meta_rule_id) + if not meta_rule: + return exceptions.MetaRuleUnknown + meta_rule_content = meta_rule[next(iter(meta_rule))] + if (not meta_rule_content['subject_categories']) or ( + not meta_rule_content['object_categories']) or ( + not meta_rule_content['action_categories']): + raise exceptions.MetaRuleContentError + diff --git a/moon_manager/moon_manager/api/db/slave.py b/moon_manager/moon_manager/api/db/slave.py new file mode 100644 index 00000000..f5ac9189 --- /dev/null +++ b/moon_manager/moon_manager/api/db/slave.py @@ -0,0 +1,55 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +from uuid import uuid4 +import logging +from moon_utilities.security_functions import enforce +from moon_manager.api.db.managers import Managers +from moon_utilities import exceptions + +logger = logging.getLogger("moon.db.api.slave") + + +class SlaveManager(Managers): + + def __init__(self, connector=None): + self.driver = connector.driver + Managers.SlaveManager = self + + @enforce(("read", "write"), "slave") + def update_slave(self, moon_user_id, slave_id, value): + if slave_id not in self.driver.get_slaves(slave_id=slave_id): + raise exceptions.SlaveNameUnknown + + return self.driver.update_slave(slave_id=slave_id, value=value) + + @enforce(("read", "write"), "slave") + def delete_slave(self, moon_user_id, slave_id): + if slave_id not in self.driver.get_slaves(slave_id=slave_id): + raise exceptions.SlaveNameUnknown + return self.driver.delete_slave(slave_id=slave_id) + + @enforce(("read", "write"), "slave") + def add_slave(self, moon_user_id, slave_id=None, value=None): + if not value or 'name' not in value or not value['name'].strip(): + raise exceptions.SlaveNameUnknown + + if slave_id in self.driver.get_slaves(slave_id=slave_id): + raise exceptions.SlaveExisting + if not slave_id: + slave_id = uuid4().hex + + return self.driver.add_slave(slave_id=slave_id, value=value) + + @enforce("read", "slave") + def get_slaves(self, moon_user_id, slave_id=None): + return self.driver.get_slaves(slave_id=slave_id) diff --git a/moon_manager/moon_manager/api/generic.py b/moon_manager/moon_manager/api/generic.py deleted file mode 100644 index 721f6213..00000000 --- a/moon_manager/moon_manager/api/generic.py +++ /dev/null @@ -1,144 +0,0 @@ -# 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 -import logging -import moon_manager.api -from python_moonutilities.security_functions import check_auth - -__version__ = "4.3.2" - -logger = 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: - logger.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/information/__init__.py b/moon_manager/moon_manager/api/information/__init__.py new file mode 100644 index 00000000..582be686 --- /dev/null +++ b/moon_manager/moon_manager/api/information/__init__.py @@ -0,0 +1,11 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + diff --git a/moon_manager/moon_manager/api/information/global_attrs.py b/moon_manager/moon_manager/api/information/global_attrs.py new file mode 100644 index 00000000..21b21445 --- /dev/null +++ b/moon_manager/moon_manager/api/information/global_attrs.py @@ -0,0 +1,145 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + +""" +API to gather information from external component like OpenStack +""" + +from uuid import uuid4 +import logging +from moon_utilities.security_functions import enforce +from moon_manager.api.information.managers import Managers + +LOGGER = logging.getLogger("moon.manager.information.global_attrs") + + +class GlobalAttrsManager(Managers): + """ + Manager use to get information from external components + """ + + def __init__(self, connector=None): + self.driver = connector.driver + Managers.GlobalAttrsManager = self + + def set_auth(self, **kwargs): + """Set authorizations if necessary + + :param kwargs: arguments which are necessary to login to the server + :return: headers to use + """ + return self.driver.set_auth(**kwargs) + + def unset_auth(self, **kwargs): + """Unset the authorization is necessary + + :param kwargs: arguments which are necessary to logout to the server + :return: headers to use + """ + return self.driver.unset_auth(**kwargs) + + @enforce("read", "pip") + def get_users(self, user_id=None, **kwargs): + """List users in the server + + :param user_id: the user name or user ID + :param kwargs: all arguments necessary to list users + :return: a list of users + """ + return self.driver.get_users(user_id=user_id, **kwargs) + + @enforce("write", "pip") + def add_user(self, user_id=None, **kwargs): + """Add a user in the server + + :param user_id: the user name or user ID + :param kwargs: all arguments necessary to add a user + :return: the user added + """ + if not user_id: + user_id = uuid4().hex + return self.driver.add_user(user_id=user_id, **kwargs) + + @enforce(("read", "write"), "pip") + def update_user(self, user_id, **kwargs): + """Update a user in the server + + :param user_id: the user name or user ID + :param kwargs: all arguments necessary to update the user + :return: the user updated + """ + return self.driver.update_user(user_id=user_id, **kwargs) + + @enforce("write", "pip") + def delete_user(self, user_id, **kwargs): + """Delete a user in the server + + :param user_id: the user name or user ID + :param kwargs: all arguments necessary to delete the user + :return: True if the user has been deleted + """ + return self.driver.delete_user(user_id=user_id, **kwargs) + + @enforce("read", "pip") + def get_objects(self, object_id=None, object_type=None, **kwargs): + """List objects in the server + + :param object_id: the object name or user ID + :param object_type: the object type (project, vms, ...) + :param kwargs: all arguments necessary to list the object + :return: a list of objects + """ + return self.driver.get_objects(object_id=object_id, object_type=object_type, **kwargs) + + @enforce("read", "pip") + def get_object(self, object_type, **kwargs): + """List objects in the server + + :param object_type: the object type (project, vms, ...) + :param kwargs: all arguments necessary to list the object + :return: a list of objects + """ + return self.driver.get_object(object_type=object_type, **kwargs) + + @enforce("write", "pip") + def add_object(self, object_id=None, object_type=None, **kwargs): + """Add an object in the server + + :param object_id: the object name or user ID + :param object_type: the object type (project, vms, ...) + :param kwargs: all arguments necessary to add the object + :return: the object added + """ + if not object_id: + object_id = uuid4().hex + return self.driver.add_object(object_id=object_id, object_type=object_type, **kwargs) + + @enforce(("read", "write"), "pip") + def update_object(self, object_id, object_type=None, **kwargs): + """Update an object in the server + + :param object_id: the object name or user ID + :param object_type: the object type (project, vms, ...) + :param kwargs: all arguments necessary to update the object + :return: the object updated + """ + return self.driver.update_object(object_id=object_id, object_type=object_type, **kwargs) + + @enforce("write", "pip") + def delete_object(self, object_id=None, object_type=None, **kwargs): + """Delete an object in the server + + :param object_id: the object name or user ID + :param object_type: the object type (project, vms, ...) + :param kwargs: all arguments necessary to delete the object + :return: True if the object has been deleted + """ + return self.driver.delete_object(object_id=object_id, object_type=object_type, **kwargs) diff --git a/moon_manager/moon_manager/api/information/information.py b/moon_manager/moon_manager/api/information/information.py new file mode 100644 index 00000000..132b8bce --- /dev/null +++ b/moon_manager/moon_manager/api/information/information.py @@ -0,0 +1,106 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + +""" +API to gather information from external component like OpenStack +""" + +from uuid import uuid4 +import logging +from moon_utilities.security_functions import enforce +from moon_manager.api.information.managers import Managers + +LOGGER = logging.getLogger("moon.manager.information.api.information") + + +class InformationManager(Managers): + """ + Manager use to get information from external components + """ + + def __init__(self, connector=None): + self.driver = connector.driver + Managers.InformationManager = self + + def set_auth(self, **kwargs): + """Set authorizations if necessary + + :param kwargs: arguments which are necessary to login to the server + :return: headers to use + """ + return self.driver.set_auth(**kwargs) + + def unset_auth(self, **kwargs): + """Unset the authorization is necessary + + :param kwargs: arguments which are necessary to logout to the server + :return: headers to use + """ + return self.driver.unset_auth(**kwargs) + + @enforce("read", "pip") + def get_items(self, item_id=None, **kwargs): + """List items in the server + + :param item_id: the item name or item ID + :param kwargs: all arguments necessary to list items + :return: a list of items + """ + return self.driver.get_items(item_id=item_id, **kwargs) + + @enforce("write", "pip") + def add_item(self, item_id=None, **kwargs): + """Add a item in the server + + :param item_id: the item name or item ID + :param kwargs: all arguments necessary to add a item + :return: the item added + """ + if not item_id: + item_id = uuid4().hex + return self.driver.add_item(item_id=item_id, **kwargs) + + @enforce(("read", "write"), "pip") + def update_item(self, item_id, **kwargs): + """Update a item in the server + + :param item_id: the item name or item ID + :param kwargs: all arguments necessary to update the item + :return: the item updated + """ + return self.driver.update_item(item_id=item_id, **kwargs) + + @enforce("write", "pip") + def delete_item(self, item_id, **kwargs): + """Delete a item in the server + + :param item_id: the item name or item ID + :param kwargs: all arguments necessary to delete the item + :return: True if the item has been deleted + """ + return self.driver.delete_item(item_id=item_id, **kwargs) + + @enforce("read", "pip") + def get_projects(self): + """List projects in the server + + :return: the list of projects + """ + return self.driver.get_projects() + + @enforce("write", "pip") + def create_project(self, **tenant_dict): + """Create a project in the server + + :param tenant_dict: all arguments necessary to create a project + :return: True if the item has been deleted + """ + return self.driver.create_project(**tenant_dict) diff --git a/moon_manager/moon_manager/api/information/managers.py b/moon_manager/moon_manager/api/information/managers.py new file mode 100644 index 00000000..23aff8f5 --- /dev/null +++ b/moon_manager/moon_manager/api/information/managers.py @@ -0,0 +1,19 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + +""" +Group all managers for this API +""" + + +class Managers(object): + """Object that links managers together""" + InformationManager = None diff --git a/moon_manager/moon_manager/api/json_export.py b/moon_manager/moon_manager/api/json_export.py index 069e5884..06a7ba71 100644 --- a/moon_manager/moon_manager/api/json_export.py +++ b/moon_manager/moon_manager/api/json_export.py @@ -1,279 +1,37 @@ -# Copyright 2018 Open Platform for NFV Project, Inc. and its contributors -# This software is distributed under the terms and conditions of the 'Apache-2.0' -# license which can be found in the file 'LICENSE' in this package distribution -# or at 'http://www.apache.org/licenses/LICENSE-2.0'. +# Software Name: MOON -import logging -from flask_restful import Resource -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 moon_manager.api.json_utils import JsonUtils, BaseException - -__version__ = "4.5.0" - -logger = logging.getLogger("moon.manager.api." + __name__) - - -class JsonExport(Resource): - __urls__ = ( - "/export", - "/export/", - ) - - def _export_rules(self, json_content): - policies = PolicyManager.get_policies(self._user_id) - rules_array = [] - - for policy_key in policies: - rules = PolicyManager.get_rules(self._user_id, policy_key) - rules = rules["rules"] - # logger.info(rules) - for rule in rules: - rule_dict = dict() - JsonUtils.copy_field_if_exists(rule, rule_dict, "instructions", dict) - JsonUtils.copy_field_if_exists(rule, rule_dict, "enabled", True) - JsonUtils.convert_id_to_name(rule["meta_rule_id"], rule_dict, "meta_rule", - "meta_rule", ModelManager, self._user_id) - JsonUtils.convert_id_to_name(policy_key, rule_dict, "policy", "policy", - PolicyManager, self._user_id) - ids = rule["rule"] - rule_description = dict() - meta_rule = ModelManager.get_meta_rules(self._user_id, rule["meta_rule_id"]) - meta_rule = [v for v in meta_rule.values()] - meta_rule = meta_rule[0] - index_subject_data = len(meta_rule["subject_categories"]) - 1 - index_object_data = len(meta_rule["subject_categories"]) + len( - meta_rule["object_categories"]) - 1 - index_action_data = len(meta_rule["subject_categories"]) + len( - meta_rule["object_categories"]) + len(meta_rule["action_categories"]) - 1 - ids_subject_data = [ids[0]] if len(meta_rule["subject_categories"]) == 1 else ids[ - 0:index_subject_data] - ids_object_data = [ids[index_object_data]] if len( - meta_rule["object_categories"]) == 1 else ids[ - index_subject_data + 1:index_object_data] - ids_action_date = [ids[index_action_data]] if len( - meta_rule["action_categories"]) == 1 else ids[ - index_object_data + 1:index_action_data] - JsonUtils.convert_ids_to_names(ids_subject_data, rule_description, "subject_data", - "subject_data", PolicyManager, self._user_id, - policy_key) - JsonUtils.convert_ids_to_names(ids_object_data, rule_description, "object_data", - "object_data", PolicyManager, self._user_id, - policy_key) - JsonUtils.convert_ids_to_names(ids_action_date, rule_description, "action_data", - "action_data", PolicyManager, self._user_id, - policy_key) - rule_dict["rule"] = rule_description - rules_array.append(rule_dict) - - if len(rules_array) > 0: - json_content['rules'] = rules_array - - def _export_meta_rules(self, json_content): - meta_rules = ModelManager.get_meta_rules(self._user_id) - meta_rules_array = [] - # logger.info(meta_rules) - for meta_rule_key in meta_rules: - # logger.info(meta_rules[meta_rule_key]) - meta_rule_dict = dict() - JsonUtils.copy_field_if_exists(meta_rules[meta_rule_key], meta_rule_dict, "name", str) - JsonUtils.copy_field_if_exists(meta_rules[meta_rule_key], meta_rule_dict, "description", - str) - JsonUtils.convert_ids_to_names(meta_rules[meta_rule_key]["subject_categories"], - meta_rule_dict, "subject_categories", "subject_category", - ModelManager, self._user_id) - JsonUtils.convert_ids_to_names(meta_rules[meta_rule_key]["object_categories"], - meta_rule_dict, "object_categories", "object_category", - ModelManager, self._user_id) - JsonUtils.convert_ids_to_names(meta_rules[meta_rule_key]["action_categories"], - meta_rule_dict, "action_categories", "action_category", - ModelManager, self._user_id) - logger.info("Exporting meta rule {}".format(meta_rule_dict)) - meta_rules_array.append(meta_rule_dict) - if len(meta_rules_array) > 0: - json_content['meta_rules'] = meta_rules_array +# Version: 5.4 - def _export_subject_object_action_assignments(self, type_element, json_content): - export_method_data = getattr(PolicyManager, 'get_' + type_element + '_assignments') - policies = PolicyManager.get_policies(self._user_id) - element_assignments_array = [] - for policy_key in policies: - assignments = export_method_data(self._user_id, policy_key) - # logger.info(assignments) - for assignment_key in assignments: - assignment_dict = dict() - JsonUtils.convert_id_to_name(assignments[assignment_key][type_element + "_id"], - assignment_dict, type_element, type_element, - PolicyManager, self._user_id, policy_key) - JsonUtils.convert_id_to_name(assignments[assignment_key]["category_id"], - assignment_dict, "category", - type_element + "_category", ModelManager, - self._user_id, policy_key) - JsonUtils.convert_ids_to_names(assignments[assignment_key]["assignments"], - assignment_dict, "assignments", - type_element + "_data", PolicyManager, self._user_id, - policy_key) - element_assignments_array.append(assignment_dict) - logger.info("Exporting {} assignment {}".format(type_element, assignment_dict)) - if len(element_assignments_array) > 0: - json_content[type_element + '_assignments'] = element_assignments_array +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 - def _export_subject_object_action_datas(self, type_element, json_content): - export_method_data = getattr(PolicyManager, 'get_' + type_element + '_data') - policies = PolicyManager.get_policies(self._user_id) - element_datas_array = [] - for policy_key in policies: - datas = export_method_data(self._user_id, policy_key) - # logger.info("data found : {}".format(datas)) - for data_group in datas: - policy_id = data_group["policy_id"] - category_id = data_group["category_id"] - # logger.info(data_group["data"]) - for data_key in data_group["data"]: - data_dict = dict() - if type_element == 'subject': - JsonUtils.copy_field_if_exists(data_group["data"][data_key], data_dict, - "name", str) - JsonUtils.copy_field_if_exists(data_group["data"][data_key], data_dict, - "description", str) - else: - JsonUtils.copy_field_if_exists(data_group["data"][data_key], data_dict, - "name", str) - JsonUtils.copy_field_if_exists(data_group["data"][data_key], data_dict, - "description", str) +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. - JsonUtils.convert_id_to_name(policy_id, data_dict, "policy", "policy", - PolicyManager, self._user_id) - JsonUtils.convert_id_to_name(category_id, data_dict, "category", - type_element + "_category", ModelManager, - self._user_id, policy_key) - logger.info("Exporting {} data {}".format(type_element, data_dict)) - element_datas_array.append(data_dict) - if len(element_datas_array) > 0: - json_content[type_element + '_data'] = element_datas_array - - def _export_subject_object_action_categories(self, type_element, json_content): - export_method = getattr(ModelManager, 'get_' + type_element + '_categories') - element_categories = export_method(self._user_id) - element_categories_array = [] - for element_category_key in element_categories: - element_category = dict() - JsonUtils.copy_field_if_exists(element_categories[element_category_key], - element_category, "name", str) - JsonUtils.copy_field_if_exists(element_categories[element_category_key], - element_category, "description", str) - element_categories_array.append(element_category) - logger.info("Exporting {} category {}".format(type_element, element_category)) - if len(element_categories_array) > 0: - json_content[type_element + '_categories'] = element_categories_array - - def _export_subject_object_action(self, type_element, json_content): - export_method = getattr(PolicyManager, 'get_' + type_element + 's') - policies = PolicyManager.get_policies(self._user_id) - element_dict = dict() - elements_array = [] - for policy_key in policies: - elements = export_method(self._user_id, policy_key) - for element_key in elements: - # logger.info("Exporting {}".format(elements[element_key])) - element = dict() - JsonUtils.copy_field_if_exists(elements[element_key], element, "name", str) - JsonUtils.copy_field_if_exists(elements[element_key], element, "description", str) - JsonUtils.copy_field_if_exists(elements[element_key], element, "extra", dict) - if element["name"] not in element_dict: - element["policies"] = [] - element_dict[element["name"]] = element - current_element = element_dict[element["name"]] - current_element["policies"].append({"name": JsonUtils.convert_id_to_name_string( - policy_key, "policy", PolicyManager, self._user_id)}) - - for key in element_dict: - logger.info("Exporting {} {}".format(type_element, element_dict[key])) - elements_array.append(element_dict[key]) - - if len(elements_array) > 0: - json_content[type_element + 's'] = elements_array - - def _export_policies(self, json_content): - policies = PolicyManager.get_policies(self._user_id) - policies_array = [] - for policy_key in policies: - policy = dict() - JsonUtils.copy_field_if_exists(policies[policy_key], policy, "name", str) - JsonUtils.copy_field_if_exists(policies[policy_key], policy, "genre", str) - JsonUtils.copy_field_if_exists(policies[policy_key], policy, "description", str) - JsonUtils.convert_id_to_name(policies[policy_key]["model_id"], policy, "model", "model", - ModelManager, self._user_id) - logger.info("Exporting policy {}".format(policy)) - policies_array.append(policy) - if len(policies_array) > 0: - json_content["policies"] = policies_array - - def _export_models(self, json_content): - models = ModelManager.get_models(self._user_id) - models_array = [] - for model_key in models: - model = dict() - JsonUtils.copy_field_if_exists(models[model_key], model, "name", str) - JsonUtils.copy_field_if_exists(models[model_key], model, "description", str) - # logger.info(models[model_key]["meta_rules"]) - JsonUtils.convert_ids_to_names(models[model_key]["meta_rules"], model, "meta_rules", - "meta_rule", ModelManager, self._user_id) - logger.info("Exporting model {}".format(model)) - models_array.append(model) - if len(models_array) > 0: - json_content["models"] = models_array - - def _export_pdps(self, json_content): - pdps = PDPManager.get_pdp(self._user_id) - pdps_array = [] - for pdp_key in pdps: - logger.info("Exporting pdp {}".format(pdps[pdp_key])) - pdps_array.append(pdps[pdp_key]) - if len(pdps_array) > 0: - json_content["pdps"] = pdps_array +import hug +import logging +from moon_manager import db_driver as driver +from moon_utilities.auth_functions import api_key_authentication +from moon_utilities.json_utils import JsonExport - def _export_json(self, user_id): - self._user_id = user_id - json_content = dict() +logger = logging.getLogger("moon.manager.api." + __name__) - logger.info("Exporting pdps...") - self._export_pdps(json_content) - logger.info("Exporting policies...") - self._export_policies(json_content) - logger.info("Exporting models...") - self._export_models(json_content) - # export subjects, subject_data, subject_categories, subject_assignements idem for object and action - list_element = [{"key": "subject"}, {"key": "object"}, {"key": "action"}] - for elt in list_element: - logger.info("Exporting {}s...".format(elt["key"])) - self._export_subject_object_action(elt["key"], json_content) - logger.info("Exporting {} categories...".format(elt["key"])) - self._export_subject_object_action_categories(elt["key"], json_content) - logger.info("Exporting {} data...".format(elt["key"])) - self._export_subject_object_action_datas(elt["key"], json_content) - logger.info("Exporting {} assignments...".format(elt["key"])) - self._export_subject_object_action_assignments(elt["key"], json_content) - logger.info("Exporting meta rules...") - self._export_meta_rules(json_content) - logger.info("Exporting rules...") - self._export_rules(json_content) - return json_content +class Export(object): - @check_auth - def get(self, user_id=None): + @staticmethod + @hug.get("/export", requires=api_key_authentication) + def get(authed_user: hug.directives.user = None): """Import file. - :param user_id: user ID who do the request + :param authed_user: user ID who do the request :return: { } :internal_api: """ - json_file = self._export_json(user_id) - logger.info(json_file) + json_file = JsonExport(driver_name="db", driver=driver).export_json( + moon_user_id=authed_user) return {"content": json_file} diff --git a/moon_manager/moon_manager/api/json_import.py b/moon_manager/moon_manager/api/json_import.py index 05f4a0c0..922c5c2c 100644 --- a/moon_manager/moon_manager/api/json_import.py +++ b/moon_manager/moon_manager/api/json_import.py @@ -1,27 +1,23 @@ -# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors -# This software is distributed under the terms and conditions of the 'Apache-2.0' -# license which can be found in the file 'LICENSE' in this package distribution -# or at 'http://www.apache.org/licenses/LICENSE-2.0'. +# Software Name: MOON -from flask import request -from flask_restful import Resource -import flask_restful -from flask import abort +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. -from python_moonutilities.security_functions import check_auth -from python_moonutilities import exceptions -import logging -import json -from moon_manager.api.base_exception import BaseException -from moon_manager.api.json_utils import JsonUtils, UnknownName -from python_moondb.core import PDPManager -from python_moondb.core import PolicyManager -from python_moondb.core import ModelManager +import hug +import logging +from moon_manager import db_driver as driver +from moon_utilities.json_utils import JsonImport +from moon_utilities.auth_functions import api_key_authentication -__version__ = "4.5.0" -logger = logging.getLogger("moon.manager.api." + __name__) +LOGGER = logging.getLogger("moon.manager.api." + __name__) INST_CALLBACK = 0 DATA_CALLBACK = 1 @@ -29,556 +25,20 @@ ASSIGNMENT_CALLBACK = 2 CATEGORIES_CALLBACK = 3 -class ForbiddenOverride(BaseException): - def __init__(self, message): - # Call the base class constructor with the parameters it needs - super(ForbiddenOverride, self).__init__(message) - - -class UnknownPolicy(BaseException): - def __init__(self, message): - # Call the base class constructor with the parameters it needs - super(UnknownPolicy, self).__init__(message) - - -class UnknownModel(BaseException): - def __init__(self, message): - # Call the base class constructor with the parameters it needs - super(UnknownModel, self).__init__(message) - - -class UnknownData(BaseException): - def __init__(self, message): - # Call the base class constructor with the parameters it needs - super(UnknownData, self).__init__(message) - - -class MissingPolicy(BaseException): - def __init__(self, message): - # Call the base class constructor with the parameters it needs - super(MissingPolicy, self).__init__(message) - - -class InvalidJson(BaseException): - def __init__(self, message): - # Call the base class constructor with the parameters it needs - super(InvalidJson, self).__init__(message) - - -class JsonImport(Resource): - __urls__ = ( - "/import", - "/import/", - ) - - def _reorder_rules_ids(self, rule, ordered_perimeter_categories_ids, json_data_ids, policy_id, - get_function): - ordered_json_ids = [None] * len(ordered_perimeter_categories_ids) - for json_id in json_data_ids: - data = get_function(self._user_id, policy_id, data_id=json_id) - data = data[0] - if data["category_id"] not in ordered_perimeter_categories_ids: - raise InvalidJson( - "The category id {} of the rule {} does not match the meta rule".format( - data["category_id"], rule)) - if ordered_json_ids[ - ordered_perimeter_categories_ids.index(data["category_id"])] is not None: - raise InvalidJson( - "The category id {} of the rule {} shall not be used twice in the same rule".format( - data["category_id"], rule)) - ordered_json_ids[ordered_perimeter_categories_ids.index(data["category_id"])] = json_id - logger.info(ordered_json_ids) - return ordered_json_ids - - def _import_rules(self, json_rules): - if not isinstance(json_rules, list): - raise InvalidJson("rules shall be a list!") - - for json_rule in json_rules: - json_to_use = dict() - JsonUtils.copy_field_if_exists(json_rule, json_to_use, "instructions", str) - JsonUtils.copy_field_if_exists(json_rule, json_to_use, "enabled", bool, - default_value=True) - - json_ids = dict() - JsonUtils.convert_name_to_id(json_rule, json_ids, "policy", "policy_id", "policy", - PolicyManager, self._user_id) - JsonUtils.convert_name_to_id(json_rule, json_to_use, "meta_rule", "meta_rule_id", - "meta_rule", ModelManager, self._user_id) - json_subject_ids = dict() - json_object_ids = dict() - json_action_ids = dict() - JsonUtils.convert_names_to_ids(json_rule["rule"], json_subject_ids, "subject_data", - "subject", "subject_data", PolicyManager, self._user_id, - json_ids["policy_id"]) - JsonUtils.convert_names_to_ids(json_rule["rule"], json_object_ids, "object_data", - "object", "object_data", PolicyManager, self._user_id, - json_ids["policy_id"]) - JsonUtils.convert_names_to_ids(json_rule["rule"], json_action_ids, "action_data", - "action", "action_data", PolicyManager, self._user_id, - json_ids["policy_id"]) - - meta_rule = ModelManager.get_meta_rules(self._user_id, json_to_use["meta_rule_id"]) - meta_rule = [v for v in meta_rule.values()] - meta_rule = meta_rule[0] - - json_to_use_rule = self._reorder_rules_ids(json_rule, meta_rule["subject_categories"], - json_subject_ids["subject"], - json_ids["policy_id"], - PolicyManager.get_subject_data) - json_to_use_rule = json_to_use_rule + self._reorder_rules_ids(json_rule, meta_rule[ - "object_categories"], json_object_ids["object"], json_ids["policy_id"], - PolicyManager.get_object_data) - json_to_use_rule = json_to_use_rule + self._reorder_rules_ids(json_rule, meta_rule[ - "action_categories"], json_action_ids["action"], json_ids["policy_id"], - PolicyManager.get_action_data) - json_to_use["rule"] = json_to_use_rule - try: - logger.debug("Adding / updating a rule from json {}".format(json_to_use)) - PolicyManager.add_rule(self._user_id, json_ids["policy_id"], - json_to_use["meta_rule_id"], json_to_use) - except exceptions.RuleExisting: - pass - except exceptions.PolicyUnknown: - raise UnknownPolicy("Unknown policy with id {}".format(json_ids["policy_id"])) - - def _import_meta_rules(self, json_meta_rules): - logger.info("Input meta rules : {}".format(json_meta_rules)) - for json_meta_rule in json_meta_rules: - json_to_use = dict() - JsonUtils.copy_field_if_exists(json_meta_rule, json_to_use, "name", str) - JsonUtils.copy_field_if_exists(json_meta_rule, json_to_use, "description", str) - JsonUtils.convert_names_to_ids(json_meta_rule, json_to_use, "subject_categories", - "subject_categories", "subject_category", ModelManager, - self._user_id) - JsonUtils.convert_names_to_ids(json_meta_rule, json_to_use, "object_categories", - "object_categories", "object_category", ModelManager, - self._user_id) - JsonUtils.convert_names_to_ids(json_meta_rule, json_to_use, "action_categories", - "action_categories", "action_category", ModelManager, - self._user_id) - logger.debug("Adding / updating a metarule from json {}".format(json_meta_rule)) - meta_rule = ModelManager.add_meta_rule(self._user_id, meta_rule_id=None, - value=json_to_use) - logger.debug("Added / updated meta rule : {}".format(meta_rule)) - - def _import_subject_object_action_assignments(self, json_item_assignments, type_element): - import_method = getattr(PolicyManager, 'add_' + type_element + '_assignment') - get_method = getattr(PolicyManager, 'get_' + type_element + '_data') - - if not isinstance(json_item_assignments, list): - raise InvalidJson(type_element + " assignments shall be a list!") - - # get the policy id related to the user - policies = PolicyManager.get_policies(self._user_id) - - for json_item_assignment in json_item_assignments: - item_override = JsonUtils.get_override(json_item_assignment) - if item_override is True: - raise ForbiddenOverride( - "{} assignments do not support override flag !".format(type_element)) - - json_assignment = dict() - JsonUtils.convert_name_to_id(json_item_assignment, json_assignment, "category", - "category_id", type_element + "_category", ModelManager, - self._user_id) - - has_found_data = False - # loop over policies - for policy_id in policies: - json_data = dict() - try: - JsonUtils.convert_name_to_id(json_item_assignment, json_assignment, - type_element, "id", type_element, PolicyManager, - self._user_id, policy_id) - JsonUtils.convert_names_to_ids(json_item_assignment, json_data, "assignments", - "data_id", type_element + "_data", PolicyManager, - self._user_id, policy_id, - json_assignment["category_id"]) - has_found_data = True - except UnknownName: - # the category or data has not been found in this policy : we look into the next one - continue - for data_id in json_data["data_id"]: - # find the policy related to the current data - data = get_method(self._user_id, policy_id, data_id, - json_assignment["category_id"]) - if data is not None and len(data) == 1: - logger.debug( - "Adding / updating a {} assignment from json {}".format(type_element, - json_assignment)) - import_method(self._user_id, policy_id, json_assignment["id"], - json_assignment["category_id"], - data_id) - else: - raise UnknownData("Unknown data with id {}".format(data_id)) - - # case the data has not been found in any policies - if has_found_data is False: - raise InvalidJson("The json contains unknown {} data or category : {}".format( - type_element, - json_item_assignment)) - - def _import_subject_object_action_datas(self, json_items_data, mandatory_policy_ids, - type_element): - if type_element == "subject": - import_method = getattr(PolicyManager, 'set_' + type_element + '_data') - else: - import_method = getattr(PolicyManager, 'add_' + type_element + '_data') - # get_method = getattr(PolicyManager, 'get_' + type_element + '_data') - - if not isinstance(json_items_data, list): - raise InvalidJson(type_element + " data shall be a list!") - - for json_item_data in json_items_data: - item_override = JsonUtils.get_override(json_items_data) - if item_override is True: - raise ForbiddenOverride( - "{} datas do not support override flag !".format(type_element)) - json_to_use = dict() - JsonUtils.copy_field_if_exists(json_item_data, json_to_use, "name", str) - JsonUtils.copy_field_if_exists(json_item_data, json_to_use, "description", str) - json_policy = dict() - # field_mandatory : not mandatory if there is some mandatory policies - JsonUtils.convert_names_to_ids(json_item_data, json_policy, "policies", "policy_id", - "policy", - PolicyManager, self._user_id, - field_mandatory=len(mandatory_policy_ids) == 0) - json_category = dict() - JsonUtils.convert_name_to_id(json_item_data, json_category, "category", "category_id", - type_element + "_category", - ModelManager, self._user_id) - policy_ids = [] - if "policy_id" in json_policy: - policy_ids = json_policy["policy_id"] - - for policy_id in policy_ids: - if policy_id is not None and policy_id not in mandatory_policy_ids: - mandatory_policy_ids.append(policy_id) - - if len(mandatory_policy_ids) == 0: - raise InvalidJson("Invalid data, the policy shall be set when importing {}".format( - json_item_data)) - category_id = None - if "category_id" in json_category: - category_id = json_category["category_id"] - if category_id is None: - raise InvalidJson( - "Invalid data, the category shall be set when importing {}".format( - json_item_data)) - - for policy_id in mandatory_policy_ids: - try: - data = import_method(self._user_id, policy_id, category_id=category_id, - value=json_to_use) - except exceptions.PolicyUnknown: - raise UnknownPolicy("Unknown policy with id {}".format(policy_id)) - except Exception as e: - logger.exception(str(e)) - raise e - - def _import_subject_object_action_categories(self, json_item_categories, type_element): - import_method = getattr(ModelManager, 'add_' + type_element + '_category') - get_method = getattr(ModelManager, 'get_' + type_element + '_categories') - - categories = get_method(self._user_id) - - if not isinstance(json_item_categories, list): - raise InvalidJson(type_element + " categories shall be a list!") - - for json_item_category in json_item_categories: - json_to_use = dict() - JsonUtils.copy_field_if_exists(json_item_category, json_to_use, "name", str) - - # check if category with the same name exists : do this in moondb ? - existing_id = None - for category_key in categories: - if categories[category_key]["name"] == json_to_use["name"]: - existing_id = category_key +class JsonImportAPI(object): - JsonUtils.copy_field_if_exists(json_item_category, json_to_use, "description", str) - item_override = JsonUtils.get_override(json_item_category) - if item_override is True: - raise ForbiddenOverride( - "{} categories do not support override flag !".format(type_element)) - - try: - category = import_method(self._user_id, existing_id, json_to_use) - except (exceptions.SubjectCategoryExisting, exceptions.ObjectCategoryExisting, - exceptions.ActionCategoryExisting): - # it already exists: do nothing - logger.warning("Ignored {} category with name {} is already in the database".format( - type_element, json_to_use["name"])) - except Exception as e: - logger.warning("Error while importing the category : {}".format(str(e))) - logger.exception(str(e)) - raise e - - def _import_subject_object_action(self, json_items, mandatory_policy_ids, type_element): - import_method = getattr(PolicyManager, 'add_' + type_element) - get_method = getattr(PolicyManager, 'get_' + type_element + 's') - - if not isinstance(json_items, list): - raise InvalidJson(type_element + " items shall be a list!") - - for json_item in json_items: - json_without_policy_name = dict() - JsonUtils.copy_field_if_exists(json_item, json_without_policy_name, "name", str) - JsonUtils.copy_field_if_exists(json_item, json_without_policy_name, "description", str) - JsonUtils.copy_field_if_exists(json_item, json_without_policy_name, "extra", dict) - JsonUtils.convert_names_to_ids(json_item, json_without_policy_name, "policies", - "policy_list", "policy", PolicyManager, self._user_id, - field_mandatory=False) - policy_ids = json_without_policy_name["policy_list"] - for mandatory_policy_id in mandatory_policy_ids: - if mandatory_policy_id not in policy_ids: - policy_ids.append(mandatory_policy_id) - # policy_ids and json_without_policy_name are references to the same array... - # json_without_policy_name["policy_list"].append(mandatory_policy_id) - - item_override = JsonUtils.get_override(json_item) - if item_override is True: - raise ForbiddenOverride("{} does not support override flag !".format(type_element)) - - if len(policy_ids) == 0: - raise MissingPolicy( - "a {} needs at least one policy to be created or updated : {}".format( - type_element, json.dumps(json_item))) - - for policy_id in policy_ids: - try: - items_in_db = get_method(self._user_id, policy_id) - key = None - for key_in_db in items_in_db: - if items_in_db[key_in_db]["name"] == json_without_policy_name["name"]: - key = key_in_db - break - element = import_method(self._user_id, policy_id, perimeter_id=key, - value=json_without_policy_name) - logger.debug("Added / updated {} : {}".format(type_element, element)) - - except exceptions.PolicyUnknown: - raise UnknownPolicy("Unknown policy when adding a {}!".format(type_element)) - except Exception as e: - logger.exception(str(e)) - raise BaseException(str(e)) - - def _import_policies(self, json_policies): - policy_mandatory_ids = [] - - if not isinstance(json_policies, list): - raise InvalidJson("policies shall be a list!") - - for json_policy in json_policies: - # TODO put this in moondb - # policy_in_db = PolicyManager.get_policies_by_name(json_without_model_name["name"]) - policies = PolicyManager.get_policies(self._user_id) - policy_in_db = None - policy_id = None - for policy_key in policies: - if policies[policy_key]["name"] == json_policy["name"]: - policy_in_db = policies[policy_key] - policy_id = policy_key - # end TODO - if policy_in_db is None: - policy_does_exist = False - else: - policy_does_exist = True - - policy_override = JsonUtils.get_override(json_policy) - policy_mandatory = JsonUtils.get_mandatory(json_policy) - - if policy_override is False and policy_does_exist: - if policy_id: - policy_mandatory_ids.append(policy_id) - logger.warning( - "Existing policy not updated because of the override option is not set !") - continue - - json_without_model_name = dict() - JsonUtils.copy_field_if_exists(json_policy, json_without_model_name, "name", str) - JsonUtils.copy_field_if_exists(json_policy, json_without_model_name, "description", str) - JsonUtils.copy_field_if_exists(json_policy, json_without_model_name, "genre", str) - JsonUtils.convert_name_to_id(json_policy, json_without_model_name, "model", "model_id", - "model", ModelManager, self._user_id, - field_mandatory=False) - - if not policy_does_exist: - logger.debug("Creating policy {} ".format(json_without_model_name)) - added_policy = PolicyManager.add_policy(self._user_id, None, - json_without_model_name) - if policy_mandatory is True: - keys = list(added_policy.keys()) - policy_mandatory_ids.append(keys[0]) - elif policy_override is True: - logger.debug("Updating policy {} ".format(json_without_model_name)) - updated_policy = PolicyManager.update_policy(self._user_id, policy_id, - json_without_model_name) - if policy_mandatory is True: - policy_mandatory_ids.append(policy_id) - return policy_mandatory_ids - - def _import_models_with_new_meta_rules(self, json_models): - if not isinstance(json_models, list): - raise InvalidJson("models shall be a list!") - - for json_model in json_models: - logger.debug("json_model {}".format(json_model)) - models = ModelManager.get_models(self._user_id) - model_in_db = None - model_id = None - for model_key in models: - if ("id" in json_model and model_key == json_model["id"]) or ( - "name" in json_model and models[model_key]["name"] == json_model["name"]): - model_in_db = models[model_key] - model_id = model_key - - # this should not occur as the model has been put in db previously in _import_models_without_new_meta_rules - if model_in_db is None: - raise UnknownModel("Unknown model ") - - json_key = dict() - JsonUtils.convert_names_to_ids(json_model, json_key, "meta_rules", "meta_rule_id", - "meta_rule", ModelManager, self._user_id) - for meta_rule_id in json_key["meta_rule_id"]: - if meta_rule_id not in model_in_db["meta_rules"]: - model_in_db["meta_rules"].append(meta_rule_id) - - ModelManager.update_model(self._user_id, model_id, model_in_db) - - def _import_models_without_new_meta_rules(self, json_models): - if not isinstance(json_models, list): - raise InvalidJson("models shall be a list!") - - for json_model in json_models: - json_without_new_metarules = dict() - JsonUtils.copy_field_if_exists(json_model, json_without_new_metarules, "name", str) - - # TODO put this in moondb - # model_in_db = ModelManager.get_models_by_name(json_without_new_metarules["name"]) - models = ModelManager.get_models(self._user_id) - model_in_db = None - for model_key in models: - if models[model_key]["name"] == json_without_new_metarules["name"]: - model_in_db = models[model_key] - model_id = model_key - # end TODO - - JsonUtils.copy_field_if_exists(json_model, json_without_new_metarules, "description", - str) - if model_in_db is None: - model_does_exist = False - else: - json_without_new_metarules["meta_rules"] = model_in_db["meta_rules"] - model_does_exist = True - model_override = JsonUtils.get_override(json_model) - if not model_does_exist: - logger.debug("Creating model {} ".format(json_without_new_metarules)) - ModelManager.add_model(self._user_id, None, json_without_new_metarules) - elif model_override is True: - logger.debug( - "Updating model with id {} : {} ".format(model_id, json_without_new_metarules)) - ModelManager.update_model(self._user_id, model_id, json_without_new_metarules) - - def _import_pdps(self, json_pdps): - if not isinstance(json_pdps, list): - raise InvalidJson("pdps shall be a list!") - - for json_pdp in json_pdps: - json_to_use = dict() - JsonUtils.copy_field_if_exists(json_pdp, json_to_use, "name", str) - JsonUtils.copy_field_if_exists(json_pdp, json_to_use, "keystone_project_id", str) - JsonUtils.copy_field_if_exists(json_pdp, json_to_use, "security_pipeline", list) - JsonUtils.copy_field_if_exists(json_pdp, json_to_use, "description", str) - - pdps = PDPManager.get_pdp(self._user_id) - exists = False - for pdp_key in pdps: - if pdps[pdp_key]["name"] == json_to_use["name"]: - PDPManager.update_pdp(self._user_id, pdp_id=pdp_key, value=json_to_use) - exists = True - if exists is False: - PDPManager.add_pdp(self._user_id, value=json_to_use) - - def _import_json(self, user_id): - self._user_id = user_id - if 'file' in request.files: - file = request.files['file'] - logger.debug("Importing {} file...".format(file)) - json_content = json.load(file) - else: - json_content = request.json - logger.debug("Importing content: {} ...".format(json_content)) - - # first import the models without the meta rules as they are not yet defined - if "models" in json_content: - logger.info("Importing models...") - self._import_models_without_new_meta_rules(json_content["models"]) - - # import the policies that depends on the models - mandatory_policy_ids = [] - if "policies" in json_content: - logger.info("Importing policies...") - mandatory_policy_ids = self._import_policies(json_content["policies"]) - - # import subjects, subject_data, subject_categories, idem for object and action - list_element = [{"key": "subject"}, {"key": "object"}, {"key": "action"}] - for elt in list_element: - in_key = elt["key"] - key = in_key + "s" - if key in json_content: - logger.info("Importing {}...".format(key)) - self._import_subject_object_action(json_content[key], mandatory_policy_ids, in_key) - key = in_key + "_categories" - if key in json_content: - logger.info("Importing {}...".format(key)) - self._import_subject_object_action_categories(json_content[key], in_key) - - # import meta rules - if "meta_rules" in json_content: - logger.info("Importing meta rules...") - self._import_meta_rules(json_content["meta_rules"]) - - # add the metarule to model - if "models" in json_content: - logger.info("Updating models with meta rules...") - self._import_models_with_new_meta_rules(json_content["models"]) - - for elt in list_element: - in_key = elt["key"] - key = in_key + "_data" - if key in json_content: - logger.info("Importing {}...".format(key)) - self._import_subject_object_action_datas(json_content[key], mandatory_policy_ids, - in_key) - - # import subjects assignments, idem for object and action - for elt in list_element: - in_key = elt["key"] - key = in_key + "_assignments" - if key in json_content: - logger.info("Importing {}...".format(key)) - self._import_subject_object_action_assignments(json_content[key], in_key) - - # import rules - if "rules" in json_content: - logger.info("Importing rules...") - self._import_rules(json_content["rules"]) - - # import pdps - if "pdps" in json_content: - logger.info("Importing pdps...") - self._import_pdps(json_content["pdps"]) - - @check_auth - def post(self, user_id=None): - """Import file. - - :param user_id: user ID who do the request - :return: { - - } - :internal_api: + @staticmethod + @hug.post("/import", requires=api_key_authentication) + def post(request, body, authed_user: hug.directives.user = None): + """ + Import data inside the database + :param request: the request send by the user + :param body: the content of the request + :param authed_user: the name of the authenticated user + :return: "Import ok !" (if import is OK) + :raises multiple exceptions depending on the context """ - self._import_json(user_id) - return "Import ok !" + json_import_ob = JsonImport(driver_name="db", driver=driver) + imported_data = json_import_ob.import_json(moon_user_id=authed_user, request=request, body=body) + LOGGER.info('Imported data: {}'.format(imported_data)) + return imported_data diff --git a/moon_manager/moon_manager/api/json_utils.py b/moon_manager/moon_manager/api/json_utils.py deleted file mode 100644 index 6a5830f1..00000000 --- a/moon_manager/moon_manager/api/json_utils.py +++ /dev/null @@ -1,282 +0,0 @@ -import logging -from moon_manager.api.base_exception import BaseException - -logger = logging.getLogger("moon.manager.api." + __name__) - - -class UnknownName(BaseException): - def __init__(self, message): - # Call the base class constructor with the parameters it needs - super(UnknownName, self).__init__(message) - - -class UnknownId(BaseException): - def __init__(self, message): - # Call the base class constructor with the parameters it needs - super(UnknownId, self).__init__(message) - - -class MissingIdOrName(BaseException): - def __init__(self, message): - # Call the base class constructor with the parameters it needs - super(MissingIdOrName, self).__init__(message) - - -class UnknownField(BaseException): - def __init__(self, message): - # Call the base class constructor with the parameters it needs - super(UnknownField, self).__init__(message) - - -class JsonUtils: - @staticmethod - def get_override(json_content): - if "override" in json_content: - return json_content["override"] - return False - - @staticmethod - def get_mandatory(json_content): - if "mandatory" in json_content: - return json_content["mandatory"] - return False - - @staticmethod - def copy_field_if_exists(json_in, json_out, field_name, type_field, default_value=None): - if field_name in json_in: - json_out[field_name] = json_in[field_name] - else: - if type_field is bool: - if default_value is None: - default_value = False - json_out[field_name] = default_value - if type_field is str: - if default_value is None: - default_value = "" - json_out[field_name] = default_value - if type_field is dict: - json_out[field_name] = dict() - if type_field is list: - json_out[field_name] = [] - - @staticmethod - def _get_element_in_db_from_id(element_type, element_id, user_id, policy_id, category_id, - meta_rule_id, manager): - # the item is supposed to be in the db, we check it exists! - if element_type == "model": - data_db = manager.get_models(user_id, model_id=element_id) - elif element_type == "policy": - data_db = manager.get_policies(user_id, policy_id=element_id) - elif element_type == "subject": - data_db = manager.get_subjects(user_id, policy_id, perimeter_id=element_id) - elif element_type == "object": - data_db = manager.get_objects(user_id, policy_id, perimeter_id=element_id) - elif element_type == "action": - data_db = manager.get_actions(user_id, policy_id, perimeter_id=element_id) - elif element_type == "subject_category": - data_db = manager.get_subject_categories(user_id, category_id=element_id) - elif element_type == "object_category": - data_db = manager.get_object_categories(user_id, category_id=element_id) - elif element_type == "action_category": - data_db = manager.get_action_categories(user_id, category_id=element_id) - elif element_type == "meta_rule": - data_db = manager.get_meta_rules(user_id, meta_rule_id=element_id) - elif element_type == "subject_data": - data_db = manager.get_subject_data(user_id, policy_id, data_id=element_id, - category_id=category_id) - elif element_type == "object_data": - data_db = manager.get_object_data(user_id, policy_id, data_id=element_id, - category_id=category_id) - elif element_type == "action_data": - data_db = manager.get_action_data(user_id, policy_id, data_id=element_id, - category_id=category_id) - elif element_type == "meta_rule": - data_db = manager.get_meta_rules(user_id, meta_rule_id=meta_rule_id) - else: - raise Exception("Conversion of {} not implemented yet!".format(element_type)) - - # logger.info(data_db) - - # do some post processing ... the result should be {key : { .... .... } } - if element_type == "subject_data" or element_type == "object_data" or element_type == "action_data": - if data_db is not None and isinstance(data_db, list): - # TODO remove comments after fixing the bug on moondb when adding metarule : we can have several identical entries ! - # if len(data_db) > 1: - # raise Exception("Several {} with the same id : {}".format(element_type, data_db)) - data_db = data_db[0] - - if data_db is not None and data_db["data"] is not None and isinstance(data_db["data"], - dict): - # TODO remove comments after fixing the bug on moondb when adding metarule : we can have several identical entries ! - # if len(data_db["data"].values()) != 1: - # raise Exception("Several {} with the same id : {}".format(element_type, data_db)) - # data_db = data_db["data"] - # TODO remove these two lines after fixing the bug on moondb when adding metarule : we can have several identical entries ! - list_values = list(data_db["data"].values()) - data_db = list_values[0] - # logger.info("subject data after postprocessing {}".format(data_db)) - return data_db - - @staticmethod - def _get_element_id_in_db_from_name(element_type, element_name, user_id, policy_id, category_id, - meta_rule_id, manager): - if element_type == "model": - data_db = manager.get_models(user_id) - elif element_type == "policy": - data_db = manager.get_policies(user_id) - elif element_type == "subject": - data_db = manager.get_subjects(user_id, policy_id) - elif element_type == "object": - data_db = manager.get_objects(user_id, policy_id) - elif element_type == "action": - data_db = manager.get_actions(user_id, policy_id) - elif element_type == "subject_category": - data_db = manager.get_subject_categories(user_id) - elif element_type == "object_category": - data_db = manager.get_object_categories(user_id) - elif element_type == "action_category": - data_db = manager.get_action_categories(user_id) - elif element_type == "meta_rule": - data_db = manager.get_meta_rules(user_id) - elif element_type == "subject_data": - data_db = manager.get_subject_data(user_id, policy_id, category_id=category_id) - elif element_type == "object_data": - data_db = manager.get_object_data(user_id, policy_id, category_id=category_id) - elif element_type == "action_data": - data_db = manager.get_action_data(user_id, policy_id, category_id=category_id) - elif element_type == "meta_rule": - data_db = manager.get_meta_rules(user_id) - elif element_type == "rule": - data_db = manager.get_rules(user_id, policy_id) - else: - raise BaseException("Conversion of {} not implemented yet!".format(element_type)) - - if isinstance(data_db, dict): - for key_id in data_db: - if isinstance(data_db[key_id], dict) and "name" in data_db[key_id]: - if data_db[key_id]["name"] == element_name: - return key_id - else: - for elt in data_db: - if isinstance(elt, - dict) and "data" in elt: # we handle here subject_data, object_data and action_data... - for data_key in elt["data"]: - # logger.info("data from the db {} ".format(elt["data"][data_key])) - data = elt["data"][data_key] - if "name" in data and data["name"] == element_name: - return data_key - if "value" in data and data["value"]["name"] == element_name: - return data_key - return None - - @staticmethod - def convert_name_to_id(json_in, json_out, field_name_in, field_name_out, element_type, manager, - user_id, policy_id=None, category_id=None, meta_rule_id=None, - field_mandatory=True): - if field_name_in not in json_in: - raise UnknownField("The field {} is not in the input json".format(field_name_in)) - - if "id" in json_in[field_name_in]: - data_db = JsonUtils._get_element_in_db_from_id(element_type, - json_in[field_name_in]["id"], user_id, - policy_id, category_id, meta_rule_id, - manager) - if data_db is None: - raise UnknownId("No {} with id {} found in database".format(element_type, - json_in[field_name_in]["id"])) - json_out[field_name_out] = json_in[field_name_in]["id"] - - elif "name" in json_in[field_name_in]: - id_in_db = JsonUtils._get_element_id_in_db_from_name(element_type, - json_in[field_name_in]["name"], - user_id, policy_id, category_id, - meta_rule_id, manager) - if id_in_db is None: - raise UnknownName( - "No {} with name {} found in database".format(element_type, - json_in[field_name_in]["name"])) - json_out[field_name_out] = id_in_db - elif field_mandatory is True: - raise MissingIdOrName("No id or name found in the input json {}".format(json_in)) - - @staticmethod - def convert_id_to_name(id_, json_out, field_name_out, element_type, manager, user_id, - policy_id=None, category_id=None, meta_rule_id=None): - json_out[field_name_out] = { - "name": JsonUtils.convert_id_to_name_string(id_, element_type, manager, user_id, - policy_id, category_id, meta_rule_id)} - - @staticmethod - def __convert_results_to_element(element): - if isinstance(element, dict) and "name" not in element and "value" not in element: - list_values = [v for v in element.values()] - elif isinstance(element, list): - list_values = element - else: - list_values = [] - list_values.append(element) - return list_values[0] - - @staticmethod - def convert_id_to_name_string(id_, element_type, manager, user_id, - policy_id=None, category_id=None, meta_rule_id=None): - - element = JsonUtils._get_element_in_db_from_id(element_type, id_, user_id, policy_id, - category_id, meta_rule_id, manager) - # logger.info(element) - if element is None: - raise UnknownId("No {} with id {} found in database".format(element_type, id_)) - res = JsonUtils.__convert_results_to_element(element) - # logger.info(res) - if "name" in res: - return res["name"] - if "value" in res and "name" in res["value"]: - return res["value"]["name"] - return None - - @staticmethod - def convert_names_to_ids(json_in, json_out, field_name_in, field_name_out, element_type, - manager, user_id, policy_id=None, category_id=None, meta_rule_id=None, - field_mandatory=True): - ids = [] - if field_name_in not in json_in: - raise UnknownField("The field {} is not in the input json".format(field_name_in)) - - for elt in json_in[field_name_in]: - if "id" in elt: - data_db = JsonUtils._get_element_in_db_from_id(element_type, elt["id"], user_id, - policy_id, category_id, - meta_rule_id, manager) - if data_db is None: - raise UnknownId( - "No {} with id {} found in database".format(element_type, elt["id"])) - ids.append(elt["id"]) - elif "name" in elt: - id_in_db = JsonUtils._get_element_id_in_db_from_name(element_type, elt["name"], - user_id, policy_id, - category_id, meta_rule_id, - manager) - if id_in_db is None: - raise UnknownName( - "No {} with name {} found in database".format(element_type, elt["name"])) - ids.append(id_in_db) - elif field_mandatory is True: - raise MissingIdOrName("No id or name found in the input json {}".format(elt)) - json_out[field_name_out] = ids - - @staticmethod - def convert_ids_to_names(ids, json_out, field_name_out, element_type, manager, user_id, - policy_id=None, category_id=None, meta_rule_id=None): - res_array = [] - for id_ in ids: - element = JsonUtils._get_element_in_db_from_id(element_type, id_, user_id, policy_id, - category_id, meta_rule_id, manager) - if element is None: - raise UnknownId("No {} with id {} found in database".format(element_type, id_)) - res = JsonUtils.__convert_results_to_element(element) - # logger.info(res) - if "name" in res: - res_array.append({"name": res["name"]}) - if "value" in res and "name" in res["value"]: - res_array.append({"name": res["value"]["name"]}) - json_out[field_name_out] = res_array diff --git a/moon_manager/moon_manager/api/logs.py b/moon_manager/moon_manager/api/logs.py new file mode 100644 index 00000000..49b39b11 --- /dev/null +++ b/moon_manager/moon_manager/api/logs.py @@ -0,0 +1,25 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +"""Test hug API (local, command-line, and HTTP access)""" +import hug + + +@hug.local() +@hug.get("/logs/") +def list(): + """ + List logs + :return: JSON status output + """ + + return {"logs": []} diff --git a/moon_manager/moon_manager/api/meta_data.py b/moon_manager/moon_manager/api/meta_data.py index b0b86d10..828124df 100644 --- a/moon_manager/moon_manager/api/meta_data.py +++ b/moon_manager/moon_manager/api/meta_data.py @@ -1,42 +1,53 @@ -# 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) +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + +""" +Meta Data are elements used to create Meta data (skeleton of security policies)subject_categories +* 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 +import hug import logging -from python_moonutilities.security_functions import check_auth -from python_moondb.core import ModelManager -from python_moonutilities.security_functions import validate_input +import requests +from moon_manager import db_driver as driver +from moon_utilities.security_functions import validate_input +from moon_utilities.auth_functions import api_key_authentication, connect_from_env +from moon_utilities.invalided_functions import invalidate_meta_data_in_slaves +from moon_manager.api import slave as slave_class +from moon_manager.api import configuration -__version__ = "4.3.2" +# from moon_manager.server import handle_exception, handle_custom_exceptions -logger = logging.getLogger("moon.manager.api." + __name__) +LOGGER = logging.getLogger("moon.manager.api." + __name__) -class SubjectCategories(Resource): +class SubjectCategories(object): """ Endpoint for subject categories requests """ - __urls__ = ( - "/subject_categories", - "/subject_categories/", - "/subject_categories/", - ) - - @validate_input("get", kwargs_state=[False, False]) - @check_auth - def get(self, category_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.get("/subject_categories", requires=api_key_authentication) + @hug.get("/subject_categories/{category_id}", requires=api_key_authentication) + def get(category_id: hug.types.text = None, authed_user: hug.directives.user = 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 + :param authed_user: user ID who do the request :return: { "subject_category_id": { "name": "name of the category", @@ -45,18 +56,19 @@ class SubjectCategories(Resource): } :internal_api: get_subject_categories """ - data = ModelManager.get_subject_categories( - user_id=user_id, category_id=category_id) + data = driver.ModelManager.get_subject_categories(moon_user_id=authed_user, + category_id=category_id) return {"subject_categories": data} - @validate_input("post", body_state={"name": True}) - @check_auth - def post(self, category_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.post("/subject_categories", requires=api_key_authentication) + def post(body: validate_input("name"), authed_user: hug.directives.user = None): """Create or update a subject category. - :param category_id: must not be used here - :param user_id: user ID who do the request + :param body: body of the request + :param authed_user: user ID who do the request :request body: { "name": "name of the category (mandatory)", "description": "description of the category (optional)" @@ -69,18 +81,19 @@ class SubjectCategories(Resource): } :internal_api: add_subject_category """ - data = ModelManager.add_subject_category( - user_id=user_id, value=request.json) + data = driver.ModelManager.add_subject_category(moon_user_id=authed_user, value=body) + return {"subject_categories": data} - @validate_input("delete", kwargs_state=[True, False]) - @check_auth - def delete(self, category_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.delete("/subject_categories/{category_id}", requires=api_key_authentication) + def delete(category_id: hug.types.text = None, authed_user: hug.directives.user = None): """Delete a subject category :param category_id: uuid of the subject category to delete - :param user_id: user ID who do the request + :param authed_user: user ID who do the request :return: { "result": "True or False", "message": "optional message (optional)" @@ -88,30 +101,29 @@ class SubjectCategories(Resource): :internal_api: delete_subject_category """ - data = ModelManager.delete_subject_category( - user_id=user_id, category_id=category_id) + driver.ModelManager.delete_subject_category(moon_user_id=authed_user, + category_id=category_id) + + slaves = slave_class.Slaves.get().get("slaves") + invalidate_meta_data_in_slaves(slaves=slaves, category_id=category_id, type='subject') return {"result": True} -class ObjectCategories(Resource): +class ObjectCategories(object): """ Endpoint for object categories requests """ - __urls__ = ( - "/object_categories", - "/object_categories/", - "/object_categories/", - ) - - @validate_input("get", kwargs_state=[False, False]) - @check_auth - def get(self, category_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.get("/object_categories", requires=api_key_authentication) + @hug.get("/object_categories/{category_id}", requires=api_key_authentication) + def get(category_id: hug.types.text = None, authed_user: hug.directives.user = 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 + :param authed_user: user ID who do the request :return: { "object_category_id": { "name": "name of the category", @@ -120,18 +132,19 @@ class ObjectCategories(Resource): } :internal_api: get_object_categories """ - data = ModelManager.get_object_categories( - user_id=user_id, category_id=category_id) + data = driver.ModelManager.get_object_categories(moon_user_id=authed_user, + category_id=category_id) return {"object_categories": data} - @validate_input("post", body_state={"name": True}) - @check_auth - def post(self, category_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.post("/object_categories", requires=api_key_authentication) + def post(body: validate_input("name"), authed_user: hug.directives.user = None): """Create or update a object category. - :param category_id: must not be used here - :param user_id: user ID who do the request + :param body: body of the request + :param authed_user: user ID who do the request :request body: { "name": "name of the category (mandatory)", "description": "description of the category (optional)" @@ -144,19 +157,18 @@ class ObjectCategories(Resource): } :internal_api: add_object_category """ - - data = ModelManager.add_object_category( - user_id=user_id, value=request.json) + data = driver.ModelManager.add_object_category(moon_user_id=authed_user, value=body) return {"object_categories": data} - @validate_input("delete", kwargs_state=[True, False]) - @check_auth - def delete(self, category_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.delete("/object_categories/{category_id}", requires=api_key_authentication) + def delete(category_id: hug.types.text = None, authed_user: hug.directives.user = None): """Delete an object category :param category_id: uuid of the object category to delete - :param user_id: user ID who do the request + :param authed_user: user ID who do the request :return: { "result": "True or False", "message": "optional message (optional)" @@ -164,30 +176,29 @@ class ObjectCategories(Resource): :internal_api: delete_object_category """ - data = ModelManager.delete_object_category( - user_id=user_id, category_id=category_id) + driver.ModelManager.delete_object_category(moon_user_id=authed_user, + category_id=category_id) + + slaves = slave_class.Slaves.get().get("slaves") + invalidate_meta_data_in_slaves(slaves=slaves, category_id=category_id, type='object') return {"result": True} -class ActionCategories(Resource): +class ActionCategories(object): """ Endpoint for action categories requests """ - __urls__ = ( - "/action_categories", - "/action_categories/", - "/action_categories/", - ) - - @validate_input("get", kwargs_state=[False, False]) - @check_auth - def get(self, category_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.get("/action_categories", requires=api_key_authentication) + @hug.get("/action_categories/{category_id}", requires=api_key_authentication) + def get(category_id: hug.types.text = None, authed_user: hug.directives.user = 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 + :param authed_user: user ID who do the request :return: { "action_category_id": { "name": "name of the category", @@ -196,19 +207,18 @@ class ActionCategories(Resource): } :internal_api: get_action_categories """ - - data = ModelManager.get_action_categories( - user_id=user_id, category_id=category_id) - + data = driver.ModelManager.get_action_categories(moon_user_id=authed_user, + category_id=category_id) return {"action_categories": data} - @validate_input("post", body_state={"name": True}) - @check_auth - def post(self, category_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.post("/action_categories", requires=api_key_authentication) + def post(body: validate_input("name"), authed_user: hug.directives.user = None): """Create or update an action category. - :param category_id: must not be used here - :param user_id: user ID who do the request + :param body: body of the request + :param authed_user: user ID who do the request :request body: { "name": "name of the category (mandatory)", "description": "description of the category (optional)" @@ -222,25 +232,353 @@ class ActionCategories(Resource): :internal_api: add_action_category """ - data = ModelManager.add_action_category( - user_id=user_id, value=request.json) + data = driver.ModelManager.add_action_category(moon_user_id=authed_user, value=body) return {"action_categories": data} - @validate_input("delete", kwargs_state=[True, False]) - @check_auth - def delete(self, category_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.delete("/action_categories/{category_id}", requires=api_key_authentication) + def delete(category_id: hug.types.text = None, authed_user: hug.directives.user = None): """Delete an action :param category_id: uuid of the action category to delete - :param user_id: user ID who do the request + :param authed_user: user ID who do the request :return: { "result": "True or False", "message": "optional message (optional)" } :internal_api: delete_action_category """ - data = ModelManager.delete_action_category( - user_id=user_id, category_id=category_id) + driver.ModelManager.delete_action_category(moon_user_id=authed_user, + category_id=category_id) + + slaves = slave_class.Slaves.get().get("slaves") + invalidate_meta_data_in_slaves(slaves=slaves, category_id=category_id, type='action') return {"result": True} + + +SubjectCategoriesAPI = hug.API(name='subject_categories', doc=SubjectCategories.__doc__) + + +@hug.object(name='subject_categories', version='1.0.0', api=SubjectCategoriesAPI) +class SubjectCategoriesCLI(object): + """An example of command like calls via an Object""" + + @staticmethod + @hug.object.cli + def list(name_or_id="", human: bool = False): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _subject_categories_req = requests.get("{}/subject_categories".format(db_conf.get("url")), + headers={"x-api-key": manager_api_key} + ) + if _subject_categories_req.status_code == 200: + if name_or_id: + _subject_categories = None + if name_or_id in _subject_categories_req.json().get("subject_categories"): + _subject_categories = _subject_categories_req.json().get("subject_categories")\ + .get(name_or_id) + else: + for _subject_categories_key in _subject_categories_req.json()\ + .get("subject_categories"): + _name = _subject_categories_req.json().get("subject_categories")\ + .get(_subject_categories_key).get("name") + if _name == name_or_id: + _subject_categories = _subject_categories_req.json()\ + .get("subject_categories").get(_subject_categories_key) + name_or_id = _subject_categories_key + break + if not _subject_categories: + raise Exception("Cannot find SubjectCategories with name or ID {}".format( + name_or_id)) + result = {"subject_categories": {name_or_id: _subject_categories}} + else: + result = _subject_categories_req.json() + + if human: + return SubjectCategoriesCLI.human_display(result) + else: + return result + LOGGER.error('Cannot list SubjectCategories {}'.format(_subject_categories_req.status_code)) + + @staticmethod + @hug.object.cli + def add(name, description="", human: bool = False): + """ + Add subject category in database + :return: JSON status output + """ + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _url = "{}/subject_categories".format(db_conf.get("url")) + _subject_categories = requests.post( + _url, + json={ + "name": name, + "description": description, + }, + headers={ + "x-api-key": manager_api_key, + "Content-Type": "application/json" + } + ) + if _subject_categories.status_code == 200: + LOGGER.warning('Create {}'.format(_subject_categories.content)) + if human: + return SubjectCategoriesCLI.human_display(_subject_categories.json()) + else: + return _subject_categories.json() + LOGGER.error('Cannot create {}'.format(name, _subject_categories.content[:40])) + + @staticmethod + @hug.object.cli + def delete(name_or_id): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _subject_categories = SubjectCategoriesCLI.list() + for _perimeter_id, _perimeter_value in _subject_categories.get("subject_categories")\ + .items(): + if _perimeter_value.get("name") == name_or_id: + _url = "{}/subject_categories/{}".format(db_conf.get("url"), _perimeter_id) + req = requests.delete( + _url, + headers={"x-api-key": manager_api_key} + ) + break + else: + LOGGER.error("Cannot find SubjectCategories with name {}".format(name_or_id)) + return False + if req.status_code == 200: + LOGGER.warning('Deleted {}'.format(name_or_id)) + return True + LOGGER.error("Cannot delete SubjectCategories with name {}".format(name_or_id)) + return False + + @staticmethod + def human_display(subject_categories_json): + human_result = "Subject Categories" + for subject_category in subject_categories_json.get("subject_categories"): + human_result += "\n" + subject_categories_json.get("subject_categories").get(subject_category).get("name") + "\n" + human_result += "\tid : " + subject_categories_json.get("subject_categories").get(subject_category).get("id") + "\n" + human_result += "\tname : " + subject_categories_json.get("subject_categories").get(subject_category).get("name") + "\n" + human_result += "\tdescription : " + subject_categories_json.get("subject_categories").get(subject_category).get("description") + "\n" + return human_result + + +ObjectCategoriesAPI = hug.API(name='object_categories', doc=ObjectCategories.__doc__) + + +@hug.object(name='object_categories', version='1.0.0', api=ObjectCategoriesAPI) +class ObjectCategoriesCLI(object): + """An example of command like calls via an Object""" + + @staticmethod + @hug.object.cli + def list(name_or_id="", human: bool = False): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _object_categories_req = requests.get("{}/object_categories".format(db_conf.get("url")), + headers={"x-api-key": manager_api_key} + ) + if _object_categories_req.status_code == 200: + if name_or_id: + _object_categories = None + if name_or_id in _object_categories_req.json().get("object_categories"): + _object_categories = _object_categories_req.json().get("object_categories")\ + .get(name_or_id) + else: + for _object_categories_key in _object_categories_req.json()\ + .get("object_categories"): + _name = _object_categories_req.json().get("object_categories")\ + .get(_object_categories_key).get("name") + if _name == name_or_id: + _object_categories = _object_categories_req.json()\ + .get("object_categories").get(_object_categories_key) + name_or_id = _object_categories_key + break + if not _object_categories: + raise Exception("Cannot find ObjectCategories with name or ID {}".format( + name_or_id)) + result = {"object_categories": {name_or_id: _object_categories}} + else: + result = _object_categories_req.json() + + if human: + return ObjectCategoriesCLI.human_display(result) + else: + return result + LOGGER.error('Cannot list ObjectCategories {}'.format(_object_categories_req.status_code)) + + @staticmethod + @hug.object.cli + def add(name, description="", human: bool = False): + """ + Add object category in database + :return: JSON status output + """ + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _url = "{}/object_categories".format(db_conf.get("url")) + _object_categories = requests.post( + _url, + json={ + "name": name, + "description": description, + }, + headers={ + "x-api-key": manager_api_key, + "Content-Type": "application/json" + } + ) + if _object_categories.status_code == 200: + LOGGER.warning('Create {}'.format(_object_categories.content)) + if human: + return ObjectCategoriesCLI.human_display(_object_categories.json()) + else: + return _object_categories.json() + LOGGER.error('Cannot create {}'.format(name, _object_categories.content[:40])) + + @staticmethod + @hug.object.cli + def delete(name_or_id): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _object_categories = ObjectCategoriesCLI.list() + for _perimeter_id, _perimeter_value in _object_categories.get("object_categories").items(): + if _perimeter_value.get("name") == name_or_id: + _url = "{}/object_categories/{}".format(db_conf.get("url"), _perimeter_id) + req = requests.delete( + _url, + headers={"x-api-key": manager_api_key} + ) + break + else: + LOGGER.error("Cannot find ObjectCategories with name {}".format(name_or_id)) + return False + if req.status_code == 200: + LOGGER.warning('Deleted {}'.format(name_or_id)) + return True + LOGGER.error("Cannot delete ObjectCategories with name {}".format(name_or_id)) + return False + + @staticmethod + def human_display(object_categories_json): + human_result = "Object Categories" + for object_category in object_categories_json.get("object_categories"): + human_result += "\n" + object_categories_json.get("object_categories").get(object_category).get("name") + "\n" + human_result += "\tid : " + object_categories_json.get("object_categories").get(object_category).get("id") + "\n" + human_result += "\tname : " + object_categories_json.get("object_categories").get(object_category).get("name") + "\n" + human_result += "\tdescription : " + object_categories_json.get("object_categories").get(object_category).get("description") + "\n" + return human_result + +ActionCategoriesAPI = hug.API(name='action_categories', doc=ActionCategories.__doc__) + + +@hug.object(name='action_categories', version='1.0.0', api=ActionCategoriesAPI) +class ActionCategoriesCLI(object): + """An example of command like calls via an Object""" + + @staticmethod + @hug.object.cli + def list(name_or_id="", human: bool = False): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _action_categories_req = requests.get("{}/action_categories".format(db_conf.get("url")), + headers={"x-api-key": manager_api_key} + ) + if _action_categories_req.status_code == 200: + if name_or_id: + _action_categories = None + if name_or_id in _action_categories_req.json().get("action_categories"): + _action_categories = _action_categories_req.json().get("action_categories")\ + .get(name_or_id) + else: + for _action_categories_key in _action_categories_req.json()\ + .get("action_categories"): + _name = _action_categories_req.json().get("action_categories")\ + .get(_action_categories_key).get("name") + if _name == name_or_id: + _action_categories = _action_categories_req.json()\ + .get("action_categories").get(_action_categories_key) + name_or_id = _action_categories_key + break + if not _action_categories: + raise Exception("Cannot find ActionCategories with name or ID {}".format( + name_or_id)) + result = {"action_categories": {name_or_id: _action_categories}} + else: + result = _action_categories_req.json() + + if human: + return ActionCategoriesCLI.human_display(result) + else: + return result + LOGGER.error('Cannot list ActionCategories {}'.format(_action_categories_req.status_code)) + + @staticmethod + @hug.object.cli + def add(name, description="",human: bool = False): + """ + Add action category in database + :return: JSON status output + """ + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _url = "{}/action_categories".format(db_conf.get("url")) + _action_categories = requests.post( + _url, + json={ + "name": name, + "description": description, + }, + headers={ + "x-api-key": manager_api_key, + "Content-Type": "application/json" + } + ) + if _action_categories.status_code == 200: + LOGGER.warning('Create {}'.format(_action_categories.content)) + if human: + return ActionCategoriesCLI.human_display(_action_categories.json()) + else: + return _action_categories.json() + LOGGER.error('Cannot create {}'.format(name, _action_categories.content[:40])) + + @staticmethod + @hug.object.cli + def delete(name_or_id): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _action_categories = ActionCategoriesCLI.list() + for _perimeter_id, _perimeter_value in _action_categories.get("action_categories").items(): + if _perimeter_value.get("name") == name_or_id: + _url = "{}/action_categories/{}".format(db_conf.get("url"), _perimeter_id) + req = requests.delete( + _url, + headers={"x-api-key": manager_api_key} + ) + break + else: + LOGGER.error("Cannot find ActionCategories with name {}".format(name_or_id)) + return False + if req.status_code == 200: + LOGGER.warning('Deleted {}'.format(name_or_id)) + return True + LOGGER.error("Cannot delete ActionCategories with name {}".format(name_or_id)) + return False + + @staticmethod + def human_display(action_categories_json): + human_result = "Action Categories" + for action_category in action_categories_json.get("action_categories"): + human_result += "\n" + action_categories_json.get("action_categories").get(action_category).get( + "name") + "\n" + human_result += "\tid : " + action_categories_json.get("action_categories").get(action_category).get( + "id") + "\n" + human_result += "\tname : " + action_categories_json.get("action_categories").get(action_category).get( + "name") + "\n" + human_result += "\tdescription : " + action_categories_json.get("action_categories").get( + action_category).get("description") + "\n" + return human_result diff --git a/moon_manager/moon_manager/api/meta_rules.py b/moon_manager/moon_manager/api/meta_rules.py index 738aad71..fbdfc2e5 100644 --- a/moon_manager/moon_manager/api/meta_rules.py +++ b/moon_manager/moon_manager/api/meta_rules.py @@ -1,39 +1,45 @@ -# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors -# This software is distributed under the terms and conditions of the 'Apache-2.0' -# license which can be found in the file 'LICENSE' in this package distribution -# or at 'http://www.apache.org/licenses/LICENSE-2.0'. +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + """ Meta rules are skeleton for security policies """ - -from flask import request -from flask_restful import Resource +import hug import logging -from python_moonutilities.security_functions import check_auth -from python_moondb.core import ModelManager -from python_moonutilities.security_functions import validate_input +import requests +from moon_manager import db_driver as driver +from moon_utilities.security_functions import validate_input +from moon_utilities.auth_functions import api_key_authentication, connect_from_env +from moon_utilities.invalided_functions import invalidate_meta_rule_in_slaves +from moon_manager.api import slave as slave_class +from moon_manager.api import configuration +from moon_manager.api import meta_data -__version__ = "4.3.2" +# from moon_manager.server import handle_exception, handle_custom_exceptions -logger = logging.getLogger("moon.manager.api." + __name__) +LOGGER = logging.getLogger("moon.manager.api." + __name__) -class MetaRules(Resource): +class MetaRules(object): """ Endpoint for meta rules requests """ - __urls__ = ( - "/meta_rules", - "/meta_rules/", - "/meta_rules/", - "/meta_rules//" - ) - - @validate_input("get", kwargs_state=[False, False]) - @check_auth - def get(self, meta_rule_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.get("/meta_rules/", requires=api_key_authentication) + @hug.get("/meta_rules/{meta_rule_id}", requires=api_key_authentication) + def get(meta_rule_id: hug.types.text = None, authed_user: hug.directives.user = None): """Retrieve all sub meta rules :param meta_rule_id: Meta rule algorithm ID @@ -52,19 +58,23 @@ class MetaRules(Resource): :internal_api: get_meta_rules """ - data = ModelManager.get_meta_rules( - user_id=user_id, meta_rule_id=meta_rule_id) + data = driver.ModelManager.get_meta_rules( + moon_user_id=authed_user, meta_rule_id=meta_rule_id) return {"meta_rules": data} - @validate_input("post", body_state={"name": True, "subject_categories": False, - "object_categories": False, "action_categories": False}) - @check_auth - def post(self, meta_rule_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.post("/meta_rules/", requires=api_key_authentication) + # @validate_input("post", body_state={"name": True, "subject_categories": False, + # "object_categories": False, "action_categories": False}) + def post( + body: validate_input("name", "subject_categories", "object_categories", + "action_categories"), authed_user: hug.directives.user = None): """Add a meta rule - :param meta_rule_id: Meta rule ID (not used here) - :param user_id: user ID who do the request + :param body: body of the request + :param authed_user: user ID who do the request :request body: post = { "name": "name of the meta rule (mandatory)", "subject_categories": ["subject_category_id1 (mandatory)", @@ -86,20 +96,23 @@ class MetaRules(Resource): :internal_api: add_meta_rules """ - data = ModelManager.add_meta_rule( - user_id=user_id, meta_rule_id=None, value=request.json) + data = driver.ModelManager.add_meta_rule( + moon_user_id=authed_user, meta_rule_id=None, value=body) return {"meta_rules": data} - @validate_input("patch", kwargs_state=[True, False], - body_state={"name": True, "subject_categories": False, - "object_categories": False, "action_categories": False}) - @check_auth - def patch(self, meta_rule_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.patch("/meta_rules/", requires=api_key_authentication) + @hug.patch("/meta_rules/{meta_rule_id}", requires=api_key_authentication) + def patch(body: validate_input("name", "subject_categories", "object_categories", + "action_categories"), meta_rule_id: hug.types.text = None, + authed_user: hug.directives.user = None): """Update a meta rule - :param meta_rule_id: Meta rule ID - :param user_id: user ID who do the request + :param body: body of the request + :param meta_rule_id: ID of the Meta Rule + :param authed_user: user ID who do the request :request body: patch = { "name": "name of the meta rule", "subject_categories": ["subject_category_id1", @@ -120,18 +133,24 @@ class MetaRules(Resource): } :internal_api: set_meta_rules """ - data = ModelManager.update_meta_rule( - user_id=user_id, meta_rule_id=meta_rule_id, value=request.json) + data = driver.ModelManager.update_meta_rule( + moon_user_id=authed_user, meta_rule_id=meta_rule_id, value=body) + + slaves = slave_class.Slaves.get().get("slaves") + invalidate_meta_rule_in_slaves(slaves=slaves, meta_rule_id=meta_rule_id,is_delete=False, + data=data) return {"meta_rules": data} - @validate_input("delete", kwargs_state=[True, False]) - @check_auth - def delete(self, meta_rule_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.delete("/meta_rules/", requires=api_key_authentication) + @hug.delete("/meta_rules/{meta_rule_id}", requires=api_key_authentication) + def delete(meta_rule_id: hug.types.text = None, authed_user: hug.directives.user = None): """Delete a meta rule :param meta_rule_id: Meta rule ID - :param user_id: user ID who do the request + :param authed_user: user ID who do the request :return: { "meta_rules": { "meta_rule_id1": { @@ -146,7 +165,145 @@ class MetaRules(Resource): :internal_api: delete_meta_rules """ - data = ModelManager.delete_meta_rule( - user_id=user_id, meta_rule_id=meta_rule_id) + driver.ModelManager.delete_meta_rule( + moon_user_id=authed_user, meta_rule_id=meta_rule_id) + + slaves = slave_class.Slaves.get().get("slaves") + invalidate_meta_rule_in_slaves(slaves=slaves, meta_rule_id=meta_rule_id) return {"result": True} + + +MetaRulesAPI = hug.API(name='meta_rules', doc=MetaRules.__doc__) + + +@hug.object(name='meta_rules', version='1.0.0', api=MetaRulesAPI) +class MetaRulesCLI(object): + """An example of command like calls via an Object""" + + @staticmethod + @hug.object.cli + def list(name_or_id="", human: bool = False): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _meta_rules_req = requests.get("{}/meta_rules".format(db_conf.get("url")), + headers={"x-api-key": manager_api_key} + ) + if _meta_rules_req.status_code == 200: + if name_or_id: + _meta_rules = None + if name_or_id in _meta_rules_req.json().get("meta_rules"): + _meta_rules = _meta_rules_req.json().get("meta_rules").get(name_or_id) + else: + for _key in _meta_rules_req.json().get("meta_rules"): + _name = _meta_rules_req.json().get("meta_rules").get(_key).get("name") + if _name == name_or_id: + _meta_rules = _meta_rules_req.json().get("meta_rules").get(_key) + name_or_id = _key + break + if not _meta_rules: + raise Exception("Cannot find meta_rules with name or ID {}".format( + name_or_id)) + result = {"meta_rules": {name_or_id: _meta_rules}} + else: + result = _meta_rules_req.json() + + if human: + return MetaRulesCLI.human_display(result) + else: + return result + LOGGER.error('Cannot list meta_rules {}'.format(_meta_rules_req.status_code)) + + @staticmethod + @hug.object.cli + def add(name, subject_categories, object_categories, action_categories, human: bool = False): + """ + Add a meta rule in database + :return: JSON status output + """ + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + subject_categories_ids = [] + for cat in subject_categories.split(","): + _cat_dict = meta_data.SubjectCategoriesCLI.list(cat).get("subject_categories") + if cat in _cat_dict: + subject_categories_ids.append(cat) + else: + subject_categories_ids.append(list(_cat_dict.keys())[0]) + object_categories_ids = [] + for cat in object_categories.split(","): + _cat_dict = meta_data.ObjectCategoriesCLI.list(cat).get("object_categories") + if cat in _cat_dict: + object_categories_ids.append(cat) + else: + object_categories_ids.append(list(_cat_dict.keys())[0]) + action_categories_ids = [] + for cat in action_categories.split(","): + _cat_dict = meta_data.ActionCategoriesCLI.list(cat).get("action_categories") + if cat in _cat_dict: + action_categories_ids.append(cat) + else: + action_categories_ids.append(list(_cat_dict.keys())[0]) + _url = "{}/meta_rules".format(db_conf.get("url")) + req = requests.post( + _url, + json={ + "name": name, + "subject_categories": subject_categories_ids, + "object_categories": object_categories_ids, + "action_categories": action_categories_ids, + }, + headers={ + "x-api-key": manager_api_key, + "Content-Type": "application/json" + } + ) + if req.status_code == 200: + LOGGER.warning('Create {}'.format(req.content)) + if human: + return MetaRulesCLI.human_display(req.json()) + else: + return req.json() + LOGGER.error('Cannot create {}'.format(name, req.content[:40])) + + @staticmethod + @hug.object.cli + def delete(name_or_id): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _meta_rules = MetaRulesCLI.list() + for _id, _value in _meta_rules.get("meta_rules").items(): + if _id == name_or_id or _value.get("name") == name_or_id: + _url = "{}/meta_rules/{}".format(db_conf.get("url"), _id) + req = requests.delete( + _url, + headers={"x-api-key": manager_api_key} + ) + break + else: + LOGGER.error("Cannot find meta_rules with name {}".format(name_or_id)) + return False + if req.status_code == 200: + LOGGER.warning('Deleted {}'.format(name_or_id)) + return True + LOGGER.error("Cannot delete meta_rules with name {}".format(name_or_id)) + return False + + @staticmethod + def human_display(meta_rules_json): + human_result = "Meta Rules" + for metarule in meta_rules_json.get("meta_rules"): + human_result += "\n" + meta_rules_json.get("meta_rules").get(metarule).get("name") + "\n" + human_result += "\tid : " + metarule + "\n" + human_result += "\tname : " + meta_rules_json.get("meta_rules").get(metarule).get("name") + "\n" + human_result += "\tdescription : " + meta_rules_json.get("meta_rules").get(metarule).get("description") + "\n" + human_result += "\tsubject_categories :\n" + for subject_category in meta_rules_json.get("meta_rules").get(metarule).get("subject_categories"): + human_result += "\t\t" + subject_category + "\n" + human_result += "\tobject_categories :\n" + for object_category in meta_rules_json.get("meta_rules").get(metarule).get("object_categories"): + human_result += "\t\t" + object_category + "\n" + human_result += "\taction_categories :\n" + for action_category in meta_rules_json.get("meta_rules").get(metarule).get("action_categories"): + human_result += "\t\t" + action_category + "\n" + return human_result diff --git a/moon_manager/moon_manager/api/models.py b/moon_manager/moon_manager/api/models.py index c72396cf..e6f3dc2d 100644 --- a/moon_manager/moon_manager/api/models.py +++ b/moon_manager/moon_manager/api/models.py @@ -1,42 +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'. +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + """ Models aggregate multiple meta rules """ -from flask import request -from flask_restful import Resource +import hug +import json import logging -from python_moonutilities.security_functions import check_auth -from python_moondb.core import ModelManager -from python_moonutilities.security_functions import validate_input +import requests +from moon_manager import db_driver as driver +from moon_utilities.security_functions import validate_input +from moon_utilities.auth_functions import api_key_authentication, connect_from_env +from moon_utilities.invalided_functions import invalidate_model_in_slaves +from moon_manager.api import slave as slave_class +from moon_manager.api import configuration -__version__ = "4.3.2" -logger = logging.getLogger("moon.manager.api." + __name__) +LOGGER = logging.getLogger("moon.manager.api." + __name__) -class Models(Resource): +class Models(object): """ Endpoint for model requests """ - __urls__ = ( - "/models", - "/models/", - "/models/", - "/models//", - ) - - @validate_input("get", kwargs_state=[False, False]) - @check_auth - def get(self, uuid=None, user_id=None): + @staticmethod + @hug.local() + @hug.get("/models", requires=api_key_authentication) + @hug.get("/models/{model_id}", requires=api_key_authentication) + def get(model_id: hug.types.text = None, moon_user_id=None): """Retrieve all models - :param uuid: uuid of the model - :param user_id: user ID who do the request + :param model_id: uuid of the model + :param moon_user_id: user ID who do the request :return: { "model_id1": { "name": "...", @@ -46,17 +51,17 @@ class Models(Resource): } :internal_api: get_models """ - data = ModelManager.get_models(user_id=user_id, model_id=uuid) - + data = driver.ModelManager.get_models(moon_user_id=moon_user_id, model_id=model_id) return {"models": data} - @validate_input("post", body_state={"name": True, "meta_rules": False}) - @check_auth - def post(self, uuid=None, user_id=None): + @staticmethod + @hug.local() + @hug.post("/models", requires=api_key_authentication) + def post(body: validate_input("name"), moon_user_id=None): """Create model. - :param uuid: uuid of the model (not used here) - :param user_id: user ID who do the request + :param body: body of the request + :param moon_user_id: user ID who do the request :request body: { "name": "name of the model (mandatory)", "description": "description of the model (optional)", @@ -71,18 +76,19 @@ class Models(Resource): } :internal_api: add_model """ - data = ModelManager.add_model( - user_id=user_id, model_id=uuid, value=request.json) + data = driver.ModelManager.add_model( + moon_user_id=moon_user_id, value=body) return {"models": data} - @validate_input("delete", kwargs_state=[True, False]) - @check_auth - def delete(self, uuid=None, user_id=None): + @staticmethod + @hug.local() + @hug.delete("/models/{model_id}", requires=api_key_authentication) + def delete(model_id: hug.types.text, moon_user_id=None): """Delete a model - :param uuid: uuid of the model to delete - :param user_id: user ID who do the request + :param model_id: uuid of the model to delete + :param moon_user_id: user ID who do the request :return: { "result": "True or False", "message": "optional message (optional)" @@ -90,18 +96,22 @@ class Models(Resource): :internal_api: delete_model """ - data = ModelManager.delete_model(user_id=user_id, model_id=uuid) + driver.ModelManager.delete_model(moon_user_id=moon_user_id, model_id=model_id) + + slaves = slave_class.Slaves.get().get("slaves") + invalidate_model_in_slaves(slaves=slaves, model_id=model_id) return {"result": True} - @validate_input("patch", kwargs_state=[True, False], - body_state={"name": True, "meta_rules": False}) - @check_auth - def patch(self, uuid=None, user_id=None): + @staticmethod + @hug.local() + @hug.patch("/models/{model_id}", requires=api_key_authentication) + def patch(body: validate_input("name"), model_id: hug.types.text, moon_user_id=None): """Update a model - :param uuid: uuid of the model to update - :param user_id: user ID who do the request + :param body: body of the request + :param model_id: uuid of the model to update + :param moon_user_id: user ID who do the request :return: { "model_id1": { "name": "name of the model", @@ -111,7 +121,136 @@ class Models(Resource): } :internal_api: update_model """ - data = ModelManager.update_model( - user_id=user_id, model_id=uuid, value=request.json) + data = driver.ModelManager.update_model( + moon_user_id=moon_user_id, model_id=model_id, value=body) + + slaves = slave_class.Slaves.get().get("slaves") + invalidate_model_in_slaves(slaves=slaves, model_id=model_id, is_delete=False, + data=data[model_id]) return {"models": data} + + +ModelsAPI = hug.API(name='models', doc=Models.__doc__) + + +@hug.object(name='models', version='1.0.0', api=ModelsAPI) +class ModelsCLI(object): + """An example of command like calls via an Object""" + + @staticmethod + @hug.object.cli + def list(name_or_id="", human: bool = False): + """ + List models from the database + :return: JSON status output + """ + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _models_req = requests.get("{}/models".format(db_conf.get("url")), + headers={"x-api-key": manager_api_key} + ) + if _models_req.status_code == 200: + if name_or_id: + _models = None + if name_or_id in _models_req.json().get("models"): + _models = _models_req.json().get("models").get(name_or_id) + else: + for _models_key in _models_req.json().get("models"): + _name = _models_req.json().get("models").get(_models_key).get("name") + if _name == name_or_id: + _models = _models_req.json().get("models").get(_models_key) + name_or_id = _models_key + break + if not _models: + raise Exception("Cannot find model with name or ID {}".format(name_or_id)) + else: + if human: + result = {"models": {name_or_id: _models}} + else: + result = {"models": [{name_or_id: _models}]} + else: + result = _models_req.json() + + if human: + return ModelsCLI.human_display(result) + else: + return result + LOGGER.error('Cannot list Models {}'.format(_models_req.status_code)) + + + @staticmethod + @hug.object.cli + def add(name, meta_rule, description="", human: bool = False): + """ + Add model in the database + :return: JSON status output + """ + from moon_manager.api import meta_rules + + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + + _meta_rules = meta_rules.MetaRules.get()["meta_rules"] + _meta_rules_by_name = {_meta_rules[i]["name"]: i for i in _meta_rules} + + if meta_rule in _meta_rules_by_name: + meta_rule_id = _meta_rules_by_name[meta_rule] + elif meta_rule in _meta_rules: + meta_rule_id = meta_rule + else: + raise Exception("Cannot find meta_rule with name or ID {}".format(meta_rule)) + + _models = requests.post( + "{}/models".format(db_conf.get("url")), + json={ + "name": name, + "description": description, + "meta_rules": [meta_rule_id] + }, + headers={ + "x-api-key": manager_api_key, + "Content-Type": "application/json" + } + ) + if _models.status_code == 200: + LOGGER.warning('Create {}'.format(_models.content)) + if human: + return ModelsCLI.human_display(_models.json()) + else: + return _models.json() + LOGGER.error('Cannot create {}'.format(name, _models.content)) + + @staticmethod + @hug.object.cli + def delete(name='default'): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _models = ModelsCLI.list() + for _slave_id, _slave_value in _models.get("models").items(): + if _slave_value.get("name") == name: + req = requests.delete( + "{}/models/{}".format(db_conf.get("url"), _slave_id), + headers={"x-api-key": manager_api_key} + ) + break + else: + LOGGER.error("Cannot find model with name {}".format(name)) + return + if req.status_code == 200: + LOGGER.warning('Deleted {}'.format(name)) + return True + LOGGER.error("Cannot delete model with name {}".format(name)) + + @staticmethod + def human_display(models_json): + human_result = "Models" + for model in models_json.get("models"): + human_result += "\n" + models_json.get("models").get(model).get("name") + " : \n" + human_result += "\tname : " + models_json.get("models").get(model).get("name") + "\n" + human_result += "\tid : " + model + "\n" + human_result += "\tdescription : " + models_json.get("models").get(model).get("description") + "\n" + human_result += "\tmeta_rules : \n" + for meta_rule in models_json.get("models").get(model).get("meta_rules"): + human_result += "\t\tid : " + meta_rule + "\n" + return human_result diff --git a/moon_manager/moon_manager/api/orchestration/__init__.py b/moon_manager/moon_manager/api/orchestration/__init__.py new file mode 100644 index 00000000..1856aa2c --- /dev/null +++ b/moon_manager/moon_manager/api/orchestration/__init__.py @@ -0,0 +1,12 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + diff --git a/moon_manager/moon_manager/api/orchestration/managers.py b/moon_manager/moon_manager/api/orchestration/managers.py new file mode 100644 index 00000000..b4776ec2 --- /dev/null +++ b/moon_manager/moon_manager/api/orchestration/managers.py @@ -0,0 +1,21 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +import logging + +logger = logging.getLogger("moon.api.orchestration.managers") + + +class Managers(object): + """Object that links managers together""" + SlaveManager = None + PipelineManager = None diff --git a/moon_manager/moon_manager/api/orchestration/pipeline.py b/moon_manager/moon_manager/api/orchestration/pipeline.py new file mode 100644 index 00000000..32d8a1f9 --- /dev/null +++ b/moon_manager/moon_manager/api/orchestration/pipeline.py @@ -0,0 +1,44 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +from uuid import uuid4 +import logging +from moon_utilities import exceptions +from moon_utilities.security_functions import enforce +from moon_manager.api.orchestration.managers import Managers + +logger = logging.getLogger("moon.manager.api.orchestration.pod") + + +class PipelineManager(Managers): + + def __init__(self, connector=None): + self.driver = connector.driver + Managers.PipelineManager = self + + @enforce(("read", "write"), "pipelines") + def update_pipeline(self, moon_user_id, pipeline_id, data): + return self.driver.update_pipeline(pipeline_id=pipeline_id, data=data) + + @enforce("write", "pipelines") + def delete_pipeline(self, moon_user_id, pipeline_id): + return self.driver.delete_pipeline(pipeline_id=pipeline_id) + + @enforce("write", "pipelines") + def add_pipeline(self, moon_user_id, pipeline_id=None, data=None): + if not pipeline_id: + pipeline_id = uuid4().hex + return self.driver.add_pipeline(pipeline_id=pipeline_id, data=data) + + @enforce("read", "pipelines") + def get_pipelines(self, moon_user_id, pipeline_id=None): + return self.driver.get_pipelines(pipeline_id=pipeline_id) diff --git a/moon_manager/moon_manager/api/orchestration/slave.py b/moon_manager/moon_manager/api/orchestration/slave.py new file mode 100644 index 00000000..200dd3d6 --- /dev/null +++ b/moon_manager/moon_manager/api/orchestration/slave.py @@ -0,0 +1,44 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +from uuid import uuid4 +import logging +from moon_utilities import exceptions +from moon_utilities.security_functions import enforce +from moon_manager.api.orchestration.managers import Managers + +logger = logging.getLogger("moon.manager.api.orchestration.pod") + + +class SlaveManager(Managers): + + def __init__(self, connector=None): + self.driver = connector.driver + Managers.SlaveManager = self + + @enforce(("read", "write"), "slaves") + def update_slave(self, moon_user_id, slave_id, value): + return self.driver.update_slave(slave_id=slave_id, value=value) + + @enforce("write", "slaves") + def delete_slave(self, moon_user_id, slave_id): + self.driver.delete_slave(slave_id=slave_id) + + @enforce("write", "slaves") + def add_slave(self, moon_user_id, slave_id=None, data=None): + if not slave_id: + slave_id = uuid4().hex + return self.driver.add_slave(slave_id=slave_id, data=data) + + @enforce("read", "slaves") + def get_slaves(self, moon_user_id, slave_id=None): + return self.driver.get_slaves(slave_id=slave_id) diff --git a/moon_manager/moon_manager/api/pdp.py b/moon_manager/moon_manager/api/pdp.py index 65a6a5f1..6f0b5214 100644 --- a/moon_manager/moon_manager/api/pdp.py +++ b/moon_manager/moon_manager/api/pdp.py @@ -1,214 +1,398 @@ -# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors -# This software is distributed under the terms and conditions of the 'Apache-2.0' -# license which can be found in the file 'LICENSE' in this package distribution -# or at 'http://www.apache.org/licenses/LICENSE-2.0'. +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + """ -PDP are Policy Decision Point. +PDP are Policy Decision Points. """ -from flask import request -from flask_restful import Resource +import hug +import json 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, exceptions -from python_moonutilities.security_functions import validate_input - -__version__ = "4.3.2" - -logger = logging.getLogger("moon.manager.api." + __name__) - - -def delete_pod(uuid): - 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: - url = "{}://{}:{}/pods".format(proto, hostname, port) - req = requests.get(url) - # except requests.exceptions.ConnectionError: - # logger.warning("Orchestrator is not ready, standby... {}".format(url)) - # time.sleep(1) - # else: - # break - for pod_key, pod_list in req.json().get("pods", {}).items(): - for pod_value in pod_list: - if "pdp_id" in pod_value: - if pod_value["pdp_id"] == uuid: - req = requests.delete( - "{}://{}:{}/pods/{}".format(proto, hostname, port, pod_key)) - if req.status_code != 200: - logger.warning( - "Cannot delete pod {} - {}".format(pod_key, pod_value['name'])) - logger.debug(req.content) - # Note (Asteroide): no need to go further if one match - break - - -def add_pod(uuid, data): - if not data.get("keystone_project_id"): - return - logger.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 as e: - logger.warning("add_pod: Orchestrator is not ready, standby...") - logger.exception(e) - time.sleep(1) - else: - break - logger.info("Pod add request answer : {}".format(req.text)) +from moon_manager.api import ERROR_CODE +from moon_manager import db_driver +from moon_utilities.auth_functions import api_key_authentication, connect_from_env +from moon_manager import orchestration_driver +from moon_utilities import exceptions +from moon_utilities.security_functions import validate_input +from moon_utilities.invalided_functions import invalidate_pdp_in_slaves +from moon_manager.api import slave as slave_class +from moon_manager.api import configuration - -def check_keystone_pid(k_pid): - data = PDPManager.get_pdp(user_id="admin") - for pdp_key, pdp_value in data.items(): - logger.info("pdp={}".format(pdp_value)) - if pdp_value["keystone_project_id"] == k_pid: - return True +LOGGER = logging.getLogger("moon.manager.api." + __name__) -class PDP(Resource): +class PDP(object): """ Endpoint for pdp requests """ - __urls__ = ( - "/pdp", - "/pdp/", - "/pdp/", - "/pdp//", - ) - - @validate_input("get", kwargs_state=[False, False]) - @check_auth - def get(self, uuid=None, user_id=None): + @staticmethod + @hug.local() + @hug.get("/pdp/", requires=api_key_authentication) + @hug.get("/pdp/{uuid}", requires=api_key_authentication) + def get(uuid: hug.types.uuid = None, authed_user: hug.directives.user = None): """Retrieve all pdp :param uuid: uuid of the pdp - :param user_id: user ID who do the request + :param authed_user: the name of the authenticated user :return: { "pdp_id1": { "name": "...", "security_pipeline": [...], - "keystone_project_id": "keystone_project_id1", + "vim_project_id": "vim_project_id1", "description": "... (optional)", } } :internal_api: get_pdp """ - - data = PDPManager.get_pdp(user_id=user_id, pdp_id=uuid) + if uuid: + uuid = str(uuid).replace("-", "") + data = db_driver.PDPManager.get_pdp(moon_user_id=authed_user, pdp_id=uuid) return {"pdps": data} - @validate_input("post", body_state={"name": True, "security_pipeline": True, - "keystone_project_id": True}) - @check_auth - def post(self, uuid=None, user_id=None): + @staticmethod + @hug.local() + @hug.post("/pdp/", requires=api_key_authentication) + def post(body: validate_input("name"), response, authed_user: hug.directives.user = None): """Create pdp. - :param uuid: uuid of the pdp (not used here) - :param user_id: user ID who do the request + :param body: preformed body from Hug + :param response: preformed response from Hug + :param authed_user: the name of the authenticated user :request body: { "name": "name of the PDP (mandatory)", "security_pipeline": ["may be empty"], - "keystone_project_id": "keystone_project_id1 (may be empty)", + "vim_project_id": "vim_project_id1 (may be empty)", "description": "description of the PDP (optional)", } :return: { "pdp_id1": { "name": "...", "security_pipeline": [...], - "keystone_project_id": "keystone_project_id1", + "vim_project_id": "vim_project_id1", "description": "... (optional)", } } :internal_api: add_pdp """ - - data = dict(request.json) - if not data.get("keystone_project_id"): - data["keystone_project_id"] = None - else: - if check_keystone_pid(data.get("keystone_project_id")): - raise exceptions.PdpKeystoneMappingConflict - data = PDPManager.add_pdp( - user_id=user_id, pdp_id=None, value=request.json) + if not body.get("security_pipeline"): + body["security_pipeline"] = [] + if not body.get("vim_project_id"): + body["vim_project_id"] = None + data = db_driver.PDPManager.add_pdp( + moon_user_id="admin", pdp_id=None, value=body) uuid = list(data.keys())[0] - logger.debug("data={}".format(data)) - logger.debug("uuid={}".format(uuid)) - add_pod(uuid=uuid, data=data[uuid]) - - return {"pdps": data} + if body["vim_project_id"] and body["security_pipeline"]: + orchestration_driver.PipelineManager.add_pipeline( + moon_user_id=authed_user, pipeline_id=uuid, data=data[uuid]) + return {"pdps": db_driver.PDPManager.get_pdp(moon_user_id=authed_user, pdp_id=uuid)} - @validate_input("delete", kwargs_state=[True, False]) - @check_auth - def delete(self, uuid, user_id=None): + @staticmethod + @hug.local() + @hug.delete("/pdp/{uuid}", requires=api_key_authentication) + def delete(uuid: hug.types.uuid, response=None, authed_user: hug.directives.user = None): """Delete a pdp :param uuid: uuid of the pdp to delete - :param user_id: user ID who do the request + :param response: preformed response from Hug + :param authed_user: the name of the authenticated user :return: { "result": "True or False", "message": "optional message (optional)" } :internal_api: delete_pdp """ - data = PDPManager.delete_pdp(user_id=user_id, pdp_id=uuid) - delete_pod(uuid) + uuid = str(uuid).replace("-", "") + data = db_driver.PDPManager.delete_pdp(moon_user_id=authed_user, pdp_id=uuid) + LOGGER.info(data) + + orchestration_driver.PipelineManager.delete_pipeline(moon_user_id=authed_user, pipeline_id=uuid) + slaves = slave_class.Slaves.get().get("slaves") + invalidate_pdp_in_slaves(slaves=slaves, pdp_id=uuid) return {"result": True} - @validate_input("patch", kwargs_state=[True, False], - body_state={"name": True, "security_pipeline": True, - "keystone_project_id": True}) - @check_auth - def patch(self, uuid, user_id=None): + @staticmethod + @hug.local() + @hug.patch("/pdp/{uuid}", requires=api_key_authentication) + def patch(uuid: hug.types.uuid, body: validate_input("name"), response, + authed_user: hug.directives.user = None): """Update a pdp - :param uuid: uuid of the pdp to update - :param user_id: user ID who do the request + :param uuid: uuid of the pdp to delete + :param body: preformed body from Hug + :param response: preformed response from Hug + :param authed_user: the name of the authenticated user :return: { "pdp_id1": { "name": "name of the PDP", "security_pipeline": ["may be empty"], - "keystone_project_id": "keystone_project_id1 (may be empty)", + "vim_project_id": "vim_project_id1 (may be empty)", "description": "description of the PDP (optional)", } } :internal_api: update_pdp """ - _data = dict(request.json) - if not _data.get("keystone_project_id"): - _data["keystone_project_id"] = None + uuid = str(uuid).replace("-", "") + prev_data = db_driver.PDPManager.get_pdp(moon_user_id=authed_user, pdp_id=uuid) + if not prev_data: + response.status = ERROR_CODE[400] + return {"message": "The PDP is unknown."} + + data = db_driver.PDPManager.update_pdp(moon_user_id=authed_user, pdp_id=uuid, value=body).get(uuid) + + orchestration_driver.PipelineManager.update_pipeline(moon_user_id=authed_user, pipeline_id=uuid, data=data) + slaves = slave_class.Slaves.get().get("slaves") + invalidate_pdp_in_slaves(slaves=slaves, pdp_id=uuid, is_delete=False, data=data) + + return {"pdps": db_driver.PDPManager.get_pdp(moon_user_id=authed_user, pdp_id=uuid)} + + +PDPAPI = hug.API(name='pdps', doc=PDP.__doc__) + + +@hug.object(name='pdps', version='1.0.0', api=PDPAPI) +class PDPCLI(object): + """An example of command like calls via an Object""" + + @staticmethod + @hug.object.cli + def list(name_or_id="", human: bool = False): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _pdps = requests.get("{}/pdp".format(db_conf.get("url")), + headers={"x-api-key": manager_api_key} + ) + if _pdps.status_code == 200: + if name_or_id: + _pdp = None + if name_or_id in _pdps.json().get("pdps"): + _pdp = _pdps.json().get("pdps").get(name_or_id) + else: + for _pdp_key in _pdps.json().get("pdps"): + if _pdps.json().get("pdps").get(_pdp_key).get("name") == name_or_id: + _pdp = _pdps.json().get("pdps").get(_pdp_key) + name_or_id = _pdp_key + break + if not _pdp: + raise Exception("Cannot find PDP with name or ID {}".format(name_or_id)) + else: + if human: + result = {"pdps": {name_or_id: _pdp}} + else: + result = {"pdps": [{name_or_id: _pdp}]} + else: + result = _pdps.json() + + if human: + return PDPCLI.human_display(result) + else: + return result + LOGGER.error('Cannot list PDP {}'.format(_pdps.status_code)) + + @staticmethod + @hug.object.cli + def add(name, description="", security_pipeline="", vim_project_id="", human: bool = False): + """ + Add pdp in the database + :return: JSON status output + """ + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + security_pipeline = security_pipeline.split(",") + _pdps = requests.post( + "{}/pdp".format(db_conf.get("url")), + json={ + "name": name, + "security_pipeline": security_pipeline, + "vim_project_id": vim_project_id, + "description": description, + }, + headers={ + "x-api-key": manager_api_key, + "Content-Type": "application/json" + } + ) + if _pdps.status_code == 200: + LOGGER.warning('Create {}'.format(_pdps.content)) + if human: + return PDPCLI.human_display(_pdps.json()) + else: + return _pdps.json() + LOGGER.error('Cannot create {}'.format(name, _pdps.content[:40])) + + @staticmethod + @hug.object.cli + def delete(name='default'): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _pdps = PDPCLI.list() + for _slave_id, _slave_value in _pdps.get("pdps").items(): + if _slave_value.get("name") == name: + req = requests.delete( + "{}/pdp/{}".format(db_conf.get("url"), _slave_id), + headers={"x-api-key": manager_api_key} + ) + break else: - if check_keystone_pid(_data.get("keystone_project_id")): - raise exceptions.PdpKeystoneMappingConflict - data = PDPManager.update_pdp( - user_id=user_id, pdp_id=uuid, value=_data) - logger.debug("data={}".format(data)) - logger.debug("uuid={}".format(uuid)) - add_pod(uuid=uuid, data=data[uuid]) + LOGGER.error("Cannot find PDP with name {}".format(name)) + return False + if req.status_code == 200: + LOGGER.warning('Deleted {}'.format(name)) + return True + LOGGER.error("Cannot delete PDP with name {}".format(name)) + return False - return {"pdps": data} + @staticmethod + @hug.object.cli + def update(name, description=None, security_pipeline=None, vim_project_id=None): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _pdps = PDPCLI.list() + + for _slave_id, _slave_value in _pdps.get("pdps").items(): + if _slave_value.get("name") == name: + description_updated = _slave_value.get("description") + security_pipeline_updated = _slave_value.get("security_pipeline") + vim_project_id_updated = _slave_value.get("vim_project_id") + + if description is not None: + description_updated = description + if security_pipeline is not None: + if security_pipeline == "": + LOGGER.error(f"Policy given to update the PDP {name} is unknown") + return + else: + security_pipeline_updated = security_pipeline.split(",") + if vim_project_id is not None: + vim_project_id_updated = vim_project_id + + req = requests.patch( + "{}/pdp/{}".format(db_conf.get("url"), _slave_id), + json={ + "name": name, + "security_pipeline": security_pipeline_updated, + "vim_project_id": vim_project_id_updated, + "description": description_updated, + }, + headers={ + "x-api-key": manager_api_key, + "Content-Type": "application/json" + } + ) + + if req.status_code == 200: + LOGGER.warning('Updated {}'.format(name)) + return True + LOGGER.error('Cannot update PDP {}'.format(req.status_code)) + return False + + @staticmethod + def human_display(pdps_json): + human_result = "PDPs" + for pdp in pdps_json.get("pdps"): + human_result += "\n" + pdps_json.get("pdps").get(pdp).get("name") + " : \n" + human_result += "\tname : " + pdps_json.get("pdps").get(pdp).get("name") + "\n" + human_result += "\tid : " + pdp + "\n" + human_result += "\tdescription : " + pdps_json.get("pdps").get(pdp).get("description") + "\n" + human_result += "\tvim_project_id : " + pdps_json.get("pdps").get(pdp).get("vim_project_id") + "\n" + human_result += "\tsecurity_pipeline : \n" + for security_pipeline in pdps_json.get("pdps").get(pdp).get("security_pipeline"): + human_result += "\t\t" + security_pipeline + "\n" + return human_result + + # FIXME: not tested + # @staticmethod + # @hug.object.cli + # def set_project(pdp_name, project_id): + # db_conf = configuration.get_configuration(key='management') + # manager_api_key = configuration.get_api_key_for_user("admin") + # _pdp = PDPCLI.get(pdp_name) + # _pdp_id = list(_pdp.get("pdps")[0].keys())[0] + # _pdp_name = _pdp.get("pdps")[0].get(_pdp_id).get("name") + # _pdps = requests.patch( + # "{}/pdp/{}".format(db_conf.get("url"), _pdp_id), + # json={ + # "name": _pdp_name, + # "vim_project_id": project_id, + # }, + # headers={ + # "x-api-key": manager_api_key, + # "Content-Type": "application/json" + # } + # ) + # if _pdps.status_code == 200: + # LOGGER.warning('Set project {}'.format(_pdps.content)) + # return _pdps.json() + # LOGGER.error('Cannot set project {} (error: {})'.format(project_id, _pdps.status_code)) + # return 'Cannot set project {} (error: {})'.format(project_id, _pdps.status_code) + # + # @staticmethod + # @hug.object.cli + # def add_pipeline(pdp_name, pipeline_id): + # db_conf = configuration.get_configuration(key='management') + # manager_api_key = configuration.get_api_key_for_user("admin") + # _pdp = PDPCLI.get(pdp_name) + # _pdp_id = list(_pdp.get("pdps")[0].keys())[0] + # _pdp_name = _pdp.get("pdps")[0].get(_pdp_id).get("name") + # _pdp_pipelines = _pdp.get("pdps")[0].get(_pdp_id).get("security_pipeline", []) + # # TODO check if pipeline exists + # _pdp_pipelines.append(pipeline_id) + # _pdps = requests.patch( + # "{}/pdp/{}".format(db_conf.get("url"), _pdp_id), + # json={ + # "name": _pdp_name, + # "security_pipeline": _pdp_pipelines, + # }, + # headers={ + # "x-api-key": manager_api_key, + # "Content-Type": "application/json" + # } + # ) + # if _pdps.status_code == 200: + # LOGGER.warning('Set project {}'.format(_pdps.content)) + # return _pdps.json() + # LOGGER.error('Cannot add security pipeline {} (error: {})'.format(pipeline_id, + # _pdps.status_code)) + # return 'Cannot add security pipeline {} (error: {})'.format(pipeline_id, _pdps.content) + # + # @staticmethod + # @hug.object.cli + # def delete_pipeline(pdp_name, pipeline_id): + # db_conf = configuration.get_configuration(key='management') + # manager_api_key = configuration.get_api_key_for_user("admin") + # _pdp = PDPCLI.get(pdp_name) + # _pdp_id = list(_pdp.get("pdps")[0].keys())[0] + # _pdp_name = _pdp.get("pdps")[0].get(_pdp_id).get("name") + # _pdp_pipelines = _pdp.get("pdps")[0].get(_pdp_id).get("security_pipeline") + # # TODO check if pipeline exists + # _pdp_pipelines.remove(pipeline_id) + # _pdps = requests.patch( + # "{}/pdp/{}".format(db_conf.get("url"), _pdp_id), + # json={ + # "name": _pdp_name, + # "security_pipeline": _pdp_pipelines, + # }, + # headers={ + # "x-api-key": manager_api_key, + # "Content-Type": "application/json" + # } + # ) + # if _pdps.status_code == 200: + # LOGGER.warning('Set project {}'.format(_pdps.content)) + # return _pdps.json() + # LOGGER.error('Cannot add security pipeline {} (error: {})'.format(pipeline_id, + # _pdps.status_code)) + # return 'Cannot add security pipeline {} (error: {})'.format(pipeline_id, _pdps.status_code) diff --git a/moon_manager/moon_manager/api/perimeter.py b/moon_manager/moon_manager/api/perimeter.py index a0fda4ad..98bb2769 100644 --- a/moon_manager/moon_manager/api/perimeter.py +++ b/moon_manager/moon_manager/api/perimeter.py @@ -1,7 +1,15 @@ -# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors -# This software is distributed under the terms and conditions of the 'Apache-2.0' -# license which can be found in the file 'LICENSE' in this package distribution -# or at 'http://www.apache.org/licenses/LICENSE-2.0'. +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + """ * Subjects are the source of an action on an object (examples : users, virtual machines) @@ -9,42 +17,40 @@ (examples virtual machines, virtual Routers) * Actions are what subject wants to do on an object """ - -from flask import request -from flask_restful import Resource +import hug import logging -from python_moonutilities.security_functions import check_auth -from python_moondb.core import PolicyManager -from python_moonutilities.security_functions import validate_input +import requests +from moon_manager import db_driver as driver +from moon_utilities import exceptions +from moon_utilities.security_functions import validate_input +from moon_utilities.auth_functions import api_key_authentication, connect_from_env +from moon_utilities.invalided_functions import invalidate_perimeter_in_slaves +from moon_manager.api import slave as slave_class +from moon_manager.api import configuration +from moon_manager.api import policy -__version__ = "4.3.2" +LOGGER = logging.getLogger("moon.manager.api." + __name__) -logger = logging.getLogger("moon.manager.api." + __name__) - -class Subjects(Resource): +class Subjects(object): """ Endpoint for subjects requests """ - __urls__ = ( - "/subjects", - "/subjects/", - "/subjects/", - "/policies//subjects", - "/policies//subjects/", - "/policies//subjects/", - ) - - @validate_input("get", kwargs_state=[False, False, False]) - @check_auth - def get(self, uuid=None, perimeter_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.get("/subjects/", requires=api_key_authentication) + @hug.get("/subjects/{perimeter_id}", requires=api_key_authentication) + @hug.get("/policies/{uuid}/subjects/", requires=api_key_authentication) + @hug.get("/policies/{uuid}/subjects/{perimeter_id}", requires=api_key_authentication) + def get(uuid: hug.types.text = None, perimeter_id: hug.types.text = None, + authed_user: hug.directives.user = 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 + :param authed_user: user ID who do the request :return: { "subject_id": { "name": "name of the subject", @@ -55,22 +61,29 @@ class Subjects(Resource): :internal_api: get_subjects """ - data = PolicyManager.get_subjects( - user_id=user_id, + # data = {"policy_id": str(uuid), "perimeter_id": str(perimeter_id)} + data = driver.PolicyManager.get_subjects( + moon_user_id=authed_user, policy_id=uuid, perimeter_id=perimeter_id ) - + # logger.info(db_driver.PolicyManager.get_subjects(policy_id=str(uuid))) return {"subjects": data} - @validate_input("post", body_state={"name": True}) - @check_auth - def post(self, uuid=None, perimeter_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.post("/newsubject", requires=api_key_authentication) + @hug.post("/subjects/{perimeter_id}", requires=api_key_authentication) + @hug.post("/policies/{uuid}/subjects/", requires=api_key_authentication) + @hug.post("/policies/{uuid}/subjects/{perimeter_id}", requires=api_key_authentication) + def post(body: validate_input("name"), uuid: hug.types.text = None, perimeter_id: + hug.types.text = None, authed_user: hug.directives.user = None): """Create or update a subject. + :param body: body of the request :param uuid: uuid of the policy :param perimeter_id: must not be used here - :param user_id: user ID who do the request + :param authed_user: user ID who do the request :request body: { "name": "name of the subject (mandatory)", "description": "description of the subject (optional)", @@ -89,20 +102,25 @@ class Subjects(Resource): :internal_api: set_subject """ - data = PolicyManager.add_subject( - user_id=user_id, policy_id=uuid, - perimeter_id=perimeter_id, value=request.json) + if 'policy_list' in body: + raise exceptions.PerimeterContentError("body should not contain policy_list") + # data = {"policy_id": uuid, "perimeter_id": perimeter_id} + data = driver.PolicyManager.add_subject(moon_user_id=authed_user, + policy_id=uuid, + perimeter_id=perimeter_id, + value=body) return {"subjects": data} - @validate_input("patch", kwargs_state=[False, True, False]) - @check_auth - def patch(self, uuid=None, perimeter_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.patch("/subjects/{perimeter_id}", requires=api_key_authentication) + def patch(body, perimeter_id: hug.types.text = None, authed_user: hug.directives.user = None): """Create or update a subject. - :param uuid: uuid of the policy + :param body: body of the request :param perimeter_id: must not be used here - :param user_id: user ID who do the request + :param authed_user: user ID who do the request :request body: { "name": "name of the subject", "description": "description of the subject (optional)", @@ -120,13 +138,24 @@ class Subjects(Resource): } :internal_api: set_subject """ - data = PolicyManager.update_subject(user_id=user_id, perimeter_id=perimeter_id, - value=request.json) + # data = {"policy_id": uuid, "perimeter_id": perimeter_id} + data = driver.PolicyManager.update_subject(moon_user_id=authed_user, + perimeter_id=perimeter_id, + value=body) + + slaves = slave_class.Slaves.get().get("slaves") + invalidate_perimeter_in_slaves(slaves=slaves, policy_id=None, perimeter_id=perimeter_id, + type="subject", data=data[perimeter_id], is_delete=False) + return {"subjects": data} - @validate_input("delete", kwargs_state=[False, True, False]) - @check_auth - def delete(self, uuid=None, perimeter_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.delete("/subjects/", requires=api_key_authentication) + @hug.delete("/subjects/{perimeter_id}", requires=api_key_authentication) + @hug.delete("/policies/{uuid}/subjects/{perimeter_id}", requires=api_key_authentication) + def delete(uuid: hug.types.text = None, perimeter_id: hug.types.text = None, + authed_user: hug.directives.user = None): """Delete a subject for a given policy :param uuid: uuid of the policy (mandatory if perimeter_id is not set) @@ -144,29 +173,30 @@ class Subjects(Resource): :internal_api: delete_subject """ - data = PolicyManager.delete_subject( - user_id=user_id, policy_id=uuid, perimeter_id=perimeter_id) + # data = {"policy_id": uuid, "perimeter_id": perimeter_id} + data = driver.PolicyManager.delete_subject( + moon_user_id=authed_user, policy_id=uuid, perimeter_id=perimeter_id) + + slaves = slave_class.Slaves.get().get("slaves") + invalidate_perimeter_in_slaves(slaves=slaves, policy_id=uuid, perimeter_id=perimeter_id, + type="subject" ) return {"result": True} -class Objects(Resource): +class Objects(object): """ Endpoint for objects requests """ - __urls__ = ( - "/objects", - "/objects/", - "/objects/", - "/policies//objects", - "/policies//objects/", - "/policies//objects/", - ) - - @validate_input("get", kwargs_state=[False, False, False]) - @check_auth - def get(self, uuid=None, perimeter_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.get("/objects/", requires=api_key_authentication) + @hug.get("/objects/{perimeter_id}", requires=api_key_authentication) + @hug.get("/policies/{uuid}/objects/", requires=api_key_authentication) + @hug.get("/policies/{uuid}/objects/{perimeter_id}", requires=api_key_authentication) + def get(uuid: hug.types.text = None, perimeter_id: hug.types.text = None, + authed_user: hug.directives.user = None): """Retrieve all objects or a specific one if perimeter_id is given for a given policy @@ -182,17 +212,22 @@ class Objects(Resource): :internal_api: get_objects """ - data = PolicyManager.get_objects( - user_id=user_id, - policy_id=uuid, - perimeter_id=perimeter_id - ) + data = driver.PolicyManager.get_objects(moon_user_id=authed_user, + policy_id=uuid, + perimeter_id=perimeter_id + ) return {"objects": data} - @validate_input("post", body_state={"name": True}) - @check_auth - def post(self, uuid=None, perimeter_id=None, user_id=None): + # + @staticmethod + @hug.local() + @hug.post("/newobject", requires=api_key_authentication) + @hug.post("/objects/{perimeter_id}", requires=api_key_authentication) + @hug.post("/policies/{uuid}/objects/", requires=api_key_authentication) + @hug.post("/policies/{uuid}/objects/{perimeter_id}", requires=api_key_authentication) + def post(body: validate_input("name"), uuid: hug.types.text = None, perimeter_id: + hug.types.text = None, authed_user: hug.directives.user = None): """Create or update a object. :param uuid: uuid of the policy @@ -210,15 +245,16 @@ class Objects(Resource): } :internal_api: set_object """ - data = PolicyManager.add_object( - user_id=user_id, policy_id=uuid, - perimeter_id=perimeter_id, value=request.json) + data = driver.PolicyManager.add_object(moon_user_id=authed_user, + policy_id=uuid, + perimeter_id=perimeter_id, value=body) return {"objects": data} - @validate_input("patch", kwargs_state=[False, True, False]) - @check_auth - def patch(self, uuid=None, perimeter_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.patch("/objects/{perimeter_id}", requires=api_key_authentication) + def patch(body, perimeter_id: hug.types.text = None, authed_user: hug.directives.user = None): """Create or update a object. :param uuid: uuid of the policy @@ -236,14 +272,23 @@ class Objects(Resource): } :internal_api: set_object """ - data = PolicyManager.update_object(user_id=user_id, perimeter_id=perimeter_id, - value=request.json) + data = driver.PolicyManager.update_object(moon_user_id=authed_user, + perimeter_id=perimeter_id, + value=body) + + slaves = slave_class.Slaves.get().get("slaves") + invalidate_perimeter_in_slaves(slaves=slaves, policy_id=None, perimeter_id=perimeter_id, + type="object", data=data[perimeter_id], is_delete=False) return {"objects": data} - @validate_input("delete", kwargs_state=[False, True, False]) - @check_auth - def delete(self, uuid=None, perimeter_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.delete("/objects/", requires=api_key_authentication) + @hug.delete("/objects/{perimeter_id}", requires=api_key_authentication) + @hug.delete("/policies/{uuid}/objects/{perimeter_id}", requires=api_key_authentication) + def delete(uuid: hug.types.text = None, perimeter_id: hug.types.text = None, authed_user: + hug.directives.user = None): """Delete a object for a given policy :param uuid: uuid of the policy (mandatory if perimeter_id is not set) @@ -258,29 +303,29 @@ class Objects(Resource): :internal_api: delete_object """ - data = PolicyManager.delete_object( - user_id=user_id, policy_id=uuid, perimeter_id=perimeter_id) + data = driver.PolicyManager.delete_object( + moon_user_id=authed_user, policy_id=uuid, perimeter_id=perimeter_id) + + slaves = slave_class.Slaves.get().get("slaves") + invalidate_perimeter_in_slaves(slaves=slaves, policy_id=uuid, perimeter_id=perimeter_id, + type="object") return {"result": True} -class Actions(Resource): +class Actions(object): """ Endpoint for actions requests """ - __urls__ = ( - "/actions", - "/actions/", - "/actions/", - "/policies//actions", - "/policies//actions/", - "/policies//actions/", - ) - - @validate_input("get", kwargs_state=[False, False, False]) - @check_auth - def get(self, uuid=None, perimeter_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.get("/actions/", requires=api_key_authentication) + @hug.get("/actions/{perimeter_id}", requires=api_key_authentication) + @hug.get("/policies/{uuid}/actions/", requires=api_key_authentication) + @hug.get("/policies/{uuid}/actions/{perimeter_id}", requires=api_key_authentication) + def get(uuid: hug.types.text = None, perimeter_id: hug.types.text = None, + authed_user: hug.directives.user = None): """Retrieve all actions or a specific one if perimeter_id is given for a given policy @@ -296,14 +341,19 @@ class Actions(Resource): :internal_api: get_actions """ - data = PolicyManager.get_actions( - user_id=user_id, policy_id=uuid, perimeter_id=perimeter_id) + data = driver.PolicyManager.get_actions( + moon_user_id=authed_user, policy_id=uuid, perimeter_id=perimeter_id) return {"actions": data} - @validate_input("post", body_state={"name": True}) - @check_auth - def post(self, uuid=None, perimeter_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.post("/newaction", requires=api_key_authentication) + @hug.post("/actions/{perimeter_id}", requires=api_key_authentication) + @hug.post("/policies/{uuid}/actions/", requires=api_key_authentication) + @hug.post("/policies/{uuid}/actions/{perimeter_id}", requires=api_key_authentication) + def post(body: validate_input("name"), uuid: hug.types.text = None, perimeter_id: + hug.types.text = None, authed_user: hug.directives.user = None): """Create or update a action. :param uuid: uuid of the policy @@ -321,15 +371,15 @@ class Actions(Resource): } :internal_api: set_action """ - data = PolicyManager.add_action( - user_id=user_id, policy_id=uuid, - perimeter_id=perimeter_id, value=request.json) + data = driver.PolicyManager.add_action( + moon_user_id=authed_user, policy_id=uuid, perimeter_id=perimeter_id, value=body) return {"actions": data} - @validate_input("patch", kwargs_state=[False, True, False]) - @check_auth - def patch(self, uuid=None, perimeter_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.patch("/actions/{perimeter_id}", requires=api_key_authentication) + def patch(body, perimeter_id: hug.types.text = None, authed_user: hug.directives.user = None): """Create or update a action. :param uuid: uuid of the policy @@ -347,14 +397,22 @@ class Actions(Resource): } :internal_api: set_action """ - data = PolicyManager.update_action(user_id=user_id, perimeter_id=perimeter_id, - value=request.json) + data = driver.PolicyManager.update_action( + moon_user_id=authed_user, perimeter_id=perimeter_id, value=body) + + slaves = slave_class.Slaves.get().get("slaves") + invalidate_perimeter_in_slaves(slaves=slaves, policy_id=None, perimeter_id=perimeter_id, + type="action", data=data[perimeter_id], is_delete=False) return {"actions": data} - @validate_input("delete", kwargs_state=[False, True, False]) - @check_auth - def delete(self, uuid=None, perimeter_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.delete("/actions/", requires=api_key_authentication) + @hug.delete("/actions/{perimeter_id}", requires=api_key_authentication) + @hug.delete("/policies/{uuid}/actions/{perimeter_id}", requires=api_key_authentication) + def delete(uuid: hug.types.text = None, perimeter_id: hug.types.text = None, authed_user: + hug.directives.user = None): """Delete a action for a given policy :param uuid: uuid of the policy (mandatory if perimeter_id is not set) @@ -369,7 +427,559 @@ class Actions(Resource): :internal_api: delete_action """ - data = PolicyManager.delete_action( - user_id=user_id, policy_id=uuid, perimeter_id=perimeter_id) + data = driver.PolicyManager.delete_action( + moon_user_id=authed_user, policy_id=uuid, perimeter_id=perimeter_id) + + slaves = slave_class.Slaves.get().get("slaves") + invalidate_perimeter_in_slaves(slaves=slaves, policy_id=uuid, perimeter_id=perimeter_id, + type="action") return {"result": True} + + +SubjectsAPI = hug.API(name='subjects', doc=Subjects.__doc__) + + +def filter_dict(data, filter_args): + for item in data: + output = [] + for arg in filter_args: + if arg.strip() in data.get(item): + output.append(str(data.get(item).get(arg.strip()))) + yield output + + +@hug.object(name='subjects', version='1.0.0', api=SubjectsAPI) +class SubjectsCLI(object): + """An example of command like calls via an Object""" + + @staticmethod + @hug.object.cli + def list(name_or_id="", filter=None, human: bool = False): + """ + List subjects from the database + :return: JSON status output + """ + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _subjects_req = requests.get("{}/subjects".format(db_conf.get("url")), + headers={"x-api-key": manager_api_key} + ) + if _subjects_req.status_code == 200: + if name_or_id: + _subjects = None + if name_or_id in _subjects_req.json().get("subjects"): + _subjects = _subjects_req.json().get("subjects").get(name_or_id) + else: + for _subjects_key in _subjects_req.json().get("subjects"): + _name = _subjects_req.json().get("subjects").get(_subjects_key).get("name") + if _name == name_or_id: + _subjects = _subjects_req.json().get("subjects").get(_subjects_key) + name_or_id = _subjects_key + break + if not _subjects: + raise Exception("Cannot find Subjects with name or ID {}".format(name_or_id)) + else: + if human: + result = {"subjects": {name_or_id: _subjects}} + else: + result = {"subjects": [{name_or_id: _subjects}]} + elif filter: + return "\n".join( + ["\t".join(_t) for _t in filter_dict(_subjects_req.json().get("subjects"), + filter.split(","))] + ) + else: + result = _subjects_req.json() + + if human: + return SubjectsCLI.human_display(result) + else: + return result + LOGGER.error('Cannot list Subjects {}'.format(_subjects_req.status_code)) + + @staticmethod + @hug.object.cli + def add(name, description="", policy_name_or_id="", human: bool = False): + """ + Add subject in the database + :return: JSON status output + """ + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _url = "{}/newsubject".format(db_conf.get("url")) + if policy_name_or_id: + policy_id = list(policy.PoliciesCLI.list(policy_name_or_id).get("policies").keys())[0] + _url = "{}/policies/{}/subjects".format(db_conf.get("url"), policy_id) + _subjects = requests.post( + _url, + json={ + "name": name, + "description": description, + }, + headers={ + "x-api-key": manager_api_key, + "Content-Type": "application/json" + } + ) + if _subjects.status_code == 200: + LOGGER.warning('Create {}'.format(_subjects.content)) + if human: + return SubjectsCLI.human_display(_subjects.json()) + else: + return _subjects.json() + LOGGER.error('Cannot create {}'.format(name, _subjects.content[:40])) + + @staticmethod + @hug.object.cli + def delete(name_or_id, policy_name_or_id): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _subjects = SubjectsCLI.list() + for _perimeter_id, _perimeter_value in _subjects.get("subjects").items(): + if _perimeter_value.get("name") == name_or_id: + _url = "{}/subjects/{}".format(db_conf.get("url"), _perimeter_id) + if policy_name_or_id: + policy_id = list( + policy.PoliciesCLI.list(policy_name_or_id).get("policies").keys())[0] + _url = "{}/policies/{}/subjects/{}".format(db_conf.get("url"), policy_id, + _perimeter_id) + req = requests.delete( + _url, + headers={"x-api-key": manager_api_key} + ) + break + else: + LOGGER.error("Cannot find Subjects with name {}".format(name_or_id)) + return False + if req.status_code == 200: + LOGGER.warning('Deleted {}'.format(name_or_id)) + return True + LOGGER.error("Cannot delete Subjects with name {}".format(name_or_id)) + return False + + @staticmethod + @hug.object.cli + def update(name_or_id, description=None, extra=None, email=None, new_name=None): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _subjects = SubjectsCLI.list() + for _perimeter_id, _perimeter_value in _subjects.get("subjects").items(): + if _perimeter_id == name_or_id or _perimeter_value.get("name") == name_or_id: + updated_name = _perimeter_value.get("name") + updated_id = _perimeter_value.get("id") + updated_description = _perimeter_value.get("description") + updated_extra = _perimeter_value.get("extra") + updated_email = _perimeter_value.get("email") + _url = "{}/subjects/{}".format(db_conf.get("url"), _perimeter_id) + + if new_name is not None: + updated_name = new_name + if description is not None: + updated_description = description + if extra is not None: + if extra == "": + updated_extra = {} + else: + updated_extra.update(dict((k, v) for k, v in (item.split(':') for item in extra.split(',')))) + if email is not None: + updated_email = email + + req = requests.patch( + _url, + json={ + "name": updated_name, + "id": updated_id, + "description": updated_description, + "extra": updated_extra, + "email": updated_email + }, + headers={"x-api-key": manager_api_key} + ) + break + else: + LOGGER.error("Cannot find Subjects with name {}".format(name_or_id)) + return False + if req.status_code == 200: + LOGGER.warning('Updated {}'.format(name_or_id)) + return True + LOGGER.error("Cannot update Subjects with name {}".format(name_or_id)) + return False + + @staticmethod + def human_display(subjects_json): + human_result = "Subjects" + for subject in subjects_json.get("subjects"): + human_result += "\n" + subjects_json.get("subjects").get(subject).get("name") + " : \n" + human_result += "\tname : " + subjects_json.get("subjects").get(subject).get("name") + "\n" + human_result += "\tid : " + subjects_json.get("subjects").get(subject).get("id") + "\n" + human_result += "\tdescription : " + subjects_json.get("subjects").get(subject).get("description") + "\n" + human_result += "\temail : " + subjects_json.get("subjects").get(subject).get("email") + "\n" + human_result += "\textra : \n" + for extra in subjects_json.get("subjects").get(subject).get("extra"): + human_result += "\t\t : " + extra + "\n" + human_result += "\tpolicies : \n" + for policy in subjects_json.get("subjects").get(subject).get("policy_list"): + human_result += "\t\tid : " + policy + "\n" + return human_result + + +ObjectsAPI = hug.API(name='objects', doc=Objects.__doc__) + + +@hug.object(name='objects', version='1.0.0', api=ObjectsAPI) +class ObjectsCLI(object): + """An example of command like calls via an Object""" + + @staticmethod + @hug.object.cli + def list(name_or_id="", filter=None, human: bool = False): + """ + List objects from the database + :return: JSON status output + """ + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _objects_req = requests.get("{}/objects".format(db_conf.get("url")), + headers={"x-api-key": manager_api_key} + ) + if _objects_req.status_code == 200: + if name_or_id: + _objects = None + if name_or_id in _objects_req.json().get("objects"): + _objects = _objects_req.json().get("objects").get(name_or_id) + else: + for _objects_key in _objects_req.json().get("objects"): + _name = _objects_req.json().get("objects").get(_objects_key).get("name") + if _name == name_or_id: + _objects = _objects_req.json().get("objects").get(_objects_key) + name_or_id = _objects_key + break + if not _objects: + raise Exception("Cannot find Objects with name or ID {}".format(name_or_id)) + else: + if human: + result = {"objects": {name_or_id: _objects}} + else: + result = {"objects": [{name_or_id: _objects}]} + elif filter: + return "\n".join( + ["\t".join(_t) for _t in filter_dict(_objects_req.json().get("objects"), + filter.split(","))] + ) + else: + result =_objects_req.json() + + if human: + return ObjectsCLI.human_display(result) + else: + return result + LOGGER.error('Cannot list Objects {}'.format(_objects_req.status_code)) + + @staticmethod + @hug.object.cli + def add(name, description="", policy_name_or_id="", human: bool = False): + """ + Add object in the database + :return: JSON status output + """ + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _url = "{}/newobject".format(db_conf.get("url")) + if policy_name_or_id: + policy_id = list(policy.PoliciesCLI.list(policy_name_or_id).get("policies").keys())[0] + _url = "{}/policies/{}/objects".format(db_conf.get("url"), policy_id) + _objects = requests.post( + _url, + json={ + "name": name, + "description": description, + }, + headers={ + "x-api-key": manager_api_key, + "Content-Type": "application/json" + } + ) + if _objects.status_code == 200: + LOGGER.warning('Create {}'.format(_objects.content)) + if human: + return ObjectsCLI.human_display(_objects.json()) + else: + return _objects.json() + LOGGER.error('Cannot create {}'.format(name, _objects.content[:40])) + + @staticmethod + @hug.object.cli + def update(name_or_id, description=None, extra=None, email=None, new_name=None): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _objects = ObjectsCLI.list() + for _perimeter_id, _perimeter_value in _objects.get("objects").items(): + if _perimeter_id == name_or_id or _perimeter_value.get("name") == name_or_id: + updated_name = _perimeter_value.get("name") + updated_id = _perimeter_value.get("id") + updated_description = _perimeter_value.get("description") + updated_extra = _perimeter_value.get("extra") + updated_email = _perimeter_value.get("email") + _url = "{}/objects/{}".format(db_conf.get("url"), _perimeter_id) + + if new_name is not None: + updated_name = new_name + if description is not None: + updated_description = description + if extra is not None: + if extra == "": + updated_extra = {} + else: + updated_extra.update(dict((k, v) for k, v in (item.split(':') for item in extra.split(',')))) + if email is not None: + updated_email = email + + req = requests.patch( + _url, + json={ + "name": updated_name, + "id": updated_id, + "description": updated_description, + "extra": updated_extra, + "email": updated_email + }, + headers={"x-api-key": manager_api_key} + ) + break + else: + LOGGER.error("Cannot find object with name {}".format(name_or_id)) + return False + if req.status_code == 200: + LOGGER.warning('Updated {}'.format(name_or_id)) + return True + LOGGER.error("Cannot update object with name {}".format(name_or_id)) + return False + + @staticmethod + @hug.object.cli + def delete(name_or_id, policy_name_or_id): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _objects = ObjectsCLI.list() + for _perimeter_id, _perimeter_value in _objects.get("objects").items(): + if _perimeter_value.get("name") == name_or_id: + _url = "{}/objects/{}".format(db_conf.get("url"), _perimeter_id) + if policy_name_or_id: + policy_id = list( + policy.PoliciesCLI.list(policy_name_or_id).get("policies").keys())[0] + _url = "{}/policies/{}/objects/{}".format(db_conf.get("url"), policy_id, + _perimeter_id) + req = requests.delete( + _url, + headers={"x-api-key": manager_api_key} + ) + break + else: + LOGGER.error("Cannot find Objects with name {}".format(name_or_id)) + return False + if req.status_code == 200: + LOGGER.warning('Deleted {}'.format(name_or_id)) + return True + LOGGER.error("Cannot delete Objects with name {}".format(name_or_id)) + return False + + @staticmethod + def human_display(objects_json): + human_result = "Objects" + for object in objects_json.get("objects"): + human_result += "\n" + objects_json.get("objects").get(object).get("name") + " : \n" + human_result += "\tname : " + objects_json.get("objects").get(object).get("name") + "\n" + human_result += "\tid : " + object + "\n" + human_result += "\tdescription : " + objects_json.get("objects").get(object).get("description") + "\n" + human_result += "\temail : " + objects_json.get("objects").get(object).get("email") + "\n" + human_result += "\textra : \n" + if objects_json.get("objects").get(object).get("extra").get("component") != None: + human_result += "\t\tcomponent : " + objects_json.get("objects").get(object).get("extra").get( + "component") + "\n" + else: + human_result + "\t\t\n" + human_result += "\tpolicies : \n" + for policy in objects_json.get("objects").get(object).get("policy_list"): + human_result += "\t\tid : " + policy + "\n" + return human_result + +ActionsAPI = hug.API(name='actions', doc=Actions.__doc__) + + +@hug.object(name='actions', version='1.0.0', api=ActionsAPI) +class ActionsCLI(object): + """An example of command like calls via an Object""" + + @staticmethod + @hug.object.cli + def list(name_or_id="", filter="", human: bool = False): + """ + List actions from the database + :return: JSON status output + """ + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _actions_req = requests.get("{}/actions".format(db_conf.get("url")), + headers={"x-api-key": manager_api_key} + ) + if _actions_req.status_code == 200: + if name_or_id: + _actions = None + if name_or_id in _actions_req.json().get("actions"): + _actions = _actions_req.json().get("actions").get(name_or_id) + else: + for _actions_key in _actions_req.json().get("actions"): + _name = _actions_req.json().get("actions").get(_actions_key).get("name") + if _name == name_or_id: + _actions = _actions_req.json().get("actions").get(_actions_key) + name_or_id = _actions_key + break + if not _actions: + raise Exception("Cannot find Actions with name or ID {}".format(name_or_id)) + else: + if human: + result = {"actions": {name_or_id: _actions}} + else: + result = {"actions": [{name_or_id: _actions}]} + elif filter: + return "\n".join( + ["\t".join(_t) for _t in filter_dict(_actions_req.json().get("actions"), + filter.split(","))] + ) + else: + result = _actions_req.json() + + if human: + return ActionsCLI.human_display(result) + else: + return result + + LOGGER.error('Cannot list Actions {}'.format(_actions_req.status_code)) + + @staticmethod + @hug.object.cli + def add(name, description="", policy_name_or_id="", human: bool = False): + """ + Add action in the database + :return: JSON status output + """ + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _url = "{}/newaction".format(db_conf.get("url")) + if policy_name_or_id: + policy_id = list(policy.PoliciesCLI.list(policy_name_or_id).get("policies").keys())[0] + _url = "{}/policies/{}/actions".format(db_conf.get("url"), policy_id) + _actions = requests.post( + _url, + json={ + "name": name, + "description": description, + }, + headers={ + "x-api-key": manager_api_key, + "Content-Type": "application/json" + } + ) + if _actions.status_code == 200: + LOGGER.warning('Create {}'.format(_actions.content)) + if human: + return ActionsCLI.human_display(_actions.json()) + else: + return _actions.json() + LOGGER.error('Cannot create {}'.format(name, _actions.content[:40])) + + @staticmethod + @hug.object.cli + def update(name_or_id, description=None, extra=None, email=None, new_name=None): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _actions = ActionsCLI.list() + for _perimeter_id, _perimeter_value in _actions.get("actions").items(): + if _perimeter_id == name_or_id or _perimeter_value.get("name") == name_or_id: + updated_name = _perimeter_value.get("name") + updated_id = _perimeter_value.get("id") + updated_description = _perimeter_value.get("description") + updated_extra = _perimeter_value.get("extra") + updated_email = _perimeter_value.get("email") + _url = "{}/actions/{}".format(db_conf.get("url"), _perimeter_id) + + if new_name is not None: + updated_name = new_name + if description is not None: + updated_description = description + if extra is not None: + if extra == "": + updated_extra = {} + else: + updated_extra.update(dict((k, v) for k, v in (item.split(':') for item in extra.split(',')))) + if email is not None: + updated_email = email + + req = requests.patch( + _url, + json={ + "name": updated_name, + "id": updated_id, + "description": updated_description, + "extra": updated_extra, + "email": updated_email + }, + headers={"x-api-key": manager_api_key} + ) + break + else: + LOGGER.error("Cannot find action with name {}".format(name_or_id)) + return False + if req.status_code == 200: + LOGGER.warning('Updated {}'.format(name_or_id)) + return True + LOGGER.error("Cannot update action with name {}".format(name_or_id)) + return False + + @staticmethod + @hug.object.cli + def delete(name_or_id, policy_name_or_id): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _actions = ActionsCLI.list() + for _perimeter_id, _perimeter_value in _actions.get("actions").items(): + if _perimeter_value.get("name") == name_or_id: + _url = "{}/actions/{}".format(db_conf.get("url"), _perimeter_id) + if policy_name_or_id: + policy_id = list( + policy.PoliciesCLI.list(policy_name_or_id).get("policies").keys())[0] + _url = "{}/policies/{}/actions/{}".format(db_conf.get("url"), policy_id, + _perimeter_id) + req = requests.delete( + _url, + headers={"x-api-key": manager_api_key} + ) + break + else: + LOGGER.error("Cannot find Actions with name {}".format(name_or_id)) + return False + if req.status_code == 200: + LOGGER.warning('Deleted {}'.format(name_or_id)) + return True + LOGGER.error("Cannot delete Actions with name {}".format(name_or_id)) + return False + + @staticmethod + def human_display(actions_json): + human_result = "Actions" + for action in actions_json.get("actions"): + human_result += "\n" + actions_json.get("actions").get(action).get("name") + " : \n" + human_result += "\tname : " + actions_json.get("actions").get(action).get("name") + "\n" + human_result += "\tid : " + actions_json.get("actions").get(action).get("id") + "\n" + human_result += "\tdescription : " + actions_json.get("actions").get(action).get("description") + "\n" + human_result += "\temail : " + actions_json.get("actions").get(action).get("email") + "\n" + human_result += "\textra : \n" + if actions_json.get("actions").get(action).get("extra").get("component") != None: + human_result += "\t\tcomponent : " + actions_json.get("actions").get(action).get("extra").get("component") + "\n" + else: + human_result + "\t\t\n" + human_result += "\tpolicies : \n" + for policy in actions_json.get("actions").get(action).get("policy_list"): + human_result += "\t\tid : " + policy + "\n" + return human_result diff --git a/moon_manager/moon_manager/api/policies.py b/moon_manager/moon_manager/api/policies.py deleted file mode 100644 index 3264e8e0..00000000 --- a/moon_manager/moon_manager/api/policies.py +++ /dev/null @@ -1,125 +0,0 @@ -# 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 -import logging -from python_moonutilities.security_functions import check_auth -from python_moondb.core import PolicyManager -from python_moonutilities.security_functions import validate_input - -__version__ = "4.3.2" - -logger = logging.getLogger("moon.manager.api." + __name__) - - -class Policies(Resource): - """ - Endpoint for policy requests - """ - - __urls__ = ( - "/policies", - "/policies/", - "/policies/", - "/policies//", - ) - - @validate_input("get", kwargs_state=[False, False]) - @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": "name of the policy (mandatory)", - "model_id": "ID of the model linked to this policy", - "genre": "authz of admin (optional, default to authz)", - "description": "description of the policy (optional)", - } - } - :internal_api: get_policies - """ - - data = PolicyManager.get_policies(user_id=user_id, policy_id=uuid) - - return {"policies": data} - - @validate_input("post", body_state={"name": True, "model_id": False}) - @check_auth - def post(self, uuid=None, user_id=None): - """Create policy. - - :param uuid: uuid of the policy (not used here if a new policy is created) - :param user_id: user ID who do the request - :request body: { - "name": "name of the policy (mandatory)", - "model_id": "ID of the model linked to this policy", - "genre": "authz of admin (optional, default to authz)", - "description": "description of the policy (optional)", - } - :return: { - "policy_id1": { - "name": "name of the policy (mandatory)", - "model_id": "ID of the model linked to this policy", - "genre": "authz of admin (optional, default to authz)", - "description": "description of the policy (optional)", - } - } - :internal_api: add_policy - """ - - data = PolicyManager.add_policy( - user_id=user_id, policy_id=uuid, value=request.json) - - return {"policies": data} - - @validate_input("delete", kwargs_state=[True, False]) - @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 (optional)" - } - :internal_api: delete_policy - """ - - data = PolicyManager.delete_policy(user_id=user_id, policy_id=uuid) - - return {"result": True} - - @validate_input("patch", kwargs_state=[True, False], - body_state={"name": True, "model_id": False}) - @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": "name of the policy (mandatory)", - "model_id": "ID of the model linked to this policy", - "genre": "authz of admin (optional, default to authz)", - "description": "description of the policy (optional)", - } - } - :internal_api: update_policy - """ - - data = PolicyManager.update_policy( - user_id=user_id, policy_id=uuid, value=request.json) - - return {"policies": data} diff --git a/moon_manager/moon_manager/api/policy.py b/moon_manager/moon_manager/api/policy.py new file mode 100644 index 00000000..727fceb6 --- /dev/null +++ b/moon_manager/moon_manager/api/policy.py @@ -0,0 +1,293 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + +""" +Policies are instances of security models and implement security policies + +""" + +import hug +import logging +import requests +from moon_manager.api import ERROR_CODE +from moon_utilities.auth_functions import api_key_authentication, connect_from_env +from moon_manager import db_driver +from moon_utilities import exceptions +from moon_utilities.security_functions import validate_input +from moon_utilities.invalided_functions import invalidate_policy_in_slaves +from moon_manager.api import slave as slave_class +from moon_manager.api import configuration + +LOGGER = logging.getLogger("moon.manager.api." + __name__) + + +class Policies(object): + """ + Endpoint for policy requests + """ + + @staticmethod + @hug.local() + @hug.get("/policies/", requires=api_key_authentication) + @hug.get("/policies/{uuid}", requires=api_key_authentication) + def get(uuid: hug.types.uuid = None, authed_user: hug.directives.user = None): + """Retrieve all policies + + :param uuid: uuid of the policy + :param authed_user: the name of the authenticated user + :return: { + "policy_id1": { + "name": "name of the policy (mandatory)", + "model_id": "ID of the model linked to this policy", + "genre": "authz of admin (optional, default to authz)", + "description": "description of the policy (optional)", + } + } + """ + if uuid: + uuid = str(uuid).replace("-", "") + data = db_driver.PolicyManager.get_policies(moon_user_id=authed_user, policy_id=uuid) + + return {"policies": data} + + @staticmethod + @hug.local() + @hug.post("/policies/", requires=api_key_authentication) + def post(body: validate_input("name"), response, authed_user: hug.directives.user = None): + """Create policy. + + :param body: preformed body from Hug + :param response: preformed response from Hug + :param authed_user: the name of the authenticated user + :request body: { + "name": "name of the policy (mandatory)", + "model_id": "ID of the model linked to this policy", + "genre": "authz of admin (optional, default to authz)", + "description": "description of the policy (optional)", + } + :return: { + "policy_id1": { + "name": "name of the policy (mandatory)", + "model_id": "ID of the model linked to this policy", + "genre": "authz of admin (optional, default to authz)", + "description": "description of the policy (optional)", + } + } + """ + data = db_driver.PolicyManager.add_policy( + moon_user_id=authed_user, policy_id=None, value=body) + + return {"policies": data} + + @staticmethod + @hug.local() + @hug.delete("/policies/{uuid}", requires=api_key_authentication) + def delete(uuid: hug.types.text, response=None, authed_user: hug.directives.user = None): + """Delete a policy + + :param uuid: uuid of the policy to delete + :param response: preformed response from Hug + :param authed_user: the name of the authenticated user + :return: { + "result": "True or False", + "message": "optional message (optional)" + } + """ + uuid = str(uuid).replace("-", "") + db_driver.PolicyManager.delete_policy( + moon_user_id=authed_user, policy_id=uuid) + slaves = slave_class.Slaves.get().get("slaves") + invalidate_policy_in_slaves(slaves=slaves, policy_id=uuid) + + return {"result": True} + + @staticmethod + @hug.local() + @hug.patch("/policies/{uuid}", requires=api_key_authentication) + def patch(uuid: hug.types.uuid, body: validate_input("name"), response, + authed_user: hug.directives.user = None): + """Update a policy + + :param uuid: uuid of the policy to update + :param body: preformed body from Hug + :param response: preformed response from Hug + :param authed_user: the name of the authenticated user + :return: { + "policy_id1": { + "name": "name of the policy (mandatory)", + "model_id": "ID of the model linked to this policy", + "genre": "authz of admin (optional, default to authz)", + "description": "description of the policy (optional)", + } + } + """ + + uuid = str(uuid).replace("-", "") + prev_data = db_driver.PolicyManager.get_policies(moon_user_id=authed_user, policy_id=uuid) + if not prev_data: + response.status = ERROR_CODE[400] + return {"message": "The policy is unknown."} + data = db_driver.PolicyManager.update_policy( + moon_user_id=authed_user, policy_id=uuid, value=body).get(uuid) + slaves = slave_class.Slaves.get().get("slaves") + invalidate_policy_in_slaves(slaves=slaves, policy_id=uuid, data=data, is_delete=False) + + return {"policies": db_driver.PolicyManager.get_policies(moon_user_id=authed_user, + policy_id=uuid)} + + +PoliciesAPI = hug.API(name='policies', doc=Policies.__doc__) + + +@hug.object(name='policies', version='1.0.0', api=PoliciesAPI) +class PoliciesCLI(object): + """An example of command like calls via an Object""" + + @staticmethod + @hug.object.cli + def list(name_or_id="", human: bool = False): + """ + List policies from the database + :return: JSON status output + """ + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _policies_req = requests.get("{}/policies".format(db_conf.get("url")), + headers={"x-api-key": manager_api_key} + ) + if _policies_req.status_code == 200: + if name_or_id: + _policies = None + if name_or_id in _policies_req.json().get("policies"): + _policies = _policies_req.json().get("policies").get(name_or_id) + else: + for _policies_key in _policies_req.json().get("policies"): + _name = _policies_req.json().get("policies").get(_policies_key).get("name") + if _name == name_or_id : + _policies = _policies_req.json().get("policies").get(_policies_key) + name_or_id = _policies_key + break + if not _policies: + raise Exception("Cannot find policy with name {}".format(name_or_id)) + else: + result = {"policies": {name_or_id: _policies}} + else: + result = _policies_req.json() + + if human: + return PoliciesCLI.human_display(result); + else: + return result + + @staticmethod + @hug.object.cli + def add(name, model, description="", genre="authz", human: bool = False): + """ + Add a new policy from the database + :return: JSON policies output + """ + from moon_manager.api import models + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _model = models.ModelsCLI.list(model).get("models")[0] + _policies = requests.post( + "{}/policies".format(db_conf.get("url")), + json={ + "name": name, + "model_id": list(_model.keys())[0], + "genre": genre, + "description": description, + }, + headers={ + "x-api-key": manager_api_key, + "Content-Type": "application/json" + } + ) + if _policies.status_code == 200: + LOGGER.warning('Create {}'.format(_policies.content)) + if human: + return PoliciesCLI.list('', True) + else: + return _policies.json() + LOGGER.error('Cannot create {} ({})'.format(name, _policies.content)) + + @staticmethod + @hug.object.cli + def delete(name_or_id): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _policies = PoliciesCLI.list() + for _id, _value in _policies.get("policies").items(): + if _id == name_or_id or _value.get("name") == name_or_id: + req = requests.delete( + "{}/policies/{}".format(db_conf.get("url"), _id), + headers={"x-api-key": manager_api_key} + ) + break + else: + LOGGER.error("Cannot find policy with name {}".format(name_or_id)) + return False + if req.status_code == 200: + LOGGER.warning('Deleted {}'.format(name_or_id)) + return True + LOGGER.error("Cannot delete policy with name {}".format(name_or_id)) + return False + + @staticmethod + @hug.object.cli + def update(name_or_id, model_id=None, description=None, genre=None): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _policies = PoliciesCLI.list() + for _id, _value in _policies.get("policies").items(): + if _id == name_or_id or _value.get("name") == name_or_id: + updated_model_id = _value.get("model_id") + updated_genre = _value.get("genre") + updated_description = _value.get("description") + + if model_id is not None: + updated_model_id = model_id + if description is not None: + updated_description = description + if genre is not None: + updated_genre = genre + + req = requests.patch( + "{}/policies/{}".format(db_conf.get("url"), _id), + json={ + "name": _value.get("name"), + "model_id": updated_model_id, + "genre": updated_genre, + "description": updated_description, + }, + headers={"x-api-key": manager_api_key} + ) + break + else: + LOGGER.error("Cannot find policy with name {}".format(name_or_id)) + return False + if req.status_code == 200: + LOGGER.warning('Updated {}'.format(name_or_id)) + return True + LOGGER.error("Cannot update policy with name {}".format(name_or_id)) + return False + + @staticmethod + def human_display(policies_json): + human_result = "Policies" + for policy in policies_json.get("policies"): + human_result += "\n" + policies_json.get("policies").get(policy).get("name") + " : \n" + human_result += "\tname : " + policies_json.get("policies").get(policy).get("name") + "\n" + human_result += "\tdescription : " + policies_json.get("policies").get(policy).get("description") + "\n" + human_result += "\tgenre : " + policies_json.get("policies").get(policy).get("genre") + "\n" + human_result += "\tmodel_id : " + policies_json.get("policies").get(policy).get("model_id") + "\n" + return human_result + diff --git a/moon_manager/moon_manager/api/rules.py b/moon_manager/moon_manager/api/rules.py index cbd39969..e984ee93 100644 --- a/moon_manager/moon_manager/api/rules.py +++ b/moon_manager/moon_manager/api/rules.py @@ -1,42 +1,63 @@ -# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors -# This software is distributed under the terms and conditions of the 'Apache-2.0' -# license which can be found in the file 'LICENSE' in this package distribution -# or at 'http://www.apache.org/licenses/LICENSE-2.0'. +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + """ -Rules (TODO) +Rules """ -from flask import request -from flask_restful import Resource +import hug +import json import logging -from python_moonutilities.security_functions import check_auth -from python_moondb.core import PolicyManager -from python_moonutilities.security_functions import validate_input +import requests +from moon_manager import db_driver as driver +from moon_utilities.security_functions import validate_input +from moon_utilities.invalided_functions import invalidate_rules_in_slaves +from moon_manager.api import configuration +from moon_utilities.auth_functions import init_db, api_key_authentication, connect_from_env +from moon_manager.api import slave as slave_class +from moon_manager.api import policy, meta_rules, data -__version__ = "4.3.2" +LOGGER = logging.getLogger("moon.manager.api." + __name__) -logger = logging.getLogger("moon.manager.api." + __name__) - -class Rules(Resource): +class Rules(object): """ Endpoint for rules requests """ - __urls__ = ("/policies//rules", - "/policies//rules/", - "/policies//rules/", - "/policies//rules//", - ) + @staticmethod + def _get_data_name(user, rule_data, policy_id): + global_data = driver.PolicyManager.get_subject_data(moon_user_id=user, policy_id=policy_id) +\ + driver.PolicyManager.get_object_data(moon_user_id=user, policy_id=policy_id) +\ + driver.PolicyManager.get_action_data(moon_user_id=user, policy_id=policy_id) + _rule_names = list() + for rule_id in rule_data: + for _data in global_data: + if rule_id in _data.get("data"): + _rule_names.append(_data.get("data")[rule_id].get("name")) + break + else: + _rule_names.append(rule_id) + return _rule_names - @validate_input("get", kwargs_state=[False, False, False]) - @check_auth - def get(self, uuid=None, rule_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.get("/policies/{uuid}/rules", requires=api_key_authentication) + @hug.get("/policies/{uuid}/rules/{rule_id}", requires=api_key_authentication) + def get(uuid: hug.types.text, rule_id: hug.types.text = None, moon_user_id: hug.directives.user = None): """Retrieve all rules or a specific one :param uuid: policy ID :param rule_id: rule ID - :param user_id: user ID who do the request + :param moon_user_id: user ID who do the request :return: { "rules": [ "policy_id": "policy_id1", @@ -50,27 +71,28 @@ class Rules(Resource): :internal_api: get_rules """ - data = PolicyManager.get_rules(user_id=user_id, - policy_id=uuid, - rule_id=rule_id) + data = driver.PolicyManager.get_rules(moon_user_id=moon_user_id, policy_id=uuid, + rule_id=rule_id) return {"rules": data} - @validate_input("post", kwargs_state=[True, False, False], - body_state={"meta_rule_id": True, "rule": True, "instructions": True}) - @check_auth - def post(self, uuid=None, rule_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.post("/policies/{uuid}/rules", requires=api_key_authentication) + def post(body: validate_input("meta_rule_id", "rule", "instructions"), + uuid: hug.types.text, + moon_user_id: hug.directives.user = None): """Add a rule to a meta rule :param uuid: policy ID - :param rule_id: rule ID (not used here) - :param user_id: user ID who do the request + :param body: body of the request + :param moon_user_id: user ID who do the request :request body: post = { "meta_rule_id": "meta_rule_id1", # mandatory "rule": ["subject_data_id2", "object_data_id2", "action_data_id2"], # mandatory - "instructions": ( # mandatory + "instructions": [ # mandatory {"decision": "grant"}, - ) + ] "enabled": True } :return: { @@ -80,18 +102,18 @@ class Rules(Resource): "rule": ["subject_data_id1", "object_data_id1", "action_data_id1"], - "instructions": ( + "instructions": [ {"decision": "grant"}, # "grant" to immediately exit, # "continue" to wait for the result of next policy # "deny" to deny the request - ) + ] } "rule_id2": { "rule": ["subject_data_id2", "object_data_id2", "action_data_id2"], - "instructions": ( + "instructions": [ { "update": { "operation": "add", @@ -102,34 +124,233 @@ class Rules(Resource): }, {"chain": {"name": "rbac"}} # chain with the policy named rbac - ) + ] } ] } :internal_api: add_rule """ - args = request.json - data = PolicyManager.add_rule(user_id=user_id, - policy_id=uuid, - meta_rule_id=args['meta_rule_id'], - value=args) + data = driver.PolicyManager.add_rule(moon_user_id=moon_user_id, policy_id=uuid, + meta_rule_id=body['meta_rule_id'], value=body) + + subject, object_, *action = Rules._get_data_name(moon_user_id, body['rule'], uuid) + instruction = body['instructions'][0]['decision'] + LOGGER.info(f"The user <{moon_user_id}> added the rule <{subject}, {object_}, {action}: {instruction}>") + + slaves = slave_class.Slaves.get().get("slaves") + invalidate_rules_in_slaves(slaves=slaves, policy_id=uuid, rule_id=None) return {"rules": data} - @validate_input("delete", kwargs_state=[True, True, False]) - @check_auth - def delete(self, uuid=None, rule_id=None, user_id=None): + @staticmethod + @hug.local() + @hug.patch("/policies/{uuid}/rules/{rule_id}", requires=api_key_authentication) + def patch(uuid: hug.types.text, rule_id: hug.types.text, body: validate_input("instructions"), + moon_user_id: hug.directives.user = None): + """Updates a rule (only its instructions) + + :param uuid: policy ID + :param body: body of the request + :param rule_id: the id of the rule to patch + :param moon_user_id: user ID who do the request + :request body: patch = { + "instructions": [ # mandatory + {"decision": "grant"}, + ] + } + :return: { + "rules": [ + "meta_rule_id": "meta_rule_id1", + "rule_id1": { + "rule": ["subject_data_id1", + "object_data_id1", + "action_data_id1"], + "instructions": [ + {"decision": "grant"}, + # "grant" to immediately exit, + # "continue" to wait for the result of next policy (not yet supported) + # "deny" to deny the request + ] + } + ] + } + :internal_api: update_rule + """ + prev_data = driver.PolicyManager.get_rules(moon_user_id=moon_user_id, policy_id=uuid, rule_id=rule_id)[rule_id] + subject, object_, *action = Rules._get_data_name(moon_user_id, prev_data['rule'], prev_data['policy_id']) + prev_inst = prev_data['instructions'][0]['decision'] + + data = driver.PolicyManager.update_rule(moon_user_id=moon_user_id, rule_id=rule_id, value=body) + + new_inst = data[rule_id]['instructions'][0]['decision'] + LOGGER.info(f"The user <{moon_user_id}> updated the rule <{subject}, {object_}, {action}> from {prev_inst} to {new_inst}") + + slaves = slave_class.Slaves.get().get("slaves") + invalidate_rules_in_slaves(slaves=slaves, policy_id=uuid, rule_id=rule_id) + + return {"rules": data} + + @staticmethod + @hug.local() + @hug.delete("/policies/{uuid}/rules/{rule_id}", requires=api_key_authentication) + def delete(uuid: hug.types.text, rule_id: hug.types.text, moon_user_id: hug.directives.user = None): """Delete one rule linked to a specific sub meta rule :param uuid: policy ID :param rule_id: rule ID - :param user_id: user ID who do the request + :param moon_user_id: user ID who do the request :return: { "result": true } :internal_api: delete_rule """ + prev_data = driver.PolicyManager.get_rules(moon_user_id=moon_user_id, policy_id=uuid, rule_id=rule_id)[rule_id] + subject, object_, *action = Rules._get_data_name(moon_user_id, prev_data['rule'], prev_data['policy_id']) + prev_inst = prev_data['instructions'][0]['decision'] + + driver.PolicyManager.delete_rule(moon_user_id=moon_user_id, policy_id=uuid, rule_id=rule_id) - data = PolicyManager.delete_rule( - user_id=user_id, policy_id=uuid, rule_id=rule_id) + LOGGER.info(f"The user <{moon_user_id}> deleted the rule <{subject}, {object_}, {action}: {prev_inst}>") + + slaves = slave_class.Slaves.get().get("slaves") + invalidate_rules_in_slaves(slaves=slaves, policy_id=uuid, rule_id=rule_id) return {"result": True} + + +RulesAPI = hug.API(name='rules', doc=Rules.__doc__) +db_conf = configuration.get_configuration(key='management') +init_db(db_conf.get("token_file")) + + +@hug.object(name='rules', version='1.0.0', api=RulesAPI) +class RulesCLI(object): + """An example of command like calls via an Object""" + + __global_data = None + + @staticmethod + def get_data_name(rule_data, policy_id): + if not RulesCLI.__global_data: + RulesCLI.__global_data = data.SubjectDataCLI.list(policy_id).get("subject_data") + \ + data.ObjectDataCLI.list(policy_id).get("object_data") + \ + data.ActionDataCLI.list(policy_id).get("action_data") + _rule_names = list() + for rule_id in rule_data: + for _data in RulesCLI.__global_data: + if rule_id in _data.get("data"): + _rule_names.append(_data.get("data")[rule_id].get("name")) + break + else: + _rule_names.append(rule_id) + return _rule_names + + @staticmethod + def get_data_id(rule_data, policy_id): + _global_data = data.SubjectDataCLI.list(policy_id).get("subject_data") + \ + data.ObjectDataCLI.list(policy_id).get("object_data") + \ + data.ActionDataCLI.list(policy_id).get("action_data") + _rule_ids = list() + for rule_id_or_name in rule_data: + _id = None + for _data in _global_data: + if rule_id_or_name in _data.get("data"): + _id = _data.get("data")[rule_id_or_name].get("name") + break + else: + for _data_key in _data.get("data"): + if _data.get("data")[_data_key]['name'] == rule_id_or_name: + _id = _data_key + break + if _id: + _rule_ids.append(_id) + break + else: + raise Exception("Cannot find data for {}".format(rule_id_or_name)) + return _rule_ids + + @staticmethod + @hug.object.cli + def list(policy_name_or_id, human: bool = False, instructions: bool = False): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + policy_id = list(policy.PoliciesCLI.list(policy_name_or_id).get("policies").keys())[0] + _rules = requests.get("{}/policies/{}/rules".format(db_conf.get("url"), policy_id), + headers={"x-api-key": manager_api_key} + ) + if _rules.status_code == 200: + if human: + for value in _rules.json().get("rules", {}).get("rules"): + if value.get("enabled"): + _rule_names = RulesCLI.get_data_name(value.get("rule"), policy_id) + output = value.get("id") + " | " + output += "{:30}".format(" ".join(_rule_names)) + if instructions: + output += " " + json.dumps(value.get("instructions")) + print(output) + else: + return _rules.json() + else: + raise Exception("Got a {} response ({})".format(_rules.status_code, _rules.text)) + + @staticmethod + @hug.object.cli + def add(policy_name_or_id, meta_rule_id_or_name, rule_items, + instructions: hug.types.one_of(("grant", "deny")) = None, enabled: bool = True): + if not instructions: + instructions = [{'decision': 'grant'}] + else: + instructions = [{'decision': instructions}] + rules_list = [] + for item in rule_items.split(","): + rules_list.append(item.strip()) + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + policy_id = list(policy.PoliciesCLI.list(policy_name_or_id).get("policies").keys())[0] + meta_rule_id = list(meta_rules.MetaRulesCLI.list(meta_rule_id_or_name). + get("meta_rules").keys())[0] + + _rules = requests.post("{}/policies/{}/rules".format(db_conf.get("url"), policy_id), + headers={"x-api-key": manager_api_key}, + json={ + "meta_rule_id": meta_rule_id, + "rule": RulesCLI.get_data_id(rules_list, policy_id), + "instructions": instructions, + "enabled": enabled + }) + if _rules.status_code == 200: + return _rules.json() + else: + raise Exception("Got a {} response ({})".format(_rules.status_code, _rules.text)) + + @staticmethod + @hug.object.cli + def update(policy_name_or_id, rule_id, instructions: hug.types.one_of(('grant', 'deny'))): + instructions = [{'decision': instructions}] + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + policy_id = list(policy.PoliciesCLI.list(policy_name_or_id).get("policies").keys())[0] + + _rules = requests.patch("{}/policies/{}/rules/{}".format(db_conf.get("url"), policy_id, rule_id), + headers={"x-api-key": manager_api_key}, + json={ + "instructions": instructions + }) + if _rules.status_code == 200: + return _rules.json() + else: + raise Exception("Got a {} response ({})".format(_rules.status_code, _rules.text)) + + @staticmethod + @hug.object.cli + def delete(policy_name_or_id, rule_id): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + policy_id = list(policy.PoliciesCLI.list(policy_name_or_id).get("policies").keys())[0] + + _rules = requests.delete("{}/policies/{}/rules/{}".format( + db_conf.get("url"), policy_id, rule_id), + headers={"x-api-key": manager_api_key}) + if _rules.status_code == 200: + return _rules.json() + else: + raise Exception("Got a {} response ({})".format(_rules.status_code, _rules.text)) diff --git a/moon_manager/moon_manager/api/slave.py b/moon_manager/moon_manager/api/slave.py new file mode 100644 index 00000000..a0201bdb --- /dev/null +++ b/moon_manager/moon_manager/api/slave.py @@ -0,0 +1,341 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + +""" +Slaves are endpoint for external connectors like OpenStack + +""" + +import logging +import hug +import os +import requests +from moon_manager.api import ERROR_CODE +from moon_manager import db_driver +from moon_manager import orchestration_driver +from moon_manager.api import configuration +from moon_utilities import exceptions +from moon_utilities.auth_functions import init_db, api_key_authentication, connect_from_env + +LOGGER = logging.getLogger("moon.manager.api." + __name__) + + +class Slaves(object): + """ + Endpoint for slave requests + """ + + @staticmethod + @hug.local() + @hug.get("/slaves/", requires=api_key_authentication) + @hug.get("/slaves/{uuid}", requires=api_key_authentication) + def get(uuid: hug.types.uuid = None, authed_user: hug.directives.user = None): + """Retrieve all slaves + + :param uuid: uuid of the pdp + :return: { + "slaves": { + "XXX": { + "name": "...", + "address": "..." + }, + "YYY": { + "name": "...", + "address": "..." + } + } + } + """ + if uuid: + uuid = str(uuid).replace("-", "") + data = db_driver.SlaveManager.get_slaves(moon_user_id=authed_user) + + return {"slaves": data} + + @staticmethod + @hug.local() + @hug.post("/slave/", requires=api_key_authentication) + def post(body, response, authed_user: hug.directives.user = None): + """Create a slave. + + :request body: { + "name": "name of the slave (mandatory)", + "address": "local_or_ssh://a.b.c.d", + "description": "description of the slave (optional)", + } + :return: { + "slaves": { + "XXX": { + "name": "...", + "address": "..." + }, + "YYY": { + "name": "...", + "address": "..." + } + } + } + """ + try: + # Create the DB item + data = db_driver.SlaveManager.add_slave( + moon_user_id=authed_user, slave_id=None, value=body) + + uuid = list(data.keys())[0] + # Build and run the process + new_data = orchestration_driver.SlaveManager.add_slave(moon_user_id=authed_user, + slave_id=uuid, data=data[uuid]) + + # Update the DB item with the information from the process (port, ...) + data = db_driver.SlaveManager.update_slave( + moon_user_id=authed_user, slave_id=uuid, value=new_data) + + except AttributeError as e: + response.status = ERROR_CODE[400] + LOGGER.exception(e) + except exceptions.MoonError as e: + response.status = ERROR_CODE[e.code] + return {"slaves": data} + + @staticmethod + @hug.local() + @hug.delete("/slave/{uuid}", requires=api_key_authentication) + def delete(uuid: hug.types.uuid, response=None, authed_user: hug.directives.user = None): + """Delete a slave + + :param uuid: uuid of the slave to delete + :param authed_user: authenticated user name + :param response: response initialized by Hug + :return: { + "result": "True or False", + "message": "optional message (optional)" + } + """ + uuid = str(uuid).replace("-", "") + try: + db_driver.SlaveManager.delete_slave( + moon_user_id=authed_user, slave_id=uuid) + + orchestration_driver.SlaveManager.delete_slave( + moon_user_id=authed_user, slave_id=uuid) + + except exceptions.MoonError as e: + response.status = ERROR_CODE[e.code] + return {"result": False, "description": str(e)} + except Exception as e: + LOGGER.exception(e) + return {"result": False, "description": str(e)} + return {"result": True} + + @staticmethod + @hug.local() + @hug.patch("/slave/{uuid}", requires=api_key_authentication) + def patch(uuid: hug.types.uuid, body, response, authed_user: hug.directives.user = None): + """Update a slave + + :param uuid: uuid of the slave to delete + :param body: body content of the Hug request + :param authed_user: authenticated user name + :param response: response initialized by Hug + :return: { + "pdp_id1": { + "name": "name of the PDP", + "address": "local_or_ssh://a.b.c.d", + "description": "description of the slave (optional)", + } + } + """ + + uuid = str(uuid).replace("-", "") + prev_data = db_driver.SlaveManager.get_slaves(moon_user_id=authed_user, slave_id=uuid) + if not prev_data: + response.status = ERROR_CODE[400] + return {"message": "The slave is unknown."} + try: + data = db_driver.SlaveManager.update_slave( + moon_user_id=authed_user, slave_id=uuid, value=body) + + + #TODO kill the server using orchestration_driver + + except AttributeError as e: + response.status = ERROR_CODE[400] + LOGGER.exception(e) + return {"message": str(e)} + except exceptions.MoonError as e: + response.status = ERROR_CODE[e.code] + return {"message": str(e)} + + orchestration_driver.SlaveManager.update_slave(moon_user_id=authed_user, slave_id=uuid, value=body) + + return { + "slaves": db_driver.SlaveManager.get_slaves(moon_user_id=authed_user, slave_id=uuid) + } + + +SlavesAPI = hug.API(name='slaves', doc=Slaves.__doc__) +db_conf = configuration.get_configuration(key='management') +init_db(db_conf.get("token_file")) + + +@hug.object(name='slaves', version='1.0.0', api=SlavesAPI) +class SlavesCLI(object): + """An example of command like calls via an Object""" + + @staticmethod + @hug.object.cli + def list(human: bool = False): + """ + List slaves from the database + :return: JSON status output + """ + db_conf = configuration.get_configuration(key='management') + + manager_api_key = connect_from_env() + _slaves = requests.get("{}/slaves".format(db_conf.get("url")), + headers={"x-api-key": manager_api_key} + ) + if _slaves.status_code == 200: + result = _slaves.json() + + if human: + return SlavesCLI.human_display(result) + else: + return result + LOGGER.error('Cannot list Slave Data {}'.format(_slaves.status_code)) + + @staticmethod + @hug.object.cli + def add(name='default', address="local", description="", grant_if_unknown_project: bool = False, human: bool = False): + """ + Add slave in the database + :return: JSON status output + """ + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _slaves = requests.post( + "{}/slave".format(db_conf.get("url")), + json={ + "name": name, + "address": address, + "description": description, + "grant_if_unknown_project": grant_if_unknown_project + }, + headers={ + "x-api-key": manager_api_key, + "Content-Type": "application/json" + } + ) + if _slaves.status_code == 200: + LOGGER.warning('Create {}'.format(_slaves.content)) + if human: + return SlavesCLI.human_display(_slaves.json()) + else: + return _slaves.json() + LOGGER.error('Cannot create {}'.format(name, _slaves.content)) + + @staticmethod + @hug.object.cli + def delete(name='default'): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _slaves = SlavesCLI.list() + for _slave_id, _slave_value in _slaves.get("slaves").items(): + if _slave_value.get("name") == name: + req = requests.delete( + "{}/slave/{}".format(db_conf.get("url"), _slave_id), + headers={"x-api-key": manager_api_key} + ) + break + else: + LOGGER.error("Cannot find slave with name {}".format(name)) + return False + if req.status_code == 200: + LOGGER.warning('Deleted {}'.format(name)) + return True + LOGGER.error("Cannot delete slave with name {}".format(name)) + return False + + @staticmethod + @hug.object.cli + def update(name='default', address=None, description=None, + grant_if_unknown_project: hug.types.one_of(("y", "n")) = None): + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _slaves = SlavesCLI.list() + + for _slave_id, _slave_value in _slaves.get("slaves").items(): + if _slave_value.get("name") == name: + address_updated = _slave_value.get("address") + description_updated = _slave_value.get("description") + grant_if_unknown_project_updated = _slave_value.get("grant_if_unknown_project") + + if address is not None: + address_updated = address + if description is not None: + description_updated = description + if grant_if_unknown_project is not None: + grant_if_unknown_project_updated = True if grant_if_unknown_project in ("y", "true", "1") else False + + req = requests.patch( + "{}/slave/{}".format(db_conf.get("url"), _slave_id), + json={ + "name": name, + "address": address_updated, + "description": description_updated, + "grant_if_unknown_project": grant_if_unknown_project_updated, + }, + headers={ + "x-api-key": manager_api_key, + "Content-Type": "application/json" + } + ) + if req.status_code == 200: + LOGGER.warning('Updated {}'.format(name)) + return True + else: + LOGGER.error('Cannot update {}'.format(name)) + return False + + LOGGER.error('Cannot find {}'.format(name)) + return False + + @staticmethod + def human_display(slaves_json): + human_result = "Slaves" + for slave in slaves_json.get("slaves"): + human_result += "\n" + slaves_json.get("slaves").get(slave).get("name") + " : \n" + human_result += "\tname : " + slaves_json.get("slaves").get(slave).get("name") + "\n" + human_result += "\tid : " + slave + "\n" + human_result += "\tdescription : " + slaves_json.get("slaves").get(slave).get("description") + "\n" + human_result += "\taddress : " + slaves_json.get("slaves").get(slave).get("address") + "\n" + human_result += "\tgrant_if_unknown_project : " + str(slaves_json.get("slaves").get(slave).get("grant_if_unknown_project")) + "\n" + human_result += "\tprocess : " + slaves_json.get("slaves").get(slave).get("process") + "\n" + human_result += "\tlog : " + slaves_json.get("slaves").get(slave).get("log") + "\n" + human_result += "\tapi_key : " + slaves_json.get("slaves").get(slave).get("api_key") + "\n" + human_result += SlavesCLI.human_display_extra(slaves_json.get("slaves").get(slave).get("extra")) + return human_result + + @staticmethod + def human_display_extra(extra_json): + human_result = "\textra" + human_result += "\n" + human_result += "\t\tdescription : " + extra_json.get("description") + "\n" + human_result += "\t\tstarttime : " + str(extra_json.get("starttime")) + "\n" + human_result += "\t\tport : " + str(extra_json.get("port")) + "\n" + human_result += "\t\tserver_ip : " + str(extra_json.get("server_ip")) + "\n" + human_result += "\t\tstatus : " + extra_json.get("status") + "\n" + human_result += "\t\tprocess : " + extra_json.get("process") + "\n" + human_result += "\t\tlog : " + extra_json.get("log") + "\n" + human_result += "\t\tapi_key : " + extra_json.get("api_key") + "\n" + return human_result + + diff --git a/moon_manager/moon_manager/api/slaves.py b/moon_manager/moon_manager/api/slaves.py deleted file mode 100644 index e2928de0..00000000 --- a/moon_manager/moon_manager/api/slaves.py +++ /dev/null @@ -1,111 +0,0 @@ -# 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 -from python_moonutilities.security_functions import check_auth - -from python_moonutilities import configuration -from python_moonutilities.security_functions import validate_input - -__version__ = "4.3.0" - -logger = logging.getLogger("moon.manager.api." + __name__) - - -class Slaves(Resource): - """ - Endpoint for pdp requests - """ - - __urls__ = ( - "/slaves", - "/slaves/", - "/slaves/", - "/slaves//", - ) - - def __init__(self, **kwargs): - conf = configuration.get_configuration("components/orchestrator") - self.orchestrator_hostname = conf["components/orchestrator"].get("hostname", - "orchestrator") - self.orchestrator_port = conf["components/orchestrator"].get("port", - 80) - - @validate_input("get", kwargs_state=[False, False]) - @check_auth - def get(self, uuid=None, user_id=None): - """Retrieve all slaves - - :param uuid: uuid of the slave - :param user_id: user ID who do the request - :return: { - "slaves": { - "XXX": { - "name": "...", - "installed": True - }, - "YYY": { - "name": "...", - "installed": False - } - } - } - """ - req = requests.get("http://{}:{}/slaves".format( - self.orchestrator_hostname, self.orchestrator_port - )) - return {"slaves": req.json().get("slaves", dict())} - - @validate_input("patch", kwargs_state=[False, False], - body_state={"op": True, "variable": True, "value": True}) - @check_auth - def patch(self, uuid=None, user_id=None): - """Update a slave - - :param uuid: uuid of the slave to update - :param user_id: user ID who do the request - :request body: { - "op": "replace", - "variable": "configured", - "value": True, - } - :return: 204 - :internal_api: add_pdp - """ - logger.info("Will made a request for {}".format(uuid)) - if request.json.get("op") == "replace" \ - and request.json.get("variable") == "configured" \ - and request.json.get("value"): - req = requests.post("http://{}:{}/pods".format( - self.orchestrator_hostname, self.orchestrator_port, - ), - json={"slave_name": uuid} - ) - if req.status_code != 200: - logger.warning("Get error from Orchestrator {} {}".format( - req.reason, req.status_code - )) - return "Orchestrator: " + str(req.reason), req.status_code - elif request.json.get("op") == "replace" \ - and request.json.get("variable") == "configured" \ - and not request.json.get("value"): - req = requests.delete("http://{}:{}/pods/{}".format( - self.orchestrator_hostname, self.orchestrator_port, uuid - )) - if req.status_code != 200: - logger.warning("Get error from Orchestrator {} {}".format( - req.reason, req.status_code - )) - return "Orchestrator: " + str(req.reason), req.status_code - else: - return "Malformed request", 400 - return {"slaves": req.json()} diff --git a/moon_manager/moon_manager/api/status.py b/moon_manager/moon_manager/api/status.py new file mode 100644 index 00000000..b299db49 --- /dev/null +++ b/moon_manager/moon_manager/api/status.py @@ -0,0 +1,127 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +"""Status API""" +import hug +import logging +import requests +from moon_utilities.auth_functions import api_key_authentication, connect_from_env +from moon_manager import orchestration_driver +from moon_manager.api import configuration +from datetime import datetime + +logger = logging.getLogger("moon.manager.api.status") + + +class Status(object): + """ + Endpoint for status requests + """ + @staticmethod + @hug.local() + @hug.get("/status/", requires=api_key_authentication) + def list_status(authed_user: hug.directives.user=None): + """ + List statuses + :return: JSON status output + """ + pipelines = orchestration_driver.PipelineManager.get_pipelines(moon_user_id=authed_user) + slaves = orchestration_driver.SlaveManager.get_slaves(moon_user_id=authed_user) + + config = configuration.search_config_file("moon.yaml") + log_file = config["logging"]["handlers"]["file"]["filename"] + + result = {"status": { + "manager": {"name": "manager", "status": "up", "log": log_file}, + }} + + for slave in slaves: + result["status"][slave] = slaves[slave] + for slave in pipelines: + result["status"][slave].update(pipelines[slave]) + + web_port = config["dashboard"]["port"] + url = ":".join(config["management"]["url"].split(":")[:-1]) + + result["status"]["web_GUI"] = {"name": "web GUI", "status": "down"} + try: + req = requests.get(f"{url}:{web_port}") + except requests.exceptions.ConnectionError: + req = None + + if req and req.status_code == 200: + result["status"]["web_GUI"].update({"status": "up", "port": web_port}) + + return result + + +StatusAPI = hug.API(name='status', doc=Status.__doc__) + + +@hug.cli("status") +def status(quiet: bool = False, human: bool = False): + """ + CLI Parameter to get status + :param quiet: + :param human: + :return: JSON status output + """ + db_conf = configuration.get_configuration(key='management') + manager_api_key = connect_from_env() + _status = requests.get("{}/status".format(db_conf.get("url")), + headers={"x-api-key": manager_api_key} + ) + + if _status.status_code == 200: + if human: + result = "Status" + statuses = _status.json()["status"].items() + for uuid, values in statuses: + # for humans, it's best to call the servers by their name + # instead of their uuid + result += f"\n{values['name']} :" + if quiet: + result += " OK" if values["status"] == "up" else " KO" + pipelines = values.get("pipelines") + if pipelines is not None: + for pipeline_uuid in pipelines: + result += f"\n\t{pipeline_uuid} :" + result += " OK" if pipelines[pipeline_uuid]["status"] == "up" else " KO" + else: + result += "\n" # not quiet mode : newline needed + result += f"\tuuid : {uuid}\n" + for k2, v2 in values.items(): + if k2 == "pipelines": + result += StatusCLI.format_pipelines_for_status(values["pipelines"]) + elif k2 == "starttime": + result += f"\t{k2} : {datetime.fromtimestamp(v2).strftime('%d/%m/%Y %H:%M:%S')}\n" + elif k2 != "name": + result += f"\t{k2} : {v2}\n" + return result + else: + return _status.json() + + +@hug.object(name='status', version='1.0.0', api=StatusAPI) +class StatusCLI(object): + """An example of command like calls via an Object""" + @staticmethod + def format_pipelines_for_status(pipelines): + result = "" + for pipeline in pipelines: + result += f"\n\t{pipeline} :\n" + for k,v in pipelines[pipeline].items(): + if k == "starttime": + result += f"\t\t{k} : {datetime.fromtimestamp(v).strftime('%d/%m/%Y %H:%M:%S')}\n" + else: + result += f"\t\t{k} : {v}\n" + return result diff --git a/moon_manager/moon_manager/api/users.py b/moon_manager/moon_manager/api/users.py new file mode 100644 index 00000000..9de78ff3 --- /dev/null +++ b/moon_manager/moon_manager/api/users.py @@ -0,0 +1,95 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + +""" +Users +""" +import hug +import logging +import getpass +from tinydb import Query +from moon_utilities.auth_functions import db, init_db, add_user, get_api_key, change_password + +LOGGER = logging.getLogger("moon.manager.api." + __name__) + +UsersAPI = hug.API('users') + + +@hug.object(name='users', version='1.0.0', api=UsersAPI) +class UsersCLI(object): + """An example of command like calls via an Object""" + + @staticmethod # nosec + @hug.object.cli + def add(username, password: hug.types.text = ""): + """ + Add a user to the database + """ + return add_user(username, password) + + @staticmethod # nosec + @hug.object.cli + def change_password(username, password: hug.types.text = "", new_password: hug.types.text = ""): + """ + Authenticate a username and password against our database + """ + result = change_password(username, password, new_password) + if not result: + return "Wrong password" + return result + + @staticmethod # nosec + @hug.object.cli + def key(username, password: hug.types.text = ""): + """ + Authenticate a username and password against our database + """ + if password == "": + password = getpass.getpass() + return get_api_key(username, password) + + @staticmethod + @hug.object.cli + def list(human: bool = False): + """ + List users from the database + """ + global db + if db is None: + init_db() + user_model = Query() + users = db.search(user_model.username.matches('.*')) + if human: + result = "Users" + if users: + for user in users: + result += f"\n{user['username']} : \n" + result += f"\tusername : {user['username']}\n" + result += f"\tapi_key : {user['api_key']}" + else: + result += f"\nNo user" + return result + else: + result = [] + if users: + for user in users: + result.append({ + 'username': user['username'], + 'api_key': user['api_key'] + }) + return {'users': result} + + + + + + + diff --git a/moon_manager/moon_manager/daemon.py b/moon_manager/moon_manager/daemon.py new file mode 100644 index 00000000..3b9f9c1e --- /dev/null +++ b/moon_manager/moon_manager/daemon.py @@ -0,0 +1,183 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + +""" +Plugin to request OpenStack infrastructure: +- Keystone +- Nova +""" + +import logging +import os +import atexit +import signal +import sys +import time +from moon_manager import pip_driver +from moon_manager import db_driver +from moon_manager.api import configuration +import hug.interface + +LOGGER = logging.getLogger("moon.manager.plugins.daemon") + +PLUGIN_TYPE = "daemon" + +db_driver.init() + + +class OpenstackDaemon(object): + + @staticmethod + def _update_subjects(): + k_users = [] + for manager in pip_driver.InformationManager["subjects"]: + k_users += list(manager.get_items().values())[0] + + user_ids = {user["id"].replace("-", ""): user for user in k_users} + + moon_subjects = db_driver.PolicyManager.get_subjects(moon_user_id=None, policy_id=None) + moon_subject_ids = moon_subjects.keys() + + for user_id in user_ids: + if user_id not in moon_subject_ids: + value = {"name": user_ids[user_id]["name"], "description": ""} + db_driver.PolicyManager.add_subject( + moon_user_id=None, policy_id=None, value=value, perimeter_id=user_id) + + @staticmethod + def _update_objects(): + k_objects = [] + for manager in pip_driver.InformationManager["objects"]: + k_objects += list(manager.get_items().values())[0] + + object_ids = {object_["id"].replace("-", ""): object_ for object_ in k_objects} + + moon_objects = db_driver.PolicyManager.get_objects(moon_user_id=None, policy_id=None) + moon_object_ids = moon_objects.keys() + + for object_id in object_ids: + if object_id not in moon_object_ids: + value = {"name": object_ids[object_id]["name"], "description": ""} + db_driver.PolicyManager.add_object( + moon_user_id=None, policy_id=None, value=value, perimeter_id=object_id) + + @staticmethod + def update(): + OpenstackDaemon._update_subjects() + OpenstackDaemon._update_objects() + + +def daemonize(pidfile, logfile): + try: + with open(pidfile, 'r') as pf: + pid = int(pf.read().strip()) + except IOError: + pid = None + + if pid: + message = "pidfile {0} already exist. " + \ + "Daemon already running?\n" + sys.stderr.write(message.format(pidfile)) + sys.exit(1) + + try: + pid = os.fork() + if pid > 0: + # exit first parent + sys.exit(0) + except OSError as err: + sys.stderr.write('fork #1 failed: {0}\n'.format(err)) + sys.exit(1) + + # decouple from parent environment + os.chdir('/') + os.setsid() + os.umask(0) + + # do second fork + try: + pid = os.fork() + if pid > 0: + # exit from second parent + sys.exit(0) + except OSError as err: + sys.stderr.write('fork #2 failed: {0}\n'.format(err)) + sys.exit(1) + + # redirect standard file descriptors + sys.stdout.flush() + sys.stderr.flush() + si = open(os.devnull, 'r') + so = open(logfile, 'a+') + se = open(logfile, 'a+') + + os.dup2(si.fileno(), sys.stdin.fileno()) + os.dup2(so.fileno(), sys.stdout.fileno()) + os.dup2(se.fileno(), sys.stderr.fileno()) + + # write pidfile + atexit.register(os.remove, pidfile) + + pid = str(os.getpid()) + with open(pidfile, 'w+') as f: + f.write(pid + '\n') + + +def kill_daemon(pidfile): + """Stop the daemon.""" + + # Get the pid from the pidfile + try: + with open(pidfile, 'r') as pf: + pid = int(pf.read().strip()) + except IOError: + pid = None + + if not pid: + message = "pidfile {0} does not exist. " + \ + "Daemon not running?\n" + sys.stderr.write(message.format(pidfile)) + return # not an error in a restart + + # Try killing the daemon process + try: + while 1: + os.kill(pid, signal.SIGTERM) + time.sleep(0.1) + except OSError as err: + e = str(err.args) + if e.find("No such process") > 0: + if os.path.exists(pidfile): + os.remove(pidfile) + else: + print(str(err.args)) + sys.exit(1) + +@hug.cli("start_daemon") +def run(): + """ start the auto-update service """ + daemon_conf = configuration.get_configuration("information").get("daemon") + daemonize(daemon_conf["pid_file"], daemon_conf["log_file"]) + + for category in pip_driver.InformationManager: + for manager in pip_driver.InformationManager[category]: + manager.set_auth() + + while True: + OpenstackDaemon.update() + time.sleep(1) + +@hug.cli("stop_daemon") +def stop(): + """ stop the auto-update service """ + pid_file = configuration.get_configuration("information").get("daemon").get("pid_file") + kill_daemon(pid_file) + diff --git a/moon_manager/moon_manager/db_driver.py b/moon_manager/moon_manager/db_driver.py new file mode 100644 index 00000000..89b20857 --- /dev/null +++ b/moon_manager/moon_manager/db_driver.py @@ -0,0 +1,256 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +import logging +from moon_manager.api import configuration +from moon_manager.api.db import model, policy, pdp, slave + +logger = logging.getLogger("moon.manager.db_driver") + + +ModelManager = None +PolicyManager = None +PDPManager = None +SlaveManager = None + + +class Driver: + + def __init__(self, driver_name, engine_name): + self.driver = configuration.get_db_driver() + self.driver = self.driver.Connector(engine_name) + + +class ModelDriver(Driver): + + def __init__(self, driver_name, engine_name): + super(ModelDriver, self).__init__(driver_name, engine_name) + + def update_model(self, model_id, value): + raise NotImplementedError() # pragma: no cover + + def delete_model(self, model_id): + raise NotImplementedError() # pragma: no cover + + def add_model(self, model_id=None, value=None): + raise NotImplementedError() # pragma: no cover + + def get_models(self, model_id=None): + raise NotImplementedError() # pragma: no cover + + def set_meta_rule(self, meta_rule_id, value): + raise NotImplementedError() # pragma: no cover + + def get_meta_rules(self, meta_rule_id=None): + raise NotImplementedError() # pragma: no cover + + def delete_meta_rule(self, meta_rule_id=None): + raise NotImplementedError() # pragma: no cover + + def get_subject_categories(self, category_id=None): + raise NotImplementedError() # pragma: no cover + + def add_subject_category(self, name, description): + raise NotImplementedError() # pragma: no cover + + def delete_subject_category(self, category_id): + raise NotImplementedError() # pragma: no cover + + def get_object_categories(self, category_id): + raise NotImplementedError() # pragma: no cover + + def add_object_category(self, category_id, value): + raise NotImplementedError() # pragma: no cover + + def delete_object_category(self, category_id): + raise NotImplementedError() # pragma: no cover + + def get_action_categories(self, category_id): + raise NotImplementedError() # pragma: no cover + + def add_action_category(self, category_id, value): + raise NotImplementedError() # pragma: no cover + + def delete_action_category(self, category_id): + raise NotImplementedError() # pragma: no cover + + +class PolicyDriver(Driver): + + def __init__(self, driver_name, engine_name): + super(PolicyDriver, self).__init__(driver_name, engine_name) + + def update_policy(self, policy_id, value): + raise NotImplementedError() # pragma: no cover + + def delete_policy(self, policy_id): + raise NotImplementedError() # pragma: no cover + + def add_policy(self, policy_id=None, value=None): + raise NotImplementedError() # pragma: no cover + + def get_policies(self, policy_id=None): + raise NotImplementedError() # pragma: no cover + + def get_subjects(self, policy_id, perimeter_id=None): + raise NotImplementedError() # pragma: no cover + + def set_subject(self, policy_id, perimeter_id=None, value=None): + raise NotImplementedError() # pragma: no cover + + def delete_subject(self, policy_id, perimeter_id): + raise NotImplementedError() # pragma: no cover + + def get_objects(self, policy_id, perimeter_id=None): + raise NotImplementedError() # pragma: no cover + + def set_object(self, policy_id, perimeter_id=None, value=None): + raise NotImplementedError() # pragma: no cover + + def delete_object(self, policy_id, perimeter_id): + raise NotImplementedError() # pragma: no cover + + def get_actions(self, policy_id, perimeter_id=None): + raise NotImplementedError() # pragma: no cover + + def set_action(self, policy_id, perimeter_id=None, value=None): + raise NotImplementedError() # pragma: no cover + + def delete_action(self, policy_id, perimeter_id): + raise NotImplementedError() # pragma: no cover + + def get_subject_data(self, policy_id, data_id=None, category_id=None): + raise NotImplementedError() # pragma: no cover + + def set_subject_data(self, policy_id, data_id=None, category_id=None, value=None): + raise NotImplementedError() # pragma: no cover + + def delete_subject_data(self, policy_id, data_id): + raise NotImplementedError() # pragma: no cover + + def get_object_data(self, policy_id, data_id=None, category_id=None): + raise NotImplementedError() # pragma: no cover + + def set_object_data(self, policy_id, data_id=None, category_id=None, value=None): + raise NotImplementedError() # pragma: no cover + + def delete_object_data(self, policy_id, data_id): + raise NotImplementedError() # pragma: no cover + + def get_action_data(self, policy_id, data_id=None, category_id=None): + raise NotImplementedError() # pragma: no cover + + def set_action_data(self, policy_id, data_id=None, category_id=None, value=None): + raise NotImplementedError() # pragma: no cover + + def delete_action_data(self, policy_id, data_id): + raise NotImplementedError() # pragma: no cover + + def get_subject_assignments(self, policy_id, subject_id=None, category_id=None): + raise NotImplementedError() # pragma: no cover + + def add_subject_assignment(self, policy_id, subject_id, category_id, data_id): + raise NotImplementedError() # pragma: no cover + + def delete_subject_assignment(self, policy_id, subject_id, category_id, data_id): + raise NotImplementedError() # pragma: no cover + + def get_object_assignments(self, policy_id, assignment_id=None): + raise NotImplementedError() # pragma: no cover + + def add_object_assignment(self, policy_id, subject_id, category_id, data_id): + raise NotImplementedError() # pragma: no cover + + def delete_object_assignment(self, policy_id, object_id, category_id, data_id): + raise NotImplementedError() # pragma: no cover + + def get_action_assignments(self, policy_id, assignment_id=None): + raise NotImplementedError() # pragma: no cover + + def add_action_assignment(self, policy_id, action_id, category_id, data_id): + raise NotImplementedError() # pragma: no cover + + def delete_action_assignment(self, policy_id, action_id, category_id, data_id): + raise NotImplementedError() # pragma: no cover + + def get_rules(self, policy_id, rule_id=None, meta_rule_id=None): + raise NotImplementedError() # pragma: no cover + + def add_rule(self, policy_id, meta_rule_id, value): + raise NotImplementedError() # pragma: no cover + + def update_rule(self, rule_id, value): + raise NotImplementedError() # pragma: no cover + + def delete_rule(self, policy_id, rule_id): + raise NotImplementedError() # pragma: no cover + + +class PDPDriver(Driver): + + def __init__(self, driver_name, engine_name): + super(PDPDriver, self).__init__(driver_name, engine_name) + + def update_pdp(self, pdp_id, value): + raise NotImplementedError() # pragma: no cover + + def delete_policy_from_pdp(self, pdp_id, policy_id): + raise NotImplementedError() # pragma: no cover + + def delete_pdp(self, pdp_id): + raise NotImplementedError() # pragma: no cover + + def add_pdp(self, pdp_id=None, value=None): + raise NotImplementedError() # pragma: no cover + + def get_pdp(self, pdp_id=None): + raise NotImplementedError() # pragma: no cover + + +class SlaveDriver(Driver): + + def __init__(self, driver_name, engine_name): + super(SlaveDriver, self).__init__(driver_name, engine_name) + + def update_slave(self, slave_id, value): + raise NotImplementedError() # pragma: no cover + + def delete_slave(self, slave_id): + raise NotImplementedError() # pragma: no cover + + def add_slave(self, slave_id=None, value=None): + raise NotImplementedError() # pragma: no cover + + def get_slaves(self, slave_id=None): + raise NotImplementedError() # pragma: no cover + + +def init(): + global ModelManager, PolicyManager, PDPManager, SlaveManager + + conf = configuration.get_configuration("database") + + ModelManager = model.ModelManager( + ModelDriver(conf['driver'], conf['url']) + ) + + PolicyManager = policy.PolicyManager( + PolicyDriver(conf['driver'], conf['url']) + ) + + PDPManager = pdp.PDPManager( + PDPDriver(conf['driver'], conf['url']) + ) + + SlaveManager = slave.SlaveManager( + SlaveDriver(conf['driver'], conf['url']) + ) diff --git a/moon_manager/moon_manager/http_server.py b/moon_manager/moon_manager/http_server.py deleted file mode 100644 index 53879529..00000000 --- a/moon_manager/moon_manager/http_server.py +++ /dev/null @@ -1,162 +0,0 @@ -# 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, Response, make_response -from flask_cors import CORS, cross_origin -from json import dumps -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.slaves import Slaves -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.json_import import JsonImport -from moon_manager.api.json_export import JsonExport -from python_moonutilities import configuration -from python_moondb.core import PDPManager - -logger = logging.getLogger("moon.manager.http_server") - -__API__ = ( - Status, Logs, API, - MetaRules, SubjectCategories, ObjectCategories, ActionCategories, - Subjects, Objects, Actions, Rules, - SubjectAssignments, ObjectAssignments, ActionAssignments, - SubjectData, ObjectData, ActionData, - Models, Policies, PDP, Slaves, JsonImport, JsonExport -) - - -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() - - -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() if item.__doc__ else "" - return { - "version": __version__, - "tree": tree - } - - -class CustomApi(Api): - - @staticmethod - def handle_error(e): - try: - error_message = dumps( - {"result": False, 'message': str(e), "code": getattr(e, "code", 500)}) - logger.error(e, exc_info=True) - logger.error(error_message) - return make_response(error_message, getattr(e, "code", 500)) - except Exception as e2: # unhandled exception in the api... - logger.exception(str(e2)) - return make_response(error_message, 500) - - -class HTTPServer(Server): - - def __init__(self, host="localhost", port=80, **kwargs): - super(HTTPServer, self).__init__(host=host, port=port, **kwargs) - self.app = Flask(__name__) - self.app.config['TRAP_HTTP_EXCEPTIONS'] = True - 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 = CustomApi(self.app, catch_all_404s=True) - self.__set_route() - - 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, sqlalchemy.exc.InternalError): - time.sleep(1) - if first: - logger.warning("Waiting for the database...") - first = False - else: - logger.warning("Database is up, resuming operations...") - break - - def run(self): - self.__check_if_db_is_up() - self.app.run(host=self._host, port=self._port, threaded=True) # nosec diff --git a/moon_manager/moon_manager/manager_setup.py b/moon_manager/moon_manager/manager_setup.py new file mode 100644 index 00000000..b3e5a1eb --- /dev/null +++ b/moon_manager/moon_manager/manager_setup.py @@ -0,0 +1,31 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + +""" +This file is used only once to install the manager +""" + +import os +import shutil +import sys + + +def setup(): + """Setup the manager + + :return: nothing + """ + if os.name == "posix": + if not os.path.exists(os.path.join("/etc", "moon")): + print("Installing configuration file in /etc") + shutil.copytree(os.path.abspath(sys.argv[0]+"/../../moon"), os.path.join("/etc/moon")) + else: + print('The directory "/etc/moon/" already exists.', file=sys.stderr) diff --git a/moon_manager/moon_manager/orchestration_driver.py b/moon_manager/moon_manager/orchestration_driver.py new file mode 100644 index 00000000..5e03c250 --- /dev/null +++ b/moon_manager/moon_manager/orchestration_driver.py @@ -0,0 +1,81 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +import logging +from moon_manager.api import configuration +from moon_manager.api.orchestration import slave, pipeline + +logger = logging.getLogger("moon.manager.orchestration_driver") + + +SlaveManager = None +PipelineManager = None + + +class Driver: + + def __init__(self, driver_name, engine_name): + self.name = driver_name + self.plug = configuration.get_orchestration_driver() + self.driver = self.plug.Connector(driver_name, engine_name) + + +class SlaveDriver(Driver): + + def __init__(self, driver_name, engine_name): + super(SlaveDriver, self).__init__(driver_name, engine_name) + self.engine = engine_name + + def update_slave(self, slave_id, data): + raise NotImplementedError() # pragma: no cover + + def delete_slave(self, slave_id): + raise NotImplementedError() # pragma: no cover + + def add_slave(self, slave_id=None, data=None): + raise NotImplementedError() # pragma: no cover + + def get_slaves(self, slave_id=None): + raise NotImplementedError() # pragma: no cover + + +class PipelineDriver(Driver): + + def __init__(self, driver_name, engine_name): + super(PipelineDriver, self).__init__(driver_name, engine_name) + self.engine = engine_name + + def update_pipeline(self, pipeline_id, data): + raise NotImplementedError() # pragma: no cover + + def delete_pipeline(self, pipeline_id): + raise NotImplementedError() # pragma: no cover + + def add_pipeline(self, pipeline_id=None, data=None): + raise NotImplementedError() # pragma: no cover + + def get_pipelines(self, slave_id=None, pipeline_id=None): + raise NotImplementedError() # pragma: no cover + + +def init(): + global SlaveManager, PipelineManager + + logger.info("Initializing driver") + conf = configuration.get_configuration("orchestration") + + SlaveManager = slave.SlaveManager( + SlaveDriver(conf['driver'], conf.get('url')) + ) + PipelineManager = pipeline.PipelineManager( + PipelineDriver(conf['driver'], conf.get('url')) + ) diff --git a/moon_manager/moon_manager/pip_driver.py b/moon_manager/moon_manager/pip_driver.py new file mode 100644 index 00000000..1a451577 --- /dev/null +++ b/moon_manager/moon_manager/pip_driver.py @@ -0,0 +1,350 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + +""" +Drivers fot the Policy Information Point +""" + +import logging +from moon_manager.api import configuration +from moon_manager.api.information import information, global_attrs + +LOGGER = logging.getLogger("moon.manager.pip_driver") + + +InformationManager = None +AttrsManager = None + + +class Driver: + """ + Generic driver + """ + + def __init__(self, driver_name, engine_name, conf={}): + self.name = driver_name + self.plug = configuration.get_information_driver(driver_name) + if self.plug: + self.driver = self.plug.Connector(driver_name, engine_name, conf) + else: + self.driver = VoidConnector(driver_name, engine_name) + + +class InformationDriver(Driver): + """ + Driver for information retrieval for external components like OpenStack + """ + + def __init__(self, driver_name, engine_name, conf): + super(InformationDriver, self).__init__(driver_name, engine_name, conf) + self.engine = engine_name + + def set_auth(self, **kwargs): + """Set authorizations if necessary + + :param kwargs: arguments which are necessary to login to the server + :return: headers to use + """ + raise NotImplementedError() # pragma: no cover + + def unset_auth(self, **kwargs): + """Unset the authorization is necessary + + :param kwargs: arguments which are necessary to logout to the server + :return: headers to use + """ + raise NotImplementedError() # pragma: no cover + + def get_items(self, item_id=None, **kwargs): + """List items in the server + + :param item_id: the item name or item ID + :param kwargs: all arguments necessary to list items + :return: a list of items + """ + raise NotImplementedError() # pragma: no cover + + def add_item(self, item_id=None, **kwargs): + """Add a item in the server + + :param item_id: the item name or item ID + :param kwargs: all arguments necessary to add a item + :return: the item added + """ + raise NotImplementedError() # pragma: no cover + + def update_item(self, item_id, **kwargs): + """Update a item in the server + + :param item_id: the item name or item ID + :param kwargs: all arguments necessary to update the item + :return: the item updated + """ + raise NotImplementedError() # pragma: no cover + + def delete_item(self, item_id, **kwargs): + """Delete a item in the server + + :param item_id: the item name or item ID + :param kwargs: all arguments necessary to delete the item + :return: True if the item has been deleted + """ + raise NotImplementedError() # pragma: no coverl + + +class GlobalAttrsDriver: + """ + Driver for global attributes in Moon + """ + + def __init__(self, driver_name, engine_name): + self.name = driver_name + self.plug = configuration.get_global_attrs_driver() + if self.plug: + self.driver = self.plug.Connector(driver_name, engine_name) + else: + self.driver = VoidConnector(driver_name, engine_name) + self.engine = engine_name + + def set_auth(self, **kwargs): + """Set authorizations if necessary + + :param kwargs: arguments which are necessary to login to the server + :return: headers to use + """ + raise NotImplementedError() # pragma: no cover + + def unset_auth(self, **kwargs): + """Unset the authorization is necessary + + :param kwargs: arguments which are necessary to logout to the server + :return: headers to use + """ + raise NotImplementedError() # pragma: no cover + + def get_users(self, user_id=None, **kwargs): + """List users in the server + + :param user_id: the user name or user ID + :param kwargs: all arguments necessary to list users + :return: a list of users + """ + raise NotImplementedError() # pragma: no cover + + def add_user(self, user_id=None, **kwargs): + """Add a user in the server + + :param user_id: the user name or user ID + :param kwargs: all arguments necessary to add a user + :return: the user added + """ + raise NotImplementedError() # pragma: no cover + + def update_user(self, user_id, **kwargs): + """Update a user in the server + + :param user_id: the user name or user ID + :param kwargs: all arguments necessary to update the user + :return: the user updated + """ + raise NotImplementedError() # pragma: no cover + + def delete_user(self, user_id, **kwargs): + """Delete a user in the server + + :param user_id: the user name or user ID + :param kwargs: all arguments necessary to delete the user + :return: True if the user has been deleted + """ + raise NotImplementedError() # pragma: no cover + + def get_objects(self, object_id=None, object_type=None, **kwargs): + """List objects in the server + + :param object_id: the object name or user ID + :param object_type: the object type (project, vms, ...) + :param kwargs: all arguments necessary to list the object + :return: a list of objects + """ + raise NotImplementedError() # pragma: no cover + + def get_object(self, object_type=None, **kwargs): + """List a specific object in the server + + :param object_type: the object type (project, vms, ...) + :param kwargs: all arguments necessary to list the object + :return: a list of objects + """ + raise NotImplementedError() # pragma: no cover + + def add_object(self, object_id=None, object_type=None, **kwargs): + """Add an object in the server + + :param object_id: the object name or user ID + :param object_type: the object type (project, vms, ...) + :param kwargs: all arguments necessary to add the object + :return: the object added + """ + raise NotImplementedError() # pragma: no cover + + def update_object(self, object_id, object_type=None, **kwargs): + """Update an object in the server + + :param object_id: the object name or user ID + :param object_type: the object type (project, vms, ...) + :param kwargs: all arguments necessary to update the object + :return: the object updated + """ + raise NotImplementedError() # pragma: no cover + + def delete_object(self, object_id, object_type=None, **kwargs): + """Delete an object in the server + + :param object_id: the object name or user ID + :param object_type: the object type (project, vms, ...) + :param kwargs: all arguments necessary to delete the object + :return: True if the object has been deleted + """ + raise NotImplementedError() # pragma: no cover + + +class VoidConnector(InformationDriver): + """ + Driver for information retrieval for external components like OpenStack + """ + + def __init__(self, driver_name, engine_name): + self.engine = engine_name + + def set_auth(self, **kwargs): + """Set authorizations if necessary + + :param kwargs: arguments which are necessary to login to the server + :return: headers to use + """ + return + + def unset_auth(self, **kwargs): + """Unset the authorization is necessary + + :param kwargs: arguments which are necessary to logout to the server + :return: headers to use + """ + return + + def get_users(self, user_id=None, **kwargs): + """List users in the server + + :param user_id: the user name or user ID + :param kwargs: all arguments necessary to list users + :return: a list of users + """ + return {} + + def add_user(self, user_id=None, **kwargs): + """Add a user in the server + + :param user_id: the user name or user ID + :param kwargs: all arguments necessary to add a user + :return: the user added + """ + return {} + + def update_user(self, user_id, **kwargs): + """Update a user in the server + + :param user_id: the user name or user ID + :param kwargs: all arguments necessary to update the user + :return: the user updated + """ + return {} + + def delete_user(self, user_id, **kwargs): + """Delete a user in the server + + :param user_id: the user name or user ID + :param kwargs: all arguments necessary to delete the user + :return: True if the user has been deleted + """ + return {} + + def get_objects(self, object_id=None, object_type=None, **kwargs): + """List objects in the server + + :param object_id: the object name or user ID + :param object_type: the object type (project, vms, ...) + :param kwargs: all arguments necessary to list the object + :return: a list of objects + """ + return {} + + def add_object(self, object_id=None, object_type=None, **kwargs): + """Add an object in the server + + :param object_id: the object name or user ID + :param object_type: the object type (project, vms, ...) + :param kwargs: all arguments necessary to add the object + :return: the object added + """ + return {} + + def update_object(self, object_id, object_type=None, **kwargs): + """Update an object in the server + + :param object_id: the object name or user ID + :param object_type: the object type (project, vms, ...) + :param kwargs: all arguments necessary to update the object + :return: the object updated + """ + return {} + + def delete_object(self, object_id, object_type=None, **kwargs): + """Delete an object in the server + + :param object_id: the object name or user ID + :param object_type: the object type (project, vms, ...) + :param kwargs: all arguments necessary to delete the object + :return: True if the object has been deleted + """ + return {} + + +def init(): + """Initialize the managers + + :return: nothing + """ + global InformationManager, AttrsManager + + InformationManager = {"subjects": [], "objects": [], "actions": []} + + LOGGER.info("Initializing driver") + conf = configuration.get_configuration("information") + + for category in InformationManager: + if category not in conf: + continue + drivers = conf.get(category).get("drivers") + for driver in drivers: + InformationManager[category].append( + information.InformationManager( + InformationDriver(driver, drivers[driver].get("url"), conf[category]["drivers"].get(driver, {})) + ) + ) + + conf = configuration.get_configuration("information").get("global_attrs") + + AttrsManager = global_attrs.GlobalAttrsManager( + GlobalAttrsDriver(conf['driver'], "") + ) + + +init() diff --git a/moon_manager/moon_manager/plugins/__init__.py b/moon_manager/moon_manager/plugins/__init__.py new file mode 100644 index 00000000..1856aa2c --- /dev/null +++ b/moon_manager/moon_manager/plugins/__init__.py @@ -0,0 +1,12 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + diff --git a/moon_manager/moon_manager/plugins/global_attrs.py b/moon_manager/moon_manager/plugins/global_attrs.py new file mode 100644 index 00000000..fdf51fd4 --- /dev/null +++ b/moon_manager/moon_manager/plugins/global_attrs.py @@ -0,0 +1,582 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + +""" +Plugin to request OpenStack infrastructure: +- Keystone +- Nova +""" + +import json +import logging +import time +import requests +from moon_manager.pip_driver import InformationDriver +from moon_manager.api.configuration import get_configuration +from moon_utilities import exceptions + +LOGGER = logging.getLogger("moon.manager.plugins.global_attrs") + +PLUGIN_TYPE = "information" + + +class AttrsConnector(InformationDriver): + + def __init__(self, driver_name, engine_name): + self.driver_name = driver_name + self.engine_name = engine_name + self.conf = get_configuration("information").get("global_attrs", {}) + self.drivers = {} + + def driver(self, driver_name="file"): + if driver_name.startswith("file"): + if not self.drivers.get("file"): + self.drivers["file"] = AttrsConnectorFile() + return self.drivers["file"] + if driver_name == "http": + if not self.drivers.get("file"): + self.drivers["http"] = AttrsConnectorHTTP() + return self.drivers["http"] + if driver_name == "mysql": + if not self.drivers.get("file"): + self.drivers["mysql"] = AttrsConnectorSQL() + return self.drivers["sql"] + if driver_name == "sqlite": + if not self.drivers.get("file"): + self.drivers["sqlite"] = AttrsConnectorSQL() + return self.drivers["sql"] + if driver_name == "driver": + if not self.drivers.get("file"): + self.drivers["driver"] = AttrsConnectorDriver() + return self.drivers["driver"] + + def set_auth(self, **kwargs): + """Set authorizations if necessary + + :param kwargs: arguments which are necessary to login to the server + :return: headers to use + """ + raise NotImplementedError + + def unset_auth(self, **kwargs): + """Unset the authorization is necessary + + :param kwargs: arguments which are necessary to logout to the server + :return: headers to use + """ + raise NotImplementedError + + def get_objects(self, object_id=None, object_type=None, **kwargs): + """List objects in the server + + :param object_id: the object name or user ID + :param object_type: the object type (project, vms, ...) + :param kwargs: all arguments necessary to list the object + :return: a list of objects + """ + if not object_type: + object_type = list(self.conf.get("attributes").keys()) + elif isinstance(object_type, str): + object_type = [object_type, ] + + results = {} + for _type in object_type: + if _type in self.conf.get("attributes"): + driver_name = self.conf.get("attributes").get(_type).get("url").split(":")[0] + value = self.driver(driver_name).get_object(_type, **kwargs) + results[_type] = { + "id": _type, + "value": value, + "values": self.conf.get("attributes").get(_type).get("values"), + "default": self.conf.get("attributes").get(_type).get("default") + } + else: + raise exceptions.AttributeUnknownError( + "Cannot find global attribute {}".format(object_type)) + return results + + def get_object(self, object_type=None, **kwargs): + """List specific object in the server + + :param object_type: the object type (project, vms, ...) + :param kwargs: all arguments necessary to list the object + :return: a list of objects + """ + if object_type in self.conf.get("attributes"): + driver_name = self.conf.get("attributes").get(object_type).get("url").split(":")[0] + value = self.driver(driver_name).get_object(object_type, **kwargs) + return { + "id": object_type, + "value": value, + "values": self.conf.get("attributes").get(object_type).get("values"), + "default": self.conf.get("attributes").get(object_type).get("default") + } + else: + raise exceptions.AttributeUnknownError( + "Cannot find global attribute {}".format(object_type)) + + def add_object(self, object_id=None, object_type=None, **kwargs): + """Add an object in the server + + :param object_id: the object name or user ID + :param object_type: the object type (project, vms, ...) + :param kwargs: all arguments necessary to add the object + :return: the object added + """ + if object_type in self.conf.get("attributes"): + driver_name = self.conf.get("attributes").get(object_type).get("url").split(":")[0] + value = self.driver(driver_name).add_object(object_id, object_type, **kwargs) + return { + "id": object_type, + "value": value, + "values": self.conf.get("attributes").get(object_type).get("values"), + "default": self.conf.get("attributes").get(object_type).get("default") + } + raise exceptions.AttributeUnknownError( + "Cannot find global attribute {}".format(object_type)) + + def update_object(self, object_id, object_type=None, **kwargs): + """Update an object in the server + + :param object_id: the object name or user ID + :param object_type: the object type (project, vms, ...) + :param kwargs: all arguments necessary to update the object + :return: the object updated + """ + if object_type in self.conf.get("attributes"): + driver_name = self.conf.get("attributes").get(object_type).get("url").split(":")[0] + value = self.driver(driver_name).update_object(object_id, object_type, **kwargs) + return { + "id": object_type, + "value": value, + "values": self.conf.get("attributes").get(object_type).get("values"), + "default": self.conf.get("attributes").get(object_type).get("default") + } + raise exceptions.AttributeUnknownError( + "Cannot find global attribute {}".format(object_type)) + + def delete_object(self, object_id=None, object_type=None, **kwargs): + """Delete an object in the server + + :param object_id: the object name or user ID + :param object_type: the object type (project, vms, ...) + :param kwargs: all arguments necessary to delete the object + :return: True if the object has been deleted + """ + if object_type in self.conf.get("attributes"): + driver_name = self.conf.get("attributes").get(object_type).get("url").split(":")[0] + value = self.driver(driver_name).delete_object(object_id, object_type, **kwargs) + return { + "id": object_type, + "value": value, + "values": self.conf.get("attributes").get(object_type).get("values"), + "default": self.conf.get("attributes").get(object_type).get("default") + } + raise exceptions.AttributeUnknownError( + "Cannot find global attribute {}".format(object_type)) + + +class AttrsConnectorFile: + + def __init__(self): + self.conf = get_configuration("information").get("global_attrs", {}) + + def set_auth(self, **kwargs): + """Set authorizations if necessary + + :param kwargs: arguments which are necessary to login to the server + :return: headers to use + """ + raise NotImplementedError + + def unset_auth(self, **kwargs): + """Unset the authorization is necessary + + :param kwargs: arguments which are necessary to logout to the server + :return: headers to use + """ + raise NotImplementedError + + def get_objects(self, object_id=None, object_type=None, **kwargs): + """List objects in the server + + :param object_id: the object name or user ID + :param object_type: the object type (project, vms, ...) + :param kwargs: all arguments necessary to list the object + :return: a list of objects + """ + if not object_type: + object_type = list(self.conf.get("attributes").keys()) + elif isinstance(object_type, str): + object_type = [object_type, ] + + for _type in object_type: + filename = self.conf.get("attributes").get(_type).get("url").split(":")[1].strip() + try: + yield {_type: open(filename).read().strip()} + except FileNotFoundError: + LOGGER.error("Cannot find file name {}".format(filename)) + yield {_type: self.conf.get("attributes").get(_type).get("default")} + + def get_object(self, object_type, **kwargs): + """Get specific object in the server + + :param object_type: the object type (project, vms, ...) + :param kwargs: all arguments necessary to list the object + :return: a list of objects + """ + filename = self.conf.get("attributes").get(object_type).get("url").split(":")[1].strip() + try: + return open(filename).read().strip() + except FileNotFoundError: + LOGGER.error("Cannot find file name {}".format(filename)) + return self.conf.get("attributes").get(object_type).get("default") + + def add_object(self, object_id=None, object_type=None, **kwargs): + """Add an object in the server + + :param object_id: the object name or user ID + :param object_type: the object type (project, vms, ...) + :param kwargs: all arguments necessary to add the object + :return: the object added + """ + filename = self.conf.get("attributes").get(object_type).get("url").split(":")[1].strip() + default_value = self.conf.get("attributes").get(object_type).get("default") + open(filename, "w").write(default_value) + return default_value + + def update_object(self, object_id, object_type=None, **kwargs): + """Update an object in the server + + :param object_id: the object name or user ID + :param object_type: the object type (project, vms, ...) + :param kwargs: all arguments necessary to update the object + :return: the object updated + """ + filename = self.conf.get("attributes").get(object_type).get("url").split(":")[1].strip() + values = self.conf.get("attributes").get(object_type).get("values") + if object_id in values: + open(filename, "w").write(object_id) + return object_id + raise exceptions.AttributeValueUnknownError( + "The given value ({}) is not part of the authorized values ({})".format( + object_id, ", ".join(values))) + + def delete_object(self, object_id=None, object_type=None, **kwargs): + """Delete an object in the server + + :param object_id: the object name or user ID + :param object_type: the object type (project, vms, ...) + :param kwargs: all arguments necessary to delete the object + :return: True if the object has been deleted + """ + filename = self.conf.get("attributes").get(object_type).get("url").split(":")[1].strip() + default_value = self.conf.get("attributes").get(object_type).get("default") + open(filename, "w").write(default_value) + return default_value + + +class AttrsConnectorHTTP: + + def __init__(self): + self.conf = get_configuration("information").get("global_attrs", {}) + + def set_auth(self, **kwargs): + """Set authorizations if necessary + + :param kwargs: arguments which are necessary to login to the server + :return: headers to use + """ + raise NotImplementedError + + def unset_auth(self, **kwargs): + """Unset the authorization is necessary + + :param kwargs: arguments which are necessary to logout to the server + :return: headers to use + """ + raise NotImplementedError + + def get_users(self, user_id=None, **kwargs): + """List users in the server + + :param user_id: the user name or user ID + :param kwargs: all arguments necessary to list users + :return: a list of users + """ + raise NotImplementedError + + def add_user(self, user_id=None, **kwargs): + """Add a user in the server + + :param user_id: the user name or user ID + :param kwargs: all arguments necessary to add a user + :return: the user added + """ + raise NotImplementedError + + def update_user(self, user_id, **kwargs): + """Update a user in the server + + :param user_id: the user name or user ID + :param kwargs: all arguments necessary to update the user + :return: the user updated + """ + raise NotImplementedError + + def delete_user(self, user_id, **kwargs): + """Delete a user in the server + + :param user_id: the user name or user ID + :param kwargs: all arguments necessary to delete the user + :return: True if the user has been deleted + """ + raise NotImplementedError + + def get_objects(self, object_id=None, object_type=None, **kwargs): + """List objects in the server + + :param object_id: the object name or user ID + :param object_type: the object type (project, vms, ...) + :param kwargs: all arguments necessary to list the object + :return: a list of objects + """ + raise NotImplementedError + + def add_object(self, object_id=None, object_type=None, **kwargs): + """Add an object in the server + + :param object_id: the object name or user ID + :param object_type: the object type (project, vms, ...) + :param kwargs: all arguments necessary to add the object + :return: the object added + """ + raise NotImplementedError + + def update_object(self, object_id, object_type=None, **kwargs): + """Update an object in the server + + :param object_id: the object name or user ID + :param object_type: the object type (project, vms, ...) + :param kwargs: all arguments necessary to update the object + :return: the object updated + """ + raise NotImplementedError + + def delete_object(self, object_id=None, object_type=None, **kwargs): + """Delete an object in the server + + :param object_id: the object name or user ID + :param object_type: the object type (project, vms, ...) + :param kwargs: all arguments necessary to delete the object + :return: True if the object has been deleted + """ + raise NotImplementedError + + +class AttrsConnectorSQL: + + def __init__(self): + self.conf = get_configuration("information").get("global_attrs", {}) + + def set_auth(self, **kwargs): + """Set authorizations if necessary + + :param kwargs: arguments which are necessary to login to the server + :return: headers to use + """ + raise NotImplementedError + + def unset_auth(self, **kwargs): + """Unset the authorization is necessary + + :param kwargs: arguments which are necessary to logout to the server + :return: headers to use + """ + raise NotImplementedError + + def get_users(self, user_id=None, **kwargs): + """List users in the server + + :param user_id: the user name or user ID + :param kwargs: all arguments necessary to list users + :return: a list of users + """ + raise NotImplementedError + + def add_user(self, user_id=None, **kwargs): + """Add a user in the server + + :param user_id: the user name or user ID + :param kwargs: all arguments necessary to add a user + :return: the user added + """ + raise NotImplementedError + + def update_user(self, user_id, **kwargs): + """Update a user in the server + + :param user_id: the user name or user ID + :param kwargs: all arguments necessary to update the user + :return: the user updated + """ + raise NotImplementedError + + def delete_user(self, user_id, **kwargs): + """Delete a user in the server + + :param user_id: the user name or user ID + :param kwargs: all arguments necessary to delete the user + :return: True if the user has been deleted + """ + raise NotImplementedError + + def get_objects(self, object_id=None, object_type=None, **kwargs): + """List objects in the server + + :param object_id: the object name or user ID + :param object_type: the object type (project, vms, ...) + :param kwargs: all arguments necessary to list the object + :return: a list of objects + """ + raise NotImplementedError + + def add_object(self, object_id=None, object_type=None, **kwargs): + """Add an object in the server + + :param object_id: the object name or user ID + :param object_type: the object type (project, vms, ...) + :param kwargs: all arguments necessary to add the object + :return: the object added + """ + raise NotImplementedError + + def update_object(self, object_id, object_type=None, **kwargs): + """Update an object in the server + + :param object_id: the object name or user ID + :param object_type: the object type (project, vms, ...) + :param kwargs: all arguments necessary to update the object + :return: the object updated + """ + raise NotImplementedError + + def delete_object(self, object_id=None, object_type=None, **kwargs): + """Delete an object in the server + + :param object_id: the object name or user ID + :param object_type: the object type (project, vms, ...) + :param kwargs: all arguments necessary to delete the object + :return: True if the object has been deleted + """ + raise NotImplementedError + + +class AttrsConnectorDriver: + + def __init__(self): + self.conf = get_configuration("information").get("global_attrs", {}) + + def set_auth(self, **kwargs): + """Set authorizations if necessary + + :param kwargs: arguments which are necessary to login to the server + :return: headers to use + """ + raise NotImplementedError + + def unset_auth(self, **kwargs): + """Unset the authorization is necessary + + :param kwargs: arguments which are necessary to logout to the server + :return: headers to use + """ + raise NotImplementedError + + def get_users(self, user_id=None, **kwargs): + """List users in the server + + :param user_id: the user name or user ID + :param kwargs: all arguments necessary to list users + :return: a list of users + """ + raise NotImplementedError + + def add_user(self, user_id=None, **kwargs): + """Add a user in the server + + :param user_id: the user name or user ID + :param kwargs: all arguments necessary to add a user + :return: the user added + """ + raise NotImplementedError + + def update_user(self, user_id, **kwargs): + """Update a user in the server + + :param user_id: the user name or user ID + :param kwargs: all arguments necessary to update the user + :return: the user updated + """ + raise NotImplementedError + + def delete_user(self, user_id, **kwargs): + """Delete a user in the server + + :param user_id: the user name or user ID + :param kwargs: all arguments necessary to delete the user + :return: True if the user has been deleted + """ + raise NotImplementedError + + def get_objects(self, object_id=None, object_type=None, **kwargs): + """List objects in the server + + :param object_id: the object name or user ID + :param object_type: the object type (project, vms, ...) + :param kwargs: all arguments necessary to list the object + :return: a list of objects + """ + raise NotImplementedError + + def add_object(self, object_id=None, object_type=None, **kwargs): + """Add an object in the server + + :param object_id: the object name or user ID + :param object_type: the object type (project, vms, ...) + :param kwargs: all arguments necessary to add the object + :return: the object added + """ + raise NotImplementedError + + def update_object(self, object_id, object_type=None, **kwargs): + """Update an object in the server + + :param object_id: the object name or user ID + :param object_type: the object type (project, vms, ...) + :param kwargs: all arguments necessary to update the object + :return: the object updated + """ + raise NotImplementedError + + def delete_object(self, object_id=None, object_type=None, **kwargs): + """Delete an object in the server + + :param object_id: the object name or user ID + :param object_type: the object type (project, vms, ...) + :param kwargs: all arguments necessary to delete the object + :return: True if the object has been deleted + """ + raise NotImplementedError + + +class Connector(AttrsConnector): + pass diff --git a/moon_manager/moon_manager/plugins/moon_keystone_plugin.py b/moon_manager/moon_manager/plugins/moon_keystone_plugin.py new file mode 100644 index 00000000..0fb9b363 --- /dev/null +++ b/moon_manager/moon_manager/plugins/moon_keystone_plugin.py @@ -0,0 +1,77 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + +""" +Plugin to request OpenStack infrastructure: +- Keystone +""" + +from moon_manager.plugins.moon_openstack_plugin import * + +LOGGER = logging.getLogger("moon.manager.plugins.moon_keystone_plugin") + +PLUGIN_TYPE = "information" +_ = str + + +class KeystoneConnector(OpenStackConnector): + + def get_items(self, item_id=None, **kwargs): + username = "" + domain_id = "" + if "username" in kwargs: + username = kwargs['username'] + if "domain_id" in kwargs: + domain_id = kwargs['domain_id'] + if username and domain_id: + return self._get(endpoint="/users?name={}&domain_id={}".format(username, domain_id), + _exception=KeystoneUserError) + elif username: + return self._get(endpoint="/users?name={}".format(username), + _exception=KeystoneUserError) + elif domain_id: + return self._get(endpoint="/users?domain_id={}".format(domain_id), + _exception=KeystoneUserError) + else: + return self._get(endpoint="/users", + _exception=KeystoneUserError) + + def add_item(self, item_id=None, **kwargs): + if 'name' not in kwargs: + raise KeystoneError("Cannot find name in request") + _user = { + "user": { + "enabled": True, + "name": kwargs['name'], + } + } + if 'project' in kwargs: + _user['user']['default_project_id'] = kwargs['project'] + if 'domain' in kwargs: + _user['user']['domain_id'] = kwargs['domain'] + if 'password' in kwargs: + _user['user']['password'] = kwargs['password'] + try: + return self._post(endpoint="/users/", + data=_user, + _exception=KeystoneUserError) + except KeystoneUserConflict: + return True + + def update_item(self, item_id, **kwargs): + raise NotImplementedError() # pragma: no cover + + def delete_item(self, item_id, **kwargs): + raise NotImplementedError() # pragma: no cover + + +class Connector(KeystoneConnector): + pass diff --git a/moon_manager/moon_manager/plugins/moon_nova_plugin.py b/moon_manager/moon_manager/plugins/moon_nova_plugin.py new file mode 100644 index 00000000..0848152e --- /dev/null +++ b/moon_manager/moon_manager/plugins/moon_nova_plugin.py @@ -0,0 +1,71 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + +""" +Plugin to request OpenStack infrastructure: +- Nova +""" + +from moon_manager.plugins.moon_openstack_plugin import * + +LOGGER = logging.getLogger("moon.manager.plugins.moon_nova_plugin") + +PLUGIN_TYPE = "information" +_ = str + +# Nova exceptions + + +class NovaError(MoonError): + description = _("There is an error connecting to Nova.") + code = 400 + title = 'Nova error' + logger = "ERROR" + + +class NovaProjectError(NovaError): + description = _("There is an error retrieving projects from the Nova service.") + code = 400 + title = 'Nova project error' + logger = "ERROR" + + +class NovaUserError(NovaError): + description = _("There is an error retrieving users from the Nova service.") + code = 400 + title = 'Nova user error' + logger = "ERROR" + + +class NovaUserConflict(NovaUserError): + description = _("A user with that name already exist.") + code = 400 + title = 'Nova user error' + logger = "ERROR" + + +class NovaConnector(OpenStackConnector): + + def get_items(self, item_id=None, **kwargs): + return self._get(endpoint="/servers", _exception=NovaProjectError) + + def add_item(self, object_id=None, **kwargs): + raise NotImplementedError() # pragma: no cover + + def update_item(self, item_id, **kwargs): + raise NotImplementedError() # pragma: no cover + + def delete_item(self, item_id, **kwargs): + raise NotImplementedError() # pragma: no cover + + +class Connector(NovaConnector): + pass diff --git a/moon_manager/moon_manager/plugins/moon_openstack_plugin.py b/moon_manager/moon_manager/plugins/moon_openstack_plugin.py new file mode 100644 index 00000000..a4b8a237 --- /dev/null +++ b/moon_manager/moon_manager/plugins/moon_openstack_plugin.py @@ -0,0 +1,203 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + +""" +Abstract plugin to request OpenStack infrastructure +""" + +import json +import logging +import time +import requests +from moon_manager.pip_driver import InformationDriver +from moon_manager.api.configuration import get_configuration +from moon_utilities.exceptions import MoonError + +LOGGER = logging.getLogger("moon.manager.plugins.moon_openstack_plugin") + +PLUGIN_TYPE = "information" +_ = str + + +# Keystone exceptions + + +class KeystoneError(MoonError): + description = _("There is an error connecting to Keystone.") + code = 400 + title = 'Keystone error' + logger = "ERROR" + + +class KeystoneProjectError(KeystoneError): + description = _("There is an error retrieving projects from the Keystone service.") + code = 400 + title = 'Keystone project error' + logger = "ERROR" + + +class KeystoneUserError(KeystoneError): + description = _("There is an error retrieving users from the Keystone service.") + code = 400 + title = 'Keystone user error' + logger = "ERROR" + + +class KeystoneUserConflict(KeystoneUserError): + description = _("A user with that name already exist.") + code = 400 + title = 'Keystone user error' + logger = "ERROR" + + +class OpenStackConnector(InformationDriver): + + def __init__(self, driver_name, engine_name, conf): + self.driver_name = driver_name + self.engine_name = engine_name + self.opst_conf = get_configuration("information") + + if not self.opst_conf: + raise Exception("Cannot find OpenStack configuration in configuration file") + + self.__headers = {} + self.__user = conf.get("user", self.opst_conf['user']) + self.__password = conf.get("password", self.opst_conf['password']) + self.__domain = conf.get("domain", self.opst_conf['domain']) + self.__project = conf.get("project", self.opst_conf['project']) + self.__url = conf.get("url", self.opst_conf['url']) + + def set_auth(self, **kwargs): + start_time = time.time() + user = kwargs.get("user", self.opst_conf['user']) + password = kwargs.get("password", self.opst_conf['password']) + domain = kwargs.get("domain", self.opst_conf['domain']) + project = kwargs.get("project", self.opst_conf['project']) + url = kwargs.get("url", self.opst_conf['url']) + headers = { + "Content-Type": "application/json" + } + data_auth = { + "auth": { + "identity": { + "methods": [ + "password" + ], + "password": { + "user": { + "domain": { + "id": domain + }, + "name": user, + "password": password + } + } + }, + "scope": { + "project": { + "domain": { + "id": domain + }, + "name": project + } + } + } + } + + while True: + req = requests.post("{}/auth/tokens".format(url), + json=data_auth, headers=headers, + verify=kwargs.get("certificate", self.opst_conf['certificate'])) + + if req.status_code in (200, 201, 204): + self.__headers['X-Auth-Token'] = req.headers['X-Subject-Token'] + return self.__headers + LOGGER.warning("Waiting for Keystone...") + if time.time() - start_time == 100: + LOGGER.error(req.text) + raise KeystoneError + time.sleep(5) + + def unset_auth(self, **kwargs): + url = kwargs.get("url", self.opst_conf['url']) + self.__headers['X-Subject-Token'] = self.__headers['X-Auth-Token'] + req = requests.delete("{}/auth/tokens".format(url), headers=self.__headers, + verify=kwargs.get("certificate", self.opst_conf['certificate'])) + if req.status_code in (200, 201, 204): + return + LOGGER.error(req.text) + raise KeystoneError + + def _get(self, endpoint, url=None, _exception=KeystoneError): + if not url: + if not self.__url: + LOGGER.warning("Cannot retrieve the URL for the OpenStack endpoint") + return {'users': []} + url = self.__url + + req = requests.get("{}{}".format(url, endpoint), + headers=self.__headers) + if req.status_code not in (200, 201): + LOGGER.error(req.text) + raise _exception + data = req.json() + return data + + def _post(self, endpoint, url=None, data=None, _exception=KeystoneError): + if not url: + if not self.__url: + LOGGER.warning("Cannot retrieve the URL for the OpenStack endpoint") + return {'users': []} + url = self.__url + + req = requests.post("{}{}".format(url, endpoint), + data=json.dumps(data), + headers=self.__headers) + if req.status_code == 409: + LOGGER.warning(req.text) + raise KeystoneUserConflict + if req.status_code not in (200, 201): + LOGGER.error(req.text) + raise _exception + data = req.json() + return data + + def create_project(self, **tenant_dict): + if "name" not in tenant_dict: + raise KeystoneProjectError("Cannot get the project name.") + _project = { + "project": { + "description": tenant_dict['description'], + "domain_id": tenant_dict['domain'], + "enabled": tenant_dict['enabled'], + "is_domain": tenant_dict['is_domain'], + "name": tenant_dict['name'] + } + } + return self._post(endpoint="/projects/", + url=self.opst_conf["url"], + data=_project, + _exception=KeystoneProjectError) + + def get_projects(self): + return self._get(endpoint="/projects/", url=self.opst_conf["url"], _exception=KeystoneProjectError) + + def get_items(self, item_id=None, **kwargs): + raise NotImplementedError() # pragma: no cover + + def add_item(self, item_id=None, **kwargs): + raise NotImplementedError() # pragma: no cover + + def update_item(self, item_id, **kwargs): + raise NotImplementedError() # pragma: no cover + + def delete_item(self, item_id, **kwargs): + raise NotImplementedError() # pragma: no cover diff --git a/moon_manager/moon_manager/plugins/pyorchestrator.py b/moon_manager/moon_manager/plugins/pyorchestrator.py new file mode 100644 index 00000000..736e9144 --- /dev/null +++ b/moon_manager/moon_manager/plugins/pyorchestrator.py @@ -0,0 +1,493 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + +""" +PyOrchestrator plugin +""" +import logging +import os +import time +import subprocess # nosec +from uuid import uuid4 +import requests +import yaml +from moon_manager.orchestration_driver import SlaveDriver +from moon_manager.orchestration_driver import PipelineDriver +from moon_manager import db_driver +from moon_manager.api.configuration import get_configuration +from moon_utilities.auth_functions import get_api_key_for_user, xor_decode +from moon_utilities import exceptions +from datetime import datetime + +LOGGER = logging.getLogger("moon.manager.orchestrator.driver.pyorchestrator") + +PLUGIN_TYPE = "orchestration" +WRAPPERS = {} +PORTS = [] + + +def init(): + """ + Initialize the plugin by initializing wrappers + :return: nothing + """ + + slaves = db_driver.SlaveManager.get_slaves(moon_user_id="admin") + # TODO: check if server with UUID is not already up and running + for _slave in slaves: + LOGGER.info("testing PDP {}".format(_slave)) + if _slave not in WRAPPERS: + start_new_server(_slave, slaves[_slave]) + + +def create_gunicorn_config(host, port, uuid): + """ + Create a Gunicorn config file in a temporary directory + :return: filename + """ + config_dir = get_configuration("orchestration").get("config_dir", "/tmp") # nosec + # (/tmp is a fallback solution) + filename = os.path.join(config_dir, "gunicorn_{}.cfg".format(uuid)) + file_descriptor = open(filename, "w") + file_descriptor.write("""bind = "{host}:{port}" +workers = {workers} +moon = "{moon_filename}" + """.format( + host=host, + port=port, + workers=1, + moon_filename=os.path.join(config_dir, "moon_{}.yaml".format(uuid)), + )) + file_descriptor.close() + return filename + + +def create_moon_config(uuid, data): + """ + Create a Gunicorn config file in a temporary directory + :return: filename + """ + _log_config = get_configuration("logging") + config_dir = get_configuration("orchestration").get("config_dir", "/tmp") # nosec + # (/tmp is a fallback solution) + _log_config["handlers"]["file"]["filename"] = os.path.join(config_dir, + "moon_{}.log".format(uuid)) + __manager_url = get_configuration("management")["url"] + api_token = get_api_key_for_user(get_configuration("management")["user"]) + filename = os.path.join(config_dir, "moon_{}.yaml".format(uuid)) + pwd_file = os.path.join(get_configuration("orchestration")["config_dir"], + "db_{}.json".format(uuid)) + config_dict = { + "type": "wrapper", + "uuid": str(uuid), + "management": { + "url": __manager_url, + "user": get_configuration("management")["user"], + "password": get_configuration("management")["password"], + "token_file": pwd_file + }, + "incremental_updates": False, + "api_token": api_token, + "data": "", + "logging": _log_config, + "orchestration": { + "driver": "moon_engine.plugins.pyorchestrator", + "connection": "local", + "port": "20000...20100", + "config_dir": config_dir + }, + "authorization": {"driver": "moon_engine.plugins.authz"}, + "plugins": {"directory": get_configuration("plugins")["directory"]}, + "debug": get_configuration(key='debug', default=False), + "grant_if_unknown_project": data.get("grant_if_unknown_project") + } + LOGGER.info("Writing config file to {}".format(filename)) + yaml.dump(config_dict, open(filename, "w"), default_flow_style=False) + return filename + + +def kill_server(uuid): + """ + Kill the server given its UUID + :param uuid: UUID of the server + :return: nothing + """ + if uuid in WRAPPERS: + LOGGER.info("Killing server {} after {} of uptime".format( + uuid, str(datetime.now() - datetime.fromtimestamp(WRAPPERS[uuid]["starttime"])) + )) + with open(WRAPPERS[uuid]["process"], 'r') as pid_file: + try: + pid = int(pid_file.read()) + except ValueError: + LOGGER.error("The pid found in {} is not valid".format(WRAPPERS[uuid]["process"])) + return + + os.kill(pid, 15) + del_server_port(WRAPPERS[uuid]["port"]) + WRAPPERS.pop(uuid) + else: + LOGGER.warning("Cannot find UUID {} in wrappers or interfaces".format(uuid)) + + +def get_ports_range(): + """ + Get the range inside we can create new server + :return: (port_min, port_max) + """ + ports_range = get_configuration("orchestration")["port"] + return int(ports_range.split(".")[0]), int(ports_range.split(".")[-1]) + + +def get_next_port(server_host="127.0.0.1"): + """ + Check the next free TCP port for this host + :param server_host: the server host + :return: a TCP port (int) + """ + port_min, port_max = get_ports_range() + _port = port_min + _ports = [] + for _wrapper in WRAPPERS: + _ports.append(WRAPPERS[_wrapper]["port"]) + _ports.sort() + if not _ports: + _port = port_min + elif _ports[-1] + 1 > port_max: + raise Exception( + "Cannot add a new slave because " + "the port range is bounded to {}".format(port_max)) + while True: + if _port in _ports: + _port += 1 + continue + try: + requests.get("http://{}:{}/status".format(server_host, _port), timeout=1) + except requests.exceptions.ConnectionError: + break + if _port > port_max: + raise Exception( + "Cannot add a new slave because " + "the port range is bounded to {}".format(port_max)) + _port += 1 + return _port + + +def add_server_port(port): + """ + Append the server port in cache + :param port: TCP port + :return: None + """ + PORTS.append(port) + + +def del_server_port(port): + """ + Delete the server port in cache + :param port: TCP port + :return: None + """ + try: + PORTS.remove(port) + except ValueError: + LOGGER.warning("port {} is not in the known port".format(port)) + + +def get_server_url(uuid=None): + """ + Retrieve the server URL for this Slave ID + If no server can be found, return None + :param uuid: slave ID + :return: a URL or None + """ + if not uuid: + return + url = "" + try: + if uuid in WRAPPERS: + url = "http://{}:{}".format(WRAPPERS[uuid]["server_ip"], + WRAPPERS[uuid]["port"]) + LOGGER.debug(f"url in get_server_url '{url}'") + if url: + response = requests.get(url + "/status") + if response.status_code == 200: + return url + except TimeoutError as _exception: + LOGGER.warning("A timeout occurred when connecting to {}".format(url)) + # if port has not be found in local data, try to get information from remote servers + port_min, port_max = get_ports_range() + # FIXME: all servers may be not on localhost + host = "127.0.0.1" + LOGGER.debug(f"Go search through slaves") + for _port in range(port_min, port_max): + try: + req = requests.get("http://{}:{}/status".format(host, _port), timeout=1) + data = req.json() + if "status" in data and data["status"]["uuid"] == uuid: + return "http://{}:{}".format(host, _port) + except Exception as _exception: + LOGGER.warning("Error getting information from {}:{} ({})".format(host, _port, str(_exception))) + return + + +def start_new_server(uuid, data): + """Start a new server in a new process + + :param uuid: UUID of the server + :param data: data of the server + :return: nothing + """ + _url = get_server_url(uuid) + config_dir = get_configuration("orchestration").get("config_dir", "/tmp") # nosec + # (/tmp is a fallback solution) + config_filename = os.path.join(config_dir, "moon_{}.yaml".format(uuid)) + # FIXME: maybe the server is not on the 127.0.0.1 + server_ip = "127.0.0.1" + LOGGER.info("Starting server {} {}".format(_url, uuid)) + # debug = get_configuration("debug", False) + if _url: + _port = int(_url.split(":")[-1]) + add_server_port(_port) + WRAPPERS[uuid] = { + "starttime": data["extra"].get("starttime"), + "port": _port, + "server_ip": server_ip, + "name": data.get("name"), + "status": "up", + "process": data.get("process"), + "api_key": data.get("api_key"), + "log": data.get("log") + } + else: + _port = get_next_port() + pid_file = os.path.join(config_dir, uuid + ".pid") + # NOTE: we have actually no solution to get the actual IP address + # so we need to put 0.0.0.0 in the host address + gunicorn_config = create_gunicorn_config(host="0.0.0.0", # nosec + port=_port, + uuid=uuid) + create_moon_config(uuid=uuid, data=data) + _command = ["gunicorn", "moon_engine.server:__hug_wsgi__", "--threads", "10", + "--log-level", "debug", "--log-file", gunicorn_config.replace("cfg", "log"), + "-p", pid_file, "-c", gunicorn_config] + LOGGER.info("command: {}".format(" ".join(_command))) + WRAPPERS[uuid] = { + "starttime": time.time(), + "port": _port, + "server_ip": server_ip, + "name": data.get("name"), + "status": "down", + "process": pid_file, + } + subprocess.Popen(_command, stdout=subprocess.PIPE, close_fds=True) # nosec + # Note: wait the process creation + time.sleep(1) + config = yaml.safe_load(open(config_filename)) + log_file = config["logging"]["handlers"]["file"]["filename"] + WRAPPERS[uuid]["log"] = log_file + for cpt in range(10): + try: + f_sock = open(log_file) + except FileNotFoundError: + time.sleep(1) + else: + break + else: + LOGGER.error("Cannot find log file ({})".format(log_file)) + return + p_sock = 0 + LOGGER.info("Process running") + WRAPPERS[uuid]["status"] = "up" + while True: + f_sock.seek(p_sock) + latest_data = f_sock.read() + p_sock = f_sock.tell() + if latest_data and "APIKEY" in latest_data: + _index_start = latest_data.index("APIKEY=") + len("APIKEY=") + _index_stop = latest_data.index("\n", _index_start) + key = latest_data[_index_start:_index_stop].strip() + api_key = get_api_key_for_user("admin") + try: + engine_api_key = xor_decode(key, api_key) + LOGGER.info(f"key={key}") + LOGGER.info(f"engine_api_key={engine_api_key}") + except exceptions.DecryptError: + engine_api_key = False + WRAPPERS[uuid]["api_key"] = engine_api_key + break + time.sleep(1) + + +class SlaveConnector(SlaveDriver): + """ + Connector to Slave API + """ + + def __init__(self, driver_name, engine_name): + self.driver_name = driver_name + self.engine_name = engine_name + + def update_slave(self, slave_id, value): + LOGGER.info("Updating the slave {} with {}".format(slave_id, value)) + slave_url = WRAPPERS[slave_id]['server_ip'] + slave_port = WRAPPERS[slave_id]['port'] + + config_dir = get_configuration("orchestration").get("config_dir", "/tmp") # nosec + config_filename = os.path.join(config_dir, "moon_{}.yaml".format(slave_id)) + + conf = yaml.safe_load(open(config_filename, 'r')) + for key in value: + if key in conf: + conf[key] = value[key] + + os.remove(config_filename) + yaml.dump(conf, open(config_filename, "w"), default_flow_style=False) + + req = requests.put("http://{}:{}/update".format(slave_url, slave_port), + headers={"x-api-key": WRAPPERS[slave_id]["api_key"]}) + return req + + def delete_slave(self, slave_id): + LOGGER.info("Deleting slave {}".format(slave_id)) + kill_server(slave_id) + + def add_slave(self, slave_id=None, data=None): + LOGGER.info("Adding slave {} {}".format(slave_id, data)) + if not slave_id: + slave_id = uuid4().hex + start_new_server(slave_id, data) + return WRAPPERS[slave_id] + + def get_slaves(self, slave_id=None): + LOGGER.info("Get slaves {}".format(WRAPPERS)) + results = {} + for wrapper in WRAPPERS: + results[wrapper] = { + "starttime": WRAPPERS[wrapper]["starttime"], + "port": WRAPPERS[wrapper]["port"], + "server_ip": WRAPPERS[wrapper]["server_ip"], + "name": WRAPPERS[wrapper]["name"], + "status": "down", + "log": WRAPPERS[wrapper]["log"] + } + try: + req = requests.get("http://{}:{}/status".format( + WRAPPERS[wrapper]["server_ip"], + WRAPPERS[wrapper]["port"] + )) + if req.status_code == 200: + results[wrapper]["status"] = "up" + else: + results[wrapper]["status"] = "down" + LOGGER.info("get_slaves: {} {} {}".format( + slave_id, req.status_code, results[wrapper]["status"])) + except TimeoutError: + LOGGER.warning("Timeout connecting {} on port {}".format( + WRAPPERS[wrapper]["server_ip"], + WRAPPERS[wrapper]["port"] + )) + except requests.exceptions.ConnectionError: + results[wrapper]["status"] = "down" + return results + + +class PipelineConnector(PipelineDriver): + """ + Connector to Pipeline API + """ + + def __init__(self, driver_name, engine_name): + self.driver_name = driver_name + self.engine_name = engine_name + + def update_pipeline(self, pipeline_id, data): + for _wrapper in WRAPPERS: + _url = get_server_url(_wrapper) + req = requests.put("{}/update/pdp/{}".format(_url, pipeline_id), + headers={"x-api-key": WRAPPERS[_wrapper]["api_key"]}, + json=data) + if req.status_code == 206: + LOGGER.warning("No pipeline available...") + elif req.status_code != 202: + LOGGER.warning("Error sending upgrade command to pipeline ({})".format(req.text)) + + def delete_pipeline(self, pipeline_id): + LOGGER.info("Deleting pipeline {}".format(pipeline_id)) + for _wrapper in WRAPPERS: + if WRAPPERS[_wrapper]['status'] == "down": + continue + # FIXME: we should manage https here + _url = "http://{}:{}".format(WRAPPERS[_wrapper]['server_ip'], + WRAPPERS[_wrapper]['port']) + req = requests.delete("{}/pipeline/{}".format(_url, pipeline_id), + headers={"x-api-key": WRAPPERS[_wrapper]["api_key"]}) + LOGGER.info("{}/pipeline/{}".format(_url, pipeline_id)) + if req.status_code != 200: + LOGGER.error("Cannot delete the pipeline in slave {} ({}, {})".format( + _wrapper, req.status_code, req.content)) + # FIXME: make a request to the correct wrapper + + def add_pipeline(self, pipeline_id=None, data=None): + LOGGER.info("Adding POD in manager {} {}".format(pipeline_id, data)) + if not pipeline_id: + pipeline_id = uuid4().hex + slaves = data.get("slaves", []) + pipelines = [] + for _wrapper in WRAPPERS: + if slaves and (WRAPPERS[_wrapper]['name'] not in slaves): + continue + # FIXME: we should manage https here + _url = "http://{}:{}".format(WRAPPERS[_wrapper]['server_ip'], + WRAPPERS[_wrapper]['port']) + req = requests.put("{}/pipeline/{}".format(_url, pipeline_id), json=data, + headers={"x-api-key": WRAPPERS[_wrapper]['api_key']}) + if req.status_code != 200: + LOGGER.error("Cannot create a new pipeline ({}, {})".format(req.status_code, + req.content)) + elif "pipelines" not in req.json(): + LOGGER.error("Cannot create a new pipeline ({}, {})".format(req.status_code, + req.content)) + else: + pipelines.append(req.json()) + LOGGER.info("Pipeline created {}".format(pipelines)) + return pipelines + # FIXME: make a request to the correct wrapper + + def get_pipelines(self, slave_id=None, pipeline_id=None): + results = {} + for _wrapper in WRAPPERS: + if slave_id and _wrapper != slave_id: + continue + if WRAPPERS[_wrapper]['status'] == "down": + continue + results[_wrapper] = {} + # FIXME: we should manage https here + _url = "http://{}:{}".format(WRAPPERS[_wrapper]['server_ip'], + WRAPPERS[_wrapper]['port']) + req = requests.get("{}/pipelines".format(_url), + headers={"x-api-key": WRAPPERS[_wrapper]['api_key']}) + if req.status_code != 200: + LOGGER.error("Cannot get information for slave {} ({}, {})".format( + _wrapper, req.status_code, req.content)) + else: + # FIXME: filter on pipeline_id + results[_wrapper] = req.json() + return results + + +class Connector(SlaveConnector, PipelineConnector): + """ + General connector to get all APIs in one endpoint + """ + + def __init__(self, *args, **kwargs): + init() diff --git a/moon_manager/moon_manager/plugins/sql.py b/moon_manager/moon_manager/plugins/sql.py new file mode 100644 index 00000000..de850a5c --- /dev/null +++ b/moon_manager/moon_manager/plugins/sql.py @@ -0,0 +1,2085 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +import copy +import json +import logging +from contextlib import contextmanager +from uuid import uuid4 + +import sqlalchemy +import sqlalchemy as sql +from moon_manager.api import configuration +from moon_manager.db_driver import PDPDriver, PolicyDriver, ModelDriver, SlaveDriver +from moon_utilities import exceptions +from sqlalchemy import create_engine +from sqlalchemy import types as sql_types +from sqlalchemy.ext.declarative import declarative_base, declared_attr +from sqlalchemy.orm import sessionmaker + +logger = logging.getLogger("moon.manager.db.driver.sql") + +PLUGIN_TYPE = "db" + +Base = declarative_base() +DEBUG = True if configuration.get_configuration( + "logging")['loggers']['moon']['level'] == "DEBUG" else False + + +class DictBase: + attributes = [] + + @classmethod + def from_dict(cls, d): + new_d = d.copy() + return cls(**new_d) + # new_d = d.copy() + # + # new_d['extra'] = {k: new_d.pop(k) for k in six.iterkeys(d) + # if k not in cls.attributes and k != 'extra'} + # + # return cls(**new_d) + + def to_dict(self): + d = dict() + for attr in self.__class__.attributes: + d[attr] = getattr(self, attr) + return d + + def __getitem__(self, key): + # if "extra" in dir(self) and key in self.extra: + # return self.extra[key] + return getattr(self, key) + + +class JsonBlob(sql_types.TypeDecorator): + impl = sql.Text + + def process_bind_param(self, value, dialect): + return json.dumps(value) + + def process_result_value(self, value, dialect): + return json.loads(value) + + +class Model(Base, DictBase): + __tablename__ = 'models' + attributes = ['id', 'name', 'value'] + id = sql.Column(sql.String(64), primary_key=True) + name = sql.Column(sql.String(256), nullable=False) + value = sql.Column(JsonBlob(), nullable=True) + + def to_dict(self): + return { + "name": self.name, + "description": self.value.get("description", ""), + "meta_rules": self.value.get("meta_rules", list()), + } + + +class Policy(Base, DictBase): + __tablename__ = 'policies' + attributes = ['id', 'name', 'model_id', 'value'] + id = sql.Column(sql.String(64), primary_key=True) + name = sql.Column(sql.String(256), nullable=False) + model_id = sql.Column(sql.String(64), nullable=True, default="") + value = sql.Column(JsonBlob(), nullable=True) + + def to_dict(self): + return { + "description": self.value.get("description", ""), + "genre": self.value.get("genre", ""), + "model_id": self.model_id, + "name": self.name + } + + +class PDP(Base, DictBase): + __tablename__ = 'pdp' + attributes = ['id', 'name', 'vim_project_id', 'value'] + id = sql.Column(sql.String(64), primary_key=True) + name = sql.Column(sql.String(256), nullable=False) + vim_project_id = sql.Column(sql.String(64), nullable=True, default="") + value = sql.Column(JsonBlob(), nullable=True) + + def to_dict(self): + return { + "name": self.name, + "description": self.value.get("description", ""), + "vim_project_id": self.vim_project_id, + "security_pipeline": self.value.get("security_pipeline", []), + } + + +class Slave(Base, DictBase): + __tablename__ = 'slaves' + attributes = ['id', 'name', 'address', 'process', 'log', 'api_key', 'value'] + id = sql.Column(sql.String(64), primary_key=True) + name = sql.Column(sql.String(256), nullable=False) + address = sql.Column(sql.String(256), nullable=True, default="") + process = sql.Column(sql.String(256), nullable=False, default="") + log = sql.Column(sql.String(256), nullable=False, default="") + api_key = sql.Column(sql.String(256), nullable=False, default="") + value = sql.Column(JsonBlob(), nullable=True) + grant_if_unknown_project = sql.Column(sql.Boolean(), nullable=False, default=True) + + def to_dict(self): + return { + "name": self.name, + "address": self.address, + "description": self.value.get("description", ""), + "grant_if_unknown_project": self.grant_if_unknown_project, + "process": self.process, + "log": self.log, + "api_key": self.api_key, + "extra": self.value + } + + +class PerimeterCategoryBase(DictBase): + attributes = ['id', 'name', 'description'] + id = sql.Column(sql.String(64), primary_key=True) + name = sql.Column(sql.String(256), nullable=False) + description = sql.Column(sql.String(256), nullable=True) + + +class SubjectCategory(Base, PerimeterCategoryBase): + __tablename__ = 'subject_categories' + + +class ObjectCategory(Base, PerimeterCategoryBase): + __tablename__ = 'object_categories' + + +class ActionCategory(Base, PerimeterCategoryBase): + __tablename__ = 'action_categories' + + +class PerimeterBase(DictBase): + attributes = ['id', 'name', 'value'] + id = sql.Column(sql.String(64), primary_key=True) + name = sql.Column(sql.String(256), nullable=False) + value = sql.Column(JsonBlob(), nullable=True) + __mapper_args__ = {'concrete': True} + + def __repr__(self): + return "{} with name {} : {}".format(self.id, self.name, json.dumps(self.value)) + + def to_return(self): + return { + 'id': self.id, + 'name': self.name, + 'description': self.value.get("description", ""), + 'email': self.value.get("email", ""), + 'extra': self.value.get("extra", dict()), + 'policy_list': self.value.get("policy_list", []) + } + + def to_dict(self): + dict_value = copy.deepcopy(self.value) + dict_value["name"] = self.name + return { + 'id': self.id, + 'value': dict_value + } + + +class Subject(Base, PerimeterBase): + __tablename__ = 'subjects' + + +class Object(Base, PerimeterBase): + __tablename__ = 'objects' + + +class Action(Base, PerimeterBase): + __tablename__ = 'actions' + + +class PerimeterDataBase(DictBase): + attributes = ['id', 'name', 'value', 'category_id', 'policy_id'] + id = sql.Column(sql.String(64), primary_key=True) + name = sql.Column(sql.String(256), nullable=False) + value = sql.Column(JsonBlob(), nullable=True) + + @declared_attr + def policy_id(cls): + return sql.Column(sql.ForeignKey("policies.id"), nullable=False) + + def to_dict(self): + return { + 'id': self.id, + 'name': self.name, + 'description': self.value.get("description", ""), + 'category_id': self.category_id, + 'policy_id': self.policy_id + } + + +class SubjectData(Base, PerimeterDataBase): + __tablename__ = 'subject_data' + category_id = sql.Column(sql.ForeignKey("subject_categories.id"), nullable=False) + + +class ObjectData(Base, PerimeterDataBase): + __tablename__ = 'object_data' + category_id = sql.Column(sql.ForeignKey("object_categories.id"), nullable=False) + + +class ActionData(Base, PerimeterDataBase): + __tablename__ = 'action_data' + category_id = sql.Column(sql.ForeignKey("action_categories.id"), nullable=False) + + +class PerimeterAssignmentBase(DictBase): + attributes = ['id', 'assignments', 'policy_id', 'subject_id', 'category_id'] + id = sql.Column(sql.String(64), primary_key=True) + assignments = sql.Column(JsonBlob(), nullable=True) + category_id = None + + @declared_attr + def policy_id(cls): + return sql.Column(sql.ForeignKey("policies.id"), nullable=False) + + def _to_dict(self, element_key, element_value): + return { + "id": self.id, + "policy_id": self.policy_id, + element_key: element_value, + "category_id": self.category_id, + "assignments": self.assignments, + } + + +class SubjectAssignment(Base, PerimeterAssignmentBase): + __tablename__ = 'subject_assignments' + subject_id = sql.Column(sql.ForeignKey("subjects.id"), nullable=False) + category_id = sql.Column(sql.ForeignKey("subject_categories.id"), nullable=False) + + def to_dict(self): + return self._to_dict("subject_id", self.subject_id) + + +class ObjectAssignment(Base, PerimeterAssignmentBase): + __tablename__ = 'object_assignments' + attributes = ['id', 'assignments', 'policy_id', 'object_id', 'category_id'] + object_id = sql.Column(sql.ForeignKey("objects.id"), nullable=False) + category_id = sql.Column(sql.ForeignKey("object_categories.id"), nullable=False) + + def to_dict(self): + return self._to_dict("object_id", self.object_id) + + +class ActionAssignment(Base, PerimeterAssignmentBase): + __tablename__ = 'action_assignments' + attributes = ['id', 'assignments', 'policy_id', 'action_id', 'category_id'] + action_id = sql.Column(sql.ForeignKey("actions.id"), nullable=False) + category_id = sql.Column(sql.ForeignKey("action_categories.id"), nullable=False) + + def to_dict(self): + return self._to_dict("action_id", self.action_id) + + +class MetaRule(Base, DictBase): + __tablename__ = 'meta_rules' + attributes = ['id', 'name', 'subject_categories', 'object_categories', 'action_categories', + 'value'] + id = sql.Column(sql.String(64), primary_key=True) + name = sql.Column(sql.String(256), nullable=False) + subject_categories = sql.Column(JsonBlob(), nullable=True) + object_categories = sql.Column(JsonBlob(), nullable=True) + action_categories = sql.Column(JsonBlob(), nullable=True) + value = sql.Column(JsonBlob(), nullable=True) + + def to_dict(self): + return { + "name": self.name, + "description": self.value.get("description", ""), + "subject_categories": self.subject_categories, + "object_categories": self.object_categories, + "action_categories": self.action_categories, + } + + +class Rule(Base, DictBase): + __tablename__ = 'rules' + attributes = ['id', 'rule', 'policy_id', 'meta_rule_id'] + id = sql.Column(sql.String(64), primary_key=True) + rule = sql.Column(JsonBlob(), nullable=True) + policy_id = sql.Column(sql.ForeignKey("policies.id"), nullable=False) + meta_rule_id = sql.Column(sql.ForeignKey("meta_rules.id"), nullable=False) + + def to_dict(self): + return { + 'id': self.id, + 'rule': self.rule["rule"], + 'instructions': self.rule["instructions"], + 'enabled': self.rule["enabled"], + 'policy_id': self.policy_id, + 'meta_rule_id': self.meta_rule_id + } + + def __repr__(self): + return "{}".format(self.rule) + + +@contextmanager +def session_scope(engine): + """Provide a transactional scope around a series of operations.""" + if type(engine) is str: + echo = DEBUG + engine = create_engine(engine, echo=echo) + session = sessionmaker(bind=engine)() + try: + yield session + session.commit() + except: + session.rollback() + raise + finally: + session.close() + + +class BaseConnector(object): + """Provide a base connector to connect them all""" + engine = "" + + def __init__(self, engine_name): + echo = DEBUG + self.engine = create_engine(engine_name, echo=echo) + + def init_db(self): + Base.metadata.create_all(self.engine) + + def set_engine(self, engine_name): + self.engine = engine_name + + def get_session(self): + return session_scope(self.engine) + + def get_session_for_read(self): + return self.get_session() + + def get_session_for_write(self): + return self.get_session() + + +class PDPConnector(BaseConnector, PDPDriver): + + def update_pdp(self, pdp_id, value): + try: + with self.get_session_for_write() as session: + query = session.query(PDP) + query = query.filter_by(id=pdp_id) + ref = query.first() + if ref: + value_wo_name = copy.deepcopy(value) + value_wo_name.pop("name", None) + value_wo_name.pop("vim_project_id", None) + ref.name = value["name"] + ref.vim_project_id = value.get("vim_project_id", "") + d = dict(ref.value) + d.update(value_wo_name) + setattr(ref, "value", d) + return {ref.id: ref.to_dict()} + except sqlalchemy.exc.IntegrityError as error: + if 'UNIQUE constraint' in str(error) or 'Duplicate entry' in str(error): + raise exceptions.PdpExisting + raise error + + def delete_policy_from_pdp(self, pdp_id, policy_id): + with self.get_session_for_write() as session: + ref = session.query(PDP).get(pdp_id) + if ref: + if policy_id in ref.value['security_pipeline']: + __value = copy.deepcopy(ref.value) + __value['security_pipeline'].remove(policy_id) + setattr(ref, "value", __value) + return {ref.id: ref.to_dict()} + return {} + + def delete_pdp(self, pdp_id): + with self.get_session_for_write() as session: + ref = session.query(PDP).get(pdp_id) + session.delete(ref) + + def add_pdp(self, pdp_id=None, value=None): + try: + with self.get_session_for_write() as session: + value_wo_name = copy.deepcopy(value) + value_wo_name.pop("name", None) + value_wo_name.pop("vim_project_id", None) + new = PDP.from_dict({ + "id": pdp_id if pdp_id else uuid4().hex, + "name": value["name"], + "vim_project_id": value["vim_project_id"], + "value": value_wo_name + }) + session.add(new) + return {new.id: new.to_dict()} + except sqlalchemy.exc.IntegrityError as error: + if 'UNIQUE constraint' in str(error) or 'Duplicate entry' in str(error): + raise exceptions.PdpExisting + raise error + + def get_pdp(self, pdp_id=None): + with self.get_session_for_read() as session: + query = session.query(PDP) + if pdp_id: + query = query.filter_by(id=pdp_id) + ref_list = query.all() + return {_ref.id: _ref.to_dict() for _ref in ref_list} + + +class SlaveConnector(BaseConnector, SlaveDriver): + + def update_slave(self, slave_id, value): + try: + with self.get_session_for_write() as session: + query = session.query(Slave) + query = query.filter_by(id=slave_id) + ref = query.first() + if ref: + value_wo_name = copy.deepcopy(value) + value_wo_name.pop("name", None) + value_wo_name.pop("address", None) + value_wo_name.pop("grant_if_unknown_project", None) + # ref.name = value["name"] + if 'address' in value: + ref.address = value.get("address") + if 'grant_if_unknown_project' in value: + ref.grant_if_unknown_project = value.get("grant_if_unknown_project") + d = dict(ref.value) + d.update(value_wo_name) + setattr(ref, "value", d) + return {ref.id: ref.to_dict()} + except sqlalchemy.exc.IntegrityError as error: + if 'UNIQUE constraint' in str(error) or 'Duplicate entry' in str(error): + raise exceptions.PdpExisting + raise error + + def delete_slave(self, slave_id): + with self.get_session_for_write() as session: + ref = session.query(Slave).get(slave_id) + session.delete(ref) + + def add_slave(self, slave_id=None, value=None): + try: + with self.get_session_for_write() as session: + value_wo_name = copy.deepcopy(value) + value_wo_name.pop("name", None) + value_wo_name.pop("address", None) + value_wo_name.pop("grant_if_unknown_project", None) + new = Slave.from_dict({ + "id": slave_id if slave_id else uuid4().hex, + "name": value["name"], + "address": value.get("address", ""), + "grant_if_unknown_project": value.get("grant_if_unknown_project"), + "log": "", + "process": "", + "api_key": "", + "value": value_wo_name + }) + session.add(new) + return {new.id: new.to_dict()} + except sqlalchemy.exc.IntegrityError as error: + if 'UNIQUE constraint' in str(error) or 'Duplicate entry' in str(error): + raise exceptions.PdpExisting + raise error + + def get_slaves(self, slave_id=None): + with self.get_session_for_read() as session: + query = session.query(Slave) + if slave_id: + query = query.filter_by(id=slave_id) + ref_list = query.all() + return {_ref.id: _ref.to_dict() for _ref in ref_list} + + +class PolicyConnector(BaseConnector, PolicyDriver): + + def update_policy(self, policy_id, value): + try: + with self.get_session_for_write() as session: + query = session.query(Policy) + query = query.filter_by(id=policy_id) + ref = query.first() + + if ref: + value_wo_other_info = copy.deepcopy(value) + value_wo_other_info.pop("name", None) + value_wo_other_info.pop("model_id", None) + ref.name = value["name"] + ref.model_id = value["model_id"] + d = dict(ref.value) + d.update(value_wo_other_info) + setattr(ref, "value", d) + return {ref.id: ref.to_dict()} + + except sqlalchemy.exc.IntegrityError as error: + if 'UNIQUE constraint' in str(error) or 'Duplicate entry' in str(error): + raise exceptions.PolicyExisting + raise error + + def delete_policy(self, policy_id): + with self.get_session_for_write() as session: + ref = session.query(Policy).get(policy_id) + session.delete(ref) + + def add_policy(self, policy_id=None, value=None): + try: + with self.get_session_for_write() as session: + value_wo_other_info = copy.deepcopy(value) + value_wo_other_info.pop("name", None) + value_wo_other_info.pop("model_id", None) + new = Policy.from_dict({ + "id": policy_id if policy_id else uuid4().hex, + "name": value["name"], + "model_id": value.get("model_id", ""), + "value": value_wo_other_info + }) + session.add(new) + return {new.id: new.to_dict()} + + except sqlalchemy.exc.IntegrityError as error: + if 'UNIQUE constraint' in str(error) or 'Duplicate entry' in str(error): + raise exceptions.PolicyExisting + raise error + + def get_policies(self, policy_id=None, policy_name=None): + with self.get_session_for_read() as session: + query = session.query(Policy) + if policy_id: + query = query.filter_by(id=policy_id) + elif policy_name: + query = query.filter_by(name=policy_name) + + ref_list = query.all() + return {_ref.id: _ref.to_dict() for _ref in ref_list} + + def __get_perimeters(self, ClassType, policy_id, perimeter_id=None): + + with self.get_session_for_read() as session: + query = session.query(ClassType) + + if perimeter_id: + query = query.filter_by(id=perimeter_id) + + ref_list = copy.deepcopy(query.all()) + + if policy_id: + results = [] + for _ref in ref_list: + _ref_value = _ref.to_return() + if policy_id in _ref_value["policy_list"]: + results.append(_ref) + return {_ref.id: _ref.to_return() for _ref in results} + return {_ref.id: _ref.to_return() for _ref in ref_list} + + def __get_perimeter_by_name(self, ClassType, perimeter_name): + # if not policy_id: + # raise exceptions.PolicyUnknown + with self.get_session_for_read() as session: + query = session.query(ClassType) + if not perimeter_name or not perimeter_name.strip(): + raise exceptions.PerimeterContentError('invalid name') + query = query.filter_by(name=perimeter_name) + ref_list = copy.deepcopy(query.all()) + return {_ref.id: _ref.to_return() for _ref in ref_list} + + def __update_perimeter(self, class_type, class_type_exception, perimeter_id, value): + if not perimeter_id: + return exceptions.PerimeterContentError + with self.get_session_for_write() as session: + query = session.query(class_type) + query = query.filter_by(id=perimeter_id) + _perimeter = query.first() + if not _perimeter: + raise class_type_exception + temp_perimeter = copy.deepcopy(_perimeter.to_dict()) + if 'name' in value: + temp_perimeter['value']['name'] = value['name'] + if 'description' in value: + temp_perimeter['value']['description'] = value['description'] + if 'extra' in value: + temp_perimeter['value']['extra'] = value['extra'] + if 'email' in value: + temp_perimeter['value']['email'] = value['email'] + name = temp_perimeter['value']['name'] + temp_perimeter['value'].pop("name", None) + new_perimeter = class_type.from_dict({ + "id": temp_perimeter["id"], + "name": name, + "value": temp_perimeter["value"] + }) + _perimeter.value = new_perimeter.value + _perimeter.name = new_perimeter.name + return {_perimeter.id: _perimeter.to_return()} + + def __set_perimeter(self, ClassType, ClassTypeException, policy_id, perimeter_id=None, + value=None): + if not value or "name" not in value or not value["name"].strip(): + raise exceptions.PerimeterContentError('invalid name') + with self.get_session_for_write() as session: + _perimeter = None + if perimeter_id: + query = session.query(ClassType) + query = query.filter_by(id=perimeter_id) + _perimeter = query.first() + if not perimeter_id and not _perimeter: + query = session.query(ClassType) + query = query.filter_by(name=value['name']) + _perimeter = query.first() + if _perimeter: + raise ClassTypeException + if not _perimeter: + value_wo_name = copy.deepcopy(value) + if "policy_list" not in value_wo_name or type( + value_wo_name["policy_list"]) is not list: + value_wo_name["policy_list"] = [] + if policy_id and policy_id not in value_wo_name["policy_list"]: + value_wo_name["policy_list"] = [policy_id, ] + + value_wo_name.pop("name", None) + new = ClassType.from_dict({ + "id": perimeter_id if perimeter_id else uuid4().hex, + "name": value["name"], + "value": value_wo_name + }) + session.add(new) + return {new.id: new.to_return()} + else: + _value = copy.deepcopy(_perimeter.to_dict()) + if "policy_list" not in _value["value"] or type( + _value["value"]["policy_list"]) is not list: + _value["value"]["policy_list"] = [] + if policy_id and policy_id not in _value["value"]["policy_list"]: + _value["value"]["policy_list"].append(policy_id) + else: + if policy_id: + raise exceptions.PolicyExisting + raise exceptions.PerimeterContentError + + _value["value"].update(value) + + name = _value["value"]["name"] + _value["value"].pop("name") + new_perimeter = ClassType.from_dict({ + "id": _value["id"], + "name": name, + "value": _value["value"] + }) + _perimeter.value = new_perimeter.value + _perimeter.name = new_perimeter.name + return {_perimeter.id: _perimeter.to_return()} + + def __delete_perimeter(self, ClassType, ClassUnknownException, policy_id, perimeter_id): + with self.get_session_for_write() as session: + query = session.query(ClassType) + query = query.filter_by(id=perimeter_id) + _perimeter = query.first() + if not _perimeter: + raise ClassUnknownException + if not _perimeter.value["policy_list"]: + session.delete(_perimeter) + else: + if not policy_id: + raise exceptions.PolicyUnknown + + old_perimeter = copy.deepcopy(_perimeter.to_dict()) + try: + old_perimeter["value"]["policy_list"].remove(policy_id) + new_perimeter = ClassType.from_dict(old_perimeter) + + + # else: + # if new_perimeter.value["policy_list"]: + setattr(_perimeter, "value", getattr(new_perimeter, "value")) + except ValueError: + if not _perimeter.value["policy_list"]: + session.delete(_perimeter) + + def get_subjects(self, policy_id, perimeter_id=None): + return self.__get_perimeters(Subject, policy_id, perimeter_id) + + def get_subject_by_name(self, perimeter_name): + return self.__get_perimeter_by_name(Subject, perimeter_name) + + def set_subject(self, policy_id, perimeter_id=None, value=None): + try: + return self.__set_perimeter(Subject, exceptions.SubjectExisting, policy_id, + perimeter_id=perimeter_id, value=value) + except sqlalchemy.exc.IntegrityError as error: + if 'UNIQUE constraint' in str(error) or 'Duplicate entry' in str(error): + raise exceptions.SubjectExisting + raise error + + def update_subject(self, perimeter_id, value): + try: + return self.__update_perimeter(Subject, exceptions.SubjectExisting, perimeter_id, value) + except sqlalchemy.exc.IntegrityError as error: + if 'UNIQUE constraint' in str(error) or 'Duplicate entry' in str(error): + raise exceptions.SubjectExisting + raise error + + def delete_subject(self, policy_id, perimeter_id): + self.__delete_perimeter(Subject, exceptions.SubjectUnknown, policy_id, perimeter_id) + + def get_objects(self, policy_id, perimeter_id=None): + return self.__get_perimeters(Object, policy_id, perimeter_id) + + def get_object_by_name(self, perimeter_name): + return self.__get_perimeter_by_name(Object, perimeter_name) + + def set_object(self, policy_id, perimeter_id=None, value=None): + try: + return self.__set_perimeter(Object, exceptions.ObjectExisting, policy_id, + perimeter_id=perimeter_id, value=value) + except sqlalchemy.exc.IntegrityError as error: + logger.exception("IntegrityError {}".format(error)) + if 'UNIQUE constraint' in str(error) or 'Duplicate entry' in str(error): + raise exceptions.ObjectExisting + raise error + + def update_object(self, perimeter_id, value): + try: + return self.__update_perimeter(Object, exceptions.ObjectExisting, perimeter_id, value) + except sqlalchemy.exc.IntegrityError as error: + if 'UNIQUE constraint' in str(error) or 'Duplicate entry' in str(error): + raise exceptions.ObjectExisting + raise error + + def delete_object(self, policy_id, perimeter_id): + self.__delete_perimeter(Object, exceptions.ObjectUnknown, policy_id, perimeter_id) + + def get_actions(self, policy_id, perimeter_id=None): + return self.__get_perimeters(Action, policy_id, perimeter_id) + + def get_action_by_name(self, perimeter_name): + return self.__get_perimeter_by_name(Action, perimeter_name) + + def set_action(self, policy_id, perimeter_id=None, value=None): + try: + return self.__set_perimeter(Action, exceptions.ActionExisting, policy_id, + perimeter_id=perimeter_id, value=value) + except sqlalchemy.exc.IntegrityError as error: + if 'UNIQUE constraint' in str(error) or 'Duplicate entry' in str(error): + raise exceptions.ActionExisting + raise error + + def update_action(self, perimeter_id, value): + try: + return self.__update_perimeter(Action, exceptions.ActionExisting, perimeter_id, value) + except sqlalchemy.exc.IntegrityError as error: + if 'UNIQUE constraint' in str(error) or 'Duplicate entry' in str(error): + raise exceptions.ActionExisting + raise error + + def delete_action(self, policy_id, perimeter_id): + self.__delete_perimeter(Action, exceptions.ActionUnknown, policy_id, perimeter_id) + + def __is_data_exist(self, ClassType, category_id=None): + + with self.get_session_for_read() as session: + query = session.query(ClassType) + query = query.filter_by(category_id=category_id) + ref_list = query.all() + if ref_list: + return True + return False + + def __get_data(self, ClassType, policy_id, data_id=None, category_id=None): + with self.get_session_for_read() as session: + query = session.query(ClassType) + if policy_id and data_id and category_id: + query = query.filter_by(policy_id=policy_id, id=data_id, category_id=category_id) + elif policy_id and category_id: + query = query.filter_by(policy_id=policy_id, category_id=category_id) + elif category_id: + query = query.filter_by(category_id=category_id) + elif policy_id: + query = query.filter_by(policy_id=policy_id) + else: + raise exceptions.PolicyUnknown + + ref_list = query.all() + return { + "policy_id": policy_id, + "category_id": category_id, + "data": {_ref.id: _ref.to_dict() for _ref in ref_list} + } + + def __set_data(self, ClassType, ClassTypeData, policy_id, data_id=None, category_id=None, + value=None): + with self.get_session_for_write() as session: + query = session.query(ClassTypeData) + query = query.filter_by(policy_id=policy_id, id=data_id, category_id=category_id) + ref = query.first() + if not ref: + value_wo_name = copy.deepcopy(value) + value_wo_name.pop("name", None) + new_ref = ClassTypeData.from_dict( + { + "id": data_id if data_id else uuid4().hex, + 'name': value["name"], + 'value': value_wo_name, + 'category_id': category_id, + 'policy_id': policy_id, + } + ) + session.add(new_ref) + ref = new_ref + else: + for attr in ClassType.attributes: + if attr != 'id': + setattr(ref, attr, getattr(ref, attr)) + # session.flush() + return { + "policy_id": policy_id, + "category_id": category_id, + "data": {ref.id: ref.to_dict()} + } + + def __delete_data(self, ClassType, policy_id, category_id, data_id): + + if not data_id: + raise exceptions.DataUnknown + with self.get_session_for_write() as session: + query = session.query(ClassType) + if category_id: + query = query.filter_by(policy_id=policy_id, category_id=category_id, id=data_id) + else: + query = query.filter_by(policy_id=policy_id, id=data_id) + ref = query.first() + if ref: + session.delete(ref) + + def is_subject_data_exist(self, category_id=None): + return self.__is_data_exist(SubjectData, category_id=category_id) + + def get_subject_data(self, policy_id, data_id=None, category_id=None): + return self.__get_data(SubjectData, policy_id, data_id=data_id, category_id=category_id) + + def set_subject_data(self, policy_id, data_id=None, category_id=None, value=None): + try: + return self.__set_data(Subject, SubjectData, policy_id, data_id=data_id, + category_id=category_id, value=value) + except sqlalchemy.exc.IntegrityError as error: + if 'UNIQUE constraint' in str(error) or 'Duplicate entry' in str(error): + raise exceptions.SubjectScopeExisting + raise error + + def delete_subject_data(self, policy_id, category_id, data_id): + return self.__delete_data(SubjectData, policy_id, category_id, data_id) + + def is_object_data_exist(self, category_id=None): + return self.__is_data_exist(ObjectData, category_id=category_id) + + def get_object_data(self, policy_id, data_id=None, category_id=None): + return self.__get_data(ObjectData, policy_id, data_id=data_id, category_id=category_id) + + def set_object_data(self, policy_id, data_id=None, category_id=None, value=None): + try: + return self.__set_data(Object, ObjectData, policy_id, data_id=data_id, + category_id=category_id, value=value) + except sqlalchemy.exc.IntegrityError as error: + if 'UNIQUE constraint' in str(error) or 'Duplicate entry' in str(error): + raise exceptions.ObjectScopeExisting + raise error + + def delete_object_data(self, policy_id, category_id, data_id): + return self.__delete_data(ObjectData, policy_id, category_id, data_id) + + def is_action_data_exist(self, category_id=None): + return self.__is_data_exist(ActionData, category_id=category_id) + + def get_action_data(self, policy_id, data_id=None, category_id=None): + return self.__get_data(ActionData, policy_id, data_id=data_id, category_id=category_id) + + def set_action_data(self, policy_id, data_id=None, category_id=None, value=None): + try: + return self.__set_data(Action, ActionData, policy_id, data_id=data_id, + category_id=category_id, value=value) + except sqlalchemy.exc.IntegrityError as error: + if 'UNIQUE constraint' in str(error) or 'Duplicate entry' in str(error): + raise exceptions.ActionScopeExisting + raise error + + def delete_action_data(self, policy_id, category_id, data_id): + return self.__delete_data(ActionData, policy_id, category_id, data_id) + + def get_subject_assignments(self, policy_id, subject_id=None, category_id=None): + with self.get_session_for_write() as session: + query = session.query(SubjectAssignment) + if subject_id and category_id: + # TODO change the subject_id to perimeter_id to allow code refactoring + query = query.filter_by(policy_id=policy_id, subject_id=subject_id, + category_id=category_id) + elif subject_id: + query = query.filter_by(policy_id=policy_id, subject_id=subject_id) + else: + query = query.filter_by(policy_id=policy_id) + ref_list = query.all() + return {_ref.id: _ref.to_dict() for _ref in ref_list} + + def add_subject_assignment(self, policy_id, subject_id, category_id, data_id): + with self.get_session_for_write() as session: + query = session.query(SubjectAssignment) + query = query.filter_by(policy_id=policy_id, subject_id=subject_id, + category_id=category_id) + ref = query.first() + if ref: + old_ref = copy.deepcopy(ref.to_dict()) + assignments = old_ref["assignments"] + if data_id not in assignments: + assignments.append(data_id) + setattr(ref, "assignments", assignments) + else: + raise exceptions.SubjectAssignmentExisting + else: + ref = SubjectAssignment.from_dict( + { + "id": uuid4().hex, + "policy_id": policy_id, + "subject_id": subject_id, + "category_id": category_id, + "assignments": [data_id, ], + } + ) + session.add(ref) + return {ref.id: ref.to_dict()} + + def is_subject_category_has_assignment(self, category_id): + return self.__is_category_has_assignment(SubjectAssignment, category_id) + + def is_object_category_has_assignment(self, category_id): + return self.__is_category_has_assignment(ObjectAssignment, category_id) + + def is_action_category_has_assignment(self, category_id): + return self.__is_category_has_assignment(ActionAssignment, category_id) + + def __is_category_has_assignment(self, ClassType, category_id): + with self.get_session_for_write() as session: + query = session.query(ClassType) + query = query.filter_by(category_id=category_id) + count = query.count() + return count > 0 + + def delete_subject_assignment(self, policy_id, subject_id, category_id, data_id): + with self.get_session_for_write() as session: + query = session.query(SubjectAssignment) + + if policy_id and subject_id and category_id: + query = query.filter_by(policy_id=policy_id, subject_id=subject_id, + category_id=category_id) + + elif policy_id and subject_id: + query = query.filter_by(policy_id=policy_id, subject_id=subject_id) + + elif policy_id: + query = query.filter_by(policy_id=policy_id) + + ref_list = query.all() + if ref_list: + for _ref in ref_list: + old_ref = copy.deepcopy(_ref.to_dict()) + assignments = old_ref["assignments"] + if data_id: + if data_id in assignments: + assignments.remove(data_id) + if not assignments: + session.delete(_ref) + else: + # FIXME (asteroide): the setattr doesn't work here ; the assignments is not updated in the database + setattr(_ref, "assignments", assignments) + else: + session.delete(_ref) + + def get_object_assignments(self, policy_id, object_id=None, category_id=None): + with self.get_session_for_write() as session: + query = session.query(ObjectAssignment) + if object_id and category_id: + # TODO change the object_id to perimeter_id to allow code refactoring + query = query.filter_by(policy_id=policy_id, object_id=object_id, + category_id=category_id) + elif object_id: + query = query.filter_by(policy_id=policy_id, object_id=object_id) + else: + query = query.filter_by(policy_id=policy_id) + ref_list = query.all() + return {_ref.id: _ref.to_dict() for _ref in ref_list} + + def add_object_assignment(self, policy_id, object_id, category_id, data_id): + with self.get_session_for_write() as session: + query = session.query(ObjectAssignment) + query = query.filter_by(policy_id=policy_id, object_id=object_id, + category_id=category_id) + ref = query.first() + if ref: + old_ref = copy.deepcopy(ref.to_dict()) + assignments = old_ref["assignments"] + if data_id not in assignments: + assignments.append(data_id) + setattr(ref, "assignments", assignments) + else: + raise exceptions.ObjectAssignmentExisting + else: + ref = ObjectAssignment.from_dict( + { + "id": uuid4().hex, + "policy_id": policy_id, + "object_id": object_id, + "category_id": category_id, + "assignments": [data_id, ], + } + ) + session.add(ref) + return {ref.id: ref.to_dict()} + + def delete_object_assignment(self, policy_id, object_id, category_id, data_id): + with self.get_session_for_write() as session: + query = session.query(ObjectAssignment) + + if policy_id and object_id and category_id: + query = query.filter_by(policy_id=policy_id, object_id=object_id, + category_id=category_id) + elif policy_id and object_id: + query = query.filter_by(policy_id=policy_id, object_id=object_id) + + elif policy_id: + query = query.filter_by(policy_id=policy_id) + + + + ref_list = query.all() + if ref_list: + for _ref in ref_list: + old_ref = copy.deepcopy(_ref.to_dict()) + assignments = old_ref["assignments"] + if data_id: + if data_id in assignments: + assignments.remove(data_id) + if not assignments: + session.delete(_ref) + else: + # FIXME (asteroide): the setattr doesn't work here ; the assignments is not updated in the database + setattr(_ref, "assignments", assignments) + else: + session.delete(_ref) + + def get_action_assignments(self, policy_id, action_id=None, category_id=None): + with self.get_session_for_write() as session: + if not policy_id: + return exceptions.PolicyUnknown + query = session.query(ActionAssignment) + if action_id and category_id: + # TODO change the action_id to perimeter_id to allow code refactoring + query = query.filter_by(policy_id=policy_id, action_id=action_id, + category_id=category_id) + elif action_id: + query = query.filter_by(policy_id=policy_id, action_id=action_id) + elif category_id: + query = query.filter_by(policy_id=policy_id, category_id=category_id) + else: + query = query.filter_by(policy_id=policy_id) + ref_list = query.all() + return {_ref.id: _ref.to_dict() for _ref in ref_list} + + def add_action_assignment(self, policy_id, action_id, category_id, data_id): + with self.get_session_for_write() as session: + query = session.query(ActionAssignment) + query = query.filter_by(policy_id=policy_id, action_id=action_id, + category_id=category_id) + ref = query.first() + if ref: + old_ref = copy.deepcopy(ref.to_dict()) + assignments = old_ref["assignments"] + if data_id not in assignments: + assignments.append(data_id) + setattr(ref, "assignments", assignments) + else: + raise exceptions.ActionAssignmentExisting + else: + ref = ActionAssignment.from_dict( + { + "id": uuid4().hex, + "policy_id": policy_id, + "action_id": action_id, + "category_id": category_id, + "assignments": [data_id, ], + } + ) + session.add(ref) + return {ref.id: ref.to_dict()} + + def delete_action_assignment(self, policy_id, action_id, category_id, data_id): + with self.get_session_for_write() as session: + query = session.query(ActionAssignment) + + if policy_id and action_id and category_id: + query = query.filter_by(policy_id=policy_id, action_id=action_id, + category_id=category_id) + + elif policy_id and action_id: + query = query.filter_by(policy_id=policy_id, action_id=action_id) + + elif policy_id: + query = query.filter_by(policy_id=policy_id) + + + + ref_list = query.all() + if ref_list: + for _ref in ref_list: + old_ref = copy.deepcopy(_ref.to_dict()) + assignments = old_ref["assignments"] + if data_id: + if data_id in assignments: + assignments.remove(data_id) + if not assignments: + session.delete(_ref) + else: + # FIXME (asteroide): the setattr doesn't work here ; the assignments is not updated in the database + setattr(_ref, "assignments", assignments) + else: + session.delete(_ref) + + def get_rules(self, policy_id, rule_id=None, meta_rule_id=None): + with self.get_session_for_read() as session: + query = session.query(Rule) + if rule_id: + query = query.filter_by(id=rule_id) + ref = query.first() + if ref: + return {ref.id: ref.to_dict()} + return {} + elif meta_rule_id and policy_id: + query = query.filter_by(policy_id=policy_id, meta_rule_id=meta_rule_id) + ref_list = query.all() + return { + "meta_rule_id": meta_rule_id, + "policy_id": policy_id, + "rules": list(map(lambda x: x.to_dict(), ref_list)) + } + else: + query = query.filter_by(policy_id=policy_id) + ref_list = query.all() + return { + "policy_id": policy_id, + "rules": list(map(lambda x: x.to_dict(), ref_list)) + } + + def is_meta_rule_has_rules(self, meta_rule_id): + with self.get_session_for_read() as session: + query = session.query(Rule) + + query = query.filter_by(meta_rule_id=meta_rule_id) + count = query.count() + return count > 0 + + def add_rule(self, policy_id, meta_rule_id, value): + try: + rules = self.get_rules(policy_id, meta_rule_id=meta_rule_id) + for _rule in map(lambda x: x["rule"], rules["rules"]): + if list(value.get('rule')) == list(_rule): + raise exceptions.RuleExisting + with self.get_session_for_write() as session: + ref = Rule.from_dict( + { + "id": uuid4().hex, + "policy_id": policy_id, + "meta_rule_id": meta_rule_id, + "rule": value + } + ) + session.add(ref) + return {ref.id: ref.to_dict()} + except sqlalchemy.exc.IntegrityError as error: + if 'UNIQUE constraint' in str(error) or 'Duplicate entry' in str(error): + raise exceptions.RuleExisting + raise error + + def update_rule(self, rule_id, value): + try: + with self.get_session_for_write() as session: + query = session.query(Rule) + query = query.filter_by(id=rule_id) + ref = query.first() + + if ref: + value_wo_name = copy.deepcopy(value) + value_wo_name.pop('name', None) + value_wo_name.pop('policy_id', None) + value_wo_name.pop('meta_rule_id', None) + d = dict(ref.rule) + d.update(value_wo_name) + ref.rule = d + return {ref.id: ref.to_dict()} + + except sqlalchemy.exc.IntegrityError as error: + if 'UNIQUE constraint' in str(error) or 'Duplicate entry' in str(error): + raise exceptions.PolicyExisting + raise error + + def delete_rule(self, policy_id, rule_id): + with self.get_session_for_write() as session: + query = session.query(Rule) + query = query.filter_by(policy_id=policy_id, id=rule_id) + ref = query.first() + if ref: + session.delete(ref) + + +class ModelConnector(BaseConnector, ModelDriver): + + def update_model(self, model_id, value): + try: + with self.get_session_for_write() as session: + query = session.query(Model) + if model_id: + query = query.filter_by(id=model_id) + ref = query.first() + if ref: + value_wo_name = copy.deepcopy(value) + value_wo_name.pop("name", None) + setattr(ref, "name", value["name"]) + d = dict(ref.value) + d.update(value_wo_name) + setattr(ref, "value", d) + return {ref.id: ref.to_dict()} + except sqlalchemy.exc.IntegrityError as error: + if 'UNIQUE constraint' in str(error) or 'Duplicate entry' in str(error): + raise exceptions.ModelExisting + raise error + + def delete_model(self, model_id): + with self.get_session_for_write() as session: + ref = session.query(Model).get(model_id) + session.delete(ref) + + def add_model(self, model_id=None, value=None): + try: + with self.get_session_for_write() as session: + value_wo_name = copy.deepcopy(value) + value_wo_name.pop("name", None) + new = Model.from_dict({ + "id": model_id if model_id else uuid4().hex, + "name": value["name"], + "value": value_wo_name + }) + session.add(new) + return {new.id: new.to_dict()} + except sqlalchemy.exc.IntegrityError as error: + if 'UNIQUE constraint' in str(error) or 'Duplicate entry' in str(error): + raise exceptions.ModelExisting + raise error + + def get_models(self, model_id=None): + with self.get_session_for_read() as session: + query = session.query(Model) + if model_id: + ref_list = query.filter(Model.id == model_id) + else: + ref_list = query.all() + + r = {_ref.id: _ref.to_dict() for _ref in ref_list} + return r + + def set_meta_rule(self, meta_rule_id, value): + try: + with self.get_session_for_write() as session: + value_wo_other_data = copy.deepcopy(value) + value_wo_other_data.pop("name", None) + value_wo_other_data.pop("subject_categories", None) + value_wo_other_data.pop("object_categories", None) + value_wo_other_data.pop("action_categories", None) + if meta_rule_id is None: + try: + ref = MetaRule.from_dict( + { + "id": uuid4().hex, + "name": value["name"], + "subject_categories": value["subject_categories"], + "object_categories": value["object_categories"], + "action_categories": value["action_categories"], + "value": value_wo_other_data + } + ) + session.add(ref) + except sqlalchemy.exc.IntegrityError as error: + if 'UNIQUE constraint' in str(error) or 'Duplicate entry' in str(error): + raise exceptions.MetaRuleExisting + raise error + else: + query = session.query(MetaRule) + query = query.filter_by(id=meta_rule_id) + ref = query.first() + setattr(ref, "name", value["name"]) + setattr(ref, "subject_categories", value["subject_categories"]) + setattr(ref, "object_categories", value["object_categories"]) + setattr(ref, "action_categories", value["action_categories"]) + setattr(ref, "value", value_wo_other_data) + return {ref.id: ref.to_dict()} + except sqlalchemy.exc.IntegrityError as error: + if 'UNIQUE constraint' in str(error) or 'Duplicate entry' in str(error): + raise exceptions.MetaRuleExisting + raise error + + def get_meta_rules(self, meta_rule_id=None): + with self.get_session_for_read() as session: + query = session.query(MetaRule) + if meta_rule_id: + query = query.filter_by(id=meta_rule_id) + ref_list = query.all() + return {_ref.id: _ref.to_dict() for _ref in ref_list} + + def delete_meta_rule(self, meta_rule_id=None): + with self.get_session_for_write() as session: + query = session.query(MetaRule) + query = query.filter_by(id=meta_rule_id) + ref = query.first() + if ref: + session.delete(ref) + + def __get_perimeter_categories(self, ClassType, category_id=None): + with self.get_session_for_read() as session: + query = session.query(ClassType) + if category_id != None: + query = query.filter_by(id=category_id) + ref_list = query.all() + return {_ref.id: _ref.to_dict() for _ref in ref_list} + + def __get_perimeter_categories_by_category_name(self, ClassType, category_name=None): + with self.get_session_for_read() as session: + query = session.query(ClassType) + if category_name != None: + query = query.filter_by(name=category_name) + ref_list = query.all() + return {_ref.id: _ref.to_dict() for _ref in ref_list} + + def __add_perimeter_category(self, ClassType, name, description, uuid=None): + if not name or not name.strip(): + raise exceptions.CategoryNameInvalid + with self.get_session_for_write() as session: + ref = ClassType.from_dict( + { + "id": uuid if uuid else uuid4().hex, + "name": name, + "description": description + } + ) + session.add(ref) + return {ref.id: ref.to_dict()} + + def __delete_perimeter_category(self, ClassType, category_id): + with self.get_session_for_write() as session: + query = session.query(ClassType) + query = query.filter_by(id=category_id) + ref = query.first() + if ref: + session.delete(ref) + #TODO: MAY BE!duplicate to get_subject_categories_by_ + def get_subject_categories(self, category_id=None, category_name=None): + if category_name != None: + return self.__get_perimeter_categories_by_category_name(SubjectCategory, category_name=category_name) + return self.__get_perimeter_categories(SubjectCategory, category_id=category_id) + + + def add_subject_category(self, name, description, uuid=None): + try: + return self.__add_perimeter_category(SubjectCategory, name, description, uuid=uuid) + except sql.exc.IntegrityError as error: + if 'UNIQUE constraint' in str(error) or 'Duplicate entry' in str(error): + raise exceptions.SubjectCategoryExisting + raise error + + def delete_subject_category(self, category_id): + self.__delete_perimeter_category(SubjectCategory, category_id) + + def get_object_categories(self, category_id=None, category_name=None): + if category_name != None: + return self.__get_perimeter_categories_by_category_name(ObjectCategory, category_name=category_name) + return self.__get_perimeter_categories(ObjectCategory, category_id=category_id) + + def add_object_category(self, name, description, uuid=None): + try: + return self.__add_perimeter_category(ObjectCategory, name, description, uuid=uuid) + except sql.exc.IntegrityError as error: + if 'UNIQUE constraint' in str(error) or 'Duplicate entry' in str(error): + raise exceptions.ObjectCategoryExisting + raise error + + def delete_object_category(self, category_id): + self.__delete_perimeter_category(ObjectCategory, category_id) + + def get_action_categories(self, category_id=None, category_name=None): + if category_name != None: + return self.__get_perimeter_categories_by_category_name(ActionCategory, category_name=category_name) + return self.__get_perimeter_categories(ActionCategory, category_id=category_id) + + def add_action_category(self, name, description, uuid=None): + try: + return self.__add_perimeter_category(ActionCategory, name, description, uuid=uuid) + except sql.exc.IntegrityError as error: + if 'UNIQUE constraint' in str(error) or 'Duplicate entry' in str(error): + raise exceptions.ActionCategoryExisting + raise error + + def delete_action_category(self, category_id): + self.__delete_perimeter_category(ActionCategory, category_id) + + # Getter and Setter for subject_category + + # def get_subject_categories_dict(self, intra_extension_id): + # with self.get_session_for_read() as session: + # query = session.query(SubjectCategory) + # query = query.filter_by(intra_extension_id=intra_extension_id) + # ref_list = query.all() + # return {_ref.id: _ref.subject_category for _ref in ref_list} + # + # def set_subject_category_dict(self, intra_extension_id, subject_category_id, subject_category_dict): + # with self.get_session_for_write() as session: + # query = session.query(SubjectCategory) + # query = query.filter_by(intra_extension_id=intra_extension_id, id=subject_category_id) + # ref = query.first() + # new_ref = SubjectCategory.from_dict( + # { + # "id": subject_category_id, + # 'subject_category': subject_category_dict, + # 'intra_extension_id': intra_extension_id + # } + # ) + # if not ref: + # session.add(new_ref) + # ref = new_ref + # else: + # for attr in SubjectCategory.attributes: + # if attr != 'id': + # setattr(ref, attr, getattr(new_ref, attr)) + # # # session.flush() + # return {subject_category_id: SubjectCategory.to_dict(ref)['subject_category']} + # + # def del_subject_category(self, intra_extension_id, subject_category_id): + # with self.get_session_for_write() as session: + # query = session.query(SubjectCategory) + # query = query.filter_by(intra_extension_id=intra_extension_id, id=subject_category_id) + # ref = query.first() + # self.del_subject_assignment(intra_extension_id, None, None, None) + # session.delete(ref) + # + # # Getter and Setter for object_category + # + # def get_object_categories_dict(self, intra_extension_id): + # with self.get_session_for_read() as session: + # query = session.query(ObjectCategory) + # query = query.filter_by(intra_extension_id=intra_extension_id) + # ref_list = query.all() + # return {_ref.id: _ref.object_category for _ref in ref_list} + # + # def set_object_category_dict(self, intra_extension_id, object_category_id, object_category_dict): + # with self.get_session_for_write() as session: + # query = session.query(ObjectCategory) + # query = query.filter_by(intra_extension_id=intra_extension_id, id=object_category_id) + # ref = query.first() + # new_ref = ObjectCategory.from_dict( + # { + # "id": object_category_id, + # 'object_category': object_category_dict, + # 'intra_extension_id': intra_extension_id + # } + # ) + # if not ref: + # session.add(new_ref) + # ref = new_ref + # else: + # for attr in ObjectCategory.attributes: + # if attr != 'id': + # setattr(ref, attr, getattr(new_ref, attr)) + # # session.flush() + # return {object_category_id: ObjectCategory.to_dict(ref)['object_category']} + # + # def del_object_category(self, intra_extension_id, object_category_id): + # with self.get_session_for_write() as session: + # query = session.query(ObjectCategory) + # query = query.filter_by(intra_extension_id=intra_extension_id, id=object_category_id) + # ref = query.first() + # self.del_object_assignment(intra_extension_id, None, None, None) + # session.delete(ref) + # + # # Getter and Setter for action_category + # + # def get_action_categories_dict(self, intra_extension_id): + # with self.get_session_for_read() as session: + # query = session.query(ActionCategory) + # query = query.filter_by(intra_extension_id=intra_extension_id) + # ref_list = query.all() + # return {_ref.id: _ref.action_category for _ref in ref_list} + # + # def set_action_category_dict(self, intra_extension_id, action_category_id, action_category_dict): + # with self.get_session_for_write() as session: + # query = session.query(ActionCategory) + # query = query.filter_by(intra_extension_id=intra_extension_id, id=action_category_id) + # ref = query.first() + # new_ref = ActionCategory.from_dict( + # { + # "id": action_category_id, + # 'action_category': action_category_dict, + # 'intra_extension_id': intra_extension_id + # } + # ) + # if not ref: + # session.add(new_ref) + # ref = new_ref + # else: + # for attr in ActionCategory.attributes: + # if attr != 'id': + # setattr(ref, attr, getattr(new_ref, attr)) + # # session.flush() + # return {action_category_id: ActionCategory.to_dict(ref)['action_category']} + # + # def del_action_category(self, intra_extension_id, action_category_id): + # with self.get_session_for_write() as session: + # query = session.query(ActionCategory) + # query = query.filter_by(intra_extension_id=intra_extension_id, id=action_category_id) + # ref = query.first() + # self.del_action_assignment(intra_extension_id, None, None, None) + # session.delete(ref) + + # Perimeter + + # def get_subjects_dict(self, intra_extension_id): + # with self.get_session_for_read() as session: + # query = session.query(Subject) + # query = query.filter_by(intra_extension_id=intra_extension_id) + # ref_list = query.all() + # return {_ref.id: _ref.subject for _ref in ref_list} + # + # def set_subject_dict(self, intra_extension_id, subject_id, subject_dict): + # with self.get_session_for_write() as session: + # query = session.query(Subject) + # query = query.filter_by(intra_extension_id=intra_extension_id, id=subject_id) + # ref = query.first() + # # if 'id' in subject_dict: + # # subject_dict['id'] = subject_id + # new_ref = Subject.from_dict( + # { + # "id": subject_id, + # 'subject': subject_dict, + # 'intra_extension_id': intra_extension_id + # } + # ) + # if not ref: + # session.add(new_ref) + # ref = new_ref + # else: + # for attr in Subject.attributes: + # if attr != 'id': + # setattr(ref, attr, getattr(new_ref, attr)) + # # session.flush() + # return {subject_id: Subject.to_dict(ref)['subject']} + # + # def del_subject(self, intra_extension_id, subject_id): + # with self.get_session_for_write() as session: + # query = session.query(Subject) + # query = query.filter_by(intra_extension_id=intra_extension_id, id=subject_id) + # ref = query.first() + # session.delete(ref) + # + # def get_objects_dict(self, intra_extension_id): + # with self.get_session_for_read() as session: + # query = session.query(Object) + # query = query.filter_by(intra_extension_id=intra_extension_id) + # ref_list = query.all() + # return {_ref.id: _ref.object for _ref in ref_list} + # + # def set_object_dict(self, intra_extension_id, object_id, object_dict): + # with self.get_session_for_write() as session: + # query = session.query(Object) + # query = query.filter_by(intra_extension_id=intra_extension_id, id=object_id) + # ref = query.first() + # new_ref = Object.from_dict( + # { + # "id": object_id, + # 'object': object_dict, + # 'intra_extension_id': intra_extension_id + # } + # ) + # if not ref: + # session.add(new_ref) + # ref = new_ref + # else: + # for attr in Object.attributes: + # if attr != 'id': + # setattr(ref, attr, getattr(new_ref, attr)) + # # session.flush() + # return {object_id: Object.to_dict(ref)['object']} + # + # def del_object(self, intra_extension_id, object_id): + # with self.get_session_for_write() as session: + # query = session.query(Object) + # query = query.filter_by(intra_extension_id=intra_extension_id, id=object_id) + # ref = query.first() + # session.delete(ref) + # + # def get_actions_dict(self, intra_extension_id): + # with self.get_session_for_read() as session: + # query = session.query(Action) + # query = query.filter_by(intra_extension_id=intra_extension_id) + # ref_list = query.all() + # return {_ref.id: _ref.action for _ref in ref_list} + # + # def set_action_dict(self, intra_extension_id, action_id, action_dict): + # with self.get_session_for_write() as session: + # query = session.query(Action) + # query = query.filter_by(intra_extension_id=intra_extension_id, id=action_id) + # ref = query.first() + # new_ref = Action.from_dict( + # { + # "id": action_id, + # 'action': action_dict, + # 'intra_extension_id': intra_extension_id + # } + # ) + # if not ref: + # session.add(new_ref) + # ref = new_ref + # else: + # for attr in Action.attributes: + # if attr != 'id': + # setattr(ref, attr, getattr(new_ref, attr)) + # # session.flush() + # return {action_id: Action.to_dict(ref)['action']} + # + # def del_action(self, intra_extension_id, action_id): + # with self.get_session_for_write() as session: + # query = session.query(Action) + # query = query.filter_by(intra_extension_id=intra_extension_id, id=action_id) + # ref = query.first() + # session.delete(ref) + + # Getter and Setter for subject_scope + + # def get_subject_scopes_dict(self, intra_extension_id, subject_category_id): + # with self.get_session_for_read() as session: + # query = session.query(SubjectScope) + # query = query.filter_by(intra_extension_id=intra_extension_id, subject_category_id=subject_category_id) + # ref_list = query.all() + # return {_ref.id: _ref.subject_scope for _ref in ref_list} + # + # def set_subject_scope_dict(self, intra_extension_id, subject_category_id, subject_scope_id, subject_scope_dict): + # with self.get_session_for_write() as session: + # query = session.query(SubjectScope) + # query = query.filter_by(intra_extension_id=intra_extension_id, subject_category_id=subject_category_id, id=subject_scope_id) + # ref = query.first() + # new_ref = SubjectScope.from_dict( + # { + # "id": subject_scope_id, + # 'subject_scope': subject_scope_dict, + # 'intra_extension_id': intra_extension_id, + # 'subject_category_id': subject_category_id + # } + # ) + # if not ref: + # session.add(new_ref) + # ref = new_ref + # else: + # for attr in Subject.attributes: + # if attr != 'id': + # setattr(ref, attr, getattr(new_ref, attr)) + # # session.flush() + # return {subject_scope_id: SubjectScope.to_dict(ref)['subject_scope']} + # + # def del_subject_scope(self, intra_extension_id, subject_category_id, subject_scope_id): + # with self.get_session_for_write() as session: + # query = session.query(SubjectScope) + # if not subject_category_id or not subject_scope_id: + # query = query.filter_by(intra_extension_id=intra_extension_id) + # for ref in query.all(): + # session.delete(ref) + # else: + # query = query.filter_by(intra_extension_id=intra_extension_id, subject_category_id=subject_category_id, id=subject_scope_id) + # ref = query.first() + # session.delete(ref) + # + # # Getter and Setter for object_category_scope + # + # def get_object_scopes_dict(self, intra_extension_id, object_category_id): + # with self.get_session_for_read() as session: + # query = session.query(ObjectScope) + # query = query.filter_by(intra_extension_id=intra_extension_id, object_category_id=object_category_id) + # ref_list = query.all() + # return {_ref.id: _ref.object_scope for _ref in ref_list} + # + # def set_object_scope_dict(self, intra_extension_id, object_category_id, object_scope_id, object_scope_dict): + # with self.get_session_for_write() as session: + # query = session.query(ObjectScope) + # query = query.filter_by(intra_extension_id=intra_extension_id, object_category_id=object_category_id, id=object_scope_id) + # ref = query.first() + # new_ref = ObjectScope.from_dict( + # { + # "id": object_scope_id, + # 'object_scope': object_scope_dict, + # 'intra_extension_id': intra_extension_id, + # 'object_category_id': object_category_id + # } + # ) + # if not ref: + # session.add(new_ref) + # ref = new_ref + # else: + # for attr in Object.attributes: + # if attr != 'id': + # setattr(ref, attr, getattr(new_ref, attr)) + # # session.flush() + # return {object_scope_id: ObjectScope.to_dict(ref)['object_scope']} + # + # def del_object_scope(self, intra_extension_id, object_category_id, object_scope_id): + # with self.get_session_for_write() as session: + # query = session.query(ObjectScope) + # if not object_category_id or not object_scope_id: + # query = query.filter_by(intra_extension_id=intra_extension_id) + # for ref in query.all(): + # session.delete(ref) + # else: + # query = query.filter_by(intra_extension_id=intra_extension_id, object_category_id=object_category_id, id=object_scope_id) + # ref = query.first() + # session.delete(ref) + # + # # Getter and Setter for action_scope + # + # def get_action_scopes_dict(self, intra_extension_id, action_category_id): + # with self.get_session_for_read() as session: + # query = session.query(ActionScope) + # query = query.filter_by(intra_extension_id=intra_extension_id, action_category_id=action_category_id) + # ref_list = query.all() + # return {_ref.id: _ref.action_scope for _ref in ref_list} + # + # def set_action_scope_dict(self, intra_extension_id, action_category_id, action_scope_id, action_scope_dict): + # with self.get_session_for_write() as session: + # query = session.query(ActionScope) + # query = query.filter_by(intra_extension_id=intra_extension_id, action_category_id=action_category_id, id=action_scope_id) + # ref = query.first() + # new_ref = ActionScope.from_dict( + # { + # "id": action_scope_id, + # 'action_scope': action_scope_dict, + # 'intra_extension_id': intra_extension_id, + # 'action_category_id': action_category_id + # } + # ) + # if not ref: + # session.add(new_ref) + # ref = new_ref + # else: + # for attr in Action.attributes: + # if attr != 'id': + # setattr(ref, attr, getattr(new_ref, attr)) + # # session.flush() + # return {action_scope_id: ActionScope.to_dict(ref)['action_scope']} + # + # def del_action_scope(self, intra_extension_id, action_category_id, action_scope_id): + # with self.get_session_for_write() as session: + # query = session.query(ActionScope) + # if not action_category_id or not action_scope_id: + # query = query.filter_by(intra_extension_id=intra_extension_id) + # for ref in query.all(): + # session.delete(ref) + # else: + # query = query.filter_by(intra_extension_id=intra_extension_id, action_category_id=action_category_id, id=action_scope_id) + # ref = query.first() + # session.delete(ref) + # + # # Getter and Setter for subject_category_assignment + # + # def get_subject_assignment_list(self, intra_extension_id, subject_id, subject_category_id): + # with self.get_session_for_read() as session: + # query = session.query(SubjectAssignment) + # if not subject_id or not subject_category_id or not subject_category_id: + # query = query.filter_by(intra_extension_id=intra_extension_id) + # ref = query.all() + # return ref + # else: + # query = query.filter_by(intra_extension_id=intra_extension_id, subject_id=subject_id, subject_category_id=subject_category_id) + # ref = query.first() + # if not ref: + # return list() + # LOG.info("get_subject_assignment_list {}".format(ref.subject_assignment)) + # return list(ref.subject_assignment) + # + # def set_subject_assignment_list(self, intra_extension_id, subject_id, subject_category_id, subject_assignment_list=[]): + # with self.get_session_for_write() as session: + # query = session.query(SubjectAssignment) + # query = query.filter_by(intra_extension_id=intra_extension_id, subject_id=subject_id, subject_category_id=subject_category_id) + # ref = query.first() + # new_ref = SubjectAssignment.from_dict( + # { + # "id": uuid4().hex, + # 'subject_assignment': subject_assignment_list, + # 'intra_extension_id': intra_extension_id, + # 'subject_id': subject_id, + # 'subject_category_id': subject_category_id + # } + # ) + # if not ref: + # session.add(new_ref) + # ref = new_ref + # else: + # for attr in SubjectAssignment.attributes: + # if attr != 'id': + # setattr(ref, attr, getattr(new_ref, attr)) + # # session.flush() + # return subject_assignment_list + # + # def add_subject_assignment_list(self, intra_extension_id, subject_id, subject_category_id, subject_scope_id): + # new_subject_assignment_list = self.get_subject_assignment_list(intra_extension_id, subject_id, subject_category_id) + # if subject_scope_id not in new_subject_assignment_list: + # new_subject_assignment_list.append(subject_scope_id) + # return self.set_subject_assignment_list(intra_extension_id, subject_id, subject_category_id, new_subject_assignment_list) + # + # def del_subject_assignment(self, intra_extension_id, subject_id, subject_category_id, subject_scope_id): + # if not subject_id or not subject_category_id or not subject_category_id: + # with self.get_session_for_write() as session: + # for ref in self.get_subject_assignment_list(intra_extension_id, None, None): + # session.delete(ref) + # session.flush() + # return + # new_subject_assignment_list = self.get_subject_assignment_list(intra_extension_id, subject_id, subject_category_id) + # new_subject_assignment_list.remove(subject_scope_id) + # return self.set_subject_assignment_list(intra_extension_id, subject_id, subject_category_id, new_subject_assignment_list) + # + # # Getter and Setter for object_category_assignment + # + # def get_object_assignment_list(self, intra_extension_id, object_id, object_category_id): + # with self.get_session_for_read() as session: + # query = session.query(ObjectAssignment) + # if not object_id or not object_category_id or not object_category_id: + # query = query.filter_by(intra_extension_id=intra_extension_id) + # ref = query.all() + # return ref + # else: + # query = query.filter_by(intra_extension_id=intra_extension_id, object_id=object_id, object_category_id=object_category_id) + # ref = query.first() + # if not ref: + # return list() + # return list(ref.object_assignment) + # + # def set_object_assignment_list(self, intra_extension_id, object_id, object_category_id, object_assignment_list=[]): + # with self.get_session_for_write() as session: + # query = session.query(ObjectAssignment) + # query = query.filter_by(intra_extension_id=intra_extension_id, object_id=object_id, object_category_id=object_category_id) + # ref = query.first() + # new_ref = ObjectAssignment.from_dict( + # { + # "id": uuid4().hex, + # 'object_assignment': object_assignment_list, + # 'intra_extension_id': intra_extension_id, + # 'object_id': object_id, + # 'object_category_id': object_category_id + # } + # ) + # if not ref: + # session.add(new_ref) + # else: + # for attr in ObjectAssignment.attributes: + # if attr != 'id': + # setattr(ref, attr, getattr(new_ref, attr)) + # # session.flush() + # return self.get_object_assignment_list(intra_extension_id, object_id, object_category_id) + # + # def add_object_assignment_list(self, intra_extension_id, object_id, object_category_id, object_scope_id): + # new_object_assignment_list = self.get_object_assignment_list(intra_extension_id, object_id, object_category_id) + # if object_scope_id not in new_object_assignment_list: + # new_object_assignment_list.append(object_scope_id) + # return self.set_object_assignment_list(intra_extension_id, object_id, object_category_id, new_object_assignment_list) + # + # def del_object_assignment(self, intra_extension_id, object_id, object_category_id, object_scope_id): + # if not object_id or not object_category_id or not object_category_id: + # with self.get_session_for_write() as session: + # for ref in self.get_object_assignment_list(intra_extension_id, None, None): + # session.delete(ref) + # session.flush() + # return + # new_object_assignment_list = self.get_object_assignment_list(intra_extension_id, object_id, object_category_id) + # new_object_assignment_list.remove(object_scope_id) + # return self.set_object_assignment_list(intra_extension_id, object_id, object_category_id, new_object_assignment_list) + # + # # Getter and Setter for action_category_assignment + # + # def get_action_assignment_list(self, intra_extension_id, action_id, action_category_id): + # with self.get_session_for_read() as session: + # query = session.query(ActionAssignment) + # if not action_id or not action_category_id or not action_category_id: + # query = query.filter_by(intra_extension_id=intra_extension_id) + # ref = query.all() + # return ref + # else: + # query = query.filter_by(intra_extension_id=intra_extension_id, action_id=action_id, action_category_id=action_category_id) + # ref = query.first() + # if not ref: + # return list() + # return list(ref.action_assignment) + # + # def set_action_assignment_list(self, intra_extension_id, action_id, action_category_id, action_assignment_list=[]): + # with self.get_session_for_write() as session: + # query = session.query(ActionAssignment) + # query = query.filter_by(intra_extension_id=intra_extension_id, action_id=action_id, action_category_id=action_category_id) + # ref = query.first() + # new_ref = ActionAssignment.from_dict( + # { + # "id": uuid4().hex, + # 'action_assignment': action_assignment_list, + # 'intra_extension_id': intra_extension_id, + # 'action_id': action_id, + # 'action_category_id': action_category_id + # } + # ) + # if not ref: + # session.add(new_ref) + # else: + # for attr in ActionAssignment.attributes: + # if attr != 'id': + # setattr(ref, attr, getattr(new_ref, attr)) + # # session.flush() + # return self.get_action_assignment_list(intra_extension_id, action_id, action_category_id) + # + # def add_action_assignment_list(self, intra_extension_id, action_id, action_category_id, action_scope_id): + # new_action_assignment_list = self.get_action_assignment_list(intra_extension_id, action_id, action_category_id) + # if action_scope_id not in new_action_assignment_list: + # new_action_assignment_list.append(action_scope_id) + # return self.set_action_assignment_list(intra_extension_id, action_id, action_category_id, new_action_assignment_list) + # + # def del_action_assignment(self, intra_extension_id, action_id, action_category_id, action_scope_id): + # if not action_id or not action_category_id or not action_category_id: + # with self.get_session_for_write() as session: + # for ref in self.get_action_assignment_list(intra_extension_id, None, None): + # session.delete(ref) + # session.flush() + # return + # new_action_assignment_list = self.get_action_assignment_list(intra_extension_id, action_id, action_category_id) + # new_action_assignment_list.remove(action_scope_id) + # return self.set_action_assignment_list(intra_extension_id, action_id, action_category_id, new_action_assignment_list) + # + # # Getter and Setter for sub_meta_rule + # + # def get_aggregation_algorithm_id(self, intra_extension_id): + # with self.get_session_for_read() as session: + # query = session.query(IntraExtension) + # query = query.filter_by(id=intra_extension_id) + # ref = query.first() + # try: + # return {"aggregation_algorithm": ref.intra_extension["aggregation_algorithm"]} + # except KeyError: + # return "" + # + # def set_aggregation_algorithm_id(self, intra_extension_id, aggregation_algorithm_id): + # with self.get_session_for_write() as session: + # query = session.query(IntraExtension) + # query = query.filter_by(id=intra_extension_id) + # ref = query.first() + # intra_extension_dict = dict(ref.intra_extension) + # intra_extension_dict["aggregation_algorithm"] = aggregation_algorithm_id + # setattr(ref, "intra_extension", intra_extension_dict) + # # session.flush() + # return {"aggregation_algorithm": ref.intra_extension["aggregation_algorithm"]} + # + # def del_aggregation_algorithm(self, intra_extension_id): + # with self.get_session_for_write() as session: + # query = session.query(IntraExtension) + # query = query.filter_by(id=intra_extension_id) + # ref = query.first() + # intra_extension_dict = dict(ref.intra_extension) + # intra_extension_dict["aggregation_algorithm"] = "" + # setattr(ref, "intra_extension", intra_extension_dict) + # return self.get_aggregation_algorithm_id(intra_extension_id) + # + # # Getter and Setter for sub_meta_rule + # + # def get_sub_meta_rules_dict(self, intra_extension_id): + # with self.get_session_for_read() as session: + # query = session.query(SubMetaRule) + # query = query.filter_by(intra_extension_id=intra_extension_id) + # ref_list = query.all() + # return {_ref.id: _ref.sub_meta_rule for _ref in ref_list} + # + # def set_sub_meta_rule_dict(self, intra_extension_id, sub_meta_rule_id, sub_meta_rule_dict): + # with self.get_session_for_write() as session: + # query = session.query(SubMetaRule) + # query = query.filter_by(intra_extension_id=intra_extension_id, id=sub_meta_rule_id) + # ref = query.first() + # new_ref = SubMetaRule.from_dict( + # { + # "id": sub_meta_rule_id, + # 'sub_meta_rule': sub_meta_rule_dict, + # 'intra_extension_id': intra_extension_id + # } + # ) + # if not ref: + # session.add(new_ref) + # else: + # _sub_meta_rule_dict = dict(ref.sub_meta_rule) + # _sub_meta_rule_dict.update(sub_meta_rule_dict) + # setattr(new_ref, "sub_meta_rule", _sub_meta_rule_dict) + # for attr in SubMetaRule.attributes: + # if attr != 'id': + # setattr(ref, attr, getattr(new_ref, attr)) + # # session.flush() + # return self.get_sub_meta_rules_dict(intra_extension_id) + # + # def del_sub_meta_rule(self, intra_extension_id, sub_meta_rule_id): + # with self.get_session_for_write() as session: + # query = session.query(SubMetaRule) + # query = query.filter_by(intra_extension_id=intra_extension_id, id=sub_meta_rule_id) + # ref = query.first() + # session.delete(ref) + # + # # Getter and Setter for rules + # + # def get_rules_dict(self, intra_extension_id, sub_meta_rule_id): + # with self.get_session_for_read() as session: + # query = session.query(Rule) + # query = query.filter_by(intra_extension_id=intra_extension_id, sub_meta_rule_id=sub_meta_rule_id) + # ref_list = query.all() + # return {_ref.id: _ref.rule for _ref in ref_list} + # + # def set_rule_dict(self, intra_extension_id, sub_meta_rule_id, rule_id, rule_list): + # with self.get_session_for_write() as session: + # query = session.query(Rule) + # query = query.filter_by(intra_extension_id=intra_extension_id, sub_meta_rule_id=sub_meta_rule_id, id=rule_id) + # ref = query.first() + # new_ref = Rule.from_dict( + # { + # "id": rule_id, + # 'rule': rule_list, + # 'intra_extension_id': intra_extension_id, + # 'sub_meta_rule_id': sub_meta_rule_id + # } + # ) + # if not ref: + # session.add(new_ref) + # ref = new_ref + # else: + # for attr in Rule.attributes: + # if attr != 'id': + # setattr(ref, attr, getattr(new_ref, attr)) + # # session.flush() + # return {rule_id: ref.rule} + # + # def del_rule(self, intra_extension_id, sub_meta_rule_id, rule_id): + # with self.get_session_for_write() as session: + # query = session.query(Rule) + # query = query.filter_by(intra_extension_id=intra_extension_id, sub_meta_rule_id=sub_meta_rule_id, id=rule_id) + # ref = query.first() + # session.delete(ref) + + +class Connector(PDPConnector, PolicyConnector, ModelConnector, SlaveConnector): + pass diff --git a/moon_manager/moon_manager/server.py b/moon_manager/moon_manager/server.py index 70ddaee0..ff6fd278 100644 --- a/moon_manager/moon_manager/server.py +++ b/moon_manager/moon_manager/server.py @@ -1,39 +1,95 @@ -# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors -# This software is distributed under the terms and conditions of the 'Apache-2.0' -# license which can be found in the file 'LICENSE' in this package distribution -# or at 'http://www.apache.org/licenses/LICENSE-2.0'. +# Software Name: MOON +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + + +import hug import logging -from python_moonutilities import configuration, exceptions -from moon_manager.http_server import HTTPServer - -logger = logging.getLogger("moon.manager.server") - - -def create_server(): - 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) - logger.info("Starting server with IP {} on port {} bind to {}".format( - hostname, port, bind)) - return HTTPServer(host=bind, port=port) - - -def run(): - server = create_server() - server.run() - - -if __name__ == '__main__': - run() +from moon_manager.api import status, logs, configuration, pdp, policy, slave, auth, \ + perimeter, assignments, meta_data, meta_rules, models, \ + json_import, json_export, rules, data, attributes +from moon_manager import db_driver,orchestration_driver +from moon_utilities.auth_functions import init_db +from falcon.http_error import HTTPError +from moon_manager.api import ERROR_CODE +from moon_utilities import exceptions +LOGGER = logging.getLogger("moon.manager.server") +configuration.init_logging() + + +@hug.response_middleware() +def CORS(request, response, resource): + response.set_header('Access-Control-Allow-Origin', '*') + response.set_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, DELETE, PATCH') + response.set_header( + 'Access-Control-Allow-Headers', + 'Authorization,Keep-Alive,User-Agent,x-api-key' + 'If-Modified-Since,Cache-Control,Content-Type,x-api-key' + ) + response.set_header( + 'Access-Control-Expose-Headers', + 'Authorization,Keep-Alive,User-Agent,' + 'If-Modified-Since,Cache-Control,Content-Type' + ) + if request.method == 'OPTIONS': + response.set_header('Access-Control-Max-Age', 1728000) + response.set_header('Content-Type', 'text/plain charset=UTF-8') + response.set_header('Content-Length', 0) + response.status_code = hug.HTTP_204 + + +@hug.startup() +def add_data(api): + """Adds initial data to the api on startup""" + LOGGER.warning("Starting the server and initializing data") + init_db(configuration.get_configuration("management").get("token_file")) + db_driver.init() + orchestration_driver.init() + + +def __get_status_code(exception): + if isinstance(exception, HTTPError): + return exception.status + status_code = getattr(exception, "code", 500) + if status_code in ERROR_CODE: + status_code = ERROR_CODE[status_code] + else: + status_code = hug.HTTP_500 + return status_code + + +@hug.exception(exceptions.MoonError) +def handle_custom_exceptions(exception, response): + response.status = __get_status_code(exception) + error_message = {"result": False, + 'message': str(exception), + "code": getattr(exception, "code", 500)} + LOGGER.exception(exception) + return error_message + + +@hug.exception(Exception) +def handle_exception(exception, response): + response.status = __get_status_code(exception) + LOGGER.exception(exception) + return {"result": False, 'message': str(exception), "code": getattr(exception, "code", 500)} + + +@hug.extend_api() +def with_other_apis(): + return [status, logs, configuration, pdp, policy, slave, auth, + perimeter, assignments, meta_data, meta_rules, models, json_import, json_export, + rules, data, attributes] + + +@hug.static('/static') +def static_front(): + return (configuration.get_configuration("dashboard").get("root"), ) diff --git a/moon_manager/moonrc b/moon_manager/moonrc new file mode 100644 index 00000000..a3feb2ce --- /dev/null +++ b/moon_manager/moonrc @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +if [[ "$#" -ne 2 ]]; then + echo "Usage : source moonrc " +else + + if [[ -n "$1" ]]; then + MOON_USERNAME="$1" + fi + + if [[ -n "$2" ]]; then + MOON_PASSWORD="$2" + fi + + export MOON_USERNAME=$MOON_USERNAME + export MOON_PASSWORD=$MOON_PASSWORD + +fi \ No newline at end of file diff --git a/moon_manager/requirements.txt b/moon_manager/requirements.txt index e2dd5c96..24d9c944 100644 --- a/moon_manager/requirements.txt +++ b/moon_manager/requirements.txt @@ -1,5 +1,9 @@ -flask -flask_restful -flask_cors -python_moonutilities -python_moondb +hug!=2.5.0 +pyyaml +moon_utilities +moon_engine +tinydb +gunicorn +requests +sqlalchemy +pymysql diff --git a/moon_manager/setup.py b/moon_manager/setup.py index 35c944c3..6fad66c9 100644 --- a/moon_manager/setup.py +++ b/moon_manager/setup.py @@ -1,12 +1,59 @@ -# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors -# This software is distributed under the terms and conditions of the 'Apache-2.0' -# license which can be found in the file 'LICENSE' in this package distribution -# or at 'http://www.apache.org/licenses/LICENSE-2.0'. +# Software Name: MOON +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +import os +import shutil from setuptools import setup, find_packages +from setuptools.command.install import install +from setuptools.command.develop import develop import moon_manager +def initConfiguration(): + if os.name == "posix": + try: + os.mkdir("/etc/moon") + except FileExistsError: + pass + if not os.path.exists(os.path.join("/etc", "moon", "moon.yaml")): + print("Installing configuration file in /etc") + shutil.copy(os.path.join("conf", "moon.yaml"), + os.path.join("/etc", "moon")) + # else: + # raise NotImplementedError('You should install configuration file somewhere ' + # 'on your system') + + +class CustomInstallCommand(install): + """Customized setuptools install command - install configuration file in etc.""" + + def run(self): + install.run(self) + initConfiguration() + + +class CustomDevelopCommand(develop): + """Customized setuptools develop command - install configuration file in etc.""" + + def run(self): + develop.run(self) + initConfiguration() + with open('requirements.txt') as f: + requirements = filter( + lambda s: (len(s)>0 and s.strip()[0]!='#'), + f.read().split('\n')) + print('requirements', requirements) + + setup( name='moon_manager', @@ -23,11 +70,24 @@ setup( long_description=open('README.md').read(), - # install_requires= , + install_requires=list(filter( + lambda s: (len(s) > 0 and s.strip()[0] != '#'), + open('requirements.txt').read().split('\n'))), + + data_files=[ + ("moon", ["conf/moon.yaml"]), + ("moon", ["moonrc"]) + ], + include_package_data=True, - url='https://git.opnfv.org/cgit/moon', + cmdclass={ + 'develop': CustomDevelopCommand, + 'install': CustomInstallCommand, + }, + + url='', classifiers=[ "Programming Language :: Python", @@ -40,8 +100,10 @@ setup( entry_points={ 'console_scripts': [ - 'moon_manager = moon_manager.server:create_server', + 'moon_manager = moon_manager.__main__:run', + 'moon_manager_setup = moon_manager.manager_setup:setup' ], + } ) diff --git a/moon_manager/tests/command_lines/test_complete.py b/moon_manager/tests/command_lines/test_complete.py new file mode 100644 index 00000000..f2d2cdf2 --- /dev/null +++ b/moon_manager/tests/command_lines/test_complete.py @@ -0,0 +1,764 @@ +# Software Name: MOON: + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + +import pytest +import os +import yaml + +pytest_plugins = ["pytester"] +CONF = """ +debug: true + +database: + # url: mysql+pymysql://moon:p4sswOrd1@db/moon + url: sqlite:////tmp/database.db + driver: moon_manager.plugins.sql + migration_dir: moon_manager.api.db.migrations + # migration_dir: /home/tom/projets/moon/moon_manager/moon_manager/api/db/migrations/ + +management: + url: http://127.0.0.1:8000 + user: admin + password: admin + token_file: moon.pwd + +orchestration: + driver: moon_manager.plugins.pyorchestrator + connection: local + # driver: moon_manager.plugins.docker_compose + # connection: ssh://admin:admin@1.1.1.1 + # driver: moon_manager.plugins.kubernetes + # connection: ~/.kube/config + port: 10000...10100 + config_dir: /tmp + +information: +# driver: moon_manager.plugins.moon_openstack_plugin +# subjects: +# driver: +# - moon_manager.plugins.openstack +# objects: +# driver: +# - moon_manager.plugins.openstack +# actions: +# driver: +# - moon_manager.plugins.openstack + openstack: + driver: moon_manager.plugins.moon_openstack_plugin + url: http://keystone:5000/v3 + user: admin + password: p4ssw0rd + domain: default + project: admin + check_token: false + certificate: false + global_attrs: + driver: moon_manager.plugins.global_attrs + attributes: + +plugins: + directory: /var/moon/plugins + +components: + manager: + port: 8080 + bind: 0.0.0.0 + hostname: manager + +logging: + version: 1 + + formatters: + brief: + format: "%(levelname)s %(name)s %(message)-30s" + custom: + format: "%(asctime)-15s %(levelname)s %(name)s %(message)s" + + handlers: + console: + class : logging.StreamHandler + formatter: custom + level : INFO + stream : ext://sys.stdout + file: + class : logging.handlers.RotatingFileHandler + formatter: custom + level : DEBUG + filename: /tmp/moon.log + maxBytes: 1048576 + backupCount: 3 + + loggers: + moon: + level: DEBUG + handlers: [console, file] + propagate: no + + root: + level: ERROR + handlers: [console] + +""" +POLICY = """ +{ + "policies": [ + { + "name": "MLS Policy", + "genre": "authz", + "description": "MLS policy", + "model": { + "name": "MLS" + }, + "mandatory": true, + "override": true + } + ], + "models": [ + { + "name": "MLS", + "description": "", + "meta_rules": [ + { + "name": "mls" + } + ], + "override": true + } + ], + "subjects": [ + { + "name": "admin", + "description": "", + "extra": {}, + "policies": [ + { + "name": "MLS Policy" + } + ] + }, + { + "name": "demo", + "description": "", + "extra": {}, + "policies": [ + { + "name": "MLS Policy" + } + ] + } + ], + "subject_categories": [ + { + "name": "level", + "description": "subject level" + } + ], + "subject_data": [ + { + "name": "high", + "description": "", + "policies": [], + "category": { + "name": "level" + } + }, + { + "name": "medium", + "description": "", + "policies": [], + "category": { + "name": "level" + } + }, + { + "name": "low", + "description": "", + "policies": [], + "category": { + "name": "level" + } + } + ], + "subject_assignments": [ + { + "subject": {"name": "admin"}, + "category": {"name": "level"}, + "assignments": [{"name": "high"}] + } + ], + "objects": [ + { + "name": "vm1", + "description": "", + "extra": {}, + "policies": [ + { + "name": "MLS Policy" + } + ] + }, + { + "name": "vm2", + "description": "", + "extra": {}, + "policies": [ + { + "name": "MLS Policy" + } + ] + }, + { + "name": "vm3", + "description": "", + "extra": {}, + "policies": [ + { + "name": "MLS Policy" + } + ] + } + ], + "object_categories": [ + { + "name": "level", + "description": "object level" + } + ], + "object_data": [ + { + "name": "high", + "description": "", + "policies": [], + "category": { + "name": "level" + } + }, + { + "name": "medium", + "description": "", + "policies": [], + "category": { + "name": "level" + } + }, + { + "name": "low", + "description": "", + "policies": [], + "category": { + "name": "level" + } + } + ], + "object_assignments": [ + { + "object": {"name": "vm1"}, + "category": {"name": "level"}, + "assignments": [{"name": "high"}] + }, + { + "object": {"name": "vm2"}, + "category": {"name": "level"}, + "assignments": [{"name": "medium"}] + } + ], + "actions": [ + { + "name": "use_image", + "description": "use_image action for glance", + "extra": { + "component": "glance" + }, + "policies": [] + }, + { + "name": "get_images", + "description": "get_images action for glance", + "extra": { + "component": "glance" + }, + "policies": [] + }, + { + "name": "update_image", + "description": "update_image action for glance", + "extra": { + "component": "glance" + }, + "policies": [] + }, + { + "name": "set_image", + "description": "set_image action for glance", + "extra": { + "component": "glance" + }, + "policies": [] + } + ], + "action_categories": [ + { + "name": "type", + "description": "" + } + ], + "action_data": [ + { + "name": "read", + "description": "read action", + "policies": [], + "category": { + "name": "type" + } + }, + { + "name": "write", + "description": "write action", + "policies": [], + "category": { + "name": "type" + } + }, + { + "name": "execute", + "description": "execute action", + "policies": [], + "category": { + "name": "type" + } + } + ], + "action_assignments": [ + { + "action": {"name": "use_image"}, + "category": {"name": "type"}, + "assignments": [{"name": "read"}, {"name": "execute"}] + }, + { + "action": {"name": "update_image"}, + "category": {"name": "type"}, + "assignments": [{"name": "read"}, {"name": "write"}] + }, + { + "action": {"name": "set_image"}, + "category": {"name": "type"}, + "assignments": [{"name": "write"}] + } + ], + "meta_rules": [ + { + "name": "mls", + "description": "", + "subject_categories": [{"name": "level"}], + "object_categories": [{"name": "level"}], + "action_categories": [{"name": "type"}] + } + ], + "rules": [ + { + "meta_rule": {"name": "mls"}, + "rule": { + "subject_data": [{"name": "high"}], + "object_data": [{"name": "high"}], + "action_data": [{"name": "read"}] + }, + "policy": {"name": "MLS Policy"}, + "instructions": [{"decision": "grant"}], + "enabled": true + }, + { + "meta_rule": {"name": "mls"}, + "rule": { + "subject_data": [{"name": "high"}], + "object_data": [{"name": "medium"}], + "action_data": [{"name": "read"}] + }, + "policy": {"name": "MLS Policy"}, + "instructions": [{"decision": "grant"}], + "enabled": true + }, + { + "meta_rule": {"name": "mls"}, + "rule": { + "subject_data": [{"name": "high"}], + "object_data": [{"name": "low"}], + "action_data": [{"name": "read"}] + }, + "policy": {"name": "MLS Policy"}, + "instructions": [{"decision": "grant"}], + "enabled": true + }, + { + "meta_rule": {"name": "mls"}, + "rule": { + "subject_data": [{"name": "medium"}], + "object_data": [{"name": "medium"}], + "action_data": [{"name": "read"}] + }, + "policy": {"name": "MLS Policy"}, + "instructions": [{"decision": "grant"}], + "enabled": true + }, + { + "meta_rule": {"name": "mls"}, + "rule": { + "subject_data": [{"name": "medium"}], + "object_data": [{"name": "low"}], + "action_data": [{"name": "read"}] + }, + "policy": {"name": "MLS Policy"}, + "instructions": [{"decision": "grant"}], + "enabled": true + }, + { + "meta_rule": {"name": "mls"}, + "rule": { + "subject_data": [{"name": "low"}], + "object_data": [{"name": "low"}], + "action_data": [{"name": "read"}] + }, + "policy": {"name": "MLS Policy"}, + "instructions": [{"decision": "grant"}], + "enabled": true + }, + { + "meta_rule": {"name": "mls"}, + "rule": { + "subject_data": [{"name": "high"}], + "object_data": [{"name": "high"}], + "action_data": [{"name": "write"}] + }, + "policy": {"name": "MLS Policy"}, + "instructions": [{"decision": "grant"}], + "enabled": true + }, + { + "meta_rule": {"name": "mls"}, + "rule": { + "subject_data": [{"name": "high"}], + "object_data": [{"name": "medium"}], + "action_data": [{"name": "write"}] + }, + "policy": {"name": "MLS Policy"}, + "instructions": [{"decision": "grant"}], + "enabled": true + }, + { + "meta_rule": {"name": "mls"}, + "rule": { + "subject_data": [{"name": "high"}], + "object_data": [{"name": "low"}], + "action_data": [{"name": "write"}] + }, + "policy": {"name": "MLS Policy"}, + "instructions": [{"decision": "grant"}], + "enabled": true + }, + { + "meta_rule": {"name": "mls"}, + "rule": { + "subject_data": [{"name": "medium"}], + "object_data": [{"name": "medium"}], + "action_data": [{"name": "write"}] + }, + "policy": {"name": "MLS Policy"}, + "instructions": [{"decision": "grant"}], + "enabled": true + }, + { + "meta_rule": {"name": "mls"}, + "rule": { + "subject_data": [{"name": "medium"}], + "object_data": [{"name": "low"}], + "action_data": [{"name": "write"}] + }, + "policy": {"name": "MLS Policy"}, + "instructions": [{"decision": "grant"}], + "enabled": true + }, + { + "meta_rule": {"name": "mls"}, + "rule": { + "subject_data": [{"name": "low"}], + "object_data": [{"name": "low"}], + "action_data": [{"name": "write"}] + }, + "policy": {"name": "MLS Policy"}, + "instructions": [{"decision": "grant"}], + "enabled": true + }, + { + "meta_rule": {"name": "mls"}, + "rule": { + "subject_data": [{"name": "high"}], + "object_data": [{"name": "high"}], + "action_data": [{"name": "execute"}] + }, + "policy": {"name": "MLS Policy"}, + "instructions": [{"decision": "grant"}], + "enabled": true + }, + { + "meta_rule": {"name": "mls"}, + "rule": { + "subject_data": [{"name": "high"}], + "object_data": [{"name": "medium"}], + "action_data": [{"name": "execute"}] + }, + "policy": {"name": "MLS Policy"}, + "instructions": [{"decision": "grant"}], + "enabled": true + }, + { + "meta_rule": {"name": "mls"}, + "rule": { + "subject_data": [{"name": "high"}], + "object_data": [{"name": "low"}], + "action_data": [{"name": "execute"}] + }, + "policy": {"name": "MLS Policy"}, + "instructions": [{"decision": "grant"}], + "enabled": true + }, + { + "meta_rule": {"name": "mls"}, + "rule": { + "subject_data": [{"name": "medium"}], + "object_data": [{"name": "medium"}], + "action_data": [{"name": "execute"}] + }, + "policy": {"name": "MLS Policy"}, + "instructions": [{"decision": "grant"}], + "enabled": true + }, + { + "meta_rule": {"name": "mls"}, + "rule": { + "subject_data": [{"name": "medium"}], + "object_data": [{"name": "low"}], + "action_data": [{"name": "execute"}] + }, + "policy": {"name": "MLS Policy"}, + "instructions": [{"decision": "grant"}], + "enabled": true + }, + { + "meta_rule": {"name": "mls"}, + "rule": { + "subject_data": [{"name": "low"}], + "object_data": [{"name": "low"}], + "action_data": [{"name": "execute"}] + }, + "policy": {"name": "MLS Policy"}, + "instructions": [{"decision": "grant"}], + "enabled": true + } + ] +} +""" +PWD = '{"_default": {"1": {"username": "admin", "password": ' \ + '"d2eeefe5df3be1d96c102bc91bd2b3c3a93d58f6c9949b91e4a478135f' \ + '383efcd66af2ede09aff03d579f44e4b6a0bd4e9d9de3dc28222fda7a70f34045fe777", ' \ + '"salt": "37df3e00b84ea5d1d5b17868b588e8c7a32fa2a18d031828ac2b6fd3c37687a2c0105' \ + '2a9c395a32b441bac2034dca1966e88039a1e83aac80795bac9c3fa92bf", "api_key": "4ec3' \ + 'babcdfc765e81e099a29b9d69bb7dbe38b8f226663c09bf79061d3d97d87e30fc5e83a90557313' \ + 'd4fc471d8ea4eecb4faabc9773594dc63018f503e36a22"}}}' + +try: + PWD = open("moon.pwd").read() +except FileNotFoundError: + PWD = open("/etc/moon/moon.pwd").read() + +os.environ["MOON_USERNAME"] = "admin" +os.environ["MOON_PASSWORD"] = "admin" + + +def get_policy_id(policies, name="MLS Policy"): + for policy_id, policy_value in policies.get("policies").items(): + if policy_value.get("name") == name: + return policy_id + + +@pytest.fixture +def run(testdir): + open(os.path.join(str(testdir), "moon.yaml"), "w").write(CONF) + open(os.path.join(str(testdir), "policy_example.json"), "w").write(POLICY) + open(os.path.join(str(testdir), "moon.pwd"), "w").write(PWD) + + def do_run(*args): + args = ["moon_manager"] + list(args) + ret = testdir.run(*args) + print(testdir) + try: + return yaml.safe_load(ret.stdout.lines[-1]) + except Exception as e: + print(e) + return ret.stdout + return do_run + + +@pytest.fixture +def import_policy(run): + if not get_policy_id(run("policies", "list")): + run("import", "policy_example.json") + assert get_policy_id(run("policies", "list")) + return get_policy_id(run("policies", "list")) + + +# def test_import(run): +# ret = run("import", "policy_example.json") +# assert ret +# # TODO: check if policy, meta-rule, ... have been created. + + +def test_slaves(run): + ret = run("slaves", "list") + assert "slaves" in ret + + +def test_pdp(run): + ret = run("pdp", "list") + assert "pdps" in ret + + +def test_policies(run): + ret = run("policies", "list") + assert "policies" in ret + + +def test_subjects(run): + ret = run("subjects", "list") + assert "subjects" in ret + + +def test_objects(run): + ret = run("objects", "list") + assert "objects" in ret + + +def test_actions(run): + ret = run("actions", "list") + assert "actions" in ret + + +def test_subject_categories(run): + ret = run("subject_categories", "list") + assert "subject_categories" in ret + + +def test_object_categories(run): + ret = run("object_categories", "list") + assert "object_categories" in ret + + +def test_action_categories(run): + ret = run("action_categories", "list") + assert "action_categories" in ret + + +# def test_subject_data(run): +# ret = run("subject_data", "get") +# assert "subject_data" in ret +# +# +# def test_object_data(run): +# ret = run("object_data", "get") +# assert "object_data" in ret +# +# +# def test_action_data(run): +# ret = run("action_data", "get") +# assert "action_data" in ret + + +def test_rules(run, import_policy): + ret = run("rules", "list", import_policy) + assert "rules" in ret + + +def test_meta_rules(run): + ret = run("meta_rules", "list") + assert "meta_rules" in ret + + +def test_models(run): + ret = run("models", "list") + print(ret) + assert "models" in ret + + +def test_subject_assignments(run, import_policy): + ret = run("subject_assignments", "list", "MLS Policy") + assert "subject_assignments" in ret + ret = run("subject_assignments", "add", "MLS Policy", "demo", "level", "low") + assert "subject_assignments" in ret + ret = run("subject_assignments", "delete", "MLS Policy", "demo", "level", "low") + assert ret + + +def test_object_assignments(run, import_policy): + ret = run("object_assignments", "list", "MLS Policy") + assert "object_assignments" in ret + ret = run("object_assignments", "add", "MLS Policy", "vm3", "level", "low") + assert "object_assignments" in ret + ret = run("object_assignments", "delete", "MLS Policy", "vm3", "level", "low") + assert ret + + +def test_action_assignments(run, import_policy): + ret = run("action_assignments", "list", "MLS Policy") + assert "action_assignments" in ret + ret = run("action_assignments", "add", "MLS Policy", "get_images", "type", "read") + assert "action_assignments" in ret + ret = run("action_assignments", "delete", "MLS Policy", "get_images", "type", "read") + assert ret + + +# def test_complete(run, import_policy): +# slaves = run("slaves", "get").get("slaves") +# if not slaves: +# ret = run("slaves", "create") +# assert "slaves" in ret +# if not get_policy_id(run("policies", "get")): +# ret = run("import", "policy_example.json") +# assert ret +# +# ret = run("subject_assignments", "create", "MLS Policy", "admin", "level", "high") +# assert "subject_assignments" in ret +# +# subjects = run("subjects", "get", "-n", "admin").get("subjects") +# subject_id = subjects +# +# ret = run("slaves", "delete", "-n", "default") +# assert ret + +def test_users(run): + ret = run("users", "add", "bob", "-p password_bob") + if ret != {'error': 'User bob already exists'}: + assert ret['user_created']['username'] == 'bob' + + ret = run("users", "key", "bob", "-p password_bob") + assert ret + + ret = run("users", "list") + assert "users" in ret + + ret = run("users", "change_password", "bob", "-p passwordbob", "-n new_password") + assert ret == "Wrong password" + + ret = run("users", "change_password", "bob", "-p password_bob", "-n new_password") + assert ret['result'] == "success" + + ret = run("users", "key", "bob", "-p password_bob") + assert not ret + + ret = run("users", "key", "bob", "-p new_password") + assert ret diff --git a/moon_manager/tests/func_postman/Import tests.postman_collection.json b/moon_manager/tests/func_postman/Import tests.postman_collection.json new file mode 100644 index 00000000..93d44e62 --- /dev/null +++ b/moon_manager/tests/func_postman/Import tests.postman_collection.json @@ -0,0 +1,1476 @@ +{ + "info": { + "_postman_id": "86591644-ffdd-4b59-87c1-64221dfa6deb", + "name": "Import tests", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "Import", + "event": [ + { + "listen": "test", + "script": { + "id": "b2ac03b5-4862-46f0-8c04-a2b491d5534a", + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Body matches string\", function () {", + " pm.expect(pm.response.text()).to.include(\"Import ok !\");", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "X-Api-Key", + "value": "{{X-Api-Key}}", + "type": "text" + }, + { + "key": "Content-Type", + "name": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"policies\": [\n {\n \"name\": \"MLS Policy\",\n \"genre\": \"authz\",\n \"description\": \"MLS policy\",\n \"model\": {\n \"name\": \"MLS\"\n },\n \"mandatory\": true,\n \"override\": true\n }\n ],\n \"models\": [\n {\n \"name\": \"MLS\",\n \"description\": \"\",\n \"meta_rules\": [\n {\n \"name\": \"mls\"\n }\n ],\n \"override\": true\n }\n ],\n \"subjects\": [\n {\n \"name\": \"admin\",\n \"description\": \"\",\n \"extra\": {},\n \"policies\": [\n {\n \"name\": \"MLS Policy\"\n }\n ]\n },\n {\n \"name\": \"demo\",\n \"description\": \"\",\n \"extra\": {},\n \"policies\": [\n {\n \"name\": \"MLS Policy\"\n }\n ]\n }\n ],\n \"subject_categories\": [\n {\n \"name\": \"level\",\n \"description\": \"subject level\"\n }\n ],\n \"subject_data\": [\n {\n \"name\": \"high\",\n \"description\": \"\",\n \"policies\": [],\n \"category\": {\n \"name\": \"level\"\n }\n },\n {\n \"name\": \"medium\",\n \"description\": \"\",\n \"policies\": [],\n \"category\": {\n \"name\": \"level\"\n }\n },\n {\n \"name\": \"low\",\n \"description\": \"\",\n \"policies\": [],\n \"category\": {\n \"name\": \"level\"\n }\n }\n ],\n \"subject_assignments\": [\n {\n \"subject\": {\"name\": \"admin\"},\n \"category\": {\"name\": \"level\"},\n \"assignments\": [{\"name\": \"high\"}]\n },\n {\n \"subject\": {\"name\": \"demo\"},\n \"category\": {\"name\": \"level\"},\n \"assignments\": [{\"name\": \"low\"}]\n }\n ],\n \"objects\": [\n {\n \"name\": \"vm1\",\n \"description\": \"\",\n \"extra\": {},\n \"policies\": [\n {\n \"name\": \"MLS Policy\"\n }\n ]\n },\n {\n \"name\": \"vm2\",\n \"description\": \"\",\n \"extra\": {},\n \"policies\": [\n {\n \"name\": \"MLS Policy\"\n }\n ]\n },\n {\n \"name\": \"vm3\",\n \"description\": \"\",\n \"extra\": {},\n \"policies\": [\n {\n \"name\": \"MLS Policy\"\n }\n ]\n }\n ],\n \"object_categories\": [\n {\n \"name\": \"level\",\n \"description\": \"object level\"\n }\n ],\n \"object_data\": [\n {\n \"name\": \"high\",\n \"description\": \"\",\n \"policies\": [],\n \"category\": {\n \"name\": \"level\"\n }\n },\n {\n \"name\": \"medium\",\n \"description\": \"\",\n \"policies\": [],\n \"category\": {\n \"name\": \"level\"\n }\n },\n {\n \"name\": \"low\",\n \"description\": \"\",\n \"policies\": [],\n \"category\": {\n \"name\": \"level\"\n }\n }\n ],\n \"object_assignments\": [\n {\n \"object\": {\"name\": \"vm1\"},\n \"category\": {\"name\": \"level\"},\n \"assignments\": [{\"name\": \"high\"}]\n },\n {\n \"object\": {\"name\": \"vm2\"},\n \"category\": {\"name\": \"level\"},\n \"assignments\": [{\"name\": \"medium\"}]\n },\n {\n \"object\": {\"name\": \"vm3\"},\n \"category\": {\"name\": \"level\"},\n \"assignments\": [{\"name\": \"low\"}]\n }\n ],\n \"actions\": [\n {\n \"name\": \"use_image\",\n \"description\": \"use_image action for glance\",\n \"extra\": {\n \"component\": \"glance\"\n },\n \"policies\": []\n },\n {\n \"name\": \"get_images\",\n \"description\": \"get_images action for glance\",\n \"extra\": {\n \"component\": \"glance\"\n },\n \"policies\": []\n },\n {\n \"name\": \"update_image\",\n \"description\": \"update_image action for glance\",\n \"extra\": {\n \"component\": \"glance\"\n },\n \"policies\": []\n },\n {\n \"name\": \"set_image\",\n \"description\": \"set_image action for glance\",\n \"extra\": {\n \"component\": \"glance\"\n },\n \"policies\": []\n }\n ],\n \"action_categories\": [\n {\n \"name\": \"type\",\n \"description\": \"\"\n }\n ],\n \"action_data\": [\n {\n \"name\": \"read\",\n \"description\": \"read action\",\n \"policies\": [],\n \"category\": {\n \"name\": \"type\"\n }\n },\n {\n \"name\": \"write\",\n \"description\": \"write action\",\n \"policies\": [],\n \"category\": {\n \"name\": \"type\"\n }\n },\n {\n \"name\": \"execute\",\n \"description\": \"execute action\",\n \"policies\": [],\n \"category\": {\n \"name\": \"type\"\n }\n }\n ],\n \"action_assignments\": [\n {\n \"action\": {\"name\": \"use_image\"},\n \"category\": {\"name\": \"type\"},\n \"assignments\": [{\"name\": \"read\"}, {\"name\": \"execute\"}]\n },\n {\n \"action\": {\"name\": \"update_image\"},\n \"category\": {\"name\": \"type\"},\n \"assignments\": [{\"name\": \"read\"}, {\"name\": \"write\"}]\n },\n {\n \"action\": {\"name\": \"set_image\"},\n \"category\": {\"name\": \"type\"},\n \"assignments\": [{\"name\": \"write\"}]\n },\n {\n \"action\": {\"name\": \"get_images\"},\n \"category\": {\"name\": \"type\"},\n \"assignments\": [{\"name\": \"read\"}]\n }\n ],\n \"meta_rules\": [\n {\n \"name\": \"mls\",\n \"description\": \"\",\n \"subject_categories\": [{\"name\": \"level\"}],\n \"object_categories\": [{\"name\": \"level\"}],\n \"action_categories\": [{\"name\": \"type\"}]\n }\n ],\n \"rules\": [\n {\n \"meta_rule\": {\"name\": \"mls\"},\n \"rule\": {\n \"subject_data\": [{\"name\": \"high\"}],\n \"object_data\": [{\"name\": \"high\"}],\n \"action_data\": [{\"name\": \"read\"}]\n },\n \"policy\": {\"name\": \"MLS Policy\"},\n \"instructions\": [{\"decision\": \"grant\"}],\n \"enabled\": true\n },\n {\n \"meta_rule\": {\"name\": \"mls\"},\n \"rule\": {\n \"subject_data\": [{\"name\": \"high\"}],\n \"object_data\": [{\"name\": \"medium\"}],\n \"action_data\": [{\"name\": \"read\"}]\n },\n \"policy\": {\"name\": \"MLS Policy\"},\n \"instructions\": [{\"decision\": \"grant\"}],\n \"enabled\": true\n },\n {\n \"meta_rule\": {\"name\": \"mls\"},\n \"rule\": {\n \"subject_data\": [{\"name\": \"high\"}],\n \"object_data\": [{\"name\": \"low\"}],\n \"action_data\": [{\"name\": \"read\"}]\n },\n \"policy\": {\"name\": \"MLS Policy\"},\n \"instructions\": [{\"decision\": \"grant\"}],\n \"enabled\": true\n },\n {\n \"meta_rule\": {\"name\": \"mls\"},\n \"rule\": {\n \"subject_data\": [{\"name\": \"medium\"}],\n \"object_data\": [{\"name\": \"medium\"}],\n \"action_data\": [{\"name\": \"read\"}]\n },\n \"policy\": {\"name\": \"MLS Policy\"},\n \"instructions\": [{\"decision\": \"grant\"}],\n \"enabled\": true\n },\n {\n \"meta_rule\": {\"name\": \"mls\"},\n \"rule\": {\n \"subject_data\": [{\"name\": \"medium\"}],\n \"object_data\": [{\"name\": \"low\"}],\n \"action_data\": [{\"name\": \"read\"}]\n },\n \"policy\": {\"name\": \"MLS Policy\"},\n \"instructions\": [{\"decision\": \"grant\"}],\n \"enabled\": true\n },\n {\n \"meta_rule\": {\"name\": \"mls\"},\n \"rule\": {\n \"subject_data\": [{\"name\": \"low\"}],\n \"object_data\": [{\"name\": \"low\"}],\n \"action_data\": [{\"name\": \"read\"}]\n },\n \"policy\": {\"name\": \"MLS Policy\"},\n \"instructions\": [{\"decision\": \"grant\"}],\n \"enabled\": true\n },\n {\n \"meta_rule\": {\"name\": \"mls\"},\n \"rule\": {\n \"subject_data\": [{\"name\": \"high\"}],\n \"object_data\": [{\"name\": \"high\"}],\n \"action_data\": [{\"name\": \"write\"}]\n },\n \"policy\": {\"name\": \"MLS Policy\"},\n \"instructions\": [{\"decision\": \"grant\"}],\n \"enabled\": true\n },\n {\n \"meta_rule\": {\"name\": \"mls\"},\n \"rule\": {\n \"subject_data\": [{\"name\": \"high\"}],\n \"object_data\": [{\"name\": \"medium\"}],\n \"action_data\": [{\"name\": \"write\"}]\n },\n \"policy\": {\"name\": \"MLS Policy\"},\n \"instructions\": [{\"decision\": \"grant\"}],\n \"enabled\": true\n },\n {\n \"meta_rule\": {\"name\": \"mls\"},\n \"rule\": {\n \"subject_data\": [{\"name\": \"high\"}],\n \"object_data\": [{\"name\": \"low\"}],\n \"action_data\": [{\"name\": \"write\"}]\n },\n \"policy\": {\"name\": \"MLS Policy\"},\n \"instructions\": [{\"decision\": \"grant\"}],\n \"enabled\": true\n },\n {\n \"meta_rule\": {\"name\": \"mls\"},\n \"rule\": {\n \"subject_data\": [{\"name\": \"medium\"}],\n \"object_data\": [{\"name\": \"medium\"}],\n \"action_data\": [{\"name\": \"write\"}]\n },\n \"policy\": {\"name\": \"MLS Policy\"},\n \"instructions\": [{\"decision\": \"grant\"}],\n \"enabled\": true\n },\n {\n \"meta_rule\": {\"name\": \"mls\"},\n \"rule\": {\n \"subject_data\": [{\"name\": \"medium\"}],\n \"object_data\": [{\"name\": \"low\"}],\n \"action_data\": [{\"name\": \"write\"}]\n },\n \"policy\": {\"name\": \"MLS Policy\"},\n \"instructions\": [{\"decision\": \"grant\"}],\n \"enabled\": true\n },\n {\n \"meta_rule\": {\"name\": \"mls\"},\n \"rule\": {\n \"subject_data\": [{\"name\": \"low\"}],\n \"object_data\": [{\"name\": \"low\"}],\n \"action_data\": [{\"name\": \"write\"}]\n },\n \"policy\": {\"name\": \"MLS Policy\"},\n \"instructions\": [{\"decision\": \"grant\"}],\n \"enabled\": true\n },\n {\n \"meta_rule\": {\"name\": \"mls\"},\n \"rule\": {\n \"subject_data\": [{\"name\": \"high\"}],\n \"object_data\": [{\"name\": \"high\"}],\n \"action_data\": [{\"name\": \"execute\"}]\n },\n \"policy\": {\"name\": \"MLS Policy\"},\n \"instructions\": [{\"decision\": \"grant\"}],\n \"enabled\": true\n },\n {\n \"meta_rule\": {\"name\": \"mls\"},\n \"rule\": {\n \"subject_data\": [{\"name\": \"high\"}],\n \"object_data\": [{\"name\": \"medium\"}],\n \"action_data\": [{\"name\": \"execute\"}]\n },\n \"policy\": {\"name\": \"MLS Policy\"},\n \"instructions\": [{\"decision\": \"grant\"}],\n \"enabled\": true\n },\n {\n \"meta_rule\": {\"name\": \"mls\"},\n \"rule\": {\n \"subject_data\": [{\"name\": \"high\"}],\n \"object_data\": [{\"name\": \"low\"}],\n \"action_data\": [{\"name\": \"execute\"}]\n },\n \"policy\": {\"name\": \"MLS Policy\"},\n \"instructions\": [{\"decision\": \"grant\"}],\n \"enabled\": true\n },\n {\n \"meta_rule\": {\"name\": \"mls\"},\n \"rule\": {\n \"subject_data\": [{\"name\": \"medium\"}],\n \"object_data\": [{\"name\": \"medium\"}],\n \"action_data\": [{\"name\": \"execute\"}]\n },\n \"policy\": {\"name\": \"MLS Policy\"},\n \"instructions\": [{\"decision\": \"grant\"}],\n \"enabled\": true\n },\n {\n \"meta_rule\": {\"name\": \"mls\"},\n \"rule\": {\n \"subject_data\": [{\"name\": \"medium\"}],\n \"object_data\": [{\"name\": \"low\"}],\n \"action_data\": [{\"name\": \"execute\"}]\n },\n \"policy\": {\"name\": \"MLS Policy\"},\n \"instructions\": [{\"decision\": \"grant\"}],\n \"enabled\": true\n },\n {\n \"meta_rule\": {\"name\": \"mls\"},\n \"rule\": {\n \"subject_data\": [{\"name\": \"low\"}],\n \"object_data\": [{\"name\": \"low\"}],\n \"action_data\": [{\"name\": \"execute\"}]\n },\n \"policy\": {\"name\": \"MLS Policy\"},\n \"instructions\": [{\"decision\": \"grant\"}],\n \"enabled\": true\n }\n ]\n}" + }, + "url": { + "raw": "http://127.0.0.1:8000/import", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "import" + ] + } + }, + "response": [] + }, + { + "name": "Get Policies", + "event": [ + { + "listen": "test", + "script": { + "id": "7a625729-6d09-4932-97ea-e7e5d8a2f2a7", + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "var jsonData = JSON.parse(responseBody);", + "var policy_id = Object.keys(jsonData.policies)[0]", + "pm.globals.set(\"policy_id\", policy_id);", + "", + "pm.test(\"Get policy name\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.policies[policy_id].name).to.eql(\"MLS Policy\");", + "});", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "X-Api-Key", + "value": "{{X-Api-Key}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:8000/policies", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "policies" + ] + } + }, + "response": [] + }, + { + "name": "Get Models", + "event": [ + { + "listen": "test", + "script": { + "id": "0d55b7e8-434a-4715-9966-866282b0d120", + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "var jsonData = JSON.parse(responseBody);", + "var model_id = Object.keys(jsonData.models)[0]", + "pm.globals.set(\"model_id\", model_id);", + "", + "pm.test(\"Get model name\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.models[model_id].name).to.eql(\"MLS\");", + "});", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "X-Api-Key", + "type": "text", + "value": "{{X-Api-Key}}" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:8000/models", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "models" + ] + } + }, + "response": [] + }, + { + "name": "Get PDP", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Api-Key", + "type": "text", + "value": "{{X-Api-Key}}" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:8000/pdp", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "pdp" + ] + } + }, + "response": [] + }, + { + "name": "Get subjects", + "event": [ + { + "listen": "test", + "script": { + "id": "0d55b7e8-434a-4715-9966-866282b0d120", + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "var jsonData = JSON.parse(responseBody);", + "var subject_id0 = Object.keys(jsonData.subjects)[0]", + "var subject_id1 = Object.keys(jsonData.subjects)[1]", + "", + "pm.test(\"Check subject name 1\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.subjects[subject_id0].name).to.be.oneOf([\"admin\", \"demo\"]);", + "});", + "", + "pm.test(\"Check subject name 2\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.subjects[subject_id1].name).to.be.oneOf([\"admin\", \"demo\"]);", + "});", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "X-Api-Key", + "type": "text", + "value": "{{X-Api-Key}}" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:8000/subjects", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "subjects" + ] + } + }, + "response": [] + }, + { + "name": "Get objects", + "event": [ + { + "listen": "test", + "script": { + "id": "0d55b7e8-434a-4715-9966-866282b0d120", + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "var jsonData = JSON.parse(responseBody);", + "var object_id0 = Object.keys(jsonData.objects)[0]", + "var object_id1 = Object.keys(jsonData.objects)[1]", + "var object_id2 = Object.keys(jsonData.objects)[2]", + "", + "pm.test(\"Check object name 1\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.objects[object_id0].name).to.be.oneOf([\"vm1\", \"vm2\", \"vm3\"]);", + "});", + "", + "pm.test(\"Check object name 2\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.objects[object_id1].name).to.be.oneOf([\"vm1\", \"vm2\", \"vm3\"]);", + "});", + "", + "pm.test(\"Check object name 3\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.objects[object_id2].name).to.be.oneOf([\"vm1\", \"vm2\", \"vm3\"]);", + "});", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "X-Api-Key", + "type": "text", + "value": "{{X-Api-Key}}" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:8000/objects", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "objects" + ] + } + }, + "response": [] + }, + { + "name": "Get actions", + "event": [ + { + "listen": "test", + "script": { + "id": "0d55b7e8-434a-4715-9966-866282b0d120", + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "var jsonData = JSON.parse(responseBody);", + "var action_id0 = Object.keys(jsonData.actions)[0]", + "var action_id1 = Object.keys(jsonData.actions)[1]", + "var action_id2 = Object.keys(jsonData.actions)[2]", + "var action_id3 = Object.keys(jsonData.actions)[3]", + "", + "pm.test(\"Check action name 1\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.actions[action_id0].name).to.be.oneOf([\"use_image\", \"update_image\", \"get_images\", \"set_image\"]);", + "});", + "", + "pm.test(\"Check action name 2\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.actions[action_id1].name).to.be.oneOf([\"use_image\", \"update_image\", \"get_images\", \"set_image\"]);", + "});", + "", + "pm.test(\"Check action name 3\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.actions[action_id2].name).to.be.oneOf([\"use_image\", \"update_image\", \"get_images\", \"set_image\"]);", + "});", + "", + "pm.test(\"Check action name 4\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.actions[action_id3].name).to.be.oneOf([\"use_image\", \"update_image\", \"get_images\", \"set_image\"]);", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "X-Api-Key", + "type": "text", + "value": "{{X-Api-Key}}" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:8000/actions", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "actions" + ] + } + }, + "response": [] + }, + { + "name": "Get subjects Assignments", + "event": [ + { + "listen": "test", + "script": { + "id": "0d55b7e8-434a-4715-9966-866282b0d120", + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "X-Api-Key", + "type": "text", + "value": "{{X-Api-Key}}" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:8000/policies/{{policy_id}}/subject_assignments", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "policies", + "{{policy_id}}", + "subject_assignments" + ] + } + }, + "response": [] + }, + { + "name": "Get objects Assignments", + "event": [ + { + "listen": "test", + "script": { + "id": "0d55b7e8-434a-4715-9966-866282b0d120", + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "X-Api-Key", + "type": "text", + "value": "{{X-Api-Key}}" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:8000/policies/{{policy_id}}/object_assignments", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "policies", + "{{policy_id}}", + "object_assignments" + ] + } + }, + "response": [] + }, + { + "name": "Get actions Assignments", + "event": [ + { + "listen": "test", + "script": { + "id": "0d55b7e8-434a-4715-9966-866282b0d120", + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "X-Api-Key", + "type": "text", + "value": "{{X-Api-Key}}" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:8000/policies/{{policy_id}}/action_assignments", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "policies", + "{{policy_id}}", + "action_assignments" + ] + } + }, + "response": [] + }, + { + "name": "Create Slave", + "event": [ + { + "listen": "test", + "script": { + "id": "93584814-9658-421c-abd8-7f9169eba774", + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "var jsonData = JSON.parse(responseBody);", + "pm.globals.set(\"slave_port\", jsonData.slaves[Object.keys(jsonData.slaves)[0]].extra.port);", + "pm.globals.set(\"engine_api_key\", jsonData.slaves[Object.keys(jsonData.slaves)[0]].extra.api_key);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{X-Api-Key}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"name\": \"slave_test\",\n\t\"description\": \"...\",\n\t\"address\": \"local\"\n}" + }, + "url": { + "raw": "http://127.0.0.1:8000/slave", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "slave" + ] + } + }, + "response": [] + }, + { + "name": "Get Slaves", + "event": [ + { + "listen": "test", + "script": { + "id": "93584814-9658-421c-abd8-7f9169eba774", + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "var jsonData = JSON.parse(responseBody);", + "pm.globals.set(\"slave_port\", jsonData.slaves[Object.keys(jsonData.slaves)[0]].extra.port);", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + }, + { + "key": "x-api-key", + "value": "{{X-Api-Key}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:8000/slaves", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "slaves" + ] + } + }, + "response": [ + { + "name": "Get Slaves", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:8000/slaves", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "slaves" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Date", + "value": "Tue, 27 Nov 2018 10:52:13 GMT" + }, + { + "key": "Server", + "value": "WSGIServer/0.2 CPython/3.6.6" + }, + { + "key": "content-type", + "value": "application/json; charset=utf-8" + }, + { + "key": "content-length", + "value": "14" + } + ], + "cookie": [], + "body": "{\n \"slaves\": {}\n}" + } + ] + }, + { + "name": "Create PDP", + "event": [ + { + "listen": "test", + "script": { + "id": "d069a3e9-2497-40ab-99db-f2775eaf8c6d", + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "var jsonData = JSON.parse(responseBody);", + "pm.globals.set(\"pdp_id\", Object.keys(jsonData.pdps)[0]);", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + }, + { + "key": "x-api-key", + "value": "{{X-Api-Key}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"name\": \"pdp_1\",\n\t\"description\": \"...\",\n\t\"vim_project_id\": \"123456789\",\n\t\"security_pipeline\": [\"{{policy_id}}\"]\n}" + }, + "url": { + "raw": "http://127.0.0.1:8000/pdp", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "pdp" + ] + } + }, + "response": [] + }, + { + "name": "Get PDP", + "event": [ + { + "listen": "test", + "script": { + "id": "d069a3e9-2497-40ab-99db-f2775eaf8c6d", + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Check PDP name\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.pdps[Object.keys(jsonData.pdps)[0]].name).is.eq(\"pdp_1\");", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "X-Api-Key", + "type": "text", + "value": "{{X-Api-Key}}" + }, + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:8000/pdp", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "pdp" + ] + } + }, + "response": [] + }, + { + "name": "Add pipeline on slave1", + "event": [ + { + "listen": "prerequest", + "script": { + "id": "ce404af6-6555-43a1-aed4-3d21f9562d24", + "exec": [ + "setTimeout(function(){}, 1000);" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "id": "1cd0f94e-8ced-4f0a-97fa-23e74e59a63f", + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "X-Api-key", + "type": "text", + "value": "{{engine_api_key}}" + }, + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"name\": \"pdp_1\",\n\t\"description\": \"...\",\n\t\"vim_project_id\": \"123456789\",\n\t\"security_pipeline\": [\"{{policy_id}}\"]\n}" + }, + "url": { + "raw": "http://127.0.0.1:{{slave_port}}/pipeline/{{pdp_id}}", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "{{slave_port}}", + "path": [ + "pipeline", + "{{pdp_id}}" + ] + } + }, + "response": [] + }, + { + "name": "Test authz admin 1", + "event": [ + { + "listen": "test", + "script": { + "id": "a44804be-c5ae-440c-a4fb-b32cb522673b", + "exec": [ + "pm.test(\"Status code is 204\", function () {", + " pm.response.to.have.status(204);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:{{slave_port}}/authz/123456789/admin/vm1/get_images", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "{{slave_port}}", + "path": [ + "authz", + "123456789", + "admin", + "vm1", + "get_images" + ] + } + }, + "response": [] + }, + { + "name": "Test authz admin 2", + "event": [ + { + "listen": "test", + "script": { + "id": "a44804be-c5ae-440c-a4fb-b32cb522673b", + "exec": [ + "pm.test(\"Status code is 204\", function () {", + " pm.response.to.have.status(204);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:{{slave_port}}/authz/123456789/admin/vm1/use_image", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "{{slave_port}}", + "path": [ + "authz", + "123456789", + "admin", + "vm1", + "use_image" + ] + } + }, + "response": [] + }, + { + "name": "Test authz admin 3", + "event": [ + { + "listen": "test", + "script": { + "id": "a44804be-c5ae-440c-a4fb-b32cb522673b", + "exec": [ + "pm.test(\"Status code is 204\", function () {", + " pm.response.to.have.status(204);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:{{slave_port}}/authz/123456789/admin/vm1/update_image", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "{{slave_port}}", + "path": [ + "authz", + "123456789", + "admin", + "vm1", + "update_image" + ] + } + }, + "response": [] + }, + { + "name": "Test authz admin 4", + "event": [ + { + "listen": "test", + "script": { + "id": "a44804be-c5ae-440c-a4fb-b32cb522673b", + "exec": [ + "pm.test(\"Status code is 204\", function () {", + " pm.response.to.have.status(204);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:{{slave_port}}/authz/123456789/admin/vm1/set_image", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "{{slave_port}}", + "path": [ + "authz", + "123456789", + "admin", + "vm1", + "set_image" + ] + } + }, + "response": [] + }, + { + "name": "Test authz demo 1", + "event": [ + { + "listen": "test", + "script": { + "id": "a44804be-c5ae-440c-a4fb-b32cb522673b", + "exec": [ + "pm.test(\"Status code is 204\", function () {", + " pm.response.to.have.status(204);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:{{slave_port}}/authz/123456789/demo/vm3/get_images", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "{{slave_port}}", + "path": [ + "authz", + "123456789", + "demo", + "vm3", + "get_images" + ] + } + }, + "response": [] + }, + { + "name": "Test authz demo 2", + "event": [ + { + "listen": "test", + "script": { + "id": "a44804be-c5ae-440c-a4fb-b32cb522673b", + "exec": [ + "pm.test(\"Status code is 204\", function () {", + " pm.response.to.have.status(204);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:{{slave_port}}/authz/123456789/demo/vm3/set_image", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "{{slave_port}}", + "path": [ + "authz", + "123456789", + "demo", + "vm3", + "set_image" + ] + } + }, + "response": [] + }, + { + "name": "Test authz demo 3", + "event": [ + { + "listen": "test", + "script": { + "id": "a44804be-c5ae-440c-a4fb-b32cb522673b", + "exec": [ + "pm.test(\"Status code is 204\", function () {", + " pm.response.to.have.status(204);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:{{slave_port}}/authz/123456789/demo/vm3/use_image", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "{{slave_port}}", + "path": [ + "authz", + "123456789", + "demo", + "vm3", + "use_image" + ] + } + }, + "response": [] + }, + { + "name": "Test authz demo 4", + "event": [ + { + "listen": "test", + "script": { + "id": "a44804be-c5ae-440c-a4fb-b32cb522673b", + "exec": [ + "pm.test(\"Status code is 403\", function () {", + " pm.response.to.have.status(403);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:{{slave_port}}/authz/123456789/demo/vm2/get_images", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "{{slave_port}}", + "path": [ + "authz", + "123456789", + "demo", + "vm2", + "get_images" + ] + } + }, + "response": [] + }, + { + "name": "Test authz demo 5", + "event": [ + { + "listen": "test", + "script": { + "id": "a44804be-c5ae-440c-a4fb-b32cb522673b", + "exec": [ + "pm.test(\"Status code is 403\", function () {", + " pm.response.to.have.status(403);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:{{slave_port}}/authz/123456789/demo/vm2/set_image", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "{{slave_port}}", + "path": [ + "authz", + "123456789", + "demo", + "vm2", + "set_image" + ] + } + }, + "response": [] + }, + { + "name": "Test authz demo 6", + "event": [ + { + "listen": "test", + "script": { + "id": "a44804be-c5ae-440c-a4fb-b32cb522673b", + "exec": [ + "pm.test(\"Status code is 403\", function () {", + " pm.response.to.have.status(403);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:{{slave_port}}/authz/123456789/demo/vm2/set_image", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "{{slave_port}}", + "path": [ + "authz", + "123456789", + "demo", + "vm2", + "set_image" + ] + } + }, + "response": [] + }, + { + "name": "Test authz demo 7", + "event": [ + { + "listen": "test", + "script": { + "id": "a44804be-c5ae-440c-a4fb-b32cb522673b", + "exec": [ + "pm.test(\"Status code is 403\", function () {", + " pm.response.to.have.status(403);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:{{slave_port}}/authz/123456789/demo/vm1/get_images", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "{{slave_port}}", + "path": [ + "authz", + "123456789", + "demo", + "vm1", + "get_images" + ] + } + }, + "response": [] + }, + { + "name": "Test authz demo 8", + "event": [ + { + "listen": "test", + "script": { + "id": "a44804be-c5ae-440c-a4fb-b32cb522673b", + "exec": [ + "pm.test(\"Status code is 403\", function () {", + " pm.response.to.have.status(403);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:{{slave_port}}/authz/123456789/demo/vm1/set_image", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "{{slave_port}}", + "path": [ + "authz", + "123456789", + "demo", + "vm1", + "set_image" + ] + } + }, + "response": [] + }, + { + "name": "Test authz demo 9", + "event": [ + { + "listen": "test", + "script": { + "id": "a44804be-c5ae-440c-a4fb-b32cb522673b", + "exec": [ + "pm.test(\"Status code is 403\", function () {", + " pm.response.to.have.status(403);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:{{slave_port}}/authz/123456789/demo/vm1/set_image", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "{{slave_port}}", + "path": [ + "authz", + "123456789", + "demo", + "vm1", + "set_image" + ] + } + }, + "response": [] + } + ] +} \ No newline at end of file diff --git a/moon_manager/tests/func_postman/Test Manager.postman_collection.json b/moon_manager/tests/func_postman/Test Manager.postman_collection.json new file mode 100644 index 00000000..8d74ce83 --- /dev/null +++ b/moon_manager/tests/func_postman/Test Manager.postman_collection.json @@ -0,0 +1,916 @@ +{ + "info": { + "_postman_id": "b08759d2-c727-4dec-bff2-3858a28c6c5b", + "name": "Test Manager", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "Auth error", + "event": [ + { + "listen": "test", + "script": { + "id": "ec805426-ec88-4416-baed-992f3d2ffdfe", + "exec": [ + "pm.test(\"Status code is 401\", function () {", + " pm.response.to.have.status(401);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "X-Api-Key", + "type": "text", + "value": "000000000000000000000000000000000000000000000000000" + }, + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": {}, + "url": { + "raw": "http://127.0.0.1:8000/status", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "status" + ] + } + }, + "response": [] + }, + { + "name": "Create Slave", + "event": [ + { + "listen": "test", + "script": { + "id": "93584814-9658-421c-abd8-7f9169eba774", + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "var jsonData = JSON.parse(responseBody);", + "pm.globals.set(\"slave_port\", jsonData.slaves[Object.keys(jsonData.slaves)[0]].extra.port);", + "pm.globals.set(\"engine_api_key\", jsonData.slaves[Object.keys(jsonData.slaves)[0]].extra.api_key);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{X-Api-Key}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"name\": \"slave_test\",\n\t\"description\": \"...\",\n\t\"address\": \"local\"\n}" + }, + "url": { + "raw": "http://127.0.0.1:8000/slave", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "slave" + ] + } + }, + "response": [] + }, + { + "name": "Get Slaves", + "event": [ + { + "listen": "test", + "script": { + "id": "93584814-9658-421c-abd8-7f9169eba774", + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "var jsonData = JSON.parse(responseBody);", + "pm.globals.set(\"slave_port\", jsonData.slaves[Object.keys(jsonData.slaves)[0]].port);", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + }, + { + "key": "x-api-key", + "value": "{{X-Api-Key}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"name\": \"test\",\n\t\"description\": \"...\",\n\t\"address\": \"local\"\n}" + }, + "url": { + "raw": "http://127.0.0.1:8000/slaves", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "slaves" + ] + } + }, + "response": [ + { + "name": "Get Slaves", + "originalRequest": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"name\": \"test\",\n\t\"description\": \"...\",\n\t\"address\": \"local\"\n}" + }, + "url": { + "raw": "http://127.0.0.1:8000/slaves", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "slaves" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Date", + "value": "Tue, 27 Nov 2018 10:52:13 GMT" + }, + { + "key": "Server", + "value": "WSGIServer/0.2 CPython/3.6.6" + }, + { + "key": "content-type", + "value": "application/json; charset=utf-8" + }, + { + "key": "content-length", + "value": "14" + } + ], + "cookie": [], + "body": "{\n \"slaves\": {}\n}" + } + ] + }, + { + "name": "Status on slave", + "event": [ + { + "listen": "prerequest", + "script": { + "id": "ce404af6-6555-43a1-aed4-3d21f9562d24", + "exec": [ + "setTimeout(function(){}, 2000);" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "id": "1cd0f94e-8ced-4f0a-97fa-23e74e59a63f", + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:{{slave_port}}/status", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "{{slave_port}}", + "path": [ + "status" + ] + } + }, + "response": [] + }, + { + "name": "Get Status", + "event": [ + { + "listen": "test", + "script": { + "id": "5cf62b3c-e6f3-4499-b87e-d34e37052e88", + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "X-Api-Key", + "type": "text", + "value": "{{X-Api-Key}}" + }, + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": {}, + "url": { + "raw": "http://127.0.0.1:8000/status", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "status" + ] + } + }, + "response": [] + }, + { + "name": "Create Policy", + "event": [ + { + "listen": "test", + "script": { + "id": "d069a3e9-2497-40ab-99db-f2775eaf8c6d", + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "var jsonData = JSON.parse(responseBody);", + "pm.globals.set(\"policy_id\", Object.keys(jsonData.policies)[0]);", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "X-Api-Key", + "type": "text", + "value": "{{X-Api-Key}}" + }, + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"name\": \"policy_1\",\n\t\"description\": \"...\"\n}" + }, + "url": { + "raw": "http://127.0.0.1:8000/policies", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "policies" + ] + } + }, + "response": [] + }, + { + "name": "Get Policy", + "event": [ + { + "listen": "test", + "script": { + "id": "d069a3e9-2497-40ab-99db-f2775eaf8c6d", + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "X-Api-Key", + "type": "text", + "value": "{{X-Api-Key}}" + }, + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"name\": \"policy_1\",\n\t\"description\": \"...\"\n}" + }, + "url": { + "raw": "http://127.0.0.1:8000/policies/{{policy_id}}", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "policies", + "{{policy_id}}" + ] + } + }, + "response": [] + }, + { + "name": "Get Policies", + "event": [ + { + "listen": "test", + "script": { + "id": "d069a3e9-2497-40ab-99db-f2775eaf8c6d", + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "X-Api-Key", + "type": "text", + "value": "{{X-Api-Key}}" + }, + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"name\": \"policy_1\",\n\t\"description\": \"...\"\n}" + }, + "url": { + "raw": "http://127.0.0.1:8000/policies", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "policies" + ] + } + }, + "response": [] + }, + { + "name": "Get PDP", + "event": [ + { + "listen": "test", + "script": { + "id": "d069a3e9-2497-40ab-99db-f2775eaf8c6d", + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "X-Api-Key", + "type": "text", + "value": "{{X-Api-Key}}" + }, + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"name\": \"policy_1\",\n\t\"description\": \"...\"\n}" + }, + "url": { + "raw": "http://127.0.0.1:8000/pdp", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "pdp" + ] + } + }, + "response": [] + }, + { + "name": "Create PDP", + "event": [ + { + "listen": "test", + "script": { + "id": "d069a3e9-2497-40ab-99db-f2775eaf8c6d", + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "var jsonData = JSON.parse(responseBody);", + "pm.globals.set(\"pdp_id\", Object.keys(jsonData.pdps)[0]);", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + }, + { + "key": "x-api-key", + "value": "{{X-Api-Key}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"name\": \"pdp_1\",\n\t\"description\": \"...\",\n\t\"vim_project_id\": \"123456789\",\n\t\"security_pipeline\": [\"{{policy_id}}\"]\n}" + }, + "url": { + "raw": "http://127.0.0.1:8000/pdp", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "pdp" + ] + } + }, + "response": [] + }, + { + "name": "Get PDP", + "event": [ + { + "listen": "test", + "script": { + "id": "d069a3e9-2497-40ab-99db-f2775eaf8c6d", + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "X-Api-Key", + "type": "text", + "value": "{{X-Api-Key}}" + }, + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"name\": \"pdp_1\",\n\t\"description\": \"...\",\n\t\"vim_project_id\": \"123456789\",\n\t\"security_pipeline\": [\"{{policy_id}}\"]\n}" + }, + "url": { + "raw": "http://127.0.0.1:8000/pdp", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "pdp" + ] + } + }, + "response": [] + }, + { + "name": "Get rules", + "event": [ + { + "listen": "test", + "script": { + "id": "d069a3e9-2497-40ab-99db-f2775eaf8c6d", + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + }, + { + "key": "x-api-key", + "value": "{{X-Api-Key}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"name\": \"pdp_1\",\n\t\"description\": \"...\",\n\t\"vim_project_id\": \"123456789\",\n\t\"security_pipeline\": [\"{{policy_id}}\"]\n}" + }, + "url": { + "raw": "http://127.0.0.1:8000/rules", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "rules" + ] + } + }, + "response": [] + }, + { + "name": "Get Subject Categories", + "event": [ + { + "listen": "test", + "script": { + "id": "bf2e2194-92e9-4e6f-8930-db19e42fb213", + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "X-Api-Key", + "type": "text", + "value": "{{X-Api-Key}}" + }, + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": {}, + "url": { + "raw": "http://127.0.0.1:8000/subject_categories", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "subject_categories" + ] + } + }, + "response": [] + }, + { + "name": "Add pipeline on slave1", + "event": [ + { + "listen": "prerequest", + "script": { + "id": "ce404af6-6555-43a1-aed4-3d21f9562d24", + "exec": [ + "setTimeout(function(){}, 1000);" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "id": "1cd0f94e-8ced-4f0a-97fa-23e74e59a63f", + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "X-Api-key", + "value": "{{engine_api_key}}", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"name\": \"pdp_1\",\n\t\"description\": \"...\",\n\t\"vim_project_id\": \"123456789\",\n\t\"security_pipeline\": [\"{{policy_id}}\"]\n}" + }, + "url": { + "raw": "http://127.0.0.1:{{slave_port}}/pipeline/ad7c3600d32c477f8b24dae62333bb5b", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "{{slave_port}}", + "path": [ + "pipeline", + "ad7c3600d32c477f8b24dae62333bb5b" + ] + } + }, + "response": [] + }, + { + "name": "Get pipeline status", + "event": [ + { + "listen": "prerequest", + "script": { + "id": "ce404af6-6555-43a1-aed4-3d21f9562d24", + "exec": [ + "setTimeout(function(){}, 1000);" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "id": "1cd0f94e-8ced-4f0a-97fa-23e74e59a63f", + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "X-Api-key", + "type": "text", + "value": "{{engine_api_key}}" + }, + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"name\": \"pdp_1\",\n\t\"description\": \"...\",\n\t\"vim_project_id\": \"123456789\",\n\t\"security_pipeline\": [\"{{policy_id}}\"]\n}" + }, + "url": { + "raw": "http://127.0.0.1:20000/status", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "20000", + "path": [ + "status" + ] + } + }, + "response": [] + }, + { + "name": "Delete PDP", + "event": [ + { + "listen": "test", + "script": { + "id": "d069a3e9-2497-40ab-99db-f2775eaf8c6d", + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "DELETE", + "header": [ + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + }, + { + "key": "x-api-key", + "value": "{{X-Api-Key}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://127.0.0.1:8000/pdp/{{pdp_id}}", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "pdp", + "{{pdp_id}}" + ] + } + }, + "response": [] + } + ] +} \ No newline at end of file diff --git a/moon_manager/tests/func_tests/Logs/test.txt b/moon_manager/tests/func_tests/Logs/test.txt new file mode 100644 index 00000000..e69de29b diff --git a/moon_manager/tests/func_tests/__init__.py b/moon_manager/tests/func_tests/__init__.py new file mode 100644 index 00000000..1fc53954 --- /dev/null +++ b/moon_manager/tests/func_tests/__init__.py @@ -0,0 +1,11 @@ +# Copyright 2019 Orange 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 logging +logging.basicConfig(level=logging.DEBUG,format='%(asctime)s %(levelname)s %(message)s', filename='C:/Users/nzpb1414/PycharmProjects/meta_data_log.log') +logger = logging.getLogger(__name__) + +logger.info('heelloo: Starts') +logger.debug('Meta-Data Test: Starts') \ No newline at end of file diff --git a/moon_manager/tests/func_tests/features/README.md b/moon_manager/tests/func_tests/features/README.md new file mode 100644 index 00000000..ae7fc240 --- /dev/null +++ b/moon_manager/tests/func_tests/features/README.md @@ -0,0 +1,11 @@ +# Installation + +```bash +pip install behave + +pip install paramiko + +pip install numpy + +pip install astropy +``` \ No newline at end of file diff --git a/moon_manager/tests/func_tests/features/__init__.py b/moon_manager/tests/func_tests/features/__init__.py new file mode 100644 index 00000000..582be686 --- /dev/null +++ b/moon_manager/tests/func_tests/features/__init__.py @@ -0,0 +1,11 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + diff --git a/moon_manager/tests/func_tests/features/assignments.feature b/moon_manager/tests/func_tests/features/assignments.feature new file mode 100644 index 00000000..543eaba2 --- /dev/null +++ b/moon_manager/tests/func_tests/features/assignments.feature @@ -0,0 +1,290 @@ +Feature: Assignments + + Background: + Given the system has no rules + And the system has no subject assignments + And the system has no action assignments + And the system has no object assignments + And the system has no subject data + And the system has no action data + And the system has no object data + And the system has no subject perimeter + And the system has no object perimeter + And the system has no action perimeter + And the system has no pdps + And the system has no policies + And the system has no models + And the system has no meta-rules + And the system has no subject categories + And the system has no action categories + And the system has no object categories + And the following meta data subject category exists + | subjectmetadataname | subjectmetadatadescription | + | Affiliation: | This meta data has the categorical information about a subject | + | Authorization-Level: | This meta data has the categorical information about an object | + | Degree: | This meta data has the categorical information about an object | + And the following meta data object category exists + | objectmetadataname | objectmetadatadescription | + | Clearance: | This meta data has the categorical information about an object | + | Type: | This meta data has the categorical information about an object | + | Class: | This meta data has the categorical information about an object | + And the following meta data action category exists + | actionmetadataname | actionmetadatadescription | + | Action-Class: | This meta data has the categorical information about an action | + | Action-Priority: | This meta data has the categorical information about an action | + | Recommendation: | This meta data has the categorical information about an action | + And the following meta rule exists + | metarulename | metaruledescription | subjectmetadata | actionmetadata | objectmetadata | + | metarule1 | Thisisabasicmetarule | Affiliation: | Action-Class: | Clearance: | + | metarule2 | Thisisabasicmetarule | Authorization-Level: | Action-Class: | Clearance: | + | metarule3 | Thisisabasicmetarule | Affiliation: | Action-Priority: | Clearance: | + | metarule4 | Thisisabasicmetarule | Authorization-Level: | Action-Priority: | Clearance: | + | metarule5 | Thisisabasicmetarule | Affiliation: | Action-Class: | Type: | + | metarule6 | Thisisabasicmetarule | Authorization-Level: | Action-Class: | Type: | + | metarule7 | Thisisabasicmetarule | Affiliation: | Action-Priority: | Type: | + | metarule8 | Thisisabasicmetarule | Authorization-Level: | Action-Priority: | Type: | + | metarule9 | Thisisabasicmetarule | Affiliation:,Authorization-Level: | Action-Class:,Action-Priority: | Clearance:,Type: | + And the following model exists + | modelname | modeldescription | metarule | + | universitymodel | Thisisabasicmodel | metarule1,metarule9 | + | universitymodel2 | Thisisabasicmodel | metarule3,metarule5,metarule8 | + | universitymodel3 | Thisisabasicmodel | metarule9 | + And the following policy exists + | policyname | policydescription | modelname | genre | + | Stanford Policy | This is a basic policy | universitymodel | Education | + | Cambridge Policy | This is a basic policy | universitymodel3 | Education | + And the following subject perimeter exists + | subjectperimetername | subjectperimeterdescription | subjectperimeteremail | subjectperimeterpassword | policies | + | JohnLewis | Thisistheexpecteduser | jlewis@orange.com | abc1234 | Stanford Policy | + | WilliamsJoeseph | Thisistheexpecteduser | wjoeseph@orange.com | abc1234 | Stanford Policy | + | WilliamsJoeseph | Thisistheexpecteduser | wjoeseph@orange.com | abc1234 | Cambridge Policy | + | WilliamsGeorge | Thisdatahasthevalueofsubjectperimeter | gwilliams@orange.com | abc1234 | | + And the following object perimeter exists + | objectperimetername | objectperimeterdescription | policies | + | ProfessorsPromotionDocument | Thisistherequesttoaccessfile | Stanford Policy | + | StudentsGradesSheet | Thisistherequesttoaccessfile | Stanford Policy | + | StudentsGradesSheet | Thisistherequesttoaccessfile | Cambridge Policy | + | Vacations | Thisistherequesttoaccessfile | | + And the following action perimeter exists + | actionperimetername | actionperimeterdescription | policies | + | Read | Thisistheactionrequired | Stanford Policy | + | Delete | Thisistheactionrequired | Stanford Policy | + | Delete | Thisistheactionrequired | Cambridge Policy | + | Edit | Thisistheactionrequired | | + And the following subject data exists + | policyname | subjectcategory | subjectdataname | subjectdatadescription | + | Stanford Policy | Affiliation: | University-of-Stanford | This data has the value of subject category | + | Stanford Policy | Affiliation: | Stanford | This data has the value of subject category | + | Stanford Policy | Authorization-Level: | Professor | This data has the value of subject category | + | Cambridge Policy | Affiliation: | University-of-Cambridge | This data has the value of subject category | + | Cambridge Policy | Authorization-Level: | Professor | This data has the value of subject category | + | Cambridge Policy | Authorization-Level: | Lecturer | This data has the value of subject category | + And the following object data exists + | policyname | objectcategory | objectdataname | objectdatadescription | + | Stanford Policy | Clearance: | Top-Secret | This data has the value of object category | + | Stanford Policy | Clearance: | Confidential | This data has the value of object category | + | Stanford Policy | Clearance: | Public | This data has the value of object category | + | Stanford Policy | Type: | Adminstrative | This data has the value of object category | + | Stanford Policy | Type: | Staff | This data has the value of object category | + | Cambridge Policy | Type: | Adminstrative | This data has the value of object category | + | Cambridge Policy | Type: | Teaching-Staff | This data has the value of object category | + | Cambridge Policy | Clearance: | Confidential | This data has the value of object category | + | Cambridge Policy | Clearance: | Access-with-permission | This data has the value of object category | + | Cambridge Policy | Clearance: | Public | This data has the value of object category | + + And the following action data exists + | policyname | actioncategory | actiondataname | actiondatadescription | + | Stanford Policy | Action-Class: | Severe | This data has the value of action category | + | Stanford Policy | Action-Class: | Low | This data has the value of action category | + | Stanford Policy | Action-Priority: | Low | This data has the value of action category | + | Cambridge Policy | Action-Priority: | High | This data has the value of action category | + | Cambridge Policy | Action-Priority: | Medium | This data has the value of action category | + | Cambridge Policy | Action-Priority: | Low | This data has the value of action category | + | Cambridge Policy | Action-Class: | Severe | This data has the value of action category | + | Cambridge Policy | Action-Class: | Intermediate | This data has the value of action category | + | Cambridge Policy | Action-Class: | Low | This data has the value of action category | + + + Scenario: Add subject assignment + When the user sets to add the following subject assignment + | subjectperimetername | subjectcategory | subjectdata | policyname | + | JohnLewis | Affiliation: | University-of-Stanford | Stanford Policy | + | WilliamsJoeseph | Affiliation: | University-of-Stanford | Stanford Policy | + | WilliamsJoeseph | Affiliation: | University-of-Cambridge | Cambridge Policy | + | WilliamsJoeseph | Authorization-Level: | Lecturer | Cambridge Policy | + Then the following subject assignment should be existed in the system + | subjectperimetername | subjectcategory | subjectdata | policyname | + | JohnLewis | Affiliation: | University-of-Stanford | Stanford Policy | + | WilliamsJoeseph | Affiliation: | University-of-Stanford | Stanford Policy | + | WilliamsJoeseph | Affiliation: | University-of-Cambridge | Cambridge Policy | + | WilliamsJoeseph | Authorization-Level: | Lecturer | Cambridge Policy | + + + Scenario Outline: Add subject assignment validations + When the user sets to add the following subject assignment + | subjectperimetername | subjectcategory | subjectdata | policyname | + | | | | | + + Then the system should reply the following + | flag | + | | + Examples: + | subjectperimetername | subjectcategory | subjectdata | policyname | flag | + | | Affiliation: | University-of-Stanford | Stanford Policy | False | + | 000000000000000000000000000000000000000000000000000 | Affiliation: | University-of-Stanford | Stanford Policy | False | + | GeorgeWilliams | Affiliation: | University-of-Cambridge | Cambridge Policy | False | + | WilliamsGeorge | Authorization-Level: | Professor | Cambridge Policy | False | + | JohnLewis | | University-of-Stanford | Stanford Policy | False | + | JohnLewis | 000000000000000000000000000000000000000000000000000 | University-of-Stanford | Stanford Policy | False | + | WilliamsJoeseph | Authorization-Level: | | Cambridge Policy | False | + | WilliamsJoeseph | Authorization-Level: | 000000000000000000000000000000000000000000000000000 | Cambridge Policy | False | + | WilliamsJoeseph | Authorization-Level: | Admin | | False | + | WilliamsJoeseph | Authorization-Level: | Admin | 000000000000000000000000000000000000000000000000000 | False | + + Scenario Outline: Add an existing subject assignment + Given the following subject assignment exists + | subjectperimetername | subjectcategory | subjectdata | policyname | + | WilliamsJoeseph | Authorization-Level: | Lecturer | Cambridge Policy | + When the user sets to add the following subject assignment + | subjectperimetername | subjectcategory | subjectdata | policyname | + | | | | | + Then the system should reply the following + | flag | + | | + Examples: + | subjectperimetername | subjectcategory | subjectdata | policyname | flag | + | WilliamsJoeseph | Authorization-Level: | Lecturer | Cambridge Policy | False | + | WilliamsJoeseph | Authorization-Level: | Professor | Cambridge Policy | True | + + Scenario: Delete subject assignments + Given the following subject assignment exists + | subjectperimetername | subjectcategory | subjectdata | policyname | + | JohnLewis | Affiliation: | University-of-Stanford | Stanford Policy | + | JohnLewis | Affiliation: | Stanford | Stanford Policy | + When the user sets to delete the following subject assignment + | subjectperimetername | subjectcategory | subjectdata | policyname | + | JohnLewis | Affiliation: | University-of-Stanford | Stanford Policy | + Then the following subject assignment should be existed in the system + | subjectperimetername | subjectcategory | subjectdata | policyname | + | JohnLewis | Affiliation: | Stanford | Stanford Policy | + + + Scenario: Add object assignments + When the user sets to add the following object assignment + | objectperimetername | objectcategory | objectdata | policyname | + | ProfessorsPromotionDocument | Clearance: | Confidential | Stanford Policy | + | ProfessorsPromotionDocument | Clearance: | Public | Stanford Policy | + | StudentsGradesSheet | Clearance: | Top-Secret | Stanford Policy | + | StudentsGradesSheet | Clearance: | Confidential | Stanford Policy | + | StudentsGradesSheet | Clearance: | Public | Stanford Policy | + | StudentsGradesSheet | Clearance: | Confidential | Cambridge Policy | + | StudentsGradesSheet | Clearance: | Public | Cambridge Policy | + Then the following object assignment should be existed in the system + | objectperimetername | objectcategory | objectdata | policyname | + | ProfessorsPromotionDocument | Clearance: | Confidential,Public | Stanford Policy | + | StudentsGradesSheet | Clearance: | Top-Secret,Confidential,Public | Stanford Policy | + | StudentsGradesSheet | Clearance: | Confidential,Public | Cambridge Policy | + + + Scenario Outline: Add object assignment validations + When the user sets to add the following object assignment + | objectperimetername | objectcategory | objectdata | policyname | + | | | | | + + Then the system should reply the following + | flag | + | | + Examples: + | objectperimetername | objectcategory | objectdata | policyname | flag | + | | Clearance: | Confidential | Cambridge Policy | False | + | Vacations | Clearance: | Confidential | Stanford Policy | False | + | 000000000000000000000000000000000000000000000000000 | Clearance: | Confidential | Stanford Policy | False | + | StudentsGradesSheet | | Confidential | Cambridge Policy | False | + | StudentsGradesSheet | 000000000000000000000000000000000000000000000000000 | Confidential | Cambridge Policy | False | + | StudentsGradesSheet | Clearance: | | Cambridge Policy | False | + | StudentsGradesSheet | Clearance: | 000000000000000000000000000000000000000000000000000 | Stanford Policy | False | + | StudentsGradesSheet | Clearance: | Confidential | | False | + | StudentsGradesSheet | Clearance: | Confidential | 000000000000000000000000000000000000000000000000000 | False | + + Scenario Outline: Add an existing object assignment + Given the following object assignment exists + | objectperimetername | objectcategory | objectdata | policyname | + | StudentsGradesSheet | Clearance: | Confidential | Stanford Policy | + When the user sets to add the following object assignment + | objectperimetername | objectcategory | objectdata | policyname | + | | | | | + Then the system should reply the following + | flag | + | | + Examples: + | objectperimetername | objectcategory | objectdata | policyname | flag | + | StudentsGradesSheet | Clearance: | Confidential | Stanford Policy | False | + + Scenario: Delete object assignment + Given the following object assignment exists + | objectperimetername | objectcategory | objectdata | policyname | + | ProfessorsPromotionDocument | Clearance: | Public | Stanford Policy | + | ProfessorsPromotionDocument | Clearance: | Confidential | Stanford Policy | + When the user sets to delete the following object assignment + | objectperimetername | objectcategory | objectdata | policyname | + | ProfessorsPromotionDocument | Clearance: | Confidential | Stanford Policy | + Then the following object assignment should be existed in the system + | objectperimetername | objectcategory | objectdata | policyname | + | ProfessorsPromotionDocument | Clearance: | Public | Stanford Policy | + + Scenario: Add action assignment + When the user sets to add the following action assignment + | actionperimetername | actioncategory | actiondata | policyname | + | Delete | Action-Priority: | Medium | Cambridge Policy | + | Read | Action-Class: | Low | Stanford Policy | + Then the following action assignment should be existed in the system + | actionperimetername | actioncategory | actiondata | policyname | + | Delete | Action-Priority: | Medium | Cambridge Policy | + | Read | Action-Class: | Low | Stanford Policy | + + Scenario Outline: Add action assignment validations + When the user sets to add the following action assignment + | actionperimetername | actioncategory | actiondata | policyname | + | | | | | + Then the system should reply the following + | flag | + | | + Examples: + | actionperimetername | actioncategory | actiondata | policyname | flag | + | | Action-Class: | Severe | Stanford Policy | False | + | Edit | Action-Class: | Severe | Stanford Policy | False | + | 000000000000000000000000000000000000000000000000000 | Action-Class: | Severe | Stanford Policy | False | + | Read | | Severe | Stanford Policy | False | + | Read | Action-Priority: | Severe | Stanford Policy | False | + | Read | 000000000000000000000000000000000000000000000000000 | Severe | Stanford Policy | False | + | Read | Action-Class: | | Stanford Policy | False | + | Read | Action-Class: | 000000000000000000000000000000000000000000000000000 | Stanford Policy | False | + | Read | Action-Class: | high | | False | + | Delete | Action-Class: | high | 000000000000000000000000000000000000000000000000000 | False | + | Delete | Action-Class: | high | Stanford Policy | False | + + Scenario Outline: Add an existing action assignment + Given the following action assignment exists + | actionperimetername | actioncategory | actiondata | policyname | + | Read | Action-Class: | Severe | Stanford Policy | + When the user sets to add the following action assignment + | actionperimetername | actioncategory | actiondata | policyname | + | | | | | + Then the system should reply the following + | flag | + | | + Examples: + | actionperimetername | actioncategory | actiondata | policyname | flag | + | Read | Action-Class: | Severe | Stanford Policy | False | + + Scenario: Delete action assignments + Given the following action assignment exists + | actionperimetername | actioncategory | actiondata | policyname | + | Read | Action-Class: | Severe | Stanford Policy | + | Read | Action-Class: | Low | Stanford Policy | + When the user sets to delete the following action assignment + | actionperimetername | actioncategory | actiondata | policyname | + | Read | Action-Class: | Severe | Stanford Policy | + Then the following action assignment should be existed in the system + | actionperimetername | actioncategory | actiondata | policyname | + | Read | Action-Class: | Low | Stanford Policy | \ No newline at end of file diff --git a/moon_manager/tests/func_tests/features/authorization_pipeline.feature b/moon_manager/tests/func_tests/features/authorization_pipeline.feature new file mode 100644 index 00000000..8a175915 --- /dev/null +++ b/moon_manager/tests/func_tests/features/authorization_pipeline.feature @@ -0,0 +1,388 @@ +Feature: Authorization Pipeline + + Background: + + #Given the manager is configured + Given no slave is created + And the slave is created + And the system has no rules + And the system has no subject assignments + And the system has no action assignments + And the system has no object assignments + And the system has no subject data + And the system has no action data + And the system has no object data + And the system has no subject perimeter + And the system has no object perimeter + And the system has no action perimeter + And the system has no pdps + And the system has no policies + And the system has no models + And the system has no meta-rules + And the system has no subject categories + And the system has no action categories + And the system has no object categories + And the following meta data subject category exists + | subjectmetadataname | subjectmetadatadescription | + | Affiliation: | This meta data has the categorical information about a subject | + | Authorization-Level: | This meta data has the categorical information about an object | + | Degree: | This meta data has the categorical information about an object | + And the following meta data object category exists + | objectmetadataname | objectmetadatadescription | + | Clearance: | This meta data has the categorical information about an object | + | Type: | This meta data has the categorical information about an object | + | Class: | This meta data has the categorical information about an object | + And the following meta data action category exists + | actionmetadataname | actionmetadatadescription | + | Action-Class: | This meta data has the categorical information about an action | + | Action-Priority: | This meta data has the categorical information about an action | + | Recommendation: | This meta data has the categorical information about an action | + And the following meta rule exists + | metarulename | metaruledescription | subjectmetadata | actionmetadata | objectmetadata | + | metarule1 | Thisisabasicmetarule | Affiliation: | Action-Class: | Clearance: | + | metarule2 | Thisisabasicmetarule | Authorization-Level: | Action-Class: | Clearance: | + | metarule3 | Thisisabasicmetarule | Affiliation: | Action-Priority: | Clearance: | + | metarule4 | Thisisabasicmetarule | Authorization-Level: | Action-Priority: | Clearance: | + | metarule5 | Thisisabasicmetarule | Affiliation: | Action-Class: | Type: | + | metarule6 | Thisisabasicmetarule | Authorization-Level: | Action-Class: | Type: | + | metarule7 | Thisisabasicmetarule | Affiliation: | Action-Priority: | Type: | + | metarule8 | Thisisabasicmetarule | Authorization-Level: | Action-Priority: | Type: | + | metarule9 | Thisisabasicmetarule | Affiliation:,Authorization-Level: | Action-Class:,Action-Priority: | Clearance:,Type: | + And the following model exists + | modelname | modeldescription | metarule | + | universitymodel | Thisisabasicmodel | metarule1 | + | universitymodel2 | Thisisabasicmodel | metarule3,metarule5,metarule8 | + | universitymodel3 | Thisisabasicmodel | metarule9 | + And the following policy exists + | policyname | policydescription | modelname | genre | + | Stanford Policy | This is a basic policy | universitymodel | Education | + | Cambridge Policy | This is a basic policy | universitymodel3 | Education | + And the following pdp exists + | pdpname | pdpdescription | keystone_project_id | security_pipeline | + | A-pdp | Thisisabasicpolicy | 0000000000000000000000000000000000000000000000000000000000000000 | Stanford Policy | + And the following subject perimeter exists + | subjectperimetername | subjectperimeterdescription | subjectperimeteremail | subjectperimeterpassword | policies | + | JohnLewis | Thisistheexpecteduser | jlewis@orange.com | abc1234 | Stanford Policy | + | WilliamsJoeseph | Thisistheexpecteduser | wjoeseph@orange.com | abc1234 | Stanford Policy | + | WilliamsJoeseph | Thisistheexpecteduser | wjoeseph@orange.com | abc1234 | Cambridge Policy | + #| WilliamsGeorge | Thisdatahasthevalueofsubjectperimeter | gwilliams@orange.com | abc1234 | | + And the following object perimeter exists + | objectperimetername | objectperimeterdescription | policies | + | ProfessorsPromotionDocument | Thisistherequesttoaccessfile | Stanford Policy | + | StudentsGradesSheet | Thisistherequesttoaccessfile | Stanford Policy | + | StudentsGradesSheet | Thisistherequesttoaccessfile | Cambridge Policy | + #| Vacations | Thisistherequesttoaccessfile | | + And the following action perimeter exists + | actionperimetername | actionperimeterdescription | policies | + | Read | Thisistheactionrequired | Stanford Policy | + | Delete | Thisistheactionrequired | Stanford Policy | + | Delete | Thisistheactionrequired | Cambridge Policy | + #| Edit | Thisistheactionrequired | | + And the following subject data exists + | policyname | subjectcategory | subjectdataname | subjectdatadescription | + | Stanford Policy | Affiliation: | University-of-Stanford | This data has the value of subject category | + | Stanford Policy | Affiliation: | Stanford | This data has the value of subject category | + | Cambridge Policy | Affiliation: | University-of-Cambridge | This data has the value of subject category | + | Cambridge Policy | Authorization-Level: | Professor | This data has the value of subject category | + | Cambridge Policy | Authorization-Level: | Lecturer | This data has the value of subject category | + And the following object data exists + | policyname | objectcategory | objectdataname | objectdatadescription | + | Stanford Policy | Clearance: | Top-Secret | This data has the value of object category | + | Stanford Policy | Clearance: | Confidential | This data has the value of object category | + | Stanford Policy | Clearance: | Public | This data has the value of object category | + | Cambridge Policy | Type: | Adminstrative | This data has the value of object category | + | Cambridge Policy | Type: | Teaching-Staff | This data has the value of object category | + | Cambridge Policy | Clearance: | Confidential | This data has the value of object category | + | Cambridge Policy | Clearance: | Access-with-permission | This data has the value of object category | + | Cambridge Policy | Clearance: | Public | This data has the value of object category | + + And the following action data exists + | policyname | actioncategory | actiondataname | actiondatadescription | + | Stanford Policy | Action-Class: | Severe | This data has the value of action category | + | Stanford Policy | Action-Class: | Low | This data has the value of action category | + | Cambridge Policy | Action-Priority: | High | This data has the value of action category | + | Cambridge Policy | Action-Priority: | Medium | This data has the value of action category | + | Cambridge Policy | Action-Priority: | Low | This data has the value of action category | + | Cambridge Policy | Action-Class: | Severe | This data has the value of action category | + | Cambridge Policy | Action-Class: | Intermediate | This data has the value of action category | + | Cambridge Policy | Action-Class: | Low | This data has the value of action category | + + And the following subject assignment exists + | subjectperimetername | subjectcategory | subjectdata | policyname | + | JohnLewis | Affiliation: | University-of-Stanford | Stanford Policy | + | WilliamsJoeseph | Affiliation: | Stanford | Stanford Policy | + + And the following object assignment exists + | objectperimetername | objectcategory | objectdata | policyname | + | StudentsGradesSheet | Clearance: | Access-with-permission | Cambridge Policy | + | StudentsGradesSheet | Clearance: | Public | Cambridge Policy | + #| StudentsGradesSheet | Clearance: | Top-Secret | Stanford Policy | + | StudentsGradesSheet | Clearance: | Confidential | Stanford Policy | + #| StudentsGradesSheet | Clearance: | Public | Stanford Policy | + And the following action assignment exists + | actionperimetername | actioncategory | actiondata | policyname | + | Read | Action-Class: | Severe | Stanford Policy | + #| Read | Action-Class: | Low | Stanford Policy | + | Delete | Action-Priority: | High | Cambridge Policy | + | Delete | Action-Priority: | Medium | Cambridge Policy | + | Delete | Action-Priority: | Low | Cambridge Policy | + And the following rule exists + | rule | metarulename | instructions | policyname | + | University-of-Stanford,Confidential,Severe | metarule1 | grant | Stanford Policy | + #| University-of-Stanford,Professor,Public,Adminstrative,Low,Low | metarule9 | grant | Stanford Policy | + And the pipeline is running + And the following authorization request is granted through pipeline + | subjectperimetername | objectperimetername | actionperimetername | + | JohnLewis | StudentsGradesSheet | Read | + + Scenario: Check authorization response after rule deletion + When the user sets to delete the following rules + | rule | metarulename | policyname | + | University-of-Stanford,Confidential,Severe | metarule1 | Stanford Policy | + And the following authorization request is sent through pipeline + | subjectperimetername | objectperimetername | actionperimetername | + | JohnLewis | ProfessorsPromotionDocument | Read | + Then the authorization response should be the following + | auth_response | + | denied | + + Scenario: Check authorization response after rule deletion then addition + When the user sets to delete the following rules + | rule | metarulename | policyname | + | University-of-Stanford,Confidential,Severe | metarule1 | Stanford Policy | + And the user sets to add the following rules + | rule | metarulename | instructions | policyname | + | University-of-Stanford,Confidential,Severe | metarule1 | grant | Stanford Policy | + And the following authorization request is sent through pipeline + | subjectperimetername | objectperimetername | actionperimetername | + | JohnLewis | ProfessorsPromotionDocument | Read | + Then the authorization response should be the following + | auth_response | + | grant | + +Scenario: Check authorization response after subject assignment deletion + When the user sets to delete the following subject assignment + | subjectperimetername | subjectcategory | subjectdata | policyname | + | JohnLewis | Affiliation: | University-of-Stanford | Stanford Policy | + And the following authorization request is sent through pipeline + | subjectperimetername | objectperimetername | actionperimetername | + | JohnLewis | ProfessorsPromotionDocument | Read | + Then the authorization response should be the following + | auth_response | + | denied | + + Scenario: Check authorization response after subject assignment deletion then addition + When the user sets to delete the following subject assignment + | subjectperimetername | subjectcategory | subjectdata | policyname | + | JohnLewis | Affiliation: | University-of-Stanford | Stanford Policy | + And the user sets to add the following subject assignment + | subjectperimetername | subjectcategory | subjectdata | policyname | + | JohnLewis | Affiliation: | University-of-Stanford | Stanford Policy | + And the following authorization request is sent through pipeline + | subjectperimetername | objectperimetername | actionperimetername | + | JohnLewis | ProfessorsPromotionDocument | Read | + Then the authorization response should be the following + | auth_response | + | grant | + + Scenario: Check authorization response after object assignment deletion + When the user sets to delete the following object assignment + | objectperimetername | objectcategory | objectdata | policyname | + | JohnLewis | Affiliation: | University-of-Stanford | Stanford Policy | + And the following authorization request is sent through pipeline + | subjectperimetername | objectperimetername | actionperimetername | + | JohnLewis | ProfessorsPromotionDocument | Read | + Then the authorization response should be the following + | auth_response | + | denied | + + Scenario: Check authorization response after object assignment deletion then addition + When the user sets to delete the following object assignment + | objectperimetername | objectcategory | objectdata | policyname | + | ProfessorsPromotionDocument | Clearance: | Confidential | Stanford Policy | + And the user sets to add the following object assignment + | objectperimetername | objectcategory | objectdata | policyname | + | ProfessorsPromotionDocument | Clearance: | Confidential | Stanford Policy | + And the following authorization request is sent through pipeline + | subjectperimetername | objectperimetername | actionperimetername | + | JohnLewis | ProfessorsPromotionDocument | Read | + Then the authorization response should be the following + | auth_response | + | grant | + + Scenario: Check authorization response after action assignment deletion + When When the user sets to delete the following action assignment + | actionperimetername | actioncategory | actiondata | policyname | + | Read | Action-Class: | Severe | Stanford Policy | + And the following authorization request is sent through pipeline + | subjectperimetername | objectperimetername | actionperimetername | + | JohnLewis | ProfessorsPromotionDocument | Read | + Then the authorization response should be the following + | auth_response | + | denied | + + Scenario: Check authorization response after action assignment deletion then addition + When the user sets to delete the following action assignment + | actionperimetername | actioncategory | actiondata | policyname | + | Read | Action-Class: | Severe | Stanford Policy | + And the user sets to add the following action assignment + | actionperimetername | actioncategory | actiondata | policyname | + | Read | Action-Class: | Low | Stanford Policy | + And the following authorization request is sent through pipeline + | subjectperimetername | objectperimetername | actionperimetername | + | JohnLewis | ProfessorsPromotionDocument | Read | + Then the authorization response should be the following + | auth_response | + | grant | + + + Scenario: Check authorization response after subject data deletion + When the user sets to delete the following subject data + | policyname | subjectcategory | subjectdataname | + | Stanford Policy | Affiliation: | University-of-Stanford | + And the following authorization request is sent through pipeline + | subjectperimetername | objectperimetername | actionperimetername | + | JohnLewis | ProfessorsPromotionDocument | Read | + Then the authorization response should be the following + | auth_response | + | denied | + + Scenario: Check authorization response after subject data deletion then addition + When the user sets to delete the following subject data + | policyname | subjectcategory | subjectdataname | + | Stanford Policy | Affiliation: | University-of-Stanford | + And the user sets to add the following subject data + | policyname | subjectcategory | subjectdataname | subjectdatadescription | + | Stanford Policy | Affiliation: | University-of-Stanford | This data has the value of subject category | + And the following authorization request is sent through pipeline + | subjectperimetername | objectperimetername | actionperimetername | + | JohnLewis | ProfessorsPromotionDocument | Read | + Then the authorization response should be the following + | auth_response | + | grant | + + Scenario: Check authorization response after object data deletion + When the user sets to delete the following object data + | policyname | objectcategory | objectdataname | + | Stanford Policy | Clearance: | Top-Secret | + And the following authorization request is sent through pipeline + | subjectperimetername | objectperimetername | actionperimetername | + | JohnLewis | ProfessorsPromotionDocument | Read | + Then the authorization response should be the following + | auth_response | + | denied | + + Scenario: Check authorization response after object data deletion then addition + When the user sets to delete the following object data + | policyname | objectcategory | objectdataname | + | Stanford Policy | Clearance: | Top-Secret | + And the user sets to add the following object data + | policyname | objectcategory | objectdataname | objectdatadescription | + | Stanford Policy | Clearance: | Confidential | This data has the value of object category | + And the following authorization request is sent through pipeline + | subjectperimetername | objectperimetername | actionperimetername | + | JohnLewis | ProfessorsPromotionDocument | Read | + Then the authorization response should be the following + | auth_response | + | grant | + + Scenario: Check authorization response after action data deletion + When the user sets to delete the following action data + | policyname | actioncategory | actiondataname | + | Stanford Policy | Action-Class: | Severe | + And the following authorization request is sent through pipeline + | subjectperimetername | objectperimetername | actionperimetername | + | JohnLewis | ProfessorsPromotionDocument | Read | + Then the authorization response should be the following + | auth_response | + | denied | + + Scenario: Check authorization response after action data deletion then addition + When the user sets to delete the following action data + | policyname | actioncategory | actiondataname | + | Stanford Policy | Action-Class: | Severe | + And the user sets to add the following action data + | policyname | actioncategory | actiondataname | actiondatadescription | + | Stanford Policy | Action-Class: | Severe | This data has the value of action category | + And the following authorization request is sent through pipeline + | subjectperimetername | objectperimetername | actionperimetername | + | JohnLewis | ProfessorsPromotionDocument | Read | + Then the authorization response should be the following + | auth_response | + | grant | + + + Scenario: Check authorization response after subject perimeter deletion + When the user sets to delete the following subject perimeter for a given policy + | subjectperimetername | policies | + | JohnLewis | Stanford Policy | + And the following authorization request is sent through pipeline + | subjectperimetername | objectperimetername | actionperimetername | + | JohnLewis | ProfessorsPromotionDocument | Read | + Then the authorization response should be the following + | auth_response | + | denied | + + Scenario: Check authorization response after subject perimeter deletion then addition + When the user sets to delete the following subject perimeter for a given policy + | subjectperimetername | policies | + | JohnLewis | Stanford Policy | + And the user sets to add the following subject perimeter + | subjectperimetername | subjectperimeterdescription | subjectperimeteremail | subjectperimeterpassword | policies | + | JohnLewis | Thisistheexpecteduser | jlewis@orange.com | abc1234 | Stanford Policy | + And the following authorization request is sent through pipeline + | subjectperimetername | objectperimetername | actionperimetername | + | JohnLewis | ProfessorsPromotionDocument | Read | + Then the authorization response should be the following + | auth_response | + | grant | + + Scenario: Check authorization response after object perimeter deletion + When the user sets to delete the following object perimeter + | objectperimetername | policies | + | ProfessorsPromotionDocument | Stanford Policy | + And the following authorization request is sent through pipeline + | subjectperimetername | objectperimetername | actionperimetername | + | JohnLewis | ProfessorsPromotionDocument | Read | + Then the authorization response should be the following + | auth_response | + | denied | + + Scenario: Check authorization response after object perimeter deletion then addition + When the user sets to delete the following object perimeter + | objectperimetername | policies | + | ProfessorsPromotionDocument | Stanford Policy | + And the user sets to add the following object perimeter + | objectperimetername | objectperimeterdescription | policies | + | ProfessorsPromotionDocument | Thisistherequesttoaccessfile | Stanford Policy | + And the following authorization request is sent through pipeline + | subjectperimetername | objectperimetername | actionperimetername | + | JohnLewis | ProfessorsPromotionDocument | Read | + Then the authorization response should be the following + | auth_response | + | grant | + + Scenario: Check authorization response after action perimeter deletion + When the user sets to delete the following action perimeter + | actionperimetername | policies | + | Read | Stanford Policy | + And the following authorization request is sent through pipeline + | subjectperimetername | objectperimetername | actionperimetername | + | JohnLewis | ProfessorsPromotionDocument | Read | + Then the authorization response should be the following + | auth_response | + | denied | + + Scenario: Check authorization response after action perimeter deletion then addition + When the user sets to delete the following action perimeter + | actionperimetername | policies | + | Read | Stanford Policy | + And the user sets to add the following action perimeter + | actionperimetername | actionperimeterdescription | policies | + | Read | Thisistheactionrequired | Stanford Policy | + And the following authorization request is sent through pipeline + | subjectperimetername | objectperimetername | actionperimetername | + | JohnLewis | ProfessorsPromotionDocument | Read | + Then the authorization response should be the following + | auth_response | + | grant | diff --git a/moon_manager/tests/func_tests/features/authorization_wrapper.feature b/moon_manager/tests/func_tests/features/authorization_wrapper.feature new file mode 100644 index 00000000..43fdb519 --- /dev/null +++ b/moon_manager/tests/func_tests/features/authorization_wrapper.feature @@ -0,0 +1,386 @@ +Feature: Authorization Wrapper + + Background: + + Given no slave is created + And the slave is created + And the system has no rules + And the system has no subject assignments + And the system has no action assignments + And the system has no object assignments + And the system has no subject data + And the system has no action data + And the system has no object data + And the system has no subject perimeter + And the system has no object perimeter + And the system has no action perimeter + And the system has no pdps + And the system has no policies + And the system has no models + And the system has no meta-rules + And the system has no subject categories + And the system has no action categories + And the system has no object categories + And the following meta data subject category exists + | subjectmetadataname | subjectmetadatadescription | + | Affiliation: | This meta data has the categorical information about a subject | + | Authorization-Level: | This meta data has the categorical information about an object | + | Degree: | This meta data has the categorical information about an object | + And the following meta data object category exists + | objectmetadataname | objectmetadatadescription | + | Clearance: | This meta data has the categorical information about an object | + | Type: | This meta data has the categorical information about an object | + | Class: | This meta data has the categorical information about an object | + And the following meta data action category exists + | actionmetadataname | actionmetadatadescription | + | Action-Class: | This meta data has the categorical information about an action | + | Action-Priority: | This meta data has the categorical information about an action | + | Recommendation: | This meta data has the categorical information about an action | + And the following meta rule exists + | metarulename | metaruledescription | subjectmetadata | actionmetadata | objectmetadata | + | metarule1 | Thisisabasicmetarule | Affiliation: | Action-Class: | Clearance: | + | metarule2 | Thisisabasicmetarule | Authorization-Level: | Action-Class: | Clearance: | + | metarule3 | Thisisabasicmetarule | Affiliation: | Action-Priority: | Clearance: | + | metarule4 | Thisisabasicmetarule | Authorization-Level: | Action-Priority: | Clearance: | + | metarule5 | Thisisabasicmetarule | Affiliation: | Action-Class: | Type: | + | metarule6 | Thisisabasicmetarule | Authorization-Level: | Action-Class: | Type: | + | metarule7 | Thisisabasicmetarule | Affiliation: | Action-Priority: | Type: | + | metarule8 | Thisisabasicmetarule | Authorization-Level: | Action-Priority: | Type: | + | metarule9 | Thisisabasicmetarule | Affiliation:,Authorization-Level: | Action-Class:,Action-Priority: | Clearance:,Type: | + And the following model exists + | modelname | modeldescription | metarule | + | universitymodel | Thisisabasicmodel | metarule1 | + | universitymodel2 | Thisisabasicmodel | metarule3,metarule5,metarule8 | + | universitymodel3 | Thisisabasicmodel | metarule9 | + And the following policy exists + | policyname | policydescription | modelname | genre | + | Stanford Policy | This is a basic policy | universitymodel | Education | + | Cambridge Policy | This is a basic policy | universitymodel3 | Education | + And the following pdp exists + | pdpname | pdpdescription | keystone_project_id | security_pipeline | + | A-pdp | Thisisabasicpolicy | 0000000000000000000000000000000000000000000000000000000000000000 | Stanford Policy | + And the following subject perimeter exists + | subjectperimetername | subjectperimeterdescription | subjectperimeteremail | subjectperimeterpassword | policies | + | JohnLewis | Thisistheexpecteduser | jlewis@orange.com | abc1234 | Stanford Policy | + | WilliamsJoeseph | Thisistheexpecteduser | wjoeseph@orange.com | abc1234 | Stanford Policy | + | WilliamsJoeseph | Thisistheexpecteduser | wjoeseph@orange.com | abc1234 | Cambridge Policy | + #| WilliamsGeorge | Thisdatahasthevalueofsubjectperimeter | gwilliams@orange.com | abc1234 | | + And the following object perimeter exists + | objectperimetername | objectperimeterdescription | policies | + | ProfessorsPromotionDocument | Thisistherequesttoaccessfile | Stanford Policy | + | StudentsGradesSheet | Thisistherequesttoaccessfile | Stanford Policy | + | StudentsGradesSheet | Thisistherequesttoaccessfile | Cambridge Policy | + #| Vacations | Thisistherequesttoaccessfile | | + And the following action perimeter exists + | actionperimetername | actionperimeterdescription | policies | + | Read | Thisistheactionrequired | Stanford Policy | + | Delete | Thisistheactionrequired | Stanford Policy | + | Delete | Thisistheactionrequired | Cambridge Policy | + #| Edit | Thisistheactionrequired | | + And the following subject data exists + | policyname | subjectcategory | subjectdataname | subjectdatadescription | + | Stanford Policy | Affiliation: | University-of-Stanford | This data has the value of subject category | + | Stanford Policy | Affiliation: | Stanford | This data has the value of subject category | + | Cambridge Policy | Affiliation: | University-of-Cambridge | This data has the value of subject category | + | Cambridge Policy | Authorization-Level: | Professor | This data has the value of subject category | + | Cambridge Policy | Authorization-Level: | Lecturer | This data has the value of subject category | + And the following object data exists + | policyname | objectcategory | objectdataname | objectdatadescription | + | Stanford Policy | Clearance: | Top-Secret | This data has the value of object category | + | Stanford Policy | Clearance: | Confidential | This data has the value of object category | + | Stanford Policy | Clearance: | Public | This data has the value of object category | + | Cambridge Policy | Type: | Adminstrative | This data has the value of object category | + | Cambridge Policy | Type: | Teaching-Staff | This data has the value of object category | + | Cambridge Policy | Clearance: | Confidential | This data has the value of object category | + | Cambridge Policy | Clearance: | Access-with-permission | This data has the value of object category | + | Cambridge Policy | Clearance: | Public | This data has the value of object category | + + And the following action data exists + | policyname | actioncategory | actiondataname | actiondatadescription | + | Stanford Policy | Action-Class: | Severe | This data has the value of action category | + | Stanford Policy | Action-Class: | Low | This data has the value of action category | + | Cambridge Policy | Action-Priority: | High | This data has the value of action category | + | Cambridge Policy | Action-Priority: | Medium | This data has the value of action category | + | Cambridge Policy | Action-Priority: | Low | This data has the value of action category | + | Cambridge Policy | Action-Class: | Severe | This data has the value of action category | + | Cambridge Policy | Action-Class: | Intermediate | This data has the value of action category | + | Cambridge Policy | Action-Class: | Low | This data has the value of action category | + + And the following subject assignment exists + | subjectperimetername | subjectcategory | subjectdata | policyname | + | JohnLewis | Affiliation: | University-of-Stanford | Stanford Policy | + | WilliamsJoeseph | Affiliation: | Stanford | Stanford Policy | + + And the following object assignment exists + | objectperimetername | objectcategory | objectdata | policyname | + | StudentsGradesSheet | Clearance: | Access-with-permission | Cambridge Policy | + | StudentsGradesSheet | Clearance: | Public | Cambridge Policy | + #| StudentsGradesSheet | Clearance: | Top-Secret | Stanford Policy | + | StudentsGradesSheet | Clearance: | Confidential | Stanford Policy | + #| StudentsGradesSheet | Clearance: | Public | Stanford Policy | + And the following action assignment exists + | actionperimetername | actioncategory | actiondata | policyname | + | Read | Action-Class: | Severe | Stanford Policy | + #| Read | Action-Class: | Low | Stanford Policy | + | Delete | Action-Priority: | High | Cambridge Policy | + | Delete | Action-Priority: | Medium | Cambridge Policy | + | Delete | Action-Priority: | Low | Cambridge Policy | + And the following rule exists + | rule | metarulename | instructions | policyname | + | University-of-Stanford,Confidential,Severe | metarule1 | grant | Stanford Policy | + #| University-of-Stanford,Professor,Public,Adminstrative,Low,Low | metarule9 | grant | Stanford Policy | + And the following authorization request is granted through wrapper + | keystone_project_id | subjectperimetername | objectperimetername | actionperimetername | + | 0000000000000000000000000000000000000000000000000000000000000000 | JohnLewis | StudentsGradesSheet | Read | + + Scenario: Check authorization response after rule deletion + When the user sets to delete the following rules + | rule | metarulename | policyname | + | University-of-Stanford,Confidential,Severe | metarule1 | Stanford Policy | + And the following authorization request is sent through wrapper + | keystone_project_id | subjectperimetername | objectperimetername | actionperimetername | + | 0000000000000000000000000000000000000000000000000000000000000000 | JohnLewis | StudentsGradesSheet | Read | + Then the authorization response should be the following + | auth_response | + | denied | + + Scenario: Check authorization response after rule deletion then addition + When the user sets to delete the following rules + | rule | metarulename | policyname | + | University-of-Stanford,Confidential,Severe | metarule1 | Stanford Policy | + And the user sets to add the following rules + | rule | metarulename | instructions | policyname | + | University-of-Stanford,Confidential,Severe | metarule1 | grant | Stanford Policy | + And the following authorization request is sent through wrapper + | keystone_project_id | subjectperimetername | objectperimetername | actionperimetername | + | 0000000000000000000000000000000000000000000000000000000000000000 | JohnLewis | StudentsGradesSheet | Read | + Then the authorization response should be the following + | auth_response | + | grant | + + Scenario: Check authorization response after subject assignment deletion + When the user sets to delete the following subject assignment + | subjectperimetername | subjectcategory | subjectdata | policyname | + | JohnLewis | Affiliation: | University-of-Stanford | Stanford Policy | + And the following authorization request is sent through wrapper + | keystone_project_id | subjectperimetername | objectperimetername | actionperimetername | + | 0000000000000000000000000000000000000000000000000000000000000000 | JohnLewis | StudentsGradesSheet | Read | + Then the authorization response should be the following + | auth_response | + | denied | + + Scenario: Check authorization response after subject assignment deletion then addition + When the user sets to delete the following subject assignment + | subjectperimetername | subjectcategory | subjectdata | policyname | + | JohnLewis | Affiliation: | University-of-Stanford | Stanford Policy | + And the user sets to add the following subject assignment + | subjectperimetername | subjectcategory | subjectdata | policyname | + | JohnLewis | Affiliation: | University-of-Stanford | Stanford Policy | + And the following authorization request is sent through wrapper + | keystone_project_id | subjectperimetername | objectperimetername | actionperimetername | + | 0000000000000000000000000000000000000000000000000000000000000000 | JohnLewis | StudentsGradesSheet | Read | + Then the authorization response should be the following + | auth_response | + | grant | + + Scenario: Check authorization response after object assignment deletion + When the user sets to delete the following object assignment + | objectperimetername | objectcategory | objectdata | policyname | + | JohnLewis | Affiliation: | University-of-Stanford | Stanford Policy | + And the following authorization request is sent through wrapper + | keystone_project_id | subjectperimetername | objectperimetername | actionperimetername | + | 0000000000000000000000000000000000000000000000000000000000000000 | JohnLewis | StudentsGradesSheet | Read | + Then the authorization response should be the following + | auth_response | + | denied | + + Scenario: Check authorization response after object assignment deletion then addition + When the user sets to delete the following object assignment + | objectperimetername | objectcategory | objectdata | policyname | + | ProfessorsPromotionDocument | Clearance: | Confidential | Stanford Policy | + And the user sets to add the following object assignment + | objectperimetername | objectcategory | objectdata | policyname | + | ProfessorsPromotionDocument | Clearance: | Confidential | Stanford Policy | + And the following authorization request is sent through wrapper + | keystone_project_id | subjectperimetername | objectperimetername | actionperimetername | + | 0000000000000000000000000000000000000000000000000000000000000000 | JohnLewis | StudentsGradesSheet | Read | + Then the authorization response should be the following + | auth_response | + | grant | + + Scenario: Check authorization response after action assignment deletion + When When the user sets to delete the following action assignment + | actionperimetername | actioncategory | actiondata | policyname | + | Read | Action-Class: | Severe | Stanford Policy | + And the following authorization request is sent through wrapper + | keystone_project_id | subjectperimetername | objectperimetername | actionperimetername | + | 0000000000000000000000000000000000000000000000000000000000000000 | JohnLewis | StudentsGradesSheet | Read | + Then the authorization response should be the following + | auth_response | + | denied | + + Scenario: Check authorization response after action assignment deletion then addition + When the user sets to delete the following action assignment + | actionperimetername | actioncategory | actiondata | policyname | + | Read | Action-Class: | Severe | Stanford Policy | + And the user sets to add the following action assignment + | actionperimetername | actioncategory | actiondata | policyname | + | Read | Action-Class: | Low | Stanford Policy | + And the following authorization request is sent through wrapper + | keystone_project_id | subjectperimetername | objectperimetername | actionperimetername | + | 0000000000000000000000000000000000000000000000000000000000000000 | JohnLewis | StudentsGradesSheet | Read | + Then the authorization response should be the following + | auth_response | + | grant | + + + Scenario: Check authorization response after subject data deletion + When the user sets to delete the following subject data + | policyname | subjectcategory | subjectdataname | + | Stanford Policy | Affiliation: | University-of-Stanford | + And the following authorization request is sent through wrapper + | keystone_project_id | subjectperimetername | objectperimetername | actionperimetername | + | 0000000000000000000000000000000000000000000000000000000000000000 | JohnLewis | StudentsGradesSheet | Read | + Then the authorization response should be the following + | auth_response | + | denied | + + Scenario: Check authorization response after subject data deletion then addition + When the user sets to delete the following subject data + | policyname | subjectcategory | subjectdataname | + | Stanford Policy | Affiliation: | University-of-Stanford | + And the user sets to add the following subject data + | policyname | subjectcategory | subjectdataname | subjectdatadescription | + | Stanford Policy | Affiliation: | University-of-Stanford | This data has the value of subject category | + And the following authorization request is sent through wrapper + | keystone_project_id | subjectperimetername | objectperimetername | actionperimetername | + | 0000000000000000000000000000000000000000000000000000000000000000 | JohnLewis | StudentsGradesSheet | Read | + Then the authorization response should be the following + | auth_response | + | grant | + + Scenario: Check authorization response after object data deletion + When the user sets to delete the following object data + | policyname | objectcategory | objectdataname | + | Stanford Policy | Clearance: | Top-Secret | + And the following authorization request is sent through wrapper + | keystone_project_id | subjectperimetername | objectperimetername | actionperimetername | + | 0000000000000000000000000000000000000000000000000000000000000000 | JohnLewis | StudentsGradesSheet | Read | + Then the authorization response should be the following + | auth_response | + | denied | + + Scenario: Check authorization response after object data deletion then addition + When the user sets to delete the following object data + | policyname | objectcategory | objectdataname | + | Stanford Policy | Clearance: | Top-Secret | + And the user sets to add the following object data + | policyname | objectcategory | objectdataname | objectdatadescription | + | Stanford Policy | Clearance: | Confidential | This data has the value of object category | + And the following authorization request is sent through wrapper + | keystone_project_id | subjectperimetername | objectperimetername | actionperimetername | + | 0000000000000000000000000000000000000000000000000000000000000000 | JohnLewis | StudentsGradesSheet | Read | + Then the authorization response should be the following + | auth_response | + | grant | + + Scenario: Check authorization response after action data deletion + When the user sets to delete the following action data + | policyname | actioncategory | actiondataname | + | Stanford Policy | Action-Class: | Severe | + And the following authorization request is sent through wrapper + | keystone_project_id | subjectperimetername | objectperimetername | actionperimetername | + | 0000000000000000000000000000000000000000000000000000000000000000 | JohnLewis | StudentsGradesSheet | Read | + Then the authorization response should be the following + | auth_response | + | denied | + + Scenario: Check authorization response after action data deletion then addition + When the user sets to delete the following action data + | policyname | actioncategory | actiondataname | + | Stanford Policy | Action-Class: | Severe | + And the user sets to add the following action data + | policyname | actioncategory | actiondataname | actiondatadescription | + | Stanford Policy | Action-Class: | Severe | This data has the value of action category | + And the following authorization request is sent through wrapper + | keystone_project_id | subjectperimetername | objectperimetername | actionperimetername | + | 0000000000000000000000000000000000000000000000000000000000000000 | JohnLewis | StudentsGradesSheet | Read | + Then the authorization response should be the following + | auth_response | + | grant | + + + Scenario: Check authorization response after subject perimeter deletion + When the user sets to delete the following subject perimeter for a given policy + | subjectperimetername | policies | + | JohnLewis | Stanford Policy | + And the following authorization request is sent through wrapper + | keystone_project_id | subjectperimetername | objectperimetername | actionperimetername | + | 0000000000000000000000000000000000000000000000000000000000000000 | JohnLewis | StudentsGradesSheet | Read | + Then the authorization response should be the following + | auth_response | + | denied | + + Scenario: Check authorization response after subject perimeter deletion then addition + When the user sets to delete the following subject perimeter for a given policy + | subjectperimetername | policies | + | JohnLewis | Stanford Policy | + And the user sets to add the following subject perimeter + | subjectperimetername | subjectperimeterdescription | subjectperimeteremail | subjectperimeterpassword | policies | + | JohnLewis | Thisistheexpecteduser | jlewis@orange.com | abc1234 | Stanford Policy | + And the following authorization request is sent through wrapper + | keystone_project_id | subjectperimetername | objectperimetername | actionperimetername | + | 0000000000000000000000000000000000000000000000000000000000000000 | JohnLewis | StudentsGradesSheet | Read | + Then the authorization response should be the following + | auth_response | + | grant | + + Scenario: Check authorization response after object perimeter deletion + When the user sets to delete the following object perimeter + | objectperimetername | policies | + | ProfessorsPromotionDocument | Stanford Policy | + And the following authorization request is sent through wrapper + | keystone_project_id | subjectperimetername | objectperimetername | actionperimetername | + | 0000000000000000000000000000000000000000000000000000000000000000 | JohnLewis | StudentsGradesSheet | Read | + Then the authorization response should be the following + | auth_response | + | denied | + + Scenario: Check authorization response after object perimeter deletion then addition + When the user sets to delete the following object perimeter + | objectperimetername | policies | + | ProfessorsPromotionDocument | Stanford Policy | + And the user sets to add the following object perimeter + | objectperimetername | objectperimeterdescription | policies | + | ProfessorsPromotionDocument | Thisistherequesttoaccessfile | Stanford Policy | + And the following authorization request is sent through wrapper + | keystone_project_id | subjectperimetername | objectperimetername | actionperimetername | + | 0000000000000000000000000000000000000000000000000000000000000000 | JohnLewis | StudentsGradesSheet | Read | + Then the authorization response should be the following + | auth_response | + | grant | + + Scenario: Check authorization response after action perimeter deletion + When the user sets to delete the following action perimeter + | actionperimetername | policies | + | Read | Stanford Policy | + And the following authorization request is sent through wrapper + | keystone_project_id | subjectperimetername | objectperimetername | actionperimetername | + | 0000000000000000000000000000000000000000000000000000000000000000 | JohnLewis | StudentsGradesSheet | Read | + Then the authorization response should be the following + | auth_response | + | denied | + + Scenario: Check authorization response after action perimeter deletion then addition + When the user sets to delete the following action perimeter + | actionperimetername | policies | + | Read | Stanford Policy | + And the user sets to add the following action perimeter + | actionperimetername | actionperimeterdescription | policies | + | Read | Thisistheactionrequired | Stanford Policy | + And the following authorization request is sent through wrapper + | keystone_project_id | subjectperimetername | objectperimetername | actionperimetername | + | 0000000000000000000000000000000000000000000000000000000000000000 | JohnLewis | StudentsGradesSheet | Read | + Then the authorization response should be the following + | auth_response | + | grant | diff --git a/moon_manager/tests/func_tests/features/data.feature b/moon_manager/tests/func_tests/features/data.feature new file mode 100644 index 00000000..1edb4098 --- /dev/null +++ b/moon_manager/tests/func_tests/features/data.feature @@ -0,0 +1,330 @@ +Feature: Data + + Background: + Given the system has no rules + And the system has no subject assignments + And the system has no action assignments + And the system has no object assignments + And the system has no subject data + And the system has no action data + And the system has no object data + And the system has no subject perimeter + And the system has no object perimeter + And the system has no action perimeter + And the system has no pdps + And the system has no policies + And the system has no models + And the system has no meta-rules + And the system has no subject categories + And the system has no action categories + And the system has no object categories + And the following meta data subject category exists + | subjectmetadataname | subjectmetadatadescription | + | Affiliation: | This meta data has the categorical information about a subject | + | Authorization-Level: | This meta data has the categorical information about an object | + | Degree: | This meta data has the categorical information about an object | + And the following meta data object category exists + | objectmetadataname | objectmetadatadescription | + | Clearance: | This meta data has the categorical information about an object | + | Type: | This meta data has the categorical information about an object | + | Class: | This meta data has the categorical information about an object | + And the following meta data action category exists + | actionmetadataname | actionmetadatadescription | + | Action-Class: | This meta data has the categorical information about an action | + | Action-Priority: | This meta data has the categorical information about an action | + | Recommendation: | This meta data has the categorical information about an action | + And the following meta rule exists + | metarulename | metaruledescription | subjectmetadata | actionmetadata | objectmetadata | + | metarule1 | Thisisabasicmetarule | Affiliation: | Action-Class: | Clearance: | + | metarule2 | Thisisabasicmetarule | Authorization-Level: | Action-Class: | Clearance: | + | metarule3 | Thisisabasicmetarule | Affiliation: | Action-Priority: | Clearance: | + | metarule4 | Thisisabasicmetarule | Authorization-Level: | Action-Priority: | Clearance: | + | metarule5 | Thisisabasicmetarule | Affiliation: | Action-Class: | Type: | + | metarule6 | Thisisabasicmetarule | Authorization-Level: | Action-Class: | Type: | + | metarule7 | Thisisabasicmetarule | Affiliation: | Action-Priority: | Type: | + | metarule8 | Thisisabasicmetarule | Authorization-Level: | Action-Priority: | Type: | + | metarule9 | Thisisabasicmetarule | Affiliation:,Authorization-Level: | Action-Class:,Action-Priority: | Clearance:,Type: | + And the following model exists + | modelname | modeldescription | metarule | + | universitymodel | Thisisabasicmodel | metarule1 | + | universitymodel2 | Thisisabasicmodel | metarule3,metarule5,metarule8 | + | universitymodel3 | Thisisabasicmodel | metarule8 | + | universitymodel4 | Thisisabasicmodel | metarule9 | + And the following policy exists + | policyname | policydescription | modelname | genre | + | Stanford Policy | This is a basic policy | universitymodel | Education | + | Cambridge Policy | This is a basic policy | universitymodel3 | Education | + | MIT Policy | This is a basic policy | universitymodel2 | Education | + | Oxford Policy | This is a basic policy | universitymodel4 | Education | + + + Scenario: Add subject data + When the user sets to add the following subject data + | policyname | subjectcategory | subjectdataname | subjectdatadescription | + | Cambridge Policy | Authorization-Level: | Teaching-staff | This data has the value of subject category | + | MIT Policy | Authorization-Level: | Teaching-staff | This data has the value of subject category | + | MIT Policy | Affiliation: | University-of-MIT | This data has the value of subject category | + | Oxford Policy | Affiliation: | University-of-Oxford | This data has the value of subject category | + | Oxford Policy | Authorization-Level: | Teaching-staff | This data has the value of subject category | + | Stanford Policy | Affiliation: | University-of-Stanford | This data has the value of subject category | + Then the following subject data should be existed in the system + | policyname | subjectcategory | subjectdataname | subjectdatadescription | + | Cambridge Policy | Authorization-Level: | Teaching-staff | This data has the value of subject category | + | MIT Policy | Authorization-Level: | Teaching-staff | This data has the value of subject category | + | MIT Policy | Affiliation: | University-of-MIT | This data has the value of subject category | + | Oxford Policy | Affiliation: | University-of-Oxford | This data has the value of subject category | + | Oxford Policy | Authorization-Level: | Teaching-staff | This data has the value of subject category | + | Stanford Policy | Affiliation: | University-of-Stanford | This data has the value of subject category | + + Scenario Outline: Add subject data validations + When the user sets to add the following subject data + | policyname | subjectcategory | subjectdataname | subjectdatadescription | + | | | | | + Then the system should reply the following + | flag | + | | + Examples: + | policyname | subjectcategory | subjectdataname | subjectdatadescription | flag | + | | Affiliation: | University-of-Stanford | This data has the value of subject category | False | + | 000000000000000000000000000000000000000000000000000000000 | Affiliation: | University-of-Stanford | This data has the value of subject category | False | + | 0000000000000000000000000000000000000000000000000000000000000000 | Affiliation: | University-of-Stanford | This data has the value of subject category | False | + | 0000000000000000000000000000000000000000000000000000000000000000000 | Affiliation: | University-of-Stanford | This data has the value of subject category | False | + | Cambridge Policy | Affiliation: | University-of-Cambridge | This data has the value of subject category | False | + | Stanford Policy | | University-of-Stanford | This data has the value of subject category | False | + | Stanford Policy | 000000000000000000000000000000000000000000000000000000000 | University-of-Stanford | This data has the value of subject category | False | + | Stanford Policy | 0000000000000000000000000000000000000000000000000000000000000000 | University-of-Stanford | This data has the value of subject category | False | + | Stanford Policy | 0000000000000000000000000000000000000000000000000000000000000000000 | University-of-Stanford | This data has the value of subject category | False | + | Stanford Policy | Affiliation: | | This data has the value of subject category | False | + | Stanford Policy | Affiliation: | _%University-of-Stanford%_ | This data has the value of subject category | True | + | Stanford Policy | Affiliation: | 1 | This data has the value of subject category | True | + | Stanford Policy | Affiliation: | University-of-Stanford | | True | + | Stanford Policy | Affiliation: | University-of-Stanford | _%This data has the value of subject category%_ | True | + + Scenario Outline: Add an existing subject data + Given the following subject data exists + | policyname | subjectcategory | subjectdataname | subjectdatadescription | + | Stanford Policy | Affiliation: | University-of-Stanford | This data has the value of subject category | + When the user sets to add the following subject data + | policyname | subjectcategory | subjectdataname | subjectdatadescription | + | | | | | + Then the system should reply the following + | flag | + | | + Examples: + | policyname | subjectcategory | subjectdataname | subjectdatadescription | flag | + | Stanford Policy | Affiliation: | University-of-Stanford | This data has the value of subject category | False | + | Stanford Policy | Affiliation: | University-of-Stanford,Faculty-of-Computer-Science | This data has the value of subject category | True | + + Scenario: Delete subject data + Given the following subject data exists + | policyname | subjectcategory | subjectdataname | subjectdatadescription | + | Stanford Policy | Affiliation: | University-of-Stanford | This data has the value of subject category | + When the user sets to delete the following subject data + | policyname | subjectcategory | subjectdataname | + | Stanford Policy | Affiliation: | University-of-Stanford | + Then the following subject data should be existed in the system + | policyname | subjectcategory | subjectdataname | subjectdatadescription | + | | | | | + + Scenario: Delete subject data that has a recorded assignment dependency + Given the following subject data exists + | policyname | subjectcategory | subjectdataname | subjectdatadescription | + | Stanford Policy | Affiliation: | University-of-Stanford | This data has the value of subject category | + And the following subject perimeter exists + | policies | subjectperimetername | subjectperimeterdescription | subjectperimeteremail | subjectperimeterpassword | + | Stanford Policy | JohnLewis | This data has the value of subject perimeter | jlewis@orange.com | abc1234 | + And the following subject assignment exists + | subjectperimetername | subjectcategory | subjectdata | policyname | + | John Lewis | Affiliation: | University-of-Stanford | Stanford Policy | + When the user sets to delete the following subject data + | policyname | subjectcategory | subjectdataname | + | Stanford Policy | Affiliation: | University-of-Stanford | + Then the system should reply the following + | flag | + | True | + And the following subject data should be existed in the system + | policyname | subjectcategory | subjectdataname | subjectdatadescription | + | | | | | + + + Scenario: Add object data + When the user sets to add the following object data + | policyname | objectcategory | objectdataname | objectdatadescription | + | Cambridge Policy | Type: | Adminstrative | This data has the value of object category | + | MIT Policy | Type: | Adminstrative | This data has the value of object category | + | MIT Policy | Clearance: | Confidential | This data has the value of object category | + | Oxford Policy | Type: | Adminstrative | This data has the value of object category | + | Oxford Policy | Clearance: | Confidential | This data has the value of object category | + | Stanford Policy | Clearance: | Confidential | This data has the value of object category | + + Then the following object data should be existed in the system + | policyname | objectcategory | objectdataname | objectdatadescription | + | Cambridge Policy | Type: | Adminstrative | This data has the value of object category | + | MIT Policy | Type: | Adminstrative | This data has the value of object category | + | MIT Policy | Clearance: | Confidential | This data has the value of object category | + | Oxford Policy | Type: | Adminstrative | This data has the value of object category | + | Oxford Policy | Clearance: | Confidential | This data has the value of object category | + | Stanford Policy | Clearance: | Confidential | This data has the value of object category | + + Scenario Outline: Add object data validations + When the user sets to add the following object data + | policyname | objectcategory | objectdataname | objectdatadescription | + | | | | | + Then the system should reply the following + | flag | + | | + Examples: + | policyname | objectcategory | objectdataname | objectdatadescription | flag | + | | Clearance: | Confidential | This data has the value of object category | False | + | 000000000000000000000000000000000000000000000000000000000 | Clearance: | Confidential | This data has the value of object category | False | + | 0000000000000000000000000000000000000000000000000000000000000000 | Clearance: | Confidential | This data has the value of object category | False | + | 0000000000000000000000000000000000000000000000000000000000000000000 | Clearance: | Confidential | This data has the value of object category | False | + #| Cambridge Policy | Clearance: | Confidential | This data has the value of object category | False | + | Stanford Policy | | Confidential | This data has the value of object category | False | + #| Stanford Policy | Type: | Confidential | This data has the value of object category | False | + | Stanford Policy | 000000000000000000000000000000000000000000000000000000000 | Confidential | This data has the value of object category | False | + | Stanford Policy | 0000000000000000000000000000000000000000000000000000000000000000 | Confidential | This data has the value of object category | False | + | Stanford Policy | 0000000000000000000000000000000000000000000000000000000000000000000 | Confidential | This data has the value of object category | False | + | Stanford Policy | Clearance: | | This data has the value of object category | False | + | Stanford Policy | Clearance: | _%Confidential%_ | This data has the value of object category | True | + | Stanford Policy | Clearance: | 1 | This data has the value of object category | True | + | Stanford Policy | Clearance: | Confidential | | True | + | Stanford Policy | Clearance: | Confidential | _%This data has the value of object category%_ | True | + + Scenario Outline: Add an existing object data + Given the following object data exists + | policyname | objectcategory | objectdataname | objectdatadescription | + | Stanford Policy | Clearance: | Confidential | This data has the value of object category | + When the user sets to add the following object data + | policyname | objectcategory | objectdataname | objectdatadescription | + | | | | | + Then the system should reply the following + | flag | + | | + Examples: + | policyname | objectcategory | objectdataname | objectdatadescription | flag | + | Stanford Policy | Clearance: | Confidential | This data has the value of object category | False | + | Stanford Policy | Clearance: | Top-Secret | This data has the value of object category | True | + + Scenario: Delete object data + Given the following object data exists + | policyname | objectcategory | objectdataname | objectdatadescription | + | Stanford Policy | Clearance: | Top-Secret | This data has the value of object category | + When the user sets to delete the following object data + | policyname | objectcategory | objectdataname | + | Stanford Policy | Clearance: | Top-Secret | + Then the following object data should be existed in the system + | policyname | objectcategory | objectdataname | objectdatadescription | + | | | | | + + Scenario: Delete object data that has a recorded assignment dependency + Given the following object data exists + | policyname | objectcategory | objectdataname | objectdatadescription | + | Stanford Policy | Clearance: | Top-Secret | This data has the value of object category | + | Cambridge Policy | Type: | Top-Secret | This data has the value of object category | + And the following object perimeter exists + | policies | objectperimetername | objectperimeterdescription | + | Stanford Policy | ProfessorsPromotionDocument | This data has the value of object perimeter | + And the following object assignment exists + | objectperimetername | objectcategory | objectdata | policyname | + | ProfessorsPromotionDocument | Clearance: | Top-Secret | Stanford Policy | + When the user sets to delete the following object data + | policyname | objectcategory | objectdataname | + | Stanford Policy | Clearance: | Top-Secret | + Then the system should reply the following + | flag | + | True | + And the following object data should be existed in the system + | policyname | objectcategory | objectdataname | objectdatadescription | + | Cambridge Policy | Type: | Top-Secret | This data has the value of object category | + + + Scenario: Add action data + When the user sets to add the following action data + | policyname | actioncategory | actiondataname | actiondatadescription | + | Cambridge Policy | Action-Priority: | high | This data has the value of action category | + | MIT Policy | Action-Priority: | high | This data has the value of action category | + | MIT Policy | Action-Class: | Severe | This data has the value of action category | + | Oxford Policy | Action-Priority: | high | This data has the value of action category | + | Oxford Policy | Action-Class: | Severe | This data has the value of action category | + | Stanford Policy | Action-Class: | Severe | This data has the value of action category | + + Then the following action data should be existed in the system + | policyname | actioncategory | actiondataname | actiondatadescription | + | Cambridge Policy | Action-Priority: | high | This data has the value of action category | + | MIT Policy | Action-Priority: | high | This data has the value of action category | + | MIT Policy | Action-Class: | Severe | This data has the value of action category | + | Oxford Policy | Action-Priority: | high | This data has the value of action category | + | Oxford Policy | Action-Class: | Severe | This data has the value of action category | + | Stanford Policy | Action-Class: | Severe | This data has the value of action category | + + Scenario Outline: Add action data validations + When the user sets to add the following action data + | policyname | actioncategory | actiondataname | actiondatadescription | + | | | | | + Then the system should reply the following + | flag | + | | + Examples: + | policyname | actioncategory | actiondataname | actiondatadescription | flag | + | | Action-Class: | Severe | This data has the value of action category | False | + | 000000000000000000000000000000000000000000000000000000000 | Action-Class: | Severe | This data has the value of action category | False | + | 0000000000000000000000000000000000000000000000000000000000000000 | Action-Class: | Severe | This data has the value of action category | False | + | 0000000000000000000000000000000000000000000000000000000000000000000 | Action-Class: | Severe | This data has the value of action category | False | + #| Cambridge Policy | Action-Class: | Severe | This data has the value of action category | False | + | Stanford Policy | | Severe | This data has the value of action category | False | + | Stanford Policy | 000000000000000000000000000000000000000000000000000000000 | Severe | This data has the value of action category | False | + | Stanford Policy | 0000000000000000000000000000000000000000000000000000000000000000 | Severe | This data has the value of action category | False | + | Stanford Policy | 0000000000000000000000000000000000000000000000000000000000000000000 | Severe | This data has the value of action category | False | + | Stanford Policy | Action-Class: | | This data has the value of action category | False | + | Stanford Policy | Action-Class: | _%Severe%_ | This data has the value of action category | True | + | Stanford Policy | Action-Class: | 1 | This data has the value of action category | True | + | Stanford Policy | Action-Class: | Severe | | True | + | Stanford Policy | Action-Class: | Severe | _%This data has the value of action category%_ | True | + + Scenario Outline: Add an existing action data + Given the following action data exists + | policyname | actioncategory | actiondataname | actiondatadescription | + | Stanford Policy | Action-Class: | Severe | This data has the value of action category | + When the user sets to add the following action data + | policyname | actioncategory | actiondataname | actiondatadescription | + | | | | | + Then the system should reply the following + | flag | + | | + Examples: + | policyname | actioncategory | actiondataname | actiondatadescription | flag | + | Stanford Policy | Action-Class: | Severe | This data has the value of action category | False | + | Stanford Policy | Action-Class: | high | This data has the value of action category | True | + + Scenario: Delete action data + Given the following action data exists + | policyname | actioncategory | actiondataname | actiondatadescription | + | Stanford Policy | Action-Class: | Severe | This data has the value of action category | + When the user sets to delete the following action data + | policyname | actioncategory | actiondataname | + | Stanford Policy | Action-Class: | Severe | + Then the following action data should be existed in the system + | policyname | actioncategory | actiondataname | actiondatadescription | + | | | | | + + Scenario: Delete action data that has a recorded assignment dependency + Given the following action data exists + | policyname | actioncategory | actiondataname | actiondatadescription | + | Stanford Policy | Action-Class: | Severe | This data has the value of action category | + | Cambridge Policy | Action-Priority: | Medium | This data has the value of action category | + And the following action perimeter exists + | policies | actionperimetername | actionperimeterdescription | + | Stanford Policy | Read | This data has the value of action perimeter | + And the following action assignment exists + | actionperimetername | actioncategory | actiondata | policyname | + | Read | Action-Class: | Severe | Stanford Policy | + When the user sets to delete the following action data + | policyname | actioncategory | actiondataname | + | Stanford Policy | Action-Class: | Severe | + Then the system should reply the following + | flag | + | True | + And the following action data should be existed in the system + | policyname | actioncategory | actiondataname | actiondatadescription | + | Cambridge Policy | Action-Priority: | Medium | This data has the value of action category | diff --git a/moon_manager/tests/func_tests/features/environment.py b/moon_manager/tests/func_tests/features/environment.py new file mode 100644 index 00000000..b65c292d --- /dev/null +++ b/moon_manager/tests/func_tests/features/environment.py @@ -0,0 +1,27 @@ +# Software Name: MOON: + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + +from __future__ import print_function +import logging + +logger = logging.getLogger(__name__) + +def before_feature(context, feature): + handler = logging.FileHandler(filename='Logs/'+"Automation Testing Log- "+ feature.name + ".log") + formatter = logging.Formatter('%(asctime)s : %(levelname)s : %(message)s') + handler.setFormatter(formatter) + handler.setLevel(logging.INFO) + logger.addHandler(handler) + + +def before_all(context): + logging.getLogger("requests").setLevel(logging.WARN) + diff --git a/moon_manager/tests/func_tests/features/meta_data.feature b/moon_manager/tests/func_tests/features/meta_data.feature new file mode 100644 index 00000000..18817e2e --- /dev/null +++ b/moon_manager/tests/func_tests/features/meta_data.feature @@ -0,0 +1,295 @@ +Feature: Meta Data ( Category ) + + Background: + Given the system has no rules + And the system has no subject assignments + And the system has no action assignments + And the system has no object assignments + And the system has no subject data + And the system has no action data + And the system has no object data + And the system has no subject perimeter + And the system has no object perimeter + And the system has no action perimeter + And the system has no pdps + And the system has no policies + And the system has no models + And the system has no meta-rules + And the system has no subject categories + And the system has no action categories + And the system has no object categories + + + + Scenario: Add subject category + When the user sets to add the following meta data subject category + | subjectmetadataname | subjectmetadatadescription | + | Affiliation: | This meta data has the categorical information about a subject | + Then the following meta data subject category should be existed in the system + | subjectmetadataname | subjectmetadatadescription | + | Affiliation: | This meta data has the categorical information about a subject | + + Scenario Outline: Add meta data subject validations + When the user sets to add the following meta data subject category + | subjectmetadataname | subjectmetadatadescription | + | | | + Then the system should reply the following + | flag | + | | + Examples: + | subjectmetadataname | subjectmetadatadescription | flag | + | | This meta data has the categorical information about a subject | False | + | Affiliation: | | True | + | 1 | This meta data has the categorical information about a subject% | True | + | _%Affiliation:%_ | This meta data has the categorical information about a subject | True | + + Scenario: Add an existing meta data subject + Given the following meta data subject category exists + | subjectmetadataname | subjectmetadatadescription | + | Affiliation: | This meta data has the categorical information about an subject1 | + When the user sets to add the following meta data subject category + | subjectmetadataname | subjectmetadatadescription | + | Affiliation: | This meta data has the categorical information about an subject1 | + Then the system should reply the following + | flag | + | False | + + Scenario: Delete subject category + Given the following meta data subject category exists + | subjectmetadataname | subjectmetadatadescription | + | Affiliation: | This meta data has the categorical information about a subject | + When the user sets to delete the following meta data subject category + | subjectmetadataname | + | Affiliation: | + Then the following meta data subject category should be existed in the system + | subjectmetadataname | subjectmetadatadescription | + | | | + + Scenario: Delete subject category that has a recorded meta-rule dependency + Given the following meta data subject category exists + | subjectmetadataname | subjectmetadatadescription | + | Affiliation: | This meta data has the categorical information about a subject | + And the following meta data object category exists + | objectmetadataname | objectmetadatadescription | + | Clearance: | This meta data has the categorical information about an object | + And the following meta data action category exists + | actionmetadataname | actionmetadatadescription | + | Action-Class: | This meta data has the categorical information about an action | + And the following meta rule exists + | metarulename | metaruledescription | subjectmetadata | actionmetadata | objectmetadata | + | metarule1 | This is a basic meta rule | Affiliation: | Action-Class: | Clearance: | + When the user sets to delete the following meta data subject category + | subjectmetadataname | + | Affiliation: | + Then the system should reply the following + | flag | + | False | + And the following meta data subject category should be existed in the system + | subjectmetadataname | subjectmetadatadescription | + | Affiliation: | This meta data has the categorical information about a subject | + + Scenario: Delete subject category after deleting the recorded meta-rule dependency + Given the following meta data subject category exists + | subjectmetadataname | subjectmetadatadescription | + | Affiliation: | This meta data has the categorical information about a subject | + And the following meta data object category exists + | objectmetadataname | objectmetadatadescription | + | Clearance: | This meta data has the categorical information about an object | + And the following meta data action category exists + | actionmetadataname | actionmetadatadescription | + | Action-Class: | This meta data has the categorical information about an action | + And the following meta rule exists + | metarulename | metaruledescription | subjectmetadata | actionmetadata | objectmetadata | + | metarule1 | This is a basic meta rule | Affiliation: | Action-Class: | Clearance: | + When the user sets to delete the following meta-rule + | metarulename | + | metarule1 | + And the user sets to delete the following meta data subject category + | subjectmetadataname | + | Affiliation: | + Then the following meta data subject category should be existed in the system + | subjectmetadataname | subjectmetadatadescription | + | | | + + + Scenario: Add object category + When the user sets to add the following meta data object category + | objectmetadataname | objectmetadatadescription | + | Clearance: | This meta data has the categorical information about an object | + Then the following meta data object category should be existed in the system + | objectmetadataname | objectmetadatadescription | + | Clearance: | This meta data has the categorical information about an object | + + Scenario Outline: Add meta data object validations + When the user sets to add the following meta data object category + | objectmetadataname | objectmetadatadescription | + | | | + Then the system should reply the following + | flag | + | | + Examples: + | objectmetadataname | objectmetadatadescription | flag | + | | This meta data has the categorical information about an object | False | + | Clearance: | | True | + | 1 | This meta data has the categorical information about an object % | True | + | _%Clearance:%_ | This meta data has the categorical information about an object | True | + + Scenario: Add an existing meta data object + Given the following meta data object category exists + | objectmetadataname | objectmetadatadescription | + | Clearance: | This meta data has the categorical information about an object | + When the user sets to add the following meta data object category + | objectmetadataname | objectmetadatadescription | + | Clearance: | This meta data has the categorical information about an object | + Then the system should reply the following + | flag | + | False | + + Scenario: Delete object category + Given the following meta data object category exists + | objectmetadataname | objectmetadatadescription | + | Clearance: | This meta data has the categorical information about an object1 | + When the user sets to delete the following meta data object category + | objectmetadataname | + | Clearance: | + Then the following meta data object category should be existed in the system + | objectmetadataname | objectmetadatadescription | + | | | + + Scenario: Delete object category that has a recorded meta-rule dependency + Given the following meta data subject category exists + | subjectmetadataname | subjectmetadatadescription | + | Affiliation: | This meta data has the categorical information about a subject | + And the following meta data object category exists + | objectmetadataname | objectmetadatadescription | + | Clearance: | This meta data has the categorical information about an object | + And the following meta data action category exists + | actionmetadataname | actionmetadatadescription | + | Action-Class: | This meta data has the categorical information about an action | + And the following meta rule exists + | metarulename | metaruledescription | subjectmetadata | actionmetadata | objectmetadata | + | metarule1 | This is a basic meta rule | Affiliation: | Action-Class: | Clearance: | + When the user sets to delete the following meta data object category + | objectmetadataname | + | Clearance: | + Then the system should reply the following + | flag | + | False | + And the following meta data object category should be existed in the system + | objectmetadataname | objectmetadatadescription | + | Clearance: | This meta data has the categorical information about an object | + + Scenario: Delete object category after deleting the recorded meta-rule dependency + Given the following meta data subject category exists + | subjectmetadataname | subjectmetadatadescription | + | Affiliation: | This meta data has the categorical information about a subject | + And the following meta data object category exists + | objectmetadataname | objectmetadatadescription | + | Clearance: | This meta data has the categorical information about an object | + And the following meta data action category exists + | actionmetadataname | actionmetadatadescription | + | Action-Class: | This meta data has the categorical information about an action | + And the following meta rule exists + | metarulename | metaruledescription | subjectmetadata | actionmetadata | objectmetadata | + | metarule1 | This is a basic meta rule | Affiliation: | Action-Class: | Clearance: | + When the user sets to delete the following meta-rule + | metarulename | + | metarule1 | + And the user sets to delete the following meta data object category + | objectmetadataname | + | Clearance: | + Then the following meta data object category should be existed in the system + | objectmetadataname | objectmetadatadescription | + | | | + + + Scenario: Add action category + When the user sets to add the following meta data action category + | actionmetadataname | actionmetadatadescription | + | Action-Class: | This meta data has the categorical information about an action | + Then the following meta data action category should be existed in the system + | actionmetadataname | actionmetadatadescription | + | Action-Class: | This meta data has the categorical information about an action | + + Scenario Outline: Add meta data action validations + When the user sets to add the following meta data action category + | actionmetadataname | actionmetadatadescription | + | | | + Then the system should reply the following + | flag | + | | + Examples: + | actionmetadataname | actionmetadatadescription | flag | + | | This meta data has the categorical information about the action | False | + | Action-Class: | | True | + | 1 | This meta data has the categorical information about the action% | True | + | _%Action-Class:%_ | This meta data has the categorical information about the action | True | + + Scenario: Add an existing meta data action + Given the following meta data action category exists + | actionmetadataname | actionmetadatadescription | + | Action-Class: | This meta data has the categorical information about an action | + When the user sets to add the following meta data action category + | actionmetadataname | actionmetadatadescription | + | Action-Class: | This meta data has the categorical information about an action | + Then the system should reply the following + | flag | + | False | + + Scenario: Delete action category + Given the following meta data action category exists + | actionmetadataname | actionmetadatadescription | + | Action-Class: | This meta data has the categorical information about an action | + When the user sets to delete the following meta data action category + | actionmetadataname | + | Action-Class: | + Then the following meta data action category should be existed in the system + | actionmetadataname | actionmetadatadescription | + | | | + + Scenario: Delete action category that has a recorded meta-rule + Given the following meta data subject category exists + | subjectmetadataname | subjectmetadatadescription | + | Affiliation: | This meta data has the categorical information about a subject | + And the following meta data object category exists + | objectmetadataname | objectmetadatadescription | + | Clearance: | This meta data has the categorical information about an object | + And the following meta data action category exists + | actionmetadataname | actionmetadatadescription | + | Action-Class: | This meta data has the categorical information about an action | + And the following meta rule exists + | metarulename | metaruledescription | subjectmetadata | actionmetadata | objectmetadata | + | metarule1 | This is a basic meta rule | Affiliation: | Action-Class: | Clearance: | + When the user sets to delete the following meta data action category + | actionmetadataname | + | Action-Class: | + Then the system should reply the following + | flag | + | False | + And the following meta data action category should be existed in the system + | actionmetadataname | actionmetadatadescription | + | Action-Class: | This meta data has the categorical information about an action | + + Scenario: Delete action Category after deleting the recorded meta-rule dependency + Given the following meta data subject category exists + | subjectmetadataname | subjectmetadatadescription | + | Affiliation: | This meta data has the categorical information about a subject | + And the following meta data object category exists + | objectmetadataname | objectmetadatadescription | + | Clearance: | This meta data has the categorical information about an object | + And the following meta data action category exists + | actionmetadataname | actionmetadatadescription | + | Action-Class: | This meta data has the categorical information about an action | + And the following meta rule exists + | metarulename | metaruledescription | subjectmetadata | actionmetadata | objectmetadata | + | metarule1 | This is a basic meta rule | Affiliation: | Action-Class: | Clearance: | + When the user sets to delete the following meta-rule + | metarulename | + | metarule1 | + And the user sets to delete the following meta data action category + | actionmetadataname | + | Action-Class: | + Then the following meta data action category should be existed in the system + | actionmetadataname | actionmetadatadescription | + | | | + diff --git a/moon_manager/tests/func_tests/features/meta_rules.feature b/moon_manager/tests/func_tests/features/meta_rules.feature new file mode 100644 index 00000000..2941d1f3 --- /dev/null +++ b/moon_manager/tests/func_tests/features/meta_rules.feature @@ -0,0 +1,234 @@ +Feature: Meta Rule + + Background: + Given the system has no rules + And the system has no subject assignments + And the system has no action assignments + And the system has no object assignments + And the system has no subject data + And the system has no action data + And the system has no object data + And the system has no subject perimeter + And the system has no object perimeter + And the system has no action perimeter + And the system has no pdps + And the system has no policies + And the system has no models + And the system has no meta-rules + And the system has no subject categories + And the system has no action categories + And the system has no object categories + And the following meta data subject category exists + | subjectmetadataname | subjectmetadatadescription | + | Affiliation: | This meta data has the categorical information about a subject | + | Authorization-Level: | This meta data has the categorical information about an object | + | Degree: | This meta data has the categorical information about an object | + And the following meta data object category exists + | objectmetadataname | objectmetadatadescription | + | Clearance: | This meta data has the categorical information about an object | + | Type: | This meta data has the categorical information about an object | + | Class: | This meta data has the categorical information about an object | + And the following meta data action category exists + | actionmetadataname | actionmetadatadescription | + | Action-Class: | This meta data has the categorical information about an action | + | Action-Priority: | This meta data has the categorical information about an action | + | Recommendation: | This meta data has the categorical information about an action | + + + Scenario: Add meta rules + When the user sets to add the following meta-rule + | metarulename | subjectmetadata | actionmetadata | objectmetadata | metaruledescription | + | A-rule | Affiliation: | Action-Class: | Clearance: | AThisisabasicmetarule | + | Z-rule | Authorization-Level:,Affiliation: | Action-Priority:,Action-Class: | Type:,Clearance: | ZThisisabasicmetarule | + Then the following meta-rules should be existed in the system + | metarulename | metaruledescription | subjectmetadata | actionmetadata | objectmetadata | + | A-rule | AThisisabasicmetarule | Affiliation: | Action-Class: | Clearance: | + | Z-rule | ZThisisabasicmetarule | Authorization-Level:,Affiliation: | Action-Priority:,Action-Class: | Type:,Clearance: | + + Scenario Outline: Add meta-rule validations + When the user sets to add the following meta-rule + | metarulename | metaruledescription | subjectmetadata | actionmetadata | objectmetadata | + | | | | | | + Then the system should reply the following + | flag | + | | + Examples: + | metarulename | metaruledescription | subjectmetadata | actionmetadata | objectmetadata | flag | + | | Thisisabasicmetarule | Affiliation: | Action-Class: | Clearance: | False | + | metarule1 | | Affiliation: | Action-Class: | Clearance: | True | + | 1 | Thisisabasicmetarule | Affiliation: | Action-Class: | Clearance: | True | + | _%metarule%_ | Thisisabasicmetarule | Affiliation: | Action-Class: | Clearance: | True | + | metarule1 | Thisisabasicmetarule | | Action-Class: | Clearance: | True | + | metarule1 | Thisisabasicmetarule | 00000000000000000000000000000000000000000 | Action-Class: | Clearance: | False | + | metarule1 | Thisisabasicmetarule | 0000000000000000000000000000000000000000000000000000000000000000 | Action-Class: | Clearance: | False | + | metarule1 | Thisisabasicmetarule | 0000000000000000000000000000000000000000000000000000000000000000000000000 | Action-Class: | Clearance: | False | + | metarule1 | Thisisabasicmetarule | Affiliation:,,Authorization-Level: | Action-Class: | Clearance: | False | + | metarule1 | Thisisabasicmetarule | Affiliation: | | Clearance: | True | + | metarule1 | Thisisabasicmetarule | Affiliation: | 00000000000000000000000000000000000000000 | Clearance: | False | + | metarule1 | Thisisabasicmetarule | Affiliation: | 0000000000000000000000000000000000000000000000000000000000000000 | Clearance: | False | + | metarule1 | Thisisabasicmetarule | Affiliation: | 0000000000000000000000000000000000000000000000000000000000000000000000000 | Clearance: | False | + | metarule1 | Thisisabasicmetarule | Affiliation: | Action-Class:,,Action-Priority: | Clearance: | False | + | metarule1 | Thisisabasicmetarule | Affiliation: | Action-Class: | | True | + | metarule1 | Thisisabasicmetarule | Affiliation: | Action-Class: | 00000000000000000000000000000000000000000 | False | + | metarule1 | Thisisabasicmetarule | Affiliation: | Action-Class: | 0000000000000000000000000000000000000000000000000000000000000000 | False | + | metarule1 | Thisisabasicmetarule | Affiliation: | Action-Class: | 0000000000000000000000000000000000000000000000000000000000000000000000000 | False | + | metarule1 | Thisisabasicmetarule | Affiliation: | Action-Class: | Clearance:,,Type: | False | + + Scenario Outline: Add an existing meta-rule + Given the following meta rule exists + | metarulename | metaruledescription | subjectmetadata | actionmetadata | objectmetadata | + | metarule1 | Thisisabasicmetarule | Affiliation: | Action-Class: | Clearance: | + When the user sets to add the following meta-rule + | metarulename | metaruledescription | subjectmetadata | actionmetadata | objectmetadata | + | | | | | | + Then the system should reply the following + | flag | + | | + Examples: + | metarulename | metaruledescription | subjectmetadata | actionmetadata | objectmetadata | flag | + | metarule1 | Thisisabasicmetarule | Service | Action-Priority: | Service | False | + | metarule2 | Thisisabasicmetarule | Affiliation: | Action-Class: | Clearance: | False | + + Scenario: Update meta rules + Given the following meta rule exists + | metarulename | metaruledescription | subjectmetadata | actionmetadata | objectmetadata | + | metarule1 | Thisisabasicmetarule | Affiliation: | Action-Class: | Clearance: | + | metarule3 | Thisisabasicmetarule | Affiliation: | Action-Priority: | Clearance: | + When the user sets to update the following meta-rule + | metarulename | updatedmetarulename | updatedmetaruledescription | updatedsubjectmetadata | updatedactionmetadata | updatedobjectmetadata | + | metarule1 | 1-MR-% | Thisisabasicmetarule% | Affiliation:,Authorization-Level: | Action-Class:,Action-Priority: | Clearance:,Type: | + Then the following meta-rules should be existed in the system + | metarulename | metaruledescription | subjectmetadata | actionmetadata | objectmetadata | + | 1-MR-% | Thisisabasicmetarule% | Affiliation:,Authorization-Level: | Action-Class:,Action-Priority: | Clearance:,Type: | + | metarule3 | Thisisabasicmetarule | Affiliation: | Action-Priority: | Clearance: | + + Scenario Outline: Update meta rules validations + Given the following meta rule exists + | metarulename | metaruledescription | subjectmetadata | actionmetadata | objectmetadata | + | metarule1 | Thisisabasicmetarule | Affiliation: | Action-Class: | Clearance: | + | metarule3 | Thisisabasicmetarule | Authorization-Level: | Action-Priority: | Type: | + When the user sets to update the following meta-rule + | metarulename | updatedmetarulename | updatedmetaruledescription | updatedsubjectmetadata | updatedactionmetadata | updatedobjectmetadata | + | | | | | | | + Then the system should reply the following + | flag | + | | + Examples: + | metarulename | updatedmetarulename | updatedmetaruledescription | updatedsubjectmetadata | updatedactionmetadata | updatedobjectmetadata | flag | + | metarule1 | | Thisisabasicmetarule | Affiliation: | Action-Class: | Clearance: | False | + | metarule1 | metaruleX | | Affiliation: | Action-Class: | Clearance: | True | + | metarule1 | 1 | Thisisabasicmetarule | Affiliation: | Action-Class: | Clearance: | True | + | metarule1 | _%metarule%_ | Thisisabasicmetarule | Affiliation: | Action-Class: | Clearance: | True | +# | metarule1 | metarule1 | Thisisabasicmetarule | 0000000000000000000000 | Action-Class: | Clearance: | False | + | metarule1 | metarule1 | Thisisabasicmetarule | 0000000000000000000000000000000000000000000000000000000000000000 | Action-Class: | Clearance: | False | + | metarule1 | metarule1 | Thisisabasicmetarule | 0000000000000000000000000000000000000000000000000000000000000000000000000 | Action-Class: | Clearance: | False | + | metarule1 | metarule1 | Thisisabasicmetarule | Affiliation:,,Authorization-Level: | Action-Class: | Clearance: | False | +# | metarule1 | metarule1 | Thisisabasicmetarule | Affiliation: | 0000000000000000000000 | Clearance: | False | + | metarule1 | metarule1 | Thisisabasicmetarule | Affiliation: | 0000000000000000000000000000000000000000000000000000000000000000 | Clearance: | False | + | metarule1 | metarule1 | Thisisabasicmetarule | Affiliation: | 0000000000000000000000000000000000000000000000000000000000000000000000000 | Clearance: | False | + | metarule1 | metarule1 | Thisisabasicmetarule | Affiliation: | Action-Class:,,Action-Priority: | Clearance: | False | +# | metarule1 | metarule1 | Thisisabasicmetarule | Affiliation: | Action-Class: | 0000000000000000000000 | False | + | metarule1 | metarule1 | Thisisabasicmetarule | Affiliation: | Action-Class: | 0000000000000000000000000000000000000000000000000000000000000000 | False | + | metarule1 | metarule1 | Thisisabasicmetarule | Affiliation: | Action-Class: | 0000000000000000000000000000000000000000000000000000000000000000000000000 | False | + | metarule1 | metarule1 | Thisisabasicmetarule | Affiliation: | Action-Class: | Clearance:,,Type: | False | + | metarule1 | metarule1 | Thisisabasicmetarule | | Action-Class: | Clearance: | True | + | metarule1 | metarule1 | Thisisabasicmetarule | Affiliation: | | Clearance: | True | + | metarule1 | metarule1 | Thisisabasicmetarule | Affiliation: | Action-Class: | | True | + | metarule1 | metarule3 | Thisisabasicmetarule | Affiliation: | Action-Class: | Clearance: | False | + | metarule1 | metarule1 | Thisisabasicmetarule | Authorization-Level: | Action-Priority: | Type: | False | + + Scenario: Update a meta rule that has a recorded rule dependency + Given the following meta rule exists + | metarulename | metaruledescription | subjectmetadata | actionmetadata | objectmetadata | + | metarule1 | Thisisabasicmetarule | Affiliation: | Action-Class: | Clearance: | + And the following model exists + | modelname | modeldescription | metarule | + | universitymodel | Thisisabasicmodel | metarule1 | + And the following policy exists + | policyname | policydescription | modelname | genre | + | Stanford-Policy | Thisisabasicpolicy | universitymodel | Education | + And the following subject perimeter exists + | subjectperimetername | subjectperimeterdescription | subjectperimeteremail | subjectperimeterpassword | policies | + | JohnLewis | Thisistheexpecteduser | jlewis@orange.com | abc1234 | Stanford-Policy | + And the following object perimeter exists + | objectperimetername | objectperimeterdescription | policies | + | ProfessorsPromotionDocument | Thisistherequesttoaccessfile | Stanford-Policy | + And the following action perimeter exists + | actionperimetername | actionperimeterdescription | policies | + | Read | Thisistheactionrequired | Stanford-Policy | + And the following subject data exists + | policyname | subjectcategory | subjectdataname | subjectdatadescription | + | Stanford-Policy | Affiliation: | University-of-Stanford | This data has the value of subject category | + And the following object data exists + | policyname | objectcategory | objectdataname | objectdatadescription | + | Stanford-Policy | Clearance: | Top-Secret | This data has the value of object category | + And the following action data exists + | policyname | actioncategory | actiondataname | actiondatadescription | + | Stanford-Policy | Action-Class: | Severe | This data has the value of action category | + And the following subject assignment exists + | subjectperimetername | subjectcategory | subjectdata | policyname | + | JohnLewis | Affiliation: | University-of-Stanford | Stanford-Policy | + And the following object assignment exists + | objectperimetername | objectcategory | objectdata | policyname | + | ProfessorsPromotionDocument | Clearance: | Top-Secret | Stanford-Policy | + And the following action assignment exists + | actionperimetername | actioncategory | actiondata | policyname | + | Read | Action-Class: | Severe | Stanford-Policy | + And the following rule exists + | rule | metarulename | instructions | policyname | + | University-of-Stanford,Top-Secret,Severe | metarule1 | grant | Stanford-Policy | + When the user sets to update the following meta-rule + | metarulename | updatedmetarulename | updatedmetaruledescription | updatedsubjectmetadata | updatedactionmetadata | updatedobjectmetadata | + | metarule1 | metarule1 | Thisisabasicmetarule | Authorization-Level: | Action-Priority: | Type: | + Then the system should reply the following + | flag | + | False | + And the following meta-rules should be existed in the system + | metarulename | metaruledescription | subjectmetadata | actionmetadata | objectmetadata | + | metarule1 | Thisisabasicmetarule | Affiliation: | Action-Class: | Clearance: | + + + Scenario: Delete meta rules + Given the following meta rule exists + | metarulename | metaruledescription | subjectmetadata | actionmetadata | objectmetadata | + | metarule1 | Thisisabasicmetarule | Affiliation: | Action-Class: | Clearance: | + When the user sets to delete the following meta-rule + | metarulename | + | metarule1 | + Then the following meta-rules should be existed in the system + | metarulename | metaruledescription | subjectmetadata | actionmetadata | objectmetadata | + | | | | | | + + Scenario: Delete meta rules that has a recorded model dependency + Given the following meta rule exists + | metarulename | metaruledescription | subjectmetadata | actionmetadata | objectmetadata | + | metarule1 | Thisisabasicmetarule | Affiliation: | Action-Class: | Clearance: | + And the following model exists + | modelname | modeldescription | metarule | + | generalmodel | Thisisabasicmodel | metarule1 | + When the user sets to delete the following meta-rule + | metarulename | + | metarule1 | + Then the system should reply the following + | flag | + | False | + And the following meta-rules should be existed in the system + | metarulename | metaruledescription | subjectmetadata | actionmetadata | objectmetadata | + | metarule1 | Thisisabasicmetarule | Affiliation: | Action-Class: | Clearance: | + + Scenario: Delete meta rules after deleting the recorded model dependency + Given the following meta rule exists + | metarulename | metaruledescription | subjectmetadata | actionmetadata | objectmetadata | + | metarule1 | Thisisabasicmetarule | Affiliation: | Action-Class: | Clearance: | + And the following model exists + | modelname | modeldescription | metarule | + | generalmodel | Thisisabasicmodel | metarule1 | + When the user sets to delete the following model + | modelname | + | generalmodel | + And the user sets to delete the following meta-rule + | metarulename | + | metarule1 | + Then the following meta-rules should be existed in the system + | metarulename | metaruledescription | subjectmetadata | actionmetadata | objectmetadata | + | | | | | | \ No newline at end of file diff --git a/moon_manager/tests/func_tests/features/model.feature b/moon_manager/tests/func_tests/features/model.feature new file mode 100644 index 00000000..1f6399ab --- /dev/null +++ b/moon_manager/tests/func_tests/features/model.feature @@ -0,0 +1,176 @@ +Feature: Model + + Background: + Given the system has no rules + And the system has no subject assignments + And the system has no action assignments + And the system has no object assignments + And the system has no subject data + And the system has no action data + And the system has no object data + And the system has no subject perimeter + And the system has no object perimeter + And the system has no action perimeter + And the system has no pdps + And the system has no policies + And the system has no models + And the system has no meta-rules + And the system has no subject categories + And the system has no action categories + And the system has no object categories + And the following meta data subject category exists + | subjectmetadataname | subjectmetadatadescription | + | Affiliation: | This meta data has the categorical information about a subject | + | Authorization-Level: | This meta data has the categorical information about an object | + | Degree: | This meta data has the categorical information about an object | + And the following meta data object category exists + | objectmetadataname | objectmetadatadescription | + | Clearance: | This meta data has the categorical information about an object | + | Type: | This meta data has the categorical information about an object | + | Class: | This meta data has the categorical information about an object | + And the following meta data action category exists + | actionmetadataname | actionmetadatadescription | + | Action-Class: | This meta data has the categorical information about an action | + | Action-Priority: | This meta data has the categorical information about an action | + | Recommendation: | This meta data has the categorical information about an action | + And the following meta rule exists + | metarulename | metaruledescription | subjectmetadata | actionmetadata | objectmetadata | + | metarule1 | This is a basic metarule | Affiliation: | Action-Class: | Clearance: | + | metarule2 | This is a basic metarule | Authorization-Level: | Action-Class: | Clearance: | + | metarule3 | This is a basic metarule | Affiliation: | Action-Priority: | Clearance: | + | metarule4 | This is a basic metarule | Authorization-Level: | Action-Priority: | Clearance: | + | metarule5 | This is a basic metarule | Affiliation: | Action-Class: | Type: | + | metarule6 | This is a basic metarule | Authorization-Level: | Action-Class: | Type: | + | metarule7 | This is a basic metarule | Affiliation: | Action-Priority: | Type: | + | metarule8 | This is a basic metarule | Affiliation:,Authorization-Level: | Action-Class:,Action-Priority: | Clearance:,Type: | + | metarule9 | This is a basic metarule | | Action-Class:,Action-Priority: | Clearance:,Type: | + | metarule10 | This is a basic metarule | Affiliation:,Authorization-Level: | | Clearance:,Type: | + | metarule11 | This is a basic metarule | Affiliation:,Authorization-Level: | Action-Class:,Action-Priority: | | + + + Scenario: Add model + When the user sets to add the following model + | modelname | modeldescription | metarule | + | A-model | Thisisabasicmodel | metarule1,metarule2,metarule6 | + | B-model | Thisisabasicmodel | metarule3,metarule4,metarule5 | + Then the following model should be existed in the system + | modelname | modeldescription | metarule | + | A-model | Thisisabasicmodel | metarule1,metarule2,metarule6 | + | B-model | Thisisabasicmodel | metarule3,metarule4,metarule5 | + + Scenario Outline: Add model validations + When the user sets to add the following model + | modelname | modeldescription | metarule | + | | | | + Then the system should reply the following + | flag | + | | + Examples: + | modelname | modeldescription | metarule | flag | + | | This model is for creating policy prototype | metarule8,metarule3 | False | + | generalmodel | | metarule8 | True | + | 1 | This model is for creating policy prototype% | metarule8 | True | + | _%model%_ | This model is for creating policy prototype1 | metarule8 | True | + | generalmodel | This model is for creating policy prototype | | True | + | generalmodel | This model is for creating policy prototype | metarule9 | True | + | generalmodel | This model is for creating policy prototype | metarule10 | True | + | generalmodel | This model is for creating policy prototype | metarule11 | True | + | generalmodel | This model is for creating policy prototype | metarule20 | False | + | generalmodel | This model is for creating policy prototype | metarule3,,metarule20 | False | + | generalmodel | This model is for creating policy prototype | 000000000000000000000 | False | + | generalmodel | This model is for creating policy prototype | 0000000000000000000000000000000000000000000000000000000000000000000 | False | + | generalmodel | This model is for creating policy prototype | 00000000000000000000000000000000000000000000000000000000000000000000000 | False | + | generalmodel | This model is for creating policy prototype | metarule8,metarule10 | True | + +Scenario Outline: Add an existing model + Given the following model exists + | modelname | modeldescription | metarule | + | generalmodel | This is a basic model | metarule1,metarule2,metarule6 | + When the user sets to add the following model + | modelname | modeldescription | metarule | + | | | | + Then the system should reply the following + | flag | + | | + Examples: + | modelname | modeldescription | metarule | flag | + | generalmodel | Thisisabasicmodel | metarule1,metarule3,metarule5 | False | + | generalmodel1 | Thisisabasicmodel | metarule1,metarule2,metarule6 | False | + + Scenario: Update model + Given the following model exists + | modelname | modeldescription | metarule | + | generalmodel | Thisisabasicmodel | metarule1,metarule2,metarule6 | + When the user sets to update the following model + | modelname | updatedmodelname | updatedmodeldescription | updatedmetarule | + | generalmodel | 1-M-% | This model is for creating policy prototype | metarule3,metarule5,metarule7 | + Then the following model should be existed in the system + | modelname | modeldescription | metarule | + | 1-M-% | This model is for creating policy prototype | metarule3,metarule5,metarule7 | + + Scenario Outline: Update model validations + Given the following model exists + | modelname | modeldescription | metarule | + | generalmodel | This model is for creating policy prototype | metarule1,metarule2,metarule6 | + When the user sets to update the following model + | modelname | updatedmodelname | updatedmodeldescription | updatedmetarule | + | | | | | + Then the system should reply the following + | flag | + | | + Examples: + | modelname | updatedmodelname | updatedmodeldescription | updatedmetarule | flag | + | generalmodel | | This model is for creating policy prototype | metarule8,metarule3 | False | + | generalmodel | generalmodel | | metarule8 | True | + | generalmodel | 1 | This model is for creating policy prototype% | metarule8 | True | + | generalmodel | _%model%_ | This model is for creating policy prototype1 | metarule8 | True | + | generalmodel | generalmodel | This model is for creating policy prototype | | True | + | generalmodel | generalmodel | This model is for creating policy prototype | metarule9 | True | + | generalmodel | generalmodel | This model is for creating policy prototype | metarule10 | True | + | generalmodel | generalmodel | This model is for creating policy prototype | metarule11 | True | + | generalmodel | generalmodel | This model is for creating policy prototype | metarule3, | False | + | generalmodel | generalmodel | This model is for creating policy prototype | 0000000000000000000000000000000000000000000000000000000000000000000 | False | + | generalmodel | generalmodel | This model is for creating policy prototype | 00000000000000000000000000000000000000000000000000000000000000000000000 | False | + | generalmodel | generalmodel | This model is for creating policy prototype | metarule8,metarule10 | True | + + Scenario: Delete a model + Given the following model exists + | modelname | modeldescription | metarule | + | generalmodel | This model is for creating policy prototype | metarule1 | + When the user sets to delete the following model + | modelname | + | generalmodel | + Then the following model should be existed in the system + | modelname | modeldescription | metarule | + | | | | + + Scenario: Delete a model that has a recorded policy dependency + Given the following model exists + | modelname | modeldescription | metarule | + | generalmodel | This model is for creating policy prototype | metarule1 | + And the following policy exists + | policyname | policydescription | modelname | genre | + | generalpolicy | This is a basic policy | generalmodel | financial | + When the user sets to delete the following model + | modelname | + | generalmodel | + Then the following model should be existed in the system + | modelname | modeldescription | metarule | + | generalmodel | This model is for creating policy prototype | metarule1 | + + Scenario: Delete a model after deleting the recorded policy dependency + Given the following model exists + | modelname | modeldescription | metarule | + | generalmodel | This model is for creating policy prototype | metarule1 | + And the following policy exists + | policyname | policydescription | modelname | genre | + | generalpolicy | This is a basic policy | generalmodel | financial | + When the user sets to delete the following policy + | policyname | + | generalpolicy | + And the user sets to delete the following model + | modelname | + | generalmodel | + Then the following model should be existed in the system + | modelname | modeldescription | metarule | + | | | | diff --git a/moon_manager/tests/func_tests/features/partner.feature b/moon_manager/tests/func_tests/features/partner.feature new file mode 100644 index 00000000..ebce3393 --- /dev/null +++ b/moon_manager/tests/func_tests/features/partner.feature @@ -0,0 +1,7 @@ +Feature: Partner + + Scenario: Add Partner + + Scenario: Update Partner + + Scenario: Delete Partner \ No newline at end of file diff --git a/moon_manager/tests/func_tests/features/pdp.feature b/moon_manager/tests/func_tests/features/pdp.feature new file mode 100644 index 00000000..0ba73bac --- /dev/null +++ b/moon_manager/tests/func_tests/features/pdp.feature @@ -0,0 +1,141 @@ +Feature: PDP + + Background: + + Given the system has no rules + And the system has no subject assignments + And the system has no action assignments + And the system has no object assignments + And the system has no subject data + And the system has no action data + And the system has no object data + And the system has no subject perimeter + And the system has no object perimeter + And the system has no action perimeter + And the system has no pdps + And the system has no policies + And the system has no models + And the system has no meta-rules + And the system has no subject categories + And the system has no action categories + And the system has no object categories + And the following meta data subject category exists + | subjectmetadataname | subjectmetadatadescription | + | Affiliation: | This meta data has the categorical information about a subject | + | Authorization-Level: | This meta data has the categorical information about an object | + And the following meta data object category exists + | objectmetadataname | objectmetadatadescription | + | Clearance: | This meta data has the categorical information about an object | + | Type: | This meta data has the categorical information about an object | + And the following meta data action category exists + | actionmetadataname | actionmetadatadescription | + | Action-Class: | This meta data has the categorical information about an action | + | Action-Priority: | This meta data has the categorical information about an action | + And the following meta rule exists + | metarulename | metaruledescription | subjectmetadata | actionmetadata | objectmetadata | + | metarule1 | Thisisabasicmetarule | Affiliation: | Action-Class: | Clearance: | + | metarule2 | Thisisabasicmetarule | Authorization-Level: | Action-Class: | Clearance: | + | metarule3 | Thisisabasicmetarule | Affiliation: | Action-Priority: | Clearance: | + | metarule4 | Thisisabasicmetarule | Authorization-Level: | Action-Priority: | Clearance: | + | metarule5 | Thisisabasicmetarule | Affiliation: | Action-Class: | Type: | + | metarule6 | Thisisabasicmetarule | Authorization-Level: | Action-Class: | Type: | + | metarule7 | Thisisabasicmetarule | Affiliation: | Action-Priority: | Type: | + | metarule8 | Thisisabasicmetarule | Affiliation:,Authorization-Level: | Action-Class:,Action-Priority: | Clearance:,Type: | + And the following model exists + | modelname | modeldescription | metarule | + | generalmodel | Thisisabasicmodel | metarule1,metarule2,metarule6 | + | generalmodel2 | Thisisabasicmodel | metarule3,metarule5,metarule8 | + And the following policy exists + | policyname | policydescription | modelname | genre | + | Policy A | Thisisabasicpolicy | generalmodel | financial | + | Policy B | Thisisabasicpolicy | generalmodel2 | financial | + | Policy C | Thisisabasicpolicy | generalmodel2 | financial | + + + Scenario: Add PDP + When the user sets to add the following pdp + | pdpname | pdpdescription | keystone_project_id | security_pipeline | + | A-pdp | Thisisabasicpolicy | 0000000000000000000000000000000000000000000000000000000000000000 | Policy A | + | B-pdp | Thisisabasicpolicy | 1111111111111111111111111111111111111111111111111111111111111111 | Policy C | + + Then the following pdp should be existed in the system + | pdpname | pdpdescription | keystone_project_id | security_pipeline | + | A-pdp | Thisisabasicpolicy | 0000000000000000000000000000000000000000000000000000000000000000 | Policy A | + | B-pdp | Thisisabasicpolicy | 1111111111111111111111111111111111111111111111111111111111111111 | Policy C | + + Scenario Outline: Add PDP validations + When the user sets to add the following pdp + | pdpname | pdpdescription | keystone_project_id | security_pipeline | + | | | | | + Then the system should reply the following + | flag | + | | + Examples: + | pdpname | pdpdescription | keystone_project_id | security_pipeline | flag | + | | This pdp is for creating a collection of policies | 0000000000000000000000000000000000000000000000000000000000000000 | Policy A | False | + | generalpdp | | 0000000000000000000000000000000000000000000000000000000000000000 | Policy A | True | + | 1 P | This pdp is for creating a collection of policies | 0000000000000000000000000000000000000000000000000000000000000000 | Policy A | True | + | _%Pdp%_ | This pdp is for creating a collection of policies% | 0000000000000000000000000000000000000000000000000000000000000000 | Policy A | True | + | generalpdp | This pdp is for creating a collection of policies% | | Policy A | False | + | generalpdp | This pdp is for creating a collection of policies | 0000000000000000000000000000000000000000000000000000000000000000 | | False | + | generalpdp | This pdp is for creating a collection of policies | 0000000000000000000000000000000000000000000000000000000000000000 | Policy A, | False | + + Scenario Outline: Add an existing PDP + Given the following pdp exists + | pdpname | pdpdescription | keystone_project_id | security_pipeline | + | A-pdp | Thisisabasicpolicy | 0000000000000000000000000000000000000000000000000000000000000000 | Policy C | + When the user sets to add the following pdp + | pdpname | pdpdescription | keystone_project_id | security_pipeline | + | | | | | + Then the system should reply the following + | flag | + | | + Examples: + | pdpname | pdpdescription | keystone_project_id | security_pipeline | flag | + | B-pdp | Thisisabasicpolicy | 0000000000000000000000000000000000000000000000000000000000000000 | Policy C | False | + | A-pdp | Thisisabasicpolicy | 3333333333333333333333333333333333333333333333333333333333333333 | Policy A | False | + + Scenario: Update PDP + Given the following pdp exists + | pdpname | pdpdescription | keystone_project_id | security_pipeline | + | A-pdp | Thisisabasicpolicy | 0000000000000000000000000000000000000000000000000000000000000000 | Policy A | + When the user sets to update the following pdp + | pdpname | updatedpdpname | updatedpdpdescription | updatedkeystone_project_id | updatedsecurity_pipeline | + | A-pdp | B-pdp | Thisisabasicpolicy | 111111111111111111111111111111111111111111111111111111111 | Policy B | + Then the following pdp should be existed in the system + | pdpname | pdpdescription | keystone_project_id | security_pipeline | + | B-pdp | Thisisabasicpolicy | 111111111111111111111111111111111111111111111111111111111 | Policy B | + + Scenario Outline: Update PDP validations + Given the following pdp exists + | pdpname | pdpdescription | keystone_project_id | security_pipeline | + | A-pdp | Thisisabasicpolicy | 0000000000000000000000000000000000000000000000000000000000000000 | Policy B | + | B-pdp | Thisisabasicpolicy | 2222222222222222222222222222222222222222222222222222222222222222 | Policy C | + When the user sets to update the following pdp + | pdpname | updatedpdpname | updatedpdpdescription | updatedkeystone_project_id | updatedsecurity_pipeline | + | | | | | | + Then the system should reply the following + | flag | + | | + Examples: + | pdpname | updatedpdpname | updatedpdpdescription | updatedkeystone_project_id | updatedsecurity_pipeline | flag | + | A-pdp | | Thispdpisforcreatingacollectionofpolicies | 111111111111111111111111111111111111111111111111111111111 | Policy A | False | + | A-pdp | generalpdp | | 111111111111111111111111111111111111111111111111111111111 | Policy A | True | + | A-pdp | 1 P | Thispdpisforcreatingacollectionofpolicies | 111111111111111111111111111111111111111111111111111111111 | Policy A | True | + | A-pdp | _%Pdp%_ | Thispdpisforcreatingacollectionofpolicies% | 111111111111111111111111111111111111111111111111111111111 | Policy A | True | + | A-pdp | generalpdp | Thispdpisforcreatingacollectionofpolicies% | | Policy A | False | + | A-pdp | generalpdp | Thispdpisforcreatingacollectionofpolicies | 111111111111111111111111111111111111111111111111111111111 | | False | + | A-pdp | generalpdp | Thispdpisforcreatingacollectionofpolicies | 111111111111111111111111111111111111111111111111111111111 | Policy A, | False | + | A-pdp | A-pdp | Thisisabasicpolicy | 0000000000000000000000000000000000000000000000000000000000000000 | Policy B | True | + | A-pdp | B-pdp | Thisisabasicpolicy | 111111111111111111111111111111111111111111111111111111111 | Policy C | False | + + Scenario: Delete PDP + Given the following pdp exists + | pdpname | pdpdescription | keystone_project_id | security_pipeline | + | A-pdp | Thisisabasicpolicy | 0000000000000000000000000000000000000000000000000000000000000000 | Policy A | + When the user sets to delete the following pdp + | pdpname | + | A-pdp | + Then the following pdp should be existed in the system + | pdpname | pdpdescription | keystone_project_id | security_pipeline | + | | | | | diff --git a/moon_manager/tests/func_tests/features/perimeter.feature b/moon_manager/tests/func_tests/features/perimeter.feature new file mode 100644 index 00000000..39820e15 --- /dev/null +++ b/moon_manager/tests/func_tests/features/perimeter.feature @@ -0,0 +1,465 @@ +Feature: Perimeter + + Background: + Given the system has no rules + And the system has no subject assignments + And the system has no action assignments + And the system has no object assignments + And the system has no subject data + And the system has no action data + And the system has no object data + And the system has no subject perimeter + And the system has no object perimeter + And the system has no action perimeter + And the system has no pdps + And the system has no policies + And the system has no models + And the system has no meta-rules + And the system has no subject categories + And the system has no action categories + And the system has no object categories + And the following meta data subject category exists + | subjectmetadataname | subjectmetadatadescription | + | Affiliation: | This meta data has the categorical information about a subject | + | Authorization-Level: | This meta data has the categorical information about an object | + | Degree: | This meta data has the categorical information about an object | + And the following meta data object category exists + | objectmetadataname | objectmetadatadescription | + | Clearance: | This meta data has the categorical information about an object | + | Type: | This meta data has the categorical information about an object | + | Class: | This meta data has the categorical information about an object | + And the following meta data action category exists + | actionmetadataname | actionmetadatadescription | + | Action-Class: | This meta data has the categorical information about an action | + | Action-Priority: | This meta data has the categorical information about an action | + | Recommendation: | This meta data has the categorical information about an action | + And the following meta rule exists + | metarulename | metaruledescription | subjectmetadata | actionmetadata | objectmetadata | + | metarule1 | Thisisabasicmetarule | Affiliation: | Action-Class: | Clearance: | + | metarule2 | Thisisabasicmetarule | Authorization-Level: | Action-Class: | Clearance: | + | metarule3 | Thisisabasicmetarule | Affiliation: | Action-Priority: | Clearance: | + | metarule4 | Thisisabasicmetarule | Authorization-Level: | Action-Priority: | Clearance: | + | metarule5 | Thisisabasicmetarule | Affiliation: | Action-Class: | Type: | + | metarule6 | Thisisabasicmetarule | Authorization-Level: | Action-Class: | Type: | + | metarule7 | Thisisabasicmetarule | Affiliation: | Action-Priority: | Type: | + | metarule8 | Thisisabasicmetarule | Authorization-Level: | Action-Priority: | Type: | + | metarule9 | Thisisabasicmetarule | Affiliation:,Authorization-Level: | Action-Class:,Action-Priority: | Clearance:,Type: | + And the following model exists + | modelname | modeldescription | metarule | + | universitymodel | Thisisabasicmodel | metarule1,metarule9 | + | universitymodel2 | Thisisabasicmodel | metarule3,metarule5,metarule8 | + | universitymodel3 | Thisisabasicmodel | metarule9 | + And the following policy exists + | policyname | policydescription | modelname | genre | + | Stanford Policy | This is a basic policy | universitymodel | Education | + | Cambridge Policy | This is a basic policy | universitymodel2 | Education | + + + Scenario: Add subject perimeter + When the user sets to add the following subject perimeter + | subjectperimetername | subjectperimeterdescription | subjectperimeteremail | subjectperimeterpassword | policies | + | JohnLewis | Thisistheexpecteduser | jlewis@orange.com | abc1234 | Stanford Policy | + | JohnLewis | Thisistheexpecteduser | jlewis@orange.com | abc1234 | Cambridge Policy | + Then the following subject perimeter should be existed in the system + | subjectperimetername | subjectperimeterdescription | subjectperimeteremail | subjectperimeterpassword | policies | + | JohnLewis | Thisistheexpecteduser | jlewis@orange.com | abc1234 | Cambridge Policy,Stanford Policy | + + Scenario Outline: Add subject perimeter validations + When the user sets to add the following subject perimeter + | subjectperimetername | subjectperimeterdescription | subjectperimeteremail | subjectperimeterpassword | policies | + | | | | | | + Then the system should reply the following + | flag | + | | + Examples: + | subjectperimetername | subjectperimeterdescription | subjectperimeteremail | subjectperimeterpassword | policies | flag | + | | Thisistheexpecteduser | jlewis@orange.com | abc1234 | Stanford Policy | False | + | _%JohnLewis%_ | Thisistheexpecteduser | jlewis@orange.com | abc1234 | Stanford Policy | True | + | JohnLewis | | jlewis@orange.com | abc1234 | Stanford Policy | True | + | JohnLewis | Thisistheexpecteduser% | jlewis@orange.com | abc1234 | Stanford Policy | True | + | JohnLewis | Thisistheexpecteduser% | jlewis@orange.com | abc1234 | | True | + + Scenario Outline: Add an existing subject perimeter + Given the following subject perimeter exists + | subjectperimetername | subjectperimeterdescription | subjectperimeteremail | subjectperimeterpassword | policies | + | JohnLewis | Thisistheexpecteduser | jlewis@orange.com | abc1234 | Stanford Policy | + When the user sets to add the following subject perimeter + | subjectperimetername | subjectperimeterdescription | subjectperimeteremail | subjectperimeterpassword | policies | + | | | | | | + Then the system should reply the following + | flag | + | | + Examples: + | subjectperimetername | subjectperimeterdescription | subjectperimeteremail | subjectperimeterpassword | policies | flag | + | JohnLewis | Thisistheexpecteduser | jlewis@orange.com | abc1234 | Stanford Policy | False | + | JohnLewis | Thisistheexpecteduser | jlewis@orange.com | abc1234 | Cambridge Policy | True | + + Scenario: Update subject perimeter + Given the following subject perimeter exists + | subjectperimetername | subjectperimeterdescription | subjectperimeteremail | subjectperimeterpassword | policies | + | JohnLewis | Thisistheexpecteduser | jlewis@orange.com | abc1234 | Stanford Policy | + | JohnLewis | Thisistheexpecteduser | jlewis@orange.com | abc1234 | Cambridge Policy | + When the user sets to update the following subject perimeter + | subjectperimetername | updatedsubjectperimetername | updatedsubjectperimeterdescription | updatedsubjectperimeteremail | updatedsubjectperimeterpassword | policies | + | JohnLewis | JoesephWilliams | Thisdatahasthevalueofsubjectperimeter | jwilliams@orange.com | abc1234 | Stanford Policy | + Then the following subject perimeter should be existed in the system + | subjectperimetername | subjectperimeterdescription | subjectperimeteremail | subjectperimeterpassword | policies | + | JoesephWilliams | Thisdatahasthevalueofsubjectperimeter | jwilliams@orange.com | abc1234 | Cambridge Policy,Stanford Policy | + + Scenario Outline: Update subject perimeter validations + Given the following subject perimeter exists + | subjectperimetername | subjectperimeterdescription | subjectperimeteremail | subjectperimeterpassword | policies | + | JohnLewis | Thisistheexpecteduser | jlewis@orange.com | abc1234 | Stanford Policy | + When the user sets to update the following subject perimeter + | subjectperimetername | updatedsubjectperimetername | updatedsubjectperimeterdescription | updatedsubjectperimeteremail | updatedsubjectperimeterpassword | policies | + | | | | | | | + Then the system should reply the following + | flag | + | | + Examples: + | subjectperimetername | updatedsubjectperimetername | updatedsubjectperimeterdescription | updatedsubjectperimeteremail | updatedsubjectperimeterpassword | policies | flag | + #| JohnLewis | | Thisistheexpecteduser | jlewis@orange.com | abc1234 | Stanford Policy | False | + | JohnLewis | _%JohnLewis%_ | Thisistheexpecteduser | jlewis@orange.com | abc1234 | Stanford Policy | True | + #| JohnLewis | JohnLewis | | jlewis@orange.com | abc1234 | Stanford Policy | True | + #| JohnLewis | JohnLewis | Thisistheexpecteduser% | jlewis@orange.com | abc1234 | Stanford Policy | True | + +Scenario: Delete subject perimeter with a policy and no assignments + Given the following subject perimeter exists + | subjectperimetername | subjectperimeterdescription | subjectperimeteremail | subjectperimeterpassword | policies | + | JohnLewis | Thisistheexpecteduser | jlewis@orange.com | abc1234 | Stanford Policy | + When the user sets to delete the following subject perimeter + | subjectperimetername | + | JohnLewis | + Then the system should reply the following + | flag | + | False | + And the following subject perimeter should be existed in the system + | subjectperimetername | subjectperimeterdescription | subjectperimeteremail | subjectperimeterpassword | policies | + | JohnLewis | Thisistheexpecteduser | jlewis@orange.com | abc1234 | Stanford Policy | + + Scenario: Check subject perimeter after removing the policy + Given the following subject perimeter exists + | subjectperimetername | subjectperimeterdescription | subjectperimeteremail | subjectperimeterpassword | policies | + | JohnLewis | Thisistheexpecteduser | jlewis@orange.com | abc1234 | Stanford Policy | + When the user sets to delete the following subject perimeter for a given policy + | subjectperimetername | policies | + | JohnLewis | Stanford Policy | + Then the following subject perimeter should be existed in the system + | subjectperimetername | subjectperimeterdescription | subjectperimeteremail | subjectperimeterpassword | policies | + | JohnLewis | Thisistheexpecteduser | jlewis@orange.com | abc1234 | | + +Scenario: Delete subject perimeter with no policy + Given the following subject perimeter exists + | subjectperimetername | subjectperimeterdescription | subjectperimeteremail | subjectperimeterpassword | policies | + | JohnLewis | Thisistheexpecteduser | jlewis@orange.com | abc1234 | Stanford Policy | + When the user sets to delete the following subject perimeter for a given policy + | subjectperimetername | policies | + | JohnLewis | Stanford Policy | + And the user sets to delete the following subject perimeter + | subjectperimetername | + | JohnLewis | + Then the following subject perimeter should be existed in the system + | subjectperimetername | subjectperimeterdescription | subjectperimeteremail | subjectperimeterpassword | policies | + | | | | | | + + Scenario: Delete subject perimeter with a policy and with assignments + Given the following subject perimeter exists + | subjectperimetername | subjectperimeterdescription | subjectperimeteremail | subjectperimeterpassword | policies | + | JohnLewis | Thisistheexpecteduser | jlewis@orange.com | abc1234 | Stanford Policy | + And the following subject data exists + | policyname | subjectcategory | subjectdataname | subjectdatadescription | + | Stanford Policy | Affiliation: | University-of-Stanford | This data has the value of subject category | + | Stanford Policy | Affiliation: | Stanford | This data has the value of subject category | + And the following subject assignment exists + | subjectperimetername | subjectcategory | subjectdata | policyname | + | JohnLewis | Affiliation: | University-of-Stanford | Stanford Policy | + | JohnLewis | Affiliation: | Stanford | Stanford Policy | + When the user sets to delete the following subject perimeter for a given policy + | subjectperimetername | policies | + | JohnLewis | Stanford Policy | + Then the system should reply the following + | flag | + | True | + And the following subject perimeter should be existed in the system + | subjectperimetername | subjectperimeterdescription | subjectperimeteremail | subjectperimeterpassword | policies | + | JohnLewis | Thisistheexpecteduser | jlewis@orange.com | abc1234 | | + And the following subject assignment should be existed in the system + | subjectperimetername | subjectcategory | subjectdata | policyname | + | | | | Stanford Policy | + + Scenario: Add object perimeter + When the user sets to add the following object perimeter + | objectperimetername | objectperimeterdescription | policies | + | ProfessorsPromotionDocument | Thisistherequesttoaccessfile | Stanford Policy | + | ProfessorsPromotionDocument | Thisistherequesttoaccessfile | Cambridge Policy | + + Then the following object perimeter should be existed in the system + | objectperimetername | objectperimeterdescription | policies | + | ProfessorsPromotionDocument | Thisistherequesttoaccessfile | Cambridge Policy,Stanford Policy | + + Scenario Outline: Add object perimeter validations + When the user sets to add the following object perimeter + | objectperimetername | objectperimeterdescription | policies | + | | | | + Then the system should reply the following + | flag | + | | + Examples: + | objectperimetername | objectperimeterdescription | policies | flag | + | | Thisistherequesttoaccessfile | Stanford Policy | False | + | _%ProfessorsPromotionDocument%_ | Thisistherequesttoaccessfile | Stanford Policy | True | + | ProfessorsPromotionDocument | | Stanford Policy | True | + | ProfessorsPromotionDocument | Thisistherequesttoaccessfile% | Stanford Policy | True | + | ProfessorsPromotionDocument | Thisistherequesttoaccessfile% | | True | + + + Scenario Outline: Add an existing object perimeter + Given the following object perimeter exists + | objectperimetername | objectperimeterdescription | policies | + | ProfessorsPromotionDocument | Thisistherequesttoaccessfile | Stanford Policy | + When the user sets to add the following object perimeter + | objectperimetername | objectperimeterdescription | policies | + | | | | + Then the system should reply the following + | flag | + | | + Examples: + | objectperimetername | objectperimeterdescription | policies | flag | + | ProfessorsPromotionDocument | Thisistherequesttoaccessfile | Stanford Policy | False | + | ProfessorsPromotionDocument | Thisistherequesttoaccessfile | Cambridge Policy | True | + + Scenario: Update object perimeter + Given the following object perimeter exists + | objectperimetername | objectperimeterdescription | policies | + | ProfessorsPromotionDocument | Thisistherequesttoaccessfile | Stanford Policy | + | ProfessorsPromotionDocument | Thisistherequesttoaccessfile | Cambridge Policy | + When the user sets to update the following object perimeter + | objectperimetername | updatedobjectperimetername | updatedobjectperimeterdescription | policies | + | ProfessorsPromotionDocument | StudentsGradsSheet | Thisistherequesttoaccessfile | Stanford Policy | + Then the following object perimeter should be existed in the system + | objectperimetername | objectperimeterdescription | policies | + | StudentsGradsSheet | Thisistherequesttoaccessfile | Cambridge Policy,Stanford Policy | + + Scenario Outline: Update object perimeter validations + Given the following object perimeter exists + | objectperimetername | objectperimeterdescription | policies | + | ProfessorsPromotionDocument | Thisistherequesttoaccessfile | Stanford Policy | + When the user sets to update the following object perimeter + | objectperimetername | updatedobjectperimetername | updatedobjectperimeterdescription | policies | + | | | | | + Then the system should reply the following + | flag | + | | + Examples: + | objectperimetername | updatedobjectperimetername | updatedobjectperimeterdescription | policies | flag | + | ProfessorsPromotionDocument | | Thisistherequesttoaccessfile | Stanford Policy | False | + | ProfessorsPromotionDocument | _%ProfessorsPromotionDocument%_ | Thisistherequesttoaccessfile | Stanford Policy | True | + | ProfessorsPromotionDocument | ProfessorsPromotionDocument | | Stanford Policy | True | + | ProfessorsPromotionDocument | ProfessorsPromotionDocument | Thisistherequesttoaccessfile% | Stanford Policy | True | + + Scenario: Delete object perimeter with a policy + Given the following object perimeter exists + | objectperimetername | objectperimeterdescription | policies | + | ProfessorsPromotionDocument | Thisistherequesttoaccessfile | Stanford Policy | + When the user sets to delete the following object perimeter + | objectperimetername | + | ProfessorsPromotionDocument | + Then the system should reply the following + | flag | + | False | + And the following object perimeter should be existed in the system + | objectperimetername | objectperimeterdescription | policies | + | ProfessorsPromotionDocument | Thisistherequesttoaccessfile | Stanford Policy | + + Scenario: Check object perimeter after removing the policy + Given the following object perimeter exists + | objectperimetername | objectperimeterdescription | policies | + | ProfessorsPromotionDocument | Thisistherequesttoaccessfile | Stanford Policy | + When the user sets to delete the following object perimeter for a given policy + | objectperimetername | policies | + | ProfessorsPromotionDocument | Stanford Policy | + Then the following object perimeter should be existed in the system + | objectperimetername | objectperimeterdescription | policies | + | ProfessorsPromotionDocument | Thisistherequesttoaccessfile | | + + Scenario: Delete object perimeter after removing the policy + Given the following object perimeter exists + | objectperimetername | objectperimeterdescription | policies | + | ProfessorsPromotionDocument | Thisistherequesttoaccessfile | Stanford Policy | + When the user sets to delete the following object perimeter for a given policy + | objectperimetername | policies | + | ProfessorsPromotionDocument | Stanford Policy | + And the user sets to delete the following object perimeter + | objectperimetername | + | ProfessorsPromotionDocument | + Then the following object perimeter should be existed in the system + | objectperimetername | objectperimeterdescription | policies | + | | | | + + Scenario: Delete object perimeter with a policy and with assignments + Given the following object perimeter exists + | objectperimetername | objectperimeterdescription | policies | + | ProfessorsPromotionDocument | Thisistherequesttoaccessfile | Stanford Policy | + And the following object data exists + | policyname | objectcategory | objectdataname | objectdatadescription | + | Stanford Policy | Clearance: | Top-Secret | This data has the value of object category | + | Stanford Policy | Clearance: | Confidential | This data has the value of object category | + | Stanford Policy | Clearance: | Public | This data has the value of object category | + | Stanford Policy | Type: | Adminstrative | This data has the value of object category | + | Stanford Policy | Type: | Staff | This data has the value of object category | + And the following object assignment exists + | objectperimetername | objectcategory | objectdata | policyname | + | ProfessorsPromotionDocument | Clearance: | Public | Stanford Policy | + | ProfessorsPromotionDocument | Clearance: | Confidential | Stanford Policy | + When the user sets to delete the following object perimeter for a given policy + | objectperimetername | policies | + | ProfessorsPromotionDocument | Stanford Policy | + Then the system should reply the following + | flag | + | True | + And the following object perimeter should be existed in the system + | objectperimetername | objectperimeterdescription | policies | + | ProfessorsPromotionDocument | Thisistherequesttoaccessfile | | + And the following object assignment should be existed in the system + | objectperimetername | objectcategory | objectdata | policyname | + | | | | Stanford Policy | + + + Scenario: Add action perimeter + When the user sets to add the following action perimeter + | actionperimetername | actionperimeterdescription | policies | + | Read | Thisistheactionrequired | Stanford Policy | + | Read | Thisistheactionrequired | Cambridge Policy | + | Delete | Thisistheactionrequired | Stanford Policy | + | Delete | Thisistheactionrequired | Cambridge Policy | + Then the following action perimeter should be existed in the system + | actionperimetername | actionperimeterdescription | policies | + | Delete | Thisistheactionrequired | Cambridge Policy,Stanford Policy | + | Read | Thisistheactionrequired | Cambridge Policy,Stanford Policy | + + Scenario Outline: Add action perimeter validations + When the user sets to add the following action perimeter + | actionperimetername | actionperimeterdescription | policies | + | | | | + Then the system should reply the following + | flag | + | | + Examples: + | actionperimetername | actionperimeterdescription | policies | flag | + | | Thisistheactionrequired | Stanford Policy | False | + | _%Read%_ | Thisistheactionrequired | Stanford Policy | True | + | Read | | Stanford Policy | True | + | Read | Thisistheactionrequired% | Stanford Policy | True | + | Read | Thisistheactionrequired% | | True | + + + Scenario Outline: Add an existing action perimeter + Given the following action perimeter exists + | actionperimetername | actionperimeterdescription | policies | + | Read | Thisistheactionrequired | Stanford Policy | + When the user sets to add the following action perimeter + | actionperimetername | actionperimeterdescription | policies | + | | | | + Then the system should reply the following + | flag | + | | + Examples: + | actionperimetername | actionperimeterdescription | policies | flag | + | Read | Thisistheactionrequired | Stanford Policy | False | + | Read | Thisistheactionrequired | Cambridge Policy | True | + + Scenario: Update action perimeter + Given the following action perimeter exists + | actionperimetername | actionperimeterdescription | policies | + | Read | Thisistheactionrequired | Stanford Policy | + | Read | Thisistheactionrequired | Cambridge Policy | + When the user sets to update the following action perimeter + | actionperimetername | updatedactionperimetername | updatedactionperimeterdescription | policies | + | Read | Delete | Thisistheactionrequired | Stanford Policy | + Then the following action perimeter should be existed in the system + | actionperimetername | actionperimeterdescription | policies | + | Delete | Thisistheactionrequired | Cambridge Policy,Stanford Policy | + + Scenario Outline: Update action perimeter validations + Given the following action perimeter exists + | actionperimetername | actionperimeterdescription | policies | + | Read | Thisistheactionrequired | Stanford Policy | + When the user sets to update the following action perimeter + | actionperimetername | updatedactionperimetername | updatedactionperimeterdescription | policies | + | | | | | + Then the system should reply the following + | flag | + | | + Examples: + | actionperimetername | updatedactionperimetername | updatedactionperimeterdescription | policies | flag | + | Read | | Thisistheactionrequired | Stanford Policy | False | + | Read | _%Read%_ | Thisistheactionrequired | Stanford Policy | True | + | Read | Read | | Stanford Policy | True | + | Read | Read | Thisistheactionrequired% | Stanford Policy | True | + + Scenario: Delete action perimeter with a policy + Given the following action perimeter exists + | actionperimetername | actionperimeterdescription | policies | + | Read | This is the action required | Stanford Policy | + When the user sets to delete the following action perimeter + | actionperimetername | + | Read | + Then the system should reply the following + | flag | + | False | + And the following action perimeter should be existed in the system + | actionperimetername | actionperimeterdescription | policies | + | Read | This is the action required | Stanford Policy | + + Scenario: Check action perimeter after removing the policy + Given the following action perimeter exists + | actionperimetername | actionperimeterdescription | policies | + | Read | Thisistheactionrequired | Stanford Policy | + When the user sets to delete the following action perimeter for a given policy + | actionperimetername | policies | + | Read | Stanford Policy | + Then the following action perimeter should be existed in the system + | actionperimetername | actionperimeterdescription | policies | + | Read | Thisistheactionrequired | | + + Scenario: Delete action perimeter after removing the policy + Given the following action perimeter exists + | actionperimetername | actionperimeterdescription | policies | + | Read | Thisistheactionrequired | Stanford Policy | + When the user sets to delete the following action perimeter for a given policy + | actionperimetername | policies | + | Read | Stanford Policy | + And the user sets to delete the following action perimeter + | actionperimetername | + | Read | + Then the following action perimeter should be existed in the system + | actionperimetername | actionperimeterdescription | policies | + | | | | + + Scenario: Delete action perimeter with a policy and with assignments + Given the following action perimeter exists + | actionperimetername | actionperimeterdescription | policies | + | Read | Thisistheactionrequired | Stanford Policy | + And the following action data exists + | policyname | actioncategory | actiondataname | actiondatadescription | + | Stanford Policy | Action-Class: | Severe | This data has the value of action category | + | Stanford Policy | Action-Class: | Low | This data has the value of action category | + | Stanford Policy | Action-Priority: | Low | This data has the value of action category | + And the following action assignment exists + | actionperimetername | actioncategory | actiondata | policyname | + | Read | Action-Class: | Severe | Stanford Policy | + | Read | Action-Class: | Low | Stanford Policy | + When the user sets to delete the following action perimeter for a given policy + | actionperimetername | policies | + | Read | Stanford Policy | + Then the system should reply the following + | flag | + | True | + And the following action perimeter should be existed in the system + | actionperimetername | actionperimeterdescription | policies | + | Read | Thisistheactionrequired | | + And the following action assignment should be existed in the system + | actionperimetername | actioncategory | actiondata | policyname | + | | | | Stanford Policy | + + diff --git a/moon_manager/tests/func_tests/features/policy.feature b/moon_manager/tests/func_tests/features/policy.feature new file mode 100644 index 00000000..e8d4077d --- /dev/null +++ b/moon_manager/tests/func_tests/features/policy.feature @@ -0,0 +1,245 @@ +Feature: Policy + + Background: + Given the system has no rules + And the system has no subject assignments + And the system has no action assignments + And the system has no object assignments + And the system has no subject data + And the system has no action data + And the system has no object data + And the system has no subject perimeter + And the system has no object perimeter + And the system has no action perimeter + And the system has no pdps + And the system has no policies + And the system has no models + And the system has no meta-rules + And the system has no subject categories + And the system has no action categories + And the system has no object categories + And the following meta data subject category exists + | subjectmetadataname | subjectmetadatadescription | + | Affiliation: | This meta data has the categorical information about a subject | + | Authorization-Level: | This meta data has the categorical information about an object | + | Degree: | This meta data has the categorical information about an object | + And the following meta data object category exists + | objectmetadataname | objectmetadatadescription | + | Clearance: | This meta data has the categorical information about an object | + | Type: | This meta data has the categorical information about an object | + | Class: | This meta data has the categorical information about an object | + And the following meta data action category exists + | actionmetadataname | actionmetadatadescription | + | Action-Class: | This meta data has the categorical information about an action | + | Action-Priority: | This meta data has the categorical information about an action | + | Recommendation: | This meta data has the categorical information about an action | + And the following meta rule exists + | metarulename | metaruledescription | subjectmetadata | actionmetadata | objectmetadata | + | metarule1 | This is a basic metarule | Affiliation: | Action-Class: | Clearance: | + | metarule2 | This is a basic metarule | Authorization-Level: | Action-Class: | Clearance: | + | metarule3 | This is a basic metarule | Affiliation: | Action-Priority: | Clearance: | + | metarule4 | This is a basic metarule | Authorization-Level: | Action-Priority: | Clearance: | + | metarule5 | This is a basic metarule | Affiliation: | Action-Class: | Type: | + | metarule6 | This is a basic metarule | Authorization-Level: | Action-Class: | Type: | + | metarule7 | This is a basic metarule | Affiliation: | Action-Priority: | Type: | + | metarule8 | This is a basic metarule | Authorization-Level: | Action-Priority: | Type: | + | metarule9 | This is a basic metarule | Affiliation:,Authorization-Level: | Action-Class:,Action-Priority: | Clearance:,Type: | + And the following model exists + | modelname | modeldescription | metarule | + | generalmodel | This is a basic model | metarule9 | + | generalmodel2 | This is a basic model | metarule3,metarule5,metarule8 | + | generalmodel3 | This is a basic model | metarule9 | + + Scenario: Add policy + When the user sets to add the following policy + | policyname | policydescription | modelname | genre | + | A policy | This is a basic policy | generalmodel | financial | + | B policy | This is a basic policy | generalmodel | administrative | + Then the following policy should be existed in the system + | policyname | policydescription | modelname | genre | + | A policy | This is a basic policy | generalmodel | financial | + | B policy | This is a basic policy | generalmodel | administrative | + + Scenario Outline: Add policy validations + When the user sets to add the following policy + | policyname | policydescription | modelname | genre | + | | | | | + Then the system should reply the following + | flag | + | | + Examples: + | policyname | policydescription | modelname | genre | flag | + | | This is a basic policy | generalmodel | financial | False | + | generalpolicy | | generalmodel | financial | True | + | generalpolicy | This is a basic policy | | financial | False | + | generalpolicy | This is a basic policy | 0000000000000000000000 | financial | False | + | generalpolicy | This is a basic policy | 0000000000000000000000000000000000000000000000000000000000000000 | financial | False | + | generalpolicy | This is a basic policy | 00000000000000000000000000000000000000000000000000000000000000000000 | financial | False | + | generalpolicy | This is a basic policy | generalmodel | | True | + | 1 | This is a basic policy | generalmodel | financial | True | + | _%policy%_ | This is a basic policy | generalmodel | financial | True | + | policy | This is a basic policy % | generalmodel | 1 | True | + | policy | This is a basic policy % | generalmodel2 | 1 | True | + | policy | This is a basic policy % | generalmodel | _%genere%_ | True | + + Scenario Outline: Add an existing policy + Given the following policy exists + | policyname | policydescription | modelname | genre | + | generalpolicy | This is a basic policy | generalmodel | financial | + When the user sets to add the following policy + | policyname | policydescription | modelname | genre | + | | | | | + Then the system should reply the following + | flag | + | | + Examples: + | policyname | policydescription | modelname | genre | flag | + | generalpolicy | This is a basic policy | generalmodel2 | financial | False | + | generalpolicy2 | This is a basic policy | generalmodel | financial | True | + + Scenario: Update policy + Given the following policy exists + | policyname | policydescription | modelname | genre | + | generalpolicy | This is a basic policy | generalmodel | financial | + When the user sets to update the following policy + | policyname | updatedpolicyname | updatedpolicydescription | updatedmodelname | updatedgenre | + | generalpolicy | 1 P % | This is a basic policy | generalmodel | financial | + Then the following policy should be existed in the system + | policyname | policydescription | modelname | genre | + | 1 P % | This is a basic policy | generalmodel | financial | + + Scenario Outline: Update policy validations + Given the following policy exists + | policyname | policydescription | modelname | genre | + | mainpolicy | This is a basic policy | generalmodel | adminstrative | + | mainpolicy2 | This is a basic policy | generalmodel | adminstrative | + When the user sets to update the following policy + | policyname | updatedpolicyname | updatedpolicydescription | updatedmodelname | updatedgenre | + | | | | | | + Then the system should reply the following + | flag | + | | + Examples: + | policyname | updatedpolicyname | updatedpolicydescription | updatedmodelname | updatedgenre | flag | + | mainpolicy | | This is a basic policy | generalmodel | financial | False | + | mainpolicy | generalpolicy | | generalmodel | financial | True | + | mainpolicy | generalpolicy | This is a basic policy | | financial | False | + | mainpolicy | generalpolicy | This is a basic policy | 0000000000000000000000 | financial | False | + | mainpolicy | generalpolicy | This is a basic policy | 0000000000000000000000000000000000000000000000000000000000000000 | financial | False | + | mainpolicy | generalpolicy | This is a basic policy | 00000000000000000000000000000000000000000000000000000000000000000000 | financial | False | + | mainpolicy | generalpolicy | This is a basic policy | generalmodel | | True | + | mainpolicy | 1 | This is a basic policy | generalmodel | financial | True | + | mainpolicy | _%policy%_ | This is a basic policy | generalmodel | financial | True | + | mainpolicy | policy | This is a basic policy % | generalmodel | financial | True | + | mainpolicy | policy | This is a basic policy % | generalmodel | 1 | True | + | mainpolicy | policy | This is a basic policy % | generalmodel2 | 1 | False | + | mainpolicy | policy | This is a basic policy % | generalmodel | _%genere%_ | True | + | mainpolicy | mainpolicy | This is a basic policy % | generalmodel | adminstrative | True | + | mainpolicy | mainpolicy2 | This is a basic policy % | generalmodel | adminstrative | False | + + Scenario: Delete policy + Given the following policy exists + | policyname | policydescription | modelname | genre | + | generalpolicy | This is a basic policy | generalmodel | financial | + When the user sets to delete the following policy + | policyname | + | generalpolicy | + Then the following policy should be existed in the system + | policyname | policydescription | modelname | genre | + | | | | | + + + Scenario: Delete a policy that has a system attributes dependency + Given the following policy exists + | policyname | policydescription | modelname | genre | + | Stanford Policy | This is a basic policy | generalmodel | financial | + | Cambridge Policy | This is a basic policy | generalmodel2 | Education | + And the following pdp exists + | pdpname | pdpdescription | keystone_project_id | security_pipeline | + | generalpdp | This is a basic pdp | 0000000000000000000000000000000000000000000000000000000000000000 | Stanford Policy | + And the following subject perimeter exists + | subjectperimetername | subjectperimeterdescription | subjectperimeteremail | subjectperimeterpassword | policies | + | JohnLewis | Thisistheexpecteduser | jlewis@orange.com | abc1234 | Stanford Policy | + | JohnLewis | Thisistheexpecteduser | jlewis@orange.com | abc1234 | Cambridge Policy | + | WilliamsJoeseph | Thisistheexpecteduser | wjoeseph@orange.com | abc1234 | Stanford Policy | + And the following object perimeter exists + | objectperimetername | objectperimeterdescription | policies | + | ProfessorsPromotionDocument | Thisistherequesttoaccessfile | Stanford Policy | + | ProfessorsPromotionDocument | Thisistherequesttoaccessfile | Cambridge Policy | + | StudentsGradesSheet | Thisistherequesttoaccessfile | Stanford Policy | + And the following action perimeter exists + | actionperimetername | actionperimeterdescription | policies | + | Delete | Thisistheactionrequired | Stanford Policy | + | Read | Thisistheactionrequired | Stanford Policy | + | Read | Thisistheactionrequired | Cambridge Policy | + And the following subject data exists + | policyname | subjectcategory | subjectdataname | subjectdatadescription | + | Stanford Policy | Affiliation: | University-of-Stanford | This data has the value of subject category | + | Stanford Policy | Affiliation: | Stanford | This data has the value of subject category | + | Stanford Policy | Authorization-Level: | Professor | This data has the value of subject category | + And the following object data exists + | policyname | objectcategory | objectdataname | objectdatadescription | + | Stanford Policy | Clearance: | Top-Secret | This data has the value of object category | + | Stanford Policy | Clearance: | Confidential | This data has the value of object category | + | Stanford Policy | Clearance: | Public | This data has the value of object category | + | Stanford Policy | Type: | Adminstrative | This data has the value of object category | + | Stanford Policy | Type: | Staff | This data has the value of object category | + And the following action data exists + | policyname | actioncategory | actiondataname | actiondatadescription | + | Stanford Policy | Action-Class: | Severe | This data has the value of action category | + | Stanford Policy | Action-Class: | Low | This data has the value of action category | + | Stanford Policy | Action-Priority: | Low | This data has the value of action category | + And the following subject assignment exists + | subjectperimetername | subjectcategory | subjectdata | policyname | + | JohnLewis | Affiliation: | University-of-Stanford | Stanford Policy | + | WilliamsJoeseph | Affiliation: | Stanford | Stanford Policy | + And the following object assignment exists + | objectperimetername | objectcategory | objectdata | policyname | + | StudentsGradesSheet | Clearance: | Public | Stanford Policy | + | StudentsGradesSheet | Clearance: | Top-Secret | Stanford Policy | + | StudentsGradesSheet | Clearance: | Confidential | Stanford Policy | + And the following action assignment exists + | actionperimetername | actioncategory | actiondata | policyname | + | Read | Action-Class: | Severe | Stanford Policy | + | Read | Action-Class: | Low | Stanford Policy | + | Read | Action-Priority: | Low | Stanford Policy | + When the user sets to delete the following policy + | policyname | + | Stanford Policy | + Then the following policy should be existed in the system + | policyname | policydescription | modelname | genre | + | Cambridge Policy | This is a basic policy | generalmodel2 | Education | + And the following pdp should be existed in the system + | pdpname | pdpdescription | keystone_project_id | security_pipeline | + | generalpdp | This is a basic pdp | 0000000000000000000000000000000000000000000000000000000000000000 | | + And the following subject perimeter should be existed in the system + | subjectperimetername | subjectperimeterdescription | subjectperimeteremail | subjectperimeterpassword | policies | + | JohnLewis | Thisistheexpecteduser | jlewis@orange.com | abc1234 | Cambridge Policy | + | WilliamsJoeseph | Thisistheexpecteduser | wjoeseph@orange.com | abc1234 | | + And the following object perimeter should be existed in the system + | objectperimetername | objectperimeterdescription | policies | + | ProfessorsPromotionDocument | Thisistherequesttoaccessfile | Cambridge Policy | + | StudentsGradesSheet | Thisistherequesttoaccessfile | | + And the following action perimeter should be existed in the system + | actionperimetername | actionperimeterdescription | policies | + | Delete | Thisistheactionrequired | | + | Read | Thisistheactionrequired | Cambridge Policy | + And the following subject data should be existed in the system + | policyname | subjectcategory | subjectdataname | subjectdatadescription | + | | | | | + And the following object data should be existed in the system + | policyname | objectcategory | objectdataname | objectdatadescription | + | | | | | + And the following action data should be existed in the system + | policyname | actioncategory | actiondataname | actiondatadescription | + | | | | | + And the following subject assignment should be existed in the system + | subjectperimetername | subjectcategory | subjectdata | policyname | + | | | | | + And the following object assignment should be existed in the system + | objectperimetername | objectcategory | objectdata | policyname | + | | | | | + And the following action assignment should be existed in the system + | actionperimetername | actioncategory | actiondata | policyname | + | | | | | + diff --git a/moon_manager/tests/func_tests/features/rules.feature b/moon_manager/tests/func_tests/features/rules.feature new file mode 100644 index 00000000..e98e2b30 --- /dev/null +++ b/moon_manager/tests/func_tests/features/rules.feature @@ -0,0 +1,188 @@ +Feature: Rules + + Background: + Given the system has no rules + And the system has no subject assignments + And the system has no action assignments + And the system has no object assignments + And the system has no subject data + And the system has no action data + And the system has no object data + And the system has no subject perimeter + And the system has no object perimeter + And the system has no action perimeter + And the system has no pdps + And the system has no policies + And the system has no models + And the system has no meta-rules + And the system has no subject categories + And the system has no action categories + And the system has no object categories + And the following meta data subject category exists + | subjectmetadataname | subjectmetadatadescription | + | Affiliation: | This meta data has the categorical information about a subject | + | Authorization-Level: | This meta data has the categorical information about an object | + | Degree: | This meta data has the categorical information about an object | + And the following meta data object category exists + | objectmetadataname | objectmetadatadescription | + | Clearance: | This meta data has the categorical information about an object | + | Type: | This meta data has the categorical information about an object | + | Class: | This meta data has the categorical information about an object | + And the following meta data action category exists + | actionmetadataname | actionmetadatadescription | + | Action-Class: | This meta data has the categorical information about an action | + | Action-Priority: | This meta data has the categorical information about an action | + | Recommendation: | This meta data has the categorical information about an action | + And the following meta rule exists + | metarulename | metaruledescription | subjectmetadata | actionmetadata | objectmetadata | + | metarule1 | Thisisabasicmetarule | Affiliation: | Action-Class: | Clearance: | + | metarule2 | Thisisabasicmetarule | Authorization-Level: | Action-Class: | Clearance: | + | metarule3 | Thisisabasicmetarule | Affiliation: | Action-Priority: | Clearance: | + | metarule4 | Thisisabasicmetarule | Authorization-Level: | Action-Priority: | Clearance: | + | metarule5 | Thisisabasicmetarule | Affiliation: | Action-Class: | Type: | + | metarule6 | Thisisabasicmetarule | Authorization-Level: | Action-Class: | Type: | + | metarule7 | Thisisabasicmetarule | Affiliation: | Action-Priority: | Type: | + | metarule8 | Thisisabasicmetarule | Authorization-Level: | Action-Priority: | Type: | + | metarule9 | Thisisabasicmetarule | Affiliation:,Authorization-Level: | Action-Class:,Action-Priority: | Clearance:,Type: | + And the following model exists + | modelname | modeldescription | metarule | + | universitymodel | Thisisabasicmodel | metarule1,metarule9 | + | universitymodel2 | Thisisabasicmodel | metarule3,metarule5,metarule8 | + | universitymodel3 | Thisisabasicmodel | metarule9 | + And the following policy exists + | policyname | policydescription | modelname | genre | + | Stanford Policy | This is a basic policy | universitymodel | Education | + | Cambridge Policy | This is a basic policy | universitymodel3 | Education | + And the following subject perimeter exists + | subjectperimetername | subjectperimeterdescription | subjectperimeteremail | subjectperimeterpassword | policies | + | JohnLewis | Thisistheexpecteduser | jlewis@orange.com | abc1234 | Stanford Policy | + | WilliamsJoeseph | Thisistheexpecteduser | wjoeseph@orange.com | abc1234 | Stanford Policy | + | WilliamsJoeseph | Thisistheexpecteduser | wjoeseph@orange.com | abc1234 | Cambridge Policy | + | WilliamsGeorge | Thisdatahasthevalueofsubjectperimeter | gwilliams@orange.com | abc1234 | | + And the following object perimeter exists + | objectperimetername | objectperimeterdescription | policies | + | ProfessorsPromotionDocument | Thisistherequesttoaccessfile | Stanford Policy | + | StudentsGradesSheet | Thisistherequesttoaccessfile | Stanford Policy | + | StudentsGradesSheet | Thisistherequesttoaccessfile | Cambridge Policy | + | Vacations | Thisistherequesttoaccessfile | | + And the following action perimeter exists + | actionperimetername | actionperimeterdescription | policies | + | Read | Thisistheactionrequired | Stanford Policy | + | Delete | Thisistheactionrequired | Stanford Policy | + | Edit | Thisistheactionrequired | | + And the following subject data exists + | policyname | subjectcategory | subjectdataname | subjectdatadescription | + | Stanford Policy | Affiliation: | University-of-Stanford | This data has the value of subject category | + | Stanford Policy | Affiliation: | Stanford | This data has the value of subject category | + | Cambridge Policy | Affiliation: | University-of-Cambridge | This data has the value of subject category | + | Cambridge Policy | Authorization-Level: | Professor | This data has the value of subject category | + | Cambridge Policy | Authorization-Level: | Lecturer | This data has the value of subject category | + And the following object data exists + | policyname | objectcategory | objectdataname | objectdatadescription | + | Stanford Policy | Clearance: | Top-Secret | This data has the value of object category | + | Stanford Policy | Clearance: | Confidential | This data has the value of object category | + | Stanford Policy | Clearance: | Public | This data has the value of object category | + | Cambridge Policy | Type: | Adminstrative | This data has the value of object category | + | Cambridge Policy | Type: | Teaching-Staff | This data has the value of object category | + | Cambridge Policy | Clearance: | Confidential | This data has the value of object category | + | Cambridge Policy | Clearance: | Access-with-permission | This data has the value of object category | + | Cambridge Policy | Clearance: | Public | This data has the value of object category | + + And the following action data exists + | policyname | actioncategory | actiondataname | actiondatadescription | + | Stanford Policy | Action-Class: | Severe | This data has the value of action category | + | Stanford Policy | Action-Class: | Low | This data has the value of action category | + | Cambridge Policy | Action-Priority: | High | This data has the value of action category | + | Cambridge Policy | Action-Priority: | Medium | This data has the value of action category | + | Cambridge Policy | Action-Priority: | Low | This data has the value of action category | + | Cambridge Policy | Action-Class: | Severe | This data has the value of action category | + | Cambridge Policy | Action-Class: | Intermediate | This data has the value of action category | + | Cambridge Policy | Action-Class: | Low | This data has the value of action category | + + And the following subject assignment exists + | subjectperimetername | subjectcategory | subjectdata | policyname | + | JohnLewis | Affiliation: | University-of-Stanford | Stanford Policy | + | WilliamsJoeseph | Affiliation: | Stanford | Stanford Policy | + + And the following object assignment exists + | objectperimetername | objectcategory | objectdata | policyname | + | StudentsGradesSheet | Clearance: | Access-with-permission | Cambridge Policy | + | StudentsGradesSheet | Clearance: | Public | Cambridge Policy | + #| StudentsGradesSheet | Clearance: | Top-Secret | Stanford Policy | + | StudentsGradesSheet | Clearance: | Confidential | Stanford Policy | + #| StudentsGradesSheet | Clearance: | Public | Stanford Policy | + And the following action assignment exists + | actionperimetername | actioncategory | actiondata | policyname | + | Read | Action-Class: | Severe | Stanford Policy | + #| Read | Action-Class: | Low | Stanford Policy | + | Delete | Action-Priority: | High | Cambridge Policy | + | Delete | Action-Priority: | Medium | Cambridge Policy | + | Delete | Action-Priority: | Low | Cambridge Policy | + + Scenario: Add rule + When the user sets to add the following rules + | rule | metarulename | instructions | policyname | + | University-of-Stanford,Confidential,Severe | metarule1 | grant | Stanford Policy | + | University-of-Cambridge,Professor,Public,Adminstrative,Low,Low | metarule9 | grant | Cambridge Policy | + Then the following rules should be existed in the system + | rule | metarulename | instructions | policyname | + | University-of-Stanford,Confidential,Severe | metarule1 | grant | Stanford Policy | + | University-of-Cambridge,Professor,Public,Adminstrative,Low,Low | metarule9 | grant | Cambridge Policy | + +Scenario Outline: Add rules validations + When the user sets to add the following rules + | rule | metarulename | instructions | policyname | + | | | | | + Then the system should reply the following + | flag | + | | + Examples: + | rule | metarulename | instructions | policyname | flag | + | | metarule1 | grant | Stanford Policy | False | + | Confidential,Severe | metarule1 | grant | Stanford Policy | False | + | ,Confidential,Severe | metarule1 | grant | Stanford Policy | False | + | 0000000000000000000000000000000000000000,Confidential,Severe | metarule1 | grant | Stanford Policy | False | + | University of USA,Confidential,Severe | metarule1 | grant | Stanford Policy | False | + | University-of-Stanford,,Confidential,Severe | metarule1 | grant | Stanford Policy | False | + | University-of-Stanford,,Confidential | metarule1 | grant | Stanford Policy | False | + | University-of-Stanford,Superficial,Severe | metarule1 | grant | Stanford Policy | False | + | University-of-Stanford,0000000000000000000000000000000000000000,Severe | metarule1 | grant | Stanford Policy | False | + | University-of-Stanford,Confidential,,Severe | metarule1 | grant | Stanford Policy | False | + | University-of-Stanford,Confidential, | metarule1 | grant | Stanford Policy | False | + | University-of-Stanford,Confidential,Non-Accessable | metarule1 | grant | Stanford Policy | False | + | University-of-Stanford,Confidential,0000000000000000000000000000000000000000 | metarule1 | grant | Stanford Policy | False | + #| University-of-Stanford,Confidential,Severe, | metarule1 | grant | Stanford Policy | False | + | University-of-Stanford,Confidential,Severe | | grant | Stanford Policy | False | + | University-of-Stanford,Confidential,Severe | metarule9 | grant | Stanford Policy | False | + | University-of-Stanford,Confidential,Severe | 000000000000000000000000000000000000000000000000000 | grant | Stanford Policy | False | + | University-of-Stanford,Confidential,Severe | metarule1 | not grant | Stanford Policy | False | + | University-of-Stanford,Confidential,Severe | metarule1 | | Stanford Policy | True | + | University-of-Stanford,Confidential,Severe | metarule1 | grant | | False | + | University-of-Stanford,Confidential,Severe | metarule1 | grant | 000000000000000000000000000000000000000000000000000 | False | + | University-of-Stanford,Confidential,Severe | metarule1 | grant | Cambridge Policy | False | + + + Scenario: Add existing rule + Given the following rule exists + | rule | metarulename | instructions | policyname | + | University-of-Stanford,Confidential,Severe | metarule1 | grant | Stanford Policy | + When the user sets to add the following rules + | rule | metarulename | instructions | policyname | + | University-of-Stanford,Confidential,Severe | metarule1 | grant | Stanford Policy | + Then the system should reply the following + | flag | + | False | + + + Scenario: Delete rule + Given the following rule exists + | rule | metarulename | instructions | policyname | + | University-of-Stanford,Confidential,Severe | metarule1 | grant | Stanford Policy | + When the user sets to delete the following rules + | rule | metarulename | policyname | + | University-of-Stanford,Confidential,Severe | metarule1 | Stanford Policy | + Then the system should reply the following + | flag | + | True | + + diff --git a/moon_manager/tests/func_tests/features/steps/Static_Variables.py b/moon_manager/tests/func_tests/features/steps/Static_Variables.py new file mode 100644 index 00000000..471f92fa --- /dev/null +++ b/moon_manager/tests/func_tests/features/steps/Static_Variables.py @@ -0,0 +1,89 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +class GeneralVariables: + serverURL="http://127.0.0.1:8000/" + + serverIP="10.237.71.141" + + serverport = "22" + + serverusername="ubuntu" + + serverpassword="ubuntu-007" + + token = "{{TOKEN}}" + + auth_headers = {"X-Api-Key": token} + + actual_authresponse = {'value': False} + + api_responseflag = {'value': False} + + pipelinePort = {'value': ""} + + wrapperPort = {'value': ""} + + projectAPI = "" + + slaveAPI="slave" + + getslavesAPI = "slaves" + + pdpAPI = "pdp" + + modelAPI = "models" + + policyAPI = "policies" + + assignpolicyid={'value': ""} + + assignsubjectperimeterid = {'value': ""} + + assignsubjectcategoryid = {'value': ""} + + assignobjectperimeterid = {'value': ""} + + assignobjectcategoryid = {'value': ""} + + assignactionperimeterid = {'value': ""} + + assignactioncategoryid = {'value': ""} + + metarulesAPI = "meta_rules" + + metadatasubjectcategoryAPI = "subject_categories" + + metadataobjectcategoryAPI = "object_categories" + + metadataactioncategoryAPI = "action_categories" + + perimetersubjectAPI = "subjects" + + perimeterobjectAPI = "objects" + + perimeteractionAPI = "actions" + + datasubjectAPI = "subject_data" + + dataobjectAPI = "object_data" + + dataactionAPI = "action_data" + + assignementssubjectAPI = "subject_assignments" + + assignementsobjectAPI = "object_assignments" + + assignementsactionAPI = "action_assignments" + + rulesAPI = "rules" + diff --git a/moon_manager/tests/func_tests/features/steps/__init__.py b/moon_manager/tests/func_tests/features/steps/__init__.py new file mode 100644 index 00000000..582be686 --- /dev/null +++ b/moon_manager/tests/func_tests/features/steps/__init__.py @@ -0,0 +1,11 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + diff --git a/moon_manager/tests/func_tests/features/steps/assignments.py b/moon_manager/tests/func_tests/features/steps/assignments.py new file mode 100644 index 00000000..e3f7b5a7 --- /dev/null +++ b/moon_manager/tests/func_tests/features/steps/assignments.py @@ -0,0 +1,858 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +from behave import * +from Static_Variables import GeneralVariables +from astropy.table import Table, Column +from common_functions import * +import requests +import json +import logging + +apis_urls = GeneralVariables() +commonfunctions = commonfunctions() + +logger = logging.getLogger(__name__) + +# Step Definition Implementation: +# 1) Get all the existing subject meta data in the system by getting the policies then their models then the model attached meta rules and then the categories +# 2) Get subject assignment id using both the policy id, data id & the category id +# 3) Loop by assignment id and delete it +@Given('the system has no subject assignments') +def step_impl(context): + logger.info("Given the system has no subject assignments") + api_responseflag = {'value': False} + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + response_policies = requests.get(apis_urls.serverURL + apis_urls.policyAPI, headers=apis_urls.auth_headers) + if len(response_policies.json()[apis_urls.policyAPI]) != 0: + for policies_ids in dict(response_policies.json()[apis_urls.policyAPI]).keys(): + # subjectcategoryidslist = [] + # subjectdataidslist = [] + # modelid = response_policies.json()[apis_urls.policyAPI][policies_ids]['model_id'] + # if (modelid != None and modelid != ""): + # metaruleslist = \ + # requests.get(apis_urls.serverURL + apis_urls.modelAPI, headers=apis_urls.auth_headers).json()[apis_urls.modelAPI][modelid]['meta_rules'] + # for metarule_ids in metaruleslist: + # categorieslist = \ + # requests.get(apis_urls.serverURL + apis_urls.metarulesAPI, + # headers=apis_urls.auth_headers).json()[apis_urls.metarulesAPI][ + # metarule_ids]['subject_categories'] + # for categoryid in categorieslist: + # if (categoryid not in subjectcategoryidslist): + # subjectcategoryidslist.append(categoryid) + # + # response_perimeters = requests.get(apis_urls.serverURL + apis_urls.perimetersubjectAPI, + # headers=apis_urls.auth_headers).json()[ + # apis_urls.perimetersubjectAPI] + # for perimeterid in dict(response_perimeters).keys(): + # for categoryid in subjectcategoryidslist: + # response_assignment = requests.get( + # apis_urls.serverURL + "policies/" + policies_ids + "/" + apis_urls.assignementssubjectAPI + "/" + + # perimeterid + "/" + categoryid, headers=apis_urls.auth_headers) + # if len(response_assignment.json()[apis_urls.assignementssubjectAPI]) != 0: + # for ids in dict(response_assignment.json()[apis_urls.assignementssubjectAPI]).keys(): + # assignmentsid = response_assignment.json()[apis_urls.assignementssubjectAPI][str(ids)][ + # 'assignments'] + # for dataid in assignmentsid: + response = requests.delete( + apis_urls.serverURL + "policies/" + policies_ids + "/" + apis_urls.assignementssubjectAPI , headers=headers) + +# Step Definition Implementation: +# 1) Get all the existing object meta data in the system by getting the policies then their models then the model attached meta rules and then the categories +# 2) Get object assignment id using both the policy id, data id & the category id +# 3) Loop by assignment id and delete it +@Given('the system has no object assignments') +def step_impl(context): + logger.info("Given the system has no object assignments") + api_responseflag = {'value': False} + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + response_policies = requests.get(apis_urls.serverURL + apis_urls.policyAPI, headers=apis_urls.auth_headers) + if len(response_policies.json()[apis_urls.policyAPI]) != 0: + for policies_ids in dict(response_policies.json()[apis_urls.policyAPI]).keys(): + # objectcategoryidslist = [] + # objectdataidslist = [] + # modelid = response_policies.json()[apis_urls.policyAPI][policies_ids]['model_id'] + # if (modelid != None and modelid != ""): + # metaruleslist = \ + # requests.get(apis_urls.serverURL + apis_urls.modelAPI, headers=apis_urls.auth_headers).json()[ + # apis_urls.modelAPI][modelid][ + # 'meta_rules'] + # for metarule_ids in metaruleslist: + # categorieslist = \ + # requests.get(apis_urls.serverURL + apis_urls.metarulesAPI, + # headers=apis_urls.auth_headers).json()[apis_urls.metarulesAPI][ + # metarule_ids]['object_categories'] + # for categoryid in categorieslist: + # if (categoryid not in objectcategoryidslist): + # objectcategoryidslist.append(categoryid) + # + # response_perimeters = \ + # requests.get(apis_urls.serverURL + apis_urls.perimeterobjectAPI, + # headers=apis_urls.auth_headers).json()[ + # apis_urls.perimeterobjectAPI] + # for perimeterid in dict(response_perimeters).keys(): + # for categoryid in objectcategoryidslist: + # response_assignment = requests.get( + # apis_urls.serverURL + "policies/" + policies_ids + "/" + apis_urls.assignementsobjectAPI + "/" + + # perimeterid + "/" + categoryid, headers=apis_urls.auth_headers) + # if len(response_assignment.json()[apis_urls.assignementsobjectAPI]) != 0: + # for ids in dict(response_assignment.json()[apis_urls.assignementsobjectAPI]).keys(): + # assignmentsid = response_assignment.json()[apis_urls.assignementsobjectAPI][str(ids)][ + # 'assignments'] + # for dataid in assignmentsid: + response = requests.delete( + apis_urls.serverURL + "policies/" + policies_ids + "/" + apis_urls.assignementsobjectAPI , headers=headers) + +# Step Definition Implementation: +# 1) Get all the existing action meta data in the system by getting the policies then their models then the model attached meta rules and then the categories +# 2) Get action assignment id using both the policy id, data id & the category id +# 3) Loop by assignment id and delete it +@Given('the system has no action assignments') +def step_impl(context): + logger.info("Given the system has no action assignments") + api_responseflag = {'value': False} + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + response_policies = requests.get(apis_urls.serverURL + apis_urls.policyAPI, headers=apis_urls.auth_headers) + if len(response_policies.json()[apis_urls.policyAPI]) != 0: + for policies_ids in dict(response_policies.json()[apis_urls.policyAPI]).keys(): + # actioncategoryidslist = [] + # actiondataidslist = [] + # modelid = response_policies.json()[apis_urls.policyAPI][policies_ids]['model_id'] + # if (modelid != None and modelid != ""): + # metaruleslist = \ + # requests.get(apis_urls.serverURL + apis_urls.modelAPI, headers=apis_urls.auth_headers).json()[ + # apis_urls.modelAPI][modelid][ + # 'meta_rules'] + # for metarule_ids in metaruleslist: + # categorieslist = \ + # requests.get(apis_urls.serverURL + apis_urls.metarulesAPI, + # headers=apis_urls.auth_headers).json()[apis_urls.metarulesAPI][ + # metarule_ids]['action_categories'] + # for categoryid in categorieslist: + # if (categoryid not in actioncategoryidslist): + # actioncategoryidslist.append(categoryid) + # + # response_perimeters = \ + # requests.get(apis_urls.serverURL + apis_urls.perimeteractionAPI, + # headers=apis_urls.auth_headers).json()[ + # apis_urls.perimeteractionAPI] + # for perimeterid in dict(response_perimeters).keys(): + # for categoryid in actioncategoryidslist: + # response_assignment = requests.get( + # apis_urls.serverURL + "policies/" + policies_ids + "/" + apis_urls.assignementsactionAPI + "/" + + # perimeterid + "/" + categoryid, headers=apis_urls.auth_headers) + # if len(response_assignment.json()[apis_urls.assignementsactionAPI]) != 0: + # for ids in dict(response_assignment.json()[apis_urls.assignementsactionAPI]).keys(): + # assignmentsid = response_assignment.json()[apis_urls.assignementsactionAPI][str(ids)][ + # 'assignments'] + # for dataid in assignmentsid: + response = requests.delete( + apis_urls.serverURL + "policies/" + policies_ids + "/" + apis_urls.assignementsactionAPI , headers=headers) + +# Step Definition Implementation: +# 1) Post subject assignment using the policy id, subject perimeter id, subject category, list of subject data ids +@Given('the following subject assignment exists') +def step_impl(context): + logger.info("Given the following subject assignment exists") + model = getattr(context, "model", None) + for row in context.table: + logger.info( + "subject perimeter name: '" + row["subjectperimetername"] + "' subject data: '" + row[ + "subjectdata"] + "' and subject category: '" + row[ + "subjectcategory"] + "' and policies: '" + row['policyname'] + "'") + + policies_id = "" + perimeter_id = "" + categoriesname = "" + dataname = "" + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + policies_id = commonfunctions.get_policyid(row['policyname']) + perimeter_id = commonfunctions.get_subjectperimeterid(row['subjectperimetername']) + categories_id = commonfunctions.get_subjectcategoryid(row['subjectcategory']) + dataids = commonfunctions.get_subjectdataid(row['subjectdata'], categories_id, policies_id) + data = { + 'id': perimeter_id, + 'category_id': categories_id, + 'data_id': dataids, + } + response = requests.post( + apis_urls.serverURL + "policies/" + str(policies_id) + "/" + apis_urls.assignementssubjectAPI, + headers=headers, data=json.dumps(data)) + + GeneralVariables.assignpolicyid['value'] = policies_id + GeneralVariables.assignsubjectperimeterid['value'] = perimeter_id + GeneralVariables.assignsubjectcategoryid['value'] = categories_id + + if response.status_code == 200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Post object assignment using the policy id, object perimeter id, object category, list of object data ids +@Given('the following object assignment exists') +def step_impl(context): + logger.info("Given the following object assignment exists") + model = getattr(context, "model", None) + for row in context.table: + logger.info( + "object perimeter name: '" + row["objectperimetername"] + "' object data: '" + row[ + "objectdata"] + "' and object category: '" + row[ + "objectcategory"] + "' and policies: '" + row['policyname'] + "'") + + policies_id = "" + perimeter_id = "" + categoriesname = "" + dataname = "" + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + policies_id = commonfunctions.get_policyid(row['policyname']) + perimeter_id = commonfunctions.get_objectperimeterid(row['objectperimetername']) + categories_id = commonfunctions.get_objectcategoryid(row['objectcategory']) + dataids = commonfunctions.get_objectdataid(row['objectdata'], categories_id, policies_id) + + data = { + 'id': perimeter_id, + 'category_id': categories_id, + 'policy_id': policies_id, + 'data_id': dataids, + } + response = requests.post( + apis_urls.serverURL + "policies/" + str(policies_id) + "/" + apis_urls.assignementsobjectAPI, + headers=headers, data=json.dumps(data)) + + GeneralVariables.assignpolicyid['value'] = policies_id + GeneralVariables.assignobjectperimeterid['value'] = perimeter_id + GeneralVariables.assignobjectcategoryid['value'] = categories_id + + if response.status_code == 200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Post action assignment using the policy id, action perimeter id, action category, list of action data ids +@Given('the following action assignment exists') +def step_impl(context): + logger.info("Given the following action assignment exists") + model = getattr(context, "model", None) + for row in context.table: + logger.info( + "action perimeter name: '" + row["actionperimetername"] + "' action data: '" + row[ + "actiondata"] + "' and action category: '" + row[ + "actioncategory"] + "' and policies: '" + row['policyname'] + "'") + + policies_id = "" + perimeter_id = "" + categoriesname = "" + dataname = "" + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + policies_id = commonfunctions.get_policyid(row['policyname']) + perimeter_id = commonfunctions.get_actionperimeterid(row['actionperimetername']) + categories_id = commonfunctions.get_actioncategoryid(row['actioncategory']) + dataids = commonfunctions.get_actiondataid(row['actiondata'], categories_id, policies_id) + + data = { + 'id': perimeter_id, + 'category_id': categories_id, + 'policy_id': policies_id, + 'data_id': dataids, + } + response = requests.post( + apis_urls.serverURL + "policies/" + str(policies_id) + "/" + apis_urls.assignementsactionAPI, + headers=headers, data=json.dumps(data)) + + GeneralVariables.assignpolicyid['value'] = policies_id + GeneralVariables.assignactionperimeterid['value'] = perimeter_id + GeneralVariables.assignactioncategoryid['value'] = categories_id + + if response.status_code == 200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Post action assignment using the policy id, action perimeter id, action category, list of action data ids +# 2) If the request code was 200 set the api response flag to true else false +@When('the user sets to add the following subject assignment') +def step_impl(context): + logger.info("When the user sets to add the following subject assignment") + + model = getattr(context, "model", None) + for row in context.table: + logger.info( + "subject perimeter name: '" + row["subjectperimetername"] + "' subject data: '" + row[ + "subjectdata"] + "' and subject category: '" + row[ + "subjectcategory"] + "' and policies: '" + row['policyname'] + "'") + + policies_id = "" + perimeter_id = "" + categoriesname = "" + dataids = "" + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + if (row['policyname'] == "" or row['policyname'] == "000000000000000000000000000000000000000000000000000"): + policyname = "Stanford Policy" + else: + policyname = row['policyname'] + policies_id = commonfunctions.get_policyid(policyname) + + if (row["subjectperimetername"] == "" or row[ + "subjectperimetername"] == "000000000000000000000000000000000000000000000000000"): + perimetername = "WilliamsJoeseph" + else: + perimetername = row["subjectperimetername"] + perimeter_id = commonfunctions.get_subjectperimeterid(perimetername) + + if (row["subjectcategory"] == "" or row[ + "subjectcategory"] == "000000000000000000000000000000000000000000000000000"): + categoriesname = "Affiliation:" + else: + categoriesname = row['subjectcategory'] + categories_id = commonfunctions.get_subjectcategoryid(categoriesname) + + if (row["subjectdata"] == "" or row["subjectdata"] == "000000000000000000000000000000000000000000000000000"): + dataids = "Professor" + else: + dataids = row['subjectdata'] + dataids = commonfunctions.get_subjectdataid(dataids, categories_id, policies_id) + + if (dataids == None): + dataids = "" + + if (row["policyname"] == "" or row["policyname"] == "000000000000000000000000000000000000000000000000000"): + policies_id = row["policyname"] + if (row["subjectperimetername"] == "" or row[ + "subjectperimetername"] == "000000000000000000000000000000000000000000000000000"): + perimeter_id = row["subjectperimetername"] + if (row["subjectcategory"] == "" or row[ + "subjectcategory"] == "000000000000000000000000000000000000000000000000000"): + categories_id = row["subjectcategory"] + if (row["subjectdata"] == "" or row["subjectdata"] == "000000000000000000000000000000000000000000000000000"): + dataids = row['subjectdata'] + data = { + 'id': perimeter_id, + 'category_id': categories_id, + 'data_id': dataids, + } + response = requests.post( + apis_urls.serverURL + "policies/" + str(policies_id) + "/" + apis_urls.assignementssubjectAPI, + headers=headers, data=json.dumps(data)) + if response.status_code == 200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Post action assignment using the policy id, action perimeter id, action category, list of action data ids +# 2) If the request code was 200 set the api response flag to true else false +@When('the user sets to add the following object assignment') +def step_impl(context): + logger.info("When the user sets to add the following object assignment") + + model = getattr(context, "model", None) + for row in context.table: + logger.info( + "object perimeter name: '" + row["objectperimetername"] + "' object data: '" + row[ + "objectdata"] + "' and object category: '" + row[ + "objectcategory"] + "' and policies: '" + row['policyname'] + "'") + + policies_id = "" + perimeter_id = "" + categoriesname = "" + dataids = "" + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + if (row['policyname'] == "" or row['policyname'] == "000000000000000000000000000000000000000000000000000"): + policyname = "Stanford Policy" + else: + policyname = row['policyname'] + policies_id = commonfunctions.get_policyid(policyname) + + if (row["objectperimetername"] == "" or row[ + "objectperimetername"] == "000000000000000000000000000000000000000000000000000"): + perimetername = "StudentsGradesSheet" + else: + perimetername = row["objectperimetername"] + perimeter_id = commonfunctions.get_objectperimeterid(perimetername) + + if (row["objectcategory"] == "" or row[ + "objectcategory"] == "000000000000000000000000000000000000000000000000000"): + categoriesname = "Clearance:" + else: + categoriesname = row['objectcategory'] + categories_id = commonfunctions.get_objectcategoryid(categoriesname) + + if (row["objectdata"] == "" or row["objectdata"] == "000000000000000000000000000000000000000000000000000"): + dataids = "Confidential" + else: + dataids = row['objectdata'] + dataids = commonfunctions.get_objectdataid(dataids, categories_id, policies_id) + + if (dataids == None): + dataids = "" + + if (row["policyname"] == "" or row["policyname"] == "000000000000000000000000000000000000000000000000000"): + policies_id = row["policyname"] + if (row["objectperimetername"] == "" or row[ + "objectperimetername"] == "000000000000000000000000000000000000000000000000000"): + perimeter_id = row["objectperimetername"] + if (row["objectcategory"] == "" or row[ + "objectcategory"] == "000000000000000000000000000000000000000000000000000"): + categories_id = row["objectcategory"] + if (row["objectdata"] == "" or row["objectdata"] == "000000000000000000000000000000000000000000000000000"): + dataids = row['objectdata'] + data = { + 'id': perimeter_id, + 'category_id': categories_id, + 'data_id': dataids, + } + response = requests.post( + apis_urls.serverURL + "policies/" + str(policies_id) + "/" + apis_urls.assignementsobjectAPI, + headers=headers, data=json.dumps(data)) + + if response.status_code == 200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Post action assignment using the policy id, action perimeter id, action category, list of action data ids +# 2) If the request code was 200 set the api response flag to true else false +@When('the user sets to add the following action assignment') +def step_impl(context): + logger.info("When the user sets to add the following action assignment") + + model = getattr(context, "model", None) + for row in context.table: + logger.info( + "action perimeter name: '" + row["actionperimetername"] + "' action data: '" + row[ + "actiondata"] + "' and action category: '" + row[ + "actioncategory"] + "' and policies: '" + row['policyname'] + "'") + + policies_id = "" + perimeter_id = "" + categoriesname = "" + dataids = "" + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + if (row['policyname'] == "" or row['policyname'] == "000000000000000000000000000000000000000000000000000"): + policyname = "Stanford Policy" + else: + policyname = row['policyname'] + policies_id = commonfunctions.get_policyid(policyname) + + if (row["actionperimetername"] == "" or row[ + "actionperimetername"] == "000000000000000000000000000000000000000000000000000"): + perimetername = "Read" + else: + perimetername = row["actionperimetername"] + perimeter_id = commonfunctions.get_actionperimeterid(perimetername) + + if (row["actioncategory"] == "" or row[ + "actioncategory"] == "000000000000000000000000000000000000000000000000000"): + categoriesname = "Action-Class:" + else: + categoriesname = row['actioncategory'] + categories_id = commonfunctions.get_actioncategoryid(categoriesname) + + if (row["actiondata"] == "" or row["actiondata"] == "000000000000000000000000000000000000000000000000000"): + dataids = "Severe" + else: + dataids = row['actiondata'] + dataids = commonfunctions.get_actiondataid(dataids, categories_id, policies_id) + + if (dataids == None): + dataids = "" + + if (row["policyname"] == "" or row["policyname"] == "000000000000000000000000000000000000000000000000000"): + policies_id = row["policyname"] + if (row["actionperimetername"] == "" or row[ + "actionperimetername"] == "000000000000000000000000000000000000000000000000000"): + perimeter_id = row["actionperimetername"] + if (row["actioncategory"] == "" or row[ + "actioncategory"] == "000000000000000000000000000000000000000000000000000"): + categories_id = row["actioncategory"] + if (row["actiondata"] == "" or row["actiondata"] == "000000000000000000000000000000000000000000000000000"): + dataids = row['actiondata'] + data = { + 'id': perimeter_id, + 'category_id': categories_id, + 'policy_id': policies_id, + 'data_id': dataids, + } + response = requests.post( + apis_urls.serverURL + "policies/" + str(policies_id) + "/" + apis_urls.assignementsactionAPI, + headers=headers, data=json.dumps(data)) + + if response.status_code == 200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Delete subject assignment by policy id,subject perimeter id, subject data id, subject category id +# 2) If the request code was 200 set the api response flag to true else false +@When('the user sets to delete the following subject assignment') +def step_impl(context): + logging.info("When the user sets to delete the following subject assignment") + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + model = getattr(context, "model", None) + for row in context.table: + logger.info( + "subject perimeter name: '" + row["subjectperimetername"] + "' subject data list: '" + row[ + "subjectdata"] + "' and subject category: '" + row[ + "subjectcategory"] + "' and policies: '" + row['policyname'] + "'") + + policies_id = "" + perimeter_id = "" + dataid = "" + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + policies_id = commonfunctions.get_policyid(row['policyname']) + perimeter_id = commonfunctions.get_subjectperimeterid(row['subjectperimetername']) + categories_id = commonfunctions.get_subjectcategoryid(row['subjectcategory']) + dataid = commonfunctions.get_subjectdataid(row["subjectdata"], categories_id, policies_id) + + response_assignment = requests.get( + apis_urls.serverURL + "policies/" + policies_id + "/" + apis_urls.assignementssubjectAPI + "/" + + perimeter_id + "/" + categories_id, headers=apis_urls.auth_headers) + logging.info(response_assignment.json()[apis_urls.assignementssubjectAPI]) + if len(response_assignment.json()[apis_urls.assignementssubjectAPI]) != 0: + for ids in dict(response_assignment.json()[apis_urls.assignementssubjectAPI]).keys(): + assignmentsidlist = response_assignment.json()[apis_urls.assignementssubjectAPI][str(ids)][ + 'assignments'] + if dataid in assignmentsidlist: + response = requests.delete( + apis_urls.serverURL + "policies/" + policies_id + "/" + apis_urls.assignementssubjectAPI + "/" + + perimeter_id + "/" + categories_id + "/" + dataid, headers=apis_urls.auth_headers) + + if response.status_code == 200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + + +# Step Definition Implementation: +# 1) Delete object assignment by policy id, object perimeter id, object data id, object category id +# 2) If the request code was 200 set the api response flag to true else false +@When('the user sets to delete the following object assignment') +def step_impl(context): + logging.info("When the user sets to delete the following object assignment") + + model = getattr(context, "model", None) + for row in context.table: + logger.info( + "object perimeter name: '" + row["objectperimetername"] + "' object data list: '" + row[ + "objectdata"] + "' and object category: '" + row[ + "objectcategory"] + "' and policies: '" + row['policyname'] + "'") + + policies_id = "" + perimeter_id = "" + datalistids = "" + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + policies_id = commonfunctions.get_policyid(row['policyname']) + perimeter_id = commonfunctions.get_objectperimeterid(row['objectperimetername']) + categories_id = commonfunctions.get_objectcategoryid(row['objectcategory']) + dataid = commonfunctions.get_objectdataid(row["objectdata"], categories_id, policies_id) + + response_assignment = requests.get( + apis_urls.serverURL + "policies/" + policies_id + "/" + apis_urls.assignementsobjectAPI + "/" + + perimeter_id + "/" + categories_id, headers=apis_urls.auth_headers) + if len(response_assignment.json()[apis_urls.assignementsobjectAPI]) != 0: + for ids in dict(response_assignment.json()[apis_urls.assignementsobjectAPI]).keys(): + assignmentsidlist = response_assignment.json()[apis_urls.assignementsobjectAPI][str(ids)][ + 'assignments'] + if dataid in assignmentsidlist: + response = requests.delete( + apis_urls.serverURL + "policies/" + policies_id + "/" + apis_urls.assignementsobjectAPI + "/" + + perimeter_id + "/" + categories_id + "/" + dataid, headers=headers) + + if response.status_code == 200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + + +# Step Definition Implementation: +# 1) Delete action assignment by policy id, action perimeter id, action data id, action category id +# 2) If the request code was 200 set the api response flag to true else false +@When('the user sets to delete the following action assignment') +def step_impl(context): + logging.info("When the user sets to delete the following action assignment") + + model = getattr(context, "model", None) + for row in context.table: + logger.info( + "action perimeter name: '" + row["actionperimetername"] + "' action data list: '" + row[ + "actiondata"] + "' and action category: '" + row[ + "actioncategory"] + "' and policies: '" + row['policyname'] + "'") + + policies_id = "" + perimeter_id = "" + datalistids = "" + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + policies_id = commonfunctions.get_policyid(row['policyname']) + perimeter_id = commonfunctions.get_actionperimeterid(row['actionperimetername']) + categories_id = commonfunctions.get_actioncategoryid(row['actioncategory']) + dataid = commonfunctions.get_actiondataid(row["actiondata"], categories_id, policies_id) + + response_assignment = requests.get( + apis_urls.serverURL + "policies/" + policies_id + "/" + apis_urls.assignementsactionAPI + "/" + + perimeter_id + "/" + categories_id, headers=apis_urls.auth_headers) + if len(response_assignment.json()[apis_urls.assignementsactionAPI]) != 0: + for ids in dict(response_assignment.json()[apis_urls.assignementsactionAPI]).keys(): + assignmentsidlist = response_assignment.json()[apis_urls.assignementsactionAPI][str(ids)][ + 'assignments'] + if dataid in assignmentsidlist: + response = requests.delete( + apis_urls.serverURL + "policies/" + policies_id + "/" + apis_urls.assignementsactionAPI + "/" + + perimeter_id + "/" + categories_id + "/" + dataid, headers=apis_urls.auth_headers) + + if response.status_code == 200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Get all the existing subject assignment per a given policy, subject perimeter and subject category by get request and put them into a table +# 2) Sort the table by subject perimeter name +# 3) Loop using both the expected and actual tables and assert the data row by row +@Then('the following subject assignment should be existed in the system') +def step_impl(context): + logger.info("Then the following subject assignment should be existed in the system") + model = getattr(context, "model", None) + apiresult = Table(names=('subjectperimetername', 'subjectcategory', 'subjectdata', 'policyname'), + dtype=('S100', 'S100', 'S100', 'S100')) + for row in context.table: + logger.info( + "subject perimeter name: '" + row["subjectperimetername"] + "' subject data list: '" + row[ + "subjectdata"] + "' and subject category: '" + row[ + "subjectcategory"] + "' and policies: '" + row['policyname'] + "'") + if (row['policyname'] == "" or row['subjectperimetername'] == ""): + response = requests.get( + apis_urls.serverURL + "policies/" + GeneralVariables.assignpolicyid[ + 'value'] + "/" + apis_urls.assignementssubjectAPI + "/" + + GeneralVariables.assignsubjectperimeterid['value'] + "/" + + GeneralVariables.assignsubjectcategoryid['value'], headers=apis_urls.auth_headers) + else: + response = requests.get( + apis_urls.serverURL + "policies/" + commonfunctions.get_policyid( + row['policyname']) + "/" + apis_urls.assignementssubjectAPI + "/" + + commonfunctions.get_subjectperimeterid(row['subjectperimetername']) + "/" + + commonfunctions.get_subjectcategoryid(row['subjectcategory']), headers=apis_urls.auth_headers) + if len(response.json()[apis_urls.assignementssubjectAPI]) != 0: + for ids in dict(response.json()[apis_urls.assignementssubjectAPI]).keys(): + apipolicies = "" + apisubjectname = commonfunctions.get_subjectperimetername( + response.json()[apis_urls.assignementssubjectAPI][str(ids)]['subject_id']) + apisubjectcategory = commonfunctions.get_subjectcategoryname( + response.json()[apis_urls.assignementssubjectAPI][str(ids)]['category_id']) + apiassignments = commonfunctions.get_subjectdataname( + response.json()[apis_urls.assignementssubjectAPI][str(ids)]['assignments'], + response.json()[apis_urls.assignementssubjectAPI][str(ids)]['category_id'], + response.json()[apis_urls.assignementssubjectAPI][str(ids)]['policy_id']) + apipolicies = commonfunctions.get_policyname( + response.json()[apis_urls.assignementssubjectAPI][str(ids)]['policy_id']) + if ((row['policyname'] == "" or row['subjectperimetername'] == "") and "".join(apiassignments)==""): + apiresult.add_row(vals=("", "", "", "")) + else: + apiresult.add_row(vals=( + apisubjectname, apisubjectcategory, apiassignments, apipolicies)) + else: + apiresult.add_row(vals=("", "", "", "")) + + apiresult.sort('subjectperimetername') + for row1, row2 in zip(context.table, apiresult): + logger.info("asserting the expected subject perimeter name: '" + str( + row1["subjectperimetername"]) + "' is the same as the actual existing '" + str( + row2["subjectperimetername"]) + "'") + assert str(row1["subjectperimetername"]) == str( + row2["subjectperimetername"]), "subject perimeter name is not correct!" + logger.info("assertion passed!") + + logger.info("asserting the expected subject data description: '" + str( + row1["subjectcategory"]) + "' is the same as the actual existing '" + str( + row2["subjectcategory"]) + "'") + assert str(row1["subjectcategory"]) == str( + row2["subjectcategory"]), "subject category is not correct!" + logger.info("assertion passed!") + + logger.info("asserting the expected subject data password: '" + str( + row1["subjectdata"]) + "' is the same as the actual existing '" + str( + row2["subjectdata"]) + "'") + assert str(row1["subjectdata"]) == str( + row2["subjectdata"]), "subject data list is not correct!" + logger.info("assertion passed!") + + #logger.info("asserting the expected policies: '" + str( + # row1["policyname"]) + "' is the same as the actual existing '" + str( + # row2["policyname"]) + "'") + #assert str(row1["policyname"]) == str(row2["policyname"]), " policies is not correct!" + #logger.info("assertion passed!") + +# Step Definition Implementation: +# 1) Get all the existing object assignment per a given policy, object perimeter and object category by get request and put them into a table +# 2) Sort the table by object perimeter name +# 3) Loop using both the expected and actual tables and assert the data row by row +@Then('the following object assignment should be existed in the system') +def step_impl(context): + logger.info("Then the following object assignment should be existed in the system") + model = getattr(context, "model", None) + apiresult = Table(names=('objectperimetername', 'objectcategory', 'objectdata', 'policyname'), + dtype=('S100', 'S100', 'S400', 'S100')) + for row in context.table: + if (row['policyname'] == "" or row['objectperimetername'] == ""): + response = requests.get( + apis_urls.serverURL + "policies/" + GeneralVariables.assignpolicyid[ + 'value'] + "/" + apis_urls.assignementsobjectAPI + "/" + + GeneralVariables.assignobjectperimeterid['value'] + "/" + + GeneralVariables.assignobjectcategoryid['value'], headers=apis_urls.auth_headers) + else: + response = requests.get( + apis_urls.serverURL + "policies/" + commonfunctions.get_policyid( + row['policyname']) + "/" + apis_urls.assignementsobjectAPI + "/" + + commonfunctions.get_objectperimeterid(row['objectperimetername']) + "/" + + commonfunctions.get_objectcategoryid(row['objectcategory']), headers=apis_urls.auth_headers) + + if len(response.json()[apis_urls.assignementsobjectAPI]) != 0: + for ids in dict(response.json()[apis_urls.assignementsobjectAPI]).keys(): + apipolicies = "" + apiobjectname = commonfunctions.get_objectperimetername( + response.json()[apis_urls.assignementsobjectAPI][str(ids)]['object_id']) + apiobjectcategory = commonfunctions.get_objectcategoryname( + response.json()[apis_urls.assignementsobjectAPI][str(ids)]['category_id']) + apiassignments = commonfunctions.get_objectdataname( + response.json()[apis_urls.assignementsobjectAPI][str(ids)]['assignments'], + response.json()[apis_urls.assignementsobjectAPI][str(ids)]['category_id'], + response.json()[apis_urls.assignementsobjectAPI][str(ids)]['policy_id']) + apipolicies = commonfunctions.get_policyname( + response.json()[apis_urls.assignementsobjectAPI][str(ids)]['policy_id']) + if ((row['policyname'] == "" or row['objectperimetername'] == "") and "".join(apiassignments) == ""): + apiresult.add_row(vals=("", "", "", "")) + else: + apiresult.add_row(vals=( + apiobjectname, apiobjectcategory, ",".join(apiassignments), apipolicies)) + else: + apiresult.add_row(vals=("", "", "", "")) + + apiresult.sort('objectperimetername') + for row1, row2 in zip(context.table, apiresult): + logger.info("asserting the expected object perimeter name: '" + str( + row1["objectperimetername"]) + "' is the same as the actual existing '" + str( + row2["objectperimetername"]) + "'") + assert str(row1["objectperimetername"]) == str( + row2["objectperimetername"]), "object perimeter name is not correct!" + logger.info("assertion passed!") + + logger.info("asserting the expected object data description: '" + str( + row1["objectcategory"]) + "' is the same as the actual existing '" + str( + row2["objectcategory"]) + "'") + assert str(row1["objectcategory"]) == str( + row2["objectcategory"]), "object category is not correct!" + logger.info("assertion passed!") + + logger.info("asserting the expected object data password: '" + str( + row1["objectdata"]) + "' is the same as the actual existing '" + str( + row2["objectdata"]) + "'") + assert str(row1["objectdata"]) == str( + row2["objectdata"]), "object data list is not correct!" + logger.info("assertion passed!") + + #logger.info("asserting the expected policies: '" + str( + # row1["policyname"]) + "' is the same as the actual existing '" + str( + # row2["policyname"]) + "'") + #assert str(row1["policyname"]) == str(row2["policyname"]), " policies is not correct!" + #logger.info("assertion passed!") + +# Step Definition Implementation: +# 1) Get all the existing action assignment per a given policy, action perimeter and action category by get request and put them into a table +# 2) Sort the table by action perimeter name +# 3) Loop using both the expected and actual tables and assert the data row by row +@Then('the following action assignment should be existed in the system') +def step_impl(context): + logger.info("Then the following action assignment should be existed in the system") + model = getattr(context, "model", None) + apiresult = Table(names=('actionperimetername', 'actioncategory', 'actiondata', 'policyname'), + dtype=('S100', 'S100', 'S100', 'S100')) + for row in context.table: + if (row['policyname'] == "" or row['actionperimetername'] == ""): + response = requests.get( + apis_urls.serverURL + "policies/" + GeneralVariables.assignpolicyid[ + 'value'] + "/" + apis_urls.assignementsactionAPI + "/" + + GeneralVariables.assignactionperimeterid['value'] + "/" + + GeneralVariables.assignactioncategoryid['value'], headers=apis_urls.auth_headers) + else: + response = requests.get( + apis_urls.serverURL + "policies/" + commonfunctions.get_policyid( + row['policyname']) + "/" + apis_urls.assignementsactionAPI + "/" + + commonfunctions.get_actionperimeterid(row['actionperimetername']) + "/" + + commonfunctions.get_actioncategoryid(row['actioncategory']), headers=apis_urls.auth_headers) + + if len(response.json()[apis_urls.assignementsactionAPI]) != 0: + for ids in dict(response.json()[apis_urls.assignementsactionAPI]).keys(): + apipolicies = "" + apiactionname = commonfunctions.get_actionperimetername( + response.json()[apis_urls.assignementsactionAPI][str(ids)]['action_id']) + apiactioncategory = commonfunctions.get_actioncategoryname( + response.json()[apis_urls.assignementsactionAPI][str(ids)]['category_id']) + apiassignments = commonfunctions.get_actiondataname( + response.json()[apis_urls.assignementsactionAPI][str(ids)]['assignments'], + response.json()[apis_urls.assignementsactionAPI][str(ids)]['category_id'], + response.json()[apis_urls.assignementsactionAPI][str(ids)]['policy_id']) + apipolicies = commonfunctions.get_policyname( + response.json()[apis_urls.assignementsactionAPI][str(ids)]['policy_id']) + logger.info(apiassignments) + if ((row['policyname'] == "" or row['actionperimetername'] == "") and "".join(apiassignments) == ""): + apiresult.add_row(vals=("", "", "", "")) + else: + apiresult.add_row(vals=( + apiactionname, apiactioncategory, apiassignments, apipolicies)) + else: + apiresult.add_row(vals=("", "", "", "")) + + apiresult.sort('actionperimetername') + for row1, row2 in zip(context.table, apiresult): + logger.info("asserting the expected action perimeter name: '" + str( + row1["actionperimetername"]) + "' is the same as the actual existing '" + str( + row2["actionperimetername"]) + "'") + assert str(row1["actionperimetername"]) == str( + row2["actionperimetername"]), "action perimeter name is not correct!" + logger.info("assertion passed!") + + logger.info("asserting the expected action data description: '" + str( + row1["actioncategory"]) + "' is the same as the actual existing '" + str( + row2["actioncategory"]) + "'") + assert str(row1["actioncategory"]) == str( + row2["actioncategory"]), "action category is not correct!" + logger.info("assertion passed!") + + logger.info("asserting the expected action data password: '" + str( + row1["actiondata"]) + "' is the same as the actual existing '" + str( + row2["actiondata"]) + "'") + assert str(row1["actiondata"]) == str( + row2["actiondata"]), "action data list is not correct!" + logger.info("assertion passed!") + + #logger.info("asserting the expected policies: '" + str( + # row1["policyname"]) + "' is the same as the actual existing '" + str( + # row2["policyname"]) + "'") + #assert str(row1["policyname"]) == str(row2["policyname"]), " policies is not correct!" + #logger.info("assertion passed!") diff --git a/moon_manager/tests/func_tests/features/steps/authorization.py b/moon_manager/tests/func_tests/features/steps/authorization.py new file mode 100644 index 00000000..5fa0ebe7 --- /dev/null +++ b/moon_manager/tests/func_tests/features/steps/authorization.py @@ -0,0 +1,217 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +from behave import * +from Static_Variables import GeneralVariables +from common_functions import * +import requests +import json +import logging +import paramiko + +apis_urls = GeneralVariables() +commonfunctions = commonfunctions() + +logger = logging.getLogger(__name__) + +# Step Definition Implementation: Incomplete Step +# 1) Connect to the server +# 2) Launch Moon Manager +# 3) Set the token in the global variables +@Given('the manager is configured') +def step_impl(context): + logger.info("\n") + logger.info("******************** Scenario: " + context.scenario.name + " ********************") + logger.info("Given the manager is configured") + api_responseflag = {'value': False} + client = paramiko.SSHClient() + client.load_system_host_keys() + # client.set_missing_host_key_policy(paramiko.WarningPolicy) + client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + client.connect(hostname=apis_urls.serverIP, port=apis_urls.serverport, username=apis_urls.serverusername, + password=apis_urls.serverpassword) + logger.info("before ") + stdin, stdout, stderr = client.exec_command( + + "sudo nohup hug -m moon_manager.server &" + " /usr/bin/python3 " + ) + #stdin, stdout, stderr = client.exec_command(" sudo /usr/local/bin/moon_manager add_user alaa00 admin") + #stdin, stdout, stderr = client.exec_command(" sudo /usr/local/bin/moon_manager get_key alaa00 admin ") + #logger.info(stdout.readlines()) + #GeneralVariables.auth_headers['X-Api-Key'] = str(stdout.readlines()) + #logger.info("token: " + str(GeneralVariables.auth_headers['X-Api-Key'])) + #logger.info("after ") + # client.close() + +# Step Definition Implementation: Incomplete Step +# 1) Get all the moon slaves +# 2) Loop on the slave by id and delete them +@Given('no slave is created') +def step_impl(context): + logger.info("\n") + logger.info("******************** Scenario: " + context.scenario.name + " ********************") + logger.info("Given no slave is created") + api_responseflag = {'value': False} + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + response = requests.get(apis_urls.serverURL + apis_urls.getslavesAPI, headers=apis_urls.auth_headers) + if len(response.json()[apis_urls.getslavesAPI]) != 0: + for ids in dict(response.json()[apis_urls.getslavesAPI]).keys(): + response = requests.delete(apis_urls.serverURL + apis_urls.slaveAPI + "/" + ids, + headers=headers) + +# Step Definition Implementation: +# 1) Create a slave by post request +# 2) Get the wrapper port id from the slave posting request & set it to the wrapperPort global variable +@Given('the slave is created') +def step_impl(context): + logger.info("Given the slave is created") + api_responseflag = {'value': False} + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + data = { + 'name': "default", + 'description': "description", + 'address': "111", + } + response = requests.post(apis_urls.serverURL + apis_urls.slaveAPI, headers=headers, + data=json.dumps(data)) + slaveid = list(response.json()[apis_urls.getslavesAPI])[0] + GeneralVariables.wrapperPort['value'] = str(response.json()[apis_urls.getslavesAPI][slaveid]['extra']['port']) + +# Step Definition Implementation: Incomplete Step +# 1) Check the Pipeline is up and running +@Given('the pipeline is running') +def step_impl(context): + logger.info("Given the pipeline is running") + +# Step Definition Implementation: Incomplete Step +# 1) Connect to the server +# 2) execute the authorization curl command using the wrapperPort +@Given('the following authorization request is granted through pipeline') +def step_impl(context): + logger.info("Given the following authorization request is granted through pipeline") + api_responseflag = {'value': False} + client = paramiko.SSHClient() + client.load_system_host_keys() + client.set_missing_host_key_policy(paramiko.WarningPolicy) + client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + client.connect(hostname=apis_urls.serverIP, port=apis_urls.serverport, username=apis_urls.serverusername, + password=apis_urls.serverpassword) + for row in context.table: + logger.info("curl http://" + str( + apis_urls.serverIP) + ":" + GeneralVariables.pipelinePort['value'] + "/authz/" + str( + row["subjectperimetername"]) + "/" + str(row["objectperimetername"]) + "/" + + str(row["actionperimetername"])) + stdin, stdout, stderr = client.exec_command("curl http://" + str( + apis_urls.serverIP) + ":" + GeneralVariables.pipelinePort['value'] + "/authz/" + str( + row["subjectperimetername"]) + "/" + str(row["objectperimetername"]) + "/" + + str(row["actionperimetername"])) + logger.info(stdout.readlines()) + GeneralVariables.actual_authresponse['value'] = str(stdout.readlines()) + +# Step Definition Implementation: Incomplete Step +# 1) Connect to the server +# 2) execute the authorization curl command using the wrapperPort +@Given('the following authorization request is granted through wrapper') +def step_impl(context): + logger.info("Given the following authorization request is granted through wrapper") + api_responseflag = {'value': False} + client = paramiko.SSHClient() + client.load_system_host_keys() + client.set_missing_host_key_policy(paramiko.WarningPolicy) + client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + client.connect(hostname=apis_urls.serverIP, port=apis_urls.serverport, username=apis_urls.serverusername, + password=apis_urls.serverpassword) + for row in context.table: + logger.info("curl http://" + str( + apis_urls.serverIP) + ":" + GeneralVariables.wrapperPort['value'] + "/authz/" + str(row[ + "keystone_project_id"]) + "/" + str( + row["subjectperimetername"]) + "/" + str(row["objectperimetername"]) + "/" + + str(row["actionperimetername"])) + stdin, stdout, stderr = client.exec_command("curl http://" + str( + apis_urls.serverIP) + ":" + GeneralVariables.wrapperPort['value'] + "/authz/" + str(row[ + "keystone_project_id"]) + "/" + str( + row["subjectperimetername"]) + "/" + str(row["objectperimetername"]) + "/" + + str(row["actionperimetername"])) + logger.info(stdout.readlines()) + GeneralVariables.actual_authresponse['value'] = str(stdout.readlines()) + +# Step Definition Implementation: Incomplete Step +# 1) Connect to the server +# 2) execute the authorization curl command using the pipelinePort +# 3) set the actual_authresponse global variable with the curl response +@When('the following authorization request is sent through pipeline') +def step_impl(context): + logger.info("Given the following authorization request is sent through pipeline") + api_responseflag = {'value': False} + client = paramiko.SSHClient() + client.load_system_host_keys() + client.set_missing_host_key_policy(paramiko.WarningPolicy) + client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + client.connect(hostname=apis_urls.serverIP, port=apis_urls.serverport, username=apis_urls.serverusername, + password=apis_urls.serverpassword) + + for row in context.table: + logger.info("curl http://" + str( + apis_urls.serverIP) + ":" + GeneralVariables.pipelinePort['value'] + "/authz/" + str( + row["subjectperimetername"]) + "/" + str(row["objectperimetername"]) + "/" + + str(row["actionperimetername"])) + stdin, stdout, stderr = client.exec_command("curl http://" + str( + apis_urls.serverIP) + ":" + GeneralVariables.pipelinePort['value'] + "/authz/" + str( + row["subjectperimetername"]) + "/" + str(row["objectperimetername"]) + "/" + + str(row["actionperimetername"])) + logger.info(stdout.readlines()) + GeneralVariables.actual_authresponse['value'] = str(stdout.readlines()) + +# Step Definition Implementation: Incomplete Step +# 1) Connect to the server +# 2) execute the authorization curl command using the pipelinePort +# 3) set the actual_authresponse global variable with the curl response +@When('the following authorization request is sent through wrapper') +def step_impl(context): + logger.info("Given the following authorization request is sent through wrapper") + api_responseflag = {'value': False} + client = paramiko.SSHClient() + client.load_system_host_keys() + client.set_missing_host_key_policy(paramiko.WarningPolicy) + client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + client.connect(hostname=apis_urls.serverIP, port=apis_urls.serverport, username=apis_urls.serverusername, + password=apis_urls.serverpassword) + + for row in context.table: + logger.info("curl http://" + str( + apis_urls.serverIP) + ":" + GeneralVariables.wrapperPort['value'] + "/authz/" + str(row[ + "keystone_project_id"]) + "/" + str( + row["subjectperimetername"]) + "/" + str(row["objectperimetername"]) + "/" + + str(row["actionperimetername"])) + stdin, stdout, stderr = client.exec_command("curl http://" + str( + apis_urls.serverIP) + ":" + GeneralVariables.wrapperPort['value'] + "/authz/" + str(row[ + "keystone_project_id"]) + "/" + str( + row["subjectperimetername"]) + "/" + str(row["objectperimetername"]) + "/" + + str(row["actionperimetername"])) + logger.info(stdout.readlines()) + GeneralVariables.actual_authresponse['value'] = str(stdout.readlines()) + +# Step Definition Implementation: Untested Step +# 1) Assert that the actual authresponse is the same as the expected. +@Then('the authorization response should be the following') +def step_impl(context): + logger.info("Then the authorization response should be the following") + for row in context.table: + logger.info("asserting the expected api response: '" + row["auth_response"] + "' and the actual response: '" + + GeneralVariables.actual_authresponse['value'] + "'") + assert row["auth_response"] == GeneralVariables.actual_authresponse[ + 'value'], "Validation is not correct, Expected: " + \ + row[ + "auth_response"] + " but the API response was: " + \ + GeneralVariables.actual_authresponse['value'] + logger.info("assertion passed!") diff --git a/moon_manager/tests/func_tests/features/steps/common_functions.py b/moon_manager/tests/func_tests/features/steps/common_functions.py new file mode 100644 index 00000000..b9b9f0bc --- /dev/null +++ b/moon_manager/tests/func_tests/features/steps/common_functions.py @@ -0,0 +1,279 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +from behave import * +from steps.Static_Variables import GeneralVariables +import requests +import json +import logging + + +logger = logging.getLogger(__name__) + +class commonfunctions: + apis_urls = GeneralVariables() + + def get_subjectcategoryid(self, subjectcategoryname): + response = requests.get(self.apis_urls.serverURL + self.apis_urls.metadatasubjectcategoryAPI,headers=self.apis_urls.auth_headers) + if len(response.json()[self.apis_urls.metadatasubjectcategoryAPI]) != 0: + for ids in dict(response.json()[self.apis_urls.metadatasubjectcategoryAPI]).keys(): + if (response.json()[self.apis_urls.metadatasubjectcategoryAPI][ids]['name'] == subjectcategoryname): + return response.json()[self.apis_urls.metadatasubjectcategoryAPI][ids]['id'] + + def get_objectcategoryid(self, objectcategoryname): + response = requests.get(self.apis_urls.serverURL + self.apis_urls.metadataobjectcategoryAPI,headers=self.apis_urls.auth_headers) + if len(response.json()[self.apis_urls.metadataobjectcategoryAPI]) != 0: + for ids in dict(response.json()[self.apis_urls.metadataobjectcategoryAPI]).keys(): + if (response.json()[self.apis_urls.metadataobjectcategoryAPI][ids]['name'] == objectcategoryname): + return response.json()[self.apis_urls.metadataobjectcategoryAPI][ids]['id'] + + def get_actioncategoryid(self, actioncategoryname): + response = requests.get(self.apis_urls.serverURL + self.apis_urls.metadataactioncategoryAPI,headers=self.apis_urls.auth_headers) + if len(response.json()[self.apis_urls.metadataactioncategoryAPI]) != 0: + for ids in dict(response.json()[self.apis_urls.metadataactioncategoryAPI]).keys(): + if (response.json()[self.apis_urls.metadataactioncategoryAPI][ids]['name'] == actioncategoryname): + return response.json()[self.apis_urls.metadataactioncategoryAPI][ids]['id'] + + def get_metaruleid(self, metarulename): + response = requests.get(self.apis_urls.serverURL + self.apis_urls.metarulesAPI,headers=self.apis_urls.auth_headers) + if len(response.json()[self.apis_urls.metarulesAPI]) != 0: + for ids in dict(response.json()[self.apis_urls.metarulesAPI]).keys(): + if (response.json()[self.apis_urls.metarulesAPI][ids]['name'] == metarulename): + return ids + + def get_modelid(self, modelname): + response = requests.get(self.apis_urls.serverURL + self.apis_urls.modelAPI,headers=self.apis_urls.auth_headers) + if len(response.json()[self.apis_urls.modelAPI]) != 0: + for ids in dict(response.json()[self.apis_urls.modelAPI]).keys(): + if (response.json()[self.apis_urls.modelAPI][ids]['name'] == modelname): + return ids + + def get_policyid(self, policyname): + response = requests.get(self.apis_urls.serverURL + self.apis_urls.policyAPI,headers=self.apis_urls.auth_headers) + if len(response.json()[self.apis_urls.policyAPI]) != 0: + for ids in dict(response.json()[self.apis_urls.policyAPI]).keys(): + if (response.json()[self.apis_urls.policyAPI][ids]['name'] == policyname): + return ids + + def get_subjectperimeterid(self,subjectperimeter ): + response = requests.get(self.apis_urls.serverURL + self.apis_urls.perimetersubjectAPI,headers=self.apis_urls.auth_headers) + if len(response.json()[self.apis_urls.perimetersubjectAPI]) != 0: + for ids in dict(response.json()[self.apis_urls.perimetersubjectAPI]).keys(): + if (response.json()[self.apis_urls.perimetersubjectAPI][ids]['name'] == subjectperimeter): + return ids + + def get_objectperimeterid(self,objectperimeter ): + response = requests.get(self.apis_urls.serverURL + self.apis_urls.perimeterobjectAPI,headers=self.apis_urls.auth_headers) + if len(response.json()[self.apis_urls.perimeterobjectAPI]) != 0: + for ids in dict(response.json()[self.apis_urls.perimeterobjectAPI]).keys(): + if (response.json()[self.apis_urls.perimeterobjectAPI][ids]['name'] == objectperimeter): + return ids + + def get_actionperimeterid(self, actionperimeter): + response = requests.get(self.apis_urls.serverURL + self.apis_urls.perimeteractionAPI,headers=self.apis_urls.auth_headers) + if len(response.json()[self.apis_urls.perimeteractionAPI]) != 0: + for ids in dict(response.json()[self.apis_urls.perimeteractionAPI]).keys(): + if (response.json()[self.apis_urls.perimeteractionAPI][ids]['name'] == actionperimeter): + return ids + + def get_subjectdataid(self,subjectdataname,subjectcategoryid,policyid ): + response_data = requests.get( + self.apis_urls.serverURL + "policies/" + policyid + "/" + self.apis_urls.datasubjectAPI + "/" + subjectcategoryid,headers=self.apis_urls.auth_headers) + if(len(response_data.json()[self.apis_urls.datasubjectAPI]))!=0: + subjectdataidslist = [] + matcheddataidslist = [] + dataids=response_data.json()[self.apis_urls.datasubjectAPI][0]['data'] + for ids in dataids: + apisubjectdataid = response_data.json()[self.apis_urls.datasubjectAPI][0]['data'][str(ids)]['id'] + subjectdataidslist.append(apisubjectdataid) + + if ((str(subjectdataname)).find(",") != -1): + datanameslist = subjectdataname.split(",") + for dataname in datanameslist: + for data_id in subjectdataidslist: + if ((response_data.json()[self.apis_urls.datasubjectAPI][0]['data'][str(data_id)][ + 'name']) == dataname): + matcheddataidslist.append(data_id) + return ",".join(matcheddataidslist) + else: + for data_id in subjectdataidslist: + if (( + response_data.json()[self.apis_urls.datasubjectAPI][0]['data'][str(data_id)]['name']) == subjectdataname): + return data_id + + def get_objectdataid(self,objectdataname,objectcategoryid,policyid ): + response_data = requests.get( + self.apis_urls.serverURL + self.apis_urls.policyAPI + "/" + policyid + "/" + self.apis_urls.dataobjectAPI + "/" + objectcategoryid,headers=self.apis_urls.auth_headers) + if (len(response_data.json()[self.apis_urls.dataobjectAPI])) != 0: + objectdataidslist = [] + matcheddataidslist=[] + for ids in response_data.json()[ self.apis_urls.dataobjectAPI][0]['data']: + apiobjectdataid = response_data.json()[ self.apis_urls.dataobjectAPI][0]['data'][str(ids)]['id'] + objectdataidslist.append(apiobjectdataid) + if ((str(objectdataname)).find(",") != -1): + datanameslist = objectdataname.split(",") + for dataname in datanameslist: + for data_id in objectdataidslist: + if ((response_data.json()[self.apis_urls.dataobjectAPI][0]['data'][str(data_id)]['name']) == dataname): + matcheddataidslist.append(data_id) + return ",".join(matcheddataidslist) + + else: + for data_id in objectdataidslist: + if ((response_data.json()[self.apis_urls.dataobjectAPI][0]['data'][str(data_id)]['name']) == objectdataname): + return data_id + + def get_actiondataid(self,actiondataname,actioncategoryid,policyid ): + response_data = requests.get( + self.apis_urls.serverURL + self.apis_urls.policyAPI + "/" + policyid + "/" + self.apis_urls.dataactionAPI + "/" + actioncategoryid,headers=self.apis_urls.auth_headers) + if (len(response_data.json()[self.apis_urls.dataactionAPI])) != 0: + actiondataidslist = [] + matcheddataidslist = [] + for ids in response_data.json()[self.apis_urls.dataactionAPI][0]['data']: + apiactiondataid = response_data.json()[self.apis_urls.dataactionAPI][0]['data'][str(ids)]['id'] + actiondataidslist.append(apiactiondataid) + if ((str(actiondataname)).find(",") != -1): + datanameslist = actiondataname.split(",") + for dataname in datanameslist: + for data_id in actiondataidslist: + if ((response_data.json()[self.apis_urls.dataactionAPI][0]['data'][str(data_id)][ + 'name']) == dataname): + matcheddataidslist.append(data_id) + return ",".join(matcheddataidslist) + else: + for data_id in actiondataidslist: + if ((response_data.json()[self.apis_urls.dataactionAPI][0]['data'][str(data_id)]['name']) == actiondataname): + return data_id + + def get_subjectcategoryname(self, subjectcategoryid): + response = requests.get(self.apis_urls.serverURL + self.apis_urls.metadatasubjectcategoryAPI,headers=self.apis_urls.auth_headers) + if len(response.json()[self.apis_urls.metadatasubjectcategoryAPI]) != 0: + for ids in dict(response.json()[self.apis_urls.metadatasubjectcategoryAPI]).keys(): + if (response.json()[self.apis_urls.metadatasubjectcategoryAPI][ids]['id'] == subjectcategoryid): + return response.json()[self.apis_urls.metadatasubjectcategoryAPI][ids]['name'] + + def get_objectcategoryname(self, objectcategoryid): + response = requests.get(self.apis_urls.serverURL + self.apis_urls.metadataobjectcategoryAPI,headers=self.apis_urls.auth_headers) + if len(response.json()[self.apis_urls.metadataobjectcategoryAPI]) != 0: + for ids in dict(response.json()[self.apis_urls.metadataobjectcategoryAPI]).keys(): + if (response.json()[self.apis_urls.metadataobjectcategoryAPI][ids]['id'] == objectcategoryid): + return response.json()[self.apis_urls.metadataobjectcategoryAPI][ids]['name'] + + def get_actioncategoryname(self, actioncategoryid): + response = requests.get(self.apis_urls.serverURL + self.apis_urls.metadataactioncategoryAPI,headers=self.apis_urls.auth_headers) + if len(response.json()[self.apis_urls.metadataactioncategoryAPI]) != 0: + for ids in dict(response.json()[self.apis_urls.metadataactioncategoryAPI]).keys(): + if (response.json()[self.apis_urls.metadataactioncategoryAPI][ids]['id'] == actioncategoryid): + return response.json()[self.apis_urls.metadataactioncategoryAPI][ids]['name'] + + def get_metarulename(self, metaruleid): + response = requests.get(self.apis_urls.serverURL + self.apis_urls.metarulesAPI,headers=self.apis_urls.auth_headers) + if len(response.json()[self.apis_urls.metarulesAPI]) != 0: + for id in dict(response.json()[self.apis_urls.metarulesAPI]).keys(): + if (id == metaruleid): + return response.json()[self.apis_urls.metarulesAPI][id]['name'] + + def get_modelname(self, modelid): + response = requests.get(self.apis_urls.serverURL + self.apis_urls.modelAPI,headers=self.apis_urls.auth_headers) + if len(response.json()[self.apis_urls.modelAPI]) != 0: + for id in dict(response.json()[self.apis_urls.modelAPI]).keys(): + if (id == modelid): + return response.json()[self.apis_urls.modelAPI][id]['name'] + + def get_policyname(self, policyid): + response = requests.get(self.apis_urls.serverURL + self.apis_urls.policyAPI,headers=self.apis_urls.auth_headers) + if len(response.json()[self.apis_urls.policyAPI]) != 0: + for id in dict(response.json()[self.apis_urls.policyAPI]).keys(): + if (id == policyid): + return response.json()[self.apis_urls.policyAPI][id]['name'] + + def get_subjectperimetername(self, subjectperimeterid): + response = requests.get(self.apis_urls.serverURL + self.apis_urls.perimetersubjectAPI,headers=self.apis_urls.auth_headers) + if len(response.json()[self.apis_urls.perimetersubjectAPI]) != 0: + for id in dict(response.json()[self.apis_urls.perimetersubjectAPI]).keys(): + if (id == subjectperimeterid): + return response.json()[self.apis_urls.perimetersubjectAPI][id]['name'] + + def get_objectperimetername(self, objectperimeterid): + response = requests.get(self.apis_urls.serverURL + self.apis_urls.perimeterobjectAPI,headers=self.apis_urls.auth_headers) + if len(response.json()[self.apis_urls.perimeterobjectAPI]) != 0: + for id in dict(response.json()[self.apis_urls.perimeterobjectAPI]).keys(): + if (id == objectperimeterid): + return response.json()[self.apis_urls.perimeterobjectAPI][id]['name'] + + def get_actionperimetername(self, actionperimeterid): + response = requests.get(self.apis_urls.serverURL + self.apis_urls.perimeteractionAPI,headers=self.apis_urls.auth_headers) + if len(response.json()[self.apis_urls.perimeteractionAPI]) != 0: + for id in dict(response.json()[self.apis_urls.perimeteractionAPI]).keys(): + if (id == actionperimeterid): + return response.json()[self.apis_urls.perimeteractionAPI][id]['name'] + + def get_subjectdataname(self, subjectdataids, subjectcategoryid, policyid): + subjectdatanames=[] + for subjectdataid in subjectdataids: + response_data = requests.get( + self.apis_urls.serverURL + "policies/" + policyid + "/" + self.apis_urls.datasubjectAPI + "/" + subjectcategoryid+"/"+subjectdataid,headers=self.apis_urls.auth_headers) + + subjectdataidslist = [] + if(response_data.status_code==200): + for ids in response_data.json()[self.apis_urls.datasubjectAPI][0]['data']: + apisubjectdataid = response_data.json()[self.apis_urls.datasubjectAPI][0]['data'][str(ids)]['id'] + subjectdataidslist.append(apisubjectdataid) + + for data_id in subjectdataidslist: + if (str((response_data.json()[self.apis_urls.datasubjectAPI][0]['data'][str(data_id)][ + 'id'])) == subjectdataid): + subjectdatanames.append(str(response_data.json()[self.apis_urls.datasubjectAPI][0]['data'][str(data_id)]['name'])) + else: + subjectdataidslist = "" + return subjectdatanames + + def get_objectdataname(self, objectdataids, objectcategoryid, policyid): + objectdatanames = [] + for objectdataid in objectdataids: + response_data = requests.get( + self.apis_urls.serverURL + "policies/" + policyid + "/" + self.apis_urls.dataobjectAPI + "/" + objectcategoryid + "/" + objectdataid,headers=self.apis_urls.auth_headers) + objectdataidslist = [] + if (response_data.status_code == 200): + for ids in response_data.json()[self.apis_urls.dataobjectAPI][0]['data']: + apiobjectdataid = response_data.json()[self.apis_urls.dataobjectAPI][0]['data'][str(ids)]['id'] + objectdataidslist.append(apiobjectdataid) + for data_id in objectdataidslist: + if (str((response_data.json()[self.apis_urls.dataobjectAPI][0]['data'][str(data_id)][ + 'id'])) == objectdataid): + objectdatanames.append( + str(response_data.json()[self.apis_urls.dataobjectAPI][0]['data'][str(data_id)]['name'])) + else: + objectdataidslist = "" + return objectdatanames + + def get_actiondataname(self, actiondataids, actioncategoryid, policyid): + actiondatanames = [] + for actiondataid in actiondataids: + response_data = requests.get( + self.apis_urls.serverURL + "policies/" + policyid + "/" + self.apis_urls.dataactionAPI + "/" + actioncategoryid + "/" + actiondataid,headers=self.apis_urls.auth_headers) + #logger.info(response_data.json()[self.apis_urls.dataactionAPI][0]) + + actiondataidslist = [] + if (response_data.status_code == 200): + for ids in response_data.json()[self.apis_urls.dataactionAPI][0]['data']: + apiactiondataid = response_data.json()[self.apis_urls.dataactionAPI][0]['data'][str(ids)]['id'] + actiondataidslist.append(apiactiondataid) + logging.info(actiondataidslist) + for data_id in actiondataidslist: + if (str((response_data.json()[self.apis_urls.dataactionAPI][0]['data'][str(data_id)][ + 'id'])) == actiondataid): + actiondatanames.append( + str(response_data.json()[self.apis_urls.dataactionAPI][0]['data'][str(data_id)]['name'])) + else: + actiondataidslist = "" + return actiondatanames \ No newline at end of file diff --git a/moon_manager/tests/func_tests/features/steps/data.py b/moon_manager/tests/func_tests/features/steps/data.py new file mode 100644 index 00000000..67d743c2 --- /dev/null +++ b/moon_manager/tests/func_tests/features/steps/data.py @@ -0,0 +1,629 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +from behave import * +from Static_Variables import GeneralVariables +from astropy.table import Table, Column +from common_functions import * +import requests +import json +import logging + +apis_urls = GeneralVariables() +commonfunctions = commonfunctions() + +logger = logging.getLogger(__name__) + +# Step Definition Implementation: +# 1) Get all the existing subject meta data in the system by getting the policies then their models then the model attached meta rules and then the categories +# 2) Get subject data using both the policy id & the category id +# 3) Loop by data id and delete it +@Given('the system has no subject data') +def step_impl(context): + logger.info("Given the system has no subject data") + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + response_policies = requests.get(apis_urls.serverURL + apis_urls.policyAPI,headers=apis_urls.auth_headers) + if len(response_policies.json()[apis_urls.policyAPI]) != 0: + for policies_ids in dict(response_policies.json()[apis_urls.policyAPI]).keys(): + subjectcategoryidslist = [] + modelid = response_policies.json()[apis_urls.policyAPI][policies_ids]['model_id'] + if (modelid != None and modelid != ""): + metaruleslist = \ + requests.get(apis_urls.serverURL + apis_urls.modelAPI,headers=apis_urls.auth_headers).json()[apis_urls.modelAPI][modelid][ + 'meta_rules'] + for metarule_ids in metaruleslist: + categorieslist = \ + requests.get(apis_urls.serverURL + apis_urls.metarulesAPI,headers=apis_urls.auth_headers).json()[apis_urls.metarulesAPI][ + metarule_ids]['subject_categories'] + for categoryid in categorieslist: + if (categoryid not in subjectcategoryidslist): + subjectcategoryidslist.append(categoryid) + + for categoryid in subjectcategoryidslist: + response_data = requests.get( + apis_urls.serverURL + apis_urls.policyAPI + "/" + policies_ids + "/" + apis_urls.datasubjectAPI + "/" + categoryid,headers=apis_urls.auth_headers) + for ids in response_data.json()[apis_urls.datasubjectAPI][0]['data']: + data_id = response_data.json()[apis_urls.datasubjectAPI][0]['data'][str(ids)]['id'] + requests.delete( + apis_urls.serverURL + apis_urls.policyAPI + "/" + policies_ids + "/" + apis_urls.datasubjectAPI + "/" + categoryid + "/" + data_id, + headers=headers) + +# Step Definition Implementation: +# 1) Post subject data using the policy id & the category id +@Given('the following subject data exists') +def step_impl(context): + logger.info("Given the following subject data exists") + model = getattr(context, "model", None) + for row in context.table: + logger.info( + "subject data name: '" + row["subjectdataname"] + "' subject data description: '" + row[ + "subjectdatadescription"] + "' and subject category: '" + row[ + "subjectcategory"] + "' and policies: '" + row['policyname'] + "'") + + policies_id = "" + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + if (len(row['policyname']) > 25): + policies_id = row['policyname'] + else: + policies_id = commonfunctions.get_policyid(row['policyname']) + + if (len(row['subjectcategory']) > 25): + categories_id = row['subjectcategory'] + else: + categories_id = commonfunctions.get_subjectcategoryid(row['subjectcategory']) + + data = { + 'name': row["subjectdataname"], + 'description': row["subjectdatadescription"], + + } + response = requests.post( + apis_urls.serverURL + "policies/" + str(policies_id) + "/" + apis_urls.datasubjectAPI + "/" + str( + categories_id), headers=headers, data=json.dumps(data)) + +# Step Definition Implementation: +# 1) Get all the existing object meta data in the system by getting the policies then their models then the model attached meta rules and then the categories +# 2) Get object data using both the policy id & the category id +# 3) Loop by data id and delete it +@Given('the system has no object data') +def step_impl(context): + logger.info("Given the system has no object data") + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + response_policies = requests.get(apis_urls.serverURL + apis_urls.policyAPI,headers=apis_urls.auth_headers) + if len(response_policies.json()[apis_urls.policyAPI]) != 0: + for policies_ids in dict(response_policies.json()[apis_urls.policyAPI]).keys(): + objectcategoryidslist = [] + modelid = response_policies.json()[apis_urls.policyAPI][policies_ids]['model_id'] + if (modelid != None and modelid != ""): + metaruleslist = \ + requests.get(apis_urls.serverURL + apis_urls.modelAPI,headers=apis_urls.auth_headers).json()[apis_urls.modelAPI][modelid][ + 'meta_rules'] + for metarule_ids in metaruleslist: + for categoryid in \ + (requests.get(apis_urls.serverURL + apis_urls.metarulesAPI,headers=apis_urls.auth_headers)).json()[apis_urls.metarulesAPI][ + metarule_ids][ + 'object_categories']: + if (categoryid not in objectcategoryidslist): + objectcategoryidslist.append(categoryid) + + for categoryid in objectcategoryidslist: + response_data = requests.get( + apis_urls.serverURL + apis_urls.policyAPI + "/" + policies_ids + "/" + apis_urls.dataobjectAPI + "/" + categoryid,headers=apis_urls.auth_headers) + for ids in response_data.json()[apis_urls.dataobjectAPI][0]['data']: + data_id = response_data.json()[apis_urls.dataobjectAPI][0]['data'][str(ids)]['id'] + requests.delete( + apis_urls.serverURL + apis_urls.policyAPI + "/" + policies_ids + "/" + apis_urls.dataobjectAPI + "/" + categoryid + "/" + data_id, + headers=headers) + +# Step Definition Implementation: +# 1) Post object data using the policy id & the category id +@Given('the following object data exists') +def step_impl(context): + model = getattr(context, "model", None) + for row in context.table: + logger.info( + "subject data name: '" + row["objectdataname"] + "' object data description: '" + row[ + "objectdatadescription"] + "' and object category: '" + row[ + "objectcategory"] + "' and policies: '" + row['policyname'] + "'") + + policies_id = "" + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + if (len(row['policyname']) > 25): + policies_id = row['policyname'] + else: + policies_id = commonfunctions.get_policyid(row['policyname']) + + if (len(row['objectcategory']) > 25): + categories_id = row['objectcategory'] + else: + categories_id = commonfunctions.get_objectcategoryid(row['objectcategory']) + + data = { + 'name': row["objectdataname"], + 'description': row["objectdatadescription"], + + } + response = requests.post( + apis_urls.serverURL + "policies/" + str(policies_id) + "/" + apis_urls.dataobjectAPI + "/" + str( + categories_id), headers=headers, data=json.dumps(data)) + +# Step Definition Implementation: +# 1) Get all the existing action meta data in the system by getting the policies then their models then the model attached meta rules and then the categories +# 2) Get action data using both the policy id & the category id +# 3) Loop by data id and delete it +@Given('the system has no action data') +def step_impl(context): + logger.info("Given the system has no action data") + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + actioncategoryidslist = [] + response_policies = requests.get(apis_urls.serverURL + apis_urls.policyAPI,headers=apis_urls.auth_headers) + if len(response_policies.json()[apis_urls.policyAPI]) != 0: + for policies_ids in dict(response_policies.json()[apis_urls.policyAPI]).keys(): + actioncategoryidslist = [] + modelid = response_policies.json()[apis_urls.policyAPI][policies_ids]['model_id'] + if (modelid != None and modelid != ""): + metaruleslist = \ + requests.get(apis_urls.serverURL + apis_urls.modelAPI,headers=apis_urls.auth_headers).json()[apis_urls.modelAPI][modelid][ + 'meta_rules'] + for metarule_ids in metaruleslist: + for categoryid in \ + (requests.get(apis_urls.serverURL + apis_urls.metarulesAPI,headers=apis_urls.auth_headers)).json()[apis_urls.metarulesAPI][ + metarule_ids][ + 'action_categories']: + if (categoryid not in actioncategoryidslist): + actioncategoryidslist.append(categoryid) + + for categoryid in actioncategoryidslist: + response_data = requests.get( + apis_urls.serverURL + apis_urls.policyAPI + "/" + policies_ids + "/" + apis_urls.dataactionAPI + "/" + categoryid,headers=apis_urls.auth_headers) + for ids in response_data.json()[apis_urls.dataactionAPI][0]['data']: + data_id = response_data.json()[apis_urls.dataactionAPI][0]['data'][str(ids)]['id'] + requests.delete( + apis_urls.serverURL + apis_urls.policyAPI + "/" + policies_ids + "/" + apis_urls.dataactionAPI + "/" + categoryid + "/" + data_id, + headers=headers) + +# Step Definition Implementation: +# 1) Post action data using the policy id & the category id +@Given('the following action data exists') +def step_impl(context): + model = getattr(context, "model", None) + for row in context.table: + logger.info( + "subject data name: '" + row["actiondataname"] + "' action data description: '" + row[ + "actiondatadescription"] + "' and action category: '" + row[ + "actioncategory"] + "' and policies: '" + row['policyname'] + "'") + + policies_id = "" + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + if (len(row['policyname']) > 25): + policies_id = row['policyname'] + else: + policies_id = commonfunctions.get_policyid(row['policyname']) + + if (len(row['actioncategory']) > 25): + categories_id = row['actioncategory'] + else: + categories_id = commonfunctions.get_actioncategoryid(row['actioncategory']) + + data = { + 'name': row["actiondataname"], + 'description': row["actiondatadescription"], + + } + response = requests.post( + apis_urls.serverURL + "policies/" + str(policies_id) + "/" + apis_urls.dataactionAPI + "/" + str( + categories_id), headers=headers, data=json.dumps(data)) + +# Step Definition Implementation: +# 1) Add subject data using the post request +# 2) If the request code was 200 set the api response flag to true else false +@When('the user sets to add the following subject data') +def step_impl(context): + logger.info("When the user sets to add the following subject data") + model = getattr(context, "model", None) + for row in context.table: + logger.info( + "subject data name: '" + row["subjectdataname"] + "' subject data description: '" + row[ + "subjectdatadescription"] + "' and subject category: '" + row[ + "subjectcategory"] + "' and policies: '" + row['policyname'] + "'") + + policies_id = "" + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + if (len(row['policyname']) > 25): + policies_id = row['policyname'] + else: + policies_id = commonfunctions.get_policyid(row['policyname']) + + if (len(row['subjectcategory']) > 25): + categories_id = row['subjectcategory'] + else: + categories_id = commonfunctions.get_subjectcategoryid(row['subjectcategory']) + + data = { + 'name': row["subjectdataname"], + 'description': row["subjectdatadescription"], + + } + response = requests.post( + apis_urls.serverURL + "policies/" + str(policies_id) + "/" + apis_urls.datasubjectAPI + "/" + str( + categories_id), headers=headers, data=json.dumps(data)) + + if response.status_code == 200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Delete subject data by policy id, subject data id, subject category id +# 2) If the request code was 200 set the api response flag to true else false +@When('the user sets to delete the following subject data') +def step_impl(context): + logging.info("When the user sets to delete the following subject data") + + model = getattr(context, "model", None) + for row in context.table: + + logger.info("subject data name:'" + row["subjectdataname"] + "' and subject category name:'" + row[ + "subjectcategory"] + "' and policy name:'" + row["policyname"] + "'") + + policies_id = [] + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + response_data = requests.delete( + apis_urls.serverURL + apis_urls.policyAPI + "/" + commonfunctions.get_policyid(row[ + "policyname"]) + "/" + apis_urls.datasubjectAPI + "/" + commonfunctions.get_subjectcategoryid( + row["subjectcategory"]) + "/" + commonfunctions.get_subjectdataid(row["subjectdataname"], + commonfunctions.get_subjectcategoryid( + row["subjectcategory"]), + commonfunctions.get_policyid( + row["policyname"])), + headers=headers) + + if response_data.status_code == 200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Add object data using the post request +# 2) If the request code was 200 set the api response flag to true else false +@When('the user sets to add the following object data') +def step_impl(context): + logger.info("When the user sets to add the following object data") + model = getattr(context, "model", None) + for row in context.table: + logger.info( + "object data name: '" + row["objectdataname"] + "' object data description: '" + row[ + "objectdatadescription"] + "' and object category: '" + row[ + "objectcategory"] + "' and policies: '" + row['policyname'] + "'") + + policies_list = [] + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + if (len(row['policyname']) > 25): + policies_id = row['policyname'] + else: + policies_id = commonfunctions.get_policyid(row['policyname']) + + if (len(row['objectcategory']) > 25): + categories_id = row['objectcategory'] + else: + categories_id = commonfunctions.get_objectcategoryid(row['objectcategory']) + + data = { + 'name': row["objectdataname"], + 'description': row["objectdatadescription"], + } + + response = requests.post( + apis_urls.serverURL + "policies/" + str(policies_id) + "/" + apis_urls.dataobjectAPI + "/" + str( + categories_id), headers=headers, data=json.dumps(data)) + + if response.status_code == 200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Delete object data by policy id, object data id, object category id +# 2) If the request code was 200 set the api response flag to true else false +@When('the user sets to delete the following object data') +def step_impl(context): + logging.info("When the user sets to delete the following object data") + model = getattr(context, "model", None) + for row in context.table: + + logger.info("object data name:'" + row["objectdataname"] + "' and object category name:'" + row[ + "objectcategory"] + "' and policy name:'" + row["policyname"] + "'") + + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + response_data = requests.delete( + apis_urls.serverURL + apis_urls.policyAPI + "/" + commonfunctions.get_policyid(row[ + "policyname"]) + "/" + apis_urls.dataobjectAPI + "/" + commonfunctions.get_objectcategoryid( + row["objectcategory"]) + "/" + commonfunctions.get_objectdataid(row["objectdataname"], + commonfunctions.get_objectcategoryid( + row["objectcategory"]), + commonfunctions.get_policyid( + row["policyname"])), + headers=headers) + + if response_data.status_code == 200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Add action data using the post request +# 2) If the request code was 200 set the api response flag to true else false +@When('the user sets to add the following action data') +def step_impl(context): + logger.info("When the user sets to add the following action data") + + model = getattr(context, "model", None) + for row in context.table: + logger.info( + "action data name: '" + row["actiondataname"] + "' action data description: '" + row[ + "actiondatadescription"] + "' and action category: '" + row[ + "actioncategory"] + "' and policies: '" + row['policyname'] + "'") + + policies_id = "" + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + if (len(row['policyname']) > 25): + policies_id = row['policyname'] + else: + policies_id = commonfunctions.get_policyid(row['policyname']) + + if (len(row['actioncategory']) > 25): + categories_id = row['actioncategory'] + else: + categories_id = commonfunctions.get_actioncategoryid(row['actioncategory']) + + data = { + 'name': row["actiondataname"], + 'description': row["actiondatadescription"], + + } + response = requests.post( + apis_urls.serverURL + "policies/" + str(policies_id) + "/" + apis_urls.dataactionAPI + "/" + str( + categories_id), headers=headers, data=json.dumps(data)) + + if response.status_code == 200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Delete action data by policy id, action data id, action category id +# 2) If the request code was 200 set the api response flag to true else false +@When('the user sets to delete the following action data') +def step_impl(context): + logging.info("When the user sets to delete the following action data") + model = getattr(context, "model", None) + for row in context.table: + + logger.info("action data name:'" + row["actiondataname"] + "' and action category name:'" + row[ + "actioncategory"] + "' and policy name:'" + row["policyname"] + "'") + + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + response_data = requests.delete( + apis_urls.serverURL + apis_urls.policyAPI + "/" + commonfunctions.get_policyid(row[ + "policyname"]) + "/" + apis_urls.dataactionAPI + "/" + commonfunctions.get_actioncategoryid( + row["actioncategory"]) + "/" + commonfunctions.get_actiondataid(row["actiondataname"], + commonfunctions.get_actioncategoryid( + row["actioncategory"]), + commonfunctions.get_policyid( + row["policyname"])), + headers=headers) + + if response_data.status_code == 200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Get all the existing subject data by get request and put them into a table +# 2) Sort the table by policy name +# 3) Loop using both the expected and actual tables and assert the data row by row +@Then('the following subject data should be existed in the system') +def step_impl(context): + logger.info("Then the following subject data should be existed in the system") + model = getattr(context, "model", None) + apiresult = Table(names=('subjectdataname', 'subjectdatadescription', 'subjectcategory', 'policyname'), + dtype=('S100', 'S100', 'S100', 'S100')) + for row in context.table: + if (row['policyname'] != ""): + response = requests.get( + apis_urls.serverURL + "policies/" + commonfunctions.get_policyid( + row['policyname']) + "/" + apis_urls.datasubjectAPI + "/" + + commonfunctions.get_subjectcategoryid(row['subjectcategory']),headers=apis_urls.auth_headers) + + if len(response.json()[apis_urls.datasubjectAPI]) != 0: + for ids in response.json()[apis_urls.datasubjectAPI][0]['data']: + apipolicies = "" + apisubjectdataname = response.json()[apis_urls.datasubjectAPI][0]['data'][str(ids)]['name'] + apisubjectdatadescription = response.json()[apis_urls.datasubjectAPI][0]['data'][str(ids)][ + 'description'] + apisubjectcategory = commonfunctions.get_subjectcategoryname( + response.json()[apis_urls.datasubjectAPI][0]['data'][str(ids)]['category_id']) + apipolicies = commonfunctions.get_policyname( + response.json()[apis_urls.datasubjectAPI][0]['data'][str(ids)]['policy_id']) + apiresult.add_row(vals=( + apisubjectdataname, apisubjectdatadescription, apisubjectcategory, apipolicies)) + else: + apiresult.add_row(vals=("", "", "", "")) + + else: + apiresult.add_row(vals=("", "", "", "")) + + apiresult.sort('policyname') + for row1, row2 in zip(context.table, apiresult): + logger.info("asserting the expected subject data name: '" + str( + row1["subjectdataname"]) + "' is the same as the actual existing '" + str( + row2["subjectdataname"]) + "'") + assert str(row1["subjectdataname"]) == str(row2["subjectdataname"]), "subject data name is not correct!" + logger.info("assertion passed!") + + logger.info("asserting the expected subject data description: '" + str( + row1["subjectdatadescription"]) + "' is the same as the actual existing '" + str( + row2["subjectdatadescription"]) + "'") + assert str(row1["subjectdatadescription"]) == str( + row2["subjectdatadescription"]), "subject data description is not correct!" + logger.info("assertion passed!") + + logger.info("asserting the expected subject data password: '" + str( + row1["subjectcategory"]) + "' is the same as the actual existing '" + str( + row2["subjectcategory"]) + "'") + assert str(row1["subjectcategory"]) == str( + row2["subjectcategory"]), "subject category is not correct!" + logger.info("assertion passed!") + + logger.info("asserting the expected policies: '" + str( + row1["policyname"]) + "' is the same as the actual existing '" + str( + row2["policyname"]) + "'") + assert str(row1["policyname"]) == str(row2["policyname"]), " policies is not correct!" + logger.info("assertion passed!") + +# Step Definition Implementation: +# 1) Get all the existing object data by get request and put them into a table +# 2) Sort the table by policy name +# 3) Loop using both the expected and actual tables and assert the data row by row +@Then('the following object data should be existed in the system') +def step_impl(context): + logger.info("Then the following object data should be existed in the system") + model = getattr(context, "model", None) + apiresult = Table(names=('objectdataname', 'objectdatadescription', 'objectcategory', 'policyname'), + dtype=('S100', 'S100', 'S100', 'S100')) + + for row in context.table: + if (row['policyname'] != ""): + response = requests.get( + apis_urls.serverURL + "policies/" + commonfunctions.get_policyid( + row['policyname']) + "/" + apis_urls.dataobjectAPI + "/" + + commonfunctions.get_objectcategoryid(row['objectcategory']),headers=apis_urls.auth_headers) + + if len(response.json()[apis_urls.dataobjectAPI]) != 0: + for ids in response.json()[apis_urls.dataobjectAPI][0]['data']: + apipolicies = "" + apiobjectdataname = response.json()[apis_urls.dataobjectAPI][0]['data'][str(ids)]['name'] + apiobjectdatadescription = response.json()[apis_urls.dataobjectAPI][0]['data'][str(ids)][ + 'description'] + apiobjectcategory = commonfunctions.get_objectcategoryname( + response.json()[apis_urls.dataobjectAPI][0]['data'][str(ids)]['category_id']) + apipolicies = commonfunctions.get_policyname( + response.json()[apis_urls.dataobjectAPI][0]['data'][str(ids)]['policy_id']) + + apiresult.add_row(vals=( + apiobjectdataname, apiobjectdatadescription, apiobjectcategory, apipolicies)) + else: + apiresult.add_row(vals=("", "", "", "")) + else: + apiresult.add_row(vals=("", "", "", "")) + + apiresult.sort('policyname') + for row1, row2 in zip(context.table, apiresult): + logger.info("asserting the expected object data name: '" + str( + row1["objectdataname"]) + "' is the same as the actual existing '" + str( + row2["objectdataname"]) + "'") + assert str(row1["objectdataname"]) == str(row2["objectdataname"]), "subject data name is not correct!" + logger.info("assertion passed!") + + logger.info("asserting the expected object data description: '" + str( + row1["objectdatadescription"]) + "' is the same as the actual existing '" + str( + row2["objectdatadescription"]) + "'") + assert str(row1["objectdatadescription"]) == str( + row2["objectdatadescription"]), "object data description is not correct!" + logger.info("assertion passed!") + + logger.info("asserting the expected object data category: '" + str( + row1["objectcategory"]) + "' is the same as the actual existing '" + str( + row2["objectcategory"]) + "'") + assert str(row1["objectcategory"]) == str( + row2["objectcategory"]), "object category is not correct!" + logger.info("assertion passed!") + + logger.info("asserting the expected policies: '" + str( + row1["policyname"]) + "' is the same as the actual existing '" + str( + row2["policyname"]) + "'") + assert str(row1["policyname"]) == str(row2["policyname"]), " policies is not correct!" + logger.info("assertion passed!") + +# Step Definition Implementation: +# 1) Get all the existing action data by get request and put them into a table +# 2) Sort the table by policy name +# 3) Loop using both the expected and actual tables and assert the data row by row +@Then('the following action data should be existed in the system') +def step_impl(context): + logger.info("Then the following action data should be existed in the system") + model = getattr(context, "model", None) + apiresult = Table(names=('actiondataname', 'actiondatadescription', 'actioncategory', 'policyname'), + dtype=('S100', 'S100', 'S100', 'S100')) + for row in context.table: + if (row['policyname'] != ""): + response = requests.get( + apis_urls.serverURL + "policies/" + commonfunctions.get_policyid( + row['policyname']) + "/" + apis_urls.dataactionAPI + "/" + + commonfunctions.get_actioncategoryid(row['actioncategory']),headers=apis_urls.auth_headers) + + if len(response.json()[apis_urls.dataactionAPI]) != 0: + for ids in response.json()[apis_urls.dataactionAPI][0]['data']: + apipolicies = "" + apiactiondataname = response.json()[apis_urls.dataactionAPI][0]['data'][str(ids)]['name'] + apiactiondatadescription = response.json()[apis_urls.dataactionAPI][0]['data'][str(ids)][ + 'description'] + apiactioncategory = commonfunctions.get_actioncategoryname( + response.json()[apis_urls.dataactionAPI][0]['data'][str(ids)]['category_id']) + apipolicies = commonfunctions.get_policyname( + response.json()[apis_urls.dataactionAPI][0]['data'][str(ids)]['policy_id']) + + apiresult.add_row(vals=( + apiactiondataname, apiactiondatadescription, apiactioncategory, apipolicies)) + else: + apiresult.add_row(vals=("", "", "", "")) + + else: + apiresult.add_row(vals=("", "", "", "")) + apiresult.sort('policyname') + for row1, row2 in zip(context.table, apiresult): + logger.info("asserting the expected action data name: '" + str( + row1["actiondataname"]) + "' is the same as the actual existing '" + str( + row2["actiondataname"]) + "'") + assert str(row1["actiondataname"]) == str(row2["actiondataname"]), "action data name is not correct!" + logger.info("assertion passed!") + + logger.info("asserting the expected action data description: '" + str( + row1["actiondatadescription"]) + "' is the same as the actual existing '" + str( + row2["actiondatadescription"]) + "'") + assert str(row1["actiondatadescription"]) == str( + row2["actiondatadescription"]), "action data description is not correct!" + logger.info("assertion passed!") + + logger.info("asserting the expected action data category: '" + str( + row1["actioncategory"]) + "' is the same as the actual existing '" + str( + row2["actioncategory"]) + "'") + assert str(row1["actioncategory"]) == str( + row2["actioncategory"]), "action category is not correct!" + logger.info("assertion passed!") + + logger.info("asserting the expected policies: '" + str( + row1["policyname"]) + "' is the same as the actual existing '" + str( + row2["policyname"]) + "'") + assert str(row1["policyname"]) == str(row2["policyname"]), " policies is not correct!" + logger.info("assertion passed!") diff --git a/moon_manager/tests/func_tests/features/steps/meta_data.py b/moon_manager/tests/func_tests/features/steps/meta_data.py new file mode 100644 index 00000000..b2a6d02c --- /dev/null +++ b/moon_manager/tests/func_tests/features/steps/meta_data.py @@ -0,0 +1,394 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +from behave import * +from Static_Variables import GeneralVariables +from astropy.table import Table, Column +from common_functions import * +import requests +import json +import logging + +apis_urls = GeneralVariables() +api_subjectcategory = {'name': "", 'description': ""} +api_objectcategory = {'name': "", 'description': ""} +api_actioncategory = {'name': "", 'description': ""} + +logger = logging.getLogger(__name__) + + +# Step Definition Implementation: +# 1) Get all the existing subject meta data in the system +# 2) Loop by id and delete them +@Given('the system has no subject categories') +def step_impl(context): + logger.info("Given the system has no subject categories") + api_responseflag = {'value': False} + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + response = requests.get(apis_urls.serverURL + apis_urls.metadatasubjectcategoryAPI, headers=apis_urls.auth_headers) + if len(response.json()[apis_urls.metadatasubjectcategoryAPI]) != 0: + for ids in dict(response.json()[apis_urls.metadatasubjectcategoryAPI]).keys(): + response = requests.delete(apis_urls.serverURL + apis_urls.metadatasubjectcategoryAPI + "/" + ids, + headers=headers) + +# Step Definition Implementation: +# 1) Get all the existing action meta data in the system +# 2) Loop by id and delete them +@Given('the system has no action categories') +def step_impl(context): + logger.info("Given the system has no action categories") + api_responseflag = {'value': False} + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + response = requests.get(apis_urls.serverURL + apis_urls.metadataactioncategoryAPI, headers=apis_urls.auth_headers) + if len(response.json()[apis_urls.metadataactioncategoryAPI]) != 0: + for ids in dict(response.json()[apis_urls.metadataactioncategoryAPI]).keys(): + response = requests.delete(apis_urls.serverURL + apis_urls.metadataactioncategoryAPI + "/" + ids, + headers=headers) + + +# Step Definition Implementation: +# 1) Get all the existing object meta data in the system +# 2) Loop by id and delete them +@Given('the system has no object categories') +def step_impl(context): + logger.info("Given the system has no object categories") + api_responseflag = {'value': False} + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + response = requests.get(apis_urls.serverURL + apis_urls.metadataobjectcategoryAPI, headers=apis_urls.auth_headers) + if len(response.json()[apis_urls.metadataobjectcategoryAPI]) != 0: + for ids in dict(response.json()[apis_urls.metadataobjectcategoryAPI]).keys(): + response = requests.delete(apis_urls.serverURL + apis_urls.metadataobjectcategoryAPI + "/" + ids, + headers=headers) + + + +# Step Definition Implementation: +# 1) Insert subject meta data using the post request +@Given('the following meta data subject category exists') +def step_impl(context): + logger.info("Given the following meta data subject category exists") + model = getattr(context, "model", None) + for row in context.table: + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + data = { + 'name': row["subjectmetadataname"], + 'description': row["subjectmetadatadescription"], + } + logger.info( + "subject category name: '" + row["subjectmetadataname"] + "' and subject category description: '" + row[ + "subjectmetadatadescription"] + "'") + response = requests.post(apis_urls.serverURL + apis_urls.metadatasubjectcategoryAPI, headers=headers, + data=json.dumps(data)) + +# Step Definition Implementation: +# 1) Insert object meta data using the post request +@Given('the following meta data object category exists') +def step_impl(context): + logger.info("Given the following meta data object category exists") + + model = getattr(context, "model", None) + for row in context.table: + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + data = { + 'name': row["objectmetadataname"], + 'description': row["objectmetadatadescription"], + } + logger.info( + "object category name: '" + row["objectmetadataname"] + "' and object category description: '" + row[ + "objectmetadatadescription"] + "'") + response = requests.post(apis_urls.serverURL + apis_urls.metadataobjectcategoryAPI, headers=headers, + data=json.dumps(data)) + +# Step Definition Implementation: +# 1) Insert action meta data using the post request +@Given('the following meta data action category exists') +def step_impl(context): + logger.info("Given the following meta data action category exists") + + model = getattr(context, "model", None) + for row in context.table: + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + data = { + 'name': row["actionmetadataname"], + 'description': row["actionmetadatadescription"], + } + logger.info( + "action category name: '" + row["actionmetadataname"] + "' and action category description: '" + row[ + "actionmetadatadescription"] + "'") + response = requests.post(apis_urls.serverURL + apis_urls.metadataactioncategoryAPI, headers=headers, + data=json.dumps(data)) + +# Step Definition Implementation: +# 1) Add subject meta data using the post request +# 2) If the request code was 200 set the api response flag to true else false +@When('the user sets to add the following meta data subject category') +def step_impl(context): + logger.info("When the user sets to add the following meta data subject category") + + model = getattr(context, "model", None) + for row in context.table: + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + data = { + 'name': row["subjectmetadataname"], + 'description': row["subjectmetadatadescription"], + } + logger.info( + "subject category name: '" + row["subjectmetadataname"] + "' and subject category description: '" + row[ + "subjectmetadatadescription"] + "'") + + response = requests.post(apis_urls.serverURL + apis_urls.metadatasubjectcategoryAPI, headers=headers, + data=json.dumps(data)) + + if response.status_code == 200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + + +# Step Definition Implementation: +# 1) Get all the subject meta data by get request +# 2) Loop by ids and search for the matching subject meta data by name and delete it +# 3) If the request code was 200 set the api response flag to true else false +@When('the user sets to delete the following meta data subject category') +def step_impl(context): + logger.info("When the user sets to delete the following meta data subject category") + + model = getattr(context, "model", None) + for row in context.table: + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + logger.info("subject category name: '" + row["subjectmetadataname"] + "'") + + response = requests.get(apis_urls.serverURL + apis_urls.metadatasubjectcategoryAPI, + headers=apis_urls.auth_headers) + for ids in dict(response.json()[apis_urls.metadatasubjectcategoryAPI]).keys(): + if (response.json()[apis_urls.metadatasubjectcategoryAPI][ids]['name'] == row["subjectmetadataname"]): + response = requests.delete(apis_urls.serverURL + apis_urls.metadatasubjectcategoryAPI + "/" + ids, + headers=headers) + if response.status_code == 200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Add object meta data using the post request +# 2) If the request code was 200 set the api response flag to true else false +@When('the user sets to add the following meta data object category') +def step_impl(context): + logger.info("When the user sets to add the following meta data object category") + + model = getattr(context, "model", None) + for row in context.table: + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + data = { + 'name': row["objectmetadataname"], + 'description': row["objectmetadatadescription"], + } + logger.info( + "object category Name: '" + row["objectmetadataname"] + "' and object category description: '" + row[ + "objectmetadatadescription"] + "''") + response = requests.post(apis_urls.serverURL + apis_urls.metadataobjectcategoryAPI, headers=headers, + data=json.dumps(data)) + if response.status_code == 200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Get all the object meta data by get request +# 2) Loop by ids and search for the matching object meta data by name and delete it +# 3) If the request code was 200 set the api response flag to true else false +@When('the user sets to delete the following meta data object category') +def step_impl(context): + logger.info("When the user sets to delete the following meta data object category") + + model = getattr(context, "model", None) + for row in context.table: + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + logger.info("object category name: '" + row["objectmetadataname"] + "'") + + response = requests.get(apis_urls.serverURL + apis_urls.metadataobjectcategoryAPI, + headers=apis_urls.auth_headers) + for ids in dict(response.json()[apis_urls.metadataobjectcategoryAPI]).keys(): + if (response.json()[apis_urls.metadataobjectcategoryAPI][ids]['name'] == row["objectmetadataname"]): + response = requests.delete(apis_urls.serverURL + apis_urls.metadataobjectcategoryAPI + "/" + ids, + headers=headers) + if response.status_code == 200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Add subject meta data using the post request +# 2) If the request code was 200 set the api response flag to true else false +@When('the user sets to add the following meta data action category') +def step_impl(context): + logger.info("When the user sets to add the following meta data action category") + + model = getattr(context, "model", None) + for row in context.table: + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + data = { + 'name': row["actionmetadataname"], + 'description': row["actionmetadatadescription"], + } + logger.info( + "action category name: '" + row["actionmetadataname"] + "' and action category description: '" + row[ + "actionmetadatadescription"] + "'") + + response = requests.post(apis_urls.serverURL + apis_urls.metadataactioncategoryAPI, headers=headers, + data=json.dumps(data)) + if response.status_code == 200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Get all the action meta data by get request +# 2) Loop by ids and search for the matching action meta data by name and delete it +# 3) If the request code was 200 set the api response flag to true else false +@When('the user sets to delete the following meta data action category') +def step_impl(context): + logger.info("When the user sets to delete the following meta data action category") + + model = getattr(context, "model", None) + for row in context.table: + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + logger.info("action category name: '" + row["actionmetadataname"] + "'") + + response = requests.get(apis_urls.serverURL + apis_urls.metadataactioncategoryAPI, + headers=apis_urls.auth_headers) + for ids in dict(response.json()[apis_urls.metadataactioncategoryAPI]).keys(): + # logger.info(ids) + if (response.json()[apis_urls.metadataactioncategoryAPI][ids]['name'] == row["actionmetadataname"]): + response = requests.delete(apis_urls.serverURL + apis_urls.metadataactioncategoryAPI + "/" + ids, + headers=headers) + # logger.info(response.status_code) + if response.status_code == 200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Get all the existing subject meta data by get request and put them into a table +# 2) Loop using both the expected and actual tables and assert the data row by row +@Then('the following meta data subject category should be existed in the system') +def step_impl(context): + logger.info("Then the following meta data subject category should be existed in the system") + + model = getattr(context, "model", None) + response = requests.get(apis_urls.serverURL + apis_urls.metadatasubjectcategoryAPI, headers=apis_urls.auth_headers) + apiresult = Table(names=('subjectcategoryname', 'subjectcategorydescription'), dtype=('S100', 'S100')) + if len(response.json()[apis_urls.metadatasubjectcategoryAPI]) != 0: + for ids in dict(response.json()[apis_urls.metadatasubjectcategoryAPI]).keys(): + apisubjectcategoryname = response.json()[apis_urls.metadatasubjectcategoryAPI][ids]['name'] + apisubjectcategorydescription = response.json()[apis_urls.metadatasubjectcategoryAPI][ids]['description'] + apiresult.add_row(vals=(apisubjectcategoryname, apisubjectcategorydescription)) + else: + apiresult.add_row(vals=("", "")) + for row1, row2 in zip(context.table, apiresult): + logger.info("asserting the expected subject category name: '" + str( + row1["subjectmetadataname"]) + "' is the same as the actual existing '" + str( + row2["subjectcategoryname"]) + "'") + assert str(row1["subjectmetadataname"]) == str( + row2["subjectcategoryname"]), "subject category name is not correct!" + logger.info("assertion passed!") + logger.info("asserting the expected subject category description: '" + str( + row1["subjectmetadatadescription"]) + "' is the same as the actual existing '" + str( + row2["subjectcategorydescription"]) + "'") + assert str(row1["subjectmetadatadescription"]) == str( + row2["subjectcategorydescription"]), "Subject meta-data category description is not correct!" + logger.info("assertion passed!") + +# Step Definition Implementation: +# 1) Get all the existing object meta data by get request and put them into a table +# 2) Loop using both the expected and actual tables and assert the data row by row +@Then('the following meta data object category should be existed in the system') +def step_impl(context): + model = getattr(context, "model", None) + logger.info("Then the following meta data object category should be existed in the system") + response = requests.get(apis_urls.serverURL + apis_urls.metadataobjectcategoryAPI, headers=apis_urls.auth_headers) + apiresult = Table(names=('objectcategoryname', 'objectcategorydescription'), dtype=('S100', 'S100')) + + if len(response.json()[apis_urls.metadataobjectcategoryAPI]) != 0: + for ids in dict(response.json()[apis_urls.metadataobjectcategoryAPI]).keys(): + apiobjectcategoryname = response.json()[apis_urls.metadataobjectcategoryAPI][ids]['name'] + apiobjectcategorydescription = response.json()[apis_urls.metadataobjectcategoryAPI][ids]['description'] + apiresult.add_row(vals=(apiobjectcategoryname, apiobjectcategorydescription)) + else: + apiresult.add_row(vals=("", "")) + for row1, row2 in zip(context.table, apiresult): + logger.info("asserting the expected object category description: '" + str( + row1["objectmetadataname"]) + "' is the same as the actual existing '" + str( + row2["objectcategoryname"]) + "'") + assert str(row1["objectmetadataname"]) == str( + row2["objectcategoryname"]), "object category name is not correct!" + logger.info("assertion passed!") + logger.info("asserting the expected object category description: '" + str( + row1["objectmetadatadescription"]) + "' is the same as the actual existing '" + str( + row2["objectcategorydescription"]) + "'") + assert str(row1["objectmetadatadescription"]) == str( + row2["objectcategorydescription"]), "object meta-data category description is not correct!" + logger.info("assertion passed!") + +# Step Definition Implementation: +# 1) Get all the existing action meta data by get request and put them into a table +# 2) Loop using both the expected and actual tables and assert the data row by row +@Then('the following meta data action category should be existed in the system') +def step_impl(context): + logger.info("Then the following meta data action category should be existed in the system") + + model = getattr(context, "model", None) + response = requests.get(apis_urls.serverURL + apis_urls.metadataactioncategoryAPI, headers=apis_urls.auth_headers) + apiresult = Table(names=('actioncategoryname', 'actioncategorydescription'), dtype=('S100', 'S100')) + if len(response.json()[apis_urls.metadataactioncategoryAPI]) != 0: + for ids in dict(response.json()[apis_urls.metadataactioncategoryAPI]).keys(): + apiactioncategoryname = response.json()[apis_urls.metadataactioncategoryAPI][ids]['name'] + apiactioncategorydescription = response.json()[apis_urls.metadataactioncategoryAPI][ids]['description'] + apiresult.add_row(vals=(apiactioncategoryname, apiactioncategorydescription)) + else: + apiresult.add_row(vals=("", "")) + for row1, row2 in zip(context.table, apiresult): + logger.info("asserting the expected action category description: '" + str( + row1["actionmetadataname"]) + "' is the same as the actual existing '" + str( + row2["actioncategoryname"]) + "'") + + assert str(row1["actionmetadataname"]) == str( + row2["actioncategoryname"]), "action category name is not correct!" + logger.info("assertion passed!") + + logger.info("asserting the expected action category description: '" + str( + row1["actionmetadatadescription"]) + "' is the same as the actual existing '" + str( + row2["actioncategorydescription"]) + "'") + + assert str(row1["actionmetadatadescription"]) == str( + row2["actioncategorydescription"]), "action meta-data category description is not correct!" + logger.info("assertion passed!") + +# Step Definition Implementation: +# Assert the saved api response flag with the expected flag +@Then('the system should reply the following') +def step_impl(context): + logger.info("Then the system should reply the following:") + model = getattr(context, "model", None) + for row in context.table: + logger.info("asserting the expected api response: '" + row["flag"] + "' and the actual response: '" + + GeneralVariables.api_responseflag['value'] + "'") + assert row["flag"] == GeneralVariables.api_responseflag['value'], "Validation is not correct, Expected: " + row[ + "flag"] + " but the API response was: " + GeneralVariables.api_responseflag['value'] + logger.info("assertion passed!") diff --git a/moon_manager/tests/func_tests/features/steps/meta_rules.py b/moon_manager/tests/func_tests/features/steps/meta_rules.py new file mode 100644 index 00000000..f56d4d4c --- /dev/null +++ b/moon_manager/tests/func_tests/features/steps/meta_rules.py @@ -0,0 +1,335 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +from behave import * +from Static_Variables import GeneralVariables +from astropy.table import Table, Column +from common_functions import * +import numpy as np +import requests +import json +import logging + +apis_urls = GeneralVariables() +commonfunctions = commonfunctions() + +logger = logging.getLogger(__name__) + +# Step Definition Implementation: +# 1) Get all the existing meta rule in the system +# 2) Loop by id and delete them +@Given('the system has no meta-rules') +def step_impl(context): + logger.info("Given the system has no meta-rules") + + api_responseflag = {'value': False} + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + response = requests.get(apis_urls.serverURL + apis_urls.metarulesAPI,headers=apis_urls.auth_headers) + if len(response.json()[apis_urls.metarulesAPI]) != 0: + for ids in dict(response.json()[apis_urls.metarulesAPI]).keys(): + response = requests.delete(apis_urls.serverURL + apis_urls.metarulesAPI + "/" + ids, + headers=headers) + +# Step Definition Implementation: +# 1) Get subject, object, action categories ids list by calling the common funtion: get_subjectcategoryid, get_objectcategoryid and get_actioncategoryid +# 2) create the meta rule data jason then post it +@Given('the following meta rule exists') +def step_impl(context): + logger.info("Given the following meta rule exists") + + model = getattr(context, "model", None) + for row in context.table: + logger.info( + "meta-rule name: '" + row["metarulename"] + "' and meta-rule description: '" + row[ + "metaruledescription"] + "' and subject categories:'" + row[ + "subjectmetadata"] + "' and object categories:'" + row["objectmetadata"] + "' and action categories:'" + + row["actionmetadata"] + "'") + subjectcategoryids = [] + objectcategoryids = [] + actioncategoryids = [] + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + if (len(row["subjectmetadata"]) < 40 and str(row["subjectmetadata"])!=""): + if(str(row["subjectmetadata"]).find(",")!=-1): + for category in row["subjectmetadata"].split(","): + subjectcategoryids.append(commonfunctions.get_subjectcategoryid(category)) + else: + subjectcategoryids.append(commonfunctions.get_subjectcategoryid(row["subjectmetadata"])) + else: + if(str(row["subjectmetadata"])==""): + subjectcategoryids=[] + else: + subjectcategoryids.append(row["subjectmetadata"]) + + if (len(row["objectmetadata"]) < 40 and str(row["objectmetadata"])!=""): + if(str(row["objectmetadata"]).find(",")!=-1): + for category in row["objectmetadata"].split(","): + objectcategoryids.append(commonfunctions.get_objectcategoryid(category)) + else: + objectcategoryids.append(commonfunctions.get_objectcategoryid(row["objectmetadata"])) + else: + if (str(row["objectmetadata"]) == ""): + objectcategoryids = [] + else: + objectcategoryids.append(row["objectmetadata"]) + + if (len(row["actionmetadata"]) < 40 and str(row["actionmetadata"])!=""): + if(str(row["actionmetadata"]).find(",")!=-1): + for category in row["actionmetadata"].split(","): + actioncategoryids.append(commonfunctions.get_actioncategoryid(category)) + else: + actioncategoryids.append(commonfunctions.get_actioncategoryid(row["actionmetadata"])) + else: + if(str(row["actionmetadata"]) == ""): + actioncategoryids = [] + else: + actioncategoryids.append(row["actionmetadata"]) + + data = { + 'name': row["metarulename"], + 'description': row["metaruledescription"], + 'subject_categories': subjectcategoryids, + 'object_categories': objectcategoryids, + 'action_categories': actioncategoryids + } + response = requests.post(apis_urls.serverURL + apis_urls.metarulesAPI, headers=headers, + data=json.dumps(data)) + +# Step Definition Implementation: +# 1) Get subject, object, action categories ids list by calling the common funtion: get_subjectcategoryid, get_objectcategoryid and get_actioncategoryid +# 2) create the meta rule data jason then post it +# 3) If the request code was 200 set the api response flag to true else false +@When('the user sets to add the following meta-rule') +def step_impl(context): + logger.info("When the user sets to add the following meta-rule") + + model = getattr(context, "model", None) + for row in context.table: + logger.info( + "meta-rule name: '" + row["metarulename"] + "' and meta-rule description: '" + row[ + "metaruledescription"] + "' and subject categories:'" + row[ + "subjectmetadata"] + "' and object categories:'" + row["objectmetadata"] + "' and action categories:'" + + row["actionmetadata"] + "'") + + subjectcategoryids = [] + objectcategoryids = [] + actioncategoryids = [] + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + if (len(row["subjectmetadata"]) < 40 and str(row["subjectmetadata"])!=""): + if (str(row["subjectmetadata"]).find(",") != -1): + for category in row["subjectmetadata"].split(","): + subjectcategoryids.append(commonfunctions.get_subjectcategoryid(category)) + else: + subjectcategoryids.append(commonfunctions.get_subjectcategoryid(row["subjectmetadata"])) + else: + subjectcategoryids.append(row["subjectmetadata"]) + + if (len(row["objectmetadata"]) < 40 and str(row["objectmetadata"])!=""): + if (str(row["objectmetadata"]).find(",") != -1): + for category in row["objectmetadata"].split(","): + objectcategoryids.append(commonfunctions.get_objectcategoryid(category)) + else: + objectcategoryids.append(commonfunctions.get_objectcategoryid(row["objectmetadata"])) + else: + objectcategoryids.append(row["objectmetadata"]) + + if (len(row["actionmetadata"]) < 40 and str(row["actionmetadata"])!=""): + if (str(row["actionmetadata"]).find(",") != -1): + for category in row["actionmetadata"].split(","): + actioncategoryids.append(commonfunctions.get_actioncategoryid(category)) + else: + actioncategoryids.append(commonfunctions.get_actioncategoryid(row["actionmetadata"])) + else: + actioncategoryids.append(row["actionmetadata"]) + + + data = { + 'name': row["metarulename"], + 'description': row["metaruledescription"], + 'subject_categories': subjectcategoryids, + 'object_categories': objectcategoryids, + 'action_categories': actioncategoryids + } + + response = requests.post(apis_urls.serverURL + apis_urls.metarulesAPI, headers=headers, + data=json.dumps(data)) + if response.status_code == 200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Get subject, object, action categories ids list by calling the common funtion: get_subjectcategoryid, get_objectcategoryid and get_actioncategoryid +# 2) create the meta rule data jason then patch the meta rule after searching for it's id. +# 3) If the request code was 200 set the api response flag to true else false +@When('the user sets to update the following meta-rule') +def step_impl(context): + logger.info("When the user sets to update the following meta-rule") + + model = getattr(context, "model", None) + for row in context.table: + logger.info( + "meta-rule name: '" + row["metarulename"] + "' which will be updated to metarule name:" + row[ + "updatedmetarulename"] + "' and meta-rule description: '" + row[ + "updatedmetaruledescription"] + "' and subject categories:'" + row[ + "updatedsubjectmetadata"] + "' and object categories:'" + row[ + "updatedobjectmetadata"] + "' and action categories:'" + + row["updatedactionmetadata"] + "'") + + subjectcategoryids = [] + objectcategoryids = [] + actioncategoryids = [] + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + if (len(row["updatedsubjectmetadata"]) > 40): + subjectcategoryids.append(row["updatedsubjectmetadata"]) + else: + for category in row["updatedsubjectmetadata"].split(","): + subjectcategoryids.append(commonfunctions.get_subjectcategoryid(category)) + + if (len(row["updatedobjectmetadata"]) > 40): + objectcategoryids.append(row["updatedobjectmetadata"]) + else: + for category in row["updatedobjectmetadata"].split(","): + objectcategoryids.append(commonfunctions.get_objectcategoryid(category)) + + if (len(row["updatedactionmetadata"]) > 40): + actioncategoryids.append(row["updatedactionmetadata"]) + else: + for category in row["updatedactionmetadata"].split(","): + actioncategoryids.append(commonfunctions.get_actioncategoryid(category)) + + data = { + 'name': row["updatedmetarulename"], + 'description': row["updatedmetaruledescription"], + 'subject_categories': subjectcategoryids, + 'object_categories': objectcategoryids, + 'action_categories': actioncategoryids + } + + response = requests.get(apis_urls.serverURL + apis_urls.metarulesAPI,headers=apis_urls.auth_headers) + for ids in dict(response.json()[apis_urls.metarulesAPI]).keys(): + if (response.json()[apis_urls.metarulesAPI][ids]['name'] == row["metarulename"]): + response = requests.patch(apis_urls.serverURL + apis_urls.metarulesAPI + '/' + ids, headers=headers, + data=json.dumps(data)) + break + if response.status_code == 200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Get all the meta rule by get request +# 2) Loop by ids and search for the matching meta rule by name and delete it +# 3) If the request code was 200 set the api response flag to true else false +@When('the user sets to delete the following meta-rule') +def step_impl(context): + logger.info("When the user sets to delete the following meta-rule") + + model = getattr(context, "model", None) + for row in context.table: + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + logger.info( + "meta-rule name: '" + row["metarulename"] + "'") + response = requests.get(apis_urls.serverURL + apis_urls.metarulesAPI,headers=apis_urls.auth_headers) + for ids in dict(response.json()[apis_urls.metarulesAPI]).keys(): + if (response.json()[apis_urls.metarulesAPI][ids]['name'] == row["metarulename"]): + response = requests.delete(apis_urls.serverURL + apis_urls.metarulesAPI + "/" + ids, + headers=headers) + if response.status_code == 200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Get all the existing action meta data by get request and put them into a table +# 2) Sort the table by meta rule name +# 3) Loop using both the expected and actual tables and assert the data row by row +@Then('the following meta-rules should be existed in the system') +def step_impl(context): + logger.info("Then the following meta-rules should be existed in the system") + response = requests.get(apis_urls.serverURL + apis_urls.metarulesAPI,headers=apis_urls.auth_headers) + apimetarulesubjectcategoryname = "" + apimetaruleobjectcategoryname = "" + apimetaruleactioncategoryname = "" + apiresult = Table( + names=('metarulename', 'metaruledescription', 'subjectmetadata', 'actionmetadata', 'objectmetadata'), + dtype=('S10', 'S100', 'S100', 'S100', 'S100')) + if len(response.json()[apis_urls.metarulesAPI]) != 0: + for ids in dict(response.json()[apis_urls.metarulesAPI]).keys(): + apimetarulesubjectcategoryname = "" + apimetaruleobjectcategoryname = "" + apimetaruleactioncategoryname = "" + apimetarulename = response.json()[apis_urls.metarulesAPI][ids]['name'] + apimetaruledescription = response.json()[apis_urls.metarulesAPI][ids]['description'] + for categoryid in response.json()[apis_urls.metarulesAPI][ids]['subject_categories']: + if (len(apimetarulesubjectcategoryname) > 2): + apimetarulesubjectcategoryname = apimetarulesubjectcategoryname + ',' + commonfunctions.get_subjectcategoryname( + categoryid) + else: + apimetarulesubjectcategoryname = commonfunctions.get_subjectcategoryname(categoryid) + for categoryid in response.json()[apis_urls.metarulesAPI][ids]['object_categories']: + if (len(apimetaruleobjectcategoryname) > 2): + apimetaruleobjectcategoryname = apimetaruleobjectcategoryname + ',' + commonfunctions.get_objectcategoryname( + categoryid) + else: + apimetaruleobjectcategoryname = commonfunctions.get_objectcategoryname(categoryid) + for categoryid in response.json()[apis_urls.metarulesAPI][ids]['action_categories']: + if (len(apimetaruleactioncategoryname) > 2): + apimetaruleactioncategoryname = apimetaruleactioncategoryname + ',' + commonfunctions.get_actioncategoryname( + categoryid) + else: + apimetaruleactioncategoryname = commonfunctions.get_actioncategoryname(categoryid) + + apiresult.add_row(vals=( + apimetarulename, apimetaruledescription, apimetarulesubjectcategoryname, apimetaruleactioncategoryname, + apimetaruleobjectcategoryname)) + + else: + apiresult.add_row(vals=("", "", "", "", "")) + + apiresult.sort('metarulename') + + for row1, row2 in zip(context.table, apiresult): + logger.info("asserting the expected meta rule name: '" + str( + row1["metarulename"]) + "' is the same as the actual existing '" + str( + row2["metarulename"]) + "'") + assert str(row1["metarulename"]) == str(row2["metarulename"]), "meta-rule name is not correct!" + logger.info("assertion passed!") + + logger.info("asserting the expected meta rule description: '" + str( + row1["metaruledescription"]) + "' is the same as the actual existing '" + str( + row2["metaruledescription"]) + "'") + assert str(row1["metaruledescription"]) == str( + row2["metaruledescription"]), "meta-rule description is not correct!" + logger.info("assertion passed!") + + logger.info("asserting the expected subject categories: '" + str( + row1["subjectmetadata"]) + "' is the same as the actual existing '" + str( + row2["subjectmetadata"]) + "'") + assert str(row1["subjectmetadata"]) == str(row2["subjectmetadata"]), "subject category is not correct!" + logger.info("assertion passed!") + + logger.info("asserting the expected object categories: '" + str( + row1["objectmetadata"]) + "' is the same as the actual existing '" + str( + row2["objectmetadata"]) + "'") + assert str(row1["objectmetadata"]) == str(row2["objectmetadata"]), "object category is not correct!" + logger.info("assertion passed!") + + logger.info("asserting the expected action categories: '" + str( + row1["actionmetadata"]) + "' is the same as the actual existing '" + str( + row2["actionmetadata"]) + "'") + assert str(row1["actionmetadata"]) == str(row2["actionmetadata"]), "action category is not correct!" + logger.info("assertion passed!") diff --git a/moon_manager/tests/func_tests/features/steps/model.py b/moon_manager/tests/func_tests/features/steps/model.py new file mode 100644 index 00000000..36b16746 --- /dev/null +++ b/moon_manager/tests/func_tests/features/steps/model.py @@ -0,0 +1,230 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +from behave import * +from Static_Variables import GeneralVariables +from astropy.table import Table, Column +from common_functions import * +import requests +import json +import logging + +apis_urls = GeneralVariables() +commonfunctions = commonfunctions() + +logger = logging.getLogger(__name__) + +# Step Definition Implementation: +# 1) Get all the existing models in the system +# 2) Loop by id and delete them +@Given('the system has no models') +def step_impl(context): + logger.info("Given the system has no models") + + api_responseflag = {'value': False} + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + response = requests.get(apis_urls.serverURL + apis_urls.modelAPI, headers=apis_urls.auth_headers) + if len(response.json()[apis_urls.modelAPI]) != 0: + for ids in dict(response.json()[apis_urls.modelAPI]).keys(): + response = requests.delete(apis_urls.serverURL + apis_urls.modelAPI + "/" + ids, + headers=headers) + +# Step Definition Implementation: +# 1) Get meta rule ids list by calling the common funtion: get_metaruleid +# 2) create the model data jason then post it +@Given('the following model exists') +def step_impl(context): + logger.info("Given the following model exists") + model = getattr(context, "model", None) + for row in context.table: + logger.info( + "model name: '" + row["modelname"] + "' model description: '" + row[ + "modeldescription"] + "' and meta-rules:'" + row[ + "metarule"]+"'") + + metarulesids = [] + + if (len(row["metarule"]) > 35): + metarulesids.append(row["metarule"]) + else: + for metarule in row["metarule"].split(","): + metarulesids.append(commonfunctions.get_metaruleid(metarule)) + + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + data = { + 'name': row["modelname"], + 'description': row["modeldescription"], + 'meta_rules': metarulesids + } + response = requests.post(apis_urls.serverURL + apis_urls.modelAPI, headers=headers, + data=json.dumps(data)) + + +# Step Definition Implementation: +# 1) Get meta rule ids list by calling the common funtion: get_metaruleid +# 2) create the model data jason then post it +# 3) If the request code was 200 set the api response flag to true else false +@When('the user sets to add the following model') +def step_impl(context): + logger.info("When the user sets to add the following model") + model = getattr(context, "model", None) + for row in context.table: + logger.info( + "model name: '" + row["modelname"] + "' model description: '" + row[ + "modeldescription"] + "' and meta-rules:'" + row[ + "metarule"] + "'") + + metarules = [] + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + if(row["metarule"]!=""): + if (len(row["metarule"]) > 35): + metarules.append(row["metarule"]) + else: + for metarule in row["metarule"].split(","): + metarules.append(commonfunctions.get_metaruleid(metarule)) + + data = { + 'name': row["modelname"], + 'description': row["modeldescription"], + 'meta_rules': metarules, + } + else: + data = { + 'name': row["modelname"], + 'description': row["modeldescription"], + 'meta_rules': "", + } + response = requests.post(apis_urls.serverURL + apis_urls.modelAPI, headers=headers, + data=json.dumps(data)) + + if response.status_code==200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + + +# Step Definition Implementation: +# 1) Get meta rule ids list by calling the common funtion: get_modelid +# 2) create the model jason then patch the model after searching for it's id. +# 3) If the request code was 200 set the api response flag to true else false +@When('the user sets to update the following model') +def step_impl(context): + logging.info("When the user sets to update the following model") + model = getattr(context, "model", None) + for row in context.table: + logger.info( + "model name: '" + row["modelname"] + "' which will be updated to model name:" + row[ + "updatedmodelname"] + "' and model description: '" + row[ + "updatedmodeldescription"] + "' meta-rules: '"+row["updatedmetarule"] + "'") + + metarules = [] + data={} + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + if(row["updatedmetarule"]!=""): + if (len(row["updatedmetarule"]) > 35): + metarules.append(row["updatedmetarule"]) + else: + for metarule in row["updatedmetarule"].split(","): + metarules.append(commonfunctions.get_metaruleid(metarule)) + data = { + 'name': row["updatedmodelname"], + 'description': row["updatedmodeldescription"], + 'meta_rules': metarules, + } + else: + data = { + 'name': row["updatedmodelname"], + 'description': row["updatedmodeldescription"], + 'meta_rules': "", + } + response = requests.get(apis_urls.serverURL + apis_urls.modelAPI, headers=apis_urls.auth_headers) + for ids in dict(response.json()[apis_urls.modelAPI]).keys(): + if (response.json()[apis_urls.modelAPI][ids]['name'] == row["modelname"]): + response = requests.patch(apis_urls.serverURL + apis_urls.modelAPI+'/'+ids, headers=headers, + data=json.dumps(data)) + + if response.status_code==200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Get all the model by get request +# 2) Loop by ids and search for the matching model by name and delete it +# 3) If the request code was 200 set the api response flag to true else false +@When('the user sets to delete the following model') +def step_impl(context): + logging.info("When the user sets to delete the following model") + model = getattr(context, "model", None) + for row in context.table: + logger.info("model name: '" + row["modelname"] + "'") + + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + logger.info("policy name:'" + row["modelname"] + "'") + response = requests.get(apis_urls.serverURL + apis_urls.modelAPI, headers=apis_urls.auth_headers) + for ids in dict(response.json()[apis_urls.modelAPI]).keys(): + if (response.json()[apis_urls.modelAPI][ids]['name'] == row["modelname"]): + response = requests.delete(apis_urls.serverURL + apis_urls.modelAPI + "/" + ids, + headers=headers) + if response.status_code==200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Get all the existing models by get request and put them into a table +# 2) Sort the table by model name +# 3) Loop using both the expected and actual tables and assert the data row by row +@Then('the following model should be existed in the system') +def step_impl(context): + logger.info("Then the following model should be existed in the system") + response = requests.get(apis_urls.serverURL + apis_urls.modelAPI, headers=apis_urls.auth_headers) + apimetarulesname="" + apiresult = Table( + names=('modelname', 'modeldescription', 'metarule'), + dtype=('S100', 'S100', 'S100')) + if len(response.json()[apis_urls.modelAPI]) != 0: + for ids in dict(response.json()[apis_urls.modelAPI]).keys(): + apimetarulesname = [] + apimodelname = response.json()[apis_urls.modelAPI][ids]['name'] + apimodeldescription = response.json()[apis_urls.modelAPI][ids]['description'] + for metaruleid in response.json()[apis_urls.modelAPI][ids]['meta_rules']: + apimetarulesname.append(commonfunctions.get_metarulename(metaruleid)) + apiresult.add_row(vals=( + apimodelname, apimodeldescription, ",".join(apimetarulesname))) + else: + apiresult.add_row(vals=("", "", "")) + + apiresult.sort('modelname') + + for row1, row2 in zip(context.table, apiresult): + logger.info("asserting the expected model name: '" + str( + row1["modelname"]) + "' is the same as the actual existing '" + str( + row2["modelname"]) + "'") + assert str(row1["modelname"]) == str(row2["modelname"]), "model name is not correct!" + logger.info("assertion passed!") + + logger.info("asserting the expected model description: '" + str( + row1["modeldescription"]) + "' is the same as the actual existing '" + str( + row2["modeldescription"]) + "'") + assert str(row1["modeldescription"]) == str(row2["modeldescription"]), "model description is not correct!" + logger.info("assertion passed!") + + logger.info("asserting the expected meta rules: '" + str( + row1["metarule"]) + "' is the same as the actual existing '" + str( + row2["metarule"]) + "'") + assert str(row1["metarule"]) == str(row2["metarule"]), "metarule is not correct!" + logger.info("assertion passed!") diff --git a/moon_manager/tests/func_tests/features/steps/pdp.py b/moon_manager/tests/func_tests/features/steps/pdp.py new file mode 100644 index 00000000..bf839658 --- /dev/null +++ b/moon_manager/tests/func_tests/features/steps/pdp.py @@ -0,0 +1,248 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +from behave import * +from Static_Variables import GeneralVariables +from astropy.table import Table +from common_functions import * +import requests +import json +import logging + +apis_urls = GeneralVariables() +commonfunctions = commonfunctions() + +logger = logging.getLogger(__name__) + +# Step Definition Implementation: +# 1) Get all the existing pdps in the system +# 2) Loop by id and delete them +@Given('the system has no pdps') +def step_impl(context): + logger.info("Given the system has no pdps") + api_responseflag = {'value': False} + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + response = requests.get(apis_urls.serverURL + apis_urls.pdpAPI, headers=apis_urls.auth_headers) + pdpjason=apis_urls.pdpAPI+"s" + if len(response.json()[pdpjason]) != 0: + for ids in dict(response.json()[pdpjason]).keys(): + response = requests.delete(apis_urls.serverURL + apis_urls.pdpAPI + "/" + ids, + headers=headers) + +# Step Definition Implementation: +# 1) Get model id by calling the common funtion: get_policyid +# 2) create the pdp data jason then post it +@Given('the following pdp exists') +def step_impl(context): + logger.info("Given the following pdp exists") + model = getattr(context, "model", None) + for row in context.table: + logger.info( + "pdp name: '" + row["pdpname"] + "' pdp description: '" + row[ + "pdpdescription"] + "' and keystone project:'" + row[ + "keystone_project_id"] + "' and security pipeline '" + row['security_pipeline'] + "'") + policies_list = [] + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + if (len(row['security_pipeline']) > 25): + policies_list = row['security_pipeline'] + else: + for policy in row["security_pipeline"].split(","): + policies_list.append(commonfunctions.get_policyid(policy)) + + data = { + 'name': row["pdpname"], + 'description': row["pdpdescription"], + 'vim_project_id': row['keystone_project_id'], + 'security_pipeline': policies_list + } + response = requests.post(apis_urls.serverURL + apis_urls.pdpAPI, headers=headers, + data=json.dumps(data)) + +# Step Definition Implementation: +# 1) Get policy id by calling the common funtion: get_policyid +# 2) create the pdp jason then patch the policy after searching for it's id. +# 3) If the request code was 200 set the api response flag to true else false +@When('the user sets to add the following pdp') +def step_impl(context): + logger.info("When the user sets to add the following pdp") + + model = getattr(context, "model", None) + for row in context.table: + logger.info( + "pdp name: '" + row["pdpname"] + "' pdp description: '" + row[ + "pdpdescription"] + "' and keystone project:'" + row[ + "keystone_project_id"] + "' and security pipeline '" + row['security_pipeline'] + "'") + + policies_list = [] + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + if (row["security_pipeline"] != ""): + if (len(row['security_pipeline']) > 25): + policies_list = row['security_pipeline'] + else: + for policy in row["security_pipeline"].split(","): + policies_list.append(commonfunctions.get_policyid(policy)) + data = { + 'name': row["pdpname"], + 'description': row["pdpdescription"], + 'vim_project_id': row['keystone_project_id'], + 'security_pipeline': policies_list + } + else: + data = { + 'name': row["pdpname"], + 'description': row["pdpdescription"], + 'vim_project_id': row['keystone_project_id'], + 'security_pipeline': "" + } + response = requests.post(apis_urls.serverURL + apis_urls.pdpAPI, headers=headers, + data=json.dumps(data)) + + if response.status_code == 200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Get model id by calling the common funtion: get_policyid +# 2) create the pdp data jason then patch it +# 3) If the request code was 200 set the api response flag to true else false +@When('the user sets to update the following pdp') +def step_impl(context): + logger.info("When the user sets to update the following pdp") + + model = getattr(context, "model", None) + policies_list=[] + for row in context.table: + logger.info( + "pdp name: '" + row["pdpname"] + "' which will be updated to pdp name:" + row[ + "updatedpdpname"] + "' and pdp description: '" + row[ + "updatedpdpdescription"] + "' keystone_project: '" + row["updatedkeystone_project_id"] + "' security pipeline: '"+row["updatedsecurity_pipeline"]+"'") + + policies_list = [] + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + if (len(row['updatedsecurity_pipeline']) > 25): + policies_list = row['updatedsecurity_pipeline'] + else: + for policy in row["updatedsecurity_pipeline"].split(","): + policies_list.append(commonfunctions.get_policyid(policy)) + + data = { + 'name': row["updatedpdpname"], + 'description': row["updatedpdpdescription"], + 'vim_project_id': row['updatedkeystone_project_id'], + 'security_pipeline': policies_list + } + + response = requests.get(apis_urls.serverURL + apis_urls.pdpAPI,headers=apis_urls.auth_headers) + logger.info(response.json()) + pdpjason = apis_urls.pdpAPI + "s" + for ids in dict(response.json()[pdpjason]).keys(): + logger.info(str(response.json()[pdpjason][ids]['name'])) + if (response.json()[pdpjason][ids]['name'] == row["pdpname"]): + logger.info(apis_urls.serverURL + apis_urls.pdpAPI+ '/' + ids) + response = requests.patch(apis_urls.serverURL + apis_urls.pdpAPI+ '/' + ids, headers=headers, + data=json.dumps(data)) + logger.info(response.json()) + + if response.status_code==200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + break + +# Step Definition Implementation: +# 1) Get all the pdps by get request +# 2) Loop by ids and search for the matching pdp by name and delete it +# 3) If the request code was 200 set the api response flag to true else false +@When('the user sets to delete the following pdp') +def step_impl(context): + logging.info("When the user sets to delete the following pdp") + + model = getattr(context, "model", None) + for row in context.table: + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + logger.info("pdp name:'" + row["pdpname"] + "'") + + response = requests.get(apis_urls.serverURL + apis_urls.pdpAPI,headers=apis_urls.auth_headers) + pdpjason=apis_urls.pdpAPI+"s" + for ids in dict(response.json()[pdpjason]).keys(): + if (response.json()[pdpjason][ids]['name'] == row["pdpname"]): + response = requests.delete(apis_urls.serverURL + apis_urls.pdpAPI + "/" + ids, + headers=headers) + + if response.status_code==200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Get all the existing pdps by get request and put them into a table +# 2) Sort the table by pdp name +# 3) Loop using both the expected and actual tables and assert the data row by row +@Then('the following pdp should be existed in the system') +def step_impl(context): + logger.info("Then the following pdp should be existed in the system") + + response = requests.get(apis_urls.serverURL + apis_urls.pdpAPI,headers=apis_urls.auth_headers) + apiresult = Table( + names=('pdpname', 'pdpdescription', 'keystone_project_id','security_pipeline'), + dtype=('S10', 'S100', 'S100','S100')) + pdp_jason=apis_urls.pdpAPI+"s" + if len(response.json()[pdp_jason]) != 0: + for ids in dict(response.json()[pdp_jason]).keys(): + apipdppolicies = "" + apipdpname = response.json()[pdp_jason][ids]['name'] + apipdpdescription = response.json()[pdp_jason][ids]['description'] + apipdpprojectid = response.json()[pdp_jason][ids]['vim_project_id'] + for policies in response.json()[pdp_jason][ids]['security_pipeline']: + if(len(apipdppolicies)>2): + apipdppolicies = apipdppolicies +','+ commonfunctions.get_policyname(policies) + else: + apipdppolicies=commonfunctions.get_policyname(policies) + + apiresult.add_row(vals=( + apipdpname, apipdpdescription, apipdpprojectid,apipdppolicies)) + + else: + apiresult.add_row(vals=("", "", "","")) + + apiresult.sort('pdpname') + for row1, row2 in zip(context.table, apiresult): + logger.info("asserting the expected pdp name: '" + str( + row1["pdpname"]) + "' is the same as the actual existing '" + str( + row2["pdpname"]) + "'") + assert str(row1["pdpname"]) == str(row2["pdpname"]), "pdp name is not correct!" + logger.info("assertion passed!") + + logger.info("asserting the expected pdp description: '" + str( + row1["pdpdescription"]) + "' is the same as the actual existing '" + str( + row2["pdpdescription"]) + "'") + + assert str(row1["pdpdescription"]) == str(row2["pdpdescription"]), "pdp description is not correct!" + logger.info("assertion passed!") + + logger.info("asserting the expected keystone project id description: '" + str( + row1["keystone_project_id"]) + "' is the same as the actual existing '" + str( + row2["keystone_project_id"]) + "'") + assert str(row1["keystone_project_id"]) == str(row2["keystone_project_id"]), "project id is not correct!" + logger.info("assertion passed!") + + logger.info("asserting the expected security pipeline description: '" + str( + row1["security_pipeline"]) + "' is the same as the actual existing '" + str( + row2["security_pipeline"]) + "'") + assert str(row1["security_pipeline"]) == str(row2["security_pipeline"]), "security_pipeline policies is not correct!" + logger.info("assertion passed!") + diff --git a/moon_manager/tests/func_tests/features/steps/perimeter.py b/moon_manager/tests/func_tests/features/steps/perimeter.py new file mode 100644 index 00000000..a4a53120 --- /dev/null +++ b/moon_manager/tests/func_tests/features/steps/perimeter.py @@ -0,0 +1,727 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +from behave import * +from Static_Variables import GeneralVariables +from astropy.table import Table +from common_functions import * +import requests +import json +import logging + +apis_urls = GeneralVariables() +commonfunctions = commonfunctions() + +logger = logging.getLogger(__name__) + +# Step Definition Implementation: +# 1) Get all the existing subject preimeters in the system +# 2) Loop by id to unlink the policies attached +# 3) Then delete the perimeter itself +@Given('the system has no subject perimeter') +def step_impl(context): + logger.info("Given the system has no subject perimeter") + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + response = requests.get(apis_urls.serverURL + apis_urls.perimetersubjectAPI,headers=apis_urls.auth_headers) + if len(response.json()[apis_urls.perimetersubjectAPI]) != 0: + for ids in dict(response.json()[apis_urls.perimetersubjectAPI]).keys(): + policies_list = response.json()[apis_urls.perimetersubjectAPI][ids]['policy_list'] + for policy in policies_list: + response_delete_policies = requests.delete( + apis_urls.serverURL + "policies/" + policy + "/" + apis_urls.perimetersubjectAPI + "/" + ids, + headers=apis_urls.auth_headers) + response_delete = requests.delete(apis_urls.serverURL + apis_urls.perimetersubjectAPI + "/" + ids, + headers=apis_urls.auth_headers) + + # exit(0) + +# Step Definition Implementation: +# 1) Post subject perimeter using the policy id +@Given('the following subject perimeter exists') +def step_impl(context): + logger.info("Given the following subject perimeter exists") + model = getattr(context, "model", None) + for row in context.table: + logger.info( + "subject perimeter name: '" + row["subjectperimetername"] + "' subject perimeter description: '" + row[ + "subjectperimeterdescription"] # "' and subject perimeter email:'" + row[ + # "subjectperimeteremail"] + "' and subject perimeter password '" + row['subjectperimeterpassword'] + + "' and policies '" + row['policies'] + "'") + + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + policyid="" + if (row['policies'] != ""): + policyid = commonfunctions.get_policyid(row['policies']) + data = { + 'name': row["subjectperimetername"], + 'description': row["subjectperimeterdescription"], + # 'email': row['subjectperimeteremail'], + # 'password': row['subjectperimeterpassword'], + + } + response = requests.post( + apis_urls.serverURL + "policies/" + policyid + "/" + apis_urls.perimetersubjectAPI, headers=headers, + data=json.dumps(data)) + +# Step Definition Implementation: +# 1) Get all the existing object preimeters in the system +# 2) Loop by id to unlink the policies attached +# 3) Then delete the perimeter itself +@Given('the system has no object perimeter') +def step_impl(context): + logger.info("Given the system has no object perimeter") + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + response = requests.get(apis_urls.serverURL + apis_urls.perimeterobjectAPI,headers=apis_urls.auth_headers) + if len(response.json()[apis_urls.perimeterobjectAPI]) != 0: + for ids in dict(response.json()[apis_urls.perimeterobjectAPI]).keys(): + policies_list = response.json()[apis_urls.perimeterobjectAPI][ids]['policy_list'] + for policy in policies_list: + response_delete_policies = requests.delete( + apis_urls.serverURL + "policies/" + policy + "/" + apis_urls.perimeterobjectAPI + "/" + ids, + headers=headers) + response_delete = requests.delete(apis_urls.serverURL + apis_urls.perimeterobjectAPI + "/" + ids, + headers=apis_urls.auth_headers) + +# Step Definition Implementation: +# 1) Post object perimeter using the policy id +@Given('the following object perimeter exists') +def step_impl(context): + logger.info("Given the following object perimeter exists") + model = getattr(context, "model", None) + for row in context.table: + logger.info( + "object perimeter name: '" + row["objectperimetername"] + "' object perimeter description: '" + row[ + "objectperimeterdescription"] + "' and policies '" + row['policies'] + "'") + + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + if (row['policies'] != ""): + policyid = commonfunctions.get_policyid(row['policies']) + + data = { + 'name': row["objectperimetername"], + 'description': row["objectperimeterdescription"], + + } + response = requests.post(apis_urls.serverURL + "policies/" + policyid + "/" + apis_urls.perimeterobjectAPI, + headers=headers, + data=json.dumps(data)) + +# Step Definition Implementation: +# 1) Get all the existing action preimeters in the system +# 2) Loop by id to unlink the policies attached +# 3) Then delete the perimeter itself +@Given('the system has no action perimeter') +def step_impl(context): + logger.info("Given the system has no action perimeter") + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + response = requests.get(apis_urls.serverURL + apis_urls.perimeteractionAPI,headers=apis_urls.auth_headers) + if len(response.json()[apis_urls.perimeteractionAPI]) != 0: + for ids in dict(response.json()[apis_urls.perimeteractionAPI]).keys(): + policies_list = response.json()[apis_urls.perimeteractionAPI][ids]['policy_list'] + for policy in policies_list: + response_delete_policies = requests.delete( + apis_urls.serverURL + "policies/" + policy + "/" + apis_urls.perimeteractionAPI + "/" + ids, + headers=headers) + response_delete = requests.delete(apis_urls.serverURL + apis_urls.perimeteractionAPI + "/" + ids, + headers=apis_urls.auth_headers) + + +# Step Definition Implementation: +# 1) Post action perimeter using the policy id +@Given('the following action perimeter exists') +def step_impl(context): + logger.info("Given the following action perimeter exists") + model = getattr(context, "model", None) + for row in context.table: + logger.info( + "action perimeter name: '" + row["actionperimetername"] + "' action perimeter description: '" + row[ + "actionperimeterdescription"] + "' and policies '" + row['policies'] + "'") + + policyid="" + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + if (row['policies'] != ""): + policyid = commonfunctions.get_policyid(row['policies']) + data = { + 'name': row["actionperimetername"], + 'description': row["actionperimeterdescription"], + + } + response = requests.post(apis_urls.serverURL + "policies/" + policyid + "/" + apis_urls.perimeteractionAPI, + headers=headers, + data=json.dumps(data)) + +# Step Definition Implementation: +# 1) Insert subject perimeter using the post request +# 2) If the request code was 200 set the api response flag to true else false +@When('the user sets to add the following subject perimeter') +def step_impl(context): + logger.info("When the user sets to add the following subject perimeter") + + model = getattr(context, "model", None) + for row in context.table: + logger.info( + "subject perimeter name: '" + row["subjectperimetername"] + "' subject perimeter description: '" + row[ + "subjectperimeterdescription"] + + # "' and subject perimeter email:'" + row["subjectperimeteremail"] + "' and subject perimeter password '" + row['subjectperimeterpassword'] + + "' and policies '" + row['policies'] + "'") + + policyid = "" + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + if (row['policies'] != ""): + policyid = commonfunctions.get_policyid(row['policies']) + data = { + 'name': row["subjectperimetername"], + 'description': row["subjectperimeterdescription"], + # 'email': row['subjectperimeteremail'], + # 'password': row['subjectperimeterpassword'], + } + response = requests.post(apis_urls.serverURL + "policies/" + policyid + "/" + apis_urls.perimetersubjectAPI, headers=headers, + data=json.dumps(data)) + + if response.status_code == 200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Search for the existing subject perimeter & get its id +# 2) create the new perimeter jason and patch it +# 3) If the request code was 200 set the api response flag to true else false +@When('the user sets to update the following subject perimeter') +def step_impl(context): + logger.info("When the user sets to update the following subject perimeter") + model = getattr(context, "model", None) + policies_list = [] + for row in context.table: + logger.info( + "subject perimeter name: '" + row[ + 'subjectperimetername'] + "' which will be updated to subject perimeter name:'" + row[ + "updatedsubjectperimetername"] + "' subject perimeter description: '" + row[ + "updatedsubjectperimeterdescription"] + + # "' and subject perimeter email:'" + row["updatedsubjectperimeteremail"] + "' and subject perimeter password '" + row['updatedsubjectperimeterpassword'] + "' and policies '" + row['policies'] + "'") + + policyid = "" + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + if (row['policies'] != ""): + policyid=commonfunctions.get_policyid(row['policies']) + else: + policyid="" + data = { + 'name': row["updatedsubjectperimetername"], + 'description': row["updatedsubjectperimeterdescription"], + # 'email': row['subjectperimeteremail'], + # 'password': row['subjectperimeterpassword'], + } + response = requests.get(apis_urls.serverURL + apis_urls.perimetersubjectAPI,headers=apis_urls.auth_headers) + for ids in dict(response.json()[apis_urls.perimetersubjectAPI]).keys(): + if (response.json()[apis_urls.perimetersubjectAPI][ids]['name'] == row["subjectperimetername"]): + #print(apis_urls.serverURL + "policies/" + policyid + "/" + apis_urls.perimetersubjectAPI + '/' + ids) + response = requests.patch(apis_urls.serverURL + apis_urls.perimetersubjectAPI + '/' + ids, + headers=headers,data=json.dumps(data)) + print(response) + + if response.status_code == 200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Search for the existing subject perimeter & get its id +# 2) Delete it without having the policy id in the request +@When('the user sets to delete the following subject perimeter') +def step_impl(context): + logging.info("When the user sets to delete the following subject perimeter") + + model = getattr(context, "model", None) + for row in context.table: + headers = { + 'Content-Type': 'application/json', + } + logger.info("subject perimeter name:'" + row["subjectperimetername"] + "'") + response = requests.get(apis_urls.serverURL + apis_urls.perimetersubjectAPI,headers=apis_urls.auth_headers) + for ids in dict(response.json()[apis_urls.perimetersubjectAPI]).keys(): + if (response.json()[apis_urls.perimetersubjectAPI][ids]['name'] == row["subjectperimetername"]): + response = requests.delete(apis_urls.serverURL + apis_urls.perimetersubjectAPI + "/" + ids, + headers=apis_urls.auth_headers) + + if response.status_code == 200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Search for the existing subject perimeter & get its id +# 2) Delete it while having the policy id in the request +@When('the user sets to delete the following subject perimeter for a given policy') +def step_impl(context): + logging.info("the user sets to delete the following subject perimeter for a given policy") + + model = getattr(context, "model", None) + for row in context.table: + headers = { + 'Content-Type': 'application/json', + } + logger.info("subject perimeter name:'" + row["subjectperimetername"] + "' and policy:"+ row["policies"]+"'") + policyid = commonfunctions.get_policyid(row['policies']) + response = requests.get(apis_urls.serverURL + apis_urls.perimetersubjectAPI,headers=apis_urls.auth_headers) + for ids in dict(response.json()[apis_urls.perimetersubjectAPI]).keys(): + if (response.json()[apis_urls.perimetersubjectAPI][ids]['name'] == row["subjectperimetername"]): + response = requests.delete(apis_urls.serverURL + "policies/" + policyid + "/" + apis_urls.perimetersubjectAPI + "/" + ids, + headers=apis_urls.auth_headers) + logger.info(response.json()) + if response.status_code == 200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Insert object perimeter using the post request +# 2) If the request code was 200 set the api response flag to true else false +@When('the user sets to add the following object perimeter') +def step_impl(context): + logger.info("When the user sets to add the following object perimeter") + + model = getattr(context, "model", None) + for row in context.table: + logger.info( + "object perimeter name: '" + row["objectperimetername"] + "' object perimeter description: '" + row[ + "objectperimeterdescription"] + "' and policies '" + row['policies'] + "'") + + policies_list = [] + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + if (row['policies'] != ""): + policyid = commonfunctions.get_policyid(row['policies']) + else: + policyid="" + data = { + 'name': row["objectperimetername"], + 'description': row["objectperimeterdescription"], + } + response = requests.post(apis_urls.serverURL + "policies/" + policyid + "/" + apis_urls.perimeterobjectAPI, headers=headers, + data=json.dumps(data)) + + if response.status_code == 200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Search for the existing object perimeter & get its id +# 2) create the new perimeter jason and patch it +# 3) If the request code was 200 set the api response flag to true else false +@When('the user sets to update the following object perimeter') +def step_impl(context): + logger.info("When the user sets to update the following object perimeter") + model = getattr(context, "model", None) + for row in context.table: + logger.info( + "object perimeter name: '" + row[ + 'objectperimetername'] + "' which will be updated to object perimeter name:" + row[ + "updatedobjectperimetername"] + "' object perimeter description: '" + row[ + "updatedobjectperimeterdescription"] + "' and policies '" + row['policies'] + "'") + + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + if (row['policies'] != ""): + policyid = commonfunctions.get_policyid(row['policies']) + else: + policyid="" + data = { + 'name': row["updatedobjectperimetername"], + 'description': row["updatedobjectperimeterdescription"], + } + response = requests.get(apis_urls.serverURL + apis_urls.perimeterobjectAPI,headers=apis_urls.auth_headers) + for ids in dict(response.json()[apis_urls.perimeterobjectAPI]).keys(): + if (response.json()[apis_urls.perimeterobjectAPI][ids]['name'] == row["objectperimetername"]): + response = requests.patch(apis_urls.serverURL + apis_urls.perimeterobjectAPI + '/' + ids, + headers=headers,data=json.dumps(data)) + + if response.status_code == 200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Search for the existing object perimeter & get its id +# 2) Delete it without having the policy id in the request +@When('the user sets to delete the following object perimeter') +def step_impl(context): + logging.info("When the user sets to delete the following object perimeter") + + model = getattr(context, "model", None) + for row in context.table: + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + logger.info("object perimeter name:'" + row["objectperimetername"] + "'") + + response = requests.get(apis_urls.serverURL + apis_urls.perimeterobjectAPI,headers=apis_urls.auth_headers) + for ids in dict(response.json()[apis_urls.perimeterobjectAPI]).keys(): + if (response.json()[apis_urls.perimeterobjectAPI][ids]['name'] == row["objectperimetername"]): + response = requests.delete(apis_urls.serverURL + apis_urls.perimeterobjectAPI + "/" + ids, + headers=apis_urls.auth_headers) + + if response.status_code == 200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Search for the existing object perimeter & get its id +# 2) Delete it while having the policy id in the request +@When('the user sets to delete the following object perimeter for a given policy') +def step_impl(context): + logging.info("the user sets to delete the following object perimeter for a given policy") + + model = getattr(context, "model", None) + for row in context.table: + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + logger.info("object perimeter name:'" + row["objectperimetername"] + "' and policy:"+ row["policies"]+"'") + policyid = commonfunctions.get_policyid(row['policies']) + response = requests.get(apis_urls.serverURL + apis_urls.perimeterobjectAPI,headers=apis_urls.auth_headers) + for ids in dict(response.json()[apis_urls.perimeterobjectAPI]).keys(): + if (response.json()[apis_urls.perimeterobjectAPI][ids]['name'] == row["objectperimetername"]): + response = requests.delete(apis_urls.serverURL + "policies/" + policyid + "/" + apis_urls.perimeterobjectAPI + "/" + ids, + headers=apis_urls.auth_headers) + + if response.status_code == 200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Insert action perimeter using the post request +# 2) If the request code was 200 set the api response flag to true else false +@When('the user sets to add the following action perimeter') +def step_impl(context): + logger.info("When the user sets to add the following action perimeter") + + model = getattr(context, "model", None) + for row in context.table: + logger.info( + "action perimeter name: '" + row["actionperimetername"] + "' action perimeter description: '" + row[ + "actionperimeterdescription"] + "' and policies '" + row['policies'] + "'") + + policyid="" + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + if (row['policies'] != ""): + policyid = commonfunctions.get_policyid(row['policies']) + else: + policyid="" + data = { + 'name': row["actionperimetername"], + 'description': row["actionperimeterdescription"], + + } + response = requests.post( + apis_urls.serverURL + "policies/" + policyid + "/" + apis_urls.perimeteractionAPI, headers=headers, + data=json.dumps(data)) + + if response.status_code == 200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Search for the existing action perimeter & get its id +# 2) create the new perimeter jason and patch it +# 3) If the request code was 200 set the api response flag to true else false +@When('the user sets to update the following action perimeter') +def step_impl(context): + logger.info("When the user sets to update the following action perimeter") + + model = getattr(context, "model", None) + + for row in context.table: + + logger.info( + "action perimeter name: '" + row[ + 'actionperimetername'] + "' which will be updated to action perimeter name:" + row[ + "updatedactionperimetername"] + "' action perimeter description: '" + row[ + "updatedactionperimeterdescription"] + "' and policies '" + row['policies'] + "'") + + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + if (row['policies'] != ""): + policyid = commonfunctions.get_policyid(row['policies']) + else: + policyid="" + data = { + 'name': row["updatedactionperimetername"], + 'description': row["updatedactionperimeterdescription"], + } + response = requests.get(apis_urls.serverURL + apis_urls.perimeteractionAPI,headers=apis_urls.auth_headers) + for ids in dict(response.json()[apis_urls.perimeteractionAPI]).keys(): + if (response.json()[apis_urls.perimeteractionAPI][ids]['name'] == row["actionperimetername"]): + response = requests.patch( + apis_urls.serverURL + apis_urls.perimeteractionAPI + '/' + ids, + headers=headers,data=json.dumps(data)) + + if response.status_code == 200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Search for the existing action perimeter & get its id +# 2) Delete it without having the policy id in the request +@When('the user sets to delete the following action perimeter') +def step_impl(context): + logging.info("When the user sets to delete the following action perimeter") + + model = getattr(context, "model", None) + for row in context.table: + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + logger.info("action perimeter name:'" + row["actionperimetername"] + "'") + response = requests.get(apis_urls.serverURL + apis_urls.perimeteractionAPI,headers=apis_urls.auth_headers) + for ids in dict(response.json()[apis_urls.perimeteractionAPI]).keys(): + if (response.json()[apis_urls.perimeteractionAPI][ids]['name'] == row["actionperimetername"]): + response = requests.delete(apis_urls.serverURL + apis_urls.perimeteractionAPI + "/" + ids, + headers=apis_urls.auth_headers) + if response.status_code == 200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Search for the existing action perimeter & get its id +# 2) Delete it while having the policy id in the request +@When('the user sets to delete the following action perimeter for a given policy') +def step_impl(context): + logging.info("the user sets to delete the following action perimeter for a given policy") + + model = getattr(context, "model", None) + for row in context.table: + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + logger.info("action perimeter name:'" + row["actionperimetername"] + "' and policy:"+ row["policies"]+"'") + policyid = commonfunctions.get_policyid(row['policies']) + response = requests.get(apis_urls.serverURL + apis_urls.perimeteractionAPI,headers=apis_urls.auth_headers) + for ids in dict(response.json()[apis_urls.perimeteractionAPI]).keys(): + if (response.json()[apis_urls.perimeteractionAPI][ids]['name'] == row["actionperimetername"]): + response = requests.delete(apis_urls.serverURL + "policies/" + policyid + "/" + apis_urls.perimeteractionAPI + "/" + ids, + headers=apis_urls.auth_headers) + + if response.status_code == 200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Get all the existing subject perimeter by get request and put them into a table +# 2) Sort the table by subject perimeter +# 3) Loop using both the expected and actual tables and assert the data row by row +@Then('the following subject perimeter should be existed in the system') +def step_impl(context): + logger.info("Then the following subject perimeter should be existed in the system") + + response = requests.get(apis_urls.serverURL + apis_urls.perimetersubjectAPI,headers=apis_urls.auth_headers) + apiresult = Table( + names=('subjectperimetername', 'subjectperimeterdescription', + # 'subjectperimeteremail', + # 'subjectperimeterpassword', + 'policies'), + dtype=('S100', 'S100', 'S100')) + + if len(response.json()[apis_urls.perimetersubjectAPI]) != 0: + for ids in dict(response.json()[apis_urls.perimetersubjectAPI]).keys(): + apipoliciesid = [] + apipolicies = "" + GeneralVariables.assignsubjectperimeterid['value']=ids + apisubjectperimetername = response.json()[apis_urls.perimetersubjectAPI][ids]['name'] + apisubjectperimeterdescription = response.json()[apis_urls.perimetersubjectAPI][ids]['description'] + # apisubjectperimeteremail = response.json()[apis_urls.perimetersubjectAPI][ids]['email'] + # apisubjectperimeterpassword = response.json()[apis_urls.perimetersubjectAPI][ids]['password'] + if (len(response.json()[apis_urls.perimetersubjectAPI][ids]['policy_list']) != 0): + for policies in response.json()[apis_urls.perimetersubjectAPI][ids]['policy_list']: + apipoliciesid.append(commonfunctions.get_policyname(str(policies))) + apipolicies = ",".join(apipoliciesid) + else: + apipolicies = "" + apiresult.add_row(vals=( + apisubjectperimetername, apisubjectperimeterdescription, + # apisubjectperimeteremail,# apisubjectperimeterpassword, + apipolicies)) + else: + apiresult.add_row(vals=("", "", "")) + + apiresult.sort('subjectperimetername') + for row1, row2 in zip(context.table, apiresult): + logger.info("asserting the expected subject perimeter name: '" + str( + row1["subjectperimetername"]) + "' is the same as the actual existing '" + str( + row2["subjectperimetername"]) + "'") + assert str(row1["subjectperimetername"]) == str( + row2["subjectperimetername"]), "subject perimeter name is not correct!" + logger.info("assertion passed!") + + logger.info("asserting the expected subject perimeter description: '" + str( + row1["subjectperimeterdescription"]) + "' is the same as the actual existing '" + str( + row2["subjectperimeterdescription"]) + "'") + assert str(row1["subjectperimeterdescription"]) == str( + row2["subjectperimeterdescription"]), "subject perimeter description is not correct!" + logger.info("assertion passed!") + + # logger.info("asserting the expected subject perimeter email: '" + str( + # row1["subjectperimeteremail"]) + "' is the same as the actual existing '" + str( + # row2["subjectperimeteremail"]) + "'") + # assert str(row1["subjectperimeteremail"]) == str( + # row2["subjectperimeteremail"]), "subject perimeter email is not correct!" + # logger.info("assertion passed!") + # + # logger.info("asserting the expected subject perimeter password: '" + str( + # row1["subjectperimeterpassword"]) + "' is the same as the actual existing '" + str( + # row2["subjectperimeterpassword"]) + "'") + # assert str(row1["subjectperimeterpassword"]) == str( + # row2["subjectperimeterpassword"]), "subject perimeter password is not correct!" + # logger.info("assertion passed!") + + if (str(row1["policies"]).find(',') == -1): + logger.info("asserting the expected policies: '" + str( + row1["policies"]) + "' is the same as the actual existing '" + str( + row2["policies"]) + "'") + logger.info("policies is not correct!") + assert str(row1["policies"]) == str(row2["policies"]), " policies is not correct!" + else: + + logger.info("asserting the expected policies: '" + ','.join( + sorted(str(row1["policies"]).split(','), key=str.lower)) + "' is the same as the actual existing '" + + ','.join(sorted(str(row2["policies"]).split(','), key=str.lower)) + "'") + logger.info("policies is not correct!") + assert ','.join(sorted(str(row1["policies"]).split(','), key=str.lower)) == ','.join( + sorted(str(row2["policies"]).split(','), key=str.lower)), " policies is not correct!" + logger.info("assertion passed!") + +# Step Definition Implementation: +# 1) Get all the existing object perimeter by get request and put them into a table +# 2) Sort the table by subject perimeter +# 3) Loop using both the expected and actual tables and assert the data row by row +@Then('the following object perimeter should be existed in the system') +def step_impl(context): + logger.info("Then the following object perimeter should be existed in the system") + response = requests.get(apis_urls.serverURL + apis_urls.perimeterobjectAPI,headers=apis_urls.auth_headers) + apiresult = Table( + names=('objectperimetername', 'objectperimeterdescription', 'policies'), + dtype=('S100', 'S100', 'S100')) + if len(response.json()[apis_urls.perimeterobjectAPI]) != 0: + for ids in dict(response.json()[apis_urls.perimeterobjectAPI]).keys(): + apipolicies = "" + apipoliciesid = [] + apiobjectperimetername = response.json()[apis_urls.perimeterobjectAPI][ids]['name'] + apiobjectperimeterdescription = response.json()[apis_urls.perimeterobjectAPI][ids]['description'] + if (len(response.json()[apis_urls.perimeterobjectAPI][ids]['policy_list']) != 0): + for policies in response.json()[apis_urls.perimeterobjectAPI][ids]['policy_list']: + apipoliciesid.append(commonfunctions.get_policyname(str(policies))) + apipolicies = ",".join(apipoliciesid) + else: + apipolicies = "" + apiresult.add_row(vals=( + apiobjectperimetername, apiobjectperimeterdescription, apipolicies)) + else: + apiresult.add_row(vals=("", "", "")) + + apiresult.sort('objectperimetername') + for row1, row2 in zip(context.table, apiresult): + logger.info("asserting the expected object perimeter name: '" + str( + row1["objectperimetername"]) + "' is the same as the actual existing '" + str( + row2["objectperimetername"]) + "'") + assert str(row1["objectperimetername"]) == str( + row2["objectperimetername"]), "object perimeter name is not correct!" + logger.info("assertion passed!") + + logger.info("asserting the expected object perimeter description: '" + str( + row1["objectperimeterdescription"]) + "' is the same as the actual existing '" + str( + row2["objectperimeterdescription"]) + "'") + assert str(row1["objectperimeterdescription"]) == str( + row2["objectperimeterdescription"]), "object perimeter description is not correct!" + logger.info("assertion passed!") + + if (str(row1["policies"]).find(',') == -1): + logger.info("asserting the expected policies: '" + str( + row1["policies"]) + "' is the same as the actual existing '" + str( + row2["policies"]) + "'") + logger.info("policies is not correct!") + assert str(row1["policies"]) == str(row2["policies"]), " policies is not correct!" + else: + logger.info("asserting the expected policies: '" + ','.join( + sorted(str(row1["policies"]).split(','), key=str.lower)) + "' is the same as the actual existing '" + + ','.join(sorted(str(row2["policies"]).split(','), key=str.lower)) + "'") + logger.info("policies is not correct!") + assert ','.join(sorted(str(row1["policies"]).split(','), key=str.lower)) == ','.join( + sorted(str(row2["policies"]).split(','), key=str.lower)), " policies is not correct!" + logger.info("assertion passed!") + +# Step Definition Implementation: +# 1) Get all the existing subject perimeter by get request and put them into a table +# 2) Sort the table by subject perimeter +# 3) Loop using both the expected and actual tables and assert the data row by row +@Then('the following action perimeter should be existed in the system') +def step_impl(context): + logger.info("Then the following action perimeter should be existed in the system") + response = requests.get(apis_urls.serverURL + apis_urls.perimeteractionAPI,headers=apis_urls.auth_headers) + apiresult = Table( + names=('actionperimetername', 'actionperimeterdescription', 'policies'), + dtype=('S100', 'S100', 'S100')) + if len(response.json()[apis_urls.perimeteractionAPI]) != 0: + for ids in dict(response.json()[apis_urls.perimeteractionAPI]).keys(): + apipolicies = "" + apipoliciesid = [] + apiactionperimetername = response.json()[apis_urls.perimeteractionAPI][ids]['name'] + apiactionperimeterdescription = response.json()[apis_urls.perimeteractionAPI][ids]['description'] + if (len(response.json()[apis_urls.perimeteractionAPI][ids]['policy_list']) != 0): + for policies in response.json()[apis_urls.perimeteractionAPI][ids]['policy_list']: + apipoliciesid.append(commonfunctions.get_policyname(str(policies))) + apipolicies = ",".join(apipoliciesid) + else: + apipolicies = "" + apiresult.add_row(vals=( + apiactionperimetername, apiactionperimeterdescription, apipolicies)) + else: + apiresult.add_row(vals=("", "", "")) + + apiresult.sort('actionperimetername') + for row1, row2 in zip(context.table, apiresult): + logger.info("asserting the expected action perimeter name: '" + str( + row1["actionperimetername"]) + "' is the same as the actual existing '" + str( + row2["actionperimetername"]) + "'") + assert str(row1["actionperimetername"]) == str( + row2["actionperimetername"]), "action perimeter name is not correct!" + logger.info("assertion passed!") + + logger.info("asserting the expected action perimeter description: '" + str( + row1["actionperimeterdescription"]) + "' is the same as the actual existing '" + str( + row2["actionperimeterdescription"]) + "'") + assert str(row1["actionperimeterdescription"]) == str( + row2["actionperimeterdescription"]), "action perimeter description is not correct!" + logger.info("assertion passed!") + + if(str(row1["policies"]).find(',')==-1): + logger.info("asserting the expected policies: '" + str( + row1["policies"]) + "' is the same as the actual existing '" + str( + row2["policies"]) + "'") + logger.info("policies is not correct!") + assert str(row1["policies"]) == str(row2["policies"]), " policies is not correct!" + else: + + logger.info("asserting the expected policies: '" + ','.join(sorted(str(row1["policies"]).split(','),key=str.lower)) + "' is the same as the actual existing '" + + ','.join(sorted(str(row2["policies"]).split(','), key=str.lower)) + "'") + logger.info("policies is not correct!") + assert ','.join(sorted(str(row1["policies"]).split(','),key=str.lower)) == ','.join(sorted(str(row2["policies"]).split(','),key=str.lower)), " policies is not correct!" + logger.info("assertion passed!") diff --git a/moon_manager/tests/func_tests/features/steps/policy.py b/moon_manager/tests/func_tests/features/steps/policy.py new file mode 100644 index 00000000..faa7156a --- /dev/null +++ b/moon_manager/tests/func_tests/features/steps/policy.py @@ -0,0 +1,219 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +from behave import * +from Static_Variables import GeneralVariables +from astropy.table import Table, Column +from common_functions import * +import requests +import json +import logging + +apis_urls = GeneralVariables() +commonfunctions = commonfunctions() + +logger = logging.getLogger(__name__) + +# Step Definition Implementation: +# 1) Get all the existing policies in the system +# 2) Loop by id and delete them +@Given('the system has no policies') +def step_impl(context): + logger.info("Given the system has no policies") + api_responseflag = {'value': False} + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + response = requests.get(apis_urls.serverURL + apis_urls.policyAPI, headers=apis_urls.auth_headers) + if len(response.json()[apis_urls.policyAPI]) != 0: + for ids in dict(response.json()[apis_urls.policyAPI]).keys(): + response = requests.delete(apis_urls.serverURL + apis_urls.policyAPI + "/" + ids, + headers=headers) + + +# Step Definition Implementation: +# 1) Get model id by calling the common funtion: get_modelid +# 2) create the policy data jason then post it +@Given('the following policy exists') +def step_impl(context): + logger.info("Given the following policy exists") + model = getattr(context, "model", None) + for row in context.table: + logger.info( + "policy name: '" + row["policyname"] + "' policy description: '" + row[ + "policydescription"] + "' and model name:'" + row[ + "modelname"] + "' and genre '"+row['genre']+"'") + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + data = { + 'name': row["policyname"], + 'description': row["policydescription"], + 'model_id': commonfunctions.get_modelid(row['modelname']), + 'genre': row['genre'] + } + response = requests.post(apis_urls.serverURL + apis_urls.policyAPI, headers=headers, + data=json.dumps(data)) + + +# Step Definition Implementation: +# 1) Get model id by calling the common funtion: get_modelid +# 2) create the policy data jason then post it +# 3) If the request code was 200 set the api response flag to true else false +@When('the user sets to add the following policy') +def step_impl(context): + logger.info("When the user sets to add the following policy") + model = getattr(context, "model", None) + for row in context.table: + logger.info( + "policy name: '" + row["policyname"] + "' policy description: '" + row[ + "policydescription"] + "' and model name:'" + row[ + "modelname"] + "' and genre '" + row['genre'] + "'") + policymodel = "" + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + if (len(row['modelname']) > 20): + policymodel=row['modelname'] + else: + policymodel=commonfunctions.get_modelid(row['modelname']) + + data = { + 'name': row["policyname"], + 'description': row["policydescription"], + 'model_id': policymodel, + 'genre': row['genre'] + } + response = requests.post(apis_urls.serverURL + apis_urls.policyAPI, headers=headers, + data=json.dumps(data)) + + if response.status_code==200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + + +# Step Definition Implementation: +# 1) Get model id by calling the common funtion: get_modelid +# 2) create the policy jason then patch the policy after searching for it's id. +# 3) If the request code was 200 set the api response flag to true else false +@When('the user sets to update the following policy') +def step_impl(context): + logger.info("When the user sets to update the following policy") + model = getattr(context, "model", None) + for row in context.table: + logger.info( + "policy name: '" + row["policyname"] + "' which will be updated to policy name:" + row[ + "updatedpolicyname"] + "' and policy description: '" + row[ + "updatedpolicydescription"] + "' model name: '" + row["updatedmodelname"] + "' and genre: '"+row["updatedgenre"]+"'") + policymodel = "" + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + if (len(row['updatedmodelname']) > 20): + policymodel = row['updatedmodelname'] + else: + policymodel = commonfunctions.get_modelid(row['updatedmodelname']) + + data = { + 'name': row["updatedpolicyname"], + 'description': row["updatedpolicydescription"], + 'model_id': policymodel, + 'genre': row['updatedgenre'] + } + response = requests.get(apis_urls.serverURL + apis_urls.policyAPI, headers=apis_urls.auth_headers) + for ids in dict(response.json()[apis_urls.policyAPI]).keys(): + if (response.json()[apis_urls.policyAPI][ids]['name'] == row["policyname"]): + print(apis_urls.serverURL + apis_urls.policyAPI + '/' + ids) + response = requests.patch(apis_urls.serverURL + apis_urls.policyAPI + '/' + ids, headers=headers, + data=json.dumps(data)) + logger.info(response.json()) + logger.info(response.status_code) + break + if response.status_code==200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Get all the policy by get request +# 2) Loop by ids and search for the matching policy by name and delete it +# 3) If the request code was 200 set the api response flag to true else false +@When('the user sets to delete the following policy') +def step_impl(context): + logger.info("When the user sets to delete the following policy") + + model = getattr(context, "model", None) + for row in context.table: + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + logger.info("policy name:'" +row["policyname"]+"'") + response = requests.get(apis_urls.serverURL + apis_urls.policyAPI, headers=apis_urls.auth_headers) + for ids in dict(response.json()[apis_urls.policyAPI]).keys(): + if (response.json()[apis_urls.policyAPI][ids]['name'] == row["policyname"]): + GeneralVariables.assignpolicyid['value']=ids + response = requests.delete(apis_urls.serverURL + apis_urls.policyAPI + "/" + ids, + headers=headers) + break + + if response.status_code==200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Get all the existing policies by get request and put them into a table +# 2) Sort the table by policy name +# 3) Loop using both the expected and actual tables and assert the data row by row +@Then('the following policy should be existed in the system') +def step_impl(context): + logger.info("Then the following policy should be existed in the system") + response = requests.get(apis_urls.serverURL + apis_urls.policyAPI, headers=apis_urls.auth_headers) + #print(response) + apiresult = Table( + names=('policyname', 'policydescription', 'modelname','genre'), + dtype=('S100', 'S100', 'S100','S100')) + if len(response.json()[apis_urls.policyAPI]) != 0: + for ids in dict(response.json()[apis_urls.policyAPI]).keys(): + apipolicyname = response.json()[apis_urls.policyAPI][ids]['name'] + apipolicydescription = response.json()[apis_urls.policyAPI][ids]['description'] + apipolicymodel = commonfunctions.get_modelname(response.json()[apis_urls.policyAPI][ids]['model_id']) + apipolicygenre=response.json()[apis_urls.policyAPI][ids]['genre'] + + apiresult.add_row(vals=( + apipolicyname, apipolicydescription, apipolicymodel,apipolicygenre)) + + else: + apiresult.add_row(vals=("", "", "","")) + + apiresult.sort('policyname') + + for row1, row2 in zip(context.table, apiresult): + logger.info("asserting the expected policy name: '" + str( + row1["policyname"]) + "' is the same as the actual existing '" + str( + row2["policyname"]) + "'") + assert str(row1["policyname"]) == str(row2["policyname"]), "policy name is not correct!" + logger.info("assertion passed!") + + logger.info("asserting the expected policy description: '" + str( + row1["policydescription"]) + "' is the same as the actual existing '" + str( + row2["policydescription"]) + "'") + assert str(row1["policydescription"]) == str(row2["policydescription"]), "policy description is not correct!" + logger.info("assertion passed!") + + logger.info("asserting the expected genre: '" + str( + row1["genre"]) + "' is the same as the actual existing '" + str( + row2["genre"]) + "'") + assert str(row1["genre"]) == str(row2["genre"]), "genre is not correct!" + logger.info("assertion passed!") + + logger.info("asserting the expected model name: '" + str( + row1["modelname"]) + "' is the same as the actual existing '" + str( + row2["modelname"]) + "'") + assert str(row1["modelname"]) == str(row2["modelname"]), "model name is not correct!" + logger.info("assertion passed!") \ No newline at end of file diff --git a/moon_manager/tests/func_tests/features/steps/rules.py b/moon_manager/tests/func_tests/features/steps/rules.py new file mode 100644 index 00000000..4dd85e2c --- /dev/null +++ b/moon_manager/tests/func_tests/features/steps/rules.py @@ -0,0 +1,495 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +from behave import * +from Static_Variables import GeneralVariables +from astropy.table import Table, Column +from common_functions import * +import numpy as np +import requests +import json +import logging + +apis_urls = GeneralVariables() +commonfunctions = commonfunctions() + +logger = logging.getLogger(__name__) + +# Step Definition Implementation: +# 1) Get all the existing rules by the policy id +# 2) Loop by assignment id and delete it +@Given('the system has no rules') +def step_impl(context): + logger.info("Given the system has no rules") + + response_policies = requests.get(apis_urls.serverURL + apis_urls.policyAPI, headers=apis_urls.auth_headers) + #logger.info(response_policies.json()) + if len(response_policies.json()[apis_urls.policyAPI]) != 0: + apiruleid = [] + for policies_ids in dict(response_policies.json()[apis_urls.policyAPI]).keys(): + response = requests.get( + apis_urls.serverURL + "policies/" + policies_ids + "/" + apis_urls.rulesAPI + "/", headers=apis_urls.auth_headers) + if len(response.json()[apis_urls.rulesAPI]['rules']) != 0: + for ids in range(len(response.json()[apis_urls.rulesAPI]['rules'])): + apiruleid.append(dict(response.json()[apis_urls.rulesAPI]['rules'][ids])['id']) + for ruleid in apiruleid: + response = requests.delete( + apis_urls.serverURL + "policies/" + policies_ids + "/" + apis_urls.rulesAPI + "/" + ruleid, headers=apis_urls.auth_headers) + +# Step Definition Implementation: +# 1) Add rule using the post request +@Given('the following rule exists') +def step_impl(context): + logger.info("Given the following rule exists") + api_responseflag = {'value': False} + model = getattr(context, "model", None) + for row in context.table: + subjectcategoryidslist = [] + subjectdataidslist = [] + objectcategoryidslist = [] + objectdataidslist = [] + actioncategoryidslist = [] + actiondataidslist = [] + ruleidslist = [] + metaruleids = "" + subjectindex = 0 + objectindex = 0 + actionindex = 0 + logger.info( + "rule '" + row["rule"] + "' and metarule name:'" + row[ + "metarulename"] + "' and instructions: '" + row[ + "instructions"] + "' and policyname:'" + row[ + "policyname"] + "'") + + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + if (len(row['policyname']) > 25): + policies_id = row['policyname'] + else: + policies_id = commonfunctions.get_policyid(row['policyname']) + + ruleparameter = row["rule"].split(",") + metarules_response = requests.get(apis_urls.serverURL + apis_urls.metarulesAPI, headers=apis_urls.auth_headers) + for metaruleids in dict(metarules_response.json()[apis_urls.metarulesAPI]).keys(): + if (metarules_response.json()[apis_urls.metarulesAPI][metaruleids]['name'] == row["metarulename"]): + meta_rule_id = metaruleids + subjectcategorieslist = \ + requests.get(apis_urls.serverURL + apis_urls.metarulesAPI, headers=apis_urls.auth_headers).json()[apis_urls.metarulesAPI][ + metaruleids]['subject_categories'] + objectcategorieslist = \ + requests.get(apis_urls.serverURL + apis_urls.metarulesAPI, headers=apis_urls.auth_headers).json()[apis_urls.metarulesAPI][ + metaruleids]['object_categories'] + actioncategorieslist = \ + requests.get(apis_urls.serverURL + apis_urls.metarulesAPI, headers=apis_urls.auth_headers).json()[apis_urls.metarulesAPI][ + metaruleids]['action_categories'] + break + + index = 0 + for categoryid in subjectcategorieslist: + data_response = requests.get( + apis_urls.serverURL + "policies/" + policies_id + "/" + apis_urls.datasubjectAPI + "/" + categoryid, headers=apis_urls.auth_headers) + if len(data_response.json()[apis_urls.datasubjectAPI]) != 0: + for ids in data_response.json()[apis_urls.datasubjectAPI][0]['data']: + if (data_response.json()[apis_urls.datasubjectAPI][0]['data'][str(ids)]['name'] == ruleparameter[ + index]): + ruleidslist.append(ids) + index = index + 1 + + for categoryid in objectcategorieslist: + data_response = requests.get( + apis_urls.serverURL + "policies/" + policies_id + "/" + apis_urls.dataobjectAPI + "/" + categoryid, headers=apis_urls.auth_headers) + if len(data_response.json()[apis_urls.dataobjectAPI]) != 0: + for ids in data_response.json()[apis_urls.dataobjectAPI][0]['data']: + if (data_response.json()[apis_urls.dataobjectAPI][0]['data'][str(ids)]['name'] == ruleparameter[ + index]): + ruleidslist.append(ids) + index = index + 1 + for categoryid in actioncategorieslist: + data_response = requests.get( + apis_urls.serverURL + "policies/" + policies_id + "/" + apis_urls.dataactionAPI + "/" + categoryid, headers=apis_urls.auth_headers) + if len(data_response.json()[apis_urls.dataactionAPI]) != 0: + for ids in data_response.json()[apis_urls.dataactionAPI][0]['data']: + if (data_response.json()[apis_urls.dataactionAPI][0]['data'][str(ids)]['name'] == ruleparameter[ + index]): + ruleidslist.append(ids) + index = index + 1 + + data = { + 'meta_rule_id': meta_rule_id, + 'rule': ruleidslist, + 'instructions': [{"decision": row['instructions']}], + 'enabled': 'True' + } + rulesresponse = requests.post(apis_urls.serverURL + "policies/" + str(policies_id) + "/" + apis_urls.rulesAPI, + headers=headers, + data=json.dumps(data)) + + +# Step Definition Implementation: +# 1) Add subject meta data using the post request +# 2) If the request code was 200 set the api response flag to true else false +@When('the user sets to add the following rules') +def step_impl(context): + logger.info("When the user sets to add the following rules") + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + api_responseflag = {'value': False} + model = getattr(context, "model", None) + for row in context.table: + subjectcategoryidslist = [] + subjectdataidslist = [] + objectcategoryidslist = [] + objectdataidslist = [] + actioncategoryidslist = [] + actiondataidslist = [] + ruleidslist = [] + metaruleids = "" + subjectindex = 0 + objectindex = 0 + actionindex = 0 + logger.info( + "rule '" + row["rule"] + "' and metarule name:'" + row[ + "metarulename"] + "' and instructions: '" + row[ + "instructions"] + "' and policyname:'" + row[ + "policyname"] + "'") + + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + if(row['policyname']=="" or row['policyname']=="000000000000000000000000000000000000000000000000000"): + policyname="Stanford Policy" + else: + policyname=row['policyname'] + policies_id = commonfunctions.get_policyid(policyname) + + if(row["metarulename"]=="" or row["metarulename"]=="000000000000000000000000000000000000000000000000000"): + mata_rule_name="metarule1" + else: + mata_rule_name = row['metarulename'] + + + if (row["rule"] != ""): + ruleparameter = row["rule"].split(",") + metarules_response = requests.get(apis_urls.serverURL + apis_urls.metarulesAPI, headers=apis_urls.auth_headers) + for metaruleids in dict(metarules_response.json()[apis_urls.metarulesAPI]).keys(): + if (metarules_response.json()[apis_urls.metarulesAPI][metaruleids]['name'] == mata_rule_name): + meta_rule_id = metaruleids + subjectcategorieslist = \ + requests.get(apis_urls.serverURL + apis_urls.metarulesAPI, headers=apis_urls.auth_headers).json()[apis_urls.metarulesAPI][ + metaruleids]['subject_categories'] + objectcategorieslist = \ + requests.get(apis_urls.serverURL + apis_urls.metarulesAPI, headers=apis_urls.auth_headers).json()[apis_urls.metarulesAPI][ + metaruleids]['object_categories'] + actioncategorieslist = \ + requests.get(apis_urls.serverURL + apis_urls.metarulesAPI, headers=apis_urls.auth_headers).json()[apis_urls.metarulesAPI][ + metaruleids]['action_categories'] + break + + index = 0 + for categoryid in subjectcategorieslist: + if (index < len(ruleparameter)): + if (len(ruleparameter[index]) < 30): + if (ruleparameter[index] != ""): + data_response = requests.get( + apis_urls.serverURL + "policies/" + policies_id + "/" + apis_urls.datasubjectAPI + "/" + categoryid, headers=apis_urls.auth_headers) + if len(data_response.json()[apis_urls.datasubjectAPI]) != 0: + for ids in data_response.json()[apis_urls.datasubjectAPI][0]['data']: + if (index < len(ruleparameter)): + if (data_response.json()[apis_urls.datasubjectAPI][0]['data'][str(ids)][ + 'name'] == + ruleparameter[ + index]): + ruleidslist.append(ids) + index = index + 1 + else: + break + else: + ruleidslist.append("") + index = index + 1 + else: + ruleidslist.append(ruleparameter[index]) + index = index + 1 + for categoryid in objectcategorieslist: + if (index < len(ruleparameter)): + if (len(ruleparameter[index]) < 30): + if (ruleparameter[index] != ""): + data_response = requests.get( + apis_urls.serverURL + "policies/" + policies_id + "/" + apis_urls.dataobjectAPI + "/" + categoryid, headers=apis_urls.auth_headers) + if len(data_response.json()[apis_urls.dataobjectAPI]) != 0: + for ids in data_response.json()[apis_urls.dataobjectAPI][0]['data']: + if (index < len(ruleparameter)): + if (data_response.json()[apis_urls.dataobjectAPI][0]['data'][str(ids)][ + 'name'] == ruleparameter[ + index]): + ruleidslist.append(ids) + index = index + 1 + else: + break + else: + ruleidslist.append("") + index = index + 1 + else: + ruleidslist.append(ruleparameter[index]) + index = index + 1 + + for categoryid in actioncategorieslist: + if (index < len(ruleparameter)): + if (len(ruleparameter[index]) < 30): + if (ruleparameter[index] != ""): + data_response = requests.get( + apis_urls.serverURL + "policies/" + policies_id + "/" + apis_urls.dataactionAPI + "/" + categoryid, headers=apis_urls.auth_headers) + if len(data_response.json()[apis_urls.dataactionAPI]) != 0: + for ids in data_response.json()[apis_urls.dataactionAPI][0]['data']: + if (index < len(ruleparameter)): + if (data_response.json()[apis_urls.dataactionAPI][0]['data'][str(ids)][ + 'name'] == ruleparameter[ + index]): + ruleidslist.append(ids) + index = index + 1 + else: + break + else: + ruleidslist.append("") + index = index + 1 + else: + ruleidslist.append(ruleparameter[index]) + index = index + 1 + if(row["metarulename"]=="" or row["metarulename"] == "000000000000000000000000000000000000000000000000000"): + meta_rule_id=row["metarulename"] + if (row["policyname"] == "" or row["policyname"] == "000000000000000000000000000000000000000000000000000"): + policies_id = row["policyname"] + data = { + 'meta_rule_id': meta_rule_id, + 'rule': ruleidslist, + 'instructions': [{"decision": row['instructions']}], + 'enabled': 'True' + } + else: + + data = { + 'meta_rule_id': commonfunctions.get_metaruleid(mata_rule_name), + 'rule': [], + 'instructions': [{"decision": row['instructions']}], + 'enabled': 'True' + } + rulesresponse = requests.post(apis_urls.serverURL + "policies/" + str(policies_id) + "/" + apis_urls.rulesAPI, + headers=headers, + data=json.dumps(data)) + logger.info(rulesresponse.json()) + if rulesresponse.status_code == 200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Get all the meta rule by get request +# 2) Loop by ids and search for the matching meta rule by name and delete it +# 3) If the request code was 200 set the api response flag to true else false +@When('the user sets to delete the following rules') +def step_impl(context): + logger.info("When the user sets to delete the following rules") + for row in context.table: + subjectcategoryidslist = [] + subjectdataidslist = [] + objectcategoryidslist = [] + objectdataidslist = [] + actioncategoryidslist = [] + actiondataidslist = [] + ruleidslist = [] + metaruleids = "" + subjectindex = 0 + objectindex = 0 + actionindex = 0 + logger.info( + "rule '" + row["rule"] + "' and metarule name:'" + row[ + "metarulename"] + "' and policyname:'" + row[ + "policyname"] + "'") + + headers = {"Content-Type": "application/json", "X-Api-Key": apis_urls.token} + + if (len(row['policyname']) > 25): + policies_id = row['policyname'] + else: + policies_id = commonfunctions.get_policyid(row['policyname']) + + ruleparameter = row["rule"].split(",") + metarules_response = requests.get(apis_urls.serverURL + apis_urls.metarulesAPI, headers=apis_urls.auth_headers) + for metaruleids in dict(metarules_response.json()[apis_urls.metarulesAPI]).keys(): + if (metarules_response.json()[apis_urls.metarulesAPI][metaruleids]['name'] == row["metarulename"]): + meta_rule_id = metaruleids + subjectcategorieslist = \ + requests.get(apis_urls.serverURL + apis_urls.metarulesAPI, headers=apis_urls.auth_headers).json()[apis_urls.metarulesAPI][ + metaruleids]['subject_categories'] + objectcategorieslist = \ + requests.get(apis_urls.serverURL + apis_urls.metarulesAPI, headers=apis_urls.auth_headers).json()[apis_urls.metarulesAPI][ + metaruleids]['object_categories'] + actioncategorieslist = \ + requests.get(apis_urls.serverURL + apis_urls.metarulesAPI, headers=apis_urls.auth_headers).json()[apis_urls.metarulesAPI][ + metaruleids]['action_categories'] + break + + index = 0 + for categoryid in subjectcategorieslist: + data_response = requests.get( + apis_urls.serverURL + "policies/" + policies_id + "/" + apis_urls.datasubjectAPI + "/" + categoryid, headers=apis_urls.auth_headers) + if len(data_response.json()[apis_urls.datasubjectAPI]) != 0: + for ids in data_response.json()[apis_urls.datasubjectAPI][0]['data']: + if (data_response.json()[apis_urls.datasubjectAPI][0]['data'][str(ids)]['name'] == ruleparameter[ + index]): + ruleidslist.append(ids) + index = index + 1 + + for categoryid in objectcategorieslist: + data_response = requests.get( + apis_urls.serverURL + "policies/" + policies_id + "/" + apis_urls.dataobjectAPI + "/" + categoryid, headers=apis_urls.auth_headers) + if len(data_response.json()[apis_urls.dataobjectAPI]) != 0: + for ids in data_response.json()[apis_urls.dataobjectAPI][0]['data']: + if (data_response.json()[apis_urls.dataobjectAPI][0]['data'][str(ids)]['name'] == ruleparameter[ + index]): + ruleidslist.append(ids) + index = index + 1 + for categoryid in actioncategorieslist: + data_response = requests.get( + apis_urls.serverURL + "policies/" + policies_id + "/" + apis_urls.dataactionAPI + "/" + categoryid, headers=apis_urls.auth_headers) + if len(data_response.json()[apis_urls.dataactionAPI]) != 0: + for ids in data_response.json()[apis_urls.dataactionAPI][0]['data']: + if (data_response.json()[apis_urls.dataactionAPI][0]['data'][str(ids)]['name'] == ruleparameter[ + index]): + ruleidslist.append(ids) + index = index + 1 + + rulesresponse = requests.get( + apis_urls.serverURL + "policies/" + policies_id + "/" + apis_urls.rulesAPI + "/", headers=apis_urls.auth_headers) + + if len(rulesresponse.json()[apis_urls.rulesAPI]) != 0: + for ids in range(len(rulesresponse.json()[apis_urls.rulesAPI]['rules'])): + if (dict(rulesresponse.json()[apis_urls.rulesAPI]['rules'][ids])[ + 'rule'] == ruleidslist): + ruleid = dict(rulesresponse.json()[apis_urls.rulesAPI]['rules'][ids])['id'] + rulesresponse = requests.delete( + apis_urls.serverURL + "policies/" + policies_id + "/" + apis_urls.rulesAPI + "/" + ruleid,headers=apis_urls.auth_headers) + + if rulesresponse.status_code == 200: + GeneralVariables.api_responseflag['value'] = 'True' + else: + GeneralVariables.api_responseflag['value'] = 'False' + +# Step Definition Implementation: +# 1) Get all the existing rules per a given policy, metarule using get request and put them into a table +# 2) Sort the table by policy name +# 3) Loop using both the expected and actual tables and assert the data row by row +@Then('the following rules should be existed in the system') +def step_impl(context): + logger.info("Then the following rule should be existed in the system") + model = getattr(context, "model", None) + apiresult = Table(names=('rule', 'metarule', 'instructions', 'policyname'), + dtype=('S1000', 'S100', 'S100', 'S100')) + + expectedresult = Table(names=('rule', 'metarule', 'instructions', 'policyname'), + dtype=('S1000', 'S100', 'S100', 'S100')) + + for row in context.table: + ruleidslist = [] + apirule = [] + if (len(row['policyname']) > 25): + policies_id = row['policyname'] + else: + policies_id = commonfunctions.get_policyid(row['policyname']) + + ruleparameter = row["rule"].split(",") + metarules_response = requests.get(apis_urls.serverURL + apis_urls.metarulesAPI, headers=apis_urls.auth_headers) + for metaruleids in dict(metarules_response.json()[apis_urls.metarulesAPI]).keys(): + if (metarules_response.json()[apis_urls.metarulesAPI][metaruleids]['name'] == row["metarulename"]): + meta_rule_id = metaruleids + subjectcategorieslist = \ + requests.get(apis_urls.serverURL + apis_urls.metarulesAPI, headers=apis_urls.auth_headers).json()[apis_urls.metarulesAPI][ + metaruleids]['subject_categories'] + objectcategorieslist = \ + requests.get(apis_urls.serverURL + apis_urls.metarulesAPI, headers=apis_urls.auth_headers).json()[apis_urls.metarulesAPI][ + metaruleids]['object_categories'] + actioncategorieslist = \ + requests.get(apis_urls.serverURL + apis_urls.metarulesAPI, headers=apis_urls.auth_headers).json()[apis_urls.metarulesAPI][ + metaruleids]['action_categories'] + + index = 0 + for categoryid in subjectcategorieslist: + data_response = requests.get( + apis_urls.serverURL + "policies/" + policies_id + "/" + apis_urls.datasubjectAPI + "/" + categoryid, headers=apis_urls.auth_headers) + if len(data_response.json()[apis_urls.datasubjectAPI]) != 0: + for ids in data_response.json()[apis_urls.datasubjectAPI][0]['data']: + if (data_response.json()[apis_urls.datasubjectAPI][0]['data'][ids]['name'] == ruleparameter[ + index]): + ruleidslist.append(ids) + index = index + 1 + + for categoryid in objectcategorieslist: + data_response = requests.get( + apis_urls.serverURL + "policies/" + policies_id + "/" + apis_urls.dataobjectAPI + "/" + categoryid, headers=apis_urls.auth_headers) + if len(data_response.json()[apis_urls.dataobjectAPI]) != 0: + for ids in data_response.json()[apis_urls.dataobjectAPI][0]['data']: + if (data_response.json()[apis_urls.dataobjectAPI][0]['data'][ids]['name'] == ruleparameter[ + index]): + ruleidslist.append(ids) + index = index + 1 + + for categoryid in actioncategorieslist: + data_response = requests.get( + apis_urls.serverURL + "policies/" + policies_id + "/" + apis_urls.dataactionAPI + "/" + categoryid, headers=apis_urls.auth_headers) + if len(data_response.json()[apis_urls.dataactionAPI]) != 0: + for ids in data_response.json()[apis_urls.dataactionAPI][0]['data']: + if (data_response.json()[apis_urls.dataactionAPI][0]['data'][ids]['name'] == ruleparameter[ + index]): + ruleidslist.append(ids) + index = index + 1 + expectedresult.add_row(vals=(','.join(ruleidslist), meta_rule_id, row['instructions'], policies_id)) + + if (row['policyname'] != ""): + apipolicyid = commonfunctions.get_policyid( + row['policyname']) + response = requests.get( + apis_urls.serverURL + "policies/" + commonfunctions.get_policyid( + row['policyname']) + "/" + apis_urls.rulesAPI + "/", headers=apis_urls.auth_headers) + + if len(response.json()[apis_urls.rulesAPI]) != 0: + for ids in range(len(response.json()[apis_urls.rulesAPI]['rules'])): + if (dict(response.json()[apis_urls.rulesAPI]['rules'][ids])[ + 'meta_rule_id'] == commonfunctions.get_metaruleid(row['metarulename'])): + apirule = dict(response.json()[apis_urls.rulesAPI]['rules'][ids])['rule'] + #logger.info(dict(dict(response.json()[apis_urls.rulesAPI]['rules'][ids])['instructions'][0])['decision']) + apiinstructions = dict(dict(response.json()[apis_urls.rulesAPI]['rules'][ids])['instructions'][0])['decision'] + apimetaruleid = dict(response.json()[apis_urls.rulesAPI]['rules'][ids])['meta_rule_id'] + apiresult.add_row(vals=(','.join(apirule), apimetaruleid, apiinstructions, apipolicyid)) + + else: + apiresult.add_row(vals=("", "", "", "")) + + else: + apiresult.add_row(vals=("", "", "", "")) + + apiresult.sort('policyname') + expectedresult.sort('policyname') + for row1, row2 in zip(expectedresult, apiresult): + logger.info("asserting the expected rule: '" + str( + row1["rule"]) + "' is the same as the actual existing '" + str( + row2["rule"]) + "'") + assert str(row1["rule"]) == str(row2["rule"]), "rule is not correct!" + logger.info("assertion passed!") + + logger.info("asserting the expected instructions: '" + str( + row1["instructions"]) + "' is the same as the actual existing '" + str( + row2["instructions"]) + "'") + assert str(row1["instructions"]) == str(row2["instructions"]), "instructions is not correct!" + logger.info("assertion passed!") + + logger.info("asserting the expected metarule: '" + str( + row1["metarule"]) + "' is the same as the actual existing '" + str( + row2["metarule"]) + "'") + assert str(row1["metarule"]) == str(row2["metarule"]), "metarule is not correct!" + logger.info("assertion passed!") diff --git a/moon_manager/tests/func_tests/run.sh b/moon_manager/tests/func_tests/run.sh new file mode 100755 index 00000000..f67ba8c6 --- /dev/null +++ b/moon_manager/tests/func_tests/run.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +# pip install behave astropy + +mkdir -p logs + +echo -e "\033[31massignments.feature\033[m" +behave --junit features/assignments.feature | grep -vE "^ " +echo -e "\033[31mdata.feature\033[m" +behave --junit features/data.feature | grep -vE "^ " +echo -e "\033[31mmeta_data.feature\033[m" +behave --junit features/meta_data.feature | grep -vE "^ " +echo -e "\033[31mmeta_rules.feature\033[m" +behave --junit features/meta_rules.feature | grep -vE "^ " +echo -e "\033[31mmodel.feature\033[m" +behave --junit features/model.feature | grep -vE "^ " +echo -e "\033[31mpartner.feature\033[m" +behave --junit features/partner.feature | grep -vE "^ " +echo -e "\033[31mpdp.feature\033[m" +behave --junit features/pdp.feature | grep -vE "^ " +echo -e "\033[31mperimeter.feature\033[m" +behave --junit features/perimeter.feature | grep -vE "^ " +echo -e "\033[31mpolicy.feature\033[m" +behave --junit features/policy.feature | grep -vE "^ " +echo -e "\033[31mrules.feature\033[m" +behave --junit features/rules.feature | grep -vE "^ " diff --git a/moon_manager/tests/functional_pod/conftest.py b/moon_manager/tests/functional_pod/conftest.py deleted file mode 100644 index b5811755..00000000 --- a/moon_manager/tests/functional_pod/conftest.py +++ /dev/null @@ -1,12 +0,0 @@ -import pytest - -print("ANALYSING CONFTEST") - - -@pytest.fixture -def context(): - print("CREATING CONTEXT") - yield { - "hostname": "manager", - "port": 8082, - } diff --git a/moon_manager/tests/functional_pod/json/mls.json b/moon_manager/tests/functional_pod/json/mls.json deleted file mode 100644 index 01ef6deb..00000000 --- a/moon_manager/tests/functional_pod/json/mls.json +++ /dev/null @@ -1,89 +0,0 @@ -{ - "pdps": [{"name" : "pdp_mls", "keystone_project_id" : "", "description": "", "policies": [{"name": "MLS policy example"}]}], - - "policies":[{ "name": "MLS policy example", "genre": "authz", "description": "", "model": {"name": "MLS"} , "mandatory" :false , "override":true}], - - "models":[{"name":"MLS", "description":"","meta_rules": [{"name" : "mls"}], "override":true}], - - - - - - "subjects": [{ "name":"adminuser", "description": "", "extra": {}, "policies": [{ "name": "MLS policy example"}]} , - { "name": "user1", "description": "", "extra": {}, "policies": [{ "name": "MLS policy example"}] }, - { "name": "user2", "description": "", "extra": {}, "policies": [{ "name": "MLS policy example"}] }], - - "subject_categories": [{ "name":"subject-security-level", "description": "" }], - - "subject_data": [{ "name":"low", "description": "", "policies": [{"name" :"MLS policy example"}], "category": {"name": "subject-security-level"}}, - { "name":"medium", "description": "", "policies": [{"name" :"MLS policy example"}], "category": {"name": "subject-security-level"}}, - { "name":"high", "description": "", "policies": [{"name" :"MLS policy example"}], "category": {"name": "subject-security-level"}}], - - "subject_assignments":[{ "subject" : {"name": "adminuser"}, "category" : {"name": "subject-security-level"}, "assignments": [{"name" : "high"}]}, - { "subject" : {"name": "user1"}, "category" : {"name": "subject-security-level"}, "assignments": [{"name" : "medium"}] }], - - - - - - - "objects": [{ "name":"vm0", "description": "", "extra": {}, "policies": [{"name": "MLS policy example"}]} , - {"name": "vm1", "description": "", "extra": {}, "policies": [{"name": "MLS policy example"}]} ], - - "object_categories": [{"name":"object-security-level", "description": ""}], - - "object_data": [{ "name":"low", "description": "", "policies": [{"name" :"MLS policy example"}], "category": {"name": "object-security-level"}}, - { "name":"medium", "description": "", "policies": [{"name" :"MLS policy example"}], "category": {"name": "object-security-level"}}, - { "name":"high", "description": "", "policies": [{"name" :"MLS policy example"}], "category": {"name": "object-security-level"}}], - - "object_assignments":[{ "object" : {"name": "vm0"}, "category" : {"name": "object-security-level"}, "assignments": [{"name" : "medium"}]}, - { "object" : {"name": "vm1"}, "category" : {"name": "object-security-level"}, "assignments": [{"name" : "low"}]}], - - - - - - - "actions": [{ "name": "start", "description": "", "extra": {}, "policies": [{"name": "MLS policy example"}]} , - { "name": "stop", "description": "", "extra": {}, "policies": [{"name": "MLS policy example"}]}], - - "action_categories": [{"name":"action-type", "description": ""}], - - "action_data": [{"name":"vm-action", "description": "", "policies": [{"name": "MLS policy example"}], "category": {"name": "action-type"}}, - {"name":"storage-action", "description": "", "policies": [{"name" :"MLS policy example"}], "category": {"name": "action-type"}}], - - "action_assignments":[{ "action" : {"name": "start"}, "category" : {"name": "action-type"}, "assignments": [{"name" : "vm-action"}]}, - { "action" : {"name": "stop"}, "category" : {"name": "action-type"}, "assignments": [{"name" : "vm-action"}]}], - - - - - - - "meta_rules":[{"name":"mls", "description": "", - "subject_categories": [{"name": "subject-security-level"}], - "object_categories": [{"name": "object-security-level"}], - "action_categories": [{"name": "action-type"}] - }], - - "rules": [{ - "meta_rule": {"name" : "mls"}, - "rule": {"subject_data" : [{"name":"high"}], "object_data": [{"name": "medium"}], "action_data": [{"name": "vm-action"}]}, - "policy": {"name" :"MLS policy example"}, - "instructions" : {"decision" : "grant"} - }, { - "meta_rule": {"name" : "mls"}, - "rule": {"subject_data" : [{"name":"high"}], "object_data": [{"name": "low"}], "action_data": [{"name": "vm-action"}]}, - "policy": {"name" :"MLS policy example"}, - "instructions" : {"decision" : "grant"} - }, { - "meta_rule": {"name" : "mls"}, - "rule": {"subject_data" : [{"name":"medium"}], "object_data": [{"name": "low"}], "action_data": [{"name": "vm-action"}]}, - "policy": {"name" :"MLS policy example"}, - "instructions" : {"decision" : "grant"} - }] - - - - -} \ No newline at end of file diff --git a/moon_manager/tests/functional_pod/json/rbac.json b/moon_manager/tests/functional_pod/json/rbac.json deleted file mode 100644 index a75f291b..00000000 --- a/moon_manager/tests/functional_pod/json/rbac.json +++ /dev/null @@ -1,85 +0,0 @@ -{ - "pdps": [{"name" : "pdp_rbac", "keystone_project_id" : "", "description": "", "policies": [{"name": "RBAC policy example"}]}], - - "policies":[{ "name": "RBAC policy example", "genre": "authz", "description": "", "model": {"name": "RBAC"} , "mandatory" :true , "override":true}], - - "models":[{"name":"RBAC", "description":"","meta_rules": [{"name" : "rbac"}], "override":true}], - - - - - - "subjects": [{ "name":"adminuser", "description": "", "extra": {}, "policies": [{ "name": "RBAC policy example"}]} , - { "name": "user1", "description": "", "extra": {}, "policies": [{ "name": "RBAC policy example"}] }, - { "name": "public", "description": "", "extra": {}, "policies": [] }], - - "subject_categories": [{ "name":"role", "description": "" }], - - "subject_data": [{ "name":"admin", "description": "", "policies": [{"name" :"RBAC policy example"}], "category": {"name": "role"}}, - { "name":"employee", "description": "", "policies": [{"name" :"RBAC policy example"}], "category": {"name": "role"}}, - { "name":"*", "description": "", "policies": [{"name" :"RBAC policy example"}], "category": {"name": "role"}}], - - "subject_assignments":[{ "subject" : {"name": "adminuser"}, "category" : {"name": "role"}, "assignments": [{"name" : "admin"}, {"name" : "employee"}, {"name" : "*"}]}, - { "subject" : {"name": "user1"}, "category" : {"name": "role"}, "assignments": [{"name" : "employee"}, {"name" : "*"}] }], - - - - - - - "objects": [{ "name":"vm0", "description": "", "extra": {}, "policies": [{"name": "RBAC policy example"}]} , - {"name": "vm1", "description": "", "extra": {}, "policies": [{"name": "RBAC policy example"}]} ], - - "object_categories": [{"name":"id", "description": ""}], - - "object_data": [{ "name":"vm0", "description": "", "policies": [{"name" :"RBAC policy example"}], "category": {"name": "id"}}, - { "name":"vm1", "description": "", "policies": [{"name" :"RBAC policy example"}], "category": {"name": "id"}}, - { "name":"*", "description": "", "policies": [{"name" :"RBAC policy example"}], "category": {"name": "id"}}], - - "object_assignments":[{ "object" : {"name": "vm0"}, "category" : {"name": "id"}, "assignments": [{"name" : "vm0"}, {"name" : "*"}]}, - { "object" : {"name": "vm1"}, "category" : {"name": "id"}, "assignments": [{"name" : "vm1"}, {"name" : "*"}]}], - - - - - - - "actions": [{ "name": "start", "description": "", "extra": {}, "policies": [{"name": "RBAC policy example"}]} , - { "name": "stop", "description": "", "extra": {}, "policies": [{"name": "RBAC policy example"}]}], - - "action_categories": [{"name":"action-type", "description": ""}], - - "action_data": [{"name":"vm-action", "description": "", "policies": [{"name": "RBAC policy example"}], "category": {"name": "action-type"}}, - {"name":"*", "description": "", "policies": [{"name" :"RBAC policy example"}], "category": {"name": "action-type"}}], - - "action_assignments":[{ "action" : {"name": "start"}, "category" : {"name": "action-type"}, "assignments": [{"name" : "vm-action"}, {"name" : "*"}]}, - { "action" : {"name": "stop"}, "category" : {"name": "action-type"}, "assignments": [{"name" : "vm-action"}, {"name" : "*"}]}], - - - - - - - "meta_rules":[{"name":"rbac", "description": "", - "subject_categories": [{"name": "role"}], - "object_categories": [{"name": "id"}], - "action_categories": [{"name": "action-type"}] - }], - - "rules": [{ - "meta_rule": {"name" : "rbac"}, - "rule": {"subject_data" : [{"name":"admin"}], "object_data": [{"name": "vm0"}], "action_data": [{"name": "vm-action"}]}, - "policy": {"name" :"RBAC policy example"}, - "instructions" : {"decision" : "grant"}, - "enabled": true - }, { - "meta_rule": {"name" : "rbac"}, - "rule": {"subject_data" : [{"name":"employee"}], "object_data": [{"name": "vm1"}], "action_data": [{"name": "vm-action"}]}, - "policy": {"name" :"RBAC policy example"}, - "instructions" : {"decision" : "grant"} - }] - - - - -} \ No newline at end of file diff --git a/moon_manager/tests/functional_pod/run_functional_tests.sh b/moon_manager/tests/functional_pod/run_functional_tests.sh deleted file mode 100644 index 960e9480..00000000 --- a/moon_manager/tests/functional_pod/run_functional_tests.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash - -if [ -d /data/dist ]; -then - pip install /data/dist/*.tar.gz --upgrade - pip install /data/dist/*.whl --upgrade -fi - - -cd /data/tests/functional_pod -pytest . diff --git a/moon_manager/tests/functional_pod/test_manager.py b/moon_manager/tests/functional_pod/test_manager.py deleted file mode 100644 index 454d861b..00000000 --- a/moon_manager/tests/functional_pod/test_manager.py +++ /dev/null @@ -1,116 +0,0 @@ -import json -import requests - -def test_import_rbac(context): - files = {'file': open('/data/tests/functional_pod/json/rbac.json', 'r')} - req = requests.post("http://{}:{}/import".format( - context.get("hostname"), - context.get("port")) - , files=files) - print(req) - result = req.json() - print(result) - req.raise_for_status() - -def test_import_mls(context): - files = {'file': open('/data/tests/functional_pod/json/mls.json', 'r')} - req = requests.post("http://{}:{}/import".format( - context.get("hostname"), - context.get("port")) - , files=files) - req.raise_for_status() - - -def test_export_rbac(context): - test_import_rbac(context) - req = requests.get("http://{}:{}/export".format( - context.get("hostname"), - context.get("port")), - data={"filename":"/data/tests/functional_pod/json/rbac_export.json"} - ) - req.raise_for_status() - - -def test_export_mls(context): - test_import_mls(context) - req = requests.get("http://{}:{}/export".format( - context.get("hostname"), - context.get("port")), - data={"filename":"/data/tests/functional_pod/json/mls_export.json"} - ) - req.raise_for_status() - - -def get_json(data): - return json.loads(data.decode("utf-8")) - - -def get_pdp(context): - req = requests.get("http://{}:{}/pdp".format( - context.get("hostname"), - context.get("port")), - timeout=3) - pdp = req.json() - return req, pdp - - -def add_pdp(context, data): - req = requests.post("http://{}:{}/pdp".format( - context.get("hostname"), - context.get("port")), - data=json.dumps(data), - headers={'Content-Type': 'application/json'}, - timeout=3) - pdp = req.json() - return req, pdp - - -def delete_pdp(context, key): - req = requests.delete("http://{}:{}/pdp/{}".format( - context.get("hostname"), - context.get("port"), key), - timeout=3) - return req - - -def delete_pdp_without_id(context): - req = requests.delete("http://{}:{}/pdp/{}".format( - context.get("hostname"), - context.get("port"), ""), - timeout=3) - return req - - -def test_get_pdp(context): - req, pdp = get_pdp(context) - assert req.status_code == 200 - assert isinstance(pdp, dict) - assert "pdps" in pdp - - -def test_add_pdp(context): - data = { - "name": "testuser", - "security_pipeline": ["policy_id_1", "policy_id_2"], - "keystone_project_id": "keystone_project_id", - "description": "description of testuser" - } - req, pdp = add_pdp(context, data) - assert req.status_code == 200 - assert isinstance(pdp, dict) - value = list(pdp["pdps"].values())[0] - assert "pdps" in pdp - assert value['name'] == "testuser" - assert value["description"] == "description of {}".format("testuser") - assert value["keystone_project_id"] == "keystone_project_id" - - -def test_delete_pdp(context): - request, pdp = get_pdp(context) - success_req = None - for key, value in pdp['pdps'].items(): - if value['name'] == "testuser": - success_req = delete_pdp(context, key) - break - assert success_req - assert success_req.status_code == 200 diff --git a/moon_manager/tests/functional_pod/test_models.py b/moon_manager/tests/functional_pod/test_models.py deleted file mode 100644 index 8b4ceef5..00000000 --- a/moon_manager/tests/functional_pod/test_models.py +++ /dev/null @@ -1,79 +0,0 @@ -import json -import requests - - -def get_models(context): - req = requests.get("http://{}:{}/models".format( - context.get("hostname"), - context.get("port")), - timeout=3) - models = req.json() - return req, models - - -def add_models(context, name): - data = { - "name": name, - "description": "description of {}".format(name), - "meta_rules": ["meta_rule_id1", "meta_rule_id2"] - } - req = requests.post("http://{}:{}/models".format( - context.get("hostname"), - context.get("port")), - data=json.dumps(data), - headers={'Content-Type': 'application/json'}, - timeout=3) - models = req.json() - return req, models - - -def delete_models(context, name): - _, models = get_models(context) - request = None - for key, value in models['models'].items(): - if value['name'] == name: - request = requests.delete("http://{}:{}/models/{}".format( - context.get("hostname"), - context.get("port"), - key), - timeout=3) - break - return request - - -def delete_models_without_id(context): - req = requests.delete("http://{}:{}/models/{}".format( - context.get("hostname"), - context.get("port"), - ""), - timeout=3) - return req - - -def test_get_models(context): - req, models = get_models(context) - assert req.status_code == 200 - assert isinstance(models, dict) - assert "models" in models - - -def test_add_models(context): - req, models = add_models(context, "testuser") - assert req.status_code == 200 - assert isinstance(models, dict) - value = list(models["models"].values())[0] - assert "models" in models - assert value['name'] == "testuser" - assert value["description"] == "description of {}".format("testuser") - assert value["meta_rules"][0] == "meta_rule_id1" - - -def test_delete_models(context): - req = delete_models(context, "testuser") - assert req.status_code == 200 - - -def test_delete_models_without_id(context): - req = delete_models_without_id(context) - assert req.status_code == 500 - diff --git a/moon_manager/tests/performance_tests/authz_pipeline.py b/moon_manager/tests/performance_tests/authz_pipeline.py new file mode 100644 index 00000000..7d2b48ce --- /dev/null +++ b/moon_manager/tests/performance_tests/authz_pipeline.py @@ -0,0 +1,115 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +from locust import TaskSet, task +import logging +import json + +LOGGER = logging.getLogger("locust") + + +class AuthzPipelineRequests(TaskSet): + token = "" + moon_errors = 0 + moon_requests = 0 + stats_filename = "/tmp/perf_stats.log" + + def on_start(self): + """ on_start is called when a Locust start before any task is scheduled """ + self.moon_errors = [] + + def __del__(self): + """ on_stop is called when the TaskSet is stopping """ + stats = {} + try: + stats = json.loads(open(self.stats_filename).read()) + except Exception: + pass + _num = stats.get("errors", 0) + _num += len(self.moon_errors) + _total = stats.get("total", 0) + _total += self.moon_requests + _list = stats.get("list", []) + _list.extend(self.moon_errors) + _percent = _num * 100 / _total + json.dump({"errors": _num, "total": _total, + "percentage": "{0:.2f}".format(_percent), + "list": _list}, + open(self.stats_filename, "w"), indent=4) + + def get(self, url, status_code=200): + with self.client.get(url, catch_response=True) as response: + self.moon_requests += 1 + if response.status_code != status_code: + self.moon_errors.append((url, f"{response.status_code}/{status_code}")) + response.success() + + @task(10) + def authz_ok1(self): + url = "/authz/{}/{}/{}".format( + "admin", "vm1", "use_image" + ) + self.get(url) + + @task(10) + def authz_ok2(self): + url = "/authz/{}/{}/{}".format( + "admin", "vm1", "get_images" + ) + self.get(url) + + @task(10) + def authz_ok3(self): + url = "/authz/{}/{}/{}".format( + "admin", "vm1", "set_image" + ) + self.get(url) + + @task(10) + def authz_ok4(self): + url = "/authz/{}/{}/{}".format( + "demo", "vm1", "set_image" + ) + self.get(url) + + @task(10) + def authz_ok5(self): + url = "/authz/{}/{}/{}".format( + "demo", "vm1", "get_images" + ) + self.get(url) + + @task(10) + def authz_rule_ko(self): + url = "/authz/{}/{}/{}".format("demo", "vm1", "use_image") + self.get(url, 403) + + @task(10) + def authz_subject_ko(self): + url = "/authz/{}/{}/{}".format("admins", "vm1", "use_image") + self.get(url, 403) + + @task(10) + def authz_object_ko(self): + url = "/authz/{}/{}/{}".format("admin", "vm4", "use_image") + self.get(url, 403) + + @task(10) + def authz_action_ko(self): + url = "/authz/{}/{}/{}".format("admin", "vm1", "use_images") + self.get(url, 403) + + @task(1) + def status(self): + self.client.get("/status/") + + diff --git a/moon_manager/tests/performance_tests/locustfile.py b/moon_manager/tests/performance_tests/locustfile.py new file mode 100644 index 00000000..cf077720 --- /dev/null +++ b/moon_manager/tests/performance_tests/locustfile.py @@ -0,0 +1,26 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +from locust import HttpLocust, TaskSet +import authz_pipeline + + +class MoonRequests(TaskSet): + tasks = { + authz_pipeline.AuthzPipelineRequests: 10, + } + + +class MoonUser(HttpLocust): + task_set = MoonRequests + min_wait = 10 + max_wait = 100 diff --git a/moon_manager/tests/performance_tests/policy_rbac.json b/moon_manager/tests/performance_tests/policy_rbac.json new file mode 100644 index 00000000..2f7c704e --- /dev/null +++ b/moon_manager/tests/performance_tests/policy_rbac.json @@ -0,0 +1,411 @@ +{ + "policies": [ + { + "name": "Policy for Locust", + "genre": "authz", + "description": "Policy for Locust", + "model": { + "name": "RBAC" + }, + "mandatory": true, + "override": true + } + ], + "models": [ + { + "name": "RBAC", + "description": "", + "meta_rules": [ + { + "name": "rbac" + } + ], + "override": true + } + ], + "subjects": [ + { + "name": "admin", + "description": "", + "extra": {}, + "policies": [ + { + "name": "Policy for Locust" + } + ] + }, + { + "name": "demo", + "description": "", + "extra": {}, + "policies": [ + { + "name": "Policy for Locust" + } + ] + } + ], + "subject_categories": [ + { + "name": "role", + "description": "role of a user" + } + ], + "subject_data": [ + { + "name": "admin", + "description": "", + "policies": [], + "category": { + "name": "role" + } + }, + { + "name": "user", + "description": "", + "policies": [], + "category": { + "name": "role" + } + } + ], + "subject_assignments": [ + { + "subject": {"name": "admin"}, + "category": {"name": "role"}, + "assignments": [{"name": "admin"}] + }, + { + "subject": {"name": "admin"}, + "category": {"name": "role"}, + "assignments": [{"name": "user"}] + }, + { + "subject": {"name": "demo"}, + "category": {"name": "role"}, + "assignments": [{"name": "user"}] + } + ], + "objects": [ + { + "name": "vm1", + "description": "", + "extra": {}, + "policies": [ + { + "name": "Policy for Locust" + } + ] + }, + { + "name": "vm2", + "description": "", + "extra": {}, + "policies": [ + { + "name": "Policy for Locust" + } + ] + }, + { + "name": "vm3", + "description": "", + "extra": {}, + "policies": [ + { + "name": "Policy for Locust" + } + ] + } + ], + "object_categories": [ + { + "name": "id", + "description": "identification of the object" + } + ], + "object_data": [ + { + "name": "vm1", + "description": "", + "policies": [], + "category": { + "name": "id" + } + }, + { + "name": "vm2", + "description": "", + "policies": [], + "category": { + "name": "id" + } + }, + { + "name": "vm3", + "description": "", + "policies": [], + "category": { + "name": "id" + } + } + ], + "object_assignments": [ + { + "object": {"name": "vm1"}, + "category": {"name": "id"}, + "assignments": [{"name": "vm1"}] + }, + { + "object": {"name": "vm2"}, + "category": {"name": "id"}, + "assignments": [{"name": "vm2"}] + }, + { + "object": {"name": "vm3"}, + "category": {"name": "id"}, + "assignments": [{"name": "vm3"}] + } + ], + "actions": [ + { + "name": "use_image", + "description": "use_image action for glance", + "extra": { + "component": "glance" + }, + "policies": [ + { + "name": "Policy for Locust" + } + ] + }, + { + "name": "get_images", + "description": "get_images action for glance", + "extra": { + "component": "glance" + }, + "policies": [ + { + "name": "Policy for Locust" + } + ] + }, + { + "name": "update_image", + "description": "update_image action for glance", + "extra": { + "component": "glance" + }, + "policies": [ + { + "name": "Policy for Locust" + } + ] + }, + { + "name": "set_image", + "description": "set_image action for glance", + "extra": { + "component": "glance" + }, + "policies": [ + { + "name": "Policy for Locust" + } + ] + } + ], + "action_categories": [ + { + "name": "type", + "description": "" + } + ], + "action_data": [ + { + "name": "read", + "description": "read action", + "policies": [], + "category": { + "name": "type" + } + }, + { + "name": "write", + "description": "write action", + "policies": [], + "category": { + "name": "type" + } + }, + { + "name": "execute", + "description": "execute action", + "policies": [], + "category": { + "name": "type" + } + } + ], + "action_assignments": [ + { + "action": {"name": "use_image"}, + "category": {"name": "type"}, + "assignments": [{"name": "read"}, {"name": "execute"}] + }, + { + "action": {"name": "update_image"}, + "category": {"name": "type"}, + "assignments": [{"name": "read"}, {"name": "write"}] + }, + { + "action": {"name": "set_image"}, + "category": {"name": "type"}, + "assignments": [{"name": "write"}] + }, + { + "action": {"name": "get_images"}, + "category": {"name": "type"}, + "assignments": [{"name": "read"}] + } + ], + "meta_rules": [ + { + "name": "rbac", + "description": "", + "subject_categories": [{"name": "role"}], + "object_categories": [{"name": "id"}], + "action_categories": [{"name": "type"}] + } + ], + "rules": [ + { + "meta_rule": {"name": "rbac"}, + "rule": { + "subject_data": [{"name": "admin"}], + "object_data": [{"name": "vm1"}], + "action_data": [{"name": "read"}] + }, + "policy": {"name": "Policy for Locust"}, + "instructions": [{"decision": "grant"}], + "enabled": true + }, + { + "meta_rule": {"name": "rbac"}, + "rule": { + "subject_data": [{"name": "admin"}], + "object_data": [{"name": "vm1"}], + "action_data": [{"name": "write"}] + }, + "policy": {"name": "Policy for Locust"}, + "instructions": [{"decision": "grant"}], + "enabled": true + }, + { + "meta_rule": {"name": "rbac"}, + "rule": { + "subject_data": [{"name": "admin"}], + "object_data": [{"name": "vm1"}], + "action_data": [{"name": "execute"}] + }, + "policy": {"name": "Policy for Locust"}, + "instructions": [{"decision": "grant"}], + "enabled": true + }, + { + "meta_rule": {"name": "rbac"}, + "rule": { + "subject_data": [{"name": "admin"}], + "object_data": [{"name": "vm2"}], + "action_data": [{"name": "read"}] + }, + "policy": {"name": "Policy for Locust"}, + "instructions": [{"decision": "grant"}], + "enabled": true + }, + { + "meta_rule": {"name": "rbac"}, + "rule": { + "subject_data": [{"name": "admin"}], + "object_data": [{"name": "vm2"}], + "action_data": [{"name": "write"}] + }, + "policy": {"name": "Policy for Locust"}, + "instructions": [{"decision": "grant"}], + "enabled": true + }, + { + "meta_rule": {"name": "rbac"}, + "rule": { + "subject_data": [{"name": "admin"}], + "object_data": [{"name": "vm3"}], + "action_data": [{"name": "read"}] + }, + "policy": {"name": "Policy for Locust"}, + "instructions": [{"decision": "grant"}], + "enabled": true + }, + { + "meta_rule": {"name": "rbac"}, + "rule": { + "subject_data": [{"name": "user"}], + "object_data": [{"name": "vm1"}], + "action_data": [{"name": "read"}] + }, + "policy": {"name": "Policy for Locust"}, + "instructions": [{"decision": "grant"}], + "enabled": true + }, + { + "meta_rule": {"name": "rbac"}, + "rule": { + "subject_data": [{"name": "user"}], + "object_data": [{"name": "vm1"}], + "action_data": [{"name": "write"}] + }, + "policy": {"name": "Policy for Locust"}, + "instructions": [{"decision": "grant"}], + "enabled": true + }, + { + "meta_rule": {"name": "rbac"}, + "rule": { + "subject_data": [{"name": "user"}], + "object_data": [{"name": "vm2"}], + "action_data": [{"name": "read"}] + }, + "policy": {"name": "Policy for Locust"}, + "instructions": [{"decision": "grant"}], + "enabled": true + } + ], + "checks": { + "granted": [ + ["admin", "vm1", "get_images"], + ["admin", "vm1", "set_image"], + ["admin", "vm1", "use_image"], + ["admin", "vm2", "get_images"], + ["admin", "vm2", "set_image"], + ["admin", "vm3", "get_images"], + ["user", "vm1", "get_images"], + ["user", "vm1", "set_image"], + ["user", "vm2", "get_images"], + ["user", "vm1", "get_images"] + ], + "denied": [ + ["admin", "vm2", "update_image"], + ["admin", "vm3", "set_image"], + ["admin", "vm3", "update_image"], + ["user", "vm1", "update_image"], + ["user", "vm2", "set_image"], + ["user", "vm2", "update_image"], + ["user", "vm1", "use_image"], + ["user", "vm2", "use_image"], + ["user", "vm3", "get_images"], + ["user", "vm3", "set_image"], + ["user", "vm3", "update_image"] + ] + } +} \ No newline at end of file diff --git a/moon_manager/tests/performance_tests_policies/actions.py b/moon_manager/tests/performance_tests_policies/actions.py new file mode 100644 index 00000000..0f31d645 --- /dev/null +++ b/moon_manager/tests/performance_tests_policies/actions.py @@ -0,0 +1,54 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +import json +from locust import TaskSet, task +from uuid import uuid4 +import utils + + +class ActionRequests(TaskSet): + token = "" + + def on_start(self): + """ on_start is called when a Locust start before any task is scheduled """ + utils.login(self) + + def on_stop(self): + """ on_stop is called when the TaskSet is stopping """ + utils.logout(self) + + @task(10) + def actions(self): + policy_id = utils.create_policy(self.client, self.token) + self.client.get("/actions", headers={"X-Api-Key": self.token}) + perimeter_name = "test_action_" + str(uuid4()) + req = self.client.post("/policies/{}/actions".format(policy_id), + headers={"X-Api-Key": self.token}, + data={ + "name": perimeter_name, + "description": "locust test", + }) + content = json.loads(req.content.decode("utf-8")) + subject_id = None + for subject_id, subject_value in content.get("actions", {}).items(): + if subject_value.get("name") == perimeter_name: + break + self.client.delete("/policies/{}/actions/{}".format(policy_id, subject_id), + headers={"X-Api-Key": self.token}) + utils.delete_policy(self.client, self.token, policy_id) + + @task(1) + def status(self): + self.client.get("/status", headers={"X-Api-Key": self.token}) + + diff --git a/moon_manager/tests/performance_tests_policies/locustfile.py b/moon_manager/tests/performance_tests_policies/locustfile.py new file mode 100644 index 00000000..368801b0 --- /dev/null +++ b/moon_manager/tests/performance_tests_policies/locustfile.py @@ -0,0 +1,32 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +from locust import HttpLocust, TaskSet +import subjects +import objects +import actions +import meta_rules + + +class MoonRequests(TaskSet): + tasks = { + subjects.SubjectRequests: 10, + objects.ObjectRequests: 10, + actions.ActionRequests: 10, + meta_rules.MetaRulesRequests: 5 + } + + +class MoonUser(HttpLocust): + task_set = MoonRequests + min_wait = 100 + max_wait = 1000 diff --git a/moon_manager/tests/performance_tests_policies/meta_rules.py b/moon_manager/tests/performance_tests_policies/meta_rules.py new file mode 100644 index 00000000..e9d85944 --- /dev/null +++ b/moon_manager/tests/performance_tests_policies/meta_rules.py @@ -0,0 +1,80 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +from locust import TaskSet, task +import json +from uuid import uuid4 +import utils + + +class MetaRulesRequests(TaskSet): + token = "" + + def on_start(self): + """ on_start is called when a Locust start before any task is scheduled """ + utils.login(self) + + def on_stop(self): + """ on_stop is called when the TaskSet is stopping """ + utils.logout(self) + + def create_category(self, otype="subject"): + self.client.get("/{}_categories".format(otype), headers={"X-Api-Key": self.token}) + category_name = "test_category_" + str(uuid4()) + req = self.client.post("/{}_categories".format(otype), + headers={"X-Api-Key": self.token}, + data={ + "name": category_name, + "description": "locust {} category tests".format(otype), + }) + content = json.loads(req.content.decode("utf-8")) + for category_id, category_value in content.get("{}_categories".format(otype), {}).items(): + if category_value.get("name") == category_name: + return category_id + + def delete_category(self, category_id, otype="subject"): + self.client.delete("/{}_categories/{}".format(otype, category_id), + headers={"X-Api-Key": self.token}) + + @task(10) + def meta_rules(self): + self.client.get("/meta_rules", headers={"X-Api-Key": self.token}) + subject_category_id = self.create_category("subject") + object_category_id = self.create_category("object") + action_category_id = self.create_category("action") + meta_rule_name = "meta_rule_" + str(uuid4()) + data = { + "name": meta_rule_name, + "subject_categories": [subject_category_id], + "object_categories": [object_category_id], + "action_categories": [action_category_id] + } + req = self.client.post("/meta_rules", + headers={"X-Api-Key": self.token, + "Content-Type": "application/json"}, + data=json.dumps(data) + ) + content = json.loads(req.content.decode("utf-8")) + for meta_rule_id, meta_rule_value in content.get("meta_rules", {}).items(): + if meta_rule_value.get("name") == meta_rule_name: + self.client.delete("/meta_rules/{}".format(meta_rule_id), + headers={"X-Api-Key": self.token}) + break + self.delete_category(subject_category_id, "subject") + self.delete_category(object_category_id, "object") + self.delete_category(action_category_id, "action") + + @task(1) + def status(self): + self.client.get("/status", headers={"X-Api-Key": self.token}) + + diff --git a/moon_manager/tests/performance_tests_policies/objects.py b/moon_manager/tests/performance_tests_policies/objects.py new file mode 100644 index 00000000..24932d70 --- /dev/null +++ b/moon_manager/tests/performance_tests_policies/objects.py @@ -0,0 +1,54 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +import json +from locust import TaskSet, task +from uuid import uuid4 +import utils + + +class ObjectRequests(TaskSet): + token = "" + + def on_start(self): + """ on_start is called when a Locust start before any task is scheduled """ + utils.login(self) + + def on_stop(self): + """ on_stop is called when the TaskSet is stopping """ + utils.logout(self) + + @task(10) + def objects(self): + policy_id = utils.create_policy(self.client, self.token) + self.client.get("/objects", headers={"X-Api-Key": self.token}) + perimeter_name = "test_object_" + str(uuid4()) + req = self.client.post("/policies/{}/objects".format(policy_id), + headers={"X-Api-Key": self.token}, + data={ + "name": perimeter_name, + "description": "locust test", + }) + content = json.loads(req.content.decode("utf-8")) + subject_id = None + for subject_id, subject_value in content.get("objects", {}).items(): + if subject_value.get("name") == perimeter_name: + break + self.client.delete("/policies/{}/objects/{}".format(policy_id, subject_id), + headers={"X-Api-Key": self.token}) + utils.delete_policy(self.client, self.token, policy_id) + + @task(1) + def status(self): + self.client.get("/status", headers={"X-Api-Key": self.token}) + + diff --git a/moon_manager/tests/performance_tests_policies/subjects.py b/moon_manager/tests/performance_tests_policies/subjects.py new file mode 100644 index 00000000..cacf04c8 --- /dev/null +++ b/moon_manager/tests/performance_tests_policies/subjects.py @@ -0,0 +1,57 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +from locust import TaskSet, task +import json +import logging +from uuid import uuid4 +import utils + +LOGGER = logging.getLogger(__name__) + + +class SubjectRequests(TaskSet): + token = "" + + def on_start(self): + """ on_start is called when a Locust start before any task is scheduled """ + utils.login(self) + + def on_stop(self): + """ on_stop is called when the TaskSet is stopping """ + utils.logout(self) + + @task(10) + def subjects(self): + policy_id = utils.create_policy(self.client, self.token) + self.client.get("/subjects", headers={"X-Api-Key": self.token}) + perimeter_name = "test_subject_" + str(uuid4()) + req = self.client.post("/policies/{}/subjects".format(policy_id), + headers={"X-Api-Key": self.token}, + data={ + "name": perimeter_name, + "description": "locust test", + }) + content = json.loads(req.content.decode("utf-8")) + subject_id = None + for subject_id, subject_value in content.get("subjects", {}).items(): + if subject_value.get("name") == perimeter_name: + break + self.client.delete("/policies/{}/subjects/{}".format(policy_id, subject_id), + headers={"X-Api-Key": self.token}) + utils.delete_policy(self.client, self.token, policy_id) + + @task(1) + def status(self): + self.client.get("/status", headers={"X-Api-Key": self.token}) + + diff --git a/moon_manager/tests/performance_tests_policies/utils.py b/moon_manager/tests/performance_tests_policies/utils.py new file mode 100644 index 00000000..4a721b4c --- /dev/null +++ b/moon_manager/tests/performance_tests_policies/utils.py @@ -0,0 +1,45 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +import json +from uuid import uuid4 + + +def login(taskset): + req = taskset.client.get("/auth", auth=("admin", "admin")) + taskset.token = req.content.decode("utf-8").strip('"') + + +def logout(taskset): + pass + + +def log(msg): + open("/tmp/tests.log", 'a').write(str(msg) + "\n") + + +def create_policy(client, token): + policy_name = "test_policy_" + str(uuid4()) + req = client.post("/policies", headers={"X-Api-Key": token}, data={ + "name": policy_name, + "description": "locust test policy", + }) + content = json.loads(req.content.decode("utf-8")) + for policy_key, policy_value in content.get("policies", {}).items(): + if policy_value.get("name") == policy_name: + return policy_key + + +def delete_policy(client, token, policy_id): + client.delete("/policies/{}".format(policy_id), headers={"X-Api-Key": token}) + + 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..1856aa2c --- /dev/null +++ b/moon_manager/tests/unit_python/api/__init__.py @@ -0,0 +1,12 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + diff --git a/moon_manager/tests/unit_python/api/import_export_utilities.py b/moon_manager/tests/unit_python/api/import_export_utilities.py deleted file mode 100644 index 2ee2627d..00000000 --- a/moon_manager/tests/unit_python/api/import_export_utilities.py +++ /dev/null @@ -1,202 +0,0 @@ -# Copyright 2018 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 api.test_unit_models as test_models -import api.test_policies as test_policies -import api.test_perimeter as test_perimeter -import api.test_meta_data as test_categories -import api.test_data as test_data -import api.test_meta_rules as test_meta_rules -import api.test_assignement as test_assignments -import api.test_rules as test_rules -import logging - -logger = logging.getLogger("moon.manager.test.api." + __name__) - - -def clean_models(client): - req, models = test_models.get_models(client) - for key in models["models"]: - client.delete("/models/{}".format(key)) - - -def clean_policies(client): - req, policies = test_policies.get_policies(client) - for key in policies["policies"]: - req = client.delete("/policies/{}".format(key)) - assert req.status_code == 200 - - -def clean_subjects(client): - subjects = test_perimeter.get_subjects(client) - logger.info("subjects {}".format(subjects)) - for key in subjects[1]["subjects"]: - subject = subjects[1]["subjects"][key] - policy_keys = subject["policy_list"] - logger.info("subjects policy_keys {}".format(policy_keys)) - for policy_key in policy_keys: - client.delete("/policies/{}/subjects/{}".format(policy_key, key)) - - -def clean_objects(client): - objects = test_perimeter.get_objects(client) - logger.info("objects {}".format(objects)) - for key in objects[1]["objects"]: - object_ = objects[1]["objects"][key] - policy_keys = object_["policy_list"] - logger.info("objects policy_keys {}".format(policy_keys)) - for policy_key in policy_keys: - client.delete("/policies/{}/objects/{}".format(policy_key, key)) - - -def clean_actions(client): - actions = test_perimeter.get_actions(client) - actions = test_perimeter.get_actions(client) - logger.info("actions {}".format(actions)) - for key in actions[1]["actions"]: - action = actions[1]["actions"][key] - policy_keys = action["policy_list"] - logger.info("action policy_keys {}".format(policy_keys)) - for policy_key in policy_keys: - client.delete("/policies/{}/actions/{}".format(policy_key, key)) - - -def clean_subject_categories(client): - req, categories = test_categories.get_subject_categories(client) - logger.info(categories) - for key in categories["subject_categories"]: - client.delete("/subject_categories/{}".format(key)) - - -def clean_object_categories(client): - req, categories = test_categories.get_object_categories(client) - logger.info(categories) - for key in categories["object_categories"]: - client.delete("/object_categories/{}".format(key)) - - -def clean_action_categories(client): - req, categories = test_categories.get_action_categories(client) - logger.info(categories) - for key in categories["action_categories"]: - client.delete("/action_categories/{}".format(key)) - - -def clean_subject_data(client): - req, policies = test_policies.get_policies(client) - logger.info("clean_subject_data on {}".format(policies)) - for policy_key in policies["policies"]: - req, data = test_data.get_subject_data(client, policy_id=policy_key) - logger.info("============= data {}".format(data)) - for data_item in data["subject_data"]: - if data_item["data"]: - for data_id in data_item["data"]: - logger.info("============= Deleting {}/{}".format(policy_key, data_id)) - client.delete("/policies/{}/subject_data/{}/{}".format(policy_key, data_item['category_id'], data_id)) - - -def clean_object_data(client): - req, policies = test_policies.get_policies(client) - for policy_key in policies["policies"]: - req, data = test_data.get_object_data(client, policy_id=policy_key) - for data_item in data["object_data"]: - if data_item["data"]: - for data_id in data_item["data"]: - logger.info("============= object_data {}/{}".format(policy_key, data_id)) - client.delete("/policies/{}/object_data/{}/{}".format(policy_key, data_item['category_id'], data_id)) - - -def clean_action_data(client): - req, policies = test_policies.get_policies(client) - for policy_key in policies["policies"]: - req, data = test_data.get_action_data(client, policy_id=policy_key) - for data_item in data["action_data"]: - if data_item["data"]: - for data_id in data_item["data"]: - logger.info("============= action_data {}/{}".format(policy_key, data_id)) - client.delete("/policies/{}/action_data/{}/{}".format(policy_key, data_item['category_id'], data_id)) - - -def clean_meta_rule(client): - req, meta_rules = test_meta_rules.get_meta_rules(client) - meta_rules = meta_rules["meta_rules"] - for meta_rule_key in meta_rules: - logger.info("clean_meta_rule.meta_rule_key={}".format(meta_rule_key)) - logger.info("clean_meta_rule.meta_rule={}".format(meta_rules[meta_rule_key])) - client.delete("/meta_rules/{}".format(meta_rule_key)) - - -def clean_subject_assignments(client): - req, policies = test_policies.get_policies(client) - for policy_key in policies["policies"]: - req, assignments = test_assignments.get_subject_assignment(client, policy_key) - for key in assignments["subject_assignments"]: - subject_key = assignments["subject_assignments"][key]["subject_id"] - cat_key = assignments["subject_assignments"][key]["category_id"] - data_keys = assignments["subject_assignments"][key]["assignments"] - for data_key in data_keys: - client.delete("/policies/{}/subject_assignments/{}/{}/{}".format(policy_key, subject_key, - cat_key, data_key)) - - -def clean_object_assignments(client): - req, policies = test_policies.get_policies(client) - for policy_key in policies["policies"]: - req, assignments = test_assignments.get_object_assignment(client, policy_key) - for key in assignments["object_assignments"]: - object_key = assignments["object_assignments"][key]["object_id"] - cat_key = assignments["object_assignments"][key]["category_id"] - data_keys = assignments["object_assignments"][key]["assignments"] - for data_key in data_keys: - client.delete("/policies/{}/object_assignments/{}/{}/{}".format(policy_key, object_key, - cat_key, data_key)) - - -def clean_action_assignments(client): - req, policies = test_policies.get_policies(client) - for policy_key in policies["policies"]: - req, assignments = test_assignments.get_action_assignment(client, policy_key) - for key in assignments["action_assignments"]: - action_key = assignments["action_assignments"][key]["action_id"] - cat_key = assignments["action_assignments"][key]["category_id"] - data_keys = assignments["action_assignments"][key]["assignments"] - for data_key in data_keys: - client.delete("/policies/{}/action_assignments/{}/{}/{}".format(policy_key, action_key, - cat_key, data_key)) - - -def clean_rules(client): - req, policies = test_policies.get_policies(client) - for policy_key in policies["policies"]: - req, rules = test_rules.get_rules(client, policy_key) - rules = rules["rules"]["rules"] - for rule_key in rules: - req = client.delete("/policies/{}/rules/{}".format(policy_key, rule_key["id"])) - - -def clean_all(client): - clean_rules(client) - - clean_subject_assignments(client) - clean_object_assignments(client) - clean_action_assignments(client) - - - clean_subject_data(client) - clean_object_data(client) - clean_action_data(client) - - clean_actions(client) - clean_objects(client) - clean_subjects(client) - - clean_subject_categories(client) - clean_object_categories(client) - clean_action_categories(client) - - - clean_policies(client) - clean_models(client) - clean_meta_rule(client) \ No newline at end of file diff --git a/moon_manager/tests/unit_python/api/meta_data_test.py b/moon_manager/tests/unit_python/api/meta_data_test.py deleted file mode 100644 index 8609f0b5..00000000 --- a/moon_manager/tests/unit_python/api/meta_data_test.py +++ /dev/null @@ -1,238 +0,0 @@ -import json -import api.utilities as utilities - -#subject_categories_test - - -def get_subject_categories(client): - req = client.get("/subject_categories") - subject_categories = utilities.get_json(req.data) - return req, subject_categories - - -def add_subject_categories(client, name): - data = { - "name": name, - "description": "description of {}".format(name) - } - req = client.post("/subject_categories", data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - subject_categories = utilities.get_json(req.data) - return req, subject_categories - - -def delete_subject_categories(client, name): - request, subject_categories = get_subject_categories(client) - for key, value in subject_categories['subject_categories'].items(): - if value['name'] == name: - req = client.delete("/subject_categories/{}".format(key)) - break - return req - - -def delete_subject_categories_without_id(client): - req = client.delete("/subject_categories/{}".format("")) - return req - - -def test_get_subject_categories(): - client = utilities.register_client() - req, subject_categories = get_subject_categories(client) - assert req.status_code == 200 - assert isinstance(subject_categories, dict) - assert "subject_categories" in subject_categories - - -def test_add_subject_categories(): - client = utilities.register_client() - req, subject_categories = add_subject_categories(client, "testuser") - assert req.status_code == 200 - assert isinstance(subject_categories, dict) - value = list(subject_categories["subject_categories"].values())[0] - assert "subject_categories" in subject_categories - assert value['name'] == "testuser" - assert value['description'] == "description of {}".format("testuser") - - -def test_add_subject_categories_with_empty_user(): - client = utilities.register_client() - req, subject_categories = add_subject_categories(client, "") - assert req.status_code == 500 - assert json.loads(req.data)["message"] == "Empty String" - - -def test_add_subject_categories_with_user_contain_space(): - client = utilities.register_client() - req, subject_categories = add_subject_categories(client, "test user") - assert req.status_code == 500 - assert json.loads(req.data)["message"] == "String contains space" - - -def test_delete_subject_categories(): - client = utilities.register_client() - req = delete_subject_categories(client, "testuser") - assert req.status_code == 200 - - -def test_delete_subject_categories_without_id(): - client = utilities.register_client() - req = delete_subject_categories_without_id(client) - assert req.status_code == 500 - - -#--------------------------------------------------------------------------- -#object_categories_test - -def get_object_categories(client): - req = client.get("/object_categories") - object_categories = utilities.get_json(req.data) - return req, object_categories - - -def add_object_categories(client, name): - data = { - "name": name, - "description": "description of {}".format(name) - } - req = client.post("/object_categories", data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - object_categories = utilities.get_json(req.data) - return req, object_categories - - -def delete_object_categories(client, name): - request, object_categories = get_object_categories(client) - for key, value in object_categories['object_categories'].items(): - if value['name'] == name: - req = client.delete("/object_categories/{}".format(key)) - break - return req - - -def delete_object_categories_without_id(client): - req = client.delete("/object_categories/{}".format("")) - return req - - -def test_get_object_categories(): - client = utilities.register_client() - req, object_categories = get_object_categories(client) - assert req.status_code == 200 - assert isinstance(object_categories, dict) - assert "object_categories" in object_categories - - -def test_add_object_categories(): - client = utilities.register_client() - req, object_categories = add_object_categories(client, "testuser") - assert req.status_code == 200 - assert isinstance(object_categories, dict) - value = list(object_categories["object_categories"].values())[0] - assert "object_categories" in object_categories - assert value['name'] == "testuser" - assert value['description'] == "description of {}".format("testuser") - - -def test_add_object_categories_with_empty_user(): - client = utilities.register_client() - req, object_categories = add_object_categories(client, "") - assert req.status_code == 500 - assert json.loads(req.data)["message"] == "Empty String" - - -def test_add_object_categories_with_user_contain_space(): - client = utilities.register_client() - req, object_categories = add_object_categories(client, "test user") - assert req.status_code == 500 - assert json.loads(req.data)["message"] == "String contains space" - - -def test_delete_object_categories(): - client = utilities.register_client() - req = delete_object_categories(client, "testuser") - assert req.status_code == 200 - - -def test_delete_object_categories_without_id(): - client = utilities.register_client() - req = delete_object_categories_without_id(client) - assert req.status_code == 500 - - -#--------------------------------------------------------------------------- -#action_categories_test - -def get_action_categories(client): - req = client.get("/action_categories") - action_categories = utilities.get_json(req.data) - return req, action_categories - - -def add_action_categories(client, name): - data = { - "name": name, - "description": "description of {}".format(name) - } - req = client.post("/action_categories", data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - action_categories = utilities.get_json(req.data) - return req, action_categories - - -def delete_action_categories(client, name): - request, action_categories = get_action_categories(client) - for key, value in action_categories['action_categories'].items(): - if value['name'] == name: - req = client.delete("/action_categories/{}".format(key)) - break - return req - - -def delete_action_categories_without_id(client): - req = client.delete("/action_categories/{}".format("")) - return req - - -def test_get_action_categories(): - client = utilities.register_client() - req, action_categories = get_action_categories(client) - assert req.status_code == 200 - assert isinstance(action_categories, dict) - assert "action_categories" in action_categories - - -def test_add_action_categories(): - client = utilities.register_client() - req, action_categories = add_action_categories(client, "testuser") - assert req.status_code == 200 - assert isinstance(action_categories, dict) - value = list(action_categories["action_categories"].values())[0] - assert "action_categories" in action_categories - assert value['name'] == "testuser" - assert value['description'] == "description of {}".format("testuser") - - -def test_add_action_categories_with_empty_user(): - client = utilities.register_client() - req, action_categories = add_action_categories(client, "") - assert req.status_code == 500 - assert json.loads(req.data)["message"] == "Empty String" - - -def test_add_action_categories_with_user_contain_space(): - client = utilities.register_client() - req, action_categories = add_action_categories(client, "test user") - assert req.status_code == 500 - assert json.loads(req.data)["message"] == "String contains space" - - -def test_delete_action_categories(): - client = utilities.register_client() - req = delete_action_categories(client, "testuser") - assert req.status_code == 200 - - -def test_delete_action_categories_without_id(): - client = utilities.register_client() - req = delete_action_categories_without_id(client) - assert req.status_code == 500 diff --git a/moon_manager/tests/unit_python/api/meta_rules_test.py b/moon_manager/tests/unit_python/api/meta_rules_test.py deleted file mode 100644 index a87c16f3..00000000 --- a/moon_manager/tests/unit_python/api/meta_rules_test.py +++ /dev/null @@ -1,162 +0,0 @@ -import json -import api.utilities as utilities - - -def get_meta_rules(client): - req = client.get("/meta_rules") - meta_rules = utilities.get_json(req.data) - return req, meta_rules - - -def add_meta_rules(client, name): - data = { - "name": name, - "subject_categories": ["subject_category_id1", - "subject_category_id2"], - "object_categories": ["object_category_id1"], - "action_categories": ["action_category_id1"] - } - req = client.post("/meta_rules", data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - meta_rules = utilities.get_json(req.data) - return req, meta_rules - - -def add_meta_rules_without_subject_category_ids(client, name): - data = { - "name": name, - "subject_categories": [], - "object_categories": ["object_category_id1"], - "action_categories": ["action_category_id1"] - } - req = client.post("/meta_rules", data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - meta_rules = utilities.get_json(req.data) - return req, meta_rules - - -def update_meta_rules(client, name, metaRuleId): - data = { - "name": name, - "subject_categories": ["subject_category_id1_update", - "subject_category_id2_update"], - "object_categories": ["object_category_id1_update"], - "action_categories": ["action_category_id1_update"] - } - req = client.patch("/meta_rules/{}".format(metaRuleId), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - meta_rules = utilities.get_json(req.data) - return req, meta_rules - - -def update_meta_rules_without_subject_category_ids(client, name): - data = { - "name": name, - "subject_categories": [], - "object_categories": ["object_category_id1"], - "action_categories": ["action_category_id1"] - } - req = client.post("/meta_rules", data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - meta_rules = utilities.get_json(req.data) - return req, meta_rules - - -def delete_meta_rules(client, name): - request, meta_rules = get_meta_rules(client) - for key, value in meta_rules['meta_rules'].items(): - if value['name'] == name: - req = client.delete("/meta_rules/{}".format(key)) - break - return req - - -def delete_meta_rules_without_id(client): - req = client.delete("/meta_rules/{}".format("")) - return req - - -def test_get_meta_rules(): - client = utilities.register_client() - req, meta_rules = get_meta_rules(client) - assert req.status_code == 200 - assert isinstance(meta_rules, dict) - assert "meta_rules" in meta_rules - - -def test_add_meta_rules(): - client = utilities.register_client() - req, meta_rules = add_meta_rules(client, "testuser") - assert req.status_code == 200 - assert isinstance(meta_rules, dict) - value = list(meta_rules["meta_rules"].values())[0] - assert "meta_rules" in meta_rules - assert value['name'] == "testuser" - assert value["subject_categories"][0] == "subject_category_id1" - assert value["object_categories"][0] == "object_category_id1" - assert value["action_categories"][0] == "action_category_id1" - - -def test_add_meta_rules_with_empty_user(): - client = utilities.register_client() - req, meta_rules = add_meta_rules(client, "") - assert req.status_code == 500 - assert json.loads(req.data)["message"] == "Empty String" - - -def test_add_meta_rules_with_user_contain_space(): - client = utilities.register_client() - req, meta_rules = add_meta_rules(client, "test user") - assert req.status_code == 500 - assert json.loads(req.data)["message"] == "String contains space" - - -def test_add_meta_rules_without_subject_categories(): - client = utilities.register_client() - req, meta_rules = add_meta_rules_without_subject_category_ids(client, "testuser") - assert req.status_code == 500 - assert json.loads(req.data)["message"] == 'Empty Container' - - -def test_delete_meta_rules(): - client = utilities.register_client() - req = delete_meta_rules(client, "testuser") - assert req.status_code == 200 - - -def test_delete_meta_rules_without_id(): - client = utilities.register_client() - req = delete_meta_rules_without_id(client) - assert req.status_code == 500 - - -def test_update_meta_rules(): - client = utilities.register_client() - req = add_meta_rules(client, "testuser") - meta_rule_id = list(req[1]['meta_rules'])[0] - req_update = update_meta_rules(client, "testuser", meta_rule_id) - assert req_update[0].status_code == 200 - value = list(req_update[1]["meta_rules"].values())[0] - assert value["subject_categories"][0] == "subject_category_id1_update" - delete_meta_rules(client, "testuser") - get_meta_rules(client) - - -def test_update_meta_rules_without_id(): - client = utilities.register_client() - req_update = update_meta_rules(client, "testuser", "") - assert req_update[0].status_code == 500 - - -def test_update_meta_rules_without_user(): - client = utilities.register_client() - req_update = update_meta_rules(client, "", "") - assert req_update[0].status_code == 500 - assert json.loads(req_update[0].data)["message"] == "Empty String" - - -def test_update_meta_rules_without_subject_categories(): - client = utilities.register_client() - req_update = update_meta_rules_without_subject_category_ids(client, "testuser") - assert req_update[0].status_code == 500 - assert json.loads(req_update[0].data)["message"] == "Empty Container" diff --git a/moon_manager/tests/unit_python/api/test_assignement.py b/moon_manager/tests/unit_python/api/test_assignement.py index b56fb420..3a127477 100644 --- a/moon_manager/tests/unit_python/api/test_assignement.py +++ b/moon_manager/tests/unit_python/api/test_assignement.py @@ -1,19 +1,60 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +import hug +from uuid import uuid4 +import pytest import api.utilities as utilities -import json from helpers import data_builder as builder -from uuid import uuid4 +from moon_utilities import exceptions + + +def delete_assignment_based_on_parameters(type, policy_id, pre_id=None, cat_id=None, data_id=None): + if type in ["subject_assignments", "object_assignments", "action_assignments"] and policy_id: + url = "/policies/" + policy_id + "/" + type + if pre_id: + url += "/" + pre_id + if cat_id: + url += "/" + cat_id + if data_id: + url += "/" + data_id + else: + return "" + from moon_manager.api import assignments + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + req = hug.test.delete(assignments, url, headers=auth_headers) + return req # subject_categories_test -def get_subject_assignment(client, policy_id): - req = client.get("/policies/{}/subject_assignments".format(policy_id)) +def get_subject_assignment(policy_id): + from moon_manager.api import assignments + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + req = hug.test.get(assignments, "/policies/{}/subject_assignments".format(policy_id), headers=auth_headers) subject_assignment = utilities.get_json(req.data) return req, subject_assignment -def add_subject_assignment(client): +def add_subject_assignment(): + from moon_manager.api import assignments + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = builder.create_new_policy( subject_category_name="subject_category1" + uuid4().hex, object_category_name="object_category1" + uuid4().hex, @@ -27,34 +68,41 @@ def add_subject_assignment(client): "category_id": subject_category_id, "data_id": data_id } - req = client.post("/policies/{}/subject_assignments".format(policy_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) + req = hug.test.post(assignments, "/policies/{}/subject_assignments/".format(policy_id), + body=data, headers=auth_headers) subject_assignment = utilities.get_json(req.data) return req, subject_assignment -def add_subject_assignment_without_cat_id(client): +def add_subject_assignment_without_cat_id(): + from moon_manager.api import assignments + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} data = { "id": "subject_id", "category_id": "", "data_id": "data_id" } - req = client.post("/policies/{}/subject_assignments".format("1111"), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) + req = hug.test.post(assignments, "/policies/{}/subject_assignments".format("1111"), body=data, + headers=auth_headers) subject_assignment = utilities.get_json(req.data) return req, subject_assignment -def delete_subject_assignment(client, policy_id, sub_id, cat_id,data_id): - req = client.delete("/policies/{}/subject_assignments/{}/{}/{}".format(policy_id, sub_id, cat_id,data_id)) +def delete_subject_assignment(policy_id, sub_id, cat_id, data_id): + from moon_manager.api import assignments + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + req = hug.test.delete(assignments, "/policies/{}/subject_assignments/{}/{}/{}".format( + policy_id, sub_id, cat_id, data_id), headers=auth_headers) return req def test_add_subject_assignment(): - client = utilities.register_client() - req, subject_assignment = add_subject_assignment(client) - assert req.status_code == 200 + req, subject_assignment = add_subject_assignment() + assert req.status == hug.HTTP_200 assert isinstance(subject_assignment, dict) assert "subject_assignments" in subject_assignment @@ -62,50 +110,97 @@ def test_add_subject_assignment(): # def test_add_subject_assignment_without_cat_id(): # client = utilities.register_client() # req, subject_assignment = add_subject_assignment_without_cat_id(client) -# assert req.status_code == 400 +# assert req.status == hug.HTTP_400 # assert json.loads(req.data)["message"] == "Key: 'category_id', [Empty String]" def test_get_subject_assignment(): - client = utilities.register_client() policy_id = builder.get_policy_id_with_subject_assignment() - req, subject_assignment = get_subject_assignment(client, policy_id) - assert req.status_code == 200 + req, subject_assignment = get_subject_assignment(policy_id) + assert req.status == hug.HTTP_200 assert isinstance(subject_assignment, dict) assert "subject_assignments" in subject_assignment def test_delete_subject_assignment(): - client = utilities.register_client() policy_id = builder.get_policy_id_with_subject_assignment() - req, subject_assignment = get_subject_assignment(client, policy_id) + req, subject_assignment = get_subject_assignment(policy_id) + value = subject_assignment["subject_assignments"] + _id = list(value.keys())[0] + success_req = delete_subject_assignment( + policy_id, + value[_id]['subject_id'], + value[_id]['category_id'], + value[_id]['assignments'][0]) + assert success_req.status == hug.HTTP_200 + + +def test_delete_subject_assignment_using_policy(): + policy_id = builder.get_policy_id_with_subject_assignment() + req, subject_assignment = get_subject_assignment(policy_id) value = subject_assignment["subject_assignments"] _id = list(value.keys())[0] - success_req = delete_subject_assignment(client, - policy_id, - value[_id]['subject_id'], - value[_id]['category_id'], - value[_id]['assignments'][0]) - assert success_req.status_code == 200 + success_req = delete_assignment_based_on_parameters( + "subject_assignments", + policy_id) + assert success_req.status == hug.HTTP_200 + + +def test_delete_subject_assignment_using_policy_perimeter_id(): + policy_id = builder.get_policy_id_with_subject_assignment() + req, subject_assignment = get_subject_assignment(policy_id) + value = subject_assignment["subject_assignments"] + _id = list(value.keys())[0] + success_req = delete_assignment_based_on_parameters( + "subject_assignments", + policy_id, + value[_id]['subject_id']) + assert success_req.status == hug.HTTP_200 + + +def test_delete_subject_assignment_using_policy_perimeter_id_category_id(): + policy_id = builder.get_policy_id_with_subject_assignment() + req, subject_assignment = get_subject_assignment(policy_id) + value = subject_assignment["subject_assignments"] + _id = list(value.keys())[0] + success_req = delete_assignment_based_on_parameters( + "subject_assignments", + policy_id, + value[_id]['subject_id'], + value[_id]['category_id']) + assert success_req.status == hug.HTTP_200 def test_delete_subject_assignment_without_policy_id(): - client = utilities.register_client() - success_req = delete_subject_assignment(client, "", "id1", "111", "data_id1") - assert success_req.status_code == 404 + + with pytest.raises(exceptions.PolicyUnknown) as exception_info: + success_req = delete_subject_assignment("", "id1", "111", "data_id1") + + assert '400: Policy Unknown' == str(exception_info.value) + + # assert success_req.status == hug.HTTP_400 + # assert success_req.data["message"] == "400: Policy Unknown" # --------------------------------------------------------------------------- # object_categories_test -def get_object_assignment(client, policy_id): - req = client.get("/policies/{}/object_assignments".format(policy_id)) +def get_object_assignment(policy_id): + from moon_manager.api import assignments + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + req = hug.test.get(assignments, "/policies/{}/object_assignments".format(policy_id), headers=auth_headers) object_assignment = utilities.get_json(req.data) return req, object_assignment -def add_object_assignment(client): +def add_object_assignment(): + from moon_manager.api import assignments + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = builder.create_new_policy( subject_category_name="subject_category1" + uuid4().hex, object_category_name="object_category1" + uuid4().hex, @@ -120,84 +215,135 @@ def add_object_assignment(client): "data_id": data_id } - req = client.post("/policies/{}/object_assignments".format(policy_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) + req = hug.test.post(assignments, "/policies/{}/object_assignments".format(policy_id), + body=data, headers=auth_headers) object_assignment = utilities.get_json(req.data) return req, object_assignment -def add_object_assignment_without_cat_id(client): +def add_object_assignment_without_cat_id(): + from moon_manager.api import assignments + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} data = { "id": "object_id", "category_id": "", "data_id": "data_id" } - req = client.post("/policies/{}/object_assignments".format("1111"), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) + req = hug.test.post(assignments, "/policies/{}/object_assignments".format("1111"), + body=data, headers=auth_headers) object_assignment = utilities.get_json(req.data) return req, object_assignment -def delete_object_assignment(client, policy_id, obj_id, cat_id, data_id): - req = client.delete("/policies/{}/object_assignments/{}/{}/{}".format(policy_id, obj_id, cat_id, data_id)) +def delete_object_assignment(policy_id, obj_id, cat_id, data_id): + from moon_manager.api import assignments + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + req = hug.test.delete(assignments, "/policies/{}/object_assignments/{}/{}/{}".format( + policy_id, obj_id, cat_id, data_id), headers=auth_headers) return req def test_get_object_assignment(): policy_id = builder.get_policy_id_with_object_assignment() - client = utilities.register_client() - req, object_assignment = get_object_assignment(client, policy_id) - assert req.status_code == 200 + + req, object_assignment = get_object_assignment(policy_id) + assert req.status == hug.HTTP_200 assert isinstance(object_assignment, dict) assert "object_assignments" in object_assignment def test_add_object_assignment(): - client = utilities.register_client() - req, object_assignment = add_object_assignment(client) - assert req.status_code == 200 + req, object_assignment = add_object_assignment() + assert req.status == hug.HTTP_200 assert "object_assignments" in object_assignment # def test_add_object_assignment_without_cat_id(): # client = utilities.register_client() # req, object_assignment = add_object_assignment_without_cat_id(client) -# assert req.status_code == 400 +# assert req.status == hug.HTTP_400 # assert json.loads(req.data)["message"] == "Key: 'category_id', [Empty String]" def test_delete_object_assignment(): - client = utilities.register_client() policy_id = builder.get_policy_id_with_object_assignment() - req, object_assignment = get_object_assignment(client, policy_id) + req, object_assignment = get_object_assignment(policy_id) value = object_assignment["object_assignments"] _id = list(value.keys())[0] - success_req = delete_object_assignment(client, - policy_id, + success_req = delete_object_assignment(policy_id, value[_id]['object_id'], value[_id]['category_id'], value[_id]['assignments'][0]) - assert success_req.status_code == 200 + assert success_req.status == hug.HTTP_200 + + +def test_delete_object_assignment_using_policy(): + policy_id = builder.get_policy_id_with_object_assignment() + req, object_assignment = get_object_assignment(policy_id) + value = object_assignment["object_assignments"] + _id = list(value.keys())[0] + success_req = delete_assignment_based_on_parameters( + "object_assignments", + policy_id) + assert success_req.status == hug.HTTP_200 + + +def test_delete_object_assignment_using_policy_perimeter_id(): + policy_id = builder.get_policy_id_with_object_assignment() + req, object_assignment = get_object_assignment(policy_id) + value = object_assignment["object_assignments"] + _id = list(value.keys())[0] + success_req = delete_assignment_based_on_parameters( + "object_assignments", + policy_id, + value[_id]['object_id']) + assert success_req.status == hug.HTTP_200 + + +def test_delete_object_assignment_using_policy_perimeter_id_category_id(): + policy_id = builder.get_policy_id_with_object_assignment() + req, object_assignment = get_object_assignment(policy_id) + value = object_assignment["object_assignments"] + _id = list(value.keys())[0] + success_req = delete_assignment_based_on_parameters( + "object_assignments", + policy_id, + value[_id]['object_id'], + value[_id]['category_id']) + assert success_req.status == hug.HTTP_200 def test_delete_object_assignment_without_policy_id(): - client = utilities.register_client() - success_req = delete_object_assignment(client, "", "id1", "111", "data_id1") - assert success_req.status_code == 404 + with pytest.raises(exceptions.PolicyUnknown) as exception_info: + success_req = delete_object_assignment("", "id1", "111", "data_id1") + # assert success_req.status == hug.HTTP_400 + # assert success_req.data["message"] == "400: Policy Unknown" + assert '400: Policy Unknown' == str(exception_info.value) # --------------------------------------------------------------------------- # action_categories_test -def get_action_assignment(client, policy_id): - req = client.get("/policies/{}/action_assignments".format(policy_id)) +def get_action_assignment(policy_id): + from moon_manager.api import assignments + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + req = hug.test.get(assignments, "/policies/{}/action_assignments".format(policy_id), headers=auth_headers) action_assignment = utilities.get_json(req.data) return req, action_assignment -def add_action_assignment(client): +def add_action_assignment(): + from moon_manager.api import assignments + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = builder.create_new_policy( subject_category_name="subject_category1" + uuid4().hex, object_category_name="object_category1" + uuid4().hex, @@ -211,70 +357,113 @@ def add_action_assignment(client): "category_id": action_category_id, "data_id": data_id } - req = client.post("/policies/{}/action_assignments".format(policy_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) + req = hug.test.post(assignments, "/policies/{}/action_assignments".format(policy_id), + body=data, + headers=auth_headers) action_assignment = utilities.get_json(req.data) return req, action_assignment -def add_action_assignment_without_cat_id(client): +def add_action_assignment_without_cat_id(): + from moon_manager.api import assignments + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} data = { "id": "action_id", "category_id": "", "data_id": "data_id" } - req = client.post("/policies/{}/action_assignments".format("1111"), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) + req = hug.test.post(assignments, "/policies/{}/action_assignments".format("1111"), + body=data, headers=auth_headers) action_assignment = utilities.get_json(req.data) return req, action_assignment -def delete_action_assignment(client, policy_id, action_id, cat_id, data_id): - req = client.delete("/policies/{}/action_assignments/{}/{}/{}".format(policy_id, action_id, cat_id, data_id)) +def delete_action_assignment(policy_id, action_id, cat_id, data_id): + from moon_manager.api import assignments + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + req = hug.test.delete(assignments, "/policies/{}/action_assignments/{}/{}/{}".format( + policy_id, action_id, cat_id, data_id), headers=auth_headers) return req def test_get_action_assignment(): policy_id = builder.get_policy_id_with_action_assignment() - client = utilities.register_client() - req, action_assignment = get_action_assignment(client, policy_id) - assert req.status_code == 200 + req, action_assignment = get_action_assignment(policy_id) + assert req.status == hug.HTTP_200 assert isinstance(action_assignment, dict) assert "action_assignments" in action_assignment def test_add_action_assignment(): - client = utilities.register_client() - req, action_assignment = add_action_assignment(client) - assert req.status_code == 200 + req, action_assignment = add_action_assignment() + assert req.status == hug.HTTP_200 assert "action_assignments" in action_assignment # def test_add_action_assignment_without_cat_id(): # client = utilities.register_client() # req, action_assignment = add_action_assignment_without_cat_id(client) -# assert req.status_code == 400 +# assert req.status == hug.HTTP_400 # assert json.loads(req.data)["message"] == "Key: 'category_id', [Empty String]" def test_delete_action_assignment(): - client = utilities.register_client() policy_id = builder.get_policy_id_with_action_assignment() - req, action_assignment = get_action_assignment(client, policy_id) + req, action_assignment = get_action_assignment(policy_id) value = action_assignment["action_assignments"] id = list(value.keys())[0] - success_req = delete_action_assignment(client, - policy_id, + success_req = delete_action_assignment(policy_id, value[id]['action_id'], value[id]['category_id'], value[id]['assignments'][0]) - assert success_req.status_code == 200 + assert success_req.status == hug.HTTP_200 + + +def test_delete_action_assignment_policy(): + policy_id = builder.get_policy_id_with_action_assignment() + req, action_assignment = get_action_assignment(policy_id) + value = action_assignment["action_assignments"] + id = list(value.keys())[0] + success_req = delete_assignment_based_on_parameters( + "action_assignments", + policy_id) + assert success_req.status == hug.HTTP_200 + + +def test_delete_action_assignment_policy_perimeter_id(): + policy_id = builder.get_policy_id_with_action_assignment() + req, action_assignment = get_action_assignment(policy_id) + value = action_assignment["action_assignments"] + id = list(value.keys())[0] + success_req = delete_assignment_based_on_parameters( + "action_assignments", + policy_id, + value[id]['action_id']) + assert success_req.status == hug.HTTP_200 + + +def test_delete_action_assignment_policy_perimeter_id_category_id(): + policy_id = builder.get_policy_id_with_action_assignment() + req, action_assignment = get_action_assignment(policy_id) + value = action_assignment["action_assignments"] + id = list(value.keys())[0] + success_req = delete_assignment_based_on_parameters( + "action_assignments", + policy_id, + value[id]['action_id'], + value[id]['category_id']) + assert success_req.status == hug.HTTP_200 def test_delete_action_assignment_without_policy_id(): - client = utilities.register_client() - success_req = delete_action_assignment(client, "", "id1", "111", "data_id1") - assert success_req.status_code == 404 + with pytest.raises(exceptions.PolicyUnknown) as exception_info: + success_req = delete_action_assignment("", "id1", "111", "data_id1") + # assert success_req.status == hug.HTTP_400 + # assert success_req.data["message"] == "400: Policy Unknown" + assert '400: Policy Unknown' == str(exception_info.value) # --------------------------------------------------------------------------- diff --git a/moon_manager/tests/unit_python/api/test_assignemnt.py b/moon_manager/tests/unit_python/api/test_assignemnt.py deleted file mode 100644 index 22c727af..00000000 --- a/moon_manager/tests/unit_python/api/test_assignemnt.py +++ /dev/null @@ -1,270 +0,0 @@ -import api.utilities as utilities -import json -from helpers import data_builder as builder -from uuid import uuid4 - - -# subject_categories_test - - -def get_subject_assignment(client, policy_id): - req = client.get("/policies/{}/subject_assignments".format(policy_id)) - subject_assignment = utilities.get_json(req.data) - return req, subject_assignment - - -def add_subject_assignment(client): - subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = builder.create_new_policy( - subject_category_name="subject_category1" + uuid4().hex, - object_category_name="object_category1" + uuid4().hex, - action_category_name="action_category1" + uuid4().hex, - meta_rule_name="meta_rule_1" + uuid4().hex) - subject_id = builder.create_subject(policy_id) - data_id = builder.create_subject_data(policy_id=policy_id, category_id=subject_category_id) - - data = { - "id": subject_id, - "category_id": subject_category_id, - "data_id": data_id - } - req = client.post("/policies/{}/subject_assignments".format(policy_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - subject_assignment = utilities.get_json(req.data) - return req, subject_assignment - - -def add_subject_assignment_without_cat_id(client): - - data = { - "id": "subject_id", - "category_id": "", - "data_id": "data_id" - } - req = client.post("/policies/{}/subject_assignments".format("1111"), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - subject_assignment = utilities.get_json(req.data) - return req, subject_assignment - - -def delete_subject_assignment(client, policy_id, sub_id, cat_id,data_id): - req = client.delete("/policies/{}/subject_assignments/{}/{}/{}".format(policy_id, sub_id, cat_id,data_id)) - return req - - -def test_add_subject_assignment(): - client = utilities.register_client() - req, subject_assignment = add_subject_assignment(client) - assert req.status_code == 200 - assert isinstance(subject_assignment, dict) - assert "subject_assignments" in subject_assignment - - -def test_add_subject_assignment_without_cat_id(): - client = utilities.register_client() - req, subject_assignment = add_subject_assignment_without_cat_id(client) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == "Key: 'category_id', [Empty String]" - - -def test_get_subject_assignment(): - client = utilities.register_client() - policy_id = builder.get_policy_id_with_subject_assignment() - req, subject_assignment = get_subject_assignment(client, policy_id) - assert req.status_code == 200 - assert isinstance(subject_assignment, dict) - assert "subject_assignments" in subject_assignment - - -def test_delete_subject_assignment(): - client = utilities.register_client() - policy_id = builder.get_policy_id_with_subject_assignment() - req, subject_assignment = get_subject_assignment(client, policy_id) - value = subject_assignment["subject_assignments"] - id = list(value.keys())[0] - success_req = delete_subject_assignment(client, policy_id, value[id]['subject_id'], value[id]['category_id'],value[id]['assignments'][0]) - assert success_req.status_code == 200 - - -def test_delete_subject_assignment_without_policy_id(): - client = utilities.register_client() - success_req = delete_subject_assignment(client, "", "id1", "111" ,"data_id1") - assert success_req.status_code == 404 - - -# --------------------------------------------------------------------------- - -# object_categories_test - - -def get_object_assignment(client, policy_id): - req = client.get("/policies/{}/object_assignments".format(policy_id)) - object_assignment = utilities.get_json(req.data) - return req, object_assignment - - -def add_object_assignment(client): - subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = builder.create_new_policy( - subject_category_name="subject_category1" + uuid4().hex, - object_category_name="object_category1" + uuid4().hex, - action_category_name="action_category1" + uuid4().hex, - meta_rule_name="meta_rule_1" + uuid4().hex) - object_id = builder.create_object(policy_id) - data_id = builder.create_object_data(policy_id=policy_id, category_id=object_category_id) - - data = { - "id": object_id, - "category_id": object_category_id, - "data_id": data_id - } - - req = client.post("/policies/{}/object_assignments".format(policy_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - object_assignment = utilities.get_json(req.data) - return req, object_assignment - - -def add_object_assignment_without_cat_id(client): - - data = { - "id": "object_id", - "category_id": "", - "data_id": "data_id" - } - req = client.post("/policies/{}/object_assignments".format("1111"), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - object_assignment = utilities.get_json(req.data) - return req, object_assignment - - -def delete_object_assignment(client, policy_id, obj_id, cat_id, data_id): - req = client.delete("/policies/{}/object_assignments/{}/{}/{}".format(policy_id, obj_id, cat_id, data_id)) - return req - - -def test_get_object_assignment(): - policy_id = builder.get_policy_id_with_object_assignment() - client = utilities.register_client() - req, object_assignment = get_object_assignment(client, policy_id) - assert req.status_code == 200 - assert isinstance(object_assignment, dict) - assert "object_assignments" in object_assignment - - -def test_add_object_assignment(): - client = utilities.register_client() - req, object_assignment = add_object_assignment(client) - assert req.status_code == 200 - assert "object_assignments" in object_assignment - - -def test_add_object_assignment_without_cat_id(): - client = utilities.register_client() - req, object_assignment = add_object_assignment_without_cat_id(client) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == "Key: 'category_id', [Empty String]" - - -def test_delete_object_assignment(): - client = utilities.register_client() - policy_id = builder.get_policy_id_with_object_assignment() - req, object_assignment = get_object_assignment(client, policy_id) - value = object_assignment["object_assignments"] - id = list(value.keys())[0] - success_req = delete_object_assignment(client, policy_id, value[id]['object_id'], value[id]['category_id'],value[id]['assignments'][0]) - assert success_req.status_code == 200 - - -def test_delete_object_assignment_without_policy_id(): - client = utilities.register_client() - success_req = delete_object_assignment(client, "", "id1", "111","data_id1") - assert success_req.status_code == 404 - - -# --------------------------------------------------------------------------- - -# action_categories_test - - -def get_action_assignment(client, policy_id): - req = client.get("/policies/{}/action_assignments".format(policy_id)) - action_assignment = utilities.get_json(req.data) - return req, action_assignment - - -def add_action_assignment(client): - subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = builder.create_new_policy( - subject_category_name="subject_category1" + uuid4().hex, - object_category_name="object_category1" + uuid4().hex, - action_category_name="action_category1" + uuid4().hex, - meta_rule_name="meta_rule_1" + uuid4().hex) - action_id = builder.create_action(policy_id) - data_id = builder.create_action_data(policy_id=policy_id, category_id=action_category_id) - - data = { - "id": action_id, - "category_id": action_category_id, - "data_id": data_id - } - req = client.post("/policies/{}/action_assignments".format(policy_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - action_assignment = utilities.get_json(req.data) - return req, action_assignment - - -def add_action_assignment_without_cat_id(client): - - data = { - "id": "action_id", - "category_id": "", - "data_id": "data_id" - } - req = client.post("/policies/{}/action_assignments".format("1111"), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - action_assignment = utilities.get_json(req.data) - return req, action_assignment - - -def delete_action_assignment(client, policy_id, action_id, cat_id, data_id): - req = client.delete("/policies/{}/action_assignments/{}/{}/{}".format(policy_id, action_id, cat_id, data_id)) - return req - - -def test_get_action_assignment(): - policy_id = builder.get_policy_id_with_action_assignment() - client = utilities.register_client() - req, action_assignment = get_action_assignment(client, policy_id) - assert req.status_code == 200 - assert isinstance(action_assignment, dict) - assert "action_assignments" in action_assignment - - -def test_add_action_assignment(): - client = utilities.register_client() - req, action_assignment = add_action_assignment(client) - assert req.status_code == 200 - assert "action_assignments" in action_assignment - - -def test_add_action_assignment_without_cat_id(): - client = utilities.register_client() - req, action_assignment = add_action_assignment_without_cat_id(client) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == "Key: 'category_id', [Empty String]" - - -def test_delete_action_assignment(): - client = utilities.register_client() - policy_id = builder.get_policy_id_with_action_assignment() - req, action_assignment = get_action_assignment(client, policy_id) - value = action_assignment["action_assignments"] - id = list(value.keys())[0] - success_req = delete_action_assignment(client, policy_id, value[id]['action_id'], value[id]['category_id'],value[id]['assignments'][0]) - assert success_req.status_code == 200 - - -def test_delete_action_assignment_without_policy_id(): - client = utilities.register_client() - success_req = delete_action_assignment(client, "", "id1", "111" ,"data_id1") - assert success_req.status_code == 404 - -# --------------------------------------------------------------------------- diff --git a/moon_manager/tests/unit_python/api/test_auth.py b/moon_manager/tests/unit_python/api/test_auth.py new file mode 100644 index 00000000..ee59bf5e --- /dev/null +++ b/moon_manager/tests/unit_python/api/test_auth.py @@ -0,0 +1,71 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +from falcon import HTTP_200, HTTP_204, HTTP_401 +import hug +import base64 +from uuid import uuid4 +from helpers import data_builder as builder + + +def test_get_auth(): + from moon_utilities.auth_functions import get_api_key_for_user + from moon_manager.api import auth + from moon_manager.api import policy + headers = {"Authorization": "Basic {}".format(base64.b64encode(b"admin:admin").decode("utf-8"))} + req = hug.test.get(auth, 'auth/', headers=headers) + assert req.status == HTTP_200 + key = req.data + assert get_api_key_for_user("admin") == req.data + headers = {"x-api-key": key} + req = hug.test.get(policy, 'policies/', headers=headers) + assert req.status == HTTP_200 + + +def test_del_auth(): + from moon_utilities.auth_functions import get_api_key_for_user + from moon_manager.api import auth + from moon_manager.api import policy + headers = {"Authorization": "Basic {}".format(base64.b64encode(b"admin:admin").decode("utf-8"))} + req = hug.test.get(auth, 'auth/', headers=headers) + assert req.status == HTTP_200 + key = req.data + headers = {"x-api-key": key} + req = hug.test.delete(auth, 'auth/', headers=headers) + assert req.status == HTTP_204 + req = hug.test.get(policy, 'policies/', headers=headers) + assert req.status == HTTP_401 + assert not get_api_key_for_user("admin") + + +def test_readd_auth(): + from moon_utilities.auth_functions import get_api_key_for_user + from moon_manager.api import auth + from moon_manager.api import policy + headers = {"Authorization": "Basic {}".format(base64.b64encode(b"admin:admin").decode("utf-8"))} + req = hug.test.get(auth, 'auth/', headers=headers) + assert req.status == HTTP_200 + key = req.data + headers = {"x-api-key": key} + req = hug.test.delete(auth, 'auth/', headers=headers) + assert req.status == HTTP_204 + headers = {"Authorization": "Basic {}".format(base64.b64encode(b"admin:admin").decode("utf-8"))} + req = hug.test.get(auth, 'auth/', headers=headers) + assert req.status == HTTP_200 + new_key = req.data + headers = {"x-api-key": new_key} + req = hug.test.get(policy, 'policies/', headers=headers) + assert req.status == HTTP_200 + assert get_api_key_for_user("admin") + assert get_api_key_for_user("admin") == new_key + assert get_api_key_for_user("admin") != key + diff --git a/moon_manager/tests/unit_python/api/test_data.py b/moon_manager/tests/unit_python/api/test_data.py index 433f69e6..019a8b45 100644 --- a/moon_manager/tests/unit_python/api/test_data.py +++ b/moon_manager/tests/unit_python/api/test_data.py @@ -1,59 +1,83 @@ -# Copyright 2018 Open Platform for NFV Project, Inc. and its contributors -# This software is distributed under the terms and conditions of the 'Apache-2.0' -# license which can be found in the file 'LICENSE' in this package distribution -# or at 'http://www.apache.org/licenses/LICENSE-2.0'. +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + -import api.utilities as utilities import json -from helpers import data_builder as builder from uuid import uuid4 +import hug +import pytest +from helpers import data_builder as builder +from helpers import policy_helper +from moon_utilities import exceptions + + # subject_categories_test -def get_subject_data(client, policy_id, category_id=None): +def get_subject_data(policy_id, category_id=None): + from moon_manager.api import data + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + if category_id is None: - req = client.get("/policies/{}/subject_data".format(policy_id)) + req = hug.test.get(data, "/policies/{}/subject_data".format(policy_id), headers=auth_headers) else: - req = client.get("/policies/{}/subject_data/{}".format(policy_id, category_id)) - subject_data = utilities.get_json(req.data) + req = hug.test.get(data, "/policies/{}/subject_data/{}".format(policy_id, category_id), headers=auth_headers) + subject_data = req.data return req, subject_data -def add_subject_data(client, name): +def add_subject_data(name): + from moon_manager.api import data + from moon_utilities.auth_functions import get_api_key_for_user + subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = builder.create_new_policy( subject_category_name="subject_category1" + uuid4().hex, object_category_name="object_category1" + uuid4().hex, action_category_name="action_category1" + uuid4().hex, meta_rule_name="meta_rule_1" + uuid4().hex) - data = { + body = { "name": name, "description": "description of {}".format(name) } - req = client.post("/policies/{}/subject_data/{}".format(policy_id, subject_category_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - subject_data = utilities.get_json(req.data) + req = hug.test.post(data, "/policies/{}/subject_data/{}".format(policy_id, subject_category_id), + body=json.dumps(body), + headers={'Content-Type': 'application/json', "X-Api-Key": get_api_key_for_user("admin")}) + subject_data = req.data return req, subject_data -def delete_subject_data(client, policy_id, category_id, data_id): - req = client.delete("/policies/{}/subject_data/{}/{}".format(policy_id,category_id,data_id)) +def delete_subject_data(policy_id, category_id, data_id): + from moon_manager.api import data + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + req = hug.test.delete(data, "/policies/{}/subject_data/{}/{}".format(policy_id, category_id, + data_id), headers=auth_headers) return req def test_get_subject_data(): - policy_id = utilities.get_policy_id() - client = utilities.register_client() - req, subject_data = get_subject_data(client, policy_id) - assert req.status_code == 200 + policy = policy_helper.add_policies() + policy_id = next(iter(policy)) + req, subject_data = get_subject_data(policy_id) + assert req.status == hug.HTTP_200 assert isinstance(subject_data, dict) assert "subject_data" in subject_data def test_add_subject_data(): - client = utilities.register_client() - req, subject_data = add_subject_data(client, "testuser") - assert req.status_code == 200 + req, subject_data = add_subject_data("testuser") + assert req.status == hug.HTTP_200 assert isinstance(subject_data, dict) value = subject_data["subject_data"]['data'] assert "subject_data" in subject_data @@ -62,73 +86,97 @@ def test_add_subject_data(): assert value[id]['description'] == "description of {}".format("testuser") +def test_add_subject_data_invalid_name(): + with pytest.raises(exceptions.DataContentError) as exception_info: + req, subject_data = add_subject_data(" ") + # assert req.status == hug.HTTP_400 + assert '400: Data Content Error' == str(exception_info.value) + with pytest.raises(exceptions.DataContentError) as exception_info: + req, subject_data = add_subject_data("") + # assert req.status == hug.HTTP_400 + assert '400: Data Content Error' == str(exception_info.value) + + def test_delete_subject_data(): - client = utilities.register_client() - subject_category_id, object_category_id, action_category_id, meta_rule_id,policy_id = builder.create_new_policy() - data_id = builder.create_subject_data(policy_id,subject_category_id) - success_req = delete_subject_data(client, policy_id, subject_category_id, data_id ) - assert success_req.status_code == 200 + subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = builder.create_new_policy() + data_id = builder.create_subject_data(policy_id, subject_category_id) + success_req = delete_subject_data(policy_id, subject_category_id, data_id) + assert success_req.status == hug.HTTP_200 def test_add_subject_data_with_forbidden_char_in_user(): - client = utilities.register_client() - req, subject_data = add_subject_data(client, "") - assert req.status_code == 400 - assert json.loads(req.data)["message"] == "Key: 'name', [Forbidden characters in string]" + with pytest.raises(exceptions.ValidationContentError) as exception_info: + req, subject_data = add_subject_data("") + # assert '400: Invalid Content' == str(exception_info.value) + assert "Key: 'name', [Forbidden characters in string]" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == "Key: 'name', [Forbidden characters in string]" def test_delete_subject_data_without_policy_id(): - client = utilities.register_client() - success_req = delete_subject_data(client, "", "", "") - assert success_req.status_code == 404 + success_req = delete_subject_data("", "", "") + assert success_req.status == hug.HTTP_405 + # --------------------------------------------------------------------------- # object_categories_test -def get_object_data(client, policy_id, category_id=None): +def get_object_data(policy_id, category_id=None): + from moon_manager.api import data + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + if category_id is None: - req = client.get("/policies/{}/object_data".format(policy_id)) + req = hug.test.get(data, "/policies/{}/object_data".format(policy_id), headers=auth_headers) else: - req = client.get("/policies/{}/object_data/{}".format(policy_id, category_id)) - object_data = utilities.get_json(req.data) + req = hug.test.get(data, "/policies/{}/object_data/{}".format(policy_id, category_id), headers=auth_headers) + object_data = req.data return req, object_data -def add_object_data(client, name): +def add_object_data(name): + from moon_manager.api import data + from moon_utilities.auth_functions import get_api_key_for_user + subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = builder.create_new_policy( subject_category_name="subject_category1" + uuid4().hex, object_category_name="object_category1" + uuid4().hex, action_category_name="action_category1" + uuid4().hex, meta_rule_name="meta_rule_1" + uuid4().hex) - data = { + body = { "name": name, "description": "description of {}".format(name) } - req = client.post("/policies/{}/object_data/{}".format(policy_id, object_category_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - object_data = utilities.get_json(req.data) + req = hug.test.post(data, "/policies/{}/object_data/{}".format(policy_id, object_category_id), + body=json.dumps(body), headers={'Content-Type': 'application/json', + "X-Api-Key": get_api_key_for_user("admin")}) + object_data = req.data return req, object_data -def delete_object_data(client, policy_id, category_id, data_id): - req = client.delete("/policies/{}/object_data/{}/{}".format(policy_id, category_id, data_id)) +def delete_object_data(policy_id, category_id, data_id): + from moon_manager.api import data + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + req = hug.test.delete(data, "/policies/{}/object_data/{}/{}".format(policy_id, category_id, + data_id), headers=auth_headers) return req def test_get_object_data(): - policy_id = utilities.get_policy_id() - client = utilities.register_client() - req, object_data = get_object_data(client, policy_id) - assert req.status_code == 200 + policy = policy_helper.add_policies() + policy_id = next(iter(policy)) + req, object_data = get_object_data(policy_id) + assert req.status == hug.HTTP_200 assert isinstance(object_data, dict) assert "object_data" in object_data def test_add_object_data(): - client = utilities.register_client() - req, object_data = add_object_data(client, "testuser") - assert req.status_code == 200 + req, object_data = add_object_data("testuser") + assert req.status == hug.HTTP_200 assert isinstance(object_data, dict) value = object_data["object_data"]['data'] assert "object_data" in object_data @@ -137,75 +185,100 @@ def test_add_object_data(): assert value[_id]['description'] == "description of {}".format("testuser") -def test_delete_object_data(): - client = utilities.register_client() +def test_add_object_data_invalid_name(): + with pytest.raises(exceptions.DataContentError) as exception_info: + req, object_data = add_object_data(" ") + # assert req.status == hug.HTTP_400 + assert '400: Data Content Error' == str(exception_info.value) + with pytest.raises(exceptions.DataContentError): + req, object_data = add_object_data("") + # assert req.status == hug.HTTP_400 + assert '400: Data Content Error' == str(exception_info.value) + +def test_delete_object_data(): subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = builder.create_new_policy() data_id = builder.create_object_data(policy_id, object_category_id) - - success_req = delete_object_data(client, policy_id, data_id, object_category_id) - assert success_req.status_code == 200 + success_req = delete_object_data(policy_id, data_id, object_category_id) + assert success_req.status == hug.HTTP_200 def test_add_object_data_with_forbidden_char_in_user(): - client = utilities.register_client() - req, subject_data = add_object_data(client, "") - assert req.status_code == 400 - assert json.loads(req.data)["message"] == "Key: 'name', [Forbidden characters in string]" + with pytest.raises(exceptions.ValidationContentError) as exception_info: + req, subject_data = add_object_data("") + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == "Key: 'name', [Forbidden characters in string]" + # assert '400: Invalid Content' == str(exception_info.value) + assert "Key: 'name', [Forbidden characters in string]" == str(exception_info.value) def test_delete_object_data_without_policy_id(): - client = utilities.register_client() - success_req = delete_object_data(client, "", "", "") - assert success_req.status_code == 404 + success_req = delete_object_data("", "", "") + assert success_req.status == hug.HTTP_405 + # --------------------------------------------------------------------------- # action_categories_test -def get_action_data(client, policy_id, category_id=None): +def get_action_data(policy_id, category_id=None): + from moon_manager.api import data + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + if category_id is None: - req = client.get("/policies/{}/action_data".format(policy_id)) + req = hug.test.get(data, "/policies/{}/action_data".format(policy_id), + headers=auth_headers) else: - req = client.get("/policies/{}/action_data/{}".format(policy_id, category_id)) - action_data = utilities.get_json(req.data) + req = hug.test.get(data, "/policies/{}/action_data/{}".format(policy_id, category_id), + headers=auth_headers) + action_data = req.data return req, action_data -def add_action_data(client, name): +def add_action_data(name): + from moon_manager.api import data + from moon_utilities.auth_functions import get_api_key_for_user + subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = builder.create_new_policy( subject_category_name="subject_category1" + uuid4().hex, object_category_name="object_category1" + uuid4().hex, action_category_name="action_category1" + uuid4().hex, meta_rule_name="meta_rule_1" + uuid4().hex) - data = { + body = { "name": name, "description": "description of {}".format(name) } - req = client.post("/policies/{}/action_data/{}".format(policy_id, action_category_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - action_data = utilities.get_json(req.data) + req = hug.test.post(data, "/policies/{}/action_data/{}".format(policy_id, action_category_id), + body=json.dumps(body), + headers={'Content-Type': 'application/json', + "X-Api-Key": get_api_key_for_user("admin")}) + action_data = req.data return req, action_data -def delete_action_data(client, policy_id, categorgy_id, data_id): - req = client.delete("/policies/{}/action_data/{}/{}".format(policy_id, categorgy_id, data_id)) +def delete_action_data(policy_id, categorgy_id, data_id): + from moon_manager.api import data + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + req = hug.test.delete(data, "/policies/{}/action_data/{}/{}".format(policy_id, categorgy_id, + data_id), headers=auth_headers) return req def test_get_action_data(): - policy_id = utilities.get_policy_id() - client = utilities.register_client() - req, action_data = get_action_data(client, policy_id) - assert req.status_code == 200 + policy = policy_helper.add_policies() + policy_id = next(iter(policy)) + req, action_data = get_action_data(policy_id) + assert req.status == hug.HTTP_200 assert isinstance(action_data, dict) assert "action_data" in action_data def test_add_action_data(): - client = utilities.register_client() - req, action_data = add_action_data(client, "testuser") - assert req.status_code == 200 + req, action_data = add_action_data("testuser") + assert req.status == hug.HTTP_200 assert isinstance(action_data, dict) value = action_data["action_data"]['data'] assert "action_data" in action_data @@ -214,26 +287,35 @@ def test_add_action_data(): assert value[id]['description'] == "description of {}".format("testuser") -def test_delete_action_data(): - client = utilities.register_client() +def test_add_action_data_invalid_name(): - subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = builder.create_new_policy() - data_id = builder.create_action_data(policy_id, action_category_id) + with pytest.raises(exceptions.DataContentError)as exception_info: + req, action_data = add_action_data(" ") + # assert req.status == hug.HTTP_400 + assert '400: Data Content Error' == str(exception_info.value) + with pytest.raises(exceptions.DataContentError) as exception_info: + req, action_data = add_action_data("") + # assert req.status == hug.HTTP_400 + assert '400: Data Content Error' == str(exception_info.value) - success_req = delete_action_data(client, policy_id, data_id, action_category_id) - assert success_req.status_code == 200 +def test_delete_action_data(): + subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = builder.create_new_policy() + data_id = builder.create_action_data(policy_id, action_category_id) + success_req = delete_action_data(policy_id, data_id, action_category_id) + assert success_req.status == hug.HTTP_200 def test_add_action_data_with_forbidden_char_in_user(): - client = utilities.register_client() - req, action_data = add_action_data(client, "") - assert req.status_code == 400 - assert json.loads(req.data)["message"] == "Key: 'name', [Forbidden characters in string]" + with pytest.raises(exceptions.ValidationContentError) as exception_info: + req, action_data = add_action_data("") + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == "Key: 'name', [Forbidden characters in string]" + # assert '400: Invalid Content' == str(exception_info.value) + assert "Key: 'name', [Forbidden characters in string]" == str(exception_info.value) def test_delete_action_data_without_policy_id(): - client = utilities.register_client() - success_req = delete_action_data(client, "", "", "") - assert success_req.status_code == 404 + success_req = delete_action_data("", "", "") + assert success_req.status == hug.HTTP_405 # --------------------------------------------------------------------------- diff --git a/moon_manager/tests/unit_python/api/test_export.py b/moon_manager/tests/unit_python/api/test_export.py deleted file mode 100644 index ac8e8d17..00000000 --- a/moon_manager/tests/unit_python/api/test_export.py +++ /dev/null @@ -1,282 +0,0 @@ -# Copyright 2018 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 json -import api.utilities as utilities -import api.import_export_utilities as import_export_utilities - - -MODEL_WITHOUT_META_RULES = {"models": [{"name": "test model", "description": "model description", "meta_rules": []}]} - -POLICIES = {"models": [{"name": "test model", "description": "", "meta_rules": []}], - "policies": [{"name": "test policy", "genre": "authz", "description": "policy description", "model": {"name" : "test model"}}]} - -SUBJECTS_OBJECTS_ACTIONS = {"models": [{"name": "test model", "description": "", "meta_rules": []}], - "policies": [{"name": "test policy", "genre": "authz", "description": "policy description", "model": {"name" : "test model"}}], - "subjects": [{"name": "testuser", "description": "description of the subject", "extra": {"field_extra_subject": "value extra subject"}, "policies": [{"name": "test policy"}]}], - "objects": [{"name": "test object", "description": "description of the object", "extra": {"field_extra_object": "value extra object"}, "policies": [{"name": "test policy"}]}], - "actions": [{"name": "test action", "description": "description of the action", "extra": {"field_extra_action": "value extra action"}, "policies": [{"name": "test policy"}]}]} - - -SUBJECT_OBJECT_ACTION_CATEGORIES = {"subject_categories": [{"name": "test subject categories", "description": "subject category description"}], - "object_categories": [{"name": "test object categories", "description": "object category description"}], - "action_categories": [{"name": "test action categories", "description": "action category description"}]} - -SUBJECT_OBJECT_ACTION_DATA = {"models": [{"name": "test model", "description": "", "meta_rules": [{"name": "meta rule"}]}], - "policies": [{"name": "test policy", "genre": "authz", "description": "policy description", "model": {"name" : "test model"}}], - "subject_categories": [{"name": "test subject categories", "description": "subject category description"}], - "object_categories": [{"name": "test object categories", "description": "object category description"}], - "action_categories": [{"name": "test action categories", "description": "action category description"}], - "subject_data": [{"name": "test subject data", "description": "subject data description", "policies": [{"name": "test policy"}], "category": {"name": "test subject categories"}}], - "object_data": [{"name": "test object data", "description": "object data description", "policies": [{"name": "test policy"}], "category": {"name": "test object categories"}}], - "action_data": [{"name": "test action data", "description": "action data description", "policies": [{"name": "test policy"}], "category": {"name": "test action categories"}}], - "meta_rules": [{"name": "meta rule", "description": "valid meta rule", "subject_categories": [{"name": "test subject categories"}], "object_categories": [{"name": "test object categories"}], "action_categories": [{"name": "test action categories"}]}]} - - -META_RULES = {"subject_categories": [{"name": "test subject categories", "description": "subject category description"}], - "object_categories": [{"name": "test object categories", "description": "object category description"}], - "action_categories": [{"name": "test action categories", "description": "object action description"}], - "meta_rules": [{"name": "meta rule", "description": "valid meta rule", "subject_categories": [{"name": "test subject categories"}], "object_categories": [{"name": "test object categories"}], "action_categories": [{"name": "test action categories"}]}]} - - -ASSIGNMENTS = {"models": [{"name": "test model", "description": "", "meta_rules": [{"name": "meta rule"}]}], - "policies": [{"name": "test policy", "genre": "authz", "description": "policy description", "model": {"name" : "test model"}}], - "subject_categories": [{"name": "test subject categories", "description": "subject category description"}], - "object_categories": [{"name": "test object categories", "description": "object category description"}], - "action_categories": [{"name": "test action categories", "description": "action category description"}], - "subject_data": [{"name": "test subject data", "description": "subject data description", "policies": [{"name": "test policy"}], "category": {"name": "test subject categories"}}], - "object_data": [{"name": "test object data", "description": "object data description", "policies": [{"name": "test policy"}], "category": {"name": "test object categories"}}], - "action_data": [{"name": "test action data", "description": "action data description", "policies": [{"name": "test policy"}], "category": {"name": "test action categories"}}], - "meta_rules": [{"name": "meta rule", "description": "valid meta rule", "subject_categories": [{"name": "test subject categories"}], "object_categories": [{"name": "test object categories"}], "action_categories": [{"name": "test action categories"}]}], - "subjects": [{"name": "testuser", "description": "description of the subject", "extra": {"field_extra_subject": "value extra subject"}, "policies": [{"name": "test policy"}]}], - "objects": [{"name": "test object e0", "description": "description of the object", "extra": {"field_extra_object": "value extra object"}, "policies": [{"name": "test policy"}]}], - "actions": [{"name": "test action e0", "description": "description of the action", "extra": {"field_extra_action": "value extra action"}, "policies": [{"name": "test policy"}]}], - "subject_assignments": [{"subject": {"name": "testuser"}, "category": {"name": "test subject categories"}, "assignments": [{"name": "test subject data"}]}], - "object_assignments": [{"object": {"name": "test object e0"}, "category": {"name": "test object categories"}, "assignments": [{"name": "test object data"}]}], - "action_assignments": [{"action": {"name": "test action e0"}, "category": {"name": "test action categories"}, "assignments": [{"name": "test action data"}]}]} - -RULES = {"models": [{"name": "test model", "description": "", "meta_rules": [{"name": "meta rule"}]}], - "policies": [{"name": "test policy", "genre": "authz", "description": "policy description", "model": {"name" : "test model"}}], - "subject_categories": [{"name": "test subject categories", "description": "subject category description"}], - "object_categories": [{"name": "test object categories", "description": "object category description"}], - "action_categories": [{"name": "test action categories", "description": "action category description"}], - "subject_data": [{"name": "test subject data", "description": "subject data description", "policies": [{"name": "test policy"}], "category": {"name": "test subject categories"}}], - "object_data": [{"name": "test object data", "description": "object data description", "policies": [{"name": "test policy"}], "category": {"name": "test object categories"}}], - "action_data": [{"name": "test action data", "description": "action data description", "policies": [{"name": "test policy"}], "category": {"name": "test action categories"}}], - "meta_rules": [{"name": "meta rule", "description": "valid meta rule", "subject_categories": [{"name": "test subject categories"}], "object_categories": [{"name": "test object categories"}], "action_categories": [{"name": "test action categories"}]}], - "subjects": [{"name": "testuser", "description": "description of the subject", "extra": {"field_extra_subject": "value extra subject"}, "policies": [{"name": "test policy"}]}], - "objects": [{"name": "test object e1", "description": "description of the object", "extra": {"field_extra_object": "value extra object"}, "policies": [{"name": "test policy"}]}], - "actions": [{"name": "test action e1", "description": "description of the action", "extra": {"field_extra_action": "value extra action"}, "policies": [{"name": "test policy"}]}], - "subject_assignments": [{"subject": {"name": "testuser"}, "category": {"name": "test subject categories"}, "assignments": [{"name": "test subject data"}]}], - "object_assignments": [{"object": {"name": "test object e1"}, "category": {"name": "test object categories"}, "assignments": [{"name": "test object data"}]}], - "action_assignments": [{"action": {"name": "test action e1"}, "category": {"name": "test action categories"}, "assignments": [{"name": "test action data"}]}], - "rules": [{"meta_rule": {"name": "meta rule"}, "rule": {"subject_data": [{"name": "test subject data"}], "object_data": [{"name": "test object data"}], "action_data": [{"name": "test action data"}]}, "policy": {"name":"test policy"}, "instructions": {"decision": "grant"}, "enabled": True}] - } - - -def test_export_models(): - client = utilities.register_client() - import_export_utilities.clean_all(client) - req = client.post("/import", content_type='application/json', data=json.dumps(MODEL_WITHOUT_META_RULES)) - data = utilities.get_json(req.data) - assert data == "Import ok !" - - req = client.get("/export") - assert req.status_code == 200 - data = utilities.get_json(req.data) - - assert "content" in data - assert "models" in data["content"] - assert isinstance(data["content"]["models"], list) - assert len(data["content"]["models"]) == 1 - model = data["content"]["models"][0] - assert model["name"] == "test model" - assert model["description"] == "model description" - assert isinstance(model["meta_rules"], list) - assert len(model["meta_rules"]) == 0 - - -def test_export_policies(): - client = utilities.register_client() - import_export_utilities.clean_all(client) - req = client.post("/import", content_type='application/json', data=json.dumps(POLICIES)) - data = utilities.get_json(req.data) - assert data == "Import ok !" - - req = client.get("/export") - assert req.status_code == 200 - data = utilities.get_json(req.data) - - assert "content" in data - assert "policies" in data["content"] - assert isinstance(data["content"]["policies"], list) - assert len(data["content"]["policies"]) == 1 - policy = data["content"]["policies"][0] - assert policy["name"] == "test policy" - assert policy["genre"] == "authz" - assert policy["description"] == "policy description" - assert "model" in policy - assert "name" in policy["model"] - model = policy["model"] - assert model["name"] == "test model" - - -def test_export_subject_object_action(): - client = utilities.register_client() - import_export_utilities.clean_all(client) - req = client.post("/import", content_type='application/json', data=json.dumps(SUBJECTS_OBJECTS_ACTIONS)) - data = utilities.get_json(req.data) - assert data == "Import ok !" - - req = client.get("/export") - assert req.status_code == 200 - data = utilities.get_json(req.data) - - assert "content" in data - type_elements = ["subject", "object", "action"] - for type_element in type_elements: - key = type_element + "s" - assert key in data["content"] - assert isinstance(data["content"][key], list) - assert len(data["content"][key]) == 1 - element = data["content"][key][0] - if type_element == "subject": - assert element["name"] == "testuser" - else: - assert element["name"] == "test "+ type_element - assert element["description"] == "description of the " + type_element - assert "policies" in element - assert isinstance(element["policies"], list) - assert len(element["policies"]) == 1 - assert isinstance(element["policies"][0], dict) - assert element["policies"][0]["name"] == "test policy" - assert isinstance(element["extra"], dict) - key_dict = "field_extra_" + type_element - value_dict = "value extra " + type_element - assert key_dict in element["extra"] - assert element["extra"][key_dict] == value_dict - - -def test_export_subject_object_action_categories(): - client = utilities.register_client() - import_export_utilities.clean_all(client) - req = client.post("/import", content_type='application/json', data=json.dumps(SUBJECT_OBJECT_ACTION_CATEGORIES)) - data = utilities.get_json(req.data) - assert data == "Import ok !" - - req = client.get("/export") - assert req.status_code == 200 - data = utilities.get_json(req.data) - assert "content" in data - type_elements = ["subject", "object", "action"] - for type_element in type_elements: - key = type_element + "_categories" - assert key in data["content"] - assert isinstance(data["content"][key], list) - assert len(data["content"][key]) == 1 - category = data["content"][key][0] - assert category["name"] == "test " + type_element + " categories" - assert category["description"] == type_element + " category description" - - -def test_export_subject_object_action_data(): - client = utilities.register_client() - import_export_utilities.clean_all(client) - req = client.post("/import", content_type='application/json', data=json.dumps(SUBJECT_OBJECT_ACTION_DATA)) - data = utilities.get_json(req.data) - assert data == "Import ok !" - - req = client.get("/export") - assert req.status_code == 200 - data = utilities.get_json(req.data) - assert "content" in data - type_elements = ["subject", "object", "action"] - for type_element in type_elements: - key = type_element + "_data" - assert key in data["content"] - assert isinstance(data["content"][key], list) - assert len(data["content"][key]) == 1 - data_elt = data["content"][key][0] - assert data_elt["name"] == "test " + type_element + " data" - assert data_elt["description"] == type_element + " data description" - assert isinstance(data_elt["policy"], dict) - assert data_elt["policy"]["name"] == "test policy" - assert isinstance(data_elt["category"], dict) - assert data_elt["category"]["name"] == "test " + type_element + " categories" - - -def test_export_assignments(): - client = utilities.register_client() - import_export_utilities.clean_all(client) - req = client.post("/import", content_type='application/json', data=json.dumps(ASSIGNMENTS)) - data = utilities.get_json(req.data) - assert data == "Import ok !" - - req = client.get("/export") - assert req.status_code == 200 - data = utilities.get_json(req.data) - assert "content" in data - type_elements = ["subject", "object", "action"] - for type_element in type_elements: - key = type_element + "_assignments" - assert key in data["content"] - assert isinstance(data["content"][key], list) - assert len(data["content"][key]) == 1 - assignment_elt = data["content"][key][0] - assert type_element in assignment_elt - assert isinstance(assignment_elt[type_element], dict) - if type_element == "subject": - assert assignment_elt[type_element]["name"] == "testuser" - else: - assert assignment_elt[type_element]["name"] == "test " + type_element + " e0" - assert "category" in assignment_elt - assert isinstance(assignment_elt["category"], dict) - assert assignment_elt["category"]["name"] == "test " + type_element + " categories" - assert "assignments" in assignment_elt - assert isinstance(assignment_elt["assignments"], list) - assert len(assignment_elt["assignments"]) == 1 - assert assignment_elt["assignments"][0]["name"] == "test " + type_element + " data" - - import_export_utilities.clean_all(client) - - -def test_export_rules(): - client = utilities.register_client() - import_export_utilities.clean_all(client) - req = client.post("/import", content_type='application/json', data=json.dumps(RULES)) - data = utilities.get_json(req.data) - assert data == "Import ok !" - - req = client.get("/export") - assert req.status_code == 200 - data = utilities.get_json(req.data) - assert "content" in data - assert "rules" in data["content"] - assert isinstance(data["content"]["rules"], list) - assert len(data["content"]["rules"]) == 1 - rule = data["content"]["rules"][0] - assert "instructions" in rule - assert "decision" in rule["instructions"] - assert rule["instructions"]["decision"] == "grant" - assert "enabled" in rule - assert rule["enabled"] - assert "meta_rule" in rule - assert rule["meta_rule"]["name"] == "meta rule" - assert "policy" in rule - assert rule["policy"]["name"] == "test policy" - assert "rule" in rule - rule = rule["rule"] - assert "subject_data" in rule - assert isinstance(rule["subject_data"], list) - assert len(rule["subject_data"]) == 1 - assert rule["subject_data"][0]["name"] == "test subject data" - assert "object_data" in rule - assert isinstance(rule["object_data"], list) - assert len(rule["object_data"]) == 1 - assert rule["object_data"][0]["name"] == "test object data" - assert "action_data" in rule - assert isinstance(rule["action_data"], list) - assert len(rule["action_data"]) == 1 - assert rule["action_data"][0]["name"] == "test action data" diff --git a/moon_manager/tests/unit_python/api/test_import.py b/moon_manager/tests/unit_python/api/test_import.py deleted file mode 100644 index af5f753a..00000000 --- a/moon_manager/tests/unit_python/api/test_import.py +++ /dev/null @@ -1,510 +0,0 @@ -# Copyright 2018 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 api.utilities as utilities -import api.test_unit_models as test_models -import api.test_policies as test_policies -import api.test_meta_data as test_categories -import api.test_data as test_data -import api.test_meta_rules as test_meta_rules -import api.test_assignement as test_assignments -import api.test_rules as test_rules -import api.import_export_utilities as import_export_utilities - -import json - - -MODEL_WITHOUT_META_RULES = [ - {"models": [{"name": "test model", "description": "", "meta_rules": []}]}, - {"models": [{"name": "test model", "description": "new description", "meta_rules": [], "override": True}]}, - {"models": [{"name": "test model", "description": "description not taken into account", "meta_rules": [], "override": False}]} - ] - -POLICIES = [ - {"policies": [{"name": "test policy", "genre": "authz", "description": "description", "model": {}, "mandatory": False}]}, - {"policies": [{"name": "test policy", "genre": "authz", "description": "new description not taken into account", "model": {"name" : "test model"}, "mandatory": True}]}, - {"policies": [{"name": "test policy", "genre": "not authz ?", "description": "generates an exception", "model": {"name" : "test model"}, "override": True}]}, - {"models": [{"name": "test model", "description": "", "meta_rules": []}], "policies": [{"name": "test policy", "genre": "not authz ?", "description": "changes taken into account", "model": {"name" : "test model"}, "override": True}]}, -] - -SUBJECTS = [{"subjects": [{"name": "testuser", "description": "description of the subject", "extra": {}, "policies": []}]}, - {"policies": [{"name": "test policy", "genre": "authz", "description": "description", "model": {}, "mandatory": False}], "subjects": [{"name": "testuser", "description": "description of the subject", "extra": {}, "policies": []}]}, - {"policies": [{"name": "test other policy", "genre": "authz", "description": "description", "model": {}, "mandatory": True}], "subjects": [{"name": "testuser", "description": "description of the subject", "extra": {}, "policies": []}]}, - {"subjects": [{"name": "testuser", "description": "new description of the subject", "extra": {"email": "new-email@test.com"}, "policies": [{"name": "test other policy"}]}]}, - {"policies": [{"name": "test policy", "genre": "authz", "description": "description", "model": {}, "mandatory": False}], "subjects": [{"name": "testuser", "description": "description of the subject", "extra": {}, "policies": [{"name": "test policy"}]}]}] - - -OBJECTS = [ - {"objects": [{"name": "test object", "description": "description of the object", "extra": {}, "policies": []}]}, - {"policies": [{"name": "test policy", "genre": "authz", "description": "description", "model": {}, "mandatory": False}], - "objects": [{"name": "test object", "description": "description of the object", "extra": {}, "policies": []}]}, - {"policies": [{"name": "test other policy", "genre": "authz", "description": "description", "model": {}, "mandatory": True}], - "objects": [{"name": "test object", "description": "description of the object", "extra": {}, "policies": []}]}, - {"objects": [{"name": "test object", "description": "new description of the object", - "extra": {"test": "test extra"}, - "policies": [{"name": "test other policy"}]}]}, - {"policies": [{"name": "test policy", "genre": "authz", "description": "description", "model": {}, "mandatory": False}], - "objects": [{"name": "test object", "description": "description of the object", "extra": {}, "policies": [{"name": "test policy"}]}]}, -] - - -ACTIONS = [{"actions": [{"name": "test action", "description": "description of the action", "extra": {}, "policies": []}]}, - {"policies": [{"name": "test policy", "genre": "authz", "description": "description", "model": {}, "mandatory": False}], "actions": [{"name": "test action", "description": "description of the action", "extra": {}, "policies": []}]}, - {"policies": [{"name": "test other policy", "genre": "authz", "description": "description", "model": {}, "mandatory": True}], "actions": [{"name": "test action", "description": "description of the action", "extra": {}, "policies": []}]}, - {"actions": [{"name": "test action", "description": "new description of the action", "extra": {"test": "test extra"}, "policies": [{"name": "test other policy"}]}]}, - {"policies": [{"name": "test policy", "genre": "authz", "description": "description", "model": {}, "mandatory": False}], "actions": [{"name": "test action", "description": "description of the action", "extra": {}, "policies": [{"name": "test policy"}]}]}] - - -SUBJECT_CATEGORIES = [{"subject_categories": [{"name": "test subject categories", "description": "subject category description"}]}, - {"subject_categories": [{"name": "test subject categories", "description": "new subject category description"}]}] - - -OBJECT_CATEGORIES = [{"object_categories": [{"name": "test object categories", "description": "object category description"}]}, - {"object_categories": [{"name": "test object categories", "description": "new object category description"}]}] - - -ACTION_CATEGORIES = [{"action_categories": [{"name": "test action categories", "description": "action category description"}]}, - {"action_categories": [{"name": "test action categories", "description": "new action category description"}]}] - -# meta_rules import is needed otherwise the search for data do not work !!! -PRE_DATA = {"models": [{"name": "test model", "description": "", "meta_rules": [{"name": "good meta rule"}, {"name": "other good meta rule"}]}], - "policies": [{"name": "test other policy", "genre": "authz", "description": "description", "model": {"name": "test model"}, "mandatory": True}], - "subject_categories": [{"name": "test subject categories", "description": "subject category description"}, {"name": "other test subject categories", "description": "subject category description"}], - "object_categories": [{"name": "test object categories", "description": "object category description"}, {"name": "other test object categories", "description": "object category description"}], - "action_categories": [{"name": "test action categories", "description": "action category description"}, {"name": "other test action categories", "description": "action category description"}], - "meta_rules": [{"name": "good meta rule", "description": "valid meta rule", "subject_categories": [{"name": "test subject categories"}], "object_categories": [{"name": "test object categories"}], "action_categories": [{"name": "test action categories"}]}, - {"name": "other good meta rule", "description": "valid meta rule", "subject_categories": [{"name": "other test subject categories"}], "object_categories": [{"name": "other test object categories"}], "action_categories": [{"name": "other test action categories"}]}]} - -SUBJECT_DATA = [{"subject_data": [{"name": "not valid subject data", "description": "", "policies": [{}], "category": {}}]}, - {"subject_data": [{"name": "not valid subject data", "description": "", "policies": [{}], "category": {"name": "test subject categories"}}]}, - {"policies": [{"name": "test policy", "genre": "authz", "description": "description", "model": {"name": "test model"}, "mandatory": True}], "subject_data": [{"name": "one valid subject data", "description": "description", "policies": [{}], "category": {"name": "test subject categories"}}]}, - {"subject_data": [{"name": "valid subject data", "description": "description", "policies": [{"name": "test policy"}], "category": {"name": "test subject categories"}}]}, - {"subject_data": [{"name": "valid subject data", "description": "new description", "policies": [{"name": "test other policy"}], "category": {"name": "test subject categories"}}]}] - -OBJECT_DATA = [{"object_data": [{"name": "not valid object data", "description": "", "policies": [{}], "category": {}}]}, - {"object_data": [{"name": "not valid object data", "description": "", "policies": [{}], "category": {"name": "test object categories"}}]}, - {"policies": [{"name": "test policy", "genre": "authz", "description": "description", "model": {"name": "test model"}, "mandatory": True}], "object_data": [{"name": "one valid object data", "description": "description", "policies": [{}], "category": {"name": "test object categories"}}]}, - {"object_data": [{"name": "valid object data", "description": "description", "policies": [{"name": "test policy"}], "category": {"name": "test object categories"}}]}, - {"object_data": [{"name": "valid object data", "description": "new description", "policies": [{"name": "test other policy"}], "category": {"name": "test object categories"}}]}] - - -ACTION_DATA = [{"action_data": [{"name": "not valid action data", "description": "", "policies": [{}], "category": {}}]}, - {"action_data": [{"name": "not valid action data", "description": "", "policies": [{}], "category": {"name": "test action categories"}}]}, - {"policies": [{"name": "test policy", "genre": "authz", "description": "description", "model": {"name": "test model"}, "mandatory": True}], "action_data": [{"name": "one valid action data", "description": "description", "policies": [{}], "category": {"name": "test action categories"}}]}, - {"action_data": [{"name": "valid action data", "description": "description", "policies": [{"name": "test policy"}], "category": {"name": "test action categories"}}]}, - {"action_data": [{"name": "valid action data", "description": "new description", "policies": [{"name": "test other policy"}], "category": {"name": "test action categories"}}]}] - - -PRE_META_RULES = {"subject_categories": [{"name": "test subject categories", "description": "subject category description"}], - "object_categories": [{"name": "test object categories", "description": "object category description"}], - "action_categories": [{"name": "test action categories", "description": "object action description"}]} - -META_RULES = [{"meta_rules" :[{"name": "bad meta rule", "description": "not valid meta rule", "subject_categories": [{"name": "not valid category"}], "object_categories": [{"name": "test object categories"}], "action_categories": [{"name": "test action categories"}]}]}, - {"meta_rules": [{"name": "bad meta rule", "description": "not valid meta rule", "subject_categories": [{"name": "test subject categories"}], "object_categories": [{"name": "not valid category"}], "action_categories": [{"name": "test action categories"}]}]}, - {"meta_rules": [{"name": "bad meta rule", "description": "not valid meta rule", "subject_categories": [{"name": "test subject categories"}], "object_categories": [{"name": "test object categories"}], "action_categories": [{"name": "not valid category"}]}]}, - {"meta_rules": [{"name": "good meta rule", "description": "valid meta rule", "subject_categories": [{"name": "test subject categories"}], "object_categories": [{"name": "test object categories"}], "action_categories": [{"name": "test action categories"}]}]}] - - -PRE_ASSIGNMENTS = {"models": [{"name": "test model", "description": "", "meta_rules": [{"name": "good meta rule"}]}], - "policies": [{"name": "test policy", "genre": "authz", "description": "description", "model": {"name" : "test model"}, "mandatory": True}], - "subject_categories": [{"name": "test subject categories", "description": "subject category description"}], - "object_categories": [{"name": "test object categories", "description": "object category description"}], - "action_categories": [{"name": "test action categories", "description": "object action description"}], - "subjects": [{"name": "testuser", "description": "description of the subject", "extra": {}, "policies": [{"name": "test policy"}]}], - "objects": [{"name": "test object", "description": "description of the object", "extra": {}, "policies": [{"name": "test policy"}]}], - "actions": [{"name": "test action", "description": "description of the action", "extra": {}, "policies": [{"name": "test policy"}]}], - "meta_rules": [{"name": "good meta rule", "description": "valid meta rule", "subject_categories": [{"name": "test subject categories"}], "object_categories": [{"name": "test object categories"}], "action_categories": [{"name": "test action categories"}]}], - "subject_data": [{"name": "subject data", "description": "test subject data", "policies": [{"name": "test policy"}], "category": {"name": "test subject categories"}}], - "object_data": [{"name": "object data", "description": "test object data", "policies": [{"name": "test policy"}], "category": {"name": "test object categories"}}], - "action_data": [{"name": "action data", "description": "test action data", "policies": [{"name": "test policy"}], "category": {"name": "test action categories"}}]} - - -SUBJECT_ASSIGNMENTS = [{"subject_assignments": [{"subject": {"name": "unknonw"}, "category" : {"name": "test subject categories"}, "assignments": [{"name": "subject data"}]}]}, - {"subject_assignments": [{"subject": {"name": "testuser"}, "category": {"name": "unknown"}, "assignments": [{"name": "subject data"}]}]}, - {"subject_assignments": [{"subject": {"name": "testuser"}, "category" : {"name": "test subject categories"}, "assignments": [{"name": "unknwon"}]}]}, - {"subject_assignments": [{"subject": {"name": "testuser"}, "category": {"name": "test subject categories"}, "assignments": [{"name": "subject data"}]}]}] - -OBJECT_ASSIGNMENTS = [{"object_assignments": [{"object": {"name": "unknown"}, "category" : {"name": "test object categories"}, "assignments": [{"name": "object data"}]}]}, - {"object_assignments": [{"object": {"name": "test object"}, "category" : {"name": "unknown"}, "assignments": [{"name": "object data"}]}]}, - {"object_assignments": [{"object": {"name": "test object"}, "category" : {"name": "test object categories"}, "assignments": [{"name": "unknown"}]}]}, - {"object_assignments": [{"object": {"name": "test object"}, "category" : {"name": "test object categories"}, "assignments": [{"name": "object data"}]}]}] - -ACTION_ASSIGNMENTS = [{"action_assignments": [{"action": {"name": "unknown"}, "category" : {"name": "test action categories"}, "assignments": [{"name": "action data"}]}]}, - {"action_assignments": [{"action": {"name": "test action"}, "category" : {"name": "unknown"}, "assignments": [{"name": "action data"}]}]}, - {"action_assignments": [{"action": {"name": "test action"}, "category" : {"name": "test action categories"}, "assignments": [{"name": "unknown"}]}]}, - {"action_assignments": [{"action": {"name": "test action"}, "category" : {"name": "test action categories"}, "assignments": [{"name": "action data"}]}]}] - -RULES = [{"rules": [{"meta_rule": {"name": "unknown meta rule"}, "policy": {"name": "test policy"}, "instructions": {"decision": "grant"}, "enabled": True, "rule": {"subject_data": [{"name": "subject data"}], "object_data": [{"name": "object data"}], "action_data": [{"name": "action data"}]}}]}, - {"rules": [{"meta_rule": {"name": "good meta rule"}, "policy": {"name": "unknown policy"}, "instructions": {"decision": "grant"}, "enabled": True, "rule": {"subject_data": [{"name": "subject data"}], "object_data": [{"name": "object data"}], "action_data": [{"name": "action data"}]}}]}, - {"rules": [{"meta_rule": {"name": "good meta rule"}, "policy": {"name": "test policy"}, "instructions": {"decision": "grant"}, "enabled": True, "rule": {"subject_data": [{"name": "unknown subject data"}], "object_data": [{"name": "object data"}], "action_data": [{"name": "action data"}]}}]}, - {"rules": [{"meta_rule": {"name": "good meta rule"}, "policy": {"name": "test policy"}, "instructions": {"decision": "grant"}, "enabled": True, "rule": {"subject_data": [{"name": "subject data"}], "object_data": [{"name": "unknown object data"}], "action_data": [{"name": "action data"}]}}]}, - {"rules": [{"meta_rule": {"name": "good meta rule"}, "policy": {"name": "test policy"}, "instructions": {"decision": "grant"}, "enabled": True, "rule": {"subject_data": [{"name": "subject data"}], "object_data": [{"name": "object data"}], "action_data": [{"name": "unknown action data"}]}}]}, - {"rules": [{"meta_rule": {"name": "good meta rule"}, "policy": {"name": "test policy"}, "instructions": {"decision": "grant"}, "enabled": True, "rule": {"subject_data": [{"name": "subject data"}], "object_data": [{"name": "object data"}], "action_data": [{"name": "action data"}]}}]}] - - -def test_import_models_without_new_meta_rules(): - client = utilities.register_client() - import_export_utilities.clean_all(client) - counter = 0 - for models_description in MODEL_WITHOUT_META_RULES: - req = client.post("/import", content_type='application/json', data=json.dumps(models_description)) - data = utilities.get_json(req.data) - assert data == "Import ok !" - req, models = test_models.get_models(client) - models = models["models"] - assert len(list(models.keys())) == 1 - values = list(models.values()) - assert values[0]["name"] == "test model" - if counter == 0: - assert len(values[0]["description"]) == 0 - if counter == 1 or counter == 2: - assert values[0]["description"] == "new description" - counter = counter + 1 - import_export_utilities.clean_all(client) - - -def test_import_policies(): - client = utilities.register_client() - import_export_utilities.clean_all(client) - counter = -1 - for policy_description in POLICIES: - counter = counter + 1 - req = client.post("/import", content_type='application/json', data=json.dumps(policy_description)) - try: - data = utilities.get_json(req.data) - assert data == "Import ok !" - except Exception: - assert counter == 2 # this is an expected failure - continue - - req, policies = test_policies.get_policies(client) - policies = policies["policies"] - assert len(list(policies.keys())) == 1 - values = list(policies.values()) - assert values[0]["name"] == "test policy" - if counter < 3: - assert values[0]["genre"] == "authz" - assert values[0]["description"] == "description" - else: - assert values[0]["genre"] == "not authz ?" - assert values[0]["description"] == "changes taken into account" - assert len(values[0]["model_id"]) > 0 - import_export_utilities.clean_all(client) - - -def test_import_subject_object_action(): - client = utilities.register_client() - type_elements = ["object", "action"] - - for type_element in type_elements: - import_export_utilities.clean_all(client) - counter = -1 - # set the getters and the comparison values - if type_element == "subject": - elements = SUBJECTS - clean_method = import_export_utilities.clean_subjects - name = "testuser" - key_extra = "email" - value_extra = "new-email@test.com" - elif type_element == "object": - elements = OBJECTS - clean_method = import_export_utilities.clean_objects - name = "test object" - key_extra = "test" - value_extra = "test extra" - else: - elements = ACTIONS - clean_method = import_export_utilities.clean_actions - name = "test action" - key_extra = "test" - value_extra = "test extra" - - for element in elements: - counter = counter + 1 - if counter == 2 or counter == 4: - clean_method(client) - - - if counter == 3: - req = client.patch("/{}s/{}".format(type_element,perimeter_id), content_type='application/json', - data=json.dumps( - element["{}s".format(type_element)][0])) - else : - req = client.post("/import", content_type='application/json', - data=json.dumps(element)) - if counter < 2: - assert req.status_code == 500 - continue - - try: - data = utilities.get_json(req.data) - except Exception as e: - assert False - #assert counter < 2 #  this is an expected failure - #continue - - if counter != 3: - assert data == "Import ok !" - get_elements = utilities.get_json(client.get("/"+type_element + "s").data) - get_elements = get_elements[type_element + "s"] - - perimeter_id = list(get_elements.keys())[0] - - assert len(list(get_elements.keys())) == 1 - values = list(get_elements.values()) - assert values[0]["name"] == name - if counter == 2 or counter == 4: - assert values[0]["description"] == "description of the " + type_element - #assert not values[0]["extra"] - if counter == 3: - assert values[0]["description"] == "new description of the " + type_element - assert values[0]["extra"][key_extra] == value_extra - - # assert len(values[0]["policy_list"]) == 1 - import_export_utilities.clean_all(client) - - -def test_import_subject_object_action_categories(): - client = utilities.register_client() - type_elements = ["subject", "object", "action"] - - for type_element in type_elements: - import_export_utilities.clean_all(client) - counter = -1 - # set the getters and the comparison values - if type_element == "subject": - elements = SUBJECT_CATEGORIES - get_method = test_categories.get_subject_categories - elif type_element == "object": - elements = OBJECT_CATEGORIES - get_method = test_categories.get_object_categories - else: - elements = ACTION_CATEGORIES - get_method = test_categories.get_action_categories - - for element in elements: - req = client.post("/import", content_type='application/json', data=json.dumps(element)) - counter = counter + 1 - data = utilities.get_json(req.data) - assert data == "Import ok !" - req, get_elements = get_method(client) - get_elements = get_elements[type_element + "_categories"] - assert len(list(get_elements.keys())) == 1 - values = list(get_elements.values()) - assert values[0]["name"] == "test " + type_element + " categories" - assert values[0]["description"] == type_element + " category description" - - -def test_import_meta_rules(): - client = utilities.register_client() - import_export_utilities.clean_all(client) - # import some categories - req = client.post("/import", content_type='application/json', data=json.dumps(PRE_META_RULES)) - data = utilities.get_json(req.data) - assert data == "Import ok !" - - counter = -1 - for meta_rule in META_RULES: - counter = counter + 1 - req = client.post("/import", content_type='application/json', data=json.dumps(meta_rule)) - if counter != 3: - assert req.status_code == 500 - continue - else: - data = utilities.get_json(req.data) - assert data == "Import ok !" - assert req.status_code == 200 - - req, meta_rules = test_meta_rules.get_meta_rules(client) - meta_rules = meta_rules["meta_rules"] - key = list(meta_rules.keys())[0] - assert isinstance(meta_rules,dict) - assert meta_rules[key]["name"] == "good meta rule" - assert meta_rules[key]["description"] == "valid meta rule" - assert len(meta_rules[key]["subject_categories"]) == 1 - assert len(meta_rules[key]["object_categories"]) == 1 - assert len(meta_rules[key]["action_categories"]) == 1 - - subject_category_key = meta_rules[key]["subject_categories"][0] - object_category_key = meta_rules[key]["object_categories"][0] - action_category_key = meta_rules[key]["action_categories"][0] - - req, sub_cat = test_categories.get_subject_categories(client) - sub_cat = sub_cat["subject_categories"] - assert sub_cat[subject_category_key]["name"] == "test subject categories" - - req, ob_cat = test_categories.get_object_categories(client) - ob_cat = ob_cat["object_categories"] - assert ob_cat[object_category_key]["name"] == "test object categories" - - req, ac_cat = test_categories.get_action_categories(client) - ac_cat = ac_cat["action_categories"] - assert ac_cat[action_category_key]["name"] == "test action categories" - - import_export_utilities.clean_all(client) - - -def test_import_subject_object_action_assignments(): - client = utilities.register_client() - import_export_utilities.clean_all(client) - - req = client.post("/import", content_type='application/json', data=json.dumps(PRE_ASSIGNMENTS)) - data = utilities.get_json(req.data) - assert data == "Import ok !" - - type_elements = ["subject", "object", "action"] - - for type_element in type_elements: - counter = -1 - if type_element == "subject": - datas = SUBJECT_ASSIGNMENTS - get_method = test_assignments.get_subject_assignment - elif type_element == "object": - datas = OBJECT_ASSIGNMENTS - get_method = test_assignments.get_object_assignment - else: - datas = ACTION_ASSIGNMENTS - get_method = test_assignments.get_action_assignment - - for assignments in datas: - counter = counter + 1 - req = client.post("/import", content_type='application/json', data=json.dumps(assignments)) - if counter != 3: - assert req.status_code == 500 - continue - else: - assert data == "Import ok !" - assert req.status_code == 200 - req, policies = test_policies.get_policies(client) - for policy_key in policies["policies"]: - req, get_assignments = get_method(client, policy_key) - get_assignments = get_assignments[type_element+"_assignments"] - assert len(get_assignments) == 1 - - -def test_import_rules(): - client = utilities.register_client() - import_export_utilities.clean_all(client) - req = client.post("/import", content_type='application/json', data=json.dumps(PRE_ASSIGNMENTS)) - data = utilities.get_json(req.data) - assert data == "Import ok !" - - counter = -1 - for rule in RULES: - counter = counter + 1 - req = client.post("/import", content_type='application/json', data=json.dumps(rule)) - - if counter < 5: - assert req.status_code == 500 - continue - - assert req.status_code == 200 - - req, rules = test_rules.test_get_rules() - rules = rules["rules"] - rules = rules["rules"] - assert len(rules) == 1 - rules = rules[0] - assert rules["enabled"] - assert rules["instructions"]["decision"] == "grant" - - req, meta_rules = test_meta_rules.get_meta_rules(client) - assert meta_rules["meta_rules"][list(meta_rules["meta_rules"].keys())[0]]["name"] == "good meta rule" - - -def test_import_subject_object_action_data(): - client = utilities.register_client() - type_elements = ["subject", "object", "action"] - - for type_element in type_elements: - import_export_utilities.clean_all(client) - req = client.post("/import", content_type='application/json', data=json.dumps(PRE_DATA)) - counter = -1 - # set the getters and the comparison values - if type_element == "subject": - elements = SUBJECT_DATA - get_method = test_data.get_subject_data - get_categories = test_categories.get_subject_categories - elif type_element == "object": - elements = OBJECT_DATA - get_method = test_data.get_object_data - get_categories = test_categories.get_object_categories - else: - elements = ACTION_DATA - get_method = test_data.get_action_data - get_categories = test_categories.get_action_categories - - for element in elements: - req = client.post("/import", content_type='application/json', data=json.dumps(element)) - counter = counter + 1 - if counter == 0 or counter == 1: - assert req.status_code == 500 - continue - assert req.status_code == 200 - data = utilities.get_json(req.data) - assert data == "Import ok !" - - req, policies = test_policies.get_policies(client) - policies = policies["policies"] - req, categories = get_categories(client) - categories = categories[type_element + "_categories"] - case_tested = False - for policy_key in policies.keys(): - policy = policies[policy_key] - for category_key in categories: - req, get_elements = get_method(client, policy_id=policy_key, category_id=category_key) - if len(get_elements[type_element+"_data"]) == 0: - continue - - # do this because the backend gives an element with empty data if the policy_key, - # category_key couple does not have any data... - get_elements = get_elements[type_element+"_data"] - if len(get_elements[0]["data"]) == 0: - continue - - if policy["name"] == "test policy": - assert len(get_elements) == 1 - el = get_elements[0] - assert isinstance(el["data"], dict) - if counter == 2: - assert len(el["data"].keys()) == 1 - el = el["data"][list(el["data"].keys())[0]] - if "value" in el: - el = el["value"] - assert el["name"] == "one valid " + type_element + " data" - if counter == 3: - assert len(el["data"].keys()) == 2 - el1 = el["data"][list(el["data"].keys())[0]] - el2 = el["data"][list(el["data"].keys())[1]] - if "value" in el1: - el1 = el1["value"] - el2 = el2["value"] - assert (el1["name"] == "one valid " + type_element + " data" and el2["name"] == "valid " + type_element + " data") or (el2["name"] == "one valid " + type_element + " data" and el1["name"] == "valid " + type_element + " data") - assert el1["description"] == "description" - assert el2["description"] == "description" - - case_tested = True - - if policy["name"] == "test other policy": - if counter == 4: - assert len(get_elements) == 1 - el = get_elements[0] - assert isinstance(el["data"], dict) - assert len(el["data"].keys()) == 1 - el = el["data"][list(el["data"].keys())[0]] - if "value" in el: - el = el["value"] - assert el["name"] == "valid " + type_element + " data" - assert el["description"] == "new description" - case_tested = True - - assert case_tested is True - - -def test_clean(): - client = utilities.register_client() - import_export_utilities.clean_all(client) - #restore the database as previously - utilities.get_policy_id() diff --git a/moon_manager/tests/unit_python/api/test_json_export.py b/moon_manager/tests/unit_python/api/test_json_export.py new file mode 100644 index 00000000..8de394c9 --- /dev/null +++ b/moon_manager/tests/unit_python/api/test_json_export.py @@ -0,0 +1,321 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +import json +import api.utilities as utilities +import helpers.import_export_helper as import_export_helper +import hug + +MODEL_WITHOUT_META_RULES = {"models": [{"name": "test model", "description": "model description", "meta_rules": []}]} + +DATA = {"subject_data": [{"name": "test subject data", "description": "subject data description", "policies": [{"name": "test policy"}], "category": {"name": "test subject categories"}}], + "object_data": [{"name": "test object data", "description": "object data description", "policies": [{"name": "test policy"}], "category": {"name": "test object categories"}}], + "action_data": [{"name": "test action data", "description": "action data description", "policies": [{"name": "test policy"}], "category": {"name": "test action categories"}}] + } + +META_RULES = {"subject_categories": [{"name": "test subject categories", "description": "subject category description"}], + "object_categories": [{"name": "test object categories", "description": "object category description"}], + "action_categories": [{"name": "test action categories", "description": "action action description"}], + "meta_rules": [{"name": "meta rule", "description": "valid meta rule", "subject_categories": [{"name": "test subject categories"}], "object_categories": [{"name": "test object categories"}], "action_categories": [{"name": "test action categories"}]}]} + + +SUBJECTS_OBJECTS_ACTIONS = {"models": [{"name": "test model", "description": "", "meta_rules": [{"name":"meta rule"}]}], + "policies": [{"name": "test policy", "genre": "authz", "description": "policy description", "model": {"name" : "test model"}}], + "subjects": [{"name": "testuser", "description": "description of the subject", "extra": {"field_extra_subject": "value extra subject"}, "policies": [{"name": "test policy"}]}], + "objects": [{"name": "test object", "description": "description of the object", "extra": {"field_extra_object": "value extra object"}, "policies": [{"name": "test policy"}]}], + "actions": [{"name": "test action", "description": "description of the action", "extra": {"field_extra_action": "value extra action"}, "policies": [{"name": "test policy"}]}], + **META_RULES + } + +SUBJECT_OBJECT_ACTION_CATEGORIES = {"subject_categories": [{"name": "test subject categories", "description": "subject category description"}], + "object_categories": [{"name": "test object categories", "description": "object category description"}], + "action_categories": [{"name": "test action categories", "description": "action category description"}]} + +SUBJECT_OBJECT_ACTION_DATA = {**SUBJECTS_OBJECTS_ACTIONS, + **DATA + } +POLICIES = {"models": [{"name": "test model", "description": "", "meta_rules": [{"name": "meta rule"}]}], + "policies": [{"name": "test policy", "genre": "authz", "description": "policy description", "model": {"name" : "test model"}}], + **META_RULES, + } + +ASSIGNMENTS = {**POLICIES, + **DATA, + "subjects": [{"name": "testuser", "description": "description of the subject", "extra": {"field_extra_subject": "value extra subject"}, "policies": [{"name": "test policy"}]}], + "objects": [{"name": "test object e0", "description": "description of the object", "extra": {"field_extra_object": "value extra object"}, "policies": [{"name": "test policy"}]}], + "actions": [{"name": "test action e0", "description": "description of the action", "extra": {"field_extra_action": "value extra action"}, "policies": [{"name": "test policy"}]}], + "subject_assignments": [{"subject": {"name": "testuser"}, "category": {"name": "test subject categories"}, "assignments": [{"name": "test subject data"}]}], + "object_assignments": [{"object": {"name": "test object e0"}, "category": {"name": "test object categories"}, "assignments": [{"name": "test object data"}]}], + "action_assignments": [{"action": {"name": "test action e0"}, "category": {"name": "test action categories"}, "assignments": [{"name": "test action data"}]}]} + +RULES = {**POLICIES, + **DATA, + "subjects": [{"name": "testuser", "description": "description of the subject", "extra": {"field_extra_subject": "value extra subject"}, "policies": [{"name": "test policy"}]}], + "objects": [{"name": "test object e1", "description": "description of the object", "extra": {"field_extra_object": "value extra object"}, "policies": [{"name": "test policy"}]}], + "actions": [{"name": "test action e1", "description": "description of the action", "extra": {"field_extra_action": "value extra action"}, "policies": [{"name": "test policy"}]}], + "subject_assignments": [{"subject": {"name": "testuser"}, "category": {"name": "test subject categories"}, "assignments": [{"name": "test subject data"}]}], + "object_assignments": [{"object": {"name": "test object e1"}, "category": {"name": "test object categories"}, "assignments": [{"name": "test object data"}]}], + "action_assignments": [{"action": {"name": "test action e1"}, "category": {"name": "test action categories"}, "assignments": [{"name": "test action data"}]}], + "rules": [{"meta_rule": {"name": "meta rule"}, "rule": {"subject_data": [{"name": "test " + "subject data"}], + "object_data": [{"name": "test object data"}], + "action_data": [{"name": "test action data"}]}, "policy": {"name":"test policy"}, "instructions": [{"decision": "grant"}], "enabled": True}] + } + + +def test_export_models(): + from moon_manager.api import json_import + from moon_manager.api import json_export + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + # import_export_helper.clean_all() + + req = hug.test.post(json_import, "/import", body=json.dumps( + MODEL_WITHOUT_META_RULES), headers={'Content-Type': 'application/json', "X-Api-Key": + get_api_key_for_user("admin")} ) + data = utilities.get_json(req.data) + assert all(e in data for e in MODEL_WITHOUT_META_RULES.keys()) + + req = hug.test.get(json_export, "/export", headers=auth_headers) + assert req.status == hug.HTTP_200 + data = utilities.get_json(req.data) + + assert "content" in data + assert "models" in data["content"] + assert isinstance(data["content"]["models"], list) + assert len(data["content"]["models"]) == 1 + model = data["content"]["models"][0] + assert model["name"] == "test model" + assert model["description"] == "model description" + assert isinstance(model["meta_rules"], list) + assert len(model["meta_rules"]) == 0 + + +def test_export_policies(): + from moon_manager.api import json_import + from moon_manager.api import json_export + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + import_export_helper.clean_all() + req = hug.test.post(json_import, "/import", body=json.dumps( + POLICIES), headers={'Content-Type': 'application/json', "X-Api-Key": + get_api_key_for_user("admin")}) + data = utilities.get_json(req.data) + assert all(e in data for e in POLICIES.keys()) + + req = hug.test.get(json_export, "/export", headers=auth_headers) + assert req.status == hug.HTTP_200 + data = utilities.get_json(req.data) + + assert "content" in data + assert "policies" in data["content"] + assert isinstance(data["content"]["policies"], list) + assert len(data["content"]["policies"]) == 1 + policy = data["content"]["policies"][0] + assert policy["name"] == "test policy" + assert policy["genre"] == "authz" + assert policy["description"] == "policy description" + assert "model" in policy + assert "name" in policy["model"] + model = policy["model"] + assert model["name"] == "test model" + + +def test_export_subject_object_action(): + from moon_manager.api import json_import + from moon_manager.api import json_export + from moon_utilities.auth_functions import get_api_key_for_user + + import_export_helper.clean_all() + req = hug.test.post(json_import, "/import", body=json.dumps( + SUBJECTS_OBJECTS_ACTIONS) ,headers={'Content-Type': 'application/json', "X-Api-Key": + get_api_key_for_user("admin")}) + data = utilities.get_json(req.data) + assert all(e in data for e in SUBJECTS_OBJECTS_ACTIONS.keys()) + + req = hug.test.get(json_export, "/export", headers={'Content-Type': 'application/json', "X-Api-Key": + get_api_key_for_user("admin")}) + assert req.status == hug.HTTP_200 + data = utilities.get_json(req.data) + + assert "content" in data + type_elements = ["subject", "object", "action"] + for type_element in type_elements: + key = type_element + "s" + assert key in data["content"] + assert isinstance(data["content"][key], list) + assert len(data["content"][key]) == 1 + element = data["content"][key][0] + if type_element == "subject": + assert element["name"] == "testuser" + else: + assert element["name"] == "test "+ type_element + assert element["description"] == "description of the " + type_element + assert "policies" in element + assert isinstance(element["policies"], list) + assert len(element["policies"]) == 1 + assert isinstance(element["policies"][0], dict) + assert element["policies"][0]["name"] == "test policy" + assert isinstance(element["extra"], dict) + key_dict = "field_extra_" + type_element + value_dict = "value extra " + type_element + assert key_dict in element["extra"] + assert element["extra"][key_dict] == value_dict + + +def test_export_subject_object_action_categories(): + from moon_manager.api import json_import + from moon_manager.api import json_export + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + import_export_helper.clean_all() + req = hug.test.post(json_import, "/import", body=json.dumps( + SUBJECT_OBJECT_ACTION_CATEGORIES), headers={'Content-Type': 'application/json', "X-Api-Key": + get_api_key_for_user("admin")}) + data = utilities.get_json(req.data) + assert all(e in data for e in SUBJECT_OBJECT_ACTION_CATEGORIES.keys()) + + req = hug.test.get(json_export, "/export", headers=auth_headers) + assert req.status == hug.HTTP_200 + data = utilities.get_json(req.data) + assert "content" in data + type_elements = ["subject", "object", "action"] + for type_element in type_elements: + key = type_element + "_categories" + assert key in data["content"] + assert isinstance(data["content"][key], list) + assert len(data["content"][key]) == 1 + category = data["content"][key][0] + assert category["name"] == "test " + type_element + " categories" + assert category["description"] == type_element + " category description" + + +def test_export_subject_object_action_data(): + from moon_manager.api import json_import + from moon_manager.api import json_export + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + import_export_helper.clean_all() + req = hug.test.post(json_import, "/import", body=json.dumps( + SUBJECT_OBJECT_ACTION_DATA), headers={'Content-Type': 'application/json', "X-Api-Key": + get_api_key_for_user("admin")}) + data = utilities.get_json(req.data) + assert all(e in data for e in SUBJECT_OBJECT_ACTION_DATA.keys()) + + req = hug.test.get(json_export, "/export", headers=auth_headers) + assert req.status == hug.HTTP_200 + data = utilities.get_json(req.data) + assert "content" in data + type_elements = ["subject", "object", "action"] + for type_element in type_elements: + key = type_element + "_data" + assert key in data["content"] + assert isinstance(data["content"][key], list) + assert len(data["content"][key]) == 1 + data_elt = data["content"][key][0] + assert data_elt["name"] == "test " + type_element + " data" + assert data_elt["description"] == type_element + " data description" + assert isinstance(data_elt["policy"], dict) + assert data_elt["policy"]["name"] == "test policy" + assert isinstance(data_elt["category"], dict) + assert data_elt["category"]["name"] == "test " + type_element + " categories" + + +def test_export_assignments(): + from moon_manager.api import json_import + from moon_manager.api import json_export + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + import_export_helper.clean_all() + req = hug.test.post(json_import, "/import", body=json.dumps( + ASSIGNMENTS), headers={'Content-Type': 'application/json', "X-Api-Key": + get_api_key_for_user("admin")}) + data = utilities.get_json(req.data) + assert all(e in data for e in ASSIGNMENTS.keys()) + + req = hug.test.get(json_export, "/export", headers=auth_headers) + assert req.status == hug.HTTP_200 + data = utilities.get_json(req.data) + assert "content" in data + type_elements = ["subject", "object", "action"] + for type_element in type_elements: + key = type_element + "_assignments" + assert key in data["content"] + assert isinstance(data["content"][key], list) + assert len(data["content"][key]) == 1 + assignment_elt = data["content"][key][0] + assert type_element in assignment_elt + assert isinstance(assignment_elt[type_element], dict) + if type_element == "subject": + assert assignment_elt[type_element]["name"] == "testuser" + else: + assert assignment_elt[type_element]["name"] == "test " + type_element + " e0" + assert "category" in assignment_elt + assert isinstance(assignment_elt["category"], dict) + assert assignment_elt["category"]["name"] == "test " + type_element + " categories" + assert "assignments" in assignment_elt + assert isinstance(assignment_elt["assignments"], list) + assert len(assignment_elt["assignments"]) == 1 + assert assignment_elt["assignments"][0]["name"] == "test " + type_element + " data" + + import_export_helper.clean_all() + + +def test_export_rules(): + from moon_manager.api import json_import + from moon_manager.api import json_export + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + import_export_helper.clean_all() + req = hug.test.post(json_import, "/import", body=json.dumps( + RULES), headers={'Content-Type': 'application/json', "X-Api-Key": + get_api_key_for_user("admin")}) + data = utilities.get_json(req.data) + assert all(e in data for e in RULES.keys()) + + req = hug.test.get(json_export, "/export", headers=auth_headers) + assert req.status == hug.HTTP_200 + data = utilities.get_json(req.data) + assert "content" in data + assert "rules" in data["content"] + assert isinstance(data["content"]["rules"], list) + assert len(data["content"]["rules"]) == 1 + rule = data["content"]["rules"][0] + assert "instructions" in rule + assert "decision" in rule["instructions"][0] + assert rule["instructions"][0]["decision"] == "grant" + assert "enabled" in rule + assert rule["enabled"] + assert "meta_rule" in rule + assert rule["meta_rule"]["name"] == "meta rule" + assert "policy" in rule + assert rule["policy"]["name"] == "test policy" + assert "rule" in rule + rule = rule["rule"] + assert "subject_data" in rule + assert isinstance(rule["subject_data"], list) + assert len(rule["subject_data"]) == 1 + assert rule["subject_data"][0]["name"] == "test subject data" + assert "object_data" in rule + assert isinstance(rule["object_data"], list) + assert len(rule["object_data"]) == 1 + assert rule["object_data"][0]["name"] == "test object data" + assert "action_data" in rule + assert isinstance(rule["action_data"], list) + assert len(rule["action_data"]) == 1 + assert rule["action_data"][0]["name"] == "test action data" diff --git a/moon_manager/tests/unit_python/api/test_json_import.py b/moon_manager/tests/unit_python/api/test_json_import.py new file mode 100644 index 00000000..3195eca3 --- /dev/null +++ b/moon_manager/tests/unit_python/api/test_json_import.py @@ -0,0 +1,832 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +import api.test_models as test_models +import api.test_policies as test_policies +import api.test_meta_data as test_categories +import api.test_data as test_data +import api.test_meta_rules as test_meta_rules +import api.test_assignement as test_assignments +import api.test_rules as test_rules +import helpers.import_export_helper as import_export_helper +import helpers.policy_helper as policy_helper +import hug +import json +import pytest +from moon_utilities import exceptions + + +MODEL_WITHOUT_META_RULES = [ + {"models": [{"name": "test model", "description": "", "meta_rules": []}]}, + {"models": [{"name": "test model", "description": "new description", "meta_rules": [], + "override": True}]}, + {"models": [{"name": "test model", "description": "description not taken into account", + "meta_rules": [], "override": False}]} +] + +POLICIES = [ + {"policies": [ + {"name": "test policy", "genre": "authz", "description": "description", "model": {}, + "mandatory": False}]}, + {"policies": [{"name": "test policy", "genre": "authz", + "description": "new description not taken into account", + "model": {"name": "test model"}, "mandatory": True}]}, + {"policies": [ + {"name": "test policy", "genre": "not authz ?", "description": "generates an exception", + "model": {"name": "test model"}, "override": True}]}, + {"models": [{"name": "test model", "description": "", "meta_rules": []}], "policies": [ + {"name": "test policy", "genre": "not authz ?", "description": "changes taken into account", + "model": {"name": "test model"}, "override": True}]}, +] + +SUBJECTS = [{"subjects": [ + {"name": "testuser", "description": "description of the subject", "extra": {}, + "policies": []}]}, + {"policies": [ + {"name": "test policy", "genre": "authz", "description": "description", "model": {}, + "mandatory": False}], "subjects": [ + {"name": "testuser", "description": "description of the subject", "extra": {}, + "policies": []}]}, + {"policies": [ + {"name": "test other policy", "genre": "authz", "description": "description", + "model": {}, "mandatory": True}], "subjects": [ + {"name": "testuser", "description": "description of the subject", "extra": {}, + "policies": []}]}, + {"subjects": [{"name": "testuser", "description": "new description of the subject", + "extra": {"email": "new-email@test.com"}, + "policies": [{"name": "test other policy"}]}]}, + {"policies": [ + {"name": "test policy", "genre": "authz", "description": "description", "model": {}, + "mandatory": False}], "subjects": [ + {"name": "testuser", "description": "description of the subject", "extra": {}, + "policies": [{"name": "test policy"}]}]}] + +OBJECTS = [ + {"objects": [{"name": "test object", "description": "description of the object", "extra": {}, + "policies": []}]}, + {"policies": [ + {"name": "test policy", "genre": "authz", "description": "description", "model": {}, + "mandatory": False}], + "objects": [{"name": "test object", "description": "description of the object", "extra": {}, + "policies": []}]}, + {"policies": [ + {"name": "test other policy", "genre": "authz", "description": "description", "model": {}, + "mandatory": True}], + "objects": [{"name": "test object", "description": "description of the object", "extra": {}, + "policies": []}]}, + {"objects": [{"name": "test object", "description": "new description of the object", + "extra": {"test": "test extra"}, + "policies": [{"name": "test other policy"}]}]}, + {"policies": [ + {"name": "test policy", "genre": "authz", "description": "description", "model": {}, + "mandatory": False}], + "objects": [{"name": "test object", "description": "description of the object", "extra": {}, + "policies": [{"name": "test policy"}]}]}, +] + +ACTIONS = [{"actions": [ + {"name": "test action", "description": "description of the action", "extra": {}, + "policies": []}]}, + {"policies": [ + {"name": "test policy", "genre": "authz", "description": "description", "model": {}, + "mandatory": False}], "actions": [ + {"name": "test action", "description": "description of the action", "extra": {}, + "policies": []}]}, + {"policies": [ + {"name": "test other policy", "genre": "authz", "description": "description", + "model": {}, "mandatory": True}], "actions": [ + {"name": "test action", "description": "description of the action", "extra": {}, + "policies": []}]}, + {"actions": [{"name": "test action", "description": "new description of the action", + "extra": {"test": "test extra"}, + "policies": [{"name": "test other policy"}]}]}, + {"policies": [ + {"name": "test policy", "genre": "authz", "description": "description", "model": {}, + "mandatory": False}], "actions": [ + {"name": "test action", "description": "description of the action", "extra": {}, + "policies": [{"name": "test policy"}]}]}] + +SUBJECT_CATEGORIES = [{"subject_categories": [ + {"name": "test subject categories", "description": "subject category description"}]}, + {"subject_categories": [{"name": "test subject categories", + "description": "new subject category description"}]}] + +OBJECT_CATEGORIES = [{"object_categories": [ + {"name": "test object categories", "description": "object category description"}]}, + {"object_categories": [{"name": "test object categories", + "description": "new object category description"}]}] + +ACTION_CATEGORIES = [{"action_categories": [ + {"name": "test action categories", "description": "action category description"}]}, + {"action_categories": [{"name": "test action categories", + "description": "new action category description"}]}] + +# meta_rules import is needed otherwise the search for data do not work !!! +PRE_DATA = {"models": [{"name": "test model", "description": "", + "meta_rules": [{"name": "good meta rule"}, + {"name": "other good meta rule"}]}], + "policies": [ + {"name": "test other policy", "genre": "authz", "description": "description", + "model": {"name": "test model"}, "mandatory": True}], + "subject_categories": [ + {"name": "test subject categories", "description": "subject category description"}, + {"name": "other test subject categories", + "description": "subject category description"}], + "object_categories": [ + {"name": "test object categories", "description": "object category description"}, + {"name": "other test object categories", + "description": "object category description"}], + "action_categories": [ + {"name": "test action categories", "description": "action category description"}, + {"name": "other test action categories", + "description": "action category description"}], + "meta_rules": [{"name": "good meta rule", "description": "valid meta rule", + "subject_categories": [{"name": "test subject categories"}], + "object_categories": [{"name": "test object categories"}], + "action_categories": [{"name": "test action categories"}]}, + {"name": "other good meta rule", "description": "valid meta rule", + "subject_categories": [{"name": "other test subject categories"}], + "object_categories": [{"name": "other test object categories"}], + "action_categories": [{"name": "other test action categories"}]}]} + +SUBJECT_DATA = [{"subject_data": [ + {"name": "not valid subject data", "description": "", "policies": [{}], "category": {}}]}, + {"subject_data": [ + {"name": "not valid subject data", "description": "", "policies": [{}], + "category": {"name": "test subject categories"}}]}, + {"policies": [ + {"name": "test policy", "genre": "authz", "description": "description", + "model": {"name": "test model"}, "mandatory": True}], "subject_data": [ + {"name": "one valid subject data", "description": "description", + "policies": [{}], "category": {"name": "test subject categories"}}]}, + {"subject_data": [{"name": "valid subject data", "description": "description", + "policies": [{"name": "test policy"}], + "category": {"name": "test subject categories"}}]}, + {"subject_data": [{"name": "valid subject data", "description": "new description", + "policies": [{"name": "test other policy"}], + "category": {"name": "test subject categories"}}]}] + +OBJECT_DATA = [{"object_data": [ + {"name": "not valid object data", "description": "", "policies": [{}], "category": {}}]}, + {"object_data": [ + {"name": "not valid object data", "description": "", "policies": [{}], + "category": {"name": "test object categories"}}]}, + {"policies": [{"name": "test policy", "genre": "authz", "description": "description", + "model": {"name": "test model"}, "mandatory": True}], "object_data": [ + {"name": "one valid object data", "description": "description", "policies": [{}], + "category": {"name": "test object categories"}}]}, + {"object_data": [{"name": "valid object data", "description": "description", + "policies": [{"name": "test policy"}], + "category": {"name": "test object categories"}}]}, + {"object_data": [{"name": "valid object data", "description": "new description", + "policies": [{"name": "test other policy"}], + "category": {"name": "test object categories"}}]}] + +ACTION_DATA = [{"action_data": [ + {"name": "not valid action data", "description": "", "policies": [{}], "category": {}}]}, + {"action_data": [ + {"name": "not valid action data", "description": "", "policies": [{}], + "category": {"name": "test action categories"}}]}, + {"policies": [{"name": "test policy", "genre": "authz", "description": "description", + "model": {"name": "test model"}, "mandatory": True}], "action_data": [ + {"name": "one valid action data", "description": "description", "policies": [{}], + "category": {"name": "test action categories"}}]}, + {"action_data": [{"name": "valid action data", "description": "description", + "policies": [{"name": "test policy"}], + "category": {"name": "test action categories"}}]}, + {"action_data": [{"name": "valid action data", "description": "new description", + "policies": [{"name": "test other policy"}], + "category": {"name": "test action categories"}}]}] + +PRE_META_RULES = {"subject_categories": [ + {"name": "test subject categories", "description": "subject category description"}], + "object_categories": [{"name": "test object categories", + "description": "object category description"}], + "action_categories": [{"name": "test action categories", + "description": "object action description"}]} + +META_RULES = [{"meta_rules": [{"name": "bad meta rule", "description": "not valid meta rule", + "subject_categories": [{"name": "not valid category"}], + "object_categories": [{"name": "test object categories"}], + "action_categories": [{"name": "test action categories"}]}]}, + {"meta_rules": [{"name": "bad meta rule", "description": "not valid meta rule", + "subject_categories": [{"name": "test subject categories"}], + "object_categories": [{"name": "not valid category"}], + "action_categories": [{"name": "test action categories"}]}]}, + {"meta_rules": [{"name": "bad meta rule", "description": "not valid meta rule", + "subject_categories": [{"name": "test subject categories"}], + "object_categories": [{"name": "test object categories"}], + "action_categories": [{"name": "not valid category"}]}]}, + {"meta_rules": [{"name": "good meta rule", "description": "valid meta rule", + "subject_categories": [{"name": "test subject categories"}], + "object_categories": [{"name": "test object categories"}], + "action_categories": [{"name": "test action categories"}]}]}] + +PRE_ASSIGNMENTS = {"models": [ + {"name": "test model", "description": "", "meta_rules": [{"name": "good meta rule"}]}], + "policies": [ + {"name": "test policy", "genre": "authz", "description": "description", + "model": {"name": "test model"}, "mandatory": True}], + "subject_categories": [{"name": "test subject categories", + "description": "subject category description"}], + "object_categories": [{"name": "test object categories", + "description": "object category description"}], + "action_categories": [{"name": "test action categories", + "description": "object action description"}], + "subjects": [{"name": "testuser", "description": "description of the subject", + "extra": {}, "policies": [{"name": "test policy"}]}], + "objects": [{"name": "test object", "description": "description of the object", + "extra": {}, "policies": [{"name": "test policy"}]}], + "actions": [{"name": "test action", "description": "description of the action", + "extra": {}, "policies": [{"name": "test policy"}]}], + "meta_rules": [{"name": "good meta rule", "description": "valid meta rule", + "subject_categories": [{"name": "test subject categories"}], + "object_categories": [{"name": "test object categories"}], + "action_categories": [{"name": "test action categories"}]}], + "subject_data": [{"name": "subject data", "description": "test subject data", + "policies": [{"name": "test policy"}], + "category": {"name": "test subject categories"}}], + "object_data": [{"name": "object data", "description": "test object data", + "policies": [{"name": "test policy"}], + "category": {"name": "test object categories"}}], + "action_data": [{"name": "action data", "description": "test action data", + "policies": [{"name": "test policy"}], + "category": {"name": "test action categories"}}]} + +SUBJECT_ASSIGNMENTS = [ + {"subject_assignments": [ + {"subject": {"name": "unknown"}, + "category": {"name": "test subject categories"}, + "assignments": [{"name": "subject data"}]}], + "exception": exceptions.InvalidJson + }, + {"subject_assignments": [ + {"subject": {"name": "testuser"}, + "category": {"name": "unknown"}, + "assignments": [{"name": "subject data"}]}], + "exception": exceptions.UnknownName + }, + {"subject_assignments": [ + {"subject": {"name": "testuser"}, + "category": {"name": "test subject categories"}, + "assignments": [{"name": "unknown"}]}], + "exception": exceptions.InvalidJson + }, + {"subject_assignments": [ + {"subject": {"name": "testuser"}, + "category": {"name": "test subject categories"}, + "assignments": [{"name": "subject data"}]}], + "exception": None + }] + +OBJECT_ASSIGNMENTS = [ + {"object_assignments": [ + {"object": {"name": "unknown"}, + "category": {"name": "test object categories"}, + "assignments": [{"name": "object data"}]}], + "exception": exceptions.InvalidJson + }, + {"object_assignments": [ + {"object": {"name": "test object"}, + "category": {"name": "unknown"}, + "assignments": [{"name": "object data"}]}], + "exception": exceptions.UnknownName + }, + {"object_assignments": [ + {"object": {"name": "test object"}, + "category": {"name": "test object categories"}, + "assignments": [{"name": "unknown"}]}], + "exception": exceptions.InvalidJson + }, + {"object_assignments": [ + {"object": {"name": "test object"}, + "category": {"name": "test object categories"}, + "assignments": [{"name": "object data"}]}], + "exception": None + }] + +ACTION_ASSIGNMENTS = [ + {"action_assignments": [ + {"action": {"name": "unknown"}, + "category": {"name": "test action categories"}, + "assignments": [{"name": "action data"}]}], + "exception": exceptions.InvalidJson + }, + {"action_assignments": [ + {"action": {"name": "test action"}, + "category": {"name": "unknown"}, + "assignments": [{"name": "action data"}]}], + "exception": exceptions.UnknownName + }, + {"action_assignments": [ + {"action": {"name": "test action"}, + "category": {"name": "test action categories"}, + "assignments": [{"name": "unknown"}]}], + "exception": exceptions.InvalidJson + }, + {"action_assignments": [ + {"action": {"name": "test action"}, + "category": {"name": "test action categories"}, + "assignments": [{"name": "action data"}]}], + "exception": None + }] + +RULES = [{"rules": [{"meta_rule": {"name": "unknown meta rule"}, "policy": {"name": "test " + "policy"}, + "instructions": [{"decision": "grant"}], "enabled": True, "rule": { + "subject_data": [{"name": "subject data"}], "object_data": [{"name": "object data"}], + "action_data": [{"name": "action data"}]}}]}, + {"rules": [{"meta_rule": {"name": "good meta rule"}, "policy": {"name": "unknown " + "policy"}, + "instructions": [{"decision": "grant"}], "enabled": True, "rule": { + "subject_data": [{"name": "subject data"}], + "object_data": [{"name": "object data"}], + "action_data": [{"name": "action data"}]}}]}, + {"rules": [{"meta_rule": {"name": "good meta rule"}, "policy": {"name": "test policy"}, + "instructions": [{"decision": "grant"}], "enabled": True, "rule": { + "subject_data": [{"name": "unknown subject data"}], + "object_data": [{"name": "object data"}], + "action_data": [{"name": "action data"}]}}]}, + {"rules": [{"meta_rule": {"name": "good meta rule"}, "policy": {"name": "test policy"}, + "instructions": [{"decision": "grant"}], "enabled": True, "rule": { + "subject_data": [{"name": "subject data"}], + "object_data": [{"name": "unknown object data"}], + "action_data": [{"name": "action data"}]}}]}, + {"rules": [{"meta_rule": {"name": "good meta rule"}, "policy": {"name": "test policy"}, + "instructions": [{"decision": "grant"}], "enabled": True, "rule": { + "subject_data": [{"name": "subject data"}], + "object_data": [{"name": "object data"}], + "action_data": [{"name": "unknown action data"}]}}]}, + {"rules": [{"meta_rule": {"name": "good meta rule"}, "policy": {"name": "test policy"}, + "instructions": [{"decision": "grant"}], "enabled": True, "rule": { + "subject_data": [{"name": "subject data"}], + "object_data": [{"name": "object data"}], + "action_data": [{"name": "action data"}]}}]}] + + +def test_import_models_without_new_meta_rules(): + from moon_utilities.auth_functions import get_api_key_for_user + + import_export_helper.clean_all() + counter = 0 + for models_description in MODEL_WITHOUT_META_RULES: + from moon_manager.api import json_import + req = hug.test.post(json_import, "/import", body=json.dumps(models_description) + , headers={'Content-Type': 'application/json', "X-Api-Key": + get_api_key_for_user("admin")}) + data = req.data + assert all(e in data for e in models_description.keys()) + req, models = test_models.get_models() + models = models["models"] + assert len(list(models.keys())) == 1 + values = list(models.values()) + assert values[0]["name"] == "test model" + if counter == 0: + assert len(values[0]["description"]) == 0 + if counter == 1 or counter == 2: + assert values[0]["description"] == "new description" + counter = counter + 1 + import_export_helper.clean_all() + + +def test_import_policies(): + from moon_utilities.auth_functions import get_api_key_for_user + + import_export_helper.clean_all() + counter = -1 + for policy_description in POLICIES: + counter = counter + 1 + from moon_manager.api import json_import + if counter == 2: + with pytest.raises(exceptions.UnknownName): + req = hug.test.post(json_import, "/import", body=json.dumps(policy_description), + headers={'Content-Type': 'application/json', + "X-Api-Key": get_api_key_for_user("admin")}) + continue + else: + req = hug.test.post(json_import, "/import", body=json.dumps(policy_description), + headers={'Content-Type': 'application/json', + "X-Api-Key": get_api_key_for_user("admin")}) + data = req.data + assert all(e in data for e in policy_description.keys()) + + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + req = test_policies.get_policies(auth_headers) + policies = req.data + policies = policies["policies"] + assert len(list(policies.keys())) == 1 + values = list(policies.values()) + assert values[0]["name"] == "test policy" + if counter < 3: + assert values[0]["genre"] == "authz" + assert values[0]["description"] == "description" + else: + assert values[0]["genre"] == "not authz ?" + assert values[0]["description"] == "changes taken into account" + assert len(values[0]["model_id"]) > 0 + import_export_helper.clean_all() + + +def test_import_subject_object_action(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + type_elements = ["object", "action"] + perimeter_id = None + + for type_element in type_elements: + import_export_helper.clean_all() + counter = -1 + # set the getters and the comparison values + if type_element == "subject": + elements = SUBJECTS + clean_method = import_export_helper.clean_subjects + name = "testuser" + key_extra = "email" + value_extra = "new-email@test.com" + elif type_element == "object": + elements = OBJECTS + clean_method = import_export_helper.clean_objects + name = "test object" + key_extra = "test" + value_extra = "test extra" + else: + elements = ACTIONS + clean_method = import_export_helper.clean_actions + name = "test action" + key_extra = "test" + value_extra = "test extra" + + for element in elements: + counter = counter + 1 + if counter == 2 or counter == 4: + clean_method() + + from moon_manager.api import perimeter + if counter == 3: + req = hug.test.patch(perimeter, "/{}s/{}".format(type_element, perimeter_id), + body=json.dumps(element["{}s".format(type_element)][0]), + headers={'Content-Type': 'application/json', + "X-Api-Key": get_api_key_for_user("admin")}) + elif counter < 2: + with pytest.raises(exceptions.PerimeterContentError) as exception_info: + req = hug.test.patch(perimeter, "/{}s/{}".format(type_element, perimeter_id), + body=json.dumps(element["{}s".format(type_element)][0]), + headers={'Content-Type': 'application/json', + "X-Api-Key": get_api_key_for_user("admin")}) + # assert req.status == hug.HTTP_400 + assert '400: Perimeter content is invalid.' == str(exception_info.value) + continue + else: + from moon_manager.api import json_import + req = hug.test.post(json_import, "/import", body=json.dumps(element), + headers={'Content-Type': 'application/json', + "X-Api-Key": get_api_key_for_user("admin")}) + + try: + data = req.data + except Exception as e: + assert False + # assert counter < 2 #  this is an expected failure + # continue + + if counter != 3: + assert any(e in data for e in element["{}s".format(type_element)][0].keys()) #NOTE: logs are skipped for some elements + + from moon_manager.api import perimeter + get_elements = hug.test.get(perimeter, "/" + type_element + "s", headers=auth_headers ).data + get_elements = get_elements[type_element + "s"] + + perimeter_id = list(get_elements.keys())[0] + + assert len(list(get_elements.keys())) == 1 + values = list(get_elements.values()) + assert values[0]["name"] == name + if counter == 2 or counter == 4: + assert values[0]["description"] == "description of the " + type_element + # assert not values[0]["extra"] + if counter == 3: + assert values[0]["description"] == "new description of the " + type_element + assert values[0]["extra"][key_extra] == value_extra + + #  assert len(values[0]["policy_list"]) == 1 + import_export_helper.clean_all() + + +def test_import_subject_object_action_categories(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + type_elements = ["subject", "object", "action"] + + for type_element in type_elements: + import_export_helper.clean_all() + counter = -1 + # set the getters and the comparison values + if type_element == "subject": + elements = SUBJECT_CATEGORIES + get_method = test_categories.get_subject_categories + elif type_element == "object": + elements = OBJECT_CATEGORIES + get_method = test_categories.get_object_categories + else: + elements = ACTION_CATEGORIES + get_method = test_categories.get_action_categories + + for element in elements: + from moon_manager.api import json_import + req = hug.test.post(json_import, "/import", body=json.dumps(element), + headers={'Content-Type': 'application/json', + "X-Api-Key": get_api_key_for_user("admin")} ) + counter = counter + 1 + data = req.data + assert all(e in data for e in element.keys()) + req, get_elements = get_method() + get_elements = get_elements[type_element + "_categories"] + assert len(list(get_elements.keys())) == 1 + values = list(get_elements.values()) + assert values[0]["name"] == "test " + type_element + " categories" + assert values[0]["description"] == type_element + " category description" + + +def test_import_meta_rules(): + from moon_utilities.auth_functions import get_api_key_for_user + + import_export_helper.clean_all() + # import some categories + from moon_manager.api import json_import + req = hug.test.post(json_import, "/import", body=json.dumps(PRE_META_RULES), + headers={'Content-Type': 'application/json', + "X-Api-Key": get_api_key_for_user("admin")}) + data = req.data + assert all(e in data for e in PRE_META_RULES.keys()) + + counter = -1 + for meta_rule in META_RULES: + counter = counter + 1 + if counter != 3: + with pytest.raises(exceptions.UnknownName) as exception_info: + req = hug.test.post(json_import, "/import", body=json.dumps(meta_rule), + headers={'Content-Type': 'application/json', + "X-Api-Key": get_api_key_for_user("admin")}) + # assert req.status == hug.HTTP_400 + assert '400: Unknown Name.' == str(exception_info.value) + continue + else: + req = hug.test.post(json_import, "/import", body=json.dumps(meta_rule), + headers={'Content-Type': 'application/json', + "X-Api-Key": get_api_key_for_user("admin")}) + data = req.data + assert all(e in data for e in meta_rule.keys()) + assert req.status == hug.HTTP_200 + + req, meta_rules = test_meta_rules.get_meta_rules() + meta_rules = meta_rules["meta_rules"] + key = list(meta_rules.keys())[0] + assert isinstance(meta_rules, dict) + assert meta_rules[key]["name"] == "good meta rule" + assert meta_rules[key]["description"] == "valid meta rule" + assert len(meta_rules[key]["subject_categories"]) == 1 + assert len(meta_rules[key]["object_categories"]) == 1 + assert len(meta_rules[key]["action_categories"]) == 1 + + subject_category_key = meta_rules[key]["subject_categories"][0] + object_category_key = meta_rules[key]["object_categories"][0] + action_category_key = meta_rules[key]["action_categories"][0] + + req, sub_cat = test_categories.get_subject_categories() + sub_cat = sub_cat["subject_categories"] + assert sub_cat[subject_category_key]["name"] == "test subject categories" + + req, ob_cat = test_categories.get_object_categories() + ob_cat = ob_cat["object_categories"] + assert ob_cat[object_category_key]["name"] == "test object categories" + + req, ac_cat = test_categories.get_action_categories() + ac_cat = ac_cat["action_categories"] + assert ac_cat[action_category_key]["name"] == "test action categories" + + import_export_helper.clean_all() + + +def test_import_subject_object_action_assignments(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + import_export_helper.clean_all() + + from moon_manager.api import json_import + req = hug.test.post(json_import, "/import", body=json.dumps(PRE_ASSIGNMENTS), + headers={'Content-Type': 'application/json', + "X-Api-Key": get_api_key_for_user("admin")} ) + data = req.data + assert any(e in data for e in PRE_ASSIGNMENTS.keys()) #NOTE: note assignment logs are skipped + + type_elements = ["subject", "object", "action"] + + for type_element in type_elements: + counter = -1 + if type_element == "subject": + datas = SUBJECT_ASSIGNMENTS + get_method = test_assignments.get_subject_assignment + elif type_element == "object": + datas = OBJECT_ASSIGNMENTS + get_method = test_assignments.get_object_assignment + else: + datas = ACTION_ASSIGNMENTS + get_method = test_assignments.get_action_assignment + + for assignments in datas: + counter = counter + 1 + my_exception = assignments.pop("exception") + if my_exception: + with pytest.raises(my_exception) as exception_info: + req = hug.test.post(json_import, "/import", body=json.dumps(assignments), + headers={'Content-Type': 'application/json', + "X-Api-Key": get_api_key_for_user("admin")}) + assert '400:' in str(exception_info.value) + else: + req = hug.test.post(json_import, "/import", body=json.dumps(assignments), + headers={'Content-Type': 'application/json', + "X-Api-Key": get_api_key_for_user("admin")}) + assert len(assignments.keys()) > 0 #NOTE logs for assignments are skipped + assert req.status == hug.HTTP_200 + req = test_policies.get_policies(auth_headers=auth_headers) + policies = req.data + for policy_key in policies["policies"]: + req, get_assignments = get_method(policy_key) + get_assignments = get_assignments[type_element + "_assignments"] + assert len(get_assignments) == 1 + + +def test_import_rules(): + from moon_utilities.auth_functions import get_api_key_for_user + + import_export_helper.clean_all() + from moon_manager.api import json_import + req = hug.test.post(json_import, "/import", body=json.dumps(PRE_ASSIGNMENTS), + headers={'Content-Type': 'application/json', + "X-Api-Key": get_api_key_for_user("admin")}) + data = req.data + assert all(e in data for e in PRE_ASSIGNMENTS.keys()) + + counter = -1 + for rule in RULES: + counter = counter + 1 + from moon_manager.api import json_import + if counter < 5: + with pytest.raises(exceptions.UnknownName) as exception_info: + req = hug.test.post(json_import, "/import", body=json.dumps(rule), + headers={'Content-Type': 'application/json', + "X-Api-Key": get_api_key_for_user("admin")}) + + # assert req.status == hug.HTTP_400 + assert '400: Unknown Name.' == str(exception_info.value) + continue + req = hug.test.post(json_import, "/import", body=json.dumps(rule), + headers={'Content-Type': 'application/json', + "X-Api-Key": get_api_key_for_user("admin")}) + + assert req.status == hug.HTTP_200 + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + policies = test_policies.get_policies(auth_headers=auth_headers).data + for policy in policies['policies']: + if policies['policies'][policy]['name'] == rule['rules'][0]['policy']['name']: + policy_id = policy + break + + req, rules = test_rules.test_get_rules(policy_id) + rules = rules["rules"] + rules = rules["rules"] + assert len(rules) == 1 + rules = rules[0] + assert rules["enabled"] + assert rules["instructions"][0]["decision"] == "grant" + + req, meta_rules = test_meta_rules.get_meta_rules() + assert meta_rules["meta_rules"][list(meta_rules["meta_rules"].keys())[0]][ + "name"] == "good meta rule" + + +def test_import_subject_object_action_data(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + type_elements = ["subject", "object", "action"] + + for type_element in type_elements: + import_export_helper.clean_all() + from moon_manager.api import json_import + req = hug.test.post(json_import, "/import", body=json.dumps(PRE_DATA), + headers={'Content-Type': 'application/json', "X-Api-Key": + get_api_key_for_user("admin")}) + counter = -1 + # set the getters and the comparison values + if type_element == "subject": + elements = SUBJECT_DATA + get_method = test_data.get_subject_data + get_categories = test_categories.get_subject_categories + elif type_element == "object": + elements = OBJECT_DATA + get_method = test_data.get_object_data + get_categories = test_categories.get_object_categories + else: + elements = ACTION_DATA + get_method = test_data.get_action_data + get_categories = test_categories.get_action_categories + + for element in elements: + from moon_manager.api import json_import + counter = counter + 1 + if counter == 0 or counter == 1: + with pytest.raises(exceptions.MissingIdOrName) as exception_info: + req = hug.test.post(json_import, "/import", body=json.dumps(element), headers={ + 'Content-Type': 'application/json', "X-Api-Key": get_api_key_for_user("admin")}) + # assert req.status == hug.HTTP_400 + assert '400: Missing ID or Name.' == str(exception_info.value) + continue + else: + req = hug.test.post(json_import, "/import", body=json.dumps(element), headers={ + 'Content-Type': 'application/json', "X-Api-Key": get_api_key_for_user("admin")}) + assert req.status == hug.HTTP_200 + data = req.data + assert all(e in data for e in element.keys()) + + req = test_policies.get_policies(auth_headers=auth_headers) + policies = req.data + policies = policies["policies"] + req, categories = get_categories() + categories = categories[type_element + "_categories"] + case_tested = False + for policy_key in policies.keys(): + policy = policies[policy_key] + for category_key in categories: + req, get_elements = get_method(policy_id=policy_key, + category_id=category_key) + if len(get_elements[type_element + "_data"]) == 0: + continue + + # do this because the backend gives an element with empty data if the policy_key, + # category_key couple does not have any data... + get_elements = get_elements[type_element + "_data"] + if len(get_elements[0]["data"]) == 0: + continue + + if policy["name"] == "test policy": + assert len(get_elements) == 1 + el = get_elements[0] + assert isinstance(el["data"], dict) + if counter == 2: + assert len(el["data"].keys()) == 1 + el = el["data"][list(el["data"].keys())[0]] + if "value" in el: + el = el["value"] + assert el["name"] == "one valid " + type_element + " data" + if counter == 3: + assert len(el["data"].keys()) == 2 + el1 = el["data"][list(el["data"].keys())[0]] + el2 = el["data"][list(el["data"].keys())[1]] + if "value" in el1: + el1 = el1["value"] + el2 = el2["value"] + assert (el1["name"] == "one valid " + type_element + " data" and el2[ + "name"] == "valid " + type_element + " data") or (el2[ + "name"] == "one valid " + type_element + " data" and + el1[ + "name"] == "valid " + type_element + " data") + assert el1["description"] == "description" + assert el2["description"] == "description" + + case_tested = True + + if policy["name"] == "test other policy": + if counter == 4: + assert len(get_elements) == 1 + el = get_elements[0] + assert isinstance(el["data"], dict) + assert len(el["data"].keys()) == 1 + el = el["data"][list(el["data"].keys())[0]] + if "value" in el: + el = el["value"] + assert el["name"] == "valid " + type_element + " data" + assert el["description"] == "new description" + case_tested = True + + assert case_tested is True + + +def test_clean(): + import_export_helper.clean_all() + # restore the database as previously + policy_helper.add_policies() diff --git a/moon_manager/tests/unit_python/api/test_keystone.py b/moon_manager/tests/unit_python/api/test_keystone.py new file mode 100644 index 00000000..5ed08ca7 --- /dev/null +++ b/moon_manager/tests/unit_python/api/test_keystone.py @@ -0,0 +1,63 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + + +def create_project(tenant_dict): + from moon_manager.pip_driver import InformationManager + return InformationManager["subjects"][0].create_project(**tenant_dict) + + +def list_projects(): + from moon_manager.pip_driver import InformationManager + return InformationManager["subjects"][0].get_projects() + + +def create_user(subject_dict): + from moon_manager.pip_driver import InformationManager + return InformationManager["subjects"][0].add_item(**subject_dict) + + +def test_create_project(): + tenant_dict = { + "description": "test_project", + "domain": ['domain_id_1'], + "enabled": True, + "is_domain": False, + "name": 'project_1' + } + project = create_project(tenant_dict) + assert project + assert project.get('name') == tenant_dict.get('name') + +# TODO TO BE UPDATED +# def test_create_project_without_name(): +# tenant_dict = { +# "description": "test_project", +# "domain_id": ['domain_id_1'], +# "enabled": True, +# "is_domain": False, +# } +# with pytest.raises(Exception) as exception_info: +# create_project(tenant_dict) +# assert '400: Keystone project error' == str(exception_info.value) + + +def test_create_user(): + subject_dict = { + "password": "password", + "domain": ['domain_id_1'], + "enabled": True, + "project": 'test_project', + "name": 'user_id_1' + } + user = create_user(subject_dict) + assert user diff --git a/moon_manager/tests/unit_python/api/test_meta_data.py b/moon_manager/tests/unit_python/api/test_meta_data.py index e6cb0833..1d37ab70 100644 --- a/moon_manager/tests/unit_python/api/test_meta_data.py +++ b/moon_manager/tests/unit_python/api/test_meta_data.py @@ -1,305 +1,370 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +import hug import json -import api.utilities as utilities from helpers import data_builder from uuid import uuid4 - +import pytest +from moon_utilities import exceptions # subject_categories_test -def get_subject_categories(client): - req = client.get("/subject_categories") - subject_categories = utilities.get_json(req.data) +def get_subject_categories(): + from moon_manager.api import meta_data + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + req = hug.test.get(meta_data, "/subject_categories", headers=auth_headers ) + subject_categories = req.data return req, subject_categories -def add_subject_categories(client, name): +def add_subject_categories(name): + from moon_manager.api import meta_data + from moon_utilities.auth_functions import get_api_key_for_user + data = { "name": name, "description": "description of {}".format(name) } - req = client.post("/subject_categories", data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - subject_categories = utilities.get_json(req.data) + req = hug.test.post(meta_data, "/subject_categories", body=json.dumps(data), + headers={'Content-Type': 'application/json', "X-Api-Key": + get_api_key_for_user("admin")}) + + subject_categories = req.data return req, subject_categories -def delete_subject_categories(client, name): - request, subject_categories = get_subject_categories(client) +def delete_subject_categories(name): + from moon_manager.api import meta_data + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + request, subject_categories = get_subject_categories() for key, value in subject_categories['subject_categories'].items(): if value['name'] == name: - return client.delete("/subject_categories/{}".format(key)) - - -def delete_subject_categories_without_id(client): - req = client.delete("/subject_categories/{}".format("")) - return req + return hug.test.delete(meta_data, "/subject_categories/{}".format(key), headers=auth_headers ) + return hug.test.delete(meta_data, "/subject_categories/{}".format(name), headers=auth_headers ) def test_get_subject_categories(): - client = utilities.register_client() - req, subject_categories = get_subject_categories(client) - assert req.status_code == 200 + req, subject_categories = get_subject_categories() + assert req.status == hug.HTTP_200 assert isinstance(subject_categories, dict) assert "subject_categories" in subject_categories def test_add_subject_categories(): - client = utilities.register_client() - req, subject_categories = add_subject_categories(client, "testuser") - assert req.status_code == 200 + name = "testuser" + uuid4().hex + req, subject_categories = add_subject_categories(name) + assert req.status == hug.HTTP_200 assert isinstance(subject_categories, dict) value = list(subject_categories["subject_categories"].values())[0] assert "subject_categories" in subject_categories - assert value['name'] == "testuser" - assert value['description'] == "description of {}".format("testuser") + assert value['name'] == name + assert value['description'] == "description of {}".format(name) def test_add_subject_categories_with_existed_name(): - client = utilities.register_client() name = uuid4().hex - req, subject_categories = add_subject_categories(client, name) - assert req.status_code == 200 - req, subject_categories = add_subject_categories(client, name) - assert req.status_code == 409 - assert json.loads(req.data)["message"] == '409: Subject Category Existing' + req, subject_categories = add_subject_categories(name) + assert req.status == hug.HTTP_200 + with pytest.raises(exceptions.SubjectCategoryExisting) as exception_info: + req, subject_categories = add_subject_categories(name) + assert '409: Subject Category Existing' == str(exception_info.value) + # assert req.status == hug.HTTP_409 + # assert req.data['message'] == '409: Subject Category Existing' def test_add_subject_categories_name_contain_space(): - client = utilities.register_client() - req, subject_categories = add_subject_categories(client, " ") - assert req.status_code == 400 - assert json.loads(req.data)["message"] == '400: Category Name Invalid' + with pytest.raises(exceptions.CategoryNameInvalid) as exception_info: + req, subject_categories = add_subject_categories(" ") + assert '400: Category Name Invalid' == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data['message'] == '400: Category Name Invalid' def test_add_subject_categories_with_empty_name(): - client = utilities.register_client() - req, subject_categories = add_subject_categories(client, "") - assert req.status_code == 400 - assert json.loads(req.data)["message"] == "Key: 'name', [Forbidden characters in string]" + with pytest.raises(exceptions.ValidationContentError) as exception_info: + req, subject_categories = add_subject_categories("") + # assert req.status == hug.HTTP_400 + # assert req.data['message'] == "Key: 'name', [Forbidden characters in string]" + assert "Key: 'name', [Forbidden characters in string]" == str(exception_info.value) def test_add_subject_categories_with_name_contain_space(): - client = utilities.register_client() - req, subject_categories = add_subject_categories(client, "testuser") - assert req.status_code == 400 - assert json.loads(req.data)["message"] == "Key: 'name', [Forbidden characters in string]" + with pytest.raises(exceptions.ValidationContentError) as exception_info: + req, subject_categories = add_subject_categories("testuser") + assert "Key: 'name', [Forbidden characters in string]" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data['message'] == "Key: 'name', [Forbidden characters in string]" def test_delete_subject_categories(): - client = utilities.register_client() - req = delete_subject_categories(client, "testuser") - assert req.status_code == 200 + name = "testuser" + uuid4().hex + add_subject_categories(name) + req = delete_subject_categories(name) + assert req.status == hug.HTTP_200 def test_delete_subject_categories_without_id(): - client = utilities.register_client() - req = delete_subject_categories_without_id(client) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == "400: Subject Category Unknown" + with pytest.raises(exceptions.SubjectCategoryUnknown) as exception_info: + req = delete_subject_categories(uuid4().hex) + assert "400: Subject Category Unknown" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data['message'] == "400: Subject Category Unknown" # --------------------------------------------------------------------------- # object_categories_test -def get_object_categories(client): - req = client.get("/object_categories") - object_categories = utilities.get_json(req.data) +def get_object_categories(): + from moon_manager.api import meta_data + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + req = hug.test.get(meta_data, "/object_categories", headers=auth_headers ) + object_categories = req.data return req, object_categories -def add_object_categories(client, name): +def add_object_categories(name): + from moon_manager.api import meta_data + from moon_utilities.auth_functions import get_api_key_for_user + data = { "name": name, "description": "description of {}".format(name) } - req = client.post("/object_categories", data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - object_categories = utilities.get_json(req.data) + req = hug.test.post(meta_data, "/object_categories", body=json.dumps(data), + headers={'Content-Type': 'application/json', "X-Api-Key": + get_api_key_for_user("admin")} ) + object_categories = req.data return req, object_categories -def delete_object_categories(client, name): - request, object_categories = get_object_categories(client) +def delete_object_categories(name): + from moon_manager.api import meta_data + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + request, object_categories = get_object_categories() for key, value in object_categories['object_categories'].items(): if value['name'] == name: - return client.delete("/object_categories/{}".format(key)) - - -def delete_object_categories_without_id(client): - req = client.delete("/object_categories/{}".format("")) - return req + return hug.test.delete(meta_data, "/object_categories/{}".format(key), + headers=auth_headers ) + return hug.test.delete(meta_data, "/object_categories/{}".format(name), headers=auth_headers ) def test_get_object_categories(): - client = utilities.register_client() - req, object_categories = get_object_categories(client) - assert req.status_code == 200 + req, object_categories = get_object_categories() + assert req.status == hug.HTTP_200 assert isinstance(object_categories, dict) assert "object_categories" in object_categories def test_add_object_categories(): - client = utilities.register_client() - req, object_categories = add_object_categories(client, "testuser") - assert req.status_code == 200 + name="testuser"+uuid4().hex + req, object_categories = add_object_categories(name) + assert req.status == hug.HTTP_200 assert isinstance(object_categories, dict) value = list(object_categories["object_categories"].values())[0] assert "object_categories" in object_categories - assert value['name'] == "testuser" - assert value['description'] == "description of {}".format("testuser") + assert value['name'] == name + assert value['description'] == "description of {}".format(name) def test_add_object_categories_with_existed_name(): - client = utilities.register_client() name = uuid4().hex - req, object_categories = add_object_categories(client, name) - assert req.status_code == 200 - req, object_categories = add_object_categories(client, name) - assert req.status_code == 409 - assert json.loads(req.data)["message"] == '409: Object Category Existing' + req, object_categories = add_object_categories(name) + assert req.status == hug.HTTP_200 + with pytest.raises(exceptions.ObjectCategoryExisting) as exception_info: + req, object_categories = add_object_categories(name) + assert "409: Object Category Existing" == str(exception_info.value) + # assert req.status == hug.HTTP_409 + # assert req.data['message'] == '409: Object Category Existing' def test_add_object_categories_name_contain_space(): - client = utilities.register_client() - req, subject_categories = add_object_categories(client, " ") - assert req.status_code == 400 - assert json.loads(req.data)["message"] == '400: Category Name Invalid' + with pytest.raises(exceptions.CategoryNameInvalid) as exception_info: + req, subject_categories = add_object_categories(" ") + assert "400: Category Name Invalid" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data['message'] == '400: Category Name Invalid' def test_add_object_categories_with_empty_name(): - client = utilities.register_client() - req, object_categories = add_object_categories(client, "") - assert req.status_code == 400 - assert json.loads(req.data)["message"] == "Key: 'name', [Forbidden characters in string]" + with pytest.raises(exceptions.ValidationContentError) as exception_info: + req, object_categories = add_object_categories("") + assert "Key: 'name', [Forbidden characters in string]" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data['message'] == "Key: 'name', [Forbidden characters in string]" def test_add_object_categories_with_name_contain_space(): - client = utilities.register_client() - req, object_categories = add_object_categories(client, "testuser") - assert req.status_code == 400 - assert json.loads(req.data)["message"] == "Key: 'name', [Forbidden characters in string]" + with pytest.raises(exceptions.ValidationContentError) as exception_info: + req, object_categories = add_object_categories("testuser") + assert "Key: 'name', [Forbidden characters in string]" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data['message'] == "Key: 'name', [Forbidden characters in string]" def test_delete_object_categories(): - client = utilities.register_client() - req = delete_object_categories(client, "testuser") - assert req.status_code == 200 + name = uuid4().hex + add_object_categories(name) + req = delete_object_categories(name) + assert req.status == hug.HTTP_200 def test_delete_object_categories_without_id(): - client = utilities.register_client() - req = delete_object_categories_without_id(client) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == "400: Object Category Unknown" + with pytest.raises(exceptions.ObjectCategoryUnknown) as exception_info: + req = delete_object_categories(uuid4().hex) + assert "400: Object Category Unknown" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data['message'] == "400: Object Category Unknown" # --------------------------------------------------------------------------- # action_categories_test -def get_action_categories(client): - req = client.get("/action_categories") - action_categories = utilities.get_json(req.data) +def get_action_categories(): + from moon_manager.api import meta_data + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + req = hug.test.get(meta_data, "/action_categories", headers=auth_headers ) + action_categories = req.data return req, action_categories -def add_action_categories(client, name): +def add_action_categories(name): + from moon_manager.api import meta_data + from moon_utilities.auth_functions import get_api_key_for_user + data = { "name": name, "description": "description of {}".format(name) } - req = client.post("/action_categories", data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - action_categories = utilities.get_json(req.data) + req = hug.test.post(meta_data, "/action_categories", body=json.dumps(data), + headers={'Content-Type': 'application/json', "X-Api-Key": + get_api_key_for_user("admin")} ) + action_categories = req.data return req, action_categories -def delete_action_categories(client, name): - request, action_categories = get_action_categories(client) +def delete_action_categories(name): + from moon_manager.api import meta_data + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + request, action_categories = get_action_categories() for key, value in action_categories['action_categories'].items(): if value['name'] == name: - return client.delete("/action_categories/{}".format(key)) - - -def delete_action_categories_without_id(client): - req = client.delete("/action_categories/{}".format("")) - return req + return hug.test.delete(meta_data, "/action_categories/{}".format(key), headers=auth_headers ) + return hug.test.delete(meta_data, "/action_categories/{}".format(name), headers=auth_headers ) def test_get_action_categories(): - client = utilities.register_client() - req, action_categories = get_action_categories(client) - assert req.status_code == 200 + req, action_categories = get_action_categories() + assert req.status == hug.HTTP_200 assert isinstance(action_categories, dict) assert "action_categories" in action_categories def test_add_action_categories(): - client = utilities.register_client() - req, action_categories = add_action_categories(client, "testuser") - assert req.status_code == 200 + name = "testuser" + uuid4().hex + req, action_categories = add_action_categories(name) + assert req.status == hug.HTTP_200 assert isinstance(action_categories, dict) value = list(action_categories["action_categories"].values())[0] assert "action_categories" in action_categories - assert value['name'] == "testuser" - assert value['description'] == "description of {}".format("testuser") + assert value['name'] == name + assert value['description'] == "description of {}".format(name) def test_add_action_categories_with_existed_name(): - client = utilities.register_client() name = uuid4().hex - req, action_categories = add_action_categories(client, name) - assert req.status_code == 200 - req, action_categories = add_action_categories(client, name) - assert req.status_code == 409 - assert json.loads(req.data)["message"] == '409: Action Category Existing' + req, action_categories = add_action_categories(name) + assert req.status == hug.HTTP_200 + with pytest.raises(exceptions.ActionCategoryExisting) as exception_info: + req, action_categories = add_action_categories(name) + assert "409: Action Category Existing" == str(exception_info.value) + # assert req.status == hug.HTTP_409 + # assert req.data['message'] == '409: Action Category Existing' def test_add_action_categories_name_contain_space(): - client = utilities.register_client() - req, subject_categories = add_action_categories(client, " ") - assert req.status_code == 400 - assert json.loads(req.data)["message"] == '400: Category Name Invalid' + with pytest.raises(exceptions.CategoryNameInvalid) as exception_info: + req, subject_categories = add_action_categories(" ") + assert "400: Category Name Invalid" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data['message'] == '400: Category Name Invalid' def test_add_action_categories_with_empty_name(): - client = utilities.register_client() - req, action_categories = add_action_categories(client, "") - assert req.status_code == 400 - assert json.loads(req.data)["message"] == "Key: 'name', [Forbidden characters in string]" + with pytest.raises(exceptions.ValidationContentError) as exception_info: + req, action_categories = add_action_categories("") + assert "Key: 'name', [Forbidden characters in string]" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data['message'] == "Key: 'name', [Forbidden characters in string]" def test_add_action_categories_with_name_contain_space(): - client = utilities.register_client() - req, action_categories = add_action_categories(client, "testuser") - assert req.status_code == 400 - assert json.loads(req.data)["message"] == "Key: 'name', [Forbidden characters in string]" + with pytest.raises(exceptions.ValidationContentError) as exception_info: + req, action_categories = add_action_categories("testuser") + assert "Key: 'name', [Forbidden characters in string]" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data['message'] == "Key: 'name', [Forbidden characters in string]" def test_delete_action_categories(): - client = utilities.register_client() - req = delete_action_categories(client, "testuser") - assert req.status_code == 200 + name = "testuser" + uuid4().hex + add_action_categories(name) + req = delete_action_categories(name) + assert req.status == hug.HTTP_200 def test_delete_action_categories_without_id(): - client = utilities.register_client() - req = delete_action_categories_without_id(client) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == "400: Action Category Unknown" + with pytest.raises(exceptions.ActionCategoryUnknown) as exception_info: + req = delete_action_categories(uuid4().hex) + assert "400: Action Category Unknown" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data['message'] == "400: Action Category Unknown" def test_delete_data_categories_connected_to_meta_rule(): + from moon_manager.api import meta_data + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + subject_category_id, object_category_id, action_category_id, meta_rule_id = data_builder.create_new_meta_rule() - client = utilities.register_client() - req = client.delete("/subject_categories/{}".format(subject_category_id)) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == '400: Subject Category With Meta Rule Error' - - req = client.delete("/object_categories/{}".format(object_category_id)) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == '400: Object Category With Meta Rule Error' - - req = client.delete("/action_categories/{}".format(action_category_id)) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == '400: Action Category With Meta Rule Error' + + with pytest.raises(exceptions.DeleteSubjectCategoryWithMetaRule) as exception_info: + req = hug.test.delete(meta_data, "/subject_categories/{}".format(subject_category_id), + headers=auth_headers ) + assert "400: Subject Category With Meta Rule Error" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data['message'] == '400: Subject Category With Meta Rule Error' + + with pytest.raises(exceptions.DeleteObjectCategoryWithMetaRule) as exception_info: + req = hug.test.delete(meta_data, "/object_categories/{}".format(object_category_id), headers=auth_headers) + assert "400: Object Category With Meta Rule Error" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data['message'] == '400: Object Category With Meta Rule Error' + + with pytest.raises(exceptions.DeleteActionCategoryWithMetaRule) as exception_info: + req = hug.test.delete(meta_data, "/action_categories/{}".format(action_category_id), headers=auth_headers) + assert "400: Action Category With Meta Rule Error" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data['message'] == '400: Action Category With Meta Rule Error' diff --git a/moon_manager/tests/unit_python/api/test_meta_rules.py b/moon_manager/tests/unit_python/api/test_meta_rules.py index 634f19da..6c6797f5 100644 --- a/moon_manager/tests/unit_python/api/test_meta_rules.py +++ b/moon_manager/tests/unit_python/api/test_meta_rules.py @@ -1,17 +1,42 @@ -import json +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +import hug import api.utilities as utilities from helpers import category_helper from helpers import data_builder +from helpers import policy_helper +from helpers import model_helper +from helpers import meta_rule_helper from uuid import uuid4 +import pytest +from moon_utilities import exceptions + +def get_meta_rules(): + from moon_manager.api import meta_rules + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} -def get_meta_rules(client): - req = client.get("/meta_rules") + req = hug.test.get(meta_rules, "/meta_rules", headers=auth_headers) meta_rules = utilities.get_json(req.data) return req, meta_rules -def add_meta_rules(client, name, data=None): +def add_meta_rules(name, data=None): + from moon_manager.api import meta_rules + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + if not data: subject_category = category_helper.add_subject_category( value={"name": "subject category name" + uuid4().hex, "description": "description 1"}) @@ -29,26 +54,34 @@ def add_meta_rules(client, name, data=None): "object_categories": [object_category_id], "action_categories": [action_category_id] } - req = client.post("/meta_rules", data=json.dumps(data), - headers={'Content-Type': 'application/json'}) + req = hug.test.post(meta_rules, "/meta_rules", body=data, + headers=auth_headers) meta_rules = utilities.get_json(req.data) return req, meta_rules -def add_meta_rules_without_category_ids(client, name): +def add_meta_rules_without_category_ids(name): + from moon_manager.api import meta_rules + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + data = { "name": name + uuid4().hex, "subject_categories": [], "object_categories": [], "action_categories": [] } - req = client.post("/meta_rules", data=json.dumps(data), - headers={'Content-Type': 'application/json'}) + req = hug.test.post(meta_rules, "/meta_rules", body=data, + headers=auth_headers) meta_rules = utilities.get_json(req.data) return req, meta_rules -def update_meta_rules(client, name, metaRuleId, data=None): +def update_meta_rules(name, metaRuleId, data=None): + from moon_manager.api import meta_rules + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + if not data: subject_category = category_helper.add_subject_category( value={"name": "subject category name update" + uuid4().hex, @@ -69,13 +102,17 @@ def update_meta_rules(client, name, metaRuleId, data=None): "action_categories": [action_category_id] } - req = client.patch("/meta_rules/{}".format(metaRuleId), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) + req = hug.test.patch(meta_rules, "/meta_rules/{}".format(metaRuleId), body=data, + headers=auth_headers) meta_rules = utilities.get_json(req.data) return req, meta_rules -def update_meta_rules_with_categories(client, name, data=None, meta_rule_id=None): +def update_meta_rules_with_categories(name, data=None, meta_rule_id=None): + from moon_manager.api import meta_rules + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + if not meta_rule_id: subject_category_id, object_category_id, action_category_id, meta_rule_id = data_builder.create_new_meta_rule() data = { @@ -85,63 +122,87 @@ def update_meta_rules_with_categories(client, name, data=None, meta_rule_id=None "action_categories": [action_category_id] } - req = client.patch("/meta_rules/{}".format(meta_rule_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) + req = hug.test.patch(meta_rules, "/meta_rules/{}".format(meta_rule_id), body=data, + headers=auth_headers) meta_rules = utilities.get_json(req.data) return req, meta_rules -def delete_meta_rules(client, name): - request, meta_rules = get_meta_rules(client) - for key, value in meta_rules['meta_rules'].items(): +def delete_meta_rules(name): + from moon_manager.api import meta_rules + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + request, meta_rules_data = get_meta_rules() + for key, value in meta_rules_data['meta_rules'].items(): if value['name'] == name: - return client.delete("/meta_rules/{}".format(key)) + return hug.test.delete(meta_rules, "/meta_rules/{}".format(key), headers=auth_headers) + +def delete_meta_rules_without_id(): + from moon_manager.api import meta_rules + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} -def delete_meta_rules_without_id(client): - req = client.delete("/meta_rules/{}".format("")) + req = hug.test.delete(meta_rules, "/meta_rules/{}".format(""), headers=auth_headers) return req def test_get_meta_rules(): - client = utilities.register_client() - req, meta_rules = get_meta_rules(client) - assert req.status_code == 200 + req, meta_rules = get_meta_rules() + assert req.status == hug.HTTP_200 assert isinstance(meta_rules, dict) assert "meta_rules" in meta_rules def test_add_meta_rules(): - client = utilities.register_client() meta_rule_name = uuid4().hex - req, meta_rules = add_meta_rules(client, meta_rule_name) - assert req.status_code == 200 + req, meta_rules = add_meta_rules(meta_rule_name) + assert req.status == hug.HTTP_200 assert isinstance(meta_rules, dict) value = list(meta_rules["meta_rules"].values())[0] assert "meta_rules" in meta_rules assert value['name'] == meta_rule_name +def test_add_meta_rules_space_name(): + with pytest.raises(exceptions.MetaRuleContentError) as exception_info: + req, meta_rules = add_meta_rules(" ") + assert "400: Meta Rule Error" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == '400: Meta Rule Error' + + +def test_add_meta_rules_empty_name(): + with pytest.raises(exceptions.MetaRuleContentError) as exception_info: + req, meta_rules = add_meta_rules("") + assert "400: Meta Rule Error" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == '400: Meta Rule Error' + + def test_add_two_meta_rules_with_same_categories_combination(): - client = utilities.register_client() meta_rule_name = uuid4().hex - req, meta_rules = add_meta_rules(client, meta_rule_name) - assert req.status_code == 200 + req, meta_rules = add_meta_rules(meta_rule_name) + data = None + assert req.status == hug.HTTP_200 for meta_rule_id in meta_rules['meta_rules']: if meta_rules['meta_rules'][meta_rule_id]['name'] == meta_rule_name: data = meta_rules['meta_rules'][meta_rule_id] + assert data data['name'] = uuid4().hex - req, meta_rules = add_meta_rules(client, name=data['name'], data=data) - assert req.status_code == 409 - assert json.loads(req.data)["message"] == '409: Meta Rule Existing' + with pytest.raises(exceptions.MetaRuleExisting) as exception_info: + req, meta_rules = add_meta_rules(name=data['name'], data=data) + assert "409: Meta Rule Existing" == str(exception_info.value) + # assert req.status == hug.HTTP_409 + # assert req.data["message"] == '409: Meta Rule Existing' def test_add_three_meta_rules_with_different_combination_but_similar_items(): - client = utilities.register_client() meta_rule_name1 = uuid4().hex - req, meta_rules = add_meta_rules(client, meta_rule_name1) - assert req.status_code == 200 + req, meta_rules = add_meta_rules(meta_rule_name1) + assert req.status == hug.HTTP_200 for meta_rule_id in meta_rules['meta_rules']: if meta_rules['meta_rules'][meta_rule_id]['name'] == meta_rule_name1: data = meta_rules['meta_rules'][meta_rule_id] @@ -149,7 +210,7 @@ def test_add_three_meta_rules_with_different_combination_but_similar_items(): meta_rule_name2 = uuid4().hex - req, meta_rules = add_meta_rules(client, meta_rule_name2) + req, meta_rules = add_meta_rules(meta_rule_name2) for meta_rule_id in meta_rules['meta_rules']: if meta_rules['meta_rules'][meta_rule_id]['name'] == meta_rule_name2: @@ -161,12 +222,11 @@ def test_add_three_meta_rules_with_different_combination_but_similar_items(): data['name'] = uuid4().hex - req, meta_rules = add_meta_rules(client, name=data['name'], data=data) - assert req.status_code == 200 + req, meta_rules = add_meta_rules(name=data['name'], data=data) + assert req.status == hug.HTTP_200 def test_add_two_meta_rules_with_different_combination_but_similar_items(): - client = utilities.register_client() meta_rule_name1 = uuid4().hex meta_rule_name2 = uuid4().hex @@ -200,8 +260,8 @@ def test_add_two_meta_rules_with_different_combination_but_similar_items(): "object_categories": [object_category_id1, object_category_id2], "action_categories": [action_category_id1, action_category_id2] } - req, meta_rules = add_meta_rules(client, meta_rule_name1, data=data) - assert req.status_code == 200 + req, meta_rules = add_meta_rules(meta_rule_name1, data=data) + assert req.status == hug.HTTP_200 data = { "name": meta_rule_name2, "subject_categories": [subject_category_id2], @@ -209,87 +269,147 @@ def test_add_two_meta_rules_with_different_combination_but_similar_items(): "action_categories": [action_category_id2] } - req, meta_rules = add_meta_rules(client, meta_rule_name1, data=data) - assert req.status_code == 200 + req, meta_rules = add_meta_rules(meta_rule_name1, data=data) + assert req.status == hug.HTTP_200 + + +# This test Succeed as it's okay to have empty id in adding meta rule, as it is not attached to model yet +def test_add_meta_rules_with_empty_subject_in_mid(): + from moon_manager.api import meta_rules + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + value = meta_rule_helper.get_body_meta_rule_with_empty_category_in_mid('subject') + with pytest.raises(exceptions.SubjectCategoryUnknown) as exception_info: + req = hug.test.post(meta_rules, "/meta_rules", body=value, + headers=auth_headers) + # assert req.status == hug.HTTP_200 + assert str(exception_info.value) == "400: Subject Category Unknown" + + +def test_add_meta_rules_with_empty_object_in_mid(): + from moon_manager.api import meta_rules + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + value = meta_rule_helper.get_body_meta_rule_with_empty_category_in_mid('object') + with pytest.raises(exceptions.ObjectCategoryUnknown) as exception_info: + req = hug.test.post(meta_rules, "/meta_rules", body=value, + headers=auth_headers) + assert str(exception_info.value) == "400: Object Category Unknown" + + +def test_add_meta_rules_with_empty_action_in_mid(): + from moon_manager.api import meta_rules + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + value = meta_rule_helper.get_body_meta_rule_with_empty_category_in_mid('action') + with pytest.raises(exceptions.ActionCategoryUnknown) as exception_info: + req = hug.test.post(meta_rules, "/meta_rules", body=value, + headers=auth_headers) + assert str(exception_info.value) == "400: Action Category Unknown" def test_add_meta_rule_with_existing_name_error(): - client = utilities.register_client() name = uuid4().hex - req, meta_rules = add_meta_rules(client, name) - assert req.status_code == 200 - req, meta_rules = add_meta_rules(client, name) - assert req.status_code == 409 - assert json.loads(req.data)["message"] == '409: Meta Rule Existing' + req, meta_rules = add_meta_rules(name) + assert req.status == hug.HTTP_200 + with pytest.raises(exceptions.MetaRuleExisting) as exception_info: + req, meta_rules = add_meta_rules(name) + assert "409: Meta Rule Existing" == str(exception_info.value) + # assert req.status == hug.HTTP_409 + # assert req.data["message"] == '409: Meta Rule Existing' def test_add_meta_rules_with_forbidden_char_in_name(): - client = utilities.register_client() - req, meta_rules = add_meta_rules(client, "") - assert req.status_code == 400 - assert json.loads(req.data)["message"] == "Key: 'name', [Forbidden characters in string]" + with pytest.raises(exceptions.ValidationContentError) as exception_info: + req, meta_rules = add_meta_rules("") + assert "Key: 'name', [Forbidden characters in string]" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == "Key: 'name', [Forbidden characters in string]" def test_add_meta_rules_with_blank_name(): - client = utilities.register_client() - req, meta_rules = add_meta_rules(client, "") - assert req.status_code == 400 - assert json.loads(req.data)["message"] == '400: Meta Rule Error' + with pytest.raises(exceptions.MetaRuleContentError) as exception_info: + req, meta_rules = add_meta_rules("") + assert "400: Meta Rule Error" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == '400: Meta Rule Error' def test_add_meta_rules_without_subject_categories(): - client = utilities.register_client() name_meta_rule = uuid4().hex - req, meta_rules = add_meta_rules_without_category_ids(client, name_meta_rule) - assert req.status_code == 200 + req, meta_rules = add_meta_rules_without_category_ids(name_meta_rule) + assert req.status == hug.HTTP_200 def test_delete_meta_rules(): - client = utilities.register_client() name_meta_rule = uuid4().hex - req, meta_rules = add_meta_rules_without_category_ids(client, name_meta_rule) + req, meta_rules = add_meta_rules_without_category_ids(name_meta_rule) meta_rule_id = next(iter(meta_rules['meta_rules'])) - req = delete_meta_rules(client, meta_rules['meta_rules'][meta_rule_id]['name']) - assert req.status_code == 200 + req = delete_meta_rules(meta_rules['meta_rules'][meta_rule_id]['name']) + assert req.status == hug.HTTP_200 def test_delete_meta_rules_without_id(): - client = utilities.register_client() - req = delete_meta_rules_without_id(client) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == "400: Meta Rule Unknown" + with pytest.raises(exceptions.MetaRuleUnknown) as exception_info: + req = delete_meta_rules_without_id() + assert "400: Meta Rule Unknown" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == "400: Meta Rule Unknown" def test_update_meta_rules(): - client = utilities.register_client() - req = add_meta_rules(client, "testuser") + name = "testuser" + uuid4().hex + req = add_meta_rules(name) + meta_rule_id = list(req[1]['meta_rules'])[0] + req_update = update_meta_rules(name, meta_rule_id) + assert req_update[0].status == hug.HTTP_200 + delete_meta_rules("testuser") + get_meta_rules() + + +def test_update_meta_rules_empty_name(): + req = add_meta_rules("testuser" + uuid4().hex) + meta_rule_id = list(req[1]['meta_rules'])[0] + with pytest.raises(exceptions.MetaRuleContentError) as exception_info: + req_update = update_meta_rules("", meta_rule_id) + assert "400: Meta Rule Error" == str(exception_info.value) + # assert req_update[0].status == hug.HTTP_400 + # assert req_update[1]['message'] == '400: Meta Rule Error' + + +def test_update_meta_rules_space_name(): + req = add_meta_rules("testuser" + uuid4().hex) meta_rule_id = list(req[1]['meta_rules'])[0] - req_update = update_meta_rules(client, "testuser", meta_rule_id) - assert req_update[0].status_code == 200 - delete_meta_rules(client, "testuser") - get_meta_rules(client) + with pytest.raises(exceptions.MetaRuleContentError) as exception_info: + req_update = update_meta_rules(" ", meta_rule_id) + assert "400: Meta Rule Error" == str(exception_info.value) + # assert req_update[0].status == hug.HTTP_400 + # assert req_update[1]['message'] == '400: Meta Rule Error' def test_update_meta_rule_with_combination_existed(): - client = utilities.register_client() meta_rule_name1 = uuid4().hex - req, meta_rules = add_meta_rules(client, meta_rule_name1) + req, meta_rules = add_meta_rules(meta_rule_name1) meta_rule_id1 = next(iter(meta_rules['meta_rules'])) data1 = meta_rules['meta_rules'][meta_rule_id1] meta_rule_name2 = uuid4().hex - req, meta_rules = add_meta_rules(client, meta_rule_name2) + req, meta_rules = add_meta_rules(meta_rule_name2) meta_rule_id2 = next(iter(meta_rules['meta_rules'])) data2 = meta_rules['meta_rules'][meta_rule_id2] data1['name'] = data2['name'] - req_update = update_meta_rules(client, name=meta_rule_name2, metaRuleId=meta_rule_id2, - data=data1) - assert req_update[0].status_code == 409 - assert req_update[1]['message']== '409: Meta Rule Existing' + with pytest.raises(exceptions.MetaRuleExisting) as exception_info: + req_update = update_meta_rules(name=meta_rule_name2, metaRuleId=meta_rule_id2, + data=data1) + assert "409: Meta Rule Existing" == str(exception_info.value) + # assert req_update[0].status == hug.HTTP_409 + # assert req_update[1]['message'] == '409: Meta Rule Existing' def test_update_meta_rule_with_different_combination_but_same_data(): - client = utilities.register_client() meta_rule_name1 = uuid4().hex subject_category = category_helper.add_subject_category( value={"name": "subject category name" + uuid4().hex, "description": "description 1"}) @@ -316,47 +436,46 @@ def test_update_meta_rule_with_different_combination_but_same_data(): "object_categories": [object_category_id1, object_category_id2], "action_categories": [action_category_id1, action_category_id2] } - req, meta_rules = add_meta_rules(client, meta_rule_name1, data=data) - assert req.status_code == 200 + req, meta_rules = add_meta_rules(meta_rule_name1, data=data) + assert req.status == hug.HTTP_200 meta_rule_name2 = uuid4().hex - req, meta_rules = add_meta_rules(client, meta_rule_name2) + req, meta_rules = add_meta_rules(meta_rule_name2) meta_rule_id2 = next(iter(meta_rules['meta_rules'])) data2 = { "name": meta_rule_name2, "subject_categories": [subject_category_id1, subject_category_id2], "object_categories": [object_category_id1], - "action_categories": [action_category_id1,action_category_id2] + "action_categories": [action_category_id1, action_category_id2] } - req_update = update_meta_rules(client, name=meta_rule_name2, metaRuleId=meta_rule_id2, + req_update = update_meta_rules(name=meta_rule_name2, metaRuleId=meta_rule_id2, data=data2) - assert req_update[0].status_code == 200 + assert req_update[0].status == hug.HTTP_200 def test_update_meta_rules_without_id(): - client = utilities.register_client() - req_update = update_meta_rules(client, "testuser", "") - assert req_update[0].status_code == 400 - assert json.loads(req_update[0].data)["message"] == "400: Meta Rule Unknown" + with pytest.raises(exceptions.MetaRuleUnknown) as exception_info: + req_update = update_meta_rules("testuser", "") + assert "400: Meta Rule Unknown" == str(exception_info.value) + # assert req_update[0].status == hug.HTTP_400 + # assert req_update[0].data["message"] == "400: Meta Rule Unknown" def test_update_meta_rules_without_name(): - client = utilities.register_client() - req_update = update_meta_rules(client, "
", "1234567") - assert req_update[0].status_code == 400 - assert json.loads(req_update[0].data)[ - "message"] == "Key: 'name', [Forbidden characters in string]" + with pytest.raises(exceptions.ValidationContentError) as exception_info: + req_update = update_meta_rules("
", "1234567") + assert "Key: 'name', [Forbidden characters in string]" == str(exception_info.value) + # assert req_update[0].status == hug.HTTP_400 + # assert req_update[0].data["message"] == "Key: 'name', [Forbidden characters in string]" def test_update_meta_rules_without_categories(): - client = utilities.register_client() - req_update = update_meta_rules_with_categories(client, "testuser") - assert req_update[0].status_code == 200 + req_update = update_meta_rules_with_categories("testuser" + uuid4().hex) + assert req_update[0].status == hug.HTTP_200 def test_update_meta_rules_with_empty_categories(): - client = utilities.register_client() subject_category_id, object_category_id, action_category_id, meta_rule_id = data_builder.create_new_meta_rule() data = { "name": "testuser", @@ -364,14 +483,73 @@ def test_update_meta_rules_with_empty_categories(): "object_categories": [""], "action_categories": [""] } - req_update = update_meta_rules_with_categories(client, "testuser", data=data, + req_update = update_meta_rules_with_categories("testuser", data=data, + meta_rule_id=meta_rule_id) + assert req_update[0].status == hug.HTTP_200 + # assert "400: Subject Category Unknown" == str(exception_info.value) + # assert req_update[0].status == hug.HTTP_400 + # assert req_update[1]['message'] == '400: Subject Category Unknown' + + +def test_update_meta_rules_with_blank_subject_categories(): + subject_category_id, object_category_id, action_category_id, meta_rule_id = data_builder.create_new_meta_rule() + data = { + "name": "testuser1", + "subject_categories": [], + "object_categories": [object_category_id], + "action_categories": [action_category_id] + } + req_update = update_meta_rules_with_categories("testuser", data=data, + meta_rule_id=meta_rule_id) + + assert req_update[0].status == hug.HTTP_200 + + +def test_update_meta_rules_with_blank_object_categories(): + subject_category_id, object_category_id, action_category_id, meta_rule_id = data_builder.create_new_meta_rule() + data = { + "name": "testuser1", + "subject_categories": [subject_category_id], + "object_categories": [], + "action_categories": [action_category_id] + } + req_update = update_meta_rules_with_categories("testuser", data=data, + meta_rule_id=meta_rule_id) + + assert req_update[0].status == hug.HTTP_200 + + +def test_update_meta_rules_with_blank_action_categories(): + subject_category_id, object_category_id, action_category_id, meta_rule_id = data_builder.create_new_meta_rule() + data = { + "name": "testuser1", + "subject_categories": [subject_category_id], + "object_categories": [object_category_id], + "action_categories": [] + } + req_update = update_meta_rules_with_categories("testuser", data=data, meta_rule_id=meta_rule_id) - assert req_update[0].status_code == 400 - assert req_update[1]['message'] == '400: Subject Category Unknown' + + assert req_update[0].status == hug.HTTP_200 + + +def test_update_meta_rules_with_empty_subject_category(): + subject_category_id, object_category_id, action_category_id, meta_rule_id = data_builder.create_new_meta_rule() + data = { + "name": "testuser", + "subject_categories": [""], + "object_categories": [object_category_id], + "action_categories": [action_category_id] + } + req_update = update_meta_rules_with_categories("testuser", data=data, + meta_rule_id=meta_rule_id) + assert req_update[0].status == hug.HTTP_200 + # assert "400: Subject Category Unknown" == str(exception_info.value) + # assert req_update[0].status == hug.HTTP_400 + # assert req_update[1]['message'] == '400: Subject Category Unknown' def test_update_meta_rules_with_empty_action_category(): - client = utilities.register_client() subject_category_id, object_category_id, action_category_id, meta_rule_id = data_builder.create_new_meta_rule() data = { "name": "testuser", @@ -379,14 +557,15 @@ def test_update_meta_rules_with_empty_action_category(): "object_categories": [object_category_id], "action_categories": [""] } - req_update = update_meta_rules_with_categories(client, "testuser", data=data, - meta_rule_id=meta_rule_id) - assert req_update[0].status_code == 400 - assert req_update[1]['message'] == '400: Action Category Unknown' + req_update = update_meta_rules_with_categories("testuser", data=data, + meta_rule_id=meta_rule_id) + assert req_update[0].status == hug.HTTP_200 + # assert "400: Action Category Unknown" == str(exception_info.value) + # assert req_update[0].status == hug.HTTP_400 + # assert req_update[1]['message'] == '400: Action Category Unknown' def test_update_meta_rules_with_empty_object_category(): - client = utilities.register_client() subject_category_id, object_category_id, action_category_id, meta_rule_id = data_builder.create_new_meta_rule() data = { "name": "testuser", @@ -394,14 +573,16 @@ def test_update_meta_rules_with_empty_object_category(): "object_categories": [""], "action_categories": [action_category_id] } - req_update = update_meta_rules_with_categories(client, "testuser", data=data, - meta_rule_id=meta_rule_id) - assert req_update[0].status_code == 400 - assert req_update[1]['message'] == '400: Object Category Unknown' + req_update = update_meta_rules_with_categories("testuser", data=data, + meta_rule_id=meta_rule_id) + + assert req_update[0].status == hug.HTTP_200 + # assert "400: Object Category Unknown" == str(exception_info.value) + # assert req_update[0].status == hug.HTTP_400 + # assert req_update[1]['message'] == '400: Object Category Unknown' def test_update_meta_rules_with_categories_and_one_empty(): - client = utilities.register_client() subject_category_id, object_category_id, action_category_id, meta_rule_id = data_builder.create_new_meta_rule() data = { "name": "testuser", @@ -409,7 +590,98 @@ def test_update_meta_rules_with_categories_and_one_empty(): "object_categories": [object_category_id, ""], "action_categories": [action_category_id, ""] } - req_update = update_meta_rules_with_categories(client, "testuser", data=data, - meta_rule_id=meta_rule_id) - assert req_update[0].status_code == 400 - assert req_update[1]['message'] == '400: Subject Category Unknown' + with pytest.raises(exceptions.SubjectCategoryUnknown) as exception_info: + req_update = update_meta_rules_with_categories("testuser", data=data, + meta_rule_id=meta_rule_id) + assert "400: Subject Category Unknown" == str(exception_info.value) + # assert req_update[0].status == hug.HTTP_400 + # assert req_update[1]['message'] == '400: Subject Category Unknown' + + +def test_add_one_meta_rules_with_different_combination_but_similar_items(): + meta_rule_name1 = uuid4().hex + + subject_category = category_helper.add_subject_category( + value={"name": "subject category name" + uuid4().hex, "description": "description 1"}) + subject_category_id1 = list(subject_category.keys())[0] + + object_category = category_helper.add_object_category( + value={"name": "object category name" + uuid4().hex, "description": "description 1"}) + object_category_id1 = list(object_category.keys())[0] + + action_category = category_helper.add_action_category( + value={"name": "action category name" + uuid4().hex, "description": "description 1"}) + action_category_id1 = list(action_category.keys())[0] + + subject_category = category_helper.add_subject_category( + value={"name": "subject category name" + uuid4().hex, "description": "description 1"}) + subject_category_id2 = list(subject_category.keys())[0] + + object_category = category_helper.add_object_category( + value={"name": "object category name" + uuid4().hex, "description": "description 1"}) + object_category_id2 = list(object_category.keys())[0] + + action_category = category_helper.add_action_category( + value={"name": "action category name" + uuid4().hex, "description": "description 1"}) + action_category_id2 = list(action_category.keys())[0] + + data = { + "name": meta_rule_name1, + "subject_categories": [subject_category_id1, subject_category_id2], + "object_categories": [object_category_id1, object_category_id2], + "action_categories": [action_category_id1, action_category_id2] + } + req, meta_rules = add_meta_rules(meta_rule_name1, data=data) + assert req.status == hug.HTTP_200 + + value = { + "name": "name_model", + "description": "test", + "meta_rules": [next(iter(meta_rules['meta_rules']))] + } + mode_id = next(iter(model_helper.add_model(value=value))) + + value = { + "name": "test_policy" + uuid4().hex, + "model_id": mode_id, + "genre": "authz", + "description": "test", + } + + policy_id = next(iter(policy_helper.add_policies(value=value))) + + data_id_1 = data_builder.create_subject_data(policy_id, subject_category_id1) + data_id_2 = data_builder.create_subject_data(policy_id, subject_category_id2) + data_id_3 = data_builder.create_object_data(policy_id, object_category_id2) + data_id_4 = data_builder.create_object_data(policy_id, object_category_id1) + data_id_5 = data_builder.create_action_data(policy_id, action_category_id1) + data_id_5 = data_builder.create_action_data(policy_id, action_category_id2) + + from moon_utilities.auth_functions import get_api_key_for_user + from falcon import HTTP_200, HTTP_400, HTTP_405, HTTP_409 + + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import policy + + req = hug.test.delete(policy, "policies/{}".format(policy_id), headers=auth_headers) + assert req.status == HTTP_200 + + +def test_update_meta_rules_with_blank_action_categories_assigned_to_used_model(): + from moon_utilities.auth_functions import get_api_key_for_user + from moon_manager.api import meta_rules + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + policies_list = policy_helper.add_policies_with_model() + policy_id = list(policies_list.keys())[0] + model_id = policies_list[policy_id]['model_id'] + models_list = model_helper.get_models(model_id=model_id) + meta_rule_id = models_list[model_id]["meta_rules"][0] + meta_rules_list = meta_rule_helper.get_meta_rules(meta_rule_id=meta_rule_id); + data = meta_rules_list[meta_rule_id] + + data["action_categories"] = [] + + with pytest.raises(exceptions.MetaRuleUpdateError) as exception_info: + hug.test.patch(meta_rules, "/meta_rules/{}".format(meta_rule_id), body=data, + headers=auth_headers) + assert "400: Meta_Rule Update Error" == str(exception_info.value) diff --git a/moon_manager/tests/unit_python/api/test_models.py b/moon_manager/tests/unit_python/api/test_models.py new file mode 100644 index 00000000..569fe1b4 --- /dev/null +++ b/moon_manager/tests/unit_python/api/test_models.py @@ -0,0 +1,475 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +import json +import hug +import pytest +from moon_utilities import exceptions +from helpers import data_builder as builder +from helpers import policy_helper +from helpers import model_helper +from uuid import uuid4 + + +def get_models(): + from moon_manager.api import models + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + req = hug.test.get(models, "/models", headers=auth_headers) + models = req.data + return req, models + + +def add_models(name, headers, data=None, ): + from moon_manager.api import models + subject_category_id, object_category_id, action_category_id, meta_rule_id = \ + builder.create_new_meta_rule() + if not data: + data = { + "name": name, + "description": "description of {}".format(name), + "meta_rules": [meta_rule_id] + } + headers['Content-Type'] = 'application/json' + req = hug.test.post(models, "/models", body=json.dumps(data), + headers=headers) + models = req.data + return req, models + + +def update_model(name, model_id, headers): + from moon_manager.api import models + subject_category_id, object_category_id, action_category_id, meta_rule_id = \ + builder.create_new_meta_rule() + data = { + "name": name, + "description": "description of {}".format(name), + "meta_rules": [meta_rule_id] + } + headers['Content-Type'] = 'application/json' + req = hug.test.patch(models, "/models/{}".format(model_id), body=json.dumps(data), + headers=headers) + if req.status == hug.HTTP_405: + return req + models = req.data + return req, models + + +def add_model_without_meta_rules_ids(name, headers): + from moon_manager.api import models + data = { + "name": name, + "description": "description of {}".format(name), + "meta_rules": [] + } + headers['Content-Type'] = 'application/json' + req = hug.test.post(models, "/models", body=json.dumps(data), + headers=headers) + models = req.data + return req, models + + +def add_model_with_empty_meta_rule_id(name, headers): + from moon_manager.api import models + data = { + "name": name, + "description": "description of {}".format(name), + "meta_rules": [""] + } + headers['Content-Type'] = 'application/json' + req = hug.test.post(models, "/models", body=json.dumps(data), + headers=headers) + models = req.data + return req, models + + +def update_model_without_meta_rules_ids(model_id, headers): + from moon_manager.api import models + name = "model_id" + uuid4().hex + data = { + "name": name, + "description": "description of {}".format(name), + "meta_rules": [] + } + headers['Content-Type'] = 'application/json' + req = hug.test.patch(models, "/models/{}".format(model_id), body=json.dumps(data), + headers=headers) + models = req.data + return req, models + + +def delete_models(name, headers): + request, models = get_models() + for key, value in models['models'].items(): + if value['name'] == name: + from moon_manager.api import models + req = hug.test.delete(models, "/models/{}".format(key), headers=headers) + break + return req + + +def delete_models_without_id(headers): + from moon_manager.api import models + req = hug.test.delete(models, "/models/{}".format(""), headers=headers) + return req + + +def clean_models(headers): + req, models = get_models() + for key, value in models['models'].items(): + print(key) + print(value) + from moon_manager.api import models + hug.test.delete(models, "/models/{}".format(key), headers=headers) + + +def test_delete_model_assigned_to_policy(): + policy_name = "testuser" + uuid4().hex + req = model_helper.add_model(model_id="mls_model_id" + uuid4().hex) + model_id = list(req.keys())[0] + data = { + "name": policy_name, + "description": "description of {}".format(policy_name), + "model_id": model_id, + "genre": "genre" + } + from moon_manager.api import policy + from moon_manager.api import models + from moon_utilities.auth_functions import get_api_key_for_user + headers = {"X-Api-Key": get_api_key_for_user("admin"), 'Content-Type': 'application/json'} + hug.test.post(policy, "/policies", body=json.dumps(data), headers=headers) + with pytest.raises(exceptions.DeleteModelWithPolicy) as exception_info: + req = hug.test.delete(models, "/models/{}".format(model_id), headers={"X-Api-Key": + get_api_key_for_user("admin")}) + assert "400: Model With Policy Error" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == '400: Model With Policy Error' + + +def test_get_models(): + req, models = get_models() + assert req.status == hug.HTTP_200 + assert isinstance(models, dict) + assert "models" in models + + +def test_add_models(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + clean_models(headers=auth_headers) + req, models = add_models("testuser", auth_headers) + assert req.status == hug.HTTP_200 + assert isinstance(models, dict) + model_id = list(models["models"])[0] + assert "models" in models + assert models['models'][model_id]['name'] == "testuser" + assert models['models'][model_id]["description"] == "description of {}".format("testuser") + + +def test_add_models_with_meta_rule_has_blank_subject(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + clean_models(headers=auth_headers) + name = "testuser1" + from moon_manager.api import models + subject_category_id, object_category_id, action_category_id, meta_rule_id = \ + builder.create_new_meta_rule(empty="subject") + data = { + "name": name, + "description": "description of {}".format(name), + "meta_rules": [meta_rule_id] + } + auth_headers['Content-Type'] = 'application/json' + req = hug.test.post(models, "/models", body=json.dumps(data), + headers=auth_headers) + assert req.status == hug.HTTP_200 + + +def test_add_models_with_meta_rule_has_blank_object(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + clean_models(headers=auth_headers) + name = "testuser1" + from moon_manager.api import models + subject_category_id, object_category_id, action_category_id, meta_rule_id = \ + builder.create_new_meta_rule(empty="object") + data = { + "name": name, + "description": "description of {}".format(name), + "meta_rules": [meta_rule_id] + } + auth_headers['Content-Type'] = 'application/json' + req = hug.test.post(models, "/models", body=json.dumps(data), + headers=auth_headers) + assert req.status == hug.HTTP_200 + + +def test_add_models_with_meta_rule_has_blank_action(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + clean_models(headers=auth_headers) + name = "testuser1" + from moon_manager.api import models + subject_category_id, object_category_id, action_category_id, meta_rule_id = \ + builder.create_new_meta_rule(empty="action") + data = { + "name": name, + "description": "description of {}".format(name), + "meta_rules": [meta_rule_id] + } + auth_headers['Content-Type'] = 'application/json' + req = hug.test.post(models, "/models", body=json.dumps(data), + headers=auth_headers) + assert req.status == hug.HTTP_200 + + +def test_delete_models(): + name = uuid4().hex + "testuser" + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + add_models(name, auth_headers) + req = delete_models(name, headers=auth_headers) + assert req.status == hug.HTTP_200 + + +def test_update_models_with_assigned_policy(): + from moon_manager.api import models + model = model_helper.add_model(model_id="mls_model_id" + uuid4().hex) + model_id = list(model.keys())[0] + value = { + "name": "test_policy" + uuid4().hex, + "model_id": model_id, + "description": "test", + } + policy_helper.add_policies(value=value) + data = { + "name": "model_" + uuid4().hex, + "description": "description of model_2", + "meta_rules": [] + } + from moon_utilities.auth_functions import get_api_key_for_user + headers = {"X-Api-Key": get_api_key_for_user("admin"), 'Content-Type': 'application/json'} + with pytest.raises(exceptions.DeleteModelWithPolicy) as exception_info: + req = hug.test.patch(models, "/models/{}".format(model_id), body=json.dumps(data), + headers=headers) + assert "400: Model With Policy Error" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == "400: Model With Policy Error" + + +def test_update_models_with_no_assigned_policy(): + from moon_manager.api import models + model = model_helper.add_model(model_id="mls_model_id" + uuid4().hex) + model_id = list(model.keys())[0] + data = { + "name": "model_" + uuid4().hex, + "description": "description of model_2", + "meta_rules": [] + } + from moon_utilities.auth_functions import get_api_key_for_user + headers = {"X-Api-Key": get_api_key_for_user("admin"), 'Content-Type': 'application/json'} + req = hug.test.patch(models, "/models/{}".format(model_id), body=json.dumps(data), + headers=headers) + assert req.status == hug.HTTP_200 + + +def test_update_models_without_meta_rule_key(): + from moon_manager.api import models + model = model_helper.add_model(model_id="mls_model_id" + uuid4().hex) + model_id = list(model.keys())[0] + + data = { + "name": "model_" + uuid4().hex, + "description": "description of model_2", + } + from moon_utilities.auth_functions import get_api_key_for_user + headers = {"X-Api-Key": get_api_key_for_user("admin"), 'Content-Type': 'application/json'} + with pytest.raises(exceptions.MetaRuleUnknown) as exception_info: + req = hug.test.patch(models, "/models/{}".format(model_id), body=json.dumps(data), + headers=headers) + assert "400: Meta Rule Unknown" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == "400: Meta Rule Unknown" + + +def test_delete_models_without_id(): + from moon_utilities.auth_functions import get_api_key_for_user + headers = {"X-Api-Key": get_api_key_for_user("admin")} + req = delete_models_without_id(headers=headers) + assert req.status == hug.HTTP_405 + + +def test_add_model_with_empty_name(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + clean_models(headers=auth_headers) + with pytest.raises(exceptions.ValidationContentError) as exception_info: + req, models = add_models("
", headers=auth_headers) + assert "Key: 'name', [Forbidden characters in string]" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == "Key: 'name', [Forbidden characters in string]" + + +def test_add_model_with_name_contain_space(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + clean_models(headers=auth_headers) + with pytest.raises(exceptions.ValidationContentError) as exception_info: + req, models = add_models("test
user", headers=auth_headers) + assert "Key: 'name', [Forbidden characters in string]" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == "Key: 'name', [Forbidden characters in string]" + + +def test_add_model_with_name_space(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + clean_models(headers=auth_headers) + with pytest.raises(exceptions.ModelContentError) as exception_info: + req, models = add_models(" ", headers=auth_headers) + assert "400: Model Unknown" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == '400: Model Unknown' + + +def test_add_model_with_empty_meta_rule_id(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + clean_models(headers=auth_headers) + with pytest.raises(exceptions.MetaRuleUnknown) as exception_info: + req, meta_rules = add_model_with_empty_meta_rule_id("testuser", headers=auth_headers) + assert "400: Meta Rule Unknown" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == '400: Meta Rule Unknown' + + +def test_add_model_with_existed_name(): + name = uuid4().hex + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + clean_models(headers=auth_headers) + req, models = add_models(name, headers=auth_headers) + assert req.status == hug.HTTP_200 + with pytest.raises(exceptions.ModelExisting) as exception_info: + req, models = add_models(name, headers=auth_headers) + assert "409: Model Error" == str(exception_info.value) + # assert req.status == hug.HTTP_409 + # assert req.data["message"] == '409: Model Error' + + +def test_add_model_with_existed_meta_rules_list(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + clean_models(headers=auth_headers) + name = uuid4().hex + subject_category_id, object_category_id, action_category_id, meta_rule_id = \ + builder.create_new_meta_rule() + data = { + "name": name, + "description": "description of {}".format(name), + "meta_rules": [meta_rule_id] + } + name = uuid4().hex + req, models = add_models(name=name, headers=auth_headers, data=data) + assert req.status == hug.HTTP_200 + data = { + "name": name, + "description": "description of {}".format(name), + "meta_rules": [meta_rule_id] + } + with pytest.raises(exceptions.ModelExisting) as exception_info: + req, models = add_models(name=name, headers=auth_headers, data=data) + assert "409: Model Error" == str(exception_info.value) + # assert req.status == hug.HTTP_409 + # assert req.data["message"] == '409: Model Error' + + +def test_add_model_without_meta_rules(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + clean_models(headers=auth_headers) + req, meta_rules = add_model_without_meta_rules_ids("testuser", headers=auth_headers) + assert req.status == hug.HTTP_200 + + +def test_update_model(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + clean_models(headers=auth_headers) + req = add_models("testuser", headers=auth_headers) + model_id = list(req[1]['models'])[0] + req_update = update_model("testuser", model_id, headers=auth_headers) + assert req_update[0].status == hug.HTTP_200 + model_id = list(req_update[1]["models"])[0] + assert req_update[1]["models"][model_id]["meta_rules"][0] is not None + delete_models("testuser", headers=auth_headers) + + +def test_update_model_name_with_space(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + clean_models(headers=auth_headers) + req = add_models("testuser", headers=auth_headers) + model_id = list(req[1]['models'])[0] + with pytest.raises(exceptions.ModelContentError) as exception_info: + req_update = update_model(" ", model_id, headers=auth_headers) + assert "400: Model Unknown" == str(exception_info.value) + # assert req_update[0].status == hug.HTTP_400 + # assert req_update[1]["message"] == '400: Model Unknown' + + +def test_update_model_with_empty_name(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + clean_models(headers=auth_headers) + req = add_models("testuser", headers=auth_headers) + model_id = list(req[1]['models'])[0] + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + with pytest.raises(exceptions.ModelContentError) as exception_info: + req_update = update_model("", model_id, headers=auth_headers) + assert "400: Model Unknown" == str(exception_info.value) + # assert req_update[0].status == hug.HTTP_400 + # assert req_update[1]['message'] == '400: Model Unknown' + + +def test_update_meta_rules_without_id(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + clean_models(headers=auth_headers) + req_update = update_model("testuser", "", headers=auth_headers) + assert req_update.status == hug.HTTP_405 + + +def test_update_meta_rules_without_name(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + with pytest.raises(exceptions.ValidationContentError) as exception_info: + req_update = update_model("
", "1234567", headers=auth_headers) + assert "Key: 'name', [Forbidden characters in string]" == str(exception_info.value) + # assert req_update[0].status == hug.HTTP_400 + # assert req_update[0].data["message"] == "Key: 'name', [Forbidden characters in string]" + + +def test_update_meta_rules_without_meta_rules(): + value = { + "name": "mls_model_id" + uuid4().hex, + "description": "test", + "meta_rules": [] + } + model = model_helper.add_model(value=value) + model_id = list(model.keys())[0] + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + req_update = update_model_without_meta_rules_ids(model_id, headers=auth_headers) + assert req_update[0].status == hug.HTTP_200 diff --git a/moon_manager/tests/unit_python/api/test_nova.py b/moon_manager/tests/unit_python/api/test_nova.py new file mode 100644 index 00000000..10118cc3 --- /dev/null +++ b/moon_manager/tests/unit_python/api/test_nova.py @@ -0,0 +1,58 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + + +def create_project(tenant_dict): + from moon_manager.pip_driver import InformationManager + return InformationManager["objects"][0].create_project(**tenant_dict) + + +def list_projects(): + from moon_manager.pip_driver import InformationManager + return InformationManager["objects"][0].get_projects() + + +def list_objects(): + from moon_manager.pip_driver import InformationManager + print(f"IM : {InformationManager['objects'][0].driver.__dict__}") + return InformationManager["objects"][0].get_items() + + +def test_create_project(): + tenant_dict = { + "description": "test_project", + "domain": ['domain_id_1'], + "enabled": True, + "is_domain": False, + "name": 'project_1' + } + project = create_project(tenant_dict) + assert project + assert project.get('name') == tenant_dict.get('name') + + +def test_list_objects(): + objects = list_objects() + assert objects + assert objects["servers"][0].get('name') == "vm1" + +# TODO TO BE UPDATED +# def test_create_project_without_name(): +# tenant_dict = { +# "description": "test_project", +# "domain_id": ['domain_id_1'], +# "enabled": True, +# "is_domain": False, +# } +# with pytest.raises(Exception) as exception_info: +# create_project(tenant_dict) +# assert '400: Keystone project error' == str(exception_info.value) diff --git a/moon_manager/tests/unit_python/api/test_pdp.py b/moon_manager/tests/unit_python/api/test_pdp.py index 53a87b21..32b75726 100644 --- a/moon_manager/tests/unit_python/api/test_pdp.py +++ b/moon_manager/tests/unit_python/api/test_pdp.py @@ -1,48 +1,135 @@ -import json -import api.utilities as utilities -from helpers import data_builder as builder -from uuid import uuid4 +# Software Name: MOON +# Version: 5.4 -def get_pdp(client): - req = client.get("/pdp") - pdp = utilities.get_json(req.data) - return req, pdp +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. -def add_pdp(client, data): - req = client.post("/pdp", data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - pdp = utilities.get_json(req.data) - return req, pdp +from falcon import HTTP_200, HTTP_400, HTTP_405 +import hug +import pytest +from moon_utilities import exceptions +from uuid import uuid4 +from helpers import data_builder as builder -def update_pdp(client, data, pdp_id): - req = client.patch("/pdp/{}".format(pdp_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - pdp = utilities.get_json(req.data) - return req, pdp +def test_get_pdp(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import pdp + req = hug.test.get(pdp, 'pdp/', headers=auth_headers) + assert req.status == HTTP_200 + assert isinstance(req.data, dict) + assert "pdps" in req.data -def delete_pdp(client, key): - req = client.delete("/pdp/{}".format(key)) - return req +def test_add_pdp_invalid_security_pipeline(mocker): + from moon_manager.api import pdp + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + mocker.patch('moon_manager.plugins.pyorchestrator.get_server_url', + return_value="http://127.0.0.1:20000") + mocker.patch("subprocess.Popen", return_value=True) + subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = builder.create_new_policy( + subject_category_name="subject_category1" + uuid4().hex, + object_category_name="object_category1" + uuid4().hex, + action_category_name="action_category1" + uuid4().hex, + meta_rule_name="meta_rule_1" + uuid4().hex, + model_name="model1" + uuid4().hex) + data_no_pipeline = { + "name": "testuser" + uuid4().hex, + "security_pipeline": [], + "vim_project_id": "vim_project_id", + "description": "description of testuser" + } + data_no_project_no_pipeline = { + "name": "testuser" + uuid4().hex, + "security_pipeline": [], + "vim_project_id": None, + "description": "description of testuser" + } + data_no_project = { + "name": "testuser" + uuid4().hex, + "security_pipeline": [policy_id], + "vim_project_id": None, + "description": "description of testuser" + } + + req = hug.test.post(pdp, "pdp/", data_no_project_no_pipeline, headers=auth_headers) + assert req.status == HTTP_200 + with pytest.raises(exceptions.PdpContentError) as exception_info: + req = hug.test.post(pdp, "pdp/", data_no_pipeline, headers=auth_headers) + assert "400: Pdp Error" == str(exception_info.value) -def delete_pdp_without_id(client): - req = client.delete("/pdp/{}".format("")) - return req + with pytest.raises(exceptions.PdpContentError) as exception_info: + req = hug.test.post(pdp, "pdp/", data_no_project, headers=auth_headers) + assert "400: Pdp Error" == str(exception_info.value) +def test_update_pdp_invalid_security_pipeline(mocker): + from moon_manager.api import pdp + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + mocker.patch('moon_manager.plugins.pyorchestrator.get_server_url', + return_value="http://127.0.0.1:20000") + mocker.patch("subprocess.Popen", return_value=True) + subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = builder.create_new_policy( + subject_category_name="subject_category1" + uuid4().hex, + object_category_name="object_category1" + uuid4().hex, + action_category_name="action_category1" + uuid4().hex, + meta_rule_name="meta_rule_1" + uuid4().hex, + model_name="model1" + uuid4().hex) + data_no_pipeline = { + "name": "testuser" + uuid4().hex, + "security_pipeline": [], + "vim_project_id": "vim_project_id", + "description": "description of testuser" + } + data_no_project_no_pipeline = { + "name": "testuser" + uuid4().hex, + "security_pipeline": [], + "vim_project_id": None, + "description": "description of testuser" + } + data_no_project = { + "name": "testuser" + uuid4().hex, + "security_pipeline": [policy_id], + "vim_project_id": None, + "description": "description of testuser" + } -def test_get_pdp(): - client = utilities.register_client() - req, pdp = get_pdp(client) - assert req.status_code == 200 - assert isinstance(pdp, dict) - assert "pdps" in pdp + data_valid = { + "name": "testuser" + uuid4().hex, + "security_pipeline": [policy_id], + "vim_project_id": "vim_project_id", + "description": "description of testuser" + } + req = hug.test.post(pdp, "pdp/", data_valid, headers=auth_headers) + assert req.status == HTTP_200 + pip_id = list(req.data['pdps'])[0] + + req = hug.test.patch(pdp, "pdp/{}".format(pip_id), data_no_project_no_pipeline, headers=auth_headers) + assert req.status == HTTP_200 + with pytest.raises(exceptions.PdpContentError) as exception_info: + req = hug.test.patch(pdp, "pdp/{}".format(pip_id), data_no_pipeline, headers=auth_headers) + assert "400: Pdp Error" == str(exception_info.value) -def test_add_pdp(): + with pytest.raises(exceptions.PdpContentError) as exception_info: + req = hug.test.patch(pdp, "pdp/{}".format(pip_id), data_no_project, headers=auth_headers) + assert "400: Pdp Error" == str(exception_info.value) + +def test_add_pdp(mocker): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import pdp + mocker.patch('moon_manager.plugins.pyorchestrator.get_server_url', + return_value="http://127.0.0.1:20000") + mocker.patch("subprocess.Popen", return_value=True) subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = builder.create_new_policy( subject_category_name="subject_category1" + uuid4().hex, object_category_name="object_category1" + uuid4().hex, @@ -50,71 +137,182 @@ def test_add_pdp(): meta_rule_name="meta_rule_1" + uuid4().hex, model_name="model1" + uuid4().hex) data = { - "name": "testuser", + "name": "testuser" + uuid4().hex, "security_pipeline": [policy_id], - "keystone_project_id": "keystone_project_id", + "vim_project_id": "vim_project_id", "description": "description of testuser" } - client = utilities.register_client() - req, pdp = add_pdp(client, data) - assert req.status_code == 200 - assert isinstance(pdp, dict) - value = list(pdp["pdps"].values())[0] - assert "pdps" in pdp - assert value['name'] == "testuser" - assert value["description"] == "description of {}".format("testuser") - assert value["keystone_project_id"] == "keystone_project_id" + req = hug.test.post(pdp, "pdp/", data, headers=auth_headers) + assert req.status == HTTP_200 + assert isinstance(req.data, dict) + found = False + assert "pdps" in req.data + for value in req.data["pdps"].values(): + if value['name'] == data['name']: + found = True + assert value["description"] == "description of {}".format("testuser") + assert value["vim_project_id"] == "vim_project_id" + break + assert found -def test_delete_pdp(): - client = utilities.register_client() - request, pdp = get_pdp(client) - success_req = None - for key, value in pdp['pdps'].items(): - if value['name'] == "testuser": - success_req = delete_pdp(client, key) - break - assert success_req - assert success_req.status_code == 200 +def test_add_pdp_name_existed(mocker): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import pdp + mocker.patch('moon_manager.plugins.pyorchestrator.get_server_url', + return_value="http://127.0.0.1:20000") + mocker.patch("subprocess.Popen", return_value=True) + subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id1 = builder.create_new_policy( + subject_category_name="subject_category1" + uuid4().hex, + object_category_name="object_category1" + uuid4().hex, + action_category_name="action_category1" + uuid4().hex, + meta_rule_name="meta_rule_1" + uuid4().hex, + model_name="model1" + uuid4().hex) + name = "testuser" + uuid4().hex + data = { + "name": name, + "security_pipeline": [policy_id1], + "vim_project_id": "vim_project_id", + "description": "description of testuser" + } + req = hug.test.post(pdp, "pdp/", data, headers=auth_headers) + assert req.status == HTTP_200 + + subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id2 = builder.create_new_policy( + subject_category_name="subject_category1" + uuid4().hex, + object_category_name="object_category1" + uuid4().hex, + action_category_name="action_category1" + uuid4().hex, + meta_rule_name="meta_rule_1" + uuid4().hex, + model_name="model1" + uuid4().hex) -def test_add_pdp_with_forbidden_char_in_user(): data = { - "name": "", - "security_pipeline": ["policy_id_1", "policy_id_2"], - "keystone_project_id": "keystone_project_id", + "name": name, + "security_pipeline": [policy_id2], + "vim_project_id": "vim_project_id" + uuid4().hex, + "description": "description of testuser" + uuid4().hex + } + with pytest.raises(exceptions.PdpExisting) as exception_info: + req = hug.test.post(pdp, "pdp/", data, headers=auth_headers) + assert "409: Pdp Error" == str(exception_info.value) + # assert req.status == hug.HTTP_409 + # assert req.data['message'] == '409: Pdp Error' + + +def test_add_pdp_policy_used(mocker): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import pdp + mocker.patch('moon_manager.plugins.pyorchestrator.get_server_url', + return_value="http://127.0.0.1:20000") + mocker.patch("subprocess.Popen", return_value=True) + subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id1 = builder.create_new_policy( + subject_category_name="subject_category1" + uuid4().hex, + object_category_name="object_category1" + uuid4().hex, + action_category_name="action_category1" + uuid4().hex, + meta_rule_name="meta_rule_1" + uuid4().hex, + model_name="model1" + uuid4().hex) + + data = { + "name": "testuser" + uuid4().hex, + "security_pipeline": [policy_id1], + "vim_project_id": "vim_project_id", "description": "description of testuser" } - client = utilities.register_client() - req, models = add_pdp(client, data) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == "Key: 'name', [Forbidden characters in string]" + req = hug.test.post(pdp, "pdp/", data, headers=auth_headers) + assert req.status == HTTP_200 + + name_uuid = "testuser" + uuid4().hex + data = { + "name": name_uuid, + "security_pipeline": [policy_id1], + "vim_project_id": "vim_project_id " + name_uuid, + "description": "description of testuser " + name_uuid + } + with pytest.raises(exceptions.PdpInUse) as exception_info: + req = hug.test.post(pdp, "pdp/", data, headers=auth_headers) + assert "400: Pdp Inuse" == str(exception_info.value) + # assert req.status == hug.HTTP_409 + # assert req.data['message'] == '409: Pdp Conflict' -def test_add_pdp_with_forbidden_char_in_keystone(): + +def test_delete_pdp(mocker): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import pdp + mocker.patch('moon_manager.plugins.pyorchestrator.get_server_url', + return_value="http://127.0.0.1:20000") + mocker.patch("subprocess.Popen", return_value=True) + subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = builder.create_new_policy( + subject_category_name="subject_category1" + uuid4().hex, + object_category_name="object_category1" + uuid4().hex, + action_category_name="action_category1" + uuid4().hex, + meta_rule_name="meta_rule_1" + uuid4().hex, + model_name="model1" + uuid4().hex) data = { - "name": "testuser", - "security_pipeline": ["policy_id_1", "policy_id_2"], - "keystone_project_id": "", + "name": "testuser" + uuid4().hex, + "security_pipeline": [policy_id], + "vim_project_id": "vim_project_id", "description": "description of testuser" } - client = utilities.register_client() - req, meta_rules = add_pdp(client, data) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == "Key: 'keystone_project_id', [Forbidden characters in string]" + req = hug.test.post(pdp, "pdp/", data, headers=auth_headers) + assert req.status == HTTP_200 + assert isinstance(req.data, dict) + req = hug.test.get(pdp, 'pdp/', headers=auth_headers) + success_req = None + for key, value in req.data['pdps'].items(): + if value['name'] == data['name']: + success_req = hug.test.delete(pdp, 'pdp/{}'.format(key), headers=auth_headers) + break + assert success_req + assert success_req.status == HTTP_200 + +# Fixme: should re-enabled the input validation for those tests +# def test_add_pdp_with_forbidden_char_in_user(): +# data = { +# "name": "", +# "security_pipeline": ["policy_id_1", "policy_id_2"], +# "vim_project_id": "vim_project_id", +# "description": "description of testuser" +# } +# req = hug.test.post(pdp, "pdp/", data) +# assert req.status == HTTP_400 +# print(req.data) +# assert req.data["message"] == "Key: 'name', [Forbidden characters in string]" +# +# +# def test_add_pdp_with_forbidden_char_in_keystone(): +# data = { +# "name": "testuser", +# "security_pipeline": ["policy_id_1", "policy_id_2"], +# "vim_project_id": "", +# "description": "description of testuser" +# } +# req = hug.test.post(pdp, "pdp/", data) +# assert req.status == 400 +# assert req.data["message"] == "Key: 'vim_project_id', [Forbidden characters in string]" -def test_update_pdp(): + +def test_update_pdp(mocker): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import pdp + mocker.patch('moon_manager.plugins.pyorchestrator.get_server_url', + return_value="http://127.0.0.1:20000") + mocker.patch("subprocess.Popen", return_value=True) subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = builder.create_new_policy( - subject_category_name="subject_category1"+uuid4().hex, - object_category_name="object_category1"+uuid4().hex, - action_category_name="action_category1"+uuid4().hex, - meta_rule_name="meta_rule_1"+uuid4().hex, - model_name="model1"+uuid4().hex) + subject_category_name="subject_category1" + uuid4().hex, + object_category_name="object_category1" + uuid4().hex, + action_category_name="action_category1" + uuid4().hex, + meta_rule_name="meta_rule_1" + uuid4().hex, + model_name="model1" + uuid4().hex) data_add = { "name": "testuser", "security_pipeline": [policy_id], - "keystone_project_id": "keystone_project_id", + "vim_project_id": "vim_project_id", "description": "description of testuser" } @@ -125,40 +323,157 @@ def test_update_pdp(): meta_rule_name="meta_rule_1" + uuid4().hex, model_name="model1" + uuid4().hex) data_update = { - "name": "testuser", + "name": "testuser_updated", "security_pipeline": [policy_id_update], - "keystone_project_id": "keystone_project_id_update", - "description": "description of testuser" + "vim_project_id": "vim_project_id_update", + "description": "description of testuser_updated" } - client = utilities.register_client() - req = add_pdp(client, data_add) - pdp_id = list(req[1]['pdps'])[0] - req_update = update_pdp(client, data_update, pdp_id) - assert req_update[0].status_code == 200 - value = list(req_update[1]["pdps"].values())[0] - assert value["keystone_project_id"] == "keystone_project_id_update" - request, pdp = get_pdp(client) - for key, value in pdp['pdps'].items(): + req = hug.test.post(pdp, "pdp/", data_add, headers=auth_headers) + pdp_id = list(req.data['pdps'])[0] + req_update = hug.test.patch(pdp, "pdp/{}".format(pdp_id), data_update, headers=auth_headers) + assert req_update.status == HTTP_200 + value = list(req_update.data["pdps"].values())[0] + assert value["vim_project_id"] == data_update["vim_project_id"] + assert value["description"] == data_update["description"] + assert value["name"] == data_update['name'] + assert value["security_pipeline"] == data_update['security_pipeline'] + req = hug.test.get(pdp, 'pdp/', headers=auth_headers) + for key, value in req.data['pdps'].items(): if value['name'] == "testuser": - delete_pdp(client, key) + hug.test.delete(pdp, 'pdp/{}'.format(key), headers=auth_headers) break -def test_update_pdp_without_id(): - client = utilities.register_client() - req_update = update_pdp(client, "testuser", "") - assert req_update[0].status_code == 400 - assert json.loads(req_update[0].data)["message"] == 'Invalid Key :name not found' +def test_update_pdp_without_id(mocker): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import pdp + mocker.patch('moon_manager.plugins.pyorchestrator.get_server_url', + return_value="http://127.0.0.1:20000") + mocker.patch("subprocess.Popen", return_value=True) + req = hug.test.patch(pdp, "pdp/", "testuser", headers=auth_headers) + assert req.status == HTTP_405 + # assert req.data["message"] == 'Invalid Key :name not found' -def test_update_pdp_without_user(): +def test_update_pdp_without_user(mocker): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import pdp + mocker.patch('moon_manager.plugins.pyorchestrator.get_server_url', + return_value="http://127.0.0.1:20000") + mocker.patch("subprocess.Popen", return_value=True) data = { "name": "", "security_pipeline": ["policy_id_1", "policy_id_2"], - "keystone_project_id": "keystone_project_id", + "vim_project_id": "vim_project_id", "description": "description of testuser" } - client = utilities.register_client() - req_update = update_pdp(client, data, "") - assert req_update[0].status_code == 400 - assert json.loads(req_update[0].data)["message"] == "Forbidden characters in string" + req = hug.test.patch(pdp, "pdp/", data, headers=auth_headers) + assert req.status == HTTP_400 + print(req.data) + assert req.data["errors"] == {'uuid': 'Invalid UUID provided'} + + +def test_update_pdp_name_existed(mocker): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import pdp + mocker.patch('moon_manager.plugins.pyorchestrator.get_server_url', + return_value="http://127.0.0.1:20000") + mocker.patch("subprocess.Popen", return_value=True) + subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id1 = builder.create_new_policy( + subject_category_name="subject_category1" + uuid4().hex, + object_category_name="object_category1" + uuid4().hex, + action_category_name="action_category1" + uuid4().hex, + meta_rule_name="meta_rule_1" + uuid4().hex, + model_name="model1" + uuid4().hex) + uuid1 = uuid4().hex + data1 = { + "name": "testuser1" + uuid1, + "security_pipeline": [policy_id1], + "vim_project_id": "vim_project_id" + uuid1, + "description": "description of testuser1" + uuid1 + } + req = hug.test.post(pdp, "pdp/", data1, headers=auth_headers) + assert req.status == HTTP_200 + + subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id2 = builder.create_new_policy( + subject_category_name="subject_category1" + uuid4().hex, + object_category_name="object_category1" + uuid4().hex, + action_category_name="action_category1" + uuid4().hex, + meta_rule_name="meta_rule_1" + uuid4().hex, + model_name="model1" + uuid4().hex) + + uuid2 = uuid4().hex + data2 = { + "name": "testuser2" + uuid2, + "security_pipeline": [policy_id2], + "vim_project_id": "vim_project_id" + uuid2, + "description": "description of testuser2" + uuid2 + } + req = hug.test.post(pdp, "pdp/", data2, headers=auth_headers) + pdp_id = list(req.data['pdps'])[0] + for item in list(req.data['pdps']): + if req.data['pdps'][item]['name']==data2['name']: + pdp_id=item + break + data2['name'] = data1['name'] + with pytest.raises(exceptions.PdpExisting) as exception_info: + req_update = hug.test.patch(pdp, "pdp/{}".format(pdp_id), data2, headers=auth_headers) + # assert req_update.data['message'] == '409: Pdp Error' + assert "409: Pdp Error" == str(exception_info.value) + + + +def test_update_pdp_policy_used(mocker): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import pdp + mocker.patch('moon_manager.plugins.pyorchestrator.get_server_url', + return_value="http://127.0.0.1:20000") + mocker.patch("subprocess.Popen", return_value=True) + subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id1 = builder.create_new_policy( + subject_category_name="subject_category1" + uuid4().hex, + object_category_name="object_category1" + uuid4().hex, + action_category_name="action_category1" + uuid4().hex, + meta_rule_name="meta_rule_1" + uuid4().hex, + model_name="model1" + uuid4().hex) + uuid1 = uuid4().hex + data1 = { + "name": "testuser1" + uuid1, + "security_pipeline": [policy_id1], + "vim_project_id": "vim_project_id" + uuid1, + "description": "description of testuser1" + uuid1 + } + req = hug.test.post(pdp, "pdp/", data1, headers=auth_headers) + assert req.status == HTTP_200 + + subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id2 = builder.create_new_policy( + subject_category_name="subject_category1" + uuid4().hex, + object_category_name="object_category1" + uuid4().hex, + action_category_name="action_category1" + uuid4().hex, + meta_rule_name="meta_rule_1" + uuid4().hex, + model_name="model1" + uuid4().hex) + + uuid2 = uuid4().hex + data2 = { + "name": "testuser2" + uuid2, + "security_pipeline": [policy_id2], + "vim_project_id": "vim_project_id" + uuid2, + "description": "description of testuser2" + uuid2 + } + req = hug.test.post(pdp, "pdp/", data2, headers=auth_headers) + pdp_id = list(req.data['pdps'])[0] + for item in list(req.data['pdps']): + if req.data['pdps'][item]['name']==data2['name']: + pdp_id=item + break + data2['security_pipeline'] = data1['security_pipeline'] + + with pytest.raises(exceptions.PdpInUse) as exception_info: + req_update = hug.test.patch(pdp, "pdp/{}".format(pdp_id), data2, headers=auth_headers) + assert "400: Pdp Inuse" == str(exception_info.value) + # assert req_update.data['message'] == '409: Pdp Conflict' + + diff --git a/moon_manager/tests/unit_python/api/test_perimeter.py b/moon_manager/tests/unit_python/api/test_perimeter.py index ff7b09d7..c741adf7 100644 --- a/moon_manager/tests/unit_python/api/test_perimeter.py +++ b/moon_manager/tests/unit_python/api/test_perimeter.py @@ -1,19 +1,39 @@ -# import moon_manager -# import moon_manager.api -import json +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +import hug import api.utilities as utilities from helpers import data_builder as builder import helpers.policy_helper as policy_helper from uuid import uuid4 +import pytest +from moon_utilities import exceptions + +def get_subjects(subject_id=None): + from moon_manager.api import perimeter + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} -def get_subjects(client): - req = client.get("/subjects") + if not subject_id: + req = hug.test.get(perimeter, 'subjects/', headers=auth_headers) + else: + req = hug.test.get(perimeter, 'subjects/{}'.format(subject_id), headers=auth_headers) subjects = utilities.get_json(req.data) return req, subjects -def add_subjects(client, policy_id, name, perimeter_id=None, data=None): +def add_subjects(policy_id, name, perimeter_id=None, data=None, auth_headers=None): + from moon_manager.api import perimeter if not data: name = name + uuid4().hex data = { @@ -23,44 +43,44 @@ def add_subjects(client, policy_id, name, perimeter_id=None, data=None): "email": "{}@moon".format(name) } if not perimeter_id: - req = client.post("/policies/{}/subjects".format(policy_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) + req = hug.test.post(perimeter, "/policies/{}/subjects".format(policy_id), + body=data, headers=auth_headers) else: - req = client.post("/policies/{}/subjects/{}".format(policy_id, perimeter_id), - data=json.dumps( - data), - headers={'Content-Type': 'application/json'}) + req = hug.test.post(perimeter, "/policies/{}/subjects/{}".format(policy_id, perimeter_id), + body=data, headers=auth_headers) subjects = utilities.get_json(req.data) return req, subjects -def delete_subjects_without_perimeter_id(client): - req = client.delete("/subjects/{}".format("")) +def delete_subjects_without_perimeter_id(auth_headers=None): + from moon_manager.api import perimeter + req = hug.test.delete(perimeter, "/subjects/{}".format(""), headers=auth_headers) return req def test_perimeter_get_subject(): - client = utilities.register_client() - req, subjects = get_subjects(client) - assert req.status_code == 200 + req, subjects = get_subjects() + assert req.status == hug.HTTP_200 assert isinstance(subjects, dict) assert "subjects" in subjects def test_perimeter_add_subject(): - client = utilities.register_client() + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} policies = policy_helper.add_policies() policy_id = list(policies.keys())[0] - req, subjects = add_subjects(client, policy_id, "testuser") + req, subjects = add_subjects(policy_id, "testuser", auth_headers=auth_headers) value = list(subjects["subjects"].values())[0] - assert req.status_code == 200 + assert req.status == hug.HTTP_200 assert value["name"] assert value["email"] def test_perimeter_add_same_subject_perimeter_id_with_new_policy_id(): - client = utilities.register_client() + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} policies1 = policy_helper.add_policies() policy_id1 = list(policies1.keys())[0] name = "testuser" @@ -71,13 +91,15 @@ def test_perimeter_add_same_subject_perimeter_id_with_new_policy_id(): "password": "password for {}".format(name), "email": "{}@moon".format(name) } - add_subjects(client, policy_id1, data['name'], perimeter_id=perimeter_id, data=data) + add_subjects(policy_id1, data['name'], perimeter_id=perimeter_id, data=data, + auth_headers=auth_headers) policies2 = policy_helper.add_policies() policy_id2 = list(policies2.keys())[0] - req, subjects = add_subjects(client, policy_id2, data['name'], - perimeter_id=perimeter_id, data=data) + req, subjects = add_subjects(policy_id2, data['name'], + perimeter_id=perimeter_id, data=data, + auth_headers=auth_headers) value = list(subjects["subjects"].values())[0] - assert req.status_code == 200 + assert req.status == hug.HTTP_200 assert value["name"] assert value["email"] assert len(value['policy_list']) == 2 @@ -86,20 +108,25 @@ def test_perimeter_add_same_subject_perimeter_id_with_new_policy_id(): def test_perimeter_add_same_subject_perimeter_id_with_different_name(): - client = utilities.register_client() + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} policies1 = policy_helper.add_policies() policy_id1 = list(policies1.keys())[0] perimeter_id = uuid4().hex - add_subjects(client, policy_id1, "testuser", perimeter_id=perimeter_id) + add_subjects(policy_id1, "testuser", perimeter_id=perimeter_id, auth_headers=auth_headers) policies2 = policy_helper.add_policies() policy_id2 = list(policies2.keys())[0] - req, subjects = add_subjects(client, policy_id2, "testuser", perimeter_id=perimeter_id) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == '400: Perimeter content is invalid.' + with pytest.raises(exceptions.PerimeterContentError) as exception_info: + req, subjects = add_subjects(policy_id2, "testuser", perimeter_id=perimeter_id, + auth_headers=auth_headers) + assert "400: Perimeter content is invalid." == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == '400: Perimeter content is invalid.' def test_perimeter_add_same_subject_name_with_new_policy_id(): - client = utilities.register_client() + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} policies1 = policy_helper.add_policies() policy_id1 = list(policies1.keys())[0] perimeter_id = uuid4().hex @@ -110,8 +137,8 @@ def test_perimeter_add_same_subject_name_with_new_policy_id(): "password": "password for {}".format(name), "email": "{}@moon".format(name) } - req, subjects = add_subjects(client, policy_id1, None, perimeter_id=perimeter_id, - data=data) + req, subjects = add_subjects(policy_id1, None, perimeter_id=perimeter_id, data=data, + auth_headers=auth_headers) policies2 = policy_helper.add_policies() policy_id2 = list(policies2.keys())[0] value = list(subjects["subjects"].values())[0] @@ -121,9 +148,9 @@ def test_perimeter_add_same_subject_name_with_new_policy_id(): "password": "password for {}".format(value['name']), "email": "{}@moon".format(value['name']) } - req, subjects = add_subjects(client, policy_id2, None, data=data) + req, subjects = add_subjects(policy_id2, None, data=data, auth_headers=auth_headers) value = list(subjects["subjects"].values())[0] - assert req.status_code == 200 + assert req.status == hug.HTTP_200 assert value["name"] assert value["email"] assert len(value['policy_list']) == 2 @@ -132,7 +159,8 @@ def test_perimeter_add_same_subject_name_with_new_policy_id(): def test_perimeter_add_same_subject_name_with_same_policy_id(): - client = utilities.register_client() + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} policies1 = policy_helper.add_policies() policy_id1 = list(policies1.keys())[0] perimeter_id = uuid4().hex @@ -143,8 +171,8 @@ def test_perimeter_add_same_subject_name_with_same_policy_id(): "password": "password for {}".format(name), "email": "{}@moon".format(name) } - req, subjects = add_subjects(client, policy_id1, None, perimeter_id=perimeter_id, - data=data) + req, subjects = add_subjects(policy_id1, None, perimeter_id=perimeter_id, + data=data, auth_headers=auth_headers) value = list(subjects["subjects"].values())[0] data = { "name": value['name'], @@ -152,31 +180,46 @@ def test_perimeter_add_same_subject_name_with_same_policy_id(): "password": "password for {}".format(value['name']), "email": "{}@moon".format(value['name']) } - req, subjects = add_subjects(client, policy_id1, None, data=data) - assert req.status_code == 409 - assert json.loads(req.data)["message"] == '409: Policy Already Exists' + with pytest.raises(exceptions.PolicyExisting) as exception_info: + req, subjects = add_subjects(policy_id1, None, data=data, auth_headers=auth_headers) + assert "409: Policy Already Exists" == str(exception_info.value) + # assert req.status == hug.HTTP_409 + # assert req.data["message"] == '409: Policy Already Exists' def test_perimeter_add_same_subject_perimeter_id_with_existed_policy_id_in_list(): - client = utilities.register_client() + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import perimeter policies = policy_helper.add_policies() policy_id = list(policies.keys())[0] name = "testuser" + uuid4().hex data = { - "name": name, + "name": name + uuid4().hex, "description": "description of {}".format(name), "password": "password for {}".format(name), "email": "{}@moon".format(name) } - req, subjects = add_subjects(client, policy_id, name, data=data) + subj_id = "b34e5a29-5494-4cc5-9356-daa244b8c254" + req, subjects = get_subjects(subj_id) + if subjects['subjects']: + for __policy_id in subjects['subjects'][subj_id]['policy_list']: + req = hug.test.delete(perimeter, + "/policies/{}/subjects/{}".format(__policy_id, subj_id), + headers=auth_headers) + req, subjects = add_subjects(policy_id, name, data=data, auth_headers=auth_headers) perimeter_id = list(subjects["subjects"].values())[0]['id'] - req, subjects = add_subjects(client, policy_id, name, perimeter_id=perimeter_id, data=data) - assert req.status_code == 409 - assert json.loads(req.data)["message"] == '409: Policy Already Exists' + with pytest.raises(exceptions.PolicyExisting) as exception_info: + req, subjects = add_subjects(policy_id, name, perimeter_id=perimeter_id, data=data, + auth_headers=auth_headers) + assert "409: Policy Already Exists" == str(exception_info.value) + # assert req.status == hug.HTTP_409 + # assert req.data["message"] == '409: Policy Already Exists' def test_perimeter_add_subject_invalid_policy_id(): - client = utilities.register_client() + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} policies = policy_helper.add_policies() policy_id = list(policies.keys())[0] name = "testuser" @@ -186,103 +229,121 @@ def test_perimeter_add_subject_invalid_policy_id(): "password": "password for {}".format(name), "email": "{}@moon".format(name) } - req, subjects = add_subjects(client, policy_id + "0", "testuser", data) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == '400: Policy Unknown' + with pytest.raises(exceptions.PolicyUnknown) as exception_info: + req, subjects = add_subjects( policy_id + "0", "testuser", data, auth_headers=auth_headers) + assert "400: Policy Unknown" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == '400: Policy Unknown' -def test_perimeter_add_subject_policy_id_none(): - client = utilities.register_client() - name = "testuser" - data = { - "name": name + uuid4().hex, - "description": "description of {}".format(name), - "password": "password for {}".format(name), - "email": "{}@moon".format(name) - } - req, subjects = add_subjects(client, None, "testuser", data) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == '400: Policy Unknown' +def test_perimeter_add_subject_blank_data(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import perimeter + policies = policy_helper.add_policies() + policy_id = list(policies.keys())[0] + with pytest.raises(exceptions.ValidationKeyError) as exception_info: + req = hug.test.post(perimeter, "/policies/{}/subjects".format(policy_id), body={'test':"aa"}, + headers=auth_headers) + assert "Invalid Key :name not found" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == 'Invalid Key :name not found' def test_perimeter_add_subject_with_forbidden_char_in_name(): - client = utilities.register_client() + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import perimeter data = { "name": "", "description": "description of {}".format(""), "password": "password for {}".format(""), "email": "{}@moon".format("") } - req = client.post("/policies/{}/subjects".format("111"), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == "Key: 'name', [Forbidden characters in string]" + subj_id = "a34e5a29-5494-4cc5-9356-daa244b8c888" + with pytest.raises(exceptions.ValidationContentError) as exception_info: + req = hug.test.post(perimeter, "/policies/{}/subjects".format(subj_id), body=data, + headers=auth_headers) + assert "Key: 'name', [Forbidden characters in string]" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == "Key: 'name', [Forbidden characters in string]" def test_perimeter_update_subject_name(): - client = utilities.register_client() + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import perimeter policies = policy_helper.add_policies() policy_id = list(policies.keys())[0] - req, subjects = add_subjects(client, policy_id, "testuser") + req, subjects = add_subjects(policy_id, "testuser", auth_headers=auth_headers) value1 = list(subjects["subjects"].values())[0] perimeter_id = value1['id'] data = { 'name': value1['name'] + "update" } - req = client.patch("/subjects/{}".format(perimeter_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) + req = hug.test.patch(perimeter, "/subjects/{}".format(perimeter_id), body=data, + headers=auth_headers) subjects = utilities.get_json(req.data) value2 = list(subjects["subjects"].values())[0] - assert req.status_code == 200 + assert req.status == hug.HTTP_200 assert value1['name'] + 'update' == value2['name'] assert value1['id'] == value2['id'] assert value1['description'] == value2['description'] def test_perimeter_update_subject_description(): - client = utilities.register_client() + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import perimeter policies = policy_helper.add_policies() policy_id = list(policies.keys())[0] - req, subjects = add_subjects(client, policy_id, "testuser") + req, subjects = add_subjects(policy_id, "testuser", auth_headers=auth_headers) value1 = list(subjects["subjects"].values())[0] perimeter_id = value1['id'] data = { 'description': value1['description'] + "update", } - req = client.patch("/subjects/{}".format(perimeter_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) + req = hug.test.patch(perimeter, "/subjects/{}".format(perimeter_id), body=data, + headers=auth_headers) subjects = utilities.get_json(req.data) value2 = list(subjects["subjects"].values())[0] - assert req.status_code == 200 + + assert req.status == hug.HTTP_200 assert value1['name'] == value2['name'] assert value1['id'] == value2['id'] assert value1['description'] + 'update' == value2['description'] def test_perimeter_update_subject_description_and_name(): - client = utilities.register_client() + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import perimeter policies = policy_helper.add_policies() policy_id = list(policies.keys())[0] - req, subjects = add_subjects(client, policy_id, "testuser") + req, subjects = add_subjects(policy_id, "testuser", auth_headers=auth_headers) value1 = list(subjects["subjects"].values())[0] perimeter_id = value1['id'] data = { 'description': value1['description'] + "update", 'name': value1['name'] + "update" } - req = client.patch("/subjects/{}".format(perimeter_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) + from moon_manager.api import perimeter + req = hug.test.patch(perimeter, "/subjects/{}".format(perimeter_id), body=data, + headers=auth_headers) subjects = utilities.get_json(req.data) value2 = list(subjects["subjects"].values())[0] - assert req.status_code == 200 + + assert req.status == hug.HTTP_200 assert value1['name'] + 'update' == value2['name'] assert value1['id'] == value2['id'] assert value1['description'] + 'update' == value2['description'] def test_perimeter_update_subject_wrong_id(): - client = utilities.register_client() + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import perimeter name = 'testuser' + uuid4().hex policies1 = policy_helper.add_policies() policy_id1 = list(policies1.keys())[0] @@ -290,64 +351,83 @@ def test_perimeter_update_subject_wrong_id(): "name": name, "description": "description of {}".format('testuser'), } - req, subjects = add_subjects(client, policy_id=policy_id1, name='testuser', data=data) + req, subjects = add_subjects(policy_id=policy_id1, name='testuser', data=data, + auth_headers=auth_headers) value1 = list(subjects["subjects"].values())[0] perimeter_id = value1['id'] data = { 'name': value1['name'] + "update", 'description': value1['description'] + "update" } - req = client.patch("/subjects/{}".format(perimeter_id + "wrong"), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == '400: Perimeter content is invalid.' + with pytest.raises(exceptions.PerimeterContentError) as exception_info: + req = hug.test.patch(perimeter, "/subjects/{}".format(perimeter_id + "wrong"), + body=data, headers=auth_headers) + assert "400: Perimeter content is invalid." == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == '400: Perimeter content is invalid.' def test_perimeter_update_subject_name_with_existed_one(): - client = utilities.register_client() + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import perimeter name1 = 'testuser' + uuid4().hex policies1 = policy_helper.add_policies() policy_id1 = list(policies1.keys())[0] perimeter_id1 = uuid4().hex - req, subjects = add_subjects(client, policy_id=policy_id1, name=name1, - perimeter_id=perimeter_id1) + req, subjects = add_subjects(policy_id=policy_id1, name=name1, + perimeter_id=perimeter_id1, auth_headers=auth_headers) value1 = list(subjects["subjects"].values())[0] perimeter_id2 = uuid4().hex name2 = 'testuser' + uuid4().hex - req, subjects = add_subjects(client, policy_id=policy_id1, name=name2, - perimeter_id=perimeter_id2) + req, subjects = add_subjects(policy_id=policy_id1, name=name2, + perimeter_id=perimeter_id2, auth_headers=auth_headers) data = { 'name': value1['name'], } - req = client.patch("/subjects/{}".format(perimeter_id2), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - assert req.status_code == 409 + with pytest.raises(exceptions.SubjectExisting) as exception_info: + req = hug.test.patch(perimeter, "/subjects/{}".format(perimeter_id2), body=data, + headers=auth_headers) + assert "409: Subject Existing" == str(exception_info.value) + # assert req.status == hug.HTTP_409 def test_perimeter_delete_subject(): - client = utilities.register_client() + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import perimeter policies = policy_helper.add_policies() policy_id = list(policies.keys())[0] - req, subjects = add_subjects(client, policy_id, "testuser") + req, subjects = add_subjects(policy_id, "testuser", auth_headers=auth_headers) subject_id = list(subjects["subjects"].values())[0]["id"] - req = client.delete("/policies/{}/subjects/{}".format(policy_id, subject_id)) - assert req.status_code == 200 + req = hug.test.delete(perimeter, "/policies/{}/subjects/{}".format(policy_id, subject_id), + headers=auth_headers) + assert req.status == hug.HTTP_200 def test_perimeter_delete_subjects_without_perimeter_id(): - client = utilities.register_client() - req = delete_subjects_without_perimeter_id(client) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == "400: Subject Unknown" + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + with pytest.raises(exceptions.SubjectUnknown) as exception_info: + req = delete_subjects_without_perimeter_id(auth_headers) + assert "400: Subject Unknown" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == "400: Subject Unknown" -def get_objects(client): - req = client.get("/objects") +def get_objects(): + from moon_manager.api import perimeter + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + req = hug.test.get(perimeter, "/objects", headers=auth_headers) objects = utilities.get_json(req.data) return req, objects -def add_objects(client, name, policyId=None, data=None, perimeter_id=None): +def add_objects(name, policyId=None, data=None, perimeter_id=None, auth_headers=None): + from moon_manager.api import perimeter if not policyId: subject_category_id, object_category_id, action_category_id, meta_rule_id, policyId = builder.create_new_policy( subject_category_name="subject_category1" + uuid4().hex, @@ -361,59 +441,70 @@ def add_objects(client, name, policyId=None, data=None, perimeter_id=None): "description": "description of {}".format(name), } if not perimeter_id: - req = client.post("/policies/{}/objects/".format(policyId), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) + req = hug.test.post(perimeter, "/policies/{}/objects/".format(policyId), body=data, + headers=auth_headers) else: - req = client.post("/policies/{}/objects/{}".format(policyId, perimeter_id), - data=json.dumps(data), - headers={'Content-Type': 'application/json'}) + req = hug.test.post(perimeter, "/policies/{}/objects/{}".format(policyId, perimeter_id), + body=data, headers=auth_headers) + objects = utilities.get_json(req.data) return req, objects -def delete_objects_without_perimeter_id(client): - req = client.delete("/objects/{}".format("")) +def delete_objects_without_perimeter_id(auth_headers=None): + from moon_manager.api import perimeter + req = hug.test.delete(perimeter, "/objects/{}".format(""), headers=auth_headers) return req def test_perimeter_get_object(): - client = utilities.register_client() - req, objects = get_objects(client) - assert req.status_code == 200 + + req, objects = get_objects() + assert req.status == hug.HTTP_200 assert isinstance(objects, dict) assert "objects" in objects def test_perimeter_add_object(): - client = utilities.register_client() - req, objects = add_objects(client, "testuser") + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + req, objects = add_objects("testuser", auth_headers=auth_headers) value = list(objects["objects"].values())[0] - assert req.status_code == 200 + assert req.status == hug.HTTP_200 assert value['name'] def test_perimeter_add_object_with_wrong_policy_id(): - client = utilities.register_client() - req, objects = add_objects(client, "testuser", policyId='wrong') - assert req.status_code == 400 - assert json.loads(req.data)["message"] == '400: Policy Unknown' + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + with pytest.raises(exceptions.PolicyUnknown) as exception_info: + req, objects = add_objects("testuser", policyId='wrong', auth_headers=auth_headers) + assert "400: Policy Unknown" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == '400: Policy Unknown' def test_perimeter_add_object_with_policy_id_none(): - client = utilities.register_client() + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import perimeter data = { "name": "testuser" + uuid4().hex, "description": "description of {}".format("testuser"), } - req = client.post("/policies/{}/objects/".format(None), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == '400: Policy Unknown' + with pytest.raises(exceptions.PolicyUnknown) as exception_info: + req = hug.test.post(perimeter, "/policies/{}/objects/".format(None), body=data, + headers=auth_headers) + assert "400: Policy Unknown" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == '400: Policy Unknown' def test_perimeter_add_same_object_name_with_new_policy_id(): - client = utilities.register_client() - req, objects = add_objects(client, "testuser") + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + req, objects = add_objects("testuser", auth_headers=auth_headers) value1 = list(objects["objects"].values())[0] policies1 = policy_helper.add_policies() policy_id1 = list(policies1.keys())[0] @@ -421,16 +512,17 @@ def test_perimeter_add_same_object_name_with_new_policy_id(): "name": value1['name'], "description": "description of {}".format('testuser'), } - req, objects = add_objects(client, 'testuser', policyId=policy_id1, data=data) + req, objects = add_objects('testuser', policyId=policy_id1, data=data, auth_headers=auth_headers) value2 = list(objects["objects"].values())[0] - assert req.status_code == 200 + assert req.status == hug.HTTP_200 assert value1['id'] == value2['id'] assert value1['name'] == value2['name'] def test_perimeter_add_same_object_perimeter_id_with_new_policy_id(): - client = utilities.register_client() - req, objects = add_objects(client, "testuser") + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + req, objects = add_objects( "testuser", auth_headers=auth_headers) value1 = list(objects["objects"].values())[0] policies1 = policy_helper.add_policies() policy_id1 = list(policies1.keys())[0] @@ -438,17 +530,18 @@ def test_perimeter_add_same_object_perimeter_id_with_new_policy_id(): "name": value1['name'], "description": "description of {}".format('testuser'), } - req, objects = add_objects(client, 'testuser', policyId=policy_id1, data=data, - perimeter_id=value1['id']) + req, objects = add_objects('testuser', policyId=policy_id1, data=data, + perimeter_id=value1['id'],auth_headers=auth_headers) value2 = list(objects["objects"].values())[0] - assert req.status_code == 200 + assert req.status == hug.HTTP_200 assert value1['id'] == value2['id'] assert value1['name'] == value2['name'] def test_perimeter_add_same_object_perimeter_id_with_different_name(): - client = utilities.register_client() - req, objects = add_objects(client, "testuser") + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + req, objects = add_objects( "testuser", auth_headers=auth_headers) value1 = list(objects["objects"].values())[0] policies1 = policy_helper.add_policies() policy_id1 = list(policies1.keys())[0] @@ -456,14 +549,17 @@ def test_perimeter_add_same_object_perimeter_id_with_different_name(): "name": value1['name'] + 'different', "description": "description of {}".format('testuser'), } - req, objects = add_objects(client, 'testuser', policyId=policy_id1, data=data, - perimeter_id=value1['id']) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == '400: Perimeter content is invalid.' + with pytest.raises(exceptions.PerimeterContentError) as exception_info: + req, objects = add_objects('testuser', policyId=policy_id1, data=data, + perimeter_id=value1['id'], auth_headers=auth_headers) + assert "400: Perimeter content is invalid." == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == '400: Perimeter content is invalid.' def test_perimeter_add_same_object_name_with_same_policy_id(): - client = utilities.register_client() + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} name = 'testuser' + uuid4().hex policies1 = policy_helper.add_policies() policy_id1 = list(policies1.keys())[0] @@ -471,16 +567,20 @@ def test_perimeter_add_same_object_name_with_same_policy_id(): "name": name, "description": "description of {}".format('testuser'), } - req, objects = add_objects(client, 'testuser', policyId=policy_id1, data=data) + req, objects = add_objects('testuser', policyId=policy_id1, data=data, auth_headers=auth_headers) value = list(objects["objects"].values())[0] - assert req.status_code == 200 - req, objects = add_objects(client, 'testuser', policyId=policy_id1, data=data) - assert req.status_code == 409 - assert json.loads(req.data)["message"] == '409: Policy Already Exists' + + assert req.status == hug.HTTP_200 + with pytest.raises(exceptions.PolicyExisting) as exception_info: + req, objects = add_objects('testuser', policyId=policy_id1, data=data, auth_headers=auth_headers) + assert "409: Policy Already Exists" == str(exception_info.value) + # assert req.status == hug.HTTP_409 + # assert req.data["message"] == '409: Policy Already Exists' def test_perimeter_add_same_object_perimeter_id_with_existed_policy_id_in_list(): - client = utilities.register_client() + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} name = 'testuser' + uuid4().hex policies1 = policy_helper.add_policies() policy_id1 = list(policies1.keys())[0] @@ -488,16 +588,21 @@ def test_perimeter_add_same_object_perimeter_id_with_existed_policy_id_in_list() "name": name, "description": "description of {}".format('testuser'), } - req, objects = add_objects(client, 'testuser', policyId=policy_id1, data=data) + req, objects = add_objects( 'testuser', policyId=policy_id1, data=data, + auth_headers=auth_headers) value = list(objects["objects"].values())[0] - req, objects = add_objects(client, 'testuser', policyId=policy_id1, data=data, - perimeter_id=value['id']) - assert req.status_code == 409 - assert json.loads(req.data)["message"] == '409: Policy Already Exists' + with pytest.raises(exceptions.PolicyExisting) as exception_info: + req, objects = add_objects('testuser', policyId=policy_id1, data=data, + perimeter_id=value['id'], auth_headers=auth_headers) + assert "409: Policy Already Exists" == str(exception_info.value) + # assert req.status == hug.HTTP_409 + # assert req.data["message"] == '409: Policy Already Exists' def test_perimeter_update_object_name(): - client = utilities.register_client() + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import perimeter name = 'testuser' + uuid4().hex policies1 = policy_helper.add_policies() policy_id1 = list(policies1.keys())[0] @@ -505,26 +610,30 @@ def test_perimeter_update_object_name(): "name": name, "description": "description of {}".format('testuser'), } - req, objects = add_objects(client, 'testuser', policyId=policy_id1, data=data) + req, objects = add_objects('testuser', policyId=policy_id1, data=data, + auth_headers=auth_headers) value1 = list(objects["objects"].values())[0] perimeter_id = value1['id'] data = { 'name': value1['name'] + "update" } - req = client.patch("/objects/{}".format(perimeter_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) + req = hug.test.patch(perimeter, "/objects/{}".format(perimeter_id), body=data, + headers=auth_headers) objects = utilities.get_json(req.data) value2 = list(objects["objects"].values())[0] - assert req.status_code == 200 + + assert req.status == hug.HTTP_200 assert value1['name'] + 'update' == value2['name'] assert value1['id'] == value2['id'] assert value1['description'] == value2['description'] def test_perimeter_update_object_description(): - client = utilities.register_client() + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import perimeter name = 'testuser' + uuid4().hex policies1 = policy_helper.add_policies() policy_id1 = list(policies1.keys())[0] @@ -532,26 +641,30 @@ def test_perimeter_update_object_description(): "name": name, "description": "description of {}".format('testuser'), } - req, objects = add_objects(client, 'testuser', policyId=policy_id1, data=data) + req, objects = add_objects('testuser', policyId=policy_id1, data=data, + auth_headers=auth_headers) value1 = list(objects["objects"].values())[0] perimeter_id = value1['id'] data = { 'description': value1['description'] + "update" } - req = client.patch("/objects/{}".format(perimeter_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) + req = hug.test.patch(perimeter, "/objects/{}".format(perimeter_id), body=data, + headers=auth_headers) objects = utilities.get_json(req.data) value2 = list(objects["objects"].values())[0] - assert req.status_code == 200 + + assert req.status == hug.HTTP_200 assert value1['name'] == value2['name'] assert value1['id'] == value2['id'] assert value1['description'] + 'update' == value2['description'] def test_perimeter_update_object_description_and_name(): - client = utilities.register_client() + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import perimeter name = 'testuser' + uuid4().hex policies1 = policy_helper.add_policies() policy_id1 = list(policies1.keys())[0] @@ -559,7 +672,8 @@ def test_perimeter_update_object_description_and_name(): "name": name, "description": "description of {}".format('testuser'), } - req, objects = add_objects(client, 'testuser', policyId=policy_id1, data=data) + req, objects = add_objects('testuser', policyId=policy_id1, data=data, + auth_headers=auth_headers) value1 = list(objects["objects"].values())[0] perimeter_id = value1['id'] @@ -567,19 +681,21 @@ def test_perimeter_update_object_description_and_name(): 'name': value1['name'] + "update", 'description': value1['description'] + "update" } - req = client.patch("/objects/{}".format(perimeter_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) + req = hug.test.patch(perimeter, "/objects/{}".format(perimeter_id), body=data, + headers=auth_headers) objects = utilities.get_json(req.data) value2 = list(objects["objects"].values())[0] - assert req.status_code == 200 + assert req.status == hug.HTTP_200 assert value1['name'] + 'update' == value2['name'] assert value1['id'] == value2['id'] assert value1['description'] + 'update' == value2['description'] def test_perimeter_update_object_wrong_id(): - client = utilities.register_client() + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import perimeter name = 'testuser' + uuid4().hex policies1 = policy_helper.add_policies() policy_id1 = list(policies1.keys())[0] @@ -587,7 +703,8 @@ def test_perimeter_update_object_wrong_id(): "name": name, "description": "description of {}".format('testuser'), } - req, objects = add_objects(client, 'testuser', policyId=policy_id1, data=data) + req, objects = add_objects('testuser', policyId=policy_id1, data=data, + auth_headers=auth_headers) value1 = list(objects["objects"].values())[0] perimeter_id = value1['id'] @@ -595,13 +712,17 @@ def test_perimeter_update_object_wrong_id(): 'name': value1['name'] + "update", 'description': value1['description'] + "update" } - req = client.patch("/objects/{}".format(perimeter_id + "wrong"), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - assert req.status_code == 400 + with pytest.raises(exceptions.PerimeterContentError) as exception_info: + req = hug.test.patch(perimeter, "/objects/{}".format(perimeter_id + "wrong"), body=data, + headers=auth_headers) + assert "400: Perimeter content is invalid." == str(exception_info.value) + # assert req.status == hug.HTTP_400 def test_perimeter_update_object_name_with_existed_one(): - client = utilities.register_client() + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import perimeter name = 'testuser' + uuid4().hex policies1 = policy_helper.add_policies() policy_id1 = list(policies1.keys())[0] @@ -609,7 +730,8 @@ def test_perimeter_update_object_name_with_existed_one(): "name": name, "description": "description of {}".format('testuser'), } - req, objects = add_objects(client, 'testuser', policyId=policy_id1, data=data1) + req, objects = add_objects('testuser', policyId=policy_id1, data=data1, + auth_headers=auth_headers) value1 = list(objects["objects"].values())[0] name = 'testuser' + uuid4().hex @@ -618,7 +740,8 @@ def test_perimeter_update_object_name_with_existed_one(): "name": name, "description": "description of {}".format('testuser'), } - req, objects = add_objects(client, 'testuser', policyId=policy_id1, data=data2) + req, objects = add_objects('testuser', policyId=policy_id1, data=data2, + auth_headers=auth_headers) value2 = list(objects["objects"].values())[0] perimeter_id2 = value2['id'] @@ -626,59 +749,113 @@ def test_perimeter_update_object_name_with_existed_one(): data3 = { 'name': value1['name'] } - req = client.patch("/objects/{}".format(perimeter_id2), data=json.dumps(data3), - headers={'Content-Type': 'application/json'}) - assert req.status_code == 409 - assert json.loads(req.data)["message"] == '409: Object Existing' + with pytest.raises(exceptions.ObjectExisting) as exception_info: + req = hug.test.patch(perimeter, "/objects/{}".format(perimeter_id2), body=data3, + headers=auth_headers) + assert "409: Object Existing" == str(exception_info.value) + # assert req.status == hug.HTTP_409 + # assert req.data["message"] == '409: Object Existing' def test_perimeter_add_object_without_name(): - client = utilities.register_client() + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import perimeter data = { "name": "
", "description": "description of {}".format(""), } - req = client.post("/policies/{}/objects/".format("111"), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == "Key: 'name', [Forbidden characters in string]" + with pytest.raises(exceptions.ValidationContentError) as exception_info: + req = hug.test.post(perimeter, "/policies/{}/objects/".format( + "a34e5a29-5494-4cc5-9356-daa244b8c888"), + body=data, headers=auth_headers) + assert "Key: 'name', [Forbidden characters in string]" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == "Key: 'name', [Forbidden characters in string]" + + +def test_perimeter_add_object_blank_data(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import perimeter + with pytest.raises(exceptions.ValidationKeyError) as exception_info: + req = hug.test.post(perimeter, "/policies/{}/objects/".format( + "a34e5a29-5494-4cc5-9356-daa244b8c888"), + body={}, headers=auth_headers) + assert "Invalid Key :name not found" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == 'Invalid Key :name not found' def test_perimeter_add_object_with_name_contain_spaces(): - client = utilities.register_client() + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import perimeter data = { "name": "test
user", "description": "description of {}".format("test user"), } - req = client.post("/policies/{}/objects/".format("111"), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == "Key: 'name', [Forbidden characters in string]" + with pytest.raises(exceptions.ValidationContentError) as exception_info: + req = hug.test.post(perimeter, "/policies/{}/objects/".format( + "a34e5a29-5494-4cc5-9356-daa244b8c888"), body=data, + headers=auth_headers) + assert "Key: 'name', [Forbidden characters in string]" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == "Key: 'name', [Forbidden characters in string]" + + +def test_perimeter_add_object_with_name_space(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import perimeter + data = { + "name": " ", + "description": "description of {}".format("test user"), + } + with pytest.raises(exceptions.PerimeterContentError) as exception_info: + req = hug.test.post(perimeter, "/policies/{}/objects/".format( + "a34e5a29-5494-4cc5-9356-daa244b8c888"), + body =data, headers=auth_headers) + assert "400: Perimeter content is invalid." == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == '400: Perimeter content is invalid.' def test_perimeter_delete_object(): - client = utilities.register_client() + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import perimeter policies = policy_helper.add_policies() policy_id = list(policies.keys())[0] object_id = builder.create_object(policy_id) - req = client.delete("/policies/{}/objects/{}".format(policy_id, object_id)) - assert req.status_code == 200 + req = hug.test.delete(perimeter, "/policies/{}/objects/{}".format(policy_id, object_id), headers=auth_headers) + + assert req.status == hug.HTTP_200 def test_perimeter_delete_objects_without_perimeter_id(): - client = utilities.register_client() - req = delete_objects_without_perimeter_id(client) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == "400: Object Unknown" + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + with pytest.raises(exceptions.ObjectUnknown) as exception_info: + req = delete_objects_without_perimeter_id(auth_headers=auth_headers) + assert "400: Object Unknown" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == "400: Object Unknown" -def get_actions(client): - req = client.get("/actions") + +def get_actions(): + from moon_manager.api import perimeter + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + req = hug.test.get(perimeter, "/actions", headers=auth_headers) actions = utilities.get_json(req.data) return req, actions -def add_actions(client, name, policy_id=None, data=None, perimeter_id=None): +def add_actions(name, policy_id=None, data=None, perimeter_id=None, auth_headers=None): + from moon_manager.api import perimeter if not policy_id: subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = builder.create_new_policy( subject_category_name="subject_category1" + uuid4().hex, @@ -693,60 +870,72 @@ def add_actions(client, name, policy_id=None, data=None, perimeter_id=None): "description": "description of {}".format(name), } if not perimeter_id: - req = client.post("/policies/{}/actions/".format(policy_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) + req = hug.test.post(perimeter, "/policies/{}/actions/".format(policy_id), body=data, + headers=auth_headers) else: - req = client.post("/policies/{}/actions/{}".format(policy_id, perimeter_id), - data=json.dumps(data), - headers={'Content-Type': 'application/json'}) + req = hug.test.post(perimeter, "/policies/{}/actions/{}".format(policy_id, perimeter_id), + body=data, headers=auth_headers) actions = utilities.get_json(req.data) return req, actions -def delete_actions_without_perimeter_id(client): - req = client.delete("/actions/{}".format("")) +def delete_actions_without_perimeter_id(auth_headers=None): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import perimeter + req = hug.test.delete(perimeter, "/actions/{}".format(""), headers=auth_headers) return req def test_perimeter_get_actions(): - client = utilities.register_client() - req, actions = get_actions(client) - assert req.status_code == 200 + + req, actions = get_actions() + + assert req.status == hug.HTTP_200 assert isinstance(actions, dict) assert "actions" in actions def test_perimeter_add_actions(): - client = utilities.register_client() - req, actions = add_actions(client, "testuser") + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + req, actions = add_actions("testuser", auth_headers=auth_headers) value = list(actions["actions"].values())[0] - assert req.status_code == 200 + assert req.status == hug.HTTP_200 assert value['name'] def test_perimeter_add_action_with_wrong_policy_id(): - client = utilities.register_client() - req, actions = add_actions(client, "testuser", policy_id="wrong") - assert req.status_code == 400 - assert json.loads(req.data)["message"] == '400: Policy Unknown' + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + with pytest.raises(exceptions.PolicyUnknown) as exception_info: + req, actions = add_actions("testuser", policy_id="wrong", auth_headers=auth_headers) + assert "400: Policy Unknown" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == '400: Policy Unknown' def test_perimeter_add_action_with_policy_id_none(): - client = utilities.register_client() + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import perimeter data = { "name": "testuser" + uuid4().hex, "description": "description of {}".format("testuser"), } - req = client.post("/policies/{}/actions/".format(None), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == '400: Policy Unknown' + with pytest.raises(exceptions.PolicyUnknown) as exception_info: + req = hug.test.post(perimeter, "/policies/{}/actions/".format(None), body=data, + headers=auth_headers) + assert "400: Policy Unknown" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == '400: Policy Unknown' def test_perimeter_add_same_action_name_with_new_policy_id(): - client = utilities.register_client() - req, action = add_actions(client, "testuser") + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + req, action = add_actions("testuser", auth_headers=auth_headers) value1 = list(action["actions"].values())[0] policies1 = policy_helper.add_policies() policy_id1 = list(policies1.keys())[0] @@ -754,16 +943,18 @@ def test_perimeter_add_same_action_name_with_new_policy_id(): "name": value1['name'], "description": "description of {}".format('testuser'), } - req, action = add_actions(client, 'testuser', policy_id=policy_id1, data=data) + req, action = add_actions('testuser', policy_id=policy_id1, data=data, + auth_headers=auth_headers) value2 = list(action["actions"].values())[0] - assert req.status_code == 200 + assert req.status == hug.HTTP_200 assert value1['id'] == value2['id'] assert value1['name'] == value2['name'] def test_perimeter_add_same_action_perimeter_id_with_new_policy_id(): - client = utilities.register_client() - req, action = add_actions(client, "testuser") + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + req, action = add_actions("testuser", auth_headers=auth_headers) value1 = list(action["actions"].values())[0] policies1 = policy_helper.add_policies() policy_id1 = list(policies1.keys())[0] @@ -771,17 +962,19 @@ def test_perimeter_add_same_action_perimeter_id_with_new_policy_id(): "name": value1['name'], "description": "description of {}".format('testuser'), } - req, action = add_actions(client, 'testuser', policy_id=policy_id1, data=data, - perimeter_id=value1['id']) + req, action = add_actions('testuser', policy_id=policy_id1, data=data, + perimeter_id=value1['id'], auth_headers=auth_headers) value2 = list(action["actions"].values())[0] - assert req.status_code == 200 + + assert req.status == hug.HTTP_200 assert value1['id'] == value2['id'] assert value1['name'] == value2['name'] def test_perimeter_add_same_action_perimeter_id_with_different_name(): - client = utilities.register_client() - req, action = add_actions(client, "testuser") + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + req, action = add_actions("testuser", auth_headers=auth_headers) value1 = list(action["actions"].values())[0] policies1 = policy_helper.add_policies() policy_id1 = list(policies1.keys())[0] @@ -789,240 +982,323 @@ def test_perimeter_add_same_action_perimeter_id_with_different_name(): "name": value1['name'] + 'different', "description": "description of {}".format('testuser'), } - req, action = add_actions(client, 'testuser', policy_id=policy_id1, data=data, - perimeter_id=value1['id']) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == '400: Perimeter content is invalid.' + with pytest.raises(exceptions.PerimeterContentError) as exception_info: + req, action = add_actions('testuser', policy_id=policy_id1, data=data, + perimeter_id=value1['id'], auth_headers=auth_headers) + assert "400: Perimeter content is invalid." == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == '400: Perimeter content is invalid.' def test_perimeter_add_same_action_name_with_same_policy_id(): - client = utilities.register_client() + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} policies1 = policy_helper.add_policies() policy_id1 = list(policies1.keys())[0] - req, action = add_actions(client, "testuser", policy_id=policy_id1) + req, action = add_actions("testuser", policy_id=policy_id1, auth_headers=auth_headers) value1 = list(action["actions"].values())[0] data = { "name": value1['name'], "description": "description of {}".format('testuser'), } - req, action = add_actions(client, 'testuser', policy_id=policy_id1, data=data) - assert req.status_code == 409 - assert json.loads(req.data)["message"] == '409: Policy Already Exists' + with pytest.raises(exceptions.PolicyExisting) as exception_info: + req, action = add_actions('testuser', policy_id=policy_id1, data=data, + auth_headers=auth_headers) + assert "409: Policy Already Exists" == str(exception_info.value) + # assert req.status == hug.HTTP_409 + # assert req.data["message"] == '409: Policy Already Exists' def test_perimeter_add_same_action_perimeter_id_with_existed_policy_id_in_list(): - client = utilities.register_client() + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} policies1 = policy_helper.add_policies() policy_id1 = list(policies1.keys())[0] - req, action = add_actions(client, "testuser", policy_id=policy_id1) + req, action = add_actions("testuser", policy_id=policy_id1, auth_headers=auth_headers) value1 = list(action["actions"].values())[0] data = { "name": value1['name'], "description": "description of {}".format('testuser'), } - req, action = add_actions(client, 'testuser', policy_id=policy_id1, data=data, - perimeter_id=value1['id']) - assert req.status_code == 409 - assert json.loads(req.data)["message"] == '409: Policy Already Exists' + with pytest.raises(exceptions.PolicyExisting) as exception_info: + req, action = add_actions('testuser', policy_id=policy_id1, data=data, + perimeter_id=value1['id'], auth_headers=auth_headers) + assert "409: Policy Already Exists" == str(exception_info.value) + # assert req.status == hug.HTTP_409 + # assert req.data["message"] == '409: Policy Already Exists' def test_perimeter_add_actions_without_name(): - client = utilities.register_client() + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import perimeter data = { "name": "", "description": "description of {}".format(""), } - req = client.post("/policies/{}/actions".format("111"), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == "Key: 'name', [Forbidden characters in string]" + with pytest.raises(exceptions.ValidationContentError) as exception_info: + req = hug.test.post(perimeter, "/policies/{}/actions".format( + "a34e5a29-5494-4cc5-9356-daa244b8c888"), + body=data, headers=auth_headers) + assert "Key: 'name', [Forbidden characters in string]" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == "Key: 'name', [Forbidden characters in string]" def test_perimeter_add_actions_with_name_contain_spaces(): - client = utilities.register_client() + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import perimeter data = { "name": "testuser", "description": "description of {}".format("test user"), } - req = client.post("/policies/{}/actions".format("111"), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == "Key: 'name', [Forbidden characters in string]" + with pytest.raises(exceptions.ValidationContentError) as exception_info: + req = hug.test.post(perimeter, "/policies/{}/actions".format( + "a34e5a29-5494-4cc5-9356-daa244b8c888"), + body=data, headers=auth_headers) + assert "Key: 'name', [Forbidden characters in string]" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == "Key: 'name', [Forbidden characters in string]" def test_add_subjects_without_policy_id(): - client = utilities.register_client() + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import perimeter data = { "name": "testuser", "description": "description of {}".format("test user"), } - req = client.post("/policies/{}/subjects".format("111"), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == "400: Policy Unknown" + with pytest.raises(exceptions.PolicyUnknown) as exception_info: + req = hug.test.post(perimeter, "/policies/{}/subjects".format( + "a34e5a29-5494-4cc5-9356-daa244b8c888"), + body=data, headers=auth_headers) + assert "400: Policy Unknown" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == "400: Policy Unknown" def test_add_objects_without_policy_id(): - client = utilities.register_client() + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import perimeter data = { "name": "testuser", "description": "description of {}".format("test user"), } - req = client.post("/policies/{}/objects".format("111"), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == "400: Policy Unknown" + with pytest.raises(exceptions.PolicyUnknown) as exception_info: + req = hug.test.post(perimeter, "/policies/{}/objects".format( + "a34e5a29-5494-4cc5-9356-daa244b8c888"), + body=data, headers=auth_headers) + assert "400: Policy Unknown" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == "400: Policy Unknown" def test_add_action_without_policy_id(): - client = utilities.register_client() + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import perimeter data = { "name": "testuser", "description": "description of {}".format("test user"), } - req = client.post("/policies/{}/actions".format("111"), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == "400: Policy Unknown" + with pytest.raises(exceptions.PolicyUnknown) as exception_info: + req = hug.test.post(perimeter, "/policies/{}/actions".format( + "a34e5a29-5494-4cc5-9356-daa244b8c888"), body=data, + headers=auth_headers) + assert "400: Policy Unknown" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == "400: Policy Unknown" def test_perimeter_update_action_name(): - client = utilities.register_client() - req, actions = add_actions(client, "testuser") + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import perimeter + req, actions = add_actions("testuser", auth_headers=auth_headers) value1 = list(actions["actions"].values())[0] perimeter_id = value1['id'] data = { 'name': value1['name'] + "update" } - req = client.patch("/actions/{}".format(perimeter_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) + req = hug.test.patch(perimeter, "/actions/{}".format(perimeter_id), body=data, + headers=auth_headers) subjects = utilities.get_json(req.data) value2 = list(subjects["actions"].values())[0] - assert req.status_code == 200 + + assert req.status == hug.HTTP_200 assert value1['name'] + 'update' == value2['name'] assert value1['id'] == value2['id'] assert value1['description'] == value2['description'] def test_perimeter_update_actions_description(): - client = utilities.register_client() - req, actions = add_actions(client, "testuser") + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import perimeter + req, actions = add_actions("testuser", auth_headers=auth_headers) value1 = list(actions["actions"].values())[0] perimeter_id = value1['id'] data = { 'description': value1['description'] + "update" } - req = client.patch("/actions/{}".format(perimeter_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) + req = hug.test.patch(perimeter, "/actions/{}".format(perimeter_id), body=data, + headers=auth_headers) subjects = utilities.get_json(req.data) value2 = list(subjects["actions"].values())[0] - assert req.status_code == 200 + + assert req.status == hug.HTTP_200 assert value1['name'] == value2['name'] assert value1['id'] == value2['id'] assert value1['description'] + 'update' == value2['description'] def test_perimeter_update_actions_description_and_name(): - client = utilities.register_client() - req, actions = add_actions(client, "testuser") + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import perimeter + req, actions = add_actions("testuser", auth_headers=auth_headers) value1 = list(actions["actions"].values())[0] perimeter_id = value1['id'] data = { 'name': value1['name'] + "update", 'description': value1['description'] + "update" } - req = client.patch("/actions/{}".format(perimeter_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) + req = hug.test.patch(perimeter, "/actions/{}".format(perimeter_id), body=data, + headers=auth_headers) subjects = utilities.get_json(req.data) value2 = list(subjects["actions"].values())[0] - assert req.status_code == 200 + + assert req.status == hug.HTTP_200 assert value1['name'] + 'update' == value2['name'] assert value1['id'] == value2['id'] assert value1['description'] + 'update' == value2['description'] def test_perimeter_update_action_wrong_id(): - client = utilities.register_client() - req, actions = add_actions(client, "testuser") + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import perimeter + req, actions = add_actions("testuser", auth_headers=auth_headers) value1 = list(actions["actions"].values())[0] perimeter_id = value1['id'] data = { 'name': value1['name'] + "update", 'description': value1['description'] + "update" } - req = client.patch("/actions/{}".format(perimeter_id + "wrong"), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == '400: Perimeter content is invalid.' + with pytest.raises(exceptions.PerimeterContentError) as exception_info: + req = hug.test.patch(perimeter, "/actions/{}".format(perimeter_id + "wrong"), body=data, + headers=auth_headers) + assert "400: Perimeter content is invalid." == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == '400: Perimeter content is invalid.' def test_perimeter_update_action_name_with_existed_one(): - client = utilities.register_client() - req, actions = add_actions(client, "testuser") + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import perimeter + req, actions = add_actions("testuser", auth_headers=auth_headers) value1 = list(actions["actions"].values())[0] - req, actions = add_actions(client, "testuser") + req, actions = add_actions("testuser", auth_headers=auth_headers) value2 = list(actions["actions"].values())[0] perimeter_id2 = value2['id'] data = { 'name': value1['name'], } - req = client.patch("/actions/{}".format(perimeter_id2), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - assert req.status_code == 409 - assert json.loads(req.data)["message"] == '409: Action Existing' + with pytest.raises(exceptions.ActionExisting) as exception_info: + req = hug.test.patch(perimeter, "/actions/{}".format(perimeter_id2), body=data, + headers=auth_headers) + assert "409: Action Existing" == str(exception_info.value) + # assert req.status == hug.HTTP_409 + # assert req.data["message"] == '409: Action Existing' def test_perimeter_delete_actions(): - client = utilities.register_client() - + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import perimeter policies = policy_helper.add_policies() policy_id = list(policies.keys())[0] action_id = builder.create_action(policy_id) - req = client.delete("/policies/{}/actions/{}".format(policy_id, action_id)) - assert req.status_code == 200 + req = hug.test.delete(perimeter, "/policies/{}/actions/{}".format(policy_id, action_id), + headers=auth_headers) -def test_delete_subject_without_policy(): - client = utilities.register_client() + assert req.status == hug.HTTP_200 + +def test_delete_subject_assigned_to_policy(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import perimeter + from moon_manager.db_driver import PolicyManager policies = policy_helper.add_policies() policy_id = list(policies.keys())[0] + subject_id = builder.create_subject(policy_id) + PolicyManager.delete_policy(moon_user_id="admin", policy_id=policy_id) + PolicyManager.delete_subject(moon_user_id="admin", policy_id=None ,perimeter_id=subject_id) - action_id = builder.create_action(policy_id) + req = hug.test.get(perimeter, "subjects/{}".format(subject_id), headers=auth_headers) + assert req.data['subjects'] == {} - req = client.delete("/subjects/{}".format(action_id)) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == "400: Policy Unknown" +def test_delete_subject_without_policy(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import perimeter + policies = policy_helper.add_policies() + policy_id = list(policies.keys())[0] -def test_delete_objects_without_policy(): - client = utilities.register_client() + subject_id = builder.create_subject(policy_id) + + with pytest.raises(exceptions.PolicyUnknown) as exception_info: + req = hug.test.delete(perimeter, "/subjects/{}".format(subject_id), headers=auth_headers) + assert "400: Policy Unknown" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == "400: Policy Unknown" + +def test_delete_objects_without_policy(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import perimeter policies = policy_helper.add_policies() policy_id = list(policies.keys())[0] - action_id = builder.create_action(policy_id) + object_id = builder.create_object(policy_id) - req = client.delete("/objects/{}".format(action_id)) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == "400: Policy Unknown" + with pytest.raises(exceptions.PolicyUnknown) as exception_info: + req = hug.test.delete(perimeter, "/objects/{}".format(object_id), headers=auth_headers) + assert "400: Policy Unknown" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == "400: Policy Unknown" -def test_delete_actions_without_policy(): - client = utilities.register_client() +def test_delete_actions_without_policy(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import perimeter policies = policy_helper.add_policies() policy_id = list(policies.keys())[0] action_id = builder.create_action(policy_id) - req = client.delete("/actions/{}".format(action_id)) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == "400: Policy Unknown" + with pytest.raises(exceptions.PolicyUnknown) as exception_info: + req = hug.test.delete(perimeter, "/actions/{}".format(action_id), headers=auth_headers) + assert "400: Policy Unknown" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == "400: Policy Unknown" def test_perimeter_delete_actions_without_perimeter_id(): - client = utilities.register_client() - req = delete_actions_without_perimeter_id(client) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == "400: Action Unknown" + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + with pytest.raises(exceptions.ActionUnknown) as exception_info: + req = delete_actions_without_perimeter_id(auth_headers=auth_headers) + assert "400: Action Unknown" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == "400: Action Unknown" diff --git a/moon_manager/tests/unit_python/api/test_perimeter_examples.py b/moon_manager/tests/unit_python/api/test_perimeter_examples.py new file mode 100644 index 00000000..0598629c --- /dev/null +++ b/moon_manager/tests/unit_python/api/test_perimeter_examples.py @@ -0,0 +1,55 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +import hug +import json + + +# def test_local_perimeter_get_subject(): +# from moon_manager.api import perimeter +# subjects = perimeter.Subjects.get() +# assert isinstance(subjects, dict) +# assert "subjects" in subjects + + + +# def test_http_perimeter_post_subject(): +# from moon_manager.api import perimeter +# result = hug.test.post(perimeter, 'subjects/b34e5a2954944cc59356daa244b8c254', +# body={'name': 'ha'}, +# headers={'Content-Type': 'application/json'}) +# assert result.status == hug.HTTP_200 +# assert isinstance(result.data, dict) +# assert "subjects" in result.data +# +# +# def test_http_perimeter_get_subject_2(): +# from moon_manager.api import perimeter +# result = hug.test.get(perimeter, 'subjects/b34e5a29-5494-4cc5-9356-daa244b8c254') +# assert result.status == hug.HTTP_200 +# assert isinstance(result.data, dict) +# assert "subjects" in result.data +# +# def test_http_perimeter_get_subject_3(): +# from moon_manager.api import perimeter +# result = hug.test.get(perimeter, 'policies/b34e5a29-5494-4cc5-9356-daa244b8c254/subjects/') +# assert result.status == hug.HTTP_200 +# assert isinstance(result.data, dict) +# assert "subjects" in result.data +# +# +# def test_http_perimeter_get_subject_4(): +# from moon_manager.api import perimeter +# result = hug.test.get(perimeter, 'policies/b34e5a29-5494-4cc5-9356-daa244b8c254/subjects/b34e5a29-5494-4cc5-9356-daa244b8c254') +# assert result.status == hug.HTTP_200 +# assert isinstance(result.data, dict) +# assert "subjects" in result.data diff --git a/moon_manager/tests/unit_python/api/test_policies.py b/moon_manager/tests/unit_python/api/test_policies.py index 76161d53..a07ba725 100644 --- a/moon_manager/tests/unit_python/api/test_policies.py +++ b/moon_manager/tests/unit_python/api/test_policies.py @@ -1,23 +1,32 @@ -# Copyright 2018 Open Platform for NFV Project, Inc. and its contributors -# This software is distributed under the terms and conditions of the 'Apache-2.0' -# license which can be found in the file 'LICENSE' in this package distribution -# or at 'http://www.apache.org/licenses/LICENSE-2.0'. +# Software Name: MOON -import json +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +from falcon import HTTP_200, HTTP_400, HTTP_405, HTTP_409 +import hug from uuid import uuid4 -import api.utilities as utilities +import pytest +from moon_utilities import exceptions from helpers import model_helper from helpers import policy_helper -from helpers import data_builder -def get_policies(client): - req = client.get("/policies") - policies = utilities.get_json(req.data) - return req, policies +def get_policies(auth_headers): + from moon_manager.api import policy + req = hug.test.get(policy, "policies", headers=auth_headers) + return req -def add_policies(client, name): +def add_policies(name, auth_headers): + from moon_manager.api import policy req = model_helper.add_model(model_id="mls_model_id" + uuid4().hex) model_id = list(req.keys())[0] data = { @@ -26,106 +35,153 @@ def add_policies(client, name): "model_id": model_id, "genre": "genre" } - req = client.post("/policies", data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - policies = utilities.get_json(req.data) - return req, policies + req = hug.test.post(policy, "policies", data, headers=auth_headers) + return req -def delete_policies_without_id(client): - req = client.delete("/policies/{}".format("")) +def delete_policies_without_id(auth_headers): + from moon_manager.api import policy + req = hug.test.delete(policy, "policies/{}".format(""), headers=auth_headers) return req def test_get_policies(): - client = utilities.register_client() - req, policies = get_policies(client) - assert req.status_code == 200 - assert isinstance(policies, dict) - assert "policies" in policies + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + req = get_policies(auth_headers=auth_headers) + assert req.status == HTTP_200 + assert isinstance(req.data, dict) + assert "policies" in req.data def test_add_policies(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} policy_name = "testuser" + uuid4().hex - client = utilities.register_client() - req, policies = add_policies(client, policy_name) - assert req.status_code == 200 - assert isinstance(policies, dict) - value = list(policies["policies"].values())[0] - assert "policies" in policies + req = add_policies(policy_name, auth_headers=auth_headers) + assert req.status == HTTP_200 + assert isinstance(req.data, dict) + value = list(req.data["policies"].values())[0] + assert "policies" in req.data assert value['name'] == policy_name assert value["description"] == "description of {}".format(policy_name) def test_add_policies_without_model(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import policy policy_name = "testuser" + uuid4().hex - client = utilities.register_client() data = { "name": policy_name, "description": "description of {}".format(policy_name), "model_id": "", "genre": "genre" } - req = client.post("/policies/", data=json.dumps(data), - headers={'Content-Type': 'application/json'}) + req = hug.test.post(policy, "policies/", data, headers=auth_headers) - assert req.status_code == 200 + assert req.status == HTTP_200 def test_add_policies_with_same_name(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} name = uuid4().hex policy_name = name - client = utilities.register_client() - req, policies = add_policies(client, policy_name) - assert req.status_code == 200 - assert isinstance(policies, dict) - value = list(policies["policies"].values())[0] - assert "policies" in policies + req = add_policies(policy_name, auth_headers=auth_headers) + assert req.status == HTTP_200 + assert isinstance(req.data, dict) + value = list(req.data["policies"].values())[0] + assert "policies" in req.data assert value['name'] == policy_name assert value["description"] == "description of {}".format(policy_name) - client = utilities.register_client() - req, policies = add_policies(client, policy_name) - assert req.status_code == 409 - assert json.loads(req.data)["message"] == '409: Policy Already Exists' + with pytest.raises(exceptions.PolicyExisting) as exception_info: + req = add_policies(policy_name, auth_headers=auth_headers) + assert "409: Policy Already Exists" == str(exception_info.value) + # assert req.status == HTTP_409 + # assert req.data["message"] == '409: Policy Already Exists' def test_add_policy_with_empty_name(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} policy_name = "" - client = utilities.register_client() - req, policies = add_policies(client, policy_name) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == '400: Policy Content Error' + with pytest.raises(exceptions.PolicyContentError) as exception_info: + req = add_policies(policy_name, auth_headers=auth_headers) + assert "400: Policy Content Error" == str(exception_info.value) + # assert req.status == HTTP_400 + # assert req.data["message"] == '400: Policy Content Error' -def test_update_policies_with_model(): +def test_add_policy_with_model_has_no_meta_rule(): + from moon_utilities.auth_functions import get_api_key_for_user + from moon_manager.api import policy + + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} policy_name = "testuser" + uuid4().hex - client = utilities.register_client() + req = model_helper.add_model_without_meta_rule() + model_id = list(req.keys())[0] data = { "name": policy_name, "description": "description of {}".format(policy_name), - "model_id": "", + "model_id": model_id, "genre": "genre" } - req = client.post("/policies/", data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - policy_id = next(iter(utilities.get_json(req.data)['policies'])) - req = model_helper.add_model(model_id="mls_model_id" + uuid4().hex) + with pytest.raises(exceptions.MetaRuleUnknown) as exception_info: + hug.test.post(policy, "policies/", data, headers=auth_headers) + assert "400: Meta Rule Unknown" == str(exception_info.value) + + +def test_add_policy_with_model_has_blank_subject_meta_rule(): + from moon_utilities.auth_functions import get_api_key_for_user + from moon_manager.api import policy + + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + policy_name = "testuser" + uuid4().hex + req = model_helper.add_model_with_blank_subject_meta_rule() model_id = list(req.keys())[0] data = { - "name": policy_name + "-2", + "name": policy_name, "description": "description of {}".format(policy_name), "model_id": model_id, "genre": "genre" } - req = client.patch("/policies/{}".format(policy_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - assert req.status_code == 200 - assert json.loads(req.data)['policies'][policy_id]['name'] == policy_name + '-2' + with pytest.raises(exceptions.MetaRuleContentError) as exception_info: + hug.test.post(policy, "policies/", data, headers=auth_headers) + assert "400: Meta Rule Error" == str(exception_info.value) + + + +# FIXME: uncomment when model API is re-inserted +# def test_update_policies_with_model(): +# from moon_manager.api import policy +# policy_name = "testuser" + uuid4().hex +# data = { +# "name": policy_name, +# "description": "description of {}".format(policy_name), +# "model_id": "", +# "genre": "genre" +# } +# req = hug.test.post(policy, "policies/", data) +# policy_id = next(iter(req.data['policies'])) +# req = model_helper.add_model(model_id="mls_model_id" + uuid4().hex) +# model_id = list(req.data.keys())[0] +# data = { +# "name": policy_name + "-2", +# "description": "description of {}".format(policy_name), +# "model_id": model_id, +# "genre": "genre" +# } +# req = hug.test.patch("policies/{}".format(policy_id), data) +# assert req.status == HTTP_200 +# assert req.data['policies'][policy_id]['name'] == policy_name + '-2' def test_update_policies_name_success(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import policy policy_name = "testuser" + uuid4().hex - client = utilities.register_client() req = model_helper.add_model(model_id="mls_model_id" + uuid4().hex) model_id = list(req.keys())[0] data = { @@ -134,9 +190,8 @@ def test_update_policies_name_success(): "model_id": model_id, "genre": "genre" } - req = client.post("/policies/", data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - policy_id = next(iter(utilities.get_json(req.data)['policies'])) + req = hug.test.post(policy, "policies/", data, headers=auth_headers) + policy_id = next(iter(req.data['policies'])) data = { "name": policy_name + "-2", @@ -144,26 +199,24 @@ def test_update_policies_name_success(): "model_id": model_id, "genre": "genre" } - req = client.patch("/policies/{}".format(policy_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - assert req.status_code == 200 - assert json.loads(req.data)['policies'][policy_id]['name'] == policy_name + '-2' + req = hug.test.patch(policy, "policies/{}".format(policy_id), data, headers=auth_headers) + assert req.status == HTTP_200 + assert req.data['policies'][policy_id]['name'] == policy_name + '-2' -def test_update_policies_model_unused(): +def test_update_blank_policies_with_model(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import policy policy_name = uuid4().hex - client = utilities.register_client() - req = model_helper.add_model(model_id="mls_model_id" + uuid4().hex) - model_id = list(req.keys())[0] data = { "name": policy_name, "description": "description of {}".format(policy_name), - "model_id": model_id, + "model_id": "", "genre": "genre" } - req = client.post("/policies/", data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - policy_id = next(iter(utilities.get_json(req.data)['policies'])) + req = hug.test.post(policy, "policies/", data, headers=auth_headers) + policy_id = next(iter(req.data['policies'])) req = model_helper.add_model(model_id="mls_model_id" + uuid4().hex) model_id = list(req.keys())[0] data = { @@ -172,55 +225,82 @@ def test_update_policies_model_unused(): "model_id": model_id, "genre": "genre" } - req = client.patch("/policies/{}".format(policy_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - assert req.status_code == 200 + req = hug.test.patch(policy, "policies/{}".format(policy_id), data, headers=auth_headers) + assert req.status == HTTP_200 -def test_update_policy_name_with_existed_one(): - policy_name1 = "testuser" + uuid4().hex - client = utilities.register_client() +def test_update_policies_model_unused(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import policy + policy_name = uuid4().hex req = model_helper.add_model(model_id="mls_model_id" + uuid4().hex) model_id = list(req.keys())[0] data = { - "name": policy_name1, - "description": "description of {}".format(policy_name1), + "name": policy_name, + "description": "description of {}".format(policy_name), "model_id": model_id, "genre": "genre" } - req = client.post("/policies/", data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - policy_id1 = next(iter(utilities.get_json(req.data)['policies'])) - - policy_name2 = "testuser" + uuid4().hex - client = utilities.register_client() + req = hug.test.post(policy, "policies/", data, headers=auth_headers) + policy_id = next(iter(req.data['policies'])) req = model_helper.add_model(model_id="mls_model_id" + uuid4().hex) model_id = list(req.keys())[0] data = { - "name": policy_name2, - "description": "description of {}".format(policy_name2), + "name": policy_name, + "description": "description of {}".format(policy_name), "model_id": model_id, "genre": "genre" } - req = client.post("/policies/", data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - policy_id2 = next(iter(utilities.get_json(req.data)['policies'])) - data = { - "name": policy_name1, - "description": "description of {}".format(policy_name1), - "model_id": model_id, - "genre": "genre" - } - req = client.patch("/policies/{}".format(policy_id2), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - assert req.status_code == 409 - assert json.loads(req.data)["message"] == '409: Policy Already Exists' + with pytest.raises(exceptions.PolicyUpdateError) as exception_info: + req = hug.test.patch(policy, "policies/{}".format(policy_id), data, headers=auth_headers) + assert "400: Policy update error" == str(exception_info.value) + + +# FIXME: uncomment when model API is re-inserted +# def test_update_policy_name_with_existed_one(): +# from moon_manager.api import policy +# policy_name1 = "testuser" + uuid4().hex +# req = model_helper.add_model(model_id="mls_model_id" + uuid4().hex) +# model_id = list(req.keys())[0] +# data = { +# "name": policy_name1, +# "description": "description of {}".format(policy_name1), +# "model_id": model_id, +# "genre": "genre" +# } +# req = hug.test.post(policy, "policies/", data) +# policy_id1 = next(iter(req.data['policies'])) +# +# policy_name2 = "testuser" + uuid4().hex +# eq = model_helper.add_model(model_id="mls_model_id" + uuid4().hex) +# model_id = list(req.data.keys())[0] +# data = { +# "name": policy_name2, +# "description": "description of {}".format(policy_name2), +# "model_id": model_id, +# "genre": "genre" +# } +# req = hug.test.post(policy, "policies/", data) +# policy_id2 = next(iter(req.data['policies'])) +# +# data = { +# "name": policy_name1, +# "description": "description of {}".format(policy_name1), +# "model_id": model_id, +# "genre": "genre" +# } +# req = hug.test.patch(policy, "policies/{}".format(policy_id2), data) +# assert req.status == HTTP_409 +# assert req.data["message"] == '409: Policy Already Exists' def test_update_policies_with_empty_name(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import policy policy_name = "testuser" + uuid4().hex - client = utilities.register_client() req = model_helper.add_model(model_id="mls_model_id" + uuid4().hex) model_id = list(req.keys())[0] data = { @@ -229,9 +309,8 @@ def test_update_policies_with_empty_name(): "model_id": model_id, "genre": "genre" } - req = client.post("/policies/", data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - policy_id = next(iter(utilities.get_json(req.data)['policies'])) + req = hug.test.post(policy, "policies/", data, headers=auth_headers) + policy_id = next(iter(req.data['policies'])) data = { "name": "", @@ -239,15 +318,18 @@ def test_update_policies_with_empty_name(): "model_id": model_id, "genre": "genre" } - req = client.patch("/policies/{}".format(policy_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == '400: Policy Content Error' + with pytest.raises(exceptions.PolicyContentError) as exception_info: + req = hug.test.patch(policy, "policies/{}".format(policy_id), data, headers=auth_headers) + assert "400: Policy Content Error" == str(exception_info.value) + # assert req.status == HTTP_400 + # assert req.data["message"] == '400: Policy Content Error' def test_update_policies_with_blank_model(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import policy policy_name = "testuser" + uuid4().hex - client = utilities.register_client() req = model_helper.add_model(model_id="mls_model_id" + uuid4().hex) model_id = list(req.keys())[0] data = { @@ -256,9 +338,8 @@ def test_update_policies_with_blank_model(): "model_id": model_id, "genre": "genre" } - req = client.post("/policies/", data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - policy_id = next(iter(utilities.get_json(req.data)['policies'])) + req = hug.test.post(policy, "policies/", data, headers=auth_headers) + policy_id = next(iter(req.data['policies'])) data = { "name": policy_name, @@ -267,76 +348,77 @@ def test_update_policies_with_blank_model(): "genre": "genre" } - req = client.patch("/policies/{}".format(policy_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - assert req.status_code == 200 + with pytest.raises(exceptions.PolicyUpdateError) as exception_info: + req = hug.test.patch(policy, "policies/{}".format(policy_id), data, headers=auth_headers) + assert "400: Policy update error" == str(exception_info.value) -def test_update_policies_connected_to_rules_with_blank_model(): - client = utilities.register_client() - req, rules, policy_id = data_builder.add_rules(client) - req = client.get("/policies") - data = utilities.get_json(req.data) - for policy_obj_id in data['policies']: - if policy_obj_id == policy_id: - policy = data['policies'][policy_obj_id] - policy['model_id'] = '' - req = client.patch("/policies/{}".format(policy_id), data=json.dumps(policy), - headers={'Content-Type': 'application/json'}) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == '400: Policy update error' +# FIXME: uncomment when model API is re-inserted +# def test_update_policies_connected_to_rules_with_blank_model(): +# from moon_manager.api import policy +# req, rules, policy_id = data_builder.add_rules() +# req = hug.test.get(policy, "policies") +# for policy_obj_id in req.data['policies']: +# if policy_obj_id == policy_id: +# policy = req.data['policies'][policy_obj_id] +# policy['model_id'] = '' +# req = hug.test.patch("/policies/{}".format(policy_id), req.data) +# assert req.status == HTTP_400 +# assert req.data["message"] == '400: Policy update error' def test_delete_policies(): - client = utilities.register_client() - - policy = policy_helper.add_policies() - policy_id = list(policy.keys())[0] - - req = client.delete("/policies/{}".format(policy_id)) - assert req.status_code == 200 - - -def test_delete_policy_with_dependencies_rule(): - client = utilities.register_client() - req, rules, policy_id = data_builder.add_rules(client) - req = client.delete("/policies/{}".format(policy_id)) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == '400: Policy With Rule Error' - - -def test_delete_policy_with_dependencies_subject_data(): - client = utilities.register_client() - req, rules, policy_id = data_builder.add_rules(client) - req = client.delete("/policies/{}/rules/{}".format(policy_id, next(iter(rules['rules'])))) - assert req.status_code == 200 - req = client.delete("/policies/{}".format(policy_id)) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == '400: Policy With Data Error' - - -def test_delete_policy_with_dependencies_perimeter(): - client = utilities.register_client() - policy = policy_helper.add_policies() - policy_id = next(iter(policy)) - - data = { - "name": 'testuser'+uuid4().hex, - "description": "description of {}".format(uuid4().hex), - "password": "password for {}".format(uuid4().hex), - "email": "{}@moon".format(uuid4().hex) - } - req = client.post("/policies/{}/subjects".format(policy_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - - assert req.status_code == 200 - req = client.delete("/policies/{}".format(policy_id)) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == '400: Policy With Perimeter Error' + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import policy + _policy = policy_helper.add_policies() + policy_id = list(_policy.keys())[0] + req = hug.test.delete(policy, "policies/{}".format(policy_id), headers=auth_headers) + assert req.status == HTTP_200 + + +# FIXME: uncomment when rule API is re-inserted +# def test_delete_policy_with_dependencies_rule(): +# from moon_manager.api import policy +# req, rules, policy_id = data_builder.add_rules() +# req = hug.test.delete(policy, "policies/{}".format(policy_id)) +# assert req.status == HTTP_400 +# assert req.data["message"] == '400: Policy With Rule Error' + + +# FIXME: uncomment when perimeter API is re-inserted +# def test_delete_policy_with_dependencies_subject_data(): +# from moon_manager.api import policy +# req, rules, policy_id = data_builder.add_rules() +# req = hug.test.delete(policy, "policies/{}/rules/{}".format(policy_id, next(iter(rules['rules'])))) +# assert req.status == HTTP_200 +# req = hug.test.delete(policy, "policies/{}".format(policy_id)) +# assert req.status == HTTP_400 +# assert req.data["message"] == '400: Policy With Data Error' + + +# FIXME: uncomment when perimeter API is re-inserted +# def test_delete_policy_with_dependencies_perimeter(): +# from moon_manager.api import policy +# _policy = policy_helper.add_policies() +# policy_id = next(iter(_policy)) +# +# data = { +# "name": 'testuser'+uuid4().hex, +# "description": "description of {}".format(uuid4().hex), +# "password": "password for {}".format(uuid4().hex), +# "email": "{}@moon".format(uuid4().hex) +# } +# req = hug.test.post(policy, "policies/{}/subjects".format(policy_id), data) +# +# assert req.status == HTTP_200 +# req = hug.test.delete(policy, "policies/{}".format(policy_id)) +# assert req.status == HTTP_400 +# assert req.data["message"] == '400: Policy With Perimeter Error' def test_delete_policies_without_id(): - client = utilities.register_client() - req = delete_policies_without_id(client) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == '400: Policy Unknown' + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + req = delete_policies_without_id(auth_headers=auth_headers) + assert req.status == HTTP_405 diff --git a/moon_manager/tests/unit_python/api/test_rules.py b/moon_manager/tests/unit_python/api/test_rules.py index a3c21839..2bb7a96f 100644 --- a/moon_manager/tests/unit_python/api/test_rules.py +++ b/moon_manager/tests/unit_python/api/test_rules.py @@ -1,114 +1,317 @@ -import api.utilities as utilities +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +import pytest +from moon_utilities import exceptions import json from helpers import data_builder as builder -from uuid import uuid4 from helpers import policy_helper +from helpers import rules_helper +import hug + +def get_rules(policy_id): + from moon_manager.api import rules + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} -def get_rules(client, policy_id): - req = client.get("/policies/{}/rules".format(policy_id)) - rules = utilities.get_json(req.data) + req = hug.test.get(rules, "/policies/{}/rules".format(policy_id), headers=auth_headers) + rules = req.data return req, rules -def add_rules_without_policy_id(client): +def add_rules_without_policy_id(headers): + from moon_manager.api import rules subject_category_id, object_category_id, action_category_id, meta_rule_id = builder.create_new_meta_rule() data = { "meta_rule_id": meta_rule_id, "rule": [subject_category_id, object_category_id, action_category_id], - "instructions": ( + "instructions": [ {"decision": "grant"}, - ), + ], "enabled": True } - req = client.post("/policies/{}/rules".format(None), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - rules = utilities.get_json(req.data) + headers['Content-Type'] = 'application/json' + req = hug.test.post(rules, "/policies/{}/rules".format(None), body=json.dumps(data), + headers=headers) + rules = req.data return req, rules -def add_rules_without_meta_rule_id(client, policy_id): +def add_rules_without_meta_rule_id(policy_id, headers): + from moon_manager.api import rules data = { "meta_rule_id": "", "rule": ["subject_data_id2", "object_data_id2", "action_data_id2"], - "instructions": ( + "instructions": [ {"decision": "grant"}, - ), + ], "enabled": True } - req = client.post("/policies/{}/rules".format(policy_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - rules = utilities.get_json(req.data) + headers['Content-Type'] = 'application/json' + req = hug.test.post(rules, "/policies/{}/rules".format(policy_id), body=json.dumps(data), + headers=headers) + rules = req.data return req, rules -def add_rules_without_rule(client, policy_id): +def add_rules_without_rule(policy_id, headers): + from moon_manager.api import rules data = { "meta_rule_id": "meta_rule_id1", - "instructions": ( + "instructions": [ {"decision": "grant"}, - ), + ], "enabled": True } - req = client.post("/policies/{}/rules".format(policy_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - rules = utilities.get_json(req.data) + headers['Content-Type'] = 'application/json' + req = hug.test.post(rules, "/policies/{}/rules".format(policy_id), body=json.dumps(data), + headers=headers) + rules = req.data return req, rules -def delete_rules(client, policy_id, meta_rule_id): - req = client.delete("/policies/{}/rules/{}".format(policy_id, meta_rule_id)) +def delete_rules(policy_id, meta_rule_id, headers): + from moon_manager.api import rules + req = hug.test.delete(rules, "/policies/{}/rules/{}".format(policy_id, meta_rule_id), + headers=headers) return req -def test_get_rules(): - policy_id = utilities.get_policy_id() - client = utilities.register_client() - req, rules = get_rules(client, policy_id) - assert req.status_code == 200 +def update_rule(policy_id, rule_id, instructions, headers): + from moon_manager.api import rules + req = hug.test.patch(rules, "/policies/{}/rules/{}".format(policy_id, rule_id), + headers=headers, + body=instructions) + return req + + +def test_add_rules_with_invalid_decision_instructions(): + from moon_manager.api import rules + + auth_headers = rules_helper.get_headers() + subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = builder.create_new_policy() + + data = { + "meta_rule_id": meta_rule_id, + "rule": [subject_category_id, object_category_id, action_category_id], + "instructions": [ + {"decision": "invalid"}, + ], + "enabled": True + } + + with pytest.raises(exceptions.RuleContentError) as exception_info: + hug.test.post(rules, "/policies/{}/rules".format(policy_id), body=json.dumps(data), + headers=auth_headers) + assert "400: Rule Error" == str(exception_info.value) + + +def test_add_rules_with_meta_rule_not_linked_with_policy_model(): + from moon_manager.api import rules + + auth_headers = rules_helper.get_headers() + policy_id = builder.create_new_policy()[-1] + meta_rule_id = builder.create_new_meta_rule()[-1] + + data = { + "meta_rule_id": meta_rule_id, + "rule": ["subject_data_id2", "object_data_id2", "action_data_id2"], + "instructions": [ + {"decision": "grant"}, + ], + "enabled": True + } + + with pytest.raises(exceptions.MetaRuleNotLinkedWithPolicyModel) as exception_info: + hug.test.post(rules, "/policies/{}/rules".format(policy_id), body=json.dumps(data), + headers=auth_headers) + assert "400: MetaRule Not Linked With Model - Policy" == str(exception_info.value) + + +def test_add_rules_with_invalid_rule(): + from moon_manager.api import rules + + auth_headers = rules_helper.get_headers() + + subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = builder.create_new_policy() + sub_data_id = builder.create_subject_data(policy_id, subject_category_id) + obj_data_id = builder.create_object_data(policy_id, object_category_id) + act_data_id = builder.create_action_data(policy_id, action_category_id) + + data = { + "meta_rule_id": meta_rule_id, + "rule": [obj_data_id, sub_data_id, act_data_id], + "instructions": [ + {"decision": "grant"}, + ], + "enabled": True + } + + with pytest.raises(exceptions.RuleContentError) as exception_info: + hug.test.post(rules, "/policies/{}/rules".format(policy_id), body=json.dumps(data), + headers=auth_headers) + assert "400: Rule Error" == str(exception_info.value) + + +def test_add_rules_with_no_given_decision_instructions(policy_id=None): + from moon_manager.api import rules + + auth_headers = rules_helper.get_headers() + subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = builder.create_new_policy() + sub_data_id = builder.create_subject_data(policy_id, subject_category_id) + obj_data_id = builder.create_object_data(policy_id, object_category_id) + act_data_id = builder.create_action_data(policy_id, action_category_id) + + data = { + "meta_rule_id": meta_rule_id, + "rule": [sub_data_id, obj_data_id, act_data_id], + "instructions": [], + "enabled": True + } + + req = hug.test.post(rules, "/policies/{}/rules".format(policy_id), body=json.dumps(data), + headers=auth_headers) + + assert req.status == hug.HTTP_200 + + default_instruction = {"decision": "grant"} + rules = req.data['rules'] + rule_id = next(iter(req.data['rules'])) + assert rules[rule_id]["instructions"][0] == default_instruction + + +def test_get_rules(policy_id=None): + if policy_id == None: + policy = policy_helper.add_policies() + policy_id = next(iter(policy)) + + req, rules = get_rules(policy_id) + assert req.status == hug.HTTP_200 assert isinstance(rules, dict) assert "rules" in rules return req, rules def test_add_rules(): - client = utilities.register_client() - req, rules, policy = builder.add_rules(client, ) - assert req.status_code == 200 + req, rules, policy = builder.add_rules() + assert req.status == hug.HTTP_200 def test_add_rules_without_policy_id(): - client = utilities.register_client() - req, rules = add_rules_without_policy_id(client) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == "400: Policy Unknown" + from moon_manager.api import rules + + subject_category_id, object_category_id, action_category_id, meta_rule_id = builder.create_new_meta_rule() + data = { + "meta_rule_id": meta_rule_id, + "rule": [subject_category_id, object_category_id, action_category_id], + "instructions": [ + {"decision": "grant"}, + ], + "enabled": True + } + + headers = rules_helper.get_headers() + with pytest.raises(exceptions.PolicyUnknown) as exception_info: + req = hug.test.post(rules, "/policies/{}/rules".format(None), body=json.dumps(data), + headers=headers) + assert "400: Policy Unknown" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == "400: Policy Unknown" + # # def test_add_rules_without_meta_rule_id(): # policy_id = utilities.get_policy_id() # client = utilities.register_client() # req, rules = add_rules_without_meta_rule_id(client, policy_id) -# assert req.status_code == 400 +# assert req.status == 400 # assert json.loads(req.data)["message"] == "Key: 'meta_rule_id', [Empty String]" def test_add_rules_without_rule(): - policy_id = utilities.get_policy_id() - client = utilities.register_client() - req, rules = add_rules_without_rule(client, policy_id) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == 'Invalid Key :rule not found' + from moon_utilities.auth_functions import get_api_key_for_user + policy = policy_helper.add_policies() + policy_id = next(iter(policy)) + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + with pytest.raises(exceptions.ValidationKeyError) as exception_info: + req, rules = add_rules_without_rule(policy_id, headers=auth_headers) + assert "Invalid Key :rule not found" == str(exception_info.value) + # assert req.status == hug.HTTP_400 + # assert req.data["message"] == 'Invalid Key :rule not found' + + +def test_update_rule_without_body(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + req, rules, policy_id = builder.add_rules() + rule_id = list(rules['rules'].keys())[0] + + req = update_rule(policy_id, rule_id, instructions=None, headers=auth_headers) + + assert req.status == hug.HTTP_400 + + +def test_update_rule_without_instructions_in_body(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + data = {"instruction": [ # faute de frappe + {"decision": "deny"}, + ]} + + req, rules, policy_id = builder.add_rules() + rule_id = list(rules['rules'].keys())[0] + + req = update_rule(policy_id, rule_id, instructions=None, headers=auth_headers) + + assert req.status == hug.HTTP_400 + + +def test_update_rule(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + req, rules, policy_id = builder.add_rules() + rule_id = list(rules['rules'].keys())[0] + + data = {"instructions": [ + {"decision": "deny"}, + ]} + req = update_rule(policy_id, rule_id, data, headers=auth_headers) + + rules = get_rules(policy_id)[1]['rules']['rules'] + + rule = None + for rule_ in rules: + if rule_['id'] == rule_id: + rule = rule_ + break + + assert req.status == hug.HTTP_200 and rule['instructions'][0]['decision'] == "deny" def test_delete_rules_with_invalid_parameters(): - client = utilities.register_client() - req = delete_rules(client, "", "") - assert req.status_code == 404 - # assert json.loads(req.data)["message"] == 'Invalid Key :rule not found' + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + req = delete_rules("", "", headers=auth_headers) + assert req.status == hug.HTTP_405 def test_delete_rules_without_policy_id(): - client = utilities.register_client() + from moon_manager.api import rules + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = builder.create_new_policy() sub_data_id = builder.create_subject_data(policy_id, subject_category_id) obj_data_id = builder.create_object_data(policy_id, object_category_id) @@ -116,14 +319,15 @@ def test_delete_rules_without_policy_id(): data = { "meta_rule_id": meta_rule_id, "rule": [sub_data_id, obj_data_id, act_data_id], - "instructions": ( + "instructions": [ {"decision": "grant"}, - ), + ], "enabled": True } - client.post("/policies/{}/rules".format(policy_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - req, added_rules = get_rules(client, policy_id) + hug.test.post(rules, "/policies/{}/rules".format(policy_id), body=json.dumps(data), + headers={'Content-Type': 'application/json', + "X-Api-Key": get_api_key_for_user("admin")}) + req, added_rules = get_rules(policy_id) id = list(added_rules["rules"]["rules"])[0]["id"] - rules = delete_rules(client, None, id) - assert rules.status_code == 200 + rules = delete_rules(None, id, headers=auth_headers) + assert rules.status == hug.HTTP_200 diff --git a/moon_manager/tests/unit_python/api/test_slaves.py b/moon_manager/tests/unit_python/api/test_slaves.py new file mode 100644 index 00000000..29d5e62e --- /dev/null +++ b/moon_manager/tests/unit_python/api/test_slaves.py @@ -0,0 +1,90 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +from falcon import HTTP_200, HTTP_400, HTTP_405 +import hug +from uuid import uuid4 +from helpers import data_builder as builder + + +def test_get_slaves(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import slave + req = hug.test.get(slave, 'slaves/', headers=auth_headers) + assert req.status == HTTP_200 + assert isinstance(req.data, dict) + assert "slaves" in req.data + for slave in req.data.get("slaves"): + assert "name" in slave + assert "description" in slave + assert "status" in slave + assert "server_ip" in slave + assert "port" in slave + + +def test_add_slave(mocker): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import slave + mocker.patch('moon_manager.plugins.pyorchestrator.get_server_url', + return_value="http://127.0.0.1:10000") + mocker.patch("subprocess.Popen", return_value=True) + data = { + "name": "test_slave_" + uuid4().hex, + "description": "description of test_slave" + } + req = hug.test.post(slave, "slave/", data, headers=auth_headers) + assert req.status == HTTP_200 + assert isinstance(req.data, dict) + found = False + assert "slaves" in req.data + for value in req.data["slaves"].values(): + assert "name" in value + assert "description" in value + assert "api_key" in value + assert "process" in value + assert "log" in value + assert "extra" in value + if value['name'] == data['name']: + found = True + assert value["description"] == "description of test_slave" + assert "port" in value.get("extra") + assert "status" in value.get("extra") + assert "server_ip" in value.get("extra") + break + assert found + + +def test_delete_slave(mocker): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + from moon_manager.api import slave + mocker.patch('moon_manager.plugins.pyorchestrator.get_server_url', + return_value="http://127.0.0.1:10000") + mocker.patch("subprocess.Popen", return_value=True) + data = { + "name": "test_slave_" + uuid4().hex, + "description": "description of test_slave" + } + req = hug.test.post(slave, "slave/", data, headers=auth_headers) + assert req.status == HTTP_200 + assert isinstance(req.data, dict) + req = hug.test.get(slave, 'slaves/', headers=auth_headers) + success_req = None + for key, value in req.data['slaves'].items(): + if value['name'] == data['name']: + success_req = hug.test.delete(slave, 'slave/{}'.format(key), headers=auth_headers) + break + assert success_req + assert success_req.status == HTTP_200 + diff --git a/moon_manager/tests/unit_python/api/test_unit_models.py b/moon_manager/tests/unit_python/api/test_unit_models.py deleted file mode 100644 index 6e93ed28..00000000 --- a/moon_manager/tests/unit_python/api/test_unit_models.py +++ /dev/null @@ -1,352 +0,0 @@ -# Copyright 2018 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 json -import api.utilities as utilities -from helpers import data_builder as builder -from helpers import policy_helper -from helpers import model_helper -from uuid import uuid4 - - -def get_models(client): - req = client.get("/models") - models = utilities.get_json(req.data) - return req, models - - -def add_models(client, name, data=None): - subject_category_id, object_category_id, action_category_id, meta_rule_id = builder.create_new_meta_rule() - - if not data: - data = { - "name": name, - "description": "description of {}".format(name), - "meta_rules": [meta_rule_id] - } - req = client.post("/models", data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - models = utilities.get_json(req.data) - return req, models - - -def update_model(client, name, model_id): - subject_category_id, object_category_id, action_category_id, meta_rule_id = builder.create_new_meta_rule() - - data = { - "name": name, - "description": "description of {}".format(name), - "meta_rules": [meta_rule_id] - } - req = client.patch("/models/{}".format(model_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - models = utilities.get_json(req.data) - return req, models - - -def add_model_without_meta_rules_ids(client, name): - data = { - "name": name, - "description": "description of {}".format(name), - "meta_rules": [] - } - req = client.post("/models", data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - models = utilities.get_json(req.data) - return req, models - - -def add_model_with_empty_meta_rule_id(client, name): - data = { - "name": name, - "description": "description of {}".format(name), - "meta_rules": [""] - } - req = client.post("/models", data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - models = utilities.get_json(req.data) - return req, models - - -def update_model_without_meta_rules_ids(client, model_id): - name = "model_id" + uuid4().hex - data = { - "name": name, - "description": "description of {}".format(name), - "meta_rules": [] - } - req = client.patch("/models/{}".format(model_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - models = utilities.get_json(req.data) - return req, models - - -def delete_models(client, name): - request, models = get_models(client) - for key, value in models['models'].items(): - if value['name'] == name: - req = client.delete("/models/{}".format(key)) - break - return req - - -def delete_models_without_id(client): - req = client.delete("/models/{}".format("")) - return req - - -def test_delete_model_assigned_to_policy(): - policy_name = "testuser" + uuid4().hex - client = utilities.register_client() - req = model_helper.add_model(model_id="mls_model_id" + uuid4().hex) - model_id = list(req.keys())[0] - data = { - "name": policy_name, - "description": "description of {}".format(policy_name), - "model_id": model_id, - "genre": "genre" - } - req = client.post("/policies", data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - req = client.delete("/models/{}".format(model_id)) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == '400: Model With Policy Error' - - -def clean_models(): - client = utilities.register_client() - req, models = get_models(client) - for key, value in models['models'].items(): - print(key) - print(value) - client.delete("/models/{}".format(key)) - - -def test_get_models(): - client = utilities.register_client() - req, models = get_models(client) - assert req.status_code == 200 - assert isinstance(models, dict) - assert "models" in models - - -def test_add_models(): - clean_models() - client = utilities.register_client() - req, models = add_models(client, "testuser") - assert req.status_code == 200 - assert isinstance(models, dict) - model_id = list(models["models"])[0] - assert "models" in models - assert models['models'][model_id]['name'] == "testuser" - assert models['models'][model_id]["description"] == "description of {}".format("testuser") - - -def test_delete_models(): - client = utilities.register_client() - req = delete_models(client, "testuser") - assert req.status_code == 200 - - -def test_update_models_with_assigned_policy(): - client = utilities.register_client() - - model = model_helper.add_model(model_id="mls_model_id" + uuid4().hex) - model_id = list(model.keys())[0] - value = { - "name": "test_policy" + uuid4().hex, - "model_id": model_id, - "description": "test", - } - policy = policy_helper.add_policies(value=value) - data = { - "name": "model_" + uuid4().hex, - "description": "description of model_2", - "meta_rules": [] - } - req = client.patch("/models/{}".format(model_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - - assert req.status_code == 400 - assert json.loads(req.data)["message"] == "400: Model With Policy Error" - - -def test_update_models_with_no_assigned_policy(): - client = utilities.register_client() - - model = model_helper.add_model(model_id="mls_model_id" + uuid4().hex) - model_id = list(model.keys())[0] - - data = { - "name": "model_" + uuid4().hex, - "description": "description of model_2", - "meta_rules": [] - } - req = client.patch("/models/{}".format(model_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - - assert req.status_code == 200 - - -def test_add_models_with_meta_rule_key(): - client = utilities.register_client() - - model = model_helper.add_model(model_id="mls_model_id" + uuid4().hex) - model_id = list(model.keys())[0] - - data = { - "name": "model_" + uuid4().hex, - "description": "description of model_2", - - } - req = client.patch("/models/{}".format(model_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - - assert req.status_code == 400 - assert json.loads(req.data)["message"] == "Invalid Key :meta_rules not found" - - -def test_delete_models_without_id(): - client = utilities.register_client() - req = delete_models_without_id(client) - assert req.status_code == 400 - assert json.loads(req.data)["message"] == "400: Model Unknown" - - -def test_add_model_with_empty_name(): - clean_models() - client = utilities.register_client() - req, models = add_models(client, "
") - assert req.status_code == 400 - assert json.loads(req.data)["message"] == "Key: 'name', [Forbidden characters in string]" - - -def test_add_model_with_name_contain_space(): - clean_models() - client = utilities.register_client() - req, models = add_models(client, "test
user") - assert req.status_code == 400 - assert json.loads(req.data)["message"] == "Key: 'name', [Forbidden characters in string]" - - -def test_add_model_with_name_space(): - clean_models() - client = utilities.register_client() - req, models = add_models(client, " ") - assert req.status_code == 400 - assert json.loads(req.data)["message"] == '400: Model Unknown' - - -def test_add_model_with_empty_meta_rule_id(): - clean_models() - client = utilities.register_client() - req, meta_rules = add_model_with_empty_meta_rule_id(client, "testuser") - assert req.status_code == 400 - assert json.loads(req.data)["message"] == '400: Meta Rule Unknown' - - -def test_add_model_with_existed_name(): - clean_models() - client = utilities.register_client() - name = uuid4().hex - req, models = add_models(client, name) - assert req.status_code == 200 - req, models = add_models(client, name) - assert req.status_code == 409 - assert json.loads(req.data)["message"] == '409: Model Error' - - -def test_add_model_with_existed_meta_rules_list(): - clean_models() - client = utilities.register_client() - name = uuid4().hex - - subject_category_id, object_category_id, action_category_id, meta_rule_id = builder.create_new_meta_rule() - data = { - "name": name, - "description": "description of {}".format(name), - "meta_rules": [meta_rule_id] - } - name = uuid4().hex - req, models = add_models(client=client, name=name, data=data) - assert req.status_code == 200 - - data = { - "name": name, - "description": "description of {}".format(name), - "meta_rules": [meta_rule_id] - } - req, models = add_models(client=client, name=name, data=data) - assert req.status_code == 409 - assert json.loads(req.data)["message"] == '409: Model Error' - - -def test_add_model_without_meta_rules(): - clean_models() - client = utilities.register_client() - req, meta_rules = add_model_without_meta_rules_ids(client, "testuser") - assert req.status_code == 200 - # assert json.loads(req.data)["message"] == "Key: 'meta_rules', [Empty Container]" - - -def test_update_model(): - clean_models() - client = utilities.register_client() - req = add_models(client, "testuser") - model_id = list(req[1]['models'])[0] - req_update = update_model(client, "testuser", model_id) - assert req_update[0].status_code == 200 - model_id = list(req_update[1]["models"])[0] - assert req_update[1]["models"][model_id]["meta_rules"][0] is not None - delete_models(client, "testuser") - - -def test_update_model_name_with_space(): - clean_models() - client = utilities.register_client() - req = add_models(client, "testuser") - model_id = list(req[1]['models'])[0] - req_update = update_model(client, " ", model_id) - assert req_update[0].status_code == 400 - assert req_update[1]["message"] == '400: Model Unknown' - - -def test_update_model_with_empty_name(): - clean_models() - client = utilities.register_client() - req = add_models(client, "testuser") - model_id = list(req[1]['models'])[0] - req_update = update_model(client, "", model_id) - assert req_update[0].status_code == 400 - assert req_update[1]['message'] == '400: Model Unknown' - - -def test_update_meta_rules_without_id(): - clean_models() - client = utilities.register_client() - req_update = update_model(client, "testuser", "") - assert req_update[0].status_code == 400 - assert json.loads(req_update[0].data)["message"] == "400: Model Unknown" - - -def test_update_meta_rules_without_name(): - client = utilities.register_client() - req_update = update_model(client, "
", "1234567") - assert req_update[0].status_code == 400 - assert json.loads(req_update[0].data)[ - "message"] == "Key: 'name', [Forbidden characters in string]" - - -def test_update_meta_rules_without_meta_rules(): - value = { - "name": "mls_model_id" + uuid4().hex, - "description": "test", - "meta_rules": [] - } - model = model_helper.add_model(value=value) - model_id = list(model.keys())[0] - client = utilities.register_client() - req_update = update_model_without_meta_rules_ids(client, model_id) - assert req_update[0].status_code == 200 diff --git a/moon_manager/tests/unit_python/api/utilities.py b/moon_manager/tests/unit_python/api/utilities.py index 2e51fec8..baf59a51 100644 --- a/moon_manager/tests/unit_python/api/utilities.py +++ b/moon_manager/tests/unit_python/api/utilities.py @@ -1,26 +1,16 @@ -import json -from uuid import uuid4 +# Software Name: MOON -def get_json(data): - return json.loads(data.decode("utf-8")) +# Version: 5.4 +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 -def register_client(): - import moon_manager.server - server = moon_manager.server.create_server() - client = server.app.test_client() - return client +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. -def get_policy_id(): - from helpers import policy_helper - value = { - "name": "test_policy"+uuid4().hex, - "model_id": "", - "genre": "authz", - "description": "test", - } - policy_helper.add_policies(value=value) - req = policy_helper.get_policies() - policy_id = list(req.keys())[0] - return policy_id +import json +from uuid import uuid4 +def get_json(data): + return data;#json.loads(data.decode("utf-8")) diff --git a/moon_manager/tests/unit_python/conftest.py b/moon_manager/tests/unit_python/conftest.py index 90a27e54..702f3c19 100644 --- a/moon_manager/tests/unit_python/conftest.py +++ b/moon_manager/tests/unit_python/conftest.py @@ -1,254 +1,164 @@ -import base64 -import json -import logging +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +import os import pytest import requests_mock +import yaml +import mock_keystone +import mock_nova +import mock_engine +import mock_slaves + + +__CONF = """ +database: + url: sqlite:////tmp/database_test.db + driver: moon_manager.plugins.sql + migration_dir: moon_manager.api.db.migrations + +management: + url: http://127.0.0.1:8000 + user: admin + password: admin + token_file: db.json + +orchestration: + driver: moon_manager.plugins.pyorchestrator + connection: local + slaves: + port: 10000...10100 + pipelines: + port: 20000...20100 + +information: + user: admin + password: p4ssw0rd + domain: default + project: admin + check_token: false + certificate: false + url: http://keystone:5000/v3 + subjects: + drivers: + moon_manager.plugins.moon_keystone_plugin: + url: http://keystone:5000/v3 + objects: + drivers: + moon_manager.plugins.moon_nova_plugin: + url: http://keystone:5000/compute/v2.1 + + global_attrs: + driver: moon_manager.plugins.global_attrs + attributes: + mode: + values: + - build + - run + default: run + url: file:/tmp/mode + #url: https://127.0.0.1:8080/mode + #url: mysql+pymysql://moon:p4sswOrd1@db/moon_mode + #url: sqlite:////tmp/database.db + #url: driver://moon_manager.plugins.my_plugin -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": "orchestrator" - }, - "pipeline": { - "interface": { - "bind": "0.0.0.0", - "port": 8080, - "container": "wukongsun/moon_interface:v4.3", - "hostname": "interface" - }, - "authz": { - "bind": "0.0.0.0", - "port": 8081, - "container": "wukongsun/moon_authz:v4.3", - "hostname": "authz" - }, - } - }, - "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", - "components/orchestrator" -) - -PODS = { - "pods": { - "721760dd-de5f-11e7-8001-3863bbb766f3": [ - { - "pdp_id": "b3d3e18abf3340e8b635fd49e6634ccd", - "port": 8080, - "genre": "interface", - "name": "interface-paltry", - "keystone_project_id": "a64beb1cc224474fb4badd43173e7101", - "namespace": "moon", - "container": "wukongsun/moon_interface:v4.3" - }, - { - "pdp_id": "b3d3e18abf3340e8b635fd49e6634ccd", - "meta_rule_id": "f8f49a779ceb47b3ac810f01ef71b4e0", - "port": 8081, - "genre": "authz", - "name": "authz-economic", - "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0", - "keystone_project_id": "a64beb1cc224474fb4badd43173e7101", - "namespace": "moon", - "container": "wukongsun/moon_authz:v4.3" - } - ] - } -} - -SLAVES = { - "slaves": [ - { - "context": - { - "cluster": "kubernetes", - "user": "kubernetes-admin" - }, - "name": "kubernetes-admin@kubernetes", - "configured": True, - "wrapper_name": "mywrapper", - "ip": "NC", - "port": 31002, - "internal_port": 8080 - } - ] -} - - -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') +plugins: + directory: /var/moon/plugins + +components: + manager: + port: 8080 + bind: 0.0.0.0 + hostname: manager + +logging: + version: 1 + + formatters: + brief: + format: "%(levelname)s %(name)s %(message)-30s" + custom: + format: "%(asctime)-15s %(levelname)s %(name)s %(message)s" + + handlers: + console: + class : logging.StreamHandler + formatter: custom + level : INFO + stream : ext://sys.stdout + file: + class : logging.handlers.RotatingFileHandler + formatter: custom + level : DEBUG + filename: /tmp/moon.log + maxBytes: 1048576 + backupCount: 3 + + loggers: + moon: + level: DEBUG + handlers: [console, file] + propagate: no + + root: + level: ERROR + handlers: [console] +""" @pytest.fixture(autouse=True) def no_requests(monkeypatch): """ Modify the response from Requests module """ + global manager_api_key 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"} - ) - - def match_request_text(request): - # request.url may be None, or '' prevents a TypeError. - return 'http://keystone:5000/v3/users?name=testuser' in request.url - - m.register_uri( - requests_mock.ANY, '/v3/users', - additional_matcher=match_request_text, - json={"users": {}} - ) - m.register_uri( - 'POST', 'http://keystone:5000/v3/users/', - json={"users": [{"id": "1111111111111"}]} - ) - m.register_uri( - 'POST', 'http://orchestrator:8083/pods', - json=PODS, - headers={"content-type": "application/json"} - ) - m.register_uri( - 'GET', 'http://orchestrator:8083/pods', - json=PODS - ) - m.register_uri( - 'GET', 'http://localhost/slaves', - json=SLAVES - ) - m.register_uri( - 'DELETE', 'http://orchestrator:8083/pods/{}'.format(list([PODS['pods'].keys()])[0]), - headers={"content-type": "application/json"} - ) - - 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 + try: + os.remove("/tmp/database_test.db") + except FileNotFoundError: + pass + try: + os.remove("/tmp/moon.pwd") + except FileNotFoundError: + pass + print("Configure...") + from moon_manager.api.configuration import init_database, set_configuration + set_configuration(yaml.safe_load(__CONF)) + print("Create a new user") + from moon_utilities.auth_functions import add_user, init_db, get_api_key_for_user + init_db() + try: + user = add_user("admin", "admin") + manager_api_key = user["api_key"] + except KeyError: + print("User already exists") + manager_api_key = get_api_key_for_user("admin") + print("Initialize the database") + init_database() + from moon_manager import db_driver, orchestration_driver + + db_driver.init() + orchestration_driver.init() + + mock_keystone.register_keystone(m) + mock_nova.register_nova(m) + mock_engine.register_engine(m) + mock_slaves.register_slaves(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") + from moon_manager.pip_driver import InformationManager + for category in InformationManager: + for manager in InformationManager[category]: + manager.set_auth() + + yield m + for category in InformationManager: + for manager in InformationManager[category]: + manager.unset_auth() diff --git a/moon_manager/tests/unit_python/helpers/__init__.py b/moon_manager/tests/unit_python/helpers/__init__.py index e69de29b..582be686 100644 --- a/moon_manager/tests/unit_python/helpers/__init__.py +++ b/moon_manager/tests/unit_python/helpers/__init__.py @@ -0,0 +1,11 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + diff --git a/moon_manager/tests/unit_python/helpers/assignment_helper.py b/moon_manager/tests/unit_python/helpers/assignment_helper.py index 22a56e38..05d13c46 100644 --- a/moon_manager/tests/unit_python/helpers/assignment_helper.py +++ b/moon_manager/tests/unit_python/helpers/assignment_helper.py @@ -1,49 +1,57 @@ -# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors -# This software is distributed under the terms and conditions of the 'Apache-2.0' -# license which can be found in the file 'LICENSE' in this package distribution -# or at 'http://www.apache.org/licenses/LICENSE-2.0'. +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + def get_action_assignments(policy_id, action_id=None, category_id=None): - from python_moondb.core import PolicyManager + from moon_manager.db_driver import PolicyManager return PolicyManager.get_action_assignments("", policy_id, action_id, category_id) def add_action_assignment(policy_id, action_id, category_id, data_id): - from python_moondb.core import PolicyManager + from moon_manager.db_driver import PolicyManager return PolicyManager.add_action_assignment("", policy_id, action_id, category_id, data_id) def delete_action_assignment(policy_id, action_id, category_id, data_id): - from python_moondb.core import PolicyManager + from moon_manager.db_driver import PolicyManager PolicyManager.delete_action_assignment("", policy_id, action_id, category_id, data_id) def get_object_assignments(policy_id, object_id=None, category_id=None): - from python_moondb.core import PolicyManager + from moon_manager.db_driver import PolicyManager return PolicyManager.get_object_assignments("", policy_id, object_id, category_id) def add_object_assignment(policy_id, object_id, category_id, data_id): - from python_moondb.core import PolicyManager + from moon_manager.db_driver import PolicyManager return PolicyManager.add_object_assignment("", policy_id, object_id, category_id, data_id) def delete_object_assignment(policy_id, object_id, category_id, data_id): - from python_moondb.core import PolicyManager + from moon_manager.db_driver import PolicyManager PolicyManager.delete_object_assignment("", policy_id, object_id, category_id, data_id) def get_subject_assignments(policy_id, subject_id=None, category_id=None): - from python_moondb.core import PolicyManager + from moon_manager.db_driver import PolicyManager return PolicyManager.get_subject_assignments("", policy_id, subject_id, category_id) def add_subject_assignment(policy_id, subject_id, category_id, data_id): - from python_moondb.core import PolicyManager + from moon_manager.db_driver import PolicyManager return PolicyManager.add_subject_assignment("", policy_id, subject_id, category_id, data_id) def delete_subject_assignment(policy_id, subject_id, category_id, data_id): - from python_moondb.core import PolicyManager + from moon_manager.db_driver import PolicyManager PolicyManager.delete_subject_assignment("", policy_id, subject_id, category_id, data_id) diff --git a/moon_manager/tests/unit_python/helpers/category_helper.py b/moon_manager/tests/unit_python/helpers/category_helper.py index 6c419ca8..bbb04e09 100644 --- a/moon_manager/tests/unit_python/helpers/category_helper.py +++ b/moon_manager/tests/unit_python/helpers/category_helper.py @@ -1,40 +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'. +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + def add_subject_category(cat_id=None, value=None): - from python_moondb.core import ModelManager - category = ModelManager.add_subject_category(user_id=None, category_id=cat_id, value=value) + from moon_manager.db_driver import ModelManager + category = ModelManager.add_subject_category(moon_user_id=None, category_id=cat_id, value=value) return category def get_subject_category(cat_id=None): - from python_moondb.core import ModelManager - category = ModelManager.get_subject_categories(user_id=None, category_id=cat_id) + from moon_manager.db_driver import ModelManager + category = ModelManager.get_subject_categories(moon_user_id=None, category_id=cat_id) return category def add_object_category(cat_id=None, value=None): - from python_moondb.core import ModelManager - category = ModelManager.add_object_category(user_id=None, category_id=cat_id, value=value) + from moon_manager.db_driver import ModelManager + category = ModelManager.add_object_category(moon_user_id=None, category_id=cat_id, value=value) return category def get_object_category(cat_id=None): - from python_moondb.core import ModelManager - category = ModelManager.get_object_categories(user_id=None, category_id=cat_id) + from moon_manager.db_driver import ModelManager + category = ModelManager.get_object_categories(moon_user_id=None, category_id=cat_id) return category def add_action_category(cat_id=None, value=None): - from python_moondb.core import ModelManager - category = ModelManager.add_action_category(user_id=None, category_id=cat_id, value=value) + from moon_manager.db_driver import ModelManager + category = ModelManager.add_action_category(moon_user_id=None, category_id=cat_id, value=value) return category def get_action_category(cat_id=None): - from python_moondb.core import ModelManager - category = ModelManager.get_action_categories(user_id=None, category_id=cat_id) + from moon_manager.db_driver import ModelManager + category = ModelManager.get_action_categories(moon_user_id=None, category_id=cat_id) return category diff --git a/moon_manager/tests/unit_python/helpers/data_builder.py b/moon_manager/tests/unit_python/helpers/data_builder.py index 91808cbe..e2799375 100644 --- a/moon_manager/tests/unit_python/helpers/data_builder.py +++ b/moon_manager/tests/unit_python/helpers/data_builder.py @@ -1,15 +1,21 @@ -# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors -# This software is distributed under the terms and conditions of the 'Apache-2.0' -# license which can be found in the file 'LICENSE' in this package distribution -# or at 'http://www.apache.org/licenses/LICENSE-2.0'. +# Software Name: MOON +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +import hug from .category_helper import * from .policy_helper import * from .data_helper import * from helpers import model_helper from .meta_rule_helper import * -import api.utilities as utilities -import json from uuid import uuid4 @@ -55,7 +61,7 @@ def create_pdp(policies_ids): value = { "name": "test_pdp", "security_pipeline": policies_ids, - "keystone_project_id": "keystone_project_id1", + "vim_project_id": "vim_project_id1", "description": "...", } return value @@ -96,7 +102,7 @@ def create_new_policy(subject_category_name=None, object_category_name=None, def create_new_meta_rule(subject_category_name=None, object_category_name=None, - action_category_name=None, meta_rule_name=None): + action_category_name=None, meta_rule_name=None, empty=None): if not subject_category_name: subject_category_name = "subjectCategory_" + uuid4().hex if not object_category_name: @@ -116,6 +122,12 @@ def create_new_meta_rule(subject_category_name=None, object_category_name=None, "object_categories": [object_category_id], "action_categories": [action_category_id] } + if empty == 'subject': + value["subject_categories"] = [] + if empty == 'object': + value["object_categories"] = [] + if empty == 'action': + value["action_categories"] = [] meta_rule = add_meta_rule(value=value) return subject_category_id, object_category_id, action_category_id, list(meta_rule.keys())[0] @@ -179,7 +191,10 @@ def create_action_data(policy_id, category_id): def get_policy_id_with_subject_assignment(): - client = utilities.register_client() + from moon_manager.api import assignments + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = create_new_policy( subject_category_name="subject_category1" + uuid4().hex, object_category_name="object_category1" + uuid4().hex, @@ -193,13 +208,16 @@ def get_policy_id_with_subject_assignment(): "category_id": subject_category_id, "data_id": data_id } - client.post("/policies/{}/subject_assignments".format(policy_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) + response = hug.test.post(assignments, "/policies/{}/subject_assignments/".format(policy_id), + body=data, headers=auth_headers) return policy_id def get_policy_id_with_object_assignment(): - client = utilities.register_client() + from moon_manager.api import assignments + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = create_new_policy( subject_category_name="subject_category1" + uuid4().hex, object_category_name="object_category1" + uuid4().hex, @@ -214,13 +232,16 @@ def get_policy_id_with_object_assignment(): "data_id": data_id } - client.post("/policies/{}/object_assignments".format(policy_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) + hug.test.post(assignments, "policies/{}/object_assignments".format(policy_id), body=data, + headers=auth_headers) return policy_id def get_policy_id_with_action_assignment(): - client = utilities.register_client() + from moon_manager.api import assignments + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = create_new_policy( subject_category_name="subject_category1" + uuid4().hex, object_category_name="object_category1" + uuid4().hex, @@ -234,12 +255,16 @@ def get_policy_id_with_action_assignment(): "category_id": action_category_id, "data_id": data_id } - client.post("/policies/{}/action_assignments".format(policy_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) + hug.test.post(assignments, "policies/{}/action_assignments".format(policy_id), body =data, + headers=auth_headers) return policy_id -def add_rules(client): +def add_rules(): + from moon_manager.api import rules + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + sub_id, obj_id, act_id, meta_rule_id, policy_id = create_new_policy("sub_cat" + uuid4().hex, "obj_cat" + uuid4().hex, "act_cat" + uuid4().hex) @@ -249,12 +274,10 @@ def add_rules(client): data = { "meta_rule_id": meta_rule_id, "rule": [sub_data_id, obj_data_id, act_data_id], - "instructions": ( + "instructions": [ {"decision": "grant"}, - ), + ], "enabled": True } - req = client.post("/policies/{}/rules".format(policy_id), data=json.dumps(data), - headers={'Content-Type': 'application/json'}) - rules = utilities.get_json(req.data) - return req, rules, policy_id + req = hug.test.post(rules, "policies/{}/rules".format(policy_id), body=data, headers=auth_headers) + return req, req.data, policy_id diff --git a/moon_manager/tests/unit_python/helpers/data_helper.py b/moon_manager/tests/unit_python/helpers/data_helper.py index e1c05640..cb1ee38c 100644 --- a/moon_manager/tests/unit_python/helpers/data_helper.py +++ b/moon_manager/tests/unit_python/helpers/data_helper.py @@ -1,99 +1,106 @@ -# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors -# This software is distributed under the terms and conditions of the 'Apache-2.0' -# license which can be found in the file 'LICENSE' in this package distribution -# or at 'http://www.apache.org/licenses/LICENSE-2.0'. +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + def get_action_data(policy_id, data_id=None, category_id=None): - from python_moondb.core import PolicyManager - return PolicyManager.get_action_data("", policy_id, data_id, category_id) + from moon_manager.db_driver import PolicyManager + return PolicyManager.get_action_data(moon_user_id="admin", policy_id=policy_id, data_id=data_id, category_id=category_id) def add_action_data(policy_id, data_id=None, category_id=None, value=None): - from python_moondb.core import PolicyManager - return PolicyManager.add_action_data("", policy_id, data_id, category_id, value) + from moon_manager.db_driver import PolicyManager + return PolicyManager.add_action_data(moon_user_id="admin", policy_id=policy_id, data_id=data_id, category_id=category_id, value=value) def delete_action_data(policy_id, data_id): - from python_moondb.core import PolicyManager - PolicyManager.delete_action_data("", policy_id=policy_id, data_id=data_id) + from moon_manager.db_driver import PolicyManager + PolicyManager.delete_action_data(moon_user_id="admin", policy_id=policy_id, data_id=data_id) def get_object_data(policy_id, data_id=None, category_id=None): - from python_moondb.core import PolicyManager - return PolicyManager.get_object_data("", policy_id, data_id, category_id) + from moon_manager.db_driver import PolicyManager + return PolicyManager.get_object_data(moon_user_id="admin", policy_id=policy_id, data_id=data_id, category_id=category_id) def add_object_data(policy_id, data_id=None, category_id=None, value=None): - from python_moondb.core import PolicyManager - return PolicyManager.add_object_data("", policy_id, data_id, category_id, value) + from moon_manager.db_driver import PolicyManager + return PolicyManager.add_object_data(moon_user_id="admin", policy_id=policy_id, data_id=data_id, category_id=category_id, value=value) def delete_object_data(policy_id, data_id): - from python_moondb.core import PolicyManager - PolicyManager.delete_object_data("", policy_id=policy_id, data_id=data_id) + from moon_manager.db_driver import PolicyManager + PolicyManager.delete_object_data(moon_user_id="admin", policy_id=policy_id, data_id=data_id) def get_subject_data(policy_id, data_id=None, category_id=None): - from python_moondb.core import PolicyManager - return PolicyManager.get_subject_data("", policy_id, data_id, category_id) + from moon_manager.db_driver import PolicyManager + return PolicyManager.get_subject_data(moon_user_id="admin", policy_id=policy_id, data_id=data_id, category_id=category_id) def add_subject_data(policy_id, data_id=None, category_id=None, value=None): - from python_moondb.core import PolicyManager - return PolicyManager.set_subject_data("", policy_id, data_id, category_id, value) + from moon_manager.db_driver import PolicyManager + return PolicyManager.set_subject_data(moon_user_id="admin", policy_id=policy_id, data_id=data_id, category_id=category_id, value=value) def delete_subject_data(policy_id, data_id): - from python_moondb.core import PolicyManager - PolicyManager.delete_subject_data("", policy_id=policy_id, data_id=data_id) + from moon_manager.db_driver import PolicyManager + PolicyManager.delete_subject_data(moon_user_id="admin", policy_id=policy_id, data_id=data_id) def get_actions(policy_id, perimeter_id=None): - from python_moondb.core import PolicyManager - return PolicyManager.get_actions("", policy_id, perimeter_id) + from moon_manager.db_driver import PolicyManager + return PolicyManager.get_actions(moon_user_id="admin", policy_id=policy_id, perimeter_id=perimeter_id) def add_action(policy_id, perimeter_id=None, value=None): - from python_moondb.core import PolicyManager - return PolicyManager.add_action("", policy_id, perimeter_id, value) + from moon_manager.db_driver import PolicyManager + return PolicyManager.add_action(moon_user_id="admin", policy_id=policy_id, perimeter_id=perimeter_id, value=value) def delete_action(policy_id, perimeter_id): - from python_moondb.core import PolicyManager - PolicyManager.delete_action("", policy_id, perimeter_id) + from moon_manager.db_driver import PolicyManager + PolicyManager.delete_action(moon_user_id="admin", policy_id=policy_id, perimeter_id=perimeter_id) def get_objects(policy_id, perimeter_id=None): - from python_moondb.core import PolicyManager - return PolicyManager.get_objects("", policy_id, perimeter_id) + from moon_manager.db_driver import PolicyManager + return PolicyManager.get_objects(moon_user_id="admin", policy_id=policy_id, perimeter_id=perimeter_id) def add_object(policy_id, perimeter_id=None, value=None): - from python_moondb.core import PolicyManager - return PolicyManager.add_object("", policy_id, perimeter_id, value) + from moon_manager.db_driver import PolicyManager + return PolicyManager.add_object(moon_user_id="admin", policy_id=policy_id, perimeter_id=perimeter_id, value=value) def delete_object(policy_id, perimeter_id): - from python_moondb.core import PolicyManager - PolicyManager.delete_object("", policy_id, perimeter_id) + from moon_manager.db_driver import PolicyManager + PolicyManager.delete_object(moon_user_id="admin", policy_id=policy_id, perimeter_id=perimeter_id) def get_subjects(policy_id, perimeter_id=None): - from python_moondb.core import PolicyManager - return PolicyManager.get_subjects("", policy_id, perimeter_id) + from moon_manager.db_driver import PolicyManager + return PolicyManager.get_subjects(moon_user_id="admin", policy_id=policy_id, perimeter_id=perimeter_id) def add_subject(policy_id, perimeter_id=None, value=None): - from python_moondb.core import PolicyManager - return PolicyManager.add_subject("", policy_id, perimeter_id, value) + from moon_manager.db_driver import PolicyManager + return PolicyManager.add_subject(moon_user_id="admin", policy_id=policy_id, perimeter_id=perimeter_id, value=value) def delete_subject(policy_id, perimeter_id): - from python_moondb.core import PolicyManager - PolicyManager.delete_subject("", policy_id, perimeter_id) + from moon_manager.db_driver import PolicyManager + PolicyManager.delete_subject(moon_user_id="admin", policy_id=policy_id, perimeter_id=perimeter_id) def get_available_metadata(policy_id): - from python_moondb.core import PolicyManager - return PolicyManager.get_available_metadata("", policy_id) + from moon_manager.db_driver import PolicyManager + return PolicyManager.get_available_metadata(moon_user_id="admin", policy_id=policy_id) diff --git a/moon_manager/tests/unit_python/helpers/import_export_helper.py b/moon_manager/tests/unit_python/helpers/import_export_helper.py new file mode 100644 index 00000000..1ba94fd0 --- /dev/null +++ b/moon_manager/tests/unit_python/helpers/import_export_helper.py @@ -0,0 +1,287 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +from api import test_models as test_models +from api import test_policies as test_policies +from api import test_perimeter as test_perimeter +from api import test_meta_data as test_categories +from api import test_data as test_data +from api import test_meta_rules as test_meta_rules +from api import test_assignement as test_assignments +from api import test_rules as test_rules +import logging +import hug + +logger = logging.getLogger("moon.manager.test.api." + __name__) + + +def clean_models(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + req, models = test_models.get_models() + for key in models["models"]: + from moon_manager.api import models + hug.test.delete(models, "/models/{}".format(key), headers=auth_headers) + + +def clean_policies(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + req = test_policies.get_policies(auth_headers=auth_headers) + + policies = req.data + for key in policies["policies"]: + from moon_manager.api import policy + req = hug.test.delete(policy, "/policies/{}".format(key), headers=auth_headers) + assert req.status == hug.HTTP_200 + + +def clean_subjects(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + subjects = test_perimeter.get_subjects() + logger.info("subjects {}".format(subjects)) + for key in subjects[1]["subjects"]: + subject = subjects[1]["subjects"][key] + policy_keys = subject["policy_list"] + logger.info("subjects policy_keys {}".format(policy_keys)) + for policy_key in policy_keys: + from moon_manager.api import perimeter + hug.test.delete(perimeter, "/policies/{}/subjects/{}".format(policy_key, key), headers=auth_headers ) + hug.test.delete(perimeter, "/subjects/{}".format(key), headers=auth_headers) + + +def clean_objects(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + objects = test_perimeter.get_objects() + logger.info("objects {}".format(objects)) + for key in objects[1]["objects"]: + object_ = objects[1]["objects"][key] + policy_keys = object_["policy_list"] + logger.info("objects policy_keys {}".format(policy_keys)) + for policy_key in policy_keys: + from moon_manager.api import perimeter + hug.test.delete(perimeter, "/policies/{}/objects/{}".format(policy_key, key), headers=auth_headers ) + hug.test.delete(perimeter, "/objects/{}".format(key), headers=auth_headers) + +def clean_actions(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + actions = test_perimeter.get_actions() + logger.info("actions {}".format(actions)) + for key in actions[1]["actions"]: + action = actions[1]["actions"][key] + policy_keys = action["policy_list"] + logger.info("action policy_keys {}".format(policy_keys)) + from moon_manager.api import perimeter + for policy_key in policy_keys: + hug.test.delete(perimeter, "/policies/{}/actions/{}".format(policy_key, key), headers=auth_headers) + hug.test.delete(perimeter, "/actions/{}".format(key), headers=auth_headers) + + + +def clean_subject_categories(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + req, categories = test_categories.get_subject_categories() + logger.info(categories) + for key in categories["subject_categories"]: + from moon_manager.api import meta_data + hug.test.delete(meta_data, "/subject_categories/{}".format(key), headers=auth_headers) + + +def clean_object_categories(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + req, categories = test_categories.get_object_categories() + logger.info(categories) + for key in categories["object_categories"]: + from moon_manager.api import meta_data + hug.test.delete(meta_data, "/object_categories/{}".format(key), headers=auth_headers) + + +def clean_action_categories(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + req, categories = test_categories.get_action_categories() + logger.info(categories) + for key in categories["action_categories"]: + from moon_manager.api import meta_data + hug.test.delete(meta_data, "/action_categories/{}".format(key), headers=auth_headers) + + +def clean_subject_data(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + req = test_policies.get_policies(auth_headers=auth_headers) + + policies = req.data + logger.info("clean_subject_data on {}".format(policies)) + for policy_key in policies["policies"]: + req, data = test_data.get_subject_data(policy_id=policy_key) + logger.info("============= data {}".format(data)) + for data_item in data["subject_data"]: + if data_item["data"]: + for data_id in data_item["data"]: + logger.info("============= Deleting {}/{}".format(policy_key, data_id)) + from moon_manager.api import data + hug.test.delete(data, "/policies/{}/subject_data/{}/{}".format(policy_key, + data_item['category_id'], data_id), headers=auth_headers) + + +def clean_object_data(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + req = test_policies.get_policies(auth_headers=auth_headers) + + policies = req.data + for policy_key in policies["policies"]: + req, data = test_data.get_object_data(policy_id=policy_key) + for data_item in data["object_data"]: + if data_item["data"]: + for data_id in data_item["data"]: + logger.info("============= object_data {}/{}".format(policy_key, data_id)) + from moon_manager.api import data + hug.test.delete(data, "/policies/{}/object_data/{}/{}".format(policy_key, + data_item['category_id'], data_id), headers=auth_headers) + + +def clean_action_data(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + req = test_policies.get_policies(auth_headers=auth_headers) + + policies = req.data + for policy_key in policies["policies"]: + req, data = test_data.get_action_data(policy_id=policy_key) + for data_item in data["action_data"]: + if data_item["data"]: + for data_id in data_item["data"]: + logger.info("============= action_data {}/{}".format(policy_key, data_id)) + from moon_manager.api import data + hug.test.delete(data, "/policies/{}/action_data/{}/{}".format(policy_key, + data_item['category_id'], data_id), headers=auth_headers) + + +def clean_meta_rule(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + req, meta_rules_obj = test_meta_rules.get_meta_rules() + meta_rules_obj = meta_rules_obj["meta_rules"] + for meta_rule_key in meta_rules_obj: + logger.info("clean_meta_rule.meta_rule_key={}".format(meta_rule_key)) + logger.info("clean_meta_rule.meta_rule={}".format(meta_rules_obj[meta_rule_key])) + from moon_manager.api import meta_rules + hug.test.delete(meta_rules, "/meta_rules/{}".format(meta_rule_key), headers=auth_headers) + + +def clean_subject_assignments(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + req = test_policies.get_policies(auth_headers=auth_headers) + + policies = req.data + for policy_key in policies["policies"]: + req, assignments = test_assignments.get_subject_assignment(policy_key) + for key in assignments["subject_assignments"]: + subject_key = assignments["subject_assignments"][key]["subject_id"] + cat_key = assignments["subject_assignments"][key]["category_id"] + data_keys = assignments["subject_assignments"][key]["assignments"] + for data_key in data_keys: + from moon_manager.api import assignments + hug.test.delete(assignments, + "/policies/{}/subject_assignments/{}/{}/{}".format(policy_key, + subject_key, cat_key, data_key), headers=auth_headers) + + +def clean_object_assignments(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + req = test_policies.get_policies(auth_headers=auth_headers) + + policies = req.data + for policy_key in policies["policies"]: + req, assignments = test_assignments.get_object_assignment(policy_key) + for key in assignments["object_assignments"]: + object_key = assignments["object_assignments"][key]["object_id"] + cat_key = assignments["object_assignments"][key]["category_id"] + data_keys = assignments["object_assignments"][key]["assignments"] + for data_key in data_keys: + from moon_manager.api import assignments + hug.test.delete(assignments, + "/policies/{}/object_assignments/{}/{}/{}".format(policy_key, + object_key, cat_key, data_key), headers=auth_headers) + + +def clean_action_assignments(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + req = test_policies.get_policies(auth_headers=auth_headers) + + policies = req.data + for policy_key in policies["policies"]: + req, assignments = test_assignments.get_action_assignment(policy_key) + for key in assignments["action_assignments"]: + action_key = assignments["action_assignments"][key]["action_id"] + cat_key = assignments["action_assignments"][key]["category_id"] + data_keys = assignments["action_assignments"][key]["assignments"] + for data_key in data_keys: + from moon_manager.api import assignments + hug.test.delete(assignments, + "/policies/{}/action_assignments/{}/{}/{}".format(policy_key, + action_key, cat_key, data_key), headers=auth_headers) + + +def clean_rules(): + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + req = test_policies.get_policies(auth_headers=auth_headers) + + policies = req.data + for policy_key in policies["policies"]: + req, rules = test_rules.get_rules(policy_key) + rules = rules["rules"]["rules"] + for rule_key in rules: + from moon_manager.api import rules + hug.test.delete(rules, "/policies/{}/rules/{}".format(policy_key, rule_key["id"]), headers=auth_headers) + + +def clean_all(): + clean_rules() + + clean_subject_assignments() + clean_object_assignments() + clean_action_assignments() + + clean_subject_data() + clean_object_data() + clean_action_data() + + clean_actions() + clean_objects() + clean_subjects() + + clean_policies() + clean_models() + clean_meta_rule() + + clean_subject_categories() + clean_object_categories() + clean_action_categories() diff --git a/moon_manager/tests/unit_python/helpers/meta_rule_helper.py b/moon_manager/tests/unit_python/helpers/meta_rule_helper.py index e882706b..0542d394 100644 --- a/moon_manager/tests/unit_python/helpers/meta_rule_helper.py +++ b/moon_manager/tests/unit_python/helpers/meta_rule_helper.py @@ -1,18 +1,25 @@ -# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors -# This software is distributed under the terms and conditions of the 'Apache-2.0' -# license which can be found in the file 'LICENSE' in this package distribution -# or at 'http://www.apache.org/licenses/LICENSE-2.0'. +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + from helpers import data_builder as builder from uuid import uuid4 def set_meta_rule(meta_rule_id, value=None): - from python_moondb.core import ModelManager + from moon_manager.db_driver import ModelManager if not value: - action_category_id = builder.create_action_category("action_category_id1"+uuid4().hex) - subject_category_id = builder.create_subject_category("subject_category_id1"+uuid4().hex) - object_category_id = builder.create_object_category("object_category_id1"+uuid4().hex) + action_category_id = builder.create_action_category("action_category_id1" + uuid4().hex) + subject_category_id = builder.create_subject_category("subject_category_id1" + uuid4().hex) + object_category_id = builder.create_object_category("object_category_id1" + uuid4().hex) value = { "name": "MLS_meta_rule", "description": "test", @@ -20,30 +27,58 @@ def set_meta_rule(meta_rule_id, value=None): "object_categories": [object_category_id], "action_categories": [action_category_id] } - return ModelManager.set_meta_rule(user_id=None, meta_rule_id=meta_rule_id, value=value) + return ModelManager.set_meta_rule(moon_user_id=None, meta_rule_id=meta_rule_id, value=value) def add_meta_rule(meta_rule_id=None, value=None): - from python_moondb.core import ModelManager + from moon_manager.db_driver import ModelManager if not value: - action_category_id = builder.create_action_category("action_category_id1"+uuid4().hex) - subject_category_id = builder.create_subject_category("subject_category_id1"+uuid4().hex) - object_category_id = builder.create_object_category("object_category_id1"+uuid4().hex) + action_category_id = builder.create_action_category("action_category_id1" + uuid4().hex) + subject_category_id = builder.create_subject_category("subject_category_id1" + uuid4().hex) + object_category_id = builder.create_object_category("object_category_id1" + uuid4().hex) value = { - "name": "MLS_meta_rule"+uuid4().hex, + "name": "MLS_meta_rule" + uuid4().hex, "description": "test", "subject_categories": [subject_category_id], "object_categories": [object_category_id], "action_categories": [action_category_id] } - return ModelManager.add_meta_rule(user_id=None, meta_rule_id=meta_rule_id, value=value) + return ModelManager.add_meta_rule(moon_user_id=None, meta_rule_id=meta_rule_id, value=value) + + +def get_body_meta_rule_with_empty_category_in_mid(type=None): + action_category_id1 = builder.create_action_category("action_category_id1" + uuid4().hex) + subject_category_id1 = builder.create_subject_category("subject_category_id1" + uuid4().hex) + object_category_id1 = builder.create_object_category("object_category_id1" + uuid4().hex) + + action_category_id2 = builder.create_action_category("action_category_id1" + uuid4().hex) + subject_category_id2 = builder.create_subject_category("subject_category_id1" + uuid4().hex) + object_category_id2 = builder.create_object_category("object_category_id1" + uuid4().hex) + value = { + "name": "MLS_meta_rule" + uuid4().hex, + "description": "test", + "subject_categories": [subject_category_id1], + "object_categories": [object_category_id1], + "action_categories": [action_category_id1] + } + if type == 'subject': + value['subject_categories'].append("") + if type == 'object': + value['object_categories'].append("") + if type == 'action': + value['action_categories'].append("") + + value['subject_categories'].append(subject_category_id2) + value['object_categories'].append(object_category_id2) + value['action_categories'].append(action_category_id2) + return value def get_meta_rules(meta_rule_id=None): - from python_moondb.core import ModelManager - return ModelManager.get_meta_rules(user_id=None, meta_rule_id=meta_rule_id) + from moon_manager.db_driver import ModelManager + return ModelManager.get_meta_rules(moon_user_id=None, meta_rule_id=meta_rule_id) def delete_meta_rules(meta_rule_id=None): - from python_moondb.core import ModelManager - ModelManager.delete_meta_rule(user_id=None, meta_rule_id=meta_rule_id) + from moon_manager.db_driver import ModelManager + ModelManager.delete_meta_rule(moon_user_id=None, meta_rule_id=meta_rule_id) diff --git a/moon_manager/tests/unit_python/helpers/model_helper.py b/moon_manager/tests/unit_python/helpers/model_helper.py index 73808e03..ed705af8 100644 --- a/moon_manager/tests/unit_python/helpers/model_helper.py +++ b/moon_manager/tests/unit_python/helpers/model_helper.py @@ -1,19 +1,26 @@ -# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors -# This software is distributed under the terms and conditions of the 'Apache-2.0' -# license which can be found in the file 'LICENSE' in this package distribution -# or at 'http://www.apache.org/licenses/LICENSE-2.0'. +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + from helpers import data_builder as builder from uuid import uuid4 def get_models(model_id=None): - from python_moondb.core import ModelManager - return ModelManager.get_models(user_id=None, model_id=model_id) + from moon_manager.db_driver import ModelManager + return ModelManager.get_models(moon_user_id=None, model_id=model_id) def add_model(model_id=None, value=None): - from python_moondb.core import ModelManager + from moon_manager.db_driver import ModelManager if not value: subject_category_id, object_category_id, action_category_id, meta_rule_id = builder.create_new_meta_rule() name = "MLS"+uuid4().hex if model_id is None else "MLS " + model_id @@ -22,27 +29,53 @@ def add_model(model_id=None, value=None): "description": "test", "meta_rules": [meta_rule_id] } - return ModelManager.add_model(user_id=None, model_id=model_id, value=value) + return ModelManager.add_model(moon_user_id=None, model_id=model_id, value=value) + + +def add_model_without_meta_rule(model_id=None, value=None): + from moon_manager.db_driver import ModelManager + if not value: + name = "MLS"+uuid4().hex if model_id is None else "MLS " + model_id + value = { + "name": name, + "description": "test", + "meta_rules": "" + } + return ModelManager.add_model(moon_user_id=None, model_id=model_id, value=value) + + +def add_model_with_blank_subject_meta_rule(model_id=None, value=None): + from moon_manager.db_driver import ModelManager + if not value: + subject_category_id, object_category_id, action_category_id, meta_rule_id = builder.create_new_meta_rule(empty='subject') + name = "MLS"+uuid4().hex if model_id is None else "MLS " + model_id + value = { + "name": name, + "description": "test", + "meta_rules": [meta_rule_id] + } + return ModelManager.add_model(moon_user_id=None, model_id=model_id, value=value) + def delete_models(uuid=None, name=None): - from python_moondb.core import ModelManager + from moon_manager.db_driver import ModelManager if not uuid: for model_id, model_value in get_models(): if name == model_value['name']: uuid = model_id break - ModelManager.delete_model(user_id=None, model_id=uuid) + ModelManager.delete_model(moon_user_id=None, model_id=uuid) def delete_all_models(): - from python_moondb.core import ModelManager + from moon_manager.db_driver import ModelManager models_values = get_models() print(models_values) for model_id, model_value in models_values.items(): - ModelManager.delete_model(user_id=None, model_id=model_id) + ModelManager.delete_model(moon_user_id=None, model_id=model_id) def update_model(model_id=None, value=None): - from python_moondb.core import ModelManager - return ModelManager.update_model(user_id=None, model_id=model_id, value=value) + from moon_manager.db_driver import ModelManager + return ModelManager.update_model(moon_user_id=None, model_id=model_id, value=value) diff --git a/moon_manager/tests/unit_python/helpers/pdp_helper.py b/moon_manager/tests/unit_python/helpers/pdp_helper.py index 3d169b06..e970961a 100644 --- a/moon_manager/tests/unit_python/helpers/pdp_helper.py +++ b/moon_manager/tests/unit_python/helpers/pdp_helper.py @@ -1,23 +1,31 @@ -# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors -# This software is distributed under the terms and conditions of the 'Apache-2.0' -# license which can be found in the file 'LICENSE' in this package distribution -# or at 'http://www.apache.org/licenses/LICENSE-2.0'. +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + def update_pdp(pdp_id, value): - from python_moondb.core import PDPManager + from moon_manager.db_driver import PDPManager return PDPManager.update_pdp("", pdp_id, value) def delete_pdp(pdp_id): - from python_moondb.core import PDPManager + from moon_manager.db_driver import PDPManager PDPManager.delete_pdp("", pdp_id) def add_pdp(pdp_id=None, value=None): - from python_moondb.core import PDPManager + from moon_manager.db_driver import PDPManager return PDPManager.add_pdp("", pdp_id, value) def get_pdp(pdp_id=None): - from python_moondb.core import PDPManager + from moon_manager.db_driver import PDPManager return PDPManager.get_pdp("", pdp_id) diff --git a/moon_manager/tests/unit_python/helpers/policy_helper.py b/moon_manager/tests/unit_python/helpers/policy_helper.py index eddd0b8d..ffd0d1bb 100644 --- a/moon_manager/tests/unit_python/helpers/policy_helper.py +++ b/moon_manager/tests/unit_python/helpers/policy_helper.py @@ -1,17 +1,25 @@ -# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors -# This software is distributed under the terms and conditions of the 'Apache-2.0' -# license which can be found in the file 'LICENSE' in this package distribution -# or at 'http://www.apache.org/licenses/LICENSE-2.0'. +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + from uuid import uuid4 +from helpers import model_helper def get_policies(): - from python_moondb.core import PolicyManager + from moon_manager.db_driver import PolicyManager return PolicyManager.get_policies("admin") def add_policies(policy_id=None, value=None): - from python_moondb.core import PolicyManager + from moon_manager.db_driver import PolicyManager if not value: value = { "name": "test_policy"+ uuid4().hex, @@ -19,11 +27,24 @@ def add_policies(policy_id=None, value=None): "genre": "authz", "description": "test", } - return PolicyManager.add_policy("admin", policy_id=policy_id, value=value) + return PolicyManager.add_policy(moon_user_id="admin", policy_id=policy_id, value=value) + + +def add_policies_with_model(policy_id=None, value=None): + from moon_manager.db_driver import PolicyManager + req = model_helper.add_model(model_id="mls_model_id" + uuid4().hex) + model_id = list(req.keys())[0] + data = { + "name": "test_policy"+ uuid4().hex, + "description": "test", + "model_id": model_id, + "genre": "genre" + } + return PolicyManager.add_policy(moon_user_id="admin", policy_id=policy_id, value=data) def delete_policies(uuid=None, name=None): - from python_moondb.core import PolicyManager + from moon_manager.db_driver import PolicyManager if not uuid: for policy_id, policy_value in get_policies(): if name == policy_value['name']: @@ -33,31 +54,31 @@ def delete_policies(uuid=None, name=None): def update_policy(policy_id, value): - from python_moondb.core import PolicyManager + from moon_manager.db_driver import PolicyManager return PolicyManager.update_policy("admin", policy_id, value) def get_policy_from_meta_rules(meta_rule_id): - from python_moondb.core import PolicyManager + from moon_manager.db_driver import PolicyManager return PolicyManager.get_policy_from_meta_rules("admin", meta_rule_id) def get_rules(policy_id=None, meta_rule_id=None, rule_id=None): - from python_moondb.core import PolicyManager + from moon_manager.db_driver import PolicyManager return PolicyManager.get_rules("", policy_id, meta_rule_id, rule_id) def add_rule(policy_id=None, meta_rule_id=None, value=None): - from python_moondb.core import PolicyManager + from moon_manager.db_driver import PolicyManager if not value: value = { "rule": ("high", "medium", "vm-action"), - "instructions": ({"decision": "grant"}), + "instructions": [{"decision": "grant"}], "enabled": "", } return PolicyManager.add_rule("", policy_id, meta_rule_id, value) def delete_rule(policy_id=None, rule_id=None): - from python_moondb.core import PolicyManager + from moon_manager.db_driver import PolicyManager PolicyManager.delete_rule("", policy_id, rule_id) diff --git a/moon_manager/tests/unit_python/helpers/rules_helper.py b/moon_manager/tests/unit_python/helpers/rules_helper.py new file mode 100644 index 00000000..ce7e8bd2 --- /dev/null +++ b/moon_manager/tests/unit_python/helpers/rules_helper.py @@ -0,0 +1,18 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +def get_headers(): + from moon_utilities.auth_functions import get_api_key_for_user + + auth_headers = {"X-Api-Key": get_api_key_for_user("admin"), + 'Content-Type': 'application/json'} + return auth_headers diff --git a/moon_manager/tests/unit_python/mock_engine.py b/moon_manager/tests/unit_python/mock_engine.py new file mode 100644 index 00000000..0685d376 --- /dev/null +++ b/moon_manager/tests/unit_python/mock_engine.py @@ -0,0 +1,19 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + + +def register_engine(m): + for port in range(20000, 20010): + m.register_uri( + 'POST', 'http://127.0.0.1:{}/update'.format(port), + json={} + ) diff --git a/moon_manager/tests/unit_python/mock_keystone.py b/moon_manager/tests/unit_python/mock_keystone.py new file mode 100644 index 00000000..73e5681d --- /dev/null +++ b/moon_manager/tests/unit_python/mock_keystone.py @@ -0,0 +1,59 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + +import requests_mock + + +def register_keystone(m): + m.register_uri( + 'POST', 'http://keystone:5000/v3/auth/tokens', + headers={'X-Subject-Token': "b34e5a29-5494-4cc5-9356-daa244b8c254"} + ) + m.register_uri( + 'DELETE', 'http://keystone:5000/v3/auth/tokens', + headers={'X-Subject-Token': "b34e5a29-5494-4cc5-9356-daa244b8c254"} + ) + 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": "b34e5a29-5494-4cc5-9356-daa244b8c254" + }]} + ) + + def match_request_text(request): + # request.url may be None, or '' prevents a TypeError. + return 'http://keystone:5000/v3/users?name=' in request.url + + m.register_uri( + requests_mock.ANY, '/v3/users', + additional_matcher=match_request_text, + json={"users": [{ + "id": "b34e5a29-5494-4cc5-9356-daa244b8c254" + }]} + ) + m.register_uri( + 'POST', 'http://keystone:5000/v3/projects/', + json={ + "description": "test_project", + "domain_id": ['domain_id_1'], + "enabled": True, + "is_domain": False, + "name": 'project_1' + } + ) diff --git a/moon_manager/tests/unit_python/mock_nova.py b/moon_manager/tests/unit_python/mock_nova.py new file mode 100644 index 00000000..e898ad1a --- /dev/null +++ b/moon_manager/tests/unit_python/mock_nova.py @@ -0,0 +1,28 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + +import requests_mock + + +def register_nova(m): + m.register_uri( + 'POST', 'http://keystone:5000/v3/auth/tokens', + headers={'X-Subject-Token': "b34e5a29-5494-4cc5-9356-daa244b8c254"} + ) + m.register_uri( + 'DELETE', 'http://keystone:5000/v3/auth/tokens', + headers={'X-Subject-Token': "b34e5a29-5494-4cc5-9356-daa244b8c254"} + ) + m.register_uri( + 'GET', 'http://keystone:5000/compute/v2.1/servers', + json={"servers": [{"name": "vm1"}]} + ) + diff --git a/moon_manager/tests/unit_python/mock_slaves.py b/moon_manager/tests/unit_python/mock_slaves.py new file mode 100644 index 00000000..935bb0de --- /dev/null +++ b/moon_manager/tests/unit_python/mock_slaves.py @@ -0,0 +1,38 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +SLAVES = { + "slaves": { + "d464cc58a0cd46dea3191ba70f4e7df8": { + "name": "slave_test", + "address": "", + "description": "...", + "api_key": "e58a882a6b658a22660f00a0c273e7f6b4c4eb5abe54eccba2cae307905d67e3746537bd790c41887e11840c2d186b6d6eeec0e426bcfa7a872cc3417a35124a", + "log": "/tmp/moon_d464cc58a0cd46dea3191ba70f4e7df8.log", + "process": "/tmp/d464cc58a0cd46dea3191ba70f4e7df8.pid", + "extra": { + "description": "...", + "starttime": 1543851265.76279, + "port": 10001, + "server_ip": "127.0.0.1", + "status": "down" + } + } + } +} + + +def register_slaves(m): + m.register_uri( + 'GET', 'http://localhost/slaves', + json=SLAVES + ) diff --git a/moon_manager/tests/unit_python/plugins/__init__.py b/moon_manager/tests/unit_python/plugins/__init__.py new file mode 100644 index 00000000..1856aa2c --- /dev/null +++ b/moon_manager/tests/unit_python/plugins/__init__.py @@ -0,0 +1,12 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + diff --git a/moon_manager/tests/unit_python/plugins/test_global_attrs.py b/moon_manager/tests/unit_python/plugins/test_global_attrs.py new file mode 100644 index 00000000..603e03ae --- /dev/null +++ b/moon_manager/tests/unit_python/plugins/test_global_attrs.py @@ -0,0 +1,148 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + + +import hug +from moon_manager.pip_driver import AttrsManager +from moon_manager.api.configuration import get_configuration + + +def test_mode_add_get(): + default_value = get_configuration( + "information")["global_attrs"]["attributes"]["mode"]["default"] + value = AttrsManager.delete_object(object_type="mode") + assert isinstance(value, dict) + for key in ("id", "value", "default", "values"): + assert key in value + value = AttrsManager.get_object(object_type="mode") + assert value["value"] == default_value + assert isinstance(value, dict) + for key in ("id", "value", "default", "values"): + assert key in value + assert value["value"] == default_value + + +def test_mode_add_gets(): + default_value = \ + get_configuration("information")["global_attrs"]["attributes"]["mode"]["default"] + value = AttrsManager.delete_object(object_type="mode") + assert isinstance(value, dict) + for key in ("id", "value", "default", "values"): + assert key in value + values = AttrsManager.get_objects() + assert "mode" in values + assert values["mode"]["value"] == default_value + assert isinstance(values["mode"], dict) + for key in ("id", "value", "default", "values"): + assert key in values["mode"] + assert values["mode"]["value"] == default_value + + +def test_mode_update(): + value = AttrsManager.update_object(object_id="build", object_type="mode") + assert isinstance(value, dict) + for key in ("id", "value", "default", "values"): + assert key in value + assert value["value"] == "build" + value = AttrsManager.get_object(object_type="mode") + assert isinstance(value, dict) + for key in ("id", "value", "default", "values"): + assert key in value + assert value["value"] == "build" + + +def test_mode_delete(): + value = AttrsManager.update_object(object_id="build", object_type="mode") + assert isinstance(value, dict) + for key in ("id", "value", "default", "values"): + assert key in value + assert value["value"] == "build" + value = AttrsManager.delete_object(object_type="mode") + assert isinstance(value, dict) + for key in ("id", "value", "default", "values"): + assert key in value + assert value["value"] == "run" + + +def test_hug_mode_add_get(): + from moon_manager.api import attributes + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + default_value = get_configuration( + "information")["global_attrs"]["attributes"]["mode"]["default"] + + req = hug.test.delete(attributes, "/attributes/{}".format("mode"), headers=auth_headers) + assert req.status == hug.HTTP_200 + value = req.data + assert isinstance(value, dict) + assert "attributes" in value + value = value["attributes"] + for key in ("id", "value", "default", "values"): + assert key in value + assert value["value"] == default_value + value = AttrsManager.get_object(object_type="mode") + assert isinstance(value, dict) + for key in ("id", "value", "default", "values"): + assert key in value + assert value["value"] == default_value + + +def test_hug_mode_update(): + from moon_manager.api import attributes + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + + req = hug.test.put(attributes, "/attributes/{}/{}".format("mode", "build"), headers=auth_headers) + assert req.status == hug.HTTP_200 + value = req.data + assert isinstance(value, dict) + assert "attributes" in value + value = value["attributes"] + for key in ("id", "value", "default", "values"): + assert key in value + assert value["value"] == "build" + value = AttrsManager.get_object(object_type="mode") + assert isinstance(value, dict) + for key in ("id", "value", "default", "values"): + assert key in value + assert value["value"] == "build" + + +def test_hug_mode_delete(): + from moon_manager.api import attributes + from moon_utilities.auth_functions import get_api_key_for_user + auth_headers = {"X-Api-Key": get_api_key_for_user("admin")} + default_value = get_configuration( + "information")["global_attrs"]["attributes"]["mode"]["default"] + + req = hug.test.put(attributes, "/attributes/{}/{}".format("mode", "build"), headers=auth_headers) + assert req.status == hug.HTTP_200 + value = req.data + assert isinstance(value, dict) + assert "attributes" in value + value = value["attributes"] + for key in ("id", "value", "default", "values"): + assert key in value + assert value["value"] == "build" + req = hug.test.delete(attributes, "/attributes/{}".format("mode"), headers=auth_headers) + assert req.status == hug.HTTP_200 + value = req.data + assert isinstance(value, dict) + assert "attributes" in value + value = value["attributes"] + for key in ("id", "value", "default", "values"): + assert key in value + assert value["value"] == default_value + value = AttrsManager.get_object(object_type="mode") + assert isinstance(value, dict) + for key in ("id", "value", "default", "values"): + assert key in value + assert value["value"] == default_value diff --git a/moon_manager/tests/unit_python/requirements.txt b/moon_manager/tests/unit_python/requirements.txt index d6f190e4..e021a5fb 100644 --- a/moon_manager/tests/unit_python/requirements.txt +++ b/moon_manager/tests/unit_python/requirements.txt @@ -1,5 +1,11 @@ -flask -flask_cors -flask_restful -python_moondb==1.2.20 -python_moonutilities==1.4.20 +hug!=2.5.0 +moon_utilities +sqlalchemy +pymysql +pytest-mock +pytest-cov +requests_mock +tinydb +pytest +pytest-benchmark +pyaml -- cgit 1.2.3-korg