diff options
Diffstat (limited to 'moon_utilities')
34 files changed, 8560 insertions, 0 deletions
diff --git a/moon_utilities/.gitignore b/moon_utilities/.gitignore new file mode 100644 index 00000000..7bff7318 --- /dev/null +++ b/moon_utilities/.gitignore @@ -0,0 +1,105 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ + diff --git a/moon_utilities/Changelog b/moon_utilities/Changelog new file mode 100644 index 00000000..61ae2fec --- /dev/null +++ b/moon_utilities/Changelog @@ -0,0 +1,54 @@ +# 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'. + + +CHANGES +======= + +0.1 +--- +- First version of the moon_utilities library. + +0.2 +--- +- Delete Keystone references in exceptions +- Update the user used to authenticate actions in moon (moon_user_id) + +0.3 +--- +- Adding validation function +- Update enforce decorator +- Refactoring by adding base exception and json utilities from manager to utilities + +0.4 +--- +- Move authentication function from moon_manager to moon_utilities +- Adding invalided_functions +- Fix a bug in security_functions.py +- Add logout functionality +- Add re-login functionality + +0.5 +--- +- Add script to automatically generate OpenStack RBAC policy from policy.json original files + +0.6 +--- +- Add a prompt to enter the password at user creation, -p option to set the password in clear in the CLI +- Move the import functionality in moon_utilities +- Fix some bugs in generate_opst_policy +- Fix some bugs when importing directly in cache +- Add the global attribute functionality +- Fix of not relevant yields in invalided_functions + +0.7 +--- +- Add an installation script +- Update import json to db and cache functions + +0.8 +--- +- Add a change password function +- Add of a method connecting the user with environment variables
\ No newline at end of file diff --git a/moon_utilities/LICENSE b/moon_utilities/LICENSE new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/moon_utilities/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/moon_utilities/MANIFEST.in b/moon_utilities/MANIFEST.in new file mode 100644 index 00000000..21c2cf92 --- /dev/null +++ b/moon_utilities/MANIFEST.in @@ -0,0 +1,10 @@ +# 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'. + +include README.md +include LICENSE +include Changelog +include setup.py +include requirements.txt diff --git a/moon_utilities/README.md b/moon_utilities/README.md new file mode 100644 index 00000000..78fdada6 --- /dev/null +++ b/moon_utilities/README.md @@ -0,0 +1,3 @@ +# moon_utilities + +Python library that implements miscellaneous functions for the Moon project
\ No newline at end of file diff --git a/moon_utilities/conf/policy.json.d/cinder.policy.json b/moon_utilities/conf/policy.json.d/cinder.policy.json new file mode 100644 index 00000000..02af88bd --- /dev/null +++ b/moon_utilities/conf/policy.json.d/cinder.policy.json @@ -0,0 +1,104 @@ +{ + "context_is_admin": "role:admin", + "admin_or_owner": "is_admin:True or project_id:%(project_id)s", + "default": "rule:admin_or_owner", + + "admin_api": "is_admin:True", + + "volume:create": "", + "volume:delete": "rule:admin_or_owner", + "volume:get": "rule:admin_or_owner", + "volume:get_all": "rule:admin_or_owner", + "volume:get_volume_metadata": "rule:admin_or_owner", + "volume:delete_volume_metadata": "rule:admin_or_owner", + "volume:update_volume_metadata": "rule:admin_or_owner", + "volume:get_volume_admin_metadata": "rule:admin_api", + "volume:update_volume_admin_metadata": "rule:admin_api", + "volume:get_snapshot": "rule:admin_or_owner", + "volume:get_all_snapshots": "rule:admin_or_owner", + "volume:create_snapshot": "rule:admin_or_owner", + "volume:delete_snapshot": "rule:admin_or_owner", + "volume:update_snapshot": "rule:admin_or_owner", + "volume:extend": "rule:admin_or_owner", + "volume:update_readonly_flag": "rule:admin_or_owner", + "volume:retype": "rule:admin_or_owner", + "volume:update": "rule:admin_or_owner", + + "volume_extension:types_manage": "rule:admin_api", + "volume_extension:types_extra_specs": "rule:admin_api", + "volume_extension:access_types_qos_specs_id": "rule:admin_api", + "volume_extension:access_types_extra_specs": "rule:admin_api", + "volume_extension:volume_type_access": "rule:admin_or_owner", + "volume_extension:volume_type_access:addProjectAccess": "rule:admin_api", + "volume_extension:volume_type_access:removeProjectAccess": "rule:admin_api", + "volume_extension:volume_type_encryption": "rule:admin_api", + "volume_extension:volume_encryption_metadata": "rule:admin_or_owner", + "volume_extension:extended_snapshot_attributes": "rule:admin_or_owner", + "volume_extension:volume_image_metadata": "rule:admin_or_owner", + + "volume_extension:quotas:show": "", + "volume_extension:quotas:update": "rule:admin_api", + "volume_extension:quotas:delete": "rule:admin_api", + "volume_extension:quota_classes": "rule:admin_api", + "volume_extension:quota_classes:validate_setup_for_nested_quota_use": "rule:admin_api", + + "volume_extension:volume_admin_actions:reset_status": "rule:admin_api", + "volume_extension:snapshot_admin_actions:reset_status": "rule:admin_api", + "volume_extension:backup_admin_actions:reset_status": "rule:admin_api", + "volume_extension:volume_admin_actions:force_delete": "rule:admin_api", + "volume_extension:volume_admin_actions:force_detach": "rule:admin_api", + "volume_extension:snapshot_admin_actions:force_delete": "rule:admin_api", + "volume_extension:backup_admin_actions:force_delete": "rule:admin_api", + "volume_extension:volume_admin_actions:migrate_volume": "rule:admin_api", + "volume_extension:volume_admin_actions:migrate_volume_completion": "rule:admin_api", + + "volume_extension:volume_host_attribute": "rule:admin_api", + "volume_extension:volume_tenant_attribute": "rule:admin_or_owner", + "volume_extension:volume_mig_status_attribute": "rule:admin_api", + "volume_extension:hosts": "rule:admin_api", + "volume_extension:services:index": "rule:admin_api", + "volume_extension:services:update" : "rule:admin_api", + + "volume_extension:volume_manage": "rule:admin_api", + "volume_extension:volume_unmanage": "rule:admin_api", + + "volume_extension:capabilities": "rule:admin_api", + + "volume:create_transfer": "rule:admin_or_owner", + "volume:accept_transfer": "", + "volume:delete_transfer": "rule:admin_or_owner", + "volume:get_all_transfers": "rule:admin_or_owner", + + "volume_extension:replication:promote": "rule:admin_api", + "volume_extension:replication:reenable": "rule:admin_api", + + "volume:enable_replication": "rule:admin_api", + "volume:disable_replication": "rule:admin_api", + "volume:failover_replication": "rule:admin_api", + "volume:list_replication_targets": "rule:admin_api", + + "backup:create" : "", + "backup:delete": "rule:admin_or_owner", + "backup:get": "rule:admin_or_owner", + "backup:get_all": "rule:admin_or_owner", + "backup:restore": "rule:admin_or_owner", + "backup:backup-import": "rule:admin_api", + "backup:backup-export": "rule:admin_api", + + "snapshot_extension:snapshot_actions:update_snapshot_status": "", + "snapshot_extension:snapshot_manage": "rule:admin_api", + "snapshot_extension:snapshot_unmanage": "rule:admin_api", + + "consistencygroup:create" : "group:nobody", + "consistencygroup:delete": "group:nobody", + "consistencygroup:update": "group:nobody", + "consistencygroup:get": "group:nobody", + "consistencygroup:get_all": "group:nobody", + + "consistencygroup:create_cgsnapshot" : "group:nobody", + "consistencygroup:delete_cgsnapshot": "group:nobody", + "consistencygroup:get_cgsnapshot": "group:nobody", + "consistencygroup:get_all_cgsnapshots": "group:nobody", + + "scheduler_extension:scheduler_stats:get_pools" : "rule:admin_api" +} diff --git a/moon_utilities/conf/policy.json.d/glance.policy.json b/moon_utilities/conf/policy.json.d/glance.policy.json new file mode 100644 index 00000000..5b1f6be7 --- /dev/null +++ b/moon_utilities/conf/policy.json.d/glance.policy.json @@ -0,0 +1,63 @@ +{ + "context_is_admin": "role:admin", + "default": "role:admin", + + "add_image": "", + "delete_image": "", + "get_image": "", + "get_images": "", + "modify_image": "", + "publicize_image": "role:admin", + "communitize_image": "", + "copy_from": "", + + "download_image": "", + "upload_image": "", + + "delete_image_location": "", + "get_image_location": "", + "set_image_location": "", + + "add_member": "", + "delete_member": "", + "get_member": "", + "get_members": "", + "modify_member": "", + + "manage_image_cache": "role:admin", + + "get_task": "", + "get_tasks": "", + "add_task": "", + "modify_task": "", + "tasks_api_access": "role:admin", + + "deactivate": "", + "reactivate": "", + + "get_metadef_namespace": "", + "get_metadef_namespaces":"", + "modify_metadef_namespace":"", + "add_metadef_namespace":"", + + "get_metadef_object":"", + "get_metadef_objects":"", + "modify_metadef_object":"", + "add_metadef_object":"", + + "list_metadef_resource_types":"", + "get_metadef_resource_type":"", + "add_metadef_resource_type_association":"", + + "get_metadef_property":"", + "get_metadef_properties":"", + "modify_metadef_property":"", + "add_metadef_property":"", + + "get_metadef_tag":"", + "get_metadef_tags":"", + "modify_metadef_tag":"", + "add_metadef_tag":"", + "add_metadef_tags":"" + +} diff --git a/moon_utilities/conf/policy.json.d/keystone.policy.json b/moon_utilities/conf/policy.json.d/keystone.policy.json new file mode 100644 index 00000000..263912bf --- /dev/null +++ b/moon_utilities/conf/policy.json.d/keystone.policy.json @@ -0,0 +1,260 @@ +{ + "admin_required": "role:admin", + "cloud_admin": "role:admin and (is_admin_project:True or domain_id:admin_domain_id)", + "service_role": "role:service", + "service_or_admin": "rule:admin_required or rule:service_role", + "owner": "user_id:%(user_id)s or user_id:%(target.token.user_id)s", + "admin_or_owner": "(rule:admin_required and domain_id:%(target.token.user.domain.id)s) or rule:owner", + "admin_and_matching_domain_id": "rule:admin_required and domain_id:%(domain_id)s", + "service_admin_or_owner": "rule:service_or_admin or rule:owner", + + "default": "rule:admin_required", + + "identity:get_region": "", + "identity:list_regions": "", + "identity:create_region": "rule:cloud_admin", + "identity:update_region": "rule:cloud_admin", + "identity:delete_region": "rule:cloud_admin", + + "identity:get_service": "rule:admin_required", + "identity:list_services": "rule:admin_required", + "identity:create_service": "rule:cloud_admin", + "identity:update_service": "rule:cloud_admin", + "identity:delete_service": "rule:cloud_admin", + + "identity:get_endpoint": "rule:admin_required", + "identity:list_endpoints": "rule:admin_required", + "identity:create_endpoint": "rule:cloud_admin", + "identity:update_endpoint": "rule:cloud_admin", + "identity:delete_endpoint": "rule:cloud_admin", + + "identity:get_registered_limit": "", + "identity:list_registered_limits": "", + "identity:create_registered_limits": "rule:admin_required", + "identity:update_registered_limits": "rule:admin_required", + "identity:delete_registered_limit": "rule:admin_required", + + "identity:get_limit": "", + "identity:list_limits": "", + "identity:create_limits": "rule:admin_required", + "identity:update_limits": "rule:admin_required", + "identity:delete_limit": "rule:admin_required", + + "identity:get_domain": "rule:cloud_admin or rule:admin_and_matching_domain_id or token.project.domain.id:%(target.domain.id)s", + "identity:list_domains": "rule:cloud_admin", + "identity:create_domain": "rule:cloud_admin", + "identity:update_domain": "rule:cloud_admin", + "identity:delete_domain": "rule:cloud_admin", + + "admin_and_matching_target_project_domain_id": "rule:admin_required and domain_id:%(target.project.domain_id)s", + "admin_and_matching_project_domain_id": "rule:admin_required and domain_id:%(project.domain_id)s", + "identity:get_project": "rule:cloud_admin or rule:admin_and_matching_target_project_domain_id or project_id:%(target.project.id)s", + "identity:list_projects": "rule:cloud_admin or rule:admin_and_matching_domain_id", + "identity:list_user_projects": "rule:owner or rule:admin_and_matching_domain_id", + "identity:create_project": "rule:cloud_admin or rule:admin_and_matching_project_domain_id", + "identity:update_project": "rule:cloud_admin or rule:admin_and_matching_target_project_domain_id", + "identity:delete_project": "rule:cloud_admin or rule:admin_and_matching_target_project_domain_id", + "identity:create_project_tag": "rule:admin_required", + "identity:delete_project_tag": "rule:admin_required", + "identity:get_project_tag": "rule:admin_required", + "identity:list_project_tags": "rule:admin_required", + "identity:delete_project_tags": "rule:admin_required", + "identity:update_project_tags": "rule:admin_required", + + "admin_and_matching_target_user_domain_id": "rule:admin_required and domain_id:%(target.user.domain_id)s", + "admin_and_matching_user_domain_id": "rule:admin_required and domain_id:%(user.domain_id)s", + "identity:get_user": "rule:cloud_admin or rule:admin_and_matching_target_user_domain_id or rule:owner", + "identity:list_users": "rule:cloud_admin or rule:admin_and_matching_domain_id", + "identity:create_user": "rule:cloud_admin or rule:admin_and_matching_user_domain_id", + "identity:update_user": "rule:cloud_admin or rule:admin_and_matching_target_user_domain_id", + "identity:delete_user": "rule:cloud_admin or rule:admin_and_matching_target_user_domain_id", + + "admin_and_matching_target_group_domain_id": "rule:admin_required and domain_id:%(target.group.domain_id)s", + "admin_and_matching_group_domain_id": "rule:admin_required and domain_id:%(group.domain_id)s", + "identity:get_group": "rule:cloud_admin or rule:admin_and_matching_target_group_domain_id", + "identity:list_groups": "rule:cloud_admin or rule:admin_and_matching_domain_id", + "identity:list_groups_for_user": "rule:owner or rule:admin_and_matching_target_user_domain_id", + "identity:create_group": "rule:cloud_admin or rule:admin_and_matching_group_domain_id", + "identity:update_group": "rule:cloud_admin or rule:admin_and_matching_target_group_domain_id", + "identity:delete_group": "rule:cloud_admin or rule:admin_and_matching_target_group_domain_id", + "identity:list_users_in_group": "rule:cloud_admin or rule:admin_and_matching_target_group_domain_id", + "identity:remove_user_from_group": "rule:cloud_admin or rule:admin_and_matching_target_group_domain_id", + "identity:check_user_in_group": "rule:cloud_admin or rule:admin_and_matching_target_group_domain_id", + "identity:add_user_to_group": "rule:cloud_admin or rule:admin_and_matching_target_group_domain_id", + + "identity:get_credential": "rule:admin_required", + "identity:list_credentials": "rule:admin_required or user_id:%(user_id)s", + "identity:create_credential": "rule:admin_required", + "identity:update_credential": "rule:admin_required", + "identity:delete_credential": "rule:admin_required", + + "identity:ec2_get_credential": "rule:admin_required or (rule:owner and user_id:%(target.credential.user_id)s)", + "identity:ec2_list_credentials": "rule:admin_required or rule:owner", + "identity:ec2_create_credential": "rule:admin_required or rule:owner", + "identity:ec2_delete_credential": "rule:admin_required or (rule:owner and user_id:%(target.credential.user_id)s)", + + "identity:get_role": "rule:admin_required", + "identity:list_roles": "rule:admin_required", + "identity:create_role": "rule:cloud_admin", + "identity:update_role": "rule:cloud_admin", + "identity:delete_role": "rule:cloud_admin", + + "identity:get_domain_role": "rule:cloud_admin or rule:get_domain_roles", + "identity:list_domain_roles": "rule:cloud_admin or rule:list_domain_roles", + "identity:create_domain_role": "rule:cloud_admin or rule:domain_admin_matches_domain_role", + "identity:update_domain_role": "rule:cloud_admin or rule:domain_admin_matches_target_domain_role", + "identity:delete_domain_role": "rule:cloud_admin or rule:domain_admin_matches_target_domain_role", + "domain_admin_matches_domain_role": "rule:admin_required and domain_id:%(role.domain_id)s", + "get_domain_roles": "rule:domain_admin_matches_target_domain_role or rule:project_admin_matches_target_domain_role", + "domain_admin_matches_target_domain_role": "rule:admin_required and domain_id:%(target.role.domain_id)s", + "project_admin_matches_target_domain_role": "rule:admin_required and project_domain_id:%(target.role.domain_id)s", + "list_domain_roles": "rule:domain_admin_matches_filter_on_list_domain_roles or rule:project_admin_matches_filter_on_list_domain_roles", + "domain_admin_matches_filter_on_list_domain_roles": "rule:admin_required and domain_id:%(domain_id)s", + "project_admin_matches_filter_on_list_domain_roles": "rule:admin_required and project_domain_id:%(domain_id)s", + "admin_and_matching_prior_role_domain_id": "rule:admin_required and domain_id:%(target.prior_role.domain_id)s", + "implied_role_matches_prior_role_domain_or_global": "(domain_id:%(target.implied_role.domain_id)s or None:%(target.implied_role.domain_id)s)", + + "identity:get_implied_role": "rule:cloud_admin or rule:admin_and_matching_prior_role_domain_id", + "identity:list_implied_roles": "rule:cloud_admin or rule:admin_and_matching_prior_role_domain_id", + "identity:create_implied_role": "rule:cloud_admin or (rule:admin_and_matching_prior_role_domain_id and rule:implied_role_matches_prior_role_domain_or_global)", + "identity:delete_implied_role": "rule:cloud_admin or rule:admin_and_matching_prior_role_domain_id", + "identity:list_role_inference_rules": "rule:cloud_admin", + "identity:check_implied_role": "rule:cloud_admin or rule:admin_and_matching_prior_role_domain_id", + + "identity:list_system_grants_for_user": "rule:admin_required", + "identity:check_system_grant_for_user": "rule:admin_required", + "identity:create_system_grant_for_user": "rule:admin_required", + "identity:revoke_system_grant_for_user": "rule:admin_required", + + "identity:list_system_grants_for_group": "rule:admin_required", + "identity:check_system_grant_for_group": "rule:admin_required", + "identity:create_system_grant_for_group": "rule:admin_required", + "identity:revoke_system_grant_for_group": "rule:admin_required", + + "identity:check_grant": "rule:cloud_admin or rule:domain_admin_for_grants or rule:project_admin_for_grants", + "identity:list_grants": "rule:cloud_admin or rule:domain_admin_for_list_grants or rule:project_admin_for_list_grants", + "identity:create_grant": "rule:cloud_admin or rule:domain_admin_for_grants or rule:project_admin_for_grants", + "identity:revoke_grant": "rule:cloud_admin or rule:domain_admin_for_grants or rule:project_admin_for_grants", + "domain_admin_for_grants": "rule:domain_admin_for_global_role_grants or rule:domain_admin_for_domain_role_grants", + "domain_admin_for_global_role_grants": "rule:admin_required and None:%(target.role.domain_id)s and rule:domain_admin_grant_match", + "domain_admin_for_domain_role_grants": "rule:admin_required and domain_id:%(target.role.domain_id)s and rule:domain_admin_grant_match", + "domain_admin_grant_match": "domain_id:%(domain_id)s or domain_id:%(target.project.domain_id)s", + "project_admin_for_grants": "rule:project_admin_for_global_role_grants or rule:project_admin_for_domain_role_grants", + "project_admin_for_global_role_grants": "rule:admin_required and None:%(target.role.domain_id)s and project_id:%(project_id)s", + "project_admin_for_domain_role_grants": "rule:admin_required and project_domain_id:%(target.role.domain_id)s and project_id:%(project_id)s", + "domain_admin_for_list_grants": "rule:admin_required and rule:domain_admin_grant_match", + "project_admin_for_list_grants": "rule:admin_required and project_id:%(project_id)s", + + "admin_on_domain_filter": "rule:admin_required and domain_id:%(scope.domain.id)s", + "admin_on_project_filter": "rule:admin_required and project_id:%(scope.project.id)s", + "admin_on_domain_of_project_filter": "rule:admin_required and domain_id:%(target.project.domain_id)s", + "identity:list_role_assignments": "rule:cloud_admin or rule:admin_on_domain_filter or rule:admin_on_project_filter", + "identity:list_role_assignments_for_tree": "rule:cloud_admin or rule:admin_on_domain_of_project_filter", + "identity:get_policy": "rule:cloud_admin", + "identity:list_policies": "rule:cloud_admin", + "identity:create_policy": "rule:cloud_admin", + "identity:update_policy": "rule:cloud_admin", + "identity:delete_policy": "rule:cloud_admin", + + "identity:check_token": "rule:admin_or_owner", + "identity:validate_token": "rule:service_admin_or_owner", + "identity:validate_token_head": "rule:service_or_admin", + "identity:revocation_list": "rule:service_or_admin", + "identity:revoke_token": "rule:admin_or_owner", + + "identity:create_trust": "user_id:%(trust.trustor_user_id)s", + "identity:list_trusts": "", + "identity:list_roles_for_trust": "", + "identity:get_role_for_trust": "", + "identity:delete_trust": "", + "identity:get_trust": "", + + "identity:create_consumer": "rule:admin_required", + "identity:get_consumer": "rule:admin_required", + "identity:list_consumers": "rule:admin_required", + "identity:delete_consumer": "rule:admin_required", + "identity:update_consumer": "rule:admin_required", + + "identity:authorize_request_token": "rule:admin_required", + "identity:list_access_token_roles": "rule:admin_required", + "identity:get_access_token_role": "rule:admin_required", + "identity:list_access_tokens": "rule:admin_required", + "identity:get_access_token": "rule:admin_required", + "identity:delete_access_token": "rule:admin_required", + + "identity:list_projects_for_endpoint": "rule:admin_required", + "identity:add_endpoint_to_project": "rule:admin_required", + "identity:check_endpoint_in_project": "rule:admin_required", + "identity:list_endpoints_for_project": "rule:admin_required", + "identity:remove_endpoint_from_project": "rule:admin_required", + + "identity:create_endpoint_group": "rule:admin_required", + "identity:list_endpoint_groups": "rule:admin_required", + "identity:get_endpoint_group": "rule:admin_required", + "identity:update_endpoint_group": "rule:admin_required", + "identity:delete_endpoint_group": "rule:admin_required", + "identity:list_projects_associated_with_endpoint_group": "rule:admin_required", + "identity:list_endpoints_associated_with_endpoint_group": "rule:admin_required", + "identity:get_endpoint_group_in_project": "rule:admin_required", + "identity:list_endpoint_groups_for_project": "rule:admin_required", + "identity:add_endpoint_group_to_project": "rule:admin_required", + "identity:remove_endpoint_group_from_project": "rule:admin_required", + + "identity:create_identity_provider": "rule:cloud_admin", + "identity:list_identity_providers": "rule:cloud_admin", + "identity:get_identity_provider": "rule:cloud_admin", + "identity:update_identity_provider": "rule:cloud_admin", + "identity:delete_identity_provider": "rule:cloud_admin", + + "identity:create_protocol": "rule:cloud_admin", + "identity:update_protocol": "rule:cloud_admin", + "identity:get_protocol": "rule:cloud_admin", + "identity:list_protocols": "rule:cloud_admin", + "identity:delete_protocol": "rule:cloud_admin", + + "identity:create_mapping": "rule:cloud_admin", + "identity:get_mapping": "rule:cloud_admin", + "identity:list_mappings": "rule:cloud_admin", + "identity:delete_mapping": "rule:cloud_admin", + "identity:update_mapping": "rule:cloud_admin", + + "identity:create_service_provider": "rule:cloud_admin", + "identity:list_service_providers": "rule:cloud_admin", + "identity:get_service_provider": "rule:cloud_admin", + "identity:update_service_provider": "rule:cloud_admin", + "identity:delete_service_provider": "rule:cloud_admin", + + "identity:get_auth_catalog": "", + "identity:get_auth_projects": "", + "identity:get_auth_domains": "", + "identity:get_auth_system": "", + + "identity:list_projects_for_user": "", + "identity:list_domains_for_user": "", + + "identity:list_revoke_events": "rule:service_or_admin", + + "identity:create_policy_association_for_endpoint": "rule:cloud_admin", + "identity:check_policy_association_for_endpoint": "rule:cloud_admin", + "identity:delete_policy_association_for_endpoint": "rule:cloud_admin", + "identity:create_policy_association_for_service": "rule:cloud_admin", + "identity:check_policy_association_for_service": "rule:cloud_admin", + "identity:delete_policy_association_for_service": "rule:cloud_admin", + "identity:create_policy_association_for_region_and_service": "rule:cloud_admin", + "identity:check_policy_association_for_region_and_service": "rule:cloud_admin", + "identity:delete_policy_association_for_region_and_service": "rule:cloud_admin", + "identity:get_policy_for_endpoint": "rule:cloud_admin", + "identity:list_endpoints_for_policy": "rule:cloud_admin", + + "identity:create_domain_config": "rule:cloud_admin", + "identity:get_domain_config": "rule:cloud_admin", + "identity:get_security_compliance_domain_config": "", + "identity:update_domain_config": "rule:cloud_admin", + "identity:delete_domain_config": "rule:cloud_admin", + "identity:get_domain_config_default": "rule:cloud_admin", + + "identity:get_application_credential": "rule:admin_or_owner", + "identity:list_application_credentials": "rule:admin_or_owner", + "identity:create_application_credential": "rule:admin_or_owner", + "identity:delete_application_credential": "rule:admin_or_owner" +} diff --git a/moon_utilities/conf/policy.json.d/neutron.policy.json b/moon_utilities/conf/policy.json.d/neutron.policy.json new file mode 100644 index 00000000..15f17203 --- /dev/null +++ b/moon_utilities/conf/policy.json.d/neutron.policy.json @@ -0,0 +1,235 @@ +{ + "context_is_admin": "role:admin or user_name:neutron", + "owner": "tenant_id:%(tenant_id)s", + "admin_or_owner": "rule:context_is_admin or rule:owner", + "context_is_advsvc": "role:advsvc", + "admin_or_network_owner": "rule:context_is_admin or tenant_id:%(network:tenant_id)s", + "admin_owner_or_network_owner": "rule:owner or rule:admin_or_network_owner", + "admin_only": "rule:context_is_admin", + "regular_user": "", + "admin_or_data_plane_int": "rule:context_is_admin or role:data_plane_integrator", + "shared": "field:networks:shared=True", + "shared_subnetpools": "field:subnetpools:shared=True", + "shared_address_scopes": "field:address_scopes:shared=True", + "external": "field:networks:router:external=True", + "default": "rule:admin_or_owner", + + "create_subnet": "rule:admin_or_network_owner", + "create_subnet:segment_id": "rule:admin_only", + "create_subnet:service_types": "rule:admin_only", + "get_subnet": "rule:admin_or_owner or rule:shared", + "get_subnet:segment_id": "rule:admin_only", + "update_subnet": "rule:admin_or_network_owner", + "update_subnet:service_types": "rule:admin_only", + "delete_subnet": "rule:admin_or_network_owner", + + "create_subnetpool": "", + "create_subnetpool:shared": "rule:admin_only", + "create_subnetpool:is_default": "rule:admin_only", + "get_subnetpool": "rule:admin_or_owner or rule:shared_subnetpools", + "update_subnetpool": "rule:admin_or_owner", + "update_subnetpool:is_default": "rule:admin_only", + "delete_subnetpool": "rule:admin_or_owner", + + "create_address_scope": "", + "create_address_scope:shared": "rule:admin_only", + "get_address_scope": "rule:admin_or_owner or rule:shared_address_scopes", + "update_address_scope": "rule:admin_or_owner", + "update_address_scope:shared": "rule:admin_only", + "delete_address_scope": "rule:admin_or_owner", + + "create_network": "", + "get_network": "rule:admin_or_owner or rule:shared or rule:external or rule:context_is_advsvc", + "get_network:router:external": "rule:regular_user", + "get_network:segments": "rule:admin_only", + "get_network:provider:network_type": "rule:admin_only", + "get_network:provider:physical_network": "rule:admin_only", + "get_network:provider:segmentation_id": "rule:admin_only", + "get_network:queue_id": "rule:admin_only", + "get_network_ip_availabilities": "rule:admin_only", + "get_network_ip_availability": "rule:admin_only", + "create_network:shared": "rule:admin_only", + "create_network:router:external": "rule:admin_only", + "create_network:is_default": "rule:admin_only", + "create_network:segments": "rule:admin_only", + "create_network:provider:network_type": "rule:admin_only", + "create_network:provider:physical_network": "rule:admin_only", + "create_network:provider:segmentation_id": "rule:admin_only", + "update_network": "rule:admin_or_owner", + "update_network:segments": "rule:admin_only", + "update_network:shared": "rule:admin_only", + "update_network:provider:network_type": "rule:admin_only", + "update_network:provider:physical_network": "rule:admin_only", + "update_network:provider:segmentation_id": "rule:admin_only", + "update_network:router:external": "rule:admin_only", + "delete_network": "rule:admin_or_owner", + + "create_segment": "rule:admin_only", + "get_segment": "rule:admin_only", + "update_segment": "rule:admin_only", + "delete_segment": "rule:admin_only", + + "network_device": "field:port:device_owner=~^network:", + "create_port": "", + "create_port:device_owner": "not rule:network_device or rule:context_is_advsvc or rule:admin_or_network_owner", + "create_port:mac_address": "rule:context_is_advsvc or rule:admin_or_network_owner", + "create_port:fixed_ips:ip_address": "rule:context_is_advsvc or rule:admin_or_network_owner", + "create_port:fixed_ips:subnet_id": "rule:context_is_advsvc or rule:admin_or_network_owner or rule:shared", + "create_port:port_security_enabled": "rule:context_is_advsvc or rule:admin_or_network_owner", + "create_port:binding:host_id": "rule:admin_only", + "create_port:binding:profile": "rule:admin_only", + "create_port:mac_learning_enabled": "rule:context_is_advsvc or rule:admin_or_network_owner", + "create_port:allowed_address_pairs": "rule:admin_or_network_owner", + "get_port": "rule:context_is_advsvc or rule:admin_owner_or_network_owner", + "get_port:queue_id": "rule:admin_only", + "get_port:binding:vif_type": "rule:admin_only", + "get_port:binding:vif_details": "rule:admin_only", + "get_port:binding:host_id": "rule:admin_only", + "get_port:binding:profile": "rule:admin_only", + "update_port": "rule:admin_or_owner or rule:context_is_advsvc", + "update_port:device_owner": "not rule:network_device or rule:context_is_advsvc or rule:admin_or_network_owner", + "update_port:mac_address": "rule:admin_only or rule:context_is_advsvc", + "update_port:fixed_ips:ip_address": "rule:context_is_advsvc or rule:admin_or_network_owner", + "update_port:fixed_ips:subnet_id": "rule:context_is_advsvc or rule:admin_or_network_owner or rule:shared", + "update_port:port_security_enabled": "rule:context_is_advsvc or rule:admin_or_network_owner", + "update_port:binding:host_id": "rule:admin_only", + "update_port:binding:profile": "rule:admin_only", + "update_port:mac_learning_enabled": "rule:context_is_advsvc or rule:admin_or_network_owner", + "update_port:allowed_address_pairs": "rule:admin_or_network_owner", + "update_port:data_plane_status": "rule:admin_or_data_plane_int", + "delete_port": "rule:context_is_advsvc or rule:admin_owner_or_network_owner", + + "get_router:ha": "rule:admin_only", + "create_router": "rule:regular_user", + "create_router:external_gateway_info:enable_snat": "rule:admin_only", + "create_router:distributed": "rule:admin_only", + "create_router:ha": "rule:admin_only", + "get_router": "http://192.168.1.50:31002/wrapper/authz/grant", + "get_router:distributed": "rule:admin_only", + "update_router": "rule:admin_or_owner", + "update_router:external_gateway_info": "rule:admin_or_owner", + "update_router:external_gateway_info:network_id": "rule:admin_or_owner", + "update_router:external_gateway_info:enable_snat": "rule:admin_only", + "update_router:distributed": "rule:admin_only", + "update_router:ha": "rule:admin_only", + "delete_router": "rule:admin_or_owner", + + "add_router_interface": "rule:admin_or_owner", + "remove_router_interface": "rule:admin_or_owner", + + "create_router:external_gateway_info:external_fixed_ips": "rule:admin_only", + "update_router:external_gateway_info:external_fixed_ips": "rule:admin_only", + + "create_qos_queue": "rule:admin_only", + "get_qos_queue": "rule:admin_only", + + "update_agent": "rule:admin_only", + "delete_agent": "rule:admin_only", + "get_agent": "rule:admin_only", + + "create_dhcp-network": "rule:admin_only", + "delete_dhcp-network": "rule:admin_only", + "get_dhcp-networks": "rule:admin_only", + "create_l3-router": "rule:admin_only", + "delete_l3-router": "rule:admin_only", + "get_l3-routers": "rule:admin_only", + "get_dhcp-agents": "rule:admin_only", + "get_l3-agents": "rule:admin_only", + "get_loadbalancer-agent": "rule:admin_only", + "get_loadbalancer-pools": "rule:admin_only", + "get_agent-loadbalancers": "rule:admin_only", + "get_loadbalancer-hosting-agent": "rule:admin_only", + + "create_floatingip": "rule:regular_user", + "create_floatingip:floating_ip_address": "rule:admin_only", + "update_floatingip": "rule:admin_or_owner", + "delete_floatingip": "rule:admin_or_owner", + "get_floatingip": "rule:admin_or_owner", + + "create_network_profile": "rule:admin_only", + "update_network_profile": "rule:admin_only", + "delete_network_profile": "rule:admin_only", + "get_network_profiles": "", + "get_network_profile": "", + "update_policy_profiles": "rule:admin_only", + "get_policy_profiles": "", + "get_policy_profile": "", + + "create_metering_label": "rule:admin_only", + "delete_metering_label": "rule:admin_only", + "get_metering_label": "rule:admin_only", + + "create_metering_label_rule": "rule:admin_only", + "delete_metering_label_rule": "rule:admin_only", + "get_metering_label_rule": "rule:admin_only", + + "get_service_provider": "rule:regular_user", + "get_lsn": "rule:admin_only", + "create_lsn": "rule:admin_only", + + "create_flavor": "rule:admin_only", + "update_flavor": "rule:admin_only", + "delete_flavor": "rule:admin_only", + "get_flavors": "rule:regular_user", + "get_flavor": "rule:regular_user", + "create_service_profile": "rule:admin_only", + "update_service_profile": "rule:admin_only", + "delete_service_profile": "rule:admin_only", + "get_service_profiles": "rule:admin_only", + "get_service_profile": "rule:admin_only", + + "get_policy": "rule:regular_user", + "create_policy": "rule:admin_only", + "update_policy": "rule:admin_only", + "delete_policy": "rule:admin_only", + "get_policy_bandwidth_limit_rule": "rule:regular_user", + "create_policy_bandwidth_limit_rule": "rule:admin_only", + "delete_policy_bandwidth_limit_rule": "rule:admin_only", + "update_policy_bandwidth_limit_rule": "rule:admin_only", + "get_policy_dscp_marking_rule": "rule:regular_user", + "create_policy_dscp_marking_rule": "rule:admin_only", + "delete_policy_dscp_marking_rule": "rule:admin_only", + "update_policy_dscp_marking_rule": "rule:admin_only", + "get_rule_type": "rule:regular_user", + "get_policy_minimum_bandwidth_rule": "rule:regular_user", + "create_policy_minimum_bandwidth_rule": "rule:admin_only", + "delete_policy_minimum_bandwidth_rule": "rule:admin_only", + "update_policy_minimum_bandwidth_rule": "rule:admin_only", + + "restrict_wildcard": "(not field:rbac_policy:target_tenant=*) or rule:admin_only", + "create_rbac_policy": "", + "create_rbac_policy:target_tenant": "rule:restrict_wildcard", + "update_rbac_policy": "rule:admin_or_owner", + "update_rbac_policy:target_tenant": "rule:restrict_wildcard and rule:admin_or_owner", + "get_rbac_policy": "rule:admin_or_owner", + "delete_rbac_policy": "rule:admin_or_owner", + + "create_flavor_service_profile": "rule:admin_only", + "delete_flavor_service_profile": "rule:admin_only", + "get_flavor_service_profile": "rule:regular_user", + "get_auto_allocated_topology": "rule:admin_or_owner", + + "create_trunk": "rule:regular_user", + "get_trunk": "rule:admin_or_owner", + "delete_trunk": "rule:admin_or_owner", + "get_subports": "", + "add_subports": "rule:admin_or_owner", + "remove_subports": "rule:admin_or_owner", + + "get_security_groups": "rule:admin_or_owner", + "get_security_group": "rule:admin_or_owner", + "create_security_group": "rule:admin_or_owner", + "update_security_group": "rule:admin_or_owner", + "delete_security_group": "rule:admin_or_owner", + "get_security_group_rules": "rule:admin_or_owner", + "get_security_group_rule": "rule:admin_or_owner", + "create_security_group_rule": "rule:admin_or_owner", + "delete_security_group_rule": "rule:admin_or_owner", + + "get_loggable_resources": "rule:admin_only", + "create_log": "rule:admin_only", + "update_log": "rule:admin_only", + "delete_log": "rule:admin_only", + "get_logs": "rule:admin_only", + "get_log": "rule:admin_only" +} diff --git a/moon_utilities/conf/policy.json.d/nova.policy.json b/moon_utilities/conf/policy.json.d/nova.policy.json new file mode 100644 index 00000000..da8f5740 --- /dev/null +++ b/moon_utilities/conf/policy.json.d/nova.policy.json @@ -0,0 +1,485 @@ +{ + "context_is_admin": "role:admin", + "admin_or_owner": "is_admin:True or project_id:%(project_id)s", + "default": "rule:admin_or_owner", + + "cells_scheduler_filter:TargetCellFilter": "is_admin:True", + + "compute:create": "", + "compute:create:attach_network": "", + "compute:create:attach_volume": "", + "compute:create:forced_host": "is_admin:True", + + "compute:get": "", + "compute:get_all": "", + "compute:get_all_tenants": "is_admin:True", + + "compute:update": "", + + "compute:get_instance_metadata": "", + "compute:get_all_instance_metadata": "", + "compute:get_all_instance_system_metadata": "", + "compute:update_instance_metadata": "", + "compute:delete_instance_metadata": "", + + "compute:get_instance_faults": "", + "compute:get_diagnostics": "", + "compute:get_instance_diagnostics": "", + + "compute:start": "rule:admin_or_owner", + "compute:stop": "rule:admin_or_owner", + + "compute:get_lock": "", + "compute:lock": "rule:admin_or_owner", + "compute:unlock": "rule:admin_or_owner", + "compute:unlock_override": "rule:admin_api", + + "compute:get_vnc_console": "", + "compute:get_spice_console": "", + "compute:get_rdp_console": "", + "compute:get_serial_console": "", + "compute:get_mks_console": "", + "compute:get_console_output": "", + + "compute:reset_network": "", + "compute:inject_network_info": "", + "compute:add_fixed_ip": "", + "compute:remove_fixed_ip": "", + + "compute:attach_volume": "", + "compute:detach_volume": "", + "compute:swap_volume": "", + + "compute:attach_interface": "", + "compute:detach_interface": "", + + "compute:set_admin_password": "", + + "compute:rescue": "", + "compute:unrescue": "", + + "compute:suspend": "", + "compute:resume": "", + + "compute:pause": "", + "compute:unpause": "", + + "compute:shelve": "", + "compute:shelve_offload": "", + "compute:unshelve": "", + + "compute:snapshot": "", + "compute:snapshot_volume_backed": "", + "compute:backup": "", + + "compute:resize": "", + "compute:confirm_resize": "", + "compute:revert_resize": "", + + "compute:rebuild": "", + "compute:reboot": "", + "compute:delete": "rule:admin_or_owner", + "compute:soft_delete": "rule:admin_or_owner", + "compute:force_delete": "rule:admin_or_owner", + + "compute:security_groups:add_to_instance": "", + "compute:security_groups:remove_from_instance": "", + + "compute:restore": "", + + "compute:volume_snapshot_create": "", + "compute:volume_snapshot_delete": "", + + "admin_api": "is_admin:True", + "compute_extension:accounts": "rule:admin_api", + "compute_extension:admin_actions": "rule:admin_api", + "compute_extension:admin_actions:pause": "rule:admin_or_owner", + "compute_extension:admin_actions:unpause": "rule:admin_or_owner", + "compute_extension:admin_actions:suspend": "rule:admin_or_owner", + "compute_extension:admin_actions:resume": "rule:admin_or_owner", + "compute_extension:admin_actions:lock": "rule:admin_or_owner", + "compute_extension:admin_actions:unlock": "rule:admin_or_owner", + "compute_extension:admin_actions:resetNetwork": "rule:admin_api", + "compute_extension:admin_actions:injectNetworkInfo": "rule:admin_api", + "compute_extension:admin_actions:createBackup": "rule:admin_or_owner", + "compute_extension:admin_actions:migrateLive": "rule:admin_api", + "compute_extension:admin_actions:resetState": "rule:admin_api", + "compute_extension:admin_actions:migrate": "rule:admin_api", + "compute_extension:aggregates": "rule:admin_api", + "compute_extension:agents": "rule:admin_api", + "compute_extension:attach_interfaces": "", + "compute_extension:baremetal_nodes": "rule:admin_api", + "compute_extension:cells": "rule:admin_api", + "compute_extension:cells:create": "rule:admin_api", + "compute_extension:cells:delete": "rule:admin_api", + "compute_extension:cells:update": "rule:admin_api", + "compute_extension:cells:sync_instances": "rule:admin_api", + "compute_extension:certificates": "", + "compute_extension:cloudpipe": "rule:admin_api", + "compute_extension:cloudpipe_update": "rule:admin_api", + "compute_extension:config_drive": "", + "compute_extension:console_output": "", + "compute_extension:consoles": "", + "compute_extension:createserverext": "", + "compute_extension:deferred_delete": "", + "compute_extension:disk_config": "", + "compute_extension:evacuate": "rule:admin_api", + "compute_extension:extended_server_attributes": "rule:admin_api", + "compute_extension:extended_status": "", + "compute_extension:extended_availability_zone": "", + "compute_extension:extended_ips": "", + "compute_extension:extended_ips_mac": "", + "compute_extension:extended_vif_net": "", + "compute_extension:extended_volumes": "", + "compute_extension:fixed_ips": "rule:admin_api", + "compute_extension:flavor_access": "", + "compute_extension:flavor_access:addTenantAccess": "rule:admin_api", + "compute_extension:flavor_access:removeTenantAccess": "rule:admin_api", + "compute_extension:flavor_disabled": "", + "compute_extension:flavor_rxtx": "", + "compute_extension:flavor_swap": "", + "compute_extension:flavorextradata": "", + "compute_extension:flavorextraspecs:index": "", + "compute_extension:flavorextraspecs:show": "", + "compute_extension:flavorextraspecs:create": "rule:admin_api", + "compute_extension:flavorextraspecs:update": "rule:admin_api", + "compute_extension:flavorextraspecs:delete": "rule:admin_api", + "compute_extension:flavormanage": "rule:admin_api", + "compute_extension:floating_ip_dns": "", + "compute_extension:floating_ip_pools": "", + "compute_extension:floating_ips": "", + "compute_extension:floating_ips_bulk": "rule:admin_api", + "compute_extension:fping": "", + "compute_extension:fping:all_tenants": "rule:admin_api", + "compute_extension:hide_server_addresses": "is_admin:False", + "compute_extension:hosts": "rule:admin_api", + "compute_extension:hypervisors": "rule:admin_api", + "compute_extension:image_size": "", + "compute_extension:instance_actions": "", + "compute_extension:instance_actions:events": "rule:admin_api", + "compute_extension:instance_usage_audit_log": "rule:admin_api", + "compute_extension:keypairs": "", + "compute_extension:keypairs:index": "", + "compute_extension:keypairs:show": "", + "compute_extension:keypairs:create": "", + "compute_extension:keypairs:delete": "", + "compute_extension:multinic": "", + "compute_extension:networks": "rule:admin_api", + "compute_extension:networks:view": "", + "compute_extension:networks_associate": "rule:admin_api", + "compute_extension:os-tenant-networks": "", + "compute_extension:quotas:show": "", + "compute_extension:quotas:update": "rule:admin_api", + "compute_extension:quotas:delete": "rule:admin_api", + "compute_extension:quota_classes": "", + "compute_extension:rescue": "", + "compute_extension:security_group_default_rules": "rule:admin_api", + "compute_extension:security_groups": "", + "compute_extension:server_diagnostics": "rule:admin_api", + "compute_extension:server_groups": "", + "compute_extension:server_password": "", + "compute_extension:server_usage": "", + "compute_extension:services": "rule:admin_api", + "compute_extension:shelve": "", + "compute_extension:shelveOffload": "rule:admin_api", + "compute_extension:simple_tenant_usage:show": "rule:admin_or_owner", + "compute_extension:simple_tenant_usage:list": "rule:admin_api", + "compute_extension:unshelve": "", + "compute_extension:users": "rule:admin_api", + "compute_extension:virtual_interfaces": "", + "compute_extension:virtual_storage_arrays": "", + "compute_extension:volumes": "", + "compute_extension:volume_attachments:index": "", + "compute_extension:volume_attachments:show": "", + "compute_extension:volume_attachments:create": "", + "compute_extension:volume_attachments:update": "", + "compute_extension:volume_attachments:delete": "", + "compute_extension:volumetypes": "", + "compute_extension:availability_zone:list": "", + "compute_extension:availability_zone:detail": "rule:admin_api", + "compute_extension:used_limits_for_admin": "rule:admin_api", + "compute_extension:migrations:index": "rule:admin_api", + "compute_extension:os-assisted-volume-snapshots:create": "rule:admin_api", + "compute_extension:os-assisted-volume-snapshots:delete": "rule:admin_api", + "compute_extension:console_auth_tokens": "rule:admin_api", + "compute_extension:os-server-external-events:create": "rule:admin_api", + + "network:get_all": "", + "network:get": "", + "network:create": "", + "network:delete": "", + "network:associate": "", + "network:disassociate": "", + "network:get_vifs_by_instance": "", + "network:allocate_for_instance": "", + "network:deallocate_for_instance": "", + "network:validate_networks": "", + "network:get_instance_uuids_by_ip_filter": "", + "network:get_instance_id_by_floating_address": "", + "network:setup_networks_on_host": "", + "network:get_backdoor_port": "", + + "network:get_floating_ip": "", + "network:get_floating_ip_pools": "", + "network:get_floating_ip_by_address": "", + "network:get_floating_ips_by_project": "", + "network:get_floating_ips_by_fixed_address": "", + "network:allocate_floating_ip": "", + "network:associate_floating_ip": "", + "network:disassociate_floating_ip": "", + "network:release_floating_ip": "", + "network:migrate_instance_start": "", + "network:migrate_instance_finish": "", + + "network:get_fixed_ip": "", + "network:get_fixed_ip_by_address": "", + "network:add_fixed_ip_to_instance": "", + "network:remove_fixed_ip_from_instance": "", + "network:add_network_to_project": "", + "network:get_instance_nw_info": "", + + "network:get_dns_domains": "", + "network:add_dns_entry": "", + "network:modify_dns_entry": "", + "network:delete_dns_entry": "", + "network:get_dns_entries_by_address": "", + "network:get_dns_entries_by_name": "", + "network:create_private_dns_domain": "", + "network:create_public_dns_domain": "", + "network:delete_dns_domain": "", + "network:attach_external_network": "rule:admin_api", + "network:get_vif_by_mac_address": "", + + "os_compute_api:servers:detail:get_all_tenants": "is_admin:True", + "os_compute_api:servers:index:get_all_tenants": "is_admin:True", + "os_compute_api:servers:confirm_resize": "", + "os_compute_api:servers:create": "", + "os_compute_api:servers:create:attach_network": "", + "os_compute_api:servers:create:attach_volume": "", + "os_compute_api:servers:create:forced_host": "rule:admin_api", + "os_compute_api:servers:delete": "", + "os_compute_api:servers:update": "", + "os_compute_api:servers:detail": "", + "os_compute_api:servers:index": "", + "os_compute_api:servers:reboot": "", + "os_compute_api:servers:rebuild": "", + "os_compute_api:servers:resize": "", + "os_compute_api:servers:revert_resize": "", + "os_compute_api:servers:show": "", + "os_compute_api:servers:create_image": "", + "os_compute_api:servers:create_image:allow_volume_backed": "", + "os_compute_api:servers:start": "rule:admin_or_owner", + "os_compute_api:servers:stop": "rule:admin_or_owner", + "os_compute_api:os-access-ips:discoverable": "", + "os_compute_api:os-access-ips": "", + "os_compute_api:os-admin-actions": "rule:admin_api", + "os_compute_api:os-admin-actions:discoverable": "", + "os_compute_api:os-admin-actions:reset_network": "rule:admin_api", + "os_compute_api:os-admin-actions:inject_network_info": "rule:admin_api", + "os_compute_api:os-admin-actions:reset_state": "rule:admin_api", + "os_compute_api:os-admin-password": "", + "os_compute_api:os-admin-password:discoverable": "", + "os_compute_api:os-aggregates:discoverable": "", + "os_compute_api:os-aggregates:index": "rule:admin_api", + "os_compute_api:os-aggregates:create": "rule:admin_api", + "os_compute_api:os-aggregates:show": "rule:admin_api", + "os_compute_api:os-aggregates:update": "rule:admin_api", + "os_compute_api:os-aggregates:delete": "rule:admin_api", + "os_compute_api:os-aggregates:add_host": "rule:admin_api", + "os_compute_api:os-aggregates:remove_host": "rule:admin_api", + "os_compute_api:os-aggregates:set_metadata": "rule:admin_api", + "os_compute_api:os-agents": "rule:admin_api", + "os_compute_api:os-agents:discoverable": "", + "os_compute_api:os-attach-interfaces": "", + "os_compute_api:os-attach-interfaces:discoverable": "", + "os_compute_api:os-baremetal-nodes": "rule:admin_api", + "os_compute_api:os-baremetal-nodes:discoverable": "", + "os_compute_api:os-block-device-mapping-v1:discoverable": "", + "os_compute_api:os-cells": "rule:admin_api", + "os_compute_api:os-cells:create": "rule:admin_api", + "os_compute_api:os-cells:delete": "rule:admin_api", + "os_compute_api:os-cells:update": "rule:admin_api", + "os_compute_api:os-cells:sync_instances": "rule:admin_api", + "os_compute_api:os-cells:discoverable": "", + "os_compute_api:os-certificates:create": "", + "os_compute_api:os-certificates:show": "", + "os_compute_api:os-certificates:discoverable": "", + "os_compute_api:os-cloudpipe": "rule:admin_api", + "os_compute_api:os-cloudpipe:discoverable": "", + "os_compute_api:os-config-drive": "", + "os_compute_api:os-consoles:discoverable": "", + "os_compute_api:os-consoles:create": "", + "os_compute_api:os-consoles:delete": "", + "os_compute_api:os-consoles:index": "", + "os_compute_api:os-consoles:show": "", + "os_compute_api:os-console-output:discoverable": "", + "os_compute_api:os-console-output": "", + "os_compute_api:os-remote-consoles": "", + "os_compute_api:os-remote-consoles:discoverable": "", + "os_compute_api:os-create-backup:discoverable": "", + "os_compute_api:os-create-backup": "rule:admin_or_owner", + "os_compute_api:os-deferred-delete": "", + "os_compute_api:os-deferred-delete:discoverable": "", + "os_compute_api:os-disk-config": "", + "os_compute_api:os-disk-config:discoverable": "", + "os_compute_api:os-evacuate": "rule:admin_api", + "os_compute_api:os-evacuate:discoverable": "", + "os_compute_api:os-extended-server-attributes": "rule:admin_api", + "os_compute_api:os-extended-server-attributes:discoverable": "", + "os_compute_api:os-extended-status": "", + "os_compute_api:os-extended-status:discoverable": "", + "os_compute_api:os-extended-availability-zone": "", + "os_compute_api:os-extended-availability-zone:discoverable": "", + "os_compute_api:extensions": "", + "os_compute_api:extension_info:discoverable": "", + "os_compute_api:os-extended-volumes": "", + "os_compute_api:os-extended-volumes:discoverable": "", + "os_compute_api:os-fixed-ips": "rule:admin_api", + "os_compute_api:os-fixed-ips:discoverable": "", + "os_compute_api:os-flavor-access": "", + "os_compute_api:os-flavor-access:discoverable": "", + "os_compute_api:os-flavor-access:remove_tenant_access": "rule:admin_api", + "os_compute_api:os-flavor-access:add_tenant_access": "rule:admin_api", + "os_compute_api:os-flavor-rxtx": "", + "os_compute_api:os-flavor-rxtx:discoverable": "", + "os_compute_api:flavors:discoverable": "", + "os_compute_api:os-flavor-extra-specs:discoverable": "", + "os_compute_api:os-flavor-extra-specs:index": "", + "os_compute_api:os-flavor-extra-specs:show": "", + "os_compute_api:os-flavor-extra-specs:create": "rule:admin_api", + "os_compute_api:os-flavor-extra-specs:update": "rule:admin_api", + "os_compute_api:os-flavor-extra-specs:delete": "rule:admin_api", + "os_compute_api:os-flavor-manage:discoverable": "", + "os_compute_api:os-flavor-manage": "rule:admin_api", + "os_compute_api:os-floating-ip-dns": "", + "os_compute_api:os-floating-ip-dns:discoverable": "", + "os_compute_api:os-floating-ip-dns:domain:update": "rule:admin_api", + "os_compute_api:os-floating-ip-dns:domain:delete": "rule:admin_api", + "os_compute_api:os-floating-ip-pools": "", + "os_compute_api:os-floating-ip-pools:discoverable": "", + "os_compute_api:os-floating-ips": "", + "os_compute_api:os-floating-ips:discoverable": "", + "os_compute_api:os-floating-ips-bulk": "rule:admin_api", + "os_compute_api:os-floating-ips-bulk:discoverable": "", + "os_compute_api:os-fping": "", + "os_compute_api:os-fping:discoverable": "", + "os_compute_api:os-fping:all_tenants": "rule:admin_api", + "os_compute_api:os-hide-server-addresses": "is_admin:False", + "os_compute_api:os-hide-server-addresses:discoverable": "", + "os_compute_api:os-hosts": "rule:admin_api", + "os_compute_api:os-hosts:discoverable": "", + "os_compute_api:os-hypervisors": "rule:admin_api", + "os_compute_api:os-hypervisors:discoverable": "", + "os_compute_api:images:discoverable": "", + "os_compute_api:image-size": "", + "os_compute_api:image-size:discoverable": "", + "os_compute_api:os-instance-actions": "", + "os_compute_api:os-instance-actions:discoverable": "", + "os_compute_api:os-instance-actions:events": "rule:admin_api", + "os_compute_api:os-instance-usage-audit-log": "rule:admin_api", + "os_compute_api:os-instance-usage-audit-log:discoverable": "", + "os_compute_api:ips:discoverable": "", + "os_compute_api:ips:index": "rule:admin_or_owner", + "os_compute_api:ips:show": "rule:admin_or_owner", + "os_compute_api:os-keypairs:discoverable": "", + "os_compute_api:os-keypairs": "", + "os_compute_api:os-keypairs:index": "rule:admin_api or user_id:%(user_id)s", + "os_compute_api:os-keypairs:show": "rule:admin_api or user_id:%(user_id)s", + "os_compute_api:os-keypairs:create": "rule:admin_api or user_id:%(user_id)s", + "os_compute_api:os-keypairs:delete": "rule:admin_api or user_id:%(user_id)s", + "os_compute_api:limits:discoverable": "", + "os_compute_api:limits": "", + "os_compute_api:os-lock-server:discoverable": "", + "os_compute_api:os-lock-server:lock": "rule:admin_or_owner", + "os_compute_api:os-lock-server:unlock": "rule:admin_or_owner", + "os_compute_api:os-lock-server:unlock:unlock_override": "rule:admin_api", + "os_compute_api:os-migrate-server:discoverable": "", + "os_compute_api:os-migrate-server:migrate": "rule:admin_api", + "os_compute_api:os-migrate-server:migrate_live": "rule:admin_api", + "os_compute_api:os-multinic": "", + "os_compute_api:os-multinic:discoverable": "", + "os_compute_api:os-networks": "rule:admin_api", + "os_compute_api:os-networks:view": "", + "os_compute_api:os-networks:discoverable": "", + "os_compute_api:os-networks-associate": "rule:admin_api", + "os_compute_api:os-networks-associate:discoverable": "", + "os_compute_api:os-pause-server:discoverable": "", + "os_compute_api:os-pause-server:pause": "rule:admin_or_owner", + "os_compute_api:os-pause-server:unpause": "rule:admin_or_owner", + "os_compute_api:os-pci:pci_servers": "", + "os_compute_api:os-pci:discoverable": "", + "os_compute_api:os-pci:index": "rule:admin_api", + "os_compute_api:os-pci:detail": "rule:admin_api", + "os_compute_api:os-pci:show": "rule:admin_api", + "os_compute_api:os-personality:discoverable": "", + "os_compute_api:os-preserve-ephemeral-rebuild:discoverable": "", + "os_compute_api:os-quota-sets:discoverable": "", + "os_compute_api:os-quota-sets:show": "rule:admin_or_owner", + "os_compute_api:os-quota-sets:defaults": "", + "os_compute_api:os-quota-sets:update": "rule:admin_api", + "os_compute_api:os-quota-sets:delete": "rule:admin_api", + "os_compute_api:os-quota-sets:detail": "rule:admin_api", + "os_compute_api:os-quota-class-sets:update": "rule:admin_api", + "os_compute_api:os-quota-class-sets:show": "is_admin:True or quota_class:%(quota_class)s", + "os_compute_api:os-quota-class-sets:discoverable": "", + "os_compute_api:os-rescue": "", + "os_compute_api:os-rescue:discoverable": "", + "os_compute_api:os-scheduler-hints:discoverable": "", + "os_compute_api:os-security-group-default-rules:discoverable": "", + "os_compute_api:os-security-group-default-rules": "rule:admin_api", + "os_compute_api:os-security-groups": "", + "os_compute_api:os-security-groups:discoverable": "", + "os_compute_api:os-server-diagnostics": "rule:admin_api", + "os_compute_api:os-server-diagnostics:discoverable": "", + "os_compute_api:os-server-password": "", + "os_compute_api:os-server-password:discoverable": "", + "os_compute_api:os-server-usage": "", + "os_compute_api:os-server-usage:discoverable": "", + "os_compute_api:os-server-groups": "", + "os_compute_api:os-server-groups:discoverable": "", + "os_compute_api:os-services": "rule:admin_api", + "os_compute_api:os-services:discoverable": "", + "os_compute_api:server-metadata:discoverable": "", + "os_compute_api:server-metadata:index": "rule:admin_or_owner", + "os_compute_api:server-metadata:show": "rule:admin_or_owner", + "os_compute_api:server-metadata:delete": "rule:admin_or_owner", + "os_compute_api:server-metadata:create": "rule:admin_or_owner", + "os_compute_api:server-metadata:update": "rule:admin_or_owner", + "os_compute_api:server-metadata:update_all": "rule:admin_or_owner", + "os_compute_api:servers:discoverable": "", + "os_compute_api:os-shelve:shelve": "", + "os_compute_api:os-shelve:shelve:discoverable": "", + "os_compute_api:os-shelve:shelve_offload": "rule:admin_api", + "os_compute_api:os-simple-tenant-usage:discoverable": "", + "os_compute_api:os-simple-tenant-usage:show": "rule:admin_or_owner", + "os_compute_api:os-simple-tenant-usage:list": "rule:admin_api", + "os_compute_api:os-suspend-server:discoverable": "", + "os_compute_api:os-suspend-server:suspend": "rule:admin_or_owner", + "os_compute_api:os-suspend-server:resume": "rule:admin_or_owner", + "os_compute_api:os-tenant-networks": "rule:admin_or_owner", + "os_compute_api:os-tenant-networks:discoverable": "", + "os_compute_api:os-shelve:unshelve": "", + "os_compute_api:os-user-data:discoverable": "", + "os_compute_api:os-virtual-interfaces": "", + "os_compute_api:os-virtual-interfaces:discoverable": "", + "os_compute_api:os-volumes": "", + "os_compute_api:os-volumes:discoverable": "", + "os_compute_api:os-volumes-attachments:index": "", + "os_compute_api:os-volumes-attachments:show": "", + "os_compute_api:os-volumes-attachments:create": "", + "os_compute_api:os-volumes-attachments:update": "", + "os_compute_api:os-volumes-attachments:delete": "", + "os_compute_api:os-volumes-attachments:discoverable": "", + "os_compute_api:os-availability-zone:list": "", + "os_compute_api:os-availability-zone:discoverable": "", + "os_compute_api:os-availability-zone:detail": "rule:admin_api", + "os_compute_api:os-used-limits": "rule:admin_api", + "os_compute_api:os-used-limits:discoverable": "", + "os_compute_api:os-migrations:index": "rule:admin_api", + "os_compute_api:os-migrations:discoverable": "", + "os_compute_api:os-assisted-volume-snapshots:create": "rule:admin_api", + "os_compute_api:os-assisted-volume-snapshots:delete": "rule:admin_api", + "os_compute_api:os-assisted-volume-snapshots:discoverable": "", + "os_compute_api:os-console-auth-tokens": "rule:admin_api", + "os_compute_api:os-server-external-events:create": "rule:admin_api" +} diff --git a/moon_utilities/moon_utilities/__init__.py b/moon_utilities/moon_utilities/__init__.py new file mode 100644 index 00000000..d1e99258 --- /dev/null +++ b/moon_utilities/moon_utilities/__init__.py @@ -0,0 +1,13 @@ +# 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. + + +__version__ = "0.8" diff --git a/moon_utilities/moon_utilities/auth_functions.py b/moon_utilities/moon_utilities/auth_functions.py new file mode 100644 index 00000000..08a0ec22 --- /dev/null +++ b/moon_utilities/moon_utilities/auth_functions.py @@ -0,0 +1,307 @@ +# 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 binascii +import hashlib +import os +import hug +import logging +import os +import getpass +from tinydb import TinyDB, Query +from moon_utilities import exceptions + +LOGGER = logging.getLogger("moon.utilities.auth_functions") +db = None + + +def init_db(db_filename="db.json"): + global db + db = TinyDB(db_filename) + + +def xor_encode(data, key): + """ + Encode data with the given key + + :param data: the data to encode + :param key: the key ie password + :return: a xor-ed version of the 2 strings + """ + if not data: + return "" + if not key: + raise exceptions.EncryptError + return binascii.hexlify( + ''.join(chr(ord(a) ^ ord(b)) for a, b in zip(data, key)).encode("utf-8")).decode("utf-8") + + +def xor_decode(data, key): + """ + Decode data with the given key + + :param data: the data to decode + :param key: the key ie password + :return: a xor-ed version of the 2 strings + """ + if not data: + return "" + if not key: + raise exceptions.DecryptError + data = binascii.a2b_hex(data.encode("utf-8")).decode("utf-8") + return ''.join(chr(ord(a) ^ ord(b)) for a, b in zip(data, key)) + + +# From https://github.com/timothycrosley/hug/blob/develop/examples/secure_auth_with_db_example.py + +def hash_password(password, salt): + """ + Securely hash a password using a provided salt + :param password: + :param salt: + :return: Hex encoded SHA512 hash of provided password + """ + password = str(password).encode('utf-8') + salt = str(salt).encode('utf-8') + return hashlib.sha512(password + salt).hexdigest() + + +def gen_api_key(username): + """ + Create a random API key for a user + :param username: + :return: Hex encoded SHA512 random string + """ + salt = str(os.urandom(64)).encode('utf-8') + return hash_password(username, salt) + + +def get_api_key_for_user(username): + """ + Return the API key for a particular user + :param username: + :return: API key + """ + global db + if db is None: + init_db() + user_model = Query() + user = db.get(user_model.username == username) + + if not user: + LOGGER.warning("User %s not found", username) + return False + + return user['api_key'] + + +def del_api_key_for_user(username): + """ + Delete the API key for a particular user + :param username: + :return: API key + """ + global db + if db is None: + init_db() + user_model = Query() + users = db.search(user_model.username == username) + + if not users: + LOGGER.warning("User %s not found", username) + return False + try: + for user in users: + user['api_key'] = None + db.write_back(users) + return True + except Exception as e: + LOGGER.exception(e) + return False + + +def connect_from_env(): + try: + user = os.environ["MOON_USERNAME"] + pw = os.environ["MOON_PASSWORD"] + except KeyError: + LOGGER.error("Set your credentials with moonrc") + exit(-1) + + return get_api_key(user, pw) + + +@hug.cli("get_key") +def get_api_key(username, password): + """ + Authenticate a username and password against our database + :param username: + :param password: + :return: authenticated username + """ + global db + if db is None: + init_db() + user_model = Query() + user = db.get(user_model.username == username) + + if not user: + LOGGER.warning("User %s not found", username) + return False + + if user['password'] == hash_password(password, user.get('salt')): + return user['api_key'] + + return False + + +@hug.cli() +def authenticate_user(username, password): + """ + Authenticate a username and password against our database + :param username: + :param password: + :return: authenticated username + """ + global db + if db is None: + init_db() + user_model = Query() + users = db.search(user_model.username == username) + + if not users: + LOGGER.warning("User %s not found", username) + return False + + for user in users: + # Note: will only update the first item + if user['password'] == hash_password(password, user.get('salt')): + if not user['api_key']: + api_key = gen_api_key(username) + user['api_key'] = api_key + db.write_back(users) + return user['username'] + LOGGER.warning("Wrong password for user %s", username) + return False + + +@hug.cli() +def change_password(username, current_password, new_password): + """ + Change the password of the user in the database + :param username: + :param current_password: + :param new_password: + :return: True or False + """ + + if current_password == "": # nosec (not a hardcoded password) + current_password = getpass.getpass() + + is_password_ok = authenticate_user(username, current_password) + if not is_password_ok: + return False + + if new_password == "": # nosec (not a hardcoded password) + new_password = getpass.getpass() + + global db + if db is None: + init_db() + user_model = Query() + user = db.search(user_model.username == username)[0] + + salt = user['salt'] + password = hash_password(new_password, salt) + api_key = gen_api_key(username) + + user_id = db.update({'password': password, 'api_key': api_key}, doc_ids=[user.doc_id]) + + return { + 'result': 'success', + 'eid': user_id, + 'user_created': user, + 'api_key': api_key + } + + +@hug.cli() +def authenticate_key(api_key): + """ + Authenticate an API key against our database + :param api_key: + :return: authenticated username + """ + global db + if db is None: + init_db() + try: + if not api_key: + return False + user_model = Query() + user = db.search(user_model.api_key == api_key)[0] + if user: + return user['username'] + except Exception as e: + LOGGER.exception(e) + LOGGER.error("Cannot retrieve user for this authentication key {}".format(api_key)) + return False + + +""" + API Methods start here +""" + +api_key_authentication = hug.authentication.api_key(authenticate_key) +basic_authentication = hug.authentication.basic(authenticate_user) + + +@hug.cli("add_user") # nosec (not a hardcoded password) +def add_user(username, password=""): + """ + CLI Parameter to add a user to the database + :param username: + :param password: if not given, a password prompt is displayed + :return: JSON status output + """ + global db + if db is None: + init_db() + user_model = Query() + if db.search(user_model.username == username): + return { + 'error': 'User {0} already exists'.format(username) + } + + if password == "": # nosec (not a hardcoded password) + password = getpass.getpass() + + salt = hashlib.sha512(str(os.urandom(64)).encode('utf-8')).hexdigest() + password = hash_password(password, salt) + api_key = gen_api_key(username) + + user = { + 'username': username, + 'password': password, + 'salt': salt, + 'api_key': api_key + } + user_id = db.insert(user) + + return { + 'result': 'success', + 'eid': user_id, + 'user_created': user, + 'api_key': api_key + } diff --git a/moon_utilities/moon_utilities/exceptions.py b/moon_utilities/moon_utilities/exceptions.py new file mode 100644 index 00000000..4e016e70 --- /dev/null +++ b/moon_utilities/moon_utilities/exceptions.py @@ -0,0 +1,903 @@ +# 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.utilities.exceptions") +_ = str + + +class MoonErrorMetaClass(type): + + def __init__(cls, name, bases, dct): + super(MoonErrorMetaClass, cls).__init__(name, bases, dct) + cls.hierarchy += "/" + str(name) + + +class MoonError(BaseException): + __metaclass__ = MoonErrorMetaClass + hierarchy = "" + description = _("There is an error requesting the Moon platform.") + code = 400 + title = 'Moon Error' + logger = "ERROR" + + def __init__(self, message="", status_code=None, payload=""): + if message: + self.description = message + if status_code: + self.code = status_code + self.payload = payload + super(MoonError, self).__init__() + + def __str__(self): + return "{}: {}".format(self.code, self.title) + + def __del__(self): + message = "{} ({}) {}".format(self.hierarchy, self.description, self.payload) + if self.logger == "ERROR": + try: + logger.error(message) + except AttributeError: + logger.error(message) + elif self.logger == "WARNING": + try: + logger.warning(message) + except AttributeError: + logger.warning(message) + elif self.logger == "CRITICAL": + try: + logger.critical(message) + except AttributeError: + logger.critical(message) + elif self.logger == "AUTHZ": + try: + logger.error(message) + except AttributeError: + logger.error(message) + else: + try: + logger.info(message) + except AttributeError: + logger.info(message) + + # def to_dict(self): + # rv = dict(self.payload or ()) + # rv['message'] = "{} ({})".format(self.hierarchy, self.description) + # rv['title'] = self.title + # rv['code'] = self.code + # return rv + + +# Exceptions for Tenant + +class TenantException(MoonError): + description = _("There is an error requesting this tenant.") + code = 400 + title = 'Tenant Error' + logger = "ERROR" + + +class TenantUnknown(TenantException): + description = _("The tenant is unknown.") + code = 400 + title = 'Tenant Unknown' + logger = "ERROR" + + +class TenantAddedNameExisting(TenantException): + description = _("The tenant name is existing.") + code = 400 + title = 'Added Tenant Name Existing' + logger = "ERROR" + + +class TenantNoIntraExtension(TenantException): + description = _("The tenant has not intra_extension.") + code = 400 + title = 'Tenant No Intra_Extension' + logger = "ERROR" + + +class TenantNoIntraAuthzExtension(TenantNoIntraExtension): + description = _("The tenant has not intra_admin_extension.") + code = 400 + title = 'Tenant No Intra_Admin_Extension' + logger = "ERROR" + + +# Exceptions for IntraExtension + + +class IntraExtensionException(MoonError): + description = _("There is an error requesting this IntraExtension.") + code = 400 + title = 'Extension Error' + + +class IntraExtensionUnknown(IntraExtensionException): + description = _("The intra_extension is unknown.") + code = 400 + title = 'Intra Extension Unknown' + logger = "Error" + + +class ModelUnknown(MoonError): + description = _("The model is unknown.") + code = 400 + title = 'Model Unknown' + logger = "Error" + + +class ModelContentError(MoonError): + description = _("The model content is invalid.") + code = 400 + title = 'Model Unknown' + logger = "Error" + + +class ModelExisting(MoonError): + description = _("The model already exists.") + code = 409 + title = 'Model Error' + logger = "Error" + + +# Authz exceptions + +class AuthzException(MoonError): + description = _("There is an authorization error requesting this IntraExtension.") + code = 403 + title = 'Authz Exception' + logger = "AUTHZ" + + +# Auth exceptions + +class AuthException(MoonError): + description = _("There is an authentication error requesting this API. " + "You must provide a valid token from Keystone.") + code = 401 + title = 'Auth Exception' + logger = "AUTHZ" + + +# Admin exceptions + +class AdminException(MoonError): + description = _("There is an error requesting this Authz IntraExtension.") + code = 400 + title = 'Authz Exception' + logger = "AUTHZ" + + +class AdminMetaData(AdminException): + code = 400 + title = 'Metadata Exception' + + +class AdminPerimeter(AdminException): + code = 400 + title = 'Perimeter Exception' + + +class AdminScope(AdminException): + code = 400 + title = 'Scope Exception' + + +class AdminAssignment(AdminException): + code = 400 + title = 'Assignment Exception' + + +class AdminMetaRule(AdminException): + code = 400 + title = 'Aggregation Algorithm Exception' + + +class AdminRule(AdminException): + code = 400 + title = 'Rule Exception' + + +class CategoryNameInvalid(AdminMetaData): + description = _("The given category name is invalid.") + code = 400 + title = 'Category Name Invalid' + logger = "ERROR" + + +class SubjectCategoryExisting(AdminMetaData): + description = _("The given subject category already exists.") + code = 409 + title = 'Subject Category Existing' + logger = "ERROR" + + +class ObjectCategoryExisting(AdminMetaData): + description = _("The given object category already exists.") + code = 409 + title = 'Object Category Existing' + logger = "ERROR" + + +class ActionCategoryExisting(AdminMetaData): + description = _("The given action category already exists.") + code = 409 + title = 'Action Category Existing' + logger = "ERROR" + + +class SubjectCategoryUnknown(AdminMetaData): + description = _("The given subject category is unknown.") + code = 400 + title = 'Subject Category Unknown' + logger = "ERROR" + + +class DeleteSubjectCategoryWithMetaRule(MoonError): + description = _("Cannot delete subject category used in meta rule ") + code = 400 + title = 'Subject Category With Meta Rule Error' + logger = "Error" + + +class DeleteObjectCategoryWithMetaRule(MoonError): + description = _("Cannot delete Object category used in meta rule ") + code = 400 + title = 'Object Category With Meta Rule Error' + logger = "Error" + + +class ObjectCategoryUnknown(AdminMetaData): + description = _("The given object category is unknown.") + code = 400 + title = 'Object Category Unknown' + logger = "ERROR" + + +class DeleteActionCategoryWithMetaRule(MoonError): + description = _("Cannot delete Action category used in meta rule ") + code = 400 + title = 'Action Category With Meta Rule Error' + logger = "Error" + + +class ActionCategoryUnknown(AdminMetaData): + description = _("The given action category is unknown.") + code = 400 + title = 'Action Category Unknown' + logger = "ERROR" + + +class PerimeterContentError(AdminPerimeter): + description = _("Perimeter content is invalid.") + code = 400 + title = 'Perimeter content is invalid.' + logger = "ERROR" + + +class DeletePerimeterWithAssignment(MoonError): + description = _("Cannot delete perimeter with assignment") + code = 400 + title = 'Perimeter With Assignment Error' + logger = "Error" + + +class SubjectUnknown(AdminPerimeter): + description = _("The given subject is unknown.") + code = 400 + title = 'Subject Unknown' + logger = "ERROR" + + +class ObjectUnknown(AdminPerimeter): + description = _("The given object is unknown.") + code = 400 + title = 'Object Unknown' + logger = "ERROR" + + +class ActionUnknown(AdminPerimeter): + description = _("The given action is unknown.") + code = 400 + title = 'Action Unknown' + logger = "ERROR" + + +class SubjectExisting(AdminPerimeter): + description = _("The given subject is existing.") + code = 409 + title = 'Subject Existing' + logger = "ERROR" + + +class ObjectExisting(AdminPerimeter): + description = _("The given object is existing.") + code = 409 + title = 'Object Existing' + logger = "ERROR" + + +class ActionExisting(AdminPerimeter): + description = _("The given action is existing.") + code = 409 + title = 'Action Existing' + logger = "ERROR" + + +class SubjectNameExisting(AdminPerimeter): + description = _("The given subject name is existing.") + code = 409 + title = 'Subject Name Existing' + logger = "ERROR" + + +class ObjectNameExisting(AdminPerimeter): + description = _("The given object name is existing.") + code = 409 + title = 'Object Name Existing' + logger = "ERROR" + + +class ActionNameExisting(AdminPerimeter): + description = _("The given action name is existing.") + code = 409 + title = 'Action Name Existing' + logger = "ERROR" + + +class ObjectsWriteNoAuthorized(AdminPerimeter): + description = _("The modification on Objects is not authorized.") + code = 400 + title = 'Objects Write No Authorized' + logger = "AUTHZ" + + +class ActionsWriteNoAuthorized(AdminPerimeter): + description = _("The modification on Actions is not authorized.") + code = 400 + title = 'Actions Write No Authorized' + logger = "AUTHZ" + + +class SubjectScopeUnknown(AdminScope): + description = _("The given subject scope is unknown.") + code = 400 + title = 'Subject Scope Unknown' + logger = "ERROR" + + +class ObjectScopeUnknown(AdminScope): + description = _("The given object scope is unknown.") + code = 400 + title = 'Object Scope Unknown' + logger = "ERROR" + + +class ActionScopeUnknown(AdminScope): + description = _("The given action scope is unknown.") + code = 400 + title = 'Action Scope Unknown' + logger = "ERROR" + + +class SubjectScopeExisting(AdminScope): + description = _("The given subject scope is existing.") + code = 409 + title = 'Subject Scope Existing' + logger = "ERROR" + + +class ObjectScopeExisting(AdminScope): + description = _("The given object scope is existing.") + code = 409 + title = 'Object Scope Existing' + logger = "ERROR" + + +class ActionScopeExisting(AdminScope): + description = _("The given action scope is existing.") + code = 409 + title = 'Action Scope Existing' + logger = "ERROR" + + +class SubjectScopeNameExisting(AdminScope): + description = _("The given subject scope name is existing.") + code = 409 + title = 'Subject Scope Name Existing' + logger = "ERROR" + + +class ObjectScopeNameExisting(AdminScope): + description = _("The given object scope name is existing.") + code = 409 + title = 'Object Scope Name Existing' + logger = "ERROR" + + +class ActionScopeNameExisting(AdminScope): + description = _("The given action scope name is existing.") + code = 409 + title = 'Action Scope Name Existing' + logger = "ERROR" + + +class SubjectAssignmentUnknown(AdminAssignment): + description = _("The given subject assignment value is unknown.") + code = 400 + title = 'Subject Assignment Unknown' + logger = "ERROR" + + +class ObjectAssignmentUnknown(AdminAssignment): + description = _("The given object assignment value is unknown.") + code = 400 + title = 'Object Assignment Unknown' + logger = "ERROR" + + +class ActionAssignmentUnknown(AdminAssignment): + description = _("The given action assignment value is unknown.") + code = 400 + title = 'Action Assignment Unknown' + logger = "ERROR" + + +class SubjectAssignmentExisting(AdminAssignment): + description = _("The given subject assignment value is existing.") + code = 409 + title = 'Subject Assignment Existing' + logger = "ERROR" + + +class ObjectAssignmentExisting(AdminAssignment): + description = _("The given object assignment value is existing.") + code = 409 + title = 'Object Assignment Existing' + logger = "ERROR" + + +class ActionAssignmentExisting(AdminAssignment): + description = _("The given action assignment value is existing.") + code = 409 + title = 'Action Assignment Existing' + logger = "ERROR" + + +class AggregationAlgorithmNotExisting(AdminMetaRule): + description = _("The given aggregation algorithm is not existing.") + code = 400 + title = 'Aggregation Algorithm Not Existing' + logger = "ERROR" + + +class AggregationAlgorithmUnknown(AdminMetaRule): + description = _("The given aggregation algorithm is unknown.") + code = 400 + title = 'Aggregation Algorithm Unknown' + logger = "ERROR" + + +class SubMetaRuleAlgorithmNotExisting(AdminMetaRule): + description = _("The given sub_meta_rule algorithm is unknown.") + code = 400 + title = 'Sub_meta_rule Algorithm Unknown' + logger = "ERROR" + + +class MetaRuleUnknown(AdminMetaRule): + description = _("The given meta rule is unknown.") + code = 400 + title = 'Meta Rule Unknown' + logger = "ERROR" + + +class MetaRuleNotLinkedWithPolicyModel(MoonError): + description = _("The meta rule is not found in the model attached to the policy.") + code = 400 + title = 'MetaRule Not Linked With Model - Policy' + logger = "Error" + + +class CategoryNotAssignedMetaRule(MoonError): + description = _("The category is not found in the meta rules attached to the policy.") + code = 400 + title = 'Category Not Linked With Meta Rule - Policy' + logger = "Error" + + +class SubMetaRuleNameExisting(AdminMetaRule): + description = _("The sub meta rule name already exists.") + code = 409 + title = 'Sub Meta Rule Name Existing' + logger = "ERROR" + + +class MetaRuleExisting(AdminMetaRule): + description = _("The meta rule already exists.") + code = 409 + title = 'Meta Rule Existing' + logger = "ERROR" + + +class MetaRuleContentError(AdminMetaRule): + description = _("Invalid content of meta rule.") + code = 400 + title = 'Meta Rule Error' + logger = "ERROR" + + +class MetaRuleUpdateError(AdminMetaRule): + description = _("Meta_rule is used in Rule.") + code = 400 + title = 'Meta_Rule Update Error' + logger = "ERROR" + + +class RuleExisting(AdminRule): + description = _("The rule already exists.") + code = 409 + title = 'Rule Existing' + logger = "ERROR" + + +class RuleContentError(AdminRule): + description = _("Invalid content of rule.") + code = 400 + title = 'Rule Error' + logger = "ERROR" + + +class RuleUnknown(AdminRule): + description = _("The rule for that request doesn't exist.") + code = 400 + title = 'Rule Unknown' + logger = "ERROR" + + +# Consul exceptions + + +class ConsulError(MoonError): + description = _("There is an error connecting to Consul.") + code = 400 + title = 'Consul error' + logger = "ERROR" + + +class ConsulComponentNotFound(ConsulError): + description = _("The component do not exist in Consul database.") + code = 500 + title = 'Consul error' + logger = "WARNING" + + +class ConsulComponentContentError(ConsulError): + description = _("invalid content of component .") + code = 500 + title = 'Consul Content error' + logger = "WARNING" + + +# Containers exceptions + + +class DockerError(MoonError): + description = _("There is an error with Docker.") + code = 400 + title = 'Docker error' + logger = "ERROR" + + +class ContainerMissing(DockerError): + description = _("Some containers are missing.") + code = 400 + title = 'Container missing' + logger = "ERROR" + + +class WrapperConflict(MoonError): + description = _("A Wrapper already exist for the specified slave.") + code = 409 + title = 'Wrapper conflict' + logger = "ERROR" + + +class PipelineConflict(MoonError): + description = _("A Pipeline already exist for the specified slave.") + code = 409 + title = 'Pipeline conflict' + logger = "ERROR" + + +class PipelineUnknown(MoonError): + description = _("This Pipeline is unknown from the system.") + code = 400 + title = 'Pipeline Unknown' + logger = "ERROR" + + +class WrapperUnknown(MoonError): + description = _("This Wrapper is unknown from the system.") + code = 400 + title = 'Wrapper Unknown' + logger = "ERROR" + + +class SlaveNameUnknown(MoonError): + description = _("The slave is unknown.") + code = 400 + title = 'Slave Unknown' + logger = "Error" + + +class SlaveExisting(MoonError): + description = _("The slave already exists.") + code = 409 + title = 'Slave Error' + logger = "Error" + + +class PdpUnknown(MoonError): + description = _("The pdp is unknown.") + code = 400 + title = 'Pdp Unknown' + logger = "Error" + + +class PdpExisting(MoonError): + description = _("The pdp already exists.") + code = 409 + title = 'Pdp Error' + logger = "Error" + + +class PdpContentError(MoonError): + description = _("Invalid content of pdp.") + code = 400 + title = 'Pdp Error' + logger = "Error" + + +class PdpInUse(MoonError): + description = _("The pdp is inuse.") + code = 400 + title = 'Pdp Inuse' + logger = "Error" + + +class PdpKeystoneMappingConflict(MoonError): + description = _("A pdp is already mapped to that Keystone project.") + code = 409 + title = 'Pdp Mapping Error' + logger = "Error" + + +class PolicyUnknown(MoonError): + description = _("The policy is unknown.") + code = 400 + title = 'Policy Unknown' + logger = "Error" + + +class PolicyContentError(MoonError): + description = _("The policy content is invalid.") + code = 400 + title = 'Policy Content Error' + logger = "Error" + + +class PolicyExisting(MoonError): + description = _("The policy already exists.") + code = 409 + title = 'Policy Already Exists' + logger = "Error" + + +class PolicyUpdateError(MoonError): + description = _("The policy data is used.") + code = 400 + title = 'Policy update error' + logger = "Error" + + +class DeleteData(MoonError): + description = _("Cannot delete data with assignment") + code = 400 + title = 'Data Error' + logger = "Error" + + +class DeleteCategoryWithData(MoonError): + description = _("Cannot delete category with data") + code = 400 + title = 'Category With Data Error' + logger = "Error" + + +class DeleteCategoryWithMetaRule(MoonError): + description = _("Cannot delete category with meta rule") + code = 400 + title = 'Category With MetaRule Error' + logger = "Error" + + +class DeleteCategoryWithAssignment(MoonError): + description = _("Cannot delete category with assignment ") + code = 400 + title = 'Category With Assignment Error' + logger = "Error" + + +class DeleteModelWithPolicy(MoonError): + description = _("Cannot delete model with policy") + code = 400 + title = 'Model With Policy Error' + logger = "Error" + + +class DeletePolicyWithPdp(MoonError): + description = _("Cannot delete policy with pdp") + code = 400 + title = 'Policy With PDP Error' + logger = "Error" + + +class DeletePolicyWithPerimeter(MoonError): + description = _("Cannot delete policy with perimeter") + code = 400 + title = 'Policy With Perimeter Error' + logger = "Error" + + +class DeletePolicyWithData(MoonError): + description = _("Cannot delete policy with data") + code = 400 + title = 'Policy With Data Error' + logger = "Error" + + +class DeletePolicyWithRules(MoonError): + description = _("Cannot delete policy with rules") + code = 400 + title = 'Policy With Rule Error' + logger = "Error" + + +class DeleteMetaRuleWithModel(MoonError): + description = _("Cannot delete meta rule with model") + code = 400 + title = 'Meta rule With Model Error' + logger = "Error" + + +class DeleteMetaRuleWithRule(MoonError): + description = _("Cannot delete meta rule with rule") + code = 400 + title = 'Meta rule With Model Error' + logger = "Error" + + +class DataContentError(MoonError): + description = _("The data Content Error.") + code = 400 + title = 'Data Content Error' + logger = "Error" + + +class DataUnknown(MoonError): + description = _("The data unknown.") + code = 400 + title = 'Data Unknown' + logger = "Error" + + +class ValidationContentError(MoonError): + description = _("The Content validation incorrect.") + code = 400 + title = 'Invalid Content' + logger = "Error" + + def __init__(self, message=""): + self.message = message + super().__init__(message) + + def __str__(self): + return self.message + + +class ValidationKeyError(MoonError): + description = _("The Key validation incorrect.") + code = 400 + title = 'Invalid Key' + logger = "Error" + + def __init__(self, message=""): + self.message = message + super().__init__(message) + + def __str__(self): + return self.message + + +class ForbiddenOverride(MoonError): + description = _("Forbidden override flag.") + code = 500 + title = 'Forbidden override.' + logger = "Error" + + +class InvalidJson(MoonError): + description = _("Invalid Json") + code = 400 + title = 'Invalid Json.' + logger = "Error" + + +class UnknownName(MoonError): + description = _("Name is Unknown") + code = 400 + title = 'Unknown Name.' + logger = "Error" + + +class UnknownId(MoonError): + description = _("ID is Unknown") + code = 400 + title = 'Unknown ID.' + logger = "Error" + + +class MissingIdOrName(MoonError): + description = _("Name or ID is missing") + code = 400 + title = 'Missing ID or Name.' + logger = "Error" + + +class UnknownField(MoonError): + description = _("Field is Unknown") + code = 400 + title = 'Unknown Field.' + logger = "Error" + + +class DecryptError(MoonError): + description = _("Cannot decrypt API key") + code = 401 + title = 'API Key Error.' + logger = "Error" + + +class EncryptError(MoonError): + description = _("Cannot encrypt API key") + code = 401 + title = 'API Key Error.' + logger = "Error" + + +class AttributeUnknownError(MoonError): + description = _("Cannot find attribute") + code = 401 + title = 'Attribute Error.' + logger = "Error" + + +class AttributeValueUnknownError(MoonError): + description = _("Cannot find value for this attribute") + code = 401 + title = 'Attribute Value Error.' + logger = "Error" + diff --git a/moon_utilities/moon_utilities/generate_opst_policy.py b/moon_utilities/moon_utilities/generate_opst_policy.py new file mode 100644 index 00000000..4e357911 --- /dev/null +++ b/moon_utilities/moon_utilities/generate_opst_policy.py @@ -0,0 +1,503 @@ +# 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. + +""" +Generate a policy template from a list of OpenStack policy.json file +""" +import argparse +import json +import logging +import os +import re +import glob +import copy + + +FILES = [ + "cinder.policy.json", + "glance.policy.json", + "keystone.policy.json", + "neutron.policy.json", + "nova.policy.json", +] +policy_in = { + "pdps": [ + { + "name": "external_pdp", + "keystone_project_id": "", + "description": "", + "policies": [{"name": "OpenStack RBAC Policy"}] + } + ], + + "policies": [ + { + "name": "OpenStack RBAC Policy", + "genre": "authz", + "description": "A RBAC policy similar of what you can find through policy.json files", + "model": {"name": "OPST_RBAC"}, "mandatory": True, "override": True + } + ], + + "models": [ + { + "name": "OPST_RBAC", + "description": "", + "meta_rules": [{"name": "rbac"}], + "override": True + } + ], + + "subjects": [ + {"name": "admin", "description": "", "extra": {}, + "policies": [{"name": "OpenStack RBAC Policy"}]} + ], + + "subject_categories": [{"name": "role", "description": "a role in OpenStack"}], + + "subject_data": [ + {"name": "admin", "description": "the admin role", + "policies": [], "category": {"name": "role"}}, + {"name": "member", "description": "the member role", + "policies": [], "category": {"name": "role"}} + ], + + "subject_assignments": [ + {"subject": {"name": "admin"}, "category": {"name": "role"}, + "assignments": [{"name": "admin"}, {"name": "member"}]}, + ], + + "objects": [ + {"name": "all", "description": "describe all element of a project", "extra": {}, + "policies": [{"name": "OpenStack RBAC Policy"}]}, + ], + + "object_categories": [{"name": "id", "description": "the UID of each virtual machine"}], + + "object_data": [ + { + "name": "all", + "description": "represents all virtual machines in this project", + "policies": [], + "category": {"name": "id"}}, + ], + + "object_assignments": [ + {"object": {"name": "all"}, "category": {"name": "id"}, "assignments": [{"name": "all"}]} + ], + + "actions": [], + + "action_categories": [{"name": "action_id", "description": ""}], + + "action_data": [], + + "action_assignments": [], + + "meta_rules": [ + { + "name": "rbac", "description": "", + "subject_categories": [{"name": "role"}], + "object_categories": [{"name": "id"}], + "action_categories": [{"name": "action_id"}] + } + ], + + "rules": [], + +} + +policy_out = copy.deepcopy(policy_in) + +AUTO_EXCLUDE_KEYS = """ +context_is_admin +admin_or_owner +admin_api +default +owner +context_is_advsvc +admin_or_network_owner +admin_owner_or_network_owner +admin_only +regular_user +admin_or_data_plane_int +shared +shared_subnetpools +shared_address_scopes +external +admin_required +cloud_admin +service_role +service_or_admin +admin_and_matching_domain_id +service_admin_or_owner +""" + +logger = logging.getLogger(__name__) +__rules = [] + + +def init(): + """ + Initialize the application + :return: argument given in the command line + """ + global policy_in, policy_out + parser = argparse.ArgumentParser() + parser.add_argument("--verbose", '-v', action='store_true', help='verbose mode') + parser.add_argument("--debug", '-d', action='store_true', help='debug mode') + parser.add_argument("--dir", + help='directory containing policy files, defaults to ./policy.json.d', + default="./policy.json.d") + parser.add_argument("--template", "-t", + help='use a specific template file, defaults to internal template', + default="") + parser.add_argument("--indent", '-i', help='indent the output (default:None)', type=int, + default=None) + parser.add_argument("--output", '-o', help='output name, defaults to opst_default_policy.json', + type=str, default="opst_default_policy.json") + parser.add_argument("--exclude", "-x", + help="Exclude some attributes in output " + "(example: \"actions,*_categories\")", + default="") + args = parser.parse_args() + logging_format = "%(levelname)s: %(message)s" + if args.verbose: + logging.basicConfig(level=logging.INFO, format=logging_format) + if args.debug: + logging.basicConfig(level=logging.DEBUG, format=logging_format) + else: + logging.basicConfig(format=logging_format) + if args.template: + try: + policy_in = json.loads(open(args.template).read()) + policy_out = copy.deepcopy(policy_in) + logger.info("Using template {}".format(args.template)) + policy_out.pop('rules') + policy_out['rules'] = [] + for cpt, item in enumerate(policy_in['rules']): + if "templates" not in item: + policy_out['rules'].append(item) + policy_out.pop('action_assignments') + policy_out['action_assignments'] = [] + for cpt, item in enumerate(policy_in['action_assignments']): + if "templates" not in item: + policy_out['action_assignments'].append(item) + + except json.decoder.JSONDecodeError as e: + logger.error("Cannot decode template file {}".format(args.template)) + if args.debug: + logger.exception(e) + + return args + + +def get_json(filename): + """ + retrieve rule from a JSON file + :param filename: url of the file + :return: list of rules in this file + """ + _json_file = json.loads(open(filename).read()) + keys = list(_json_file.keys()) + values = list(_json_file.values()) + for value in values: + if value in keys: + keys.remove(value) + return keys + + +def get_flat(filename): + """ + retrieve rule from a flat text file + :param filename: url of the file + :return: list of rules in this file + """ + results = [] + for line in open(filename): + key = line.split('"')[1] + results.append(key) + return results + + +def get_opst_rules(args): + """ + Get all rules in each policy.json + :param args: arguments given in the command line + :return: all rules in a dict + """ + results = {} + for filename in glob.glob(os.path.join(args.dir, "**/*.json"), recursive=True): + logger.info("Reading {}".format(filename)) + component = filename.replace("policy.json", "").strip("/") + component = os.path.basename(component).split(".")[0] + try: + keys = get_json(filename) + except json.decoder.JSONDecodeError: + keys = get_flat(filename) + for _key in AUTO_EXCLUDE_KEYS.splitlines(): + if _key in keys: + keys.remove(_key) + results[component] = keys + logger.info("Adding {} definitions in {}".format(len(keys), component)) + return results + + +def get_policy_name(): + """ + Retrieve the policy name from the policy dict + Useful if the policy data comes from a template + """ + for _policy in policy_in.get("policies"): + return _policy.get("name") + + +def get_meta_rule_name(): + """ + Retrieve the policy name from the policy dict + Useful if the policy data comes from a template + """ + for _policy in policy_in.get("meta_rules"): + return _policy.get("name") + + +def get_default_data(data, category): + """ + Find the default value from a list of data, return the first one if no default found + :param data: the data to search in + :param category: the category of the data + :return: one name contained in data + """ + for _data in data: + if _data.get("category").get("name") == category: + if _data.get("extra", {}).get("action") == "default": + return _data.get("name") + # default: return the first one + for _data in data: + if _data.get("category").get("name") == category: + return _data.get("name") + + +def get_meta_rule(meta_rule_name=None): + for meta_rule in policy_in['meta_rules']: + if meta_rule_name == meta_rule.get('name'): + return meta_rule + else: + return policy_in['meta_rules'][0] + + +def build_actions(opst_rule, component): + _output = { + "name": opst_rule, + "description": "{} action for {}".format(opst_rule, component), + "extra": {"component": component}, + "policies": [] + } + policy_out['actions'].append(_output) + + +def build_action_data(opst_rule, component): + _output = { + "name": opst_rule, + "description": "{} action for {}".format(opst_rule, component), + "policies": [], + "category": {"name": "action_id"} + } + policy_out['action_data'].append(_output) + + +def build_action_assignments_with_templates(opst_rule): + for assignment in policy_in['action_assignments']: + for template in assignment.get('templates', []): + name = template.get('action', {}).get('name') + new = None + if "filter:" in name: + if "*" == name.split(":")[-1].strip(): + new = copy.deepcopy(template) + new['action']['name'] = opst_rule + else: + for _str in name.split(":")[-1].strip().split(","): + if _str.strip() in opst_rule: + new = copy.deepcopy(template) + new['action']['name'] = opst_rule + if new: + policy_out['action_assignments'].append(new) + + +def build_action_assignments(opst_rule): + _output = { + "action": {"name": opst_rule}, + "category": {"name": "action_id"}, + "assignments": [{"name": opst_rule}, ]} + policy_out['action_assignments'].append(_output) + build_action_assignments_with_templates(opst_rule) + + +def add_rule(rule): + # TODO: check rule before adding it + if rule in __rules: + # note: don't add the rule if already added + return + __rules.append(rule) + _raw_rule = { + "subject_data": [], + "object_data": [], + "action_data": [] + } + cpt = 0 + for _ in get_meta_rule().get("subject_categories"): + _raw_rule["subject_data"].append({"name": rule[cpt]}) + cpt += 1 + for _ in get_meta_rule().get("object_categories"): + _raw_rule["object_data"].append({"name": rule[cpt]}) + cpt += 1 + for _ in get_meta_rule().get("action_categories"): + _raw_rule["action_data"].append({"name": rule[cpt]}) + cpt += 1 + + _output = { + "meta_rule": {"name": get_meta_rule_name()}, + "rule": _raw_rule, + "policy": {"name": get_policy_name()}, + "instructions": [{"decision": "grant"}], + "enabled": True + } + policy_out['rules'].append(_output) + + +def check_filter_on_template(data_list, opst_rule): + for cpt, _data in enumerate(data_list): + if "filter:" in _data: + filter_str = _data.partition(":")[-1] + if filter_str == "*": + data_list[cpt] = opst_rule + add_rule(data_list) + else: + for _str in filter_str.split(","): + if _str.strip() in opst_rule: + data_list[cpt] = opst_rule + add_rule(data_list) + break + + +def build_rules_with_templates(rule, opst_rule): + meta_rule = get_meta_rule() + for template in rule.get("templates", []): + data_list = [] + for cat in meta_rule.get("subject_categories"): + for item in template.get("subject"): + if item.get("category") == cat.get('name'): + data_list.append(item.get("name")) + break + for cat in meta_rule.get("object_categories"): + for item in template.get("object"): + if item.get("category") == cat.get('name'): + data_list.append(item.get("name")) + break + for cat in meta_rule.get("action_categories"): + for item in template.get("action"): + if item.get("category") == cat.get('name'): + data_list.append(item.get("name")) + break + check_filter_on_template(data_list, opst_rule) + + +def build_rules(opst_rule): + rules = policy_in.get("rules") + for rule in rules: + if isinstance(rule, dict): + build_rules_with_templates(rule, opst_rule) + else: + add_rule(rule) + + +def build_dict(results): + """ + Build the dictionary given the actions found in the policy.json files + :param results: list of rule for each component + :return: nothing + """ + policy_out["rules"] = [] + for component in results: + for opst_rule in results[component]: + build_actions(opst_rule, component) + build_action_data(opst_rule, component) + build_action_assignments(opst_rule) + build_rules(opst_rule) + + +def exclude_attrs(args): + """ + Exclude attributes from the output JSON file + :param args: arguments given in the command line + :return: nothing + """ + attrs_to_exclude = [] + if not args.exclude: + return + for excl_item in args.exclude.split(","): + excl_item = excl_item.replace("*", ".*").strip() + logger.debug("excl_item=%s", excl_item) + for attr in policy_in: + logger.debug("attr=%s", attr) + if re.match(excl_item, attr): + attrs_to_exclude.append(attr) + for attr in attrs_to_exclude: + logger.info("Deleting %s", attr) + policy_out.pop(attr) + + +def write_tests(rules): + if "admin" not in map(lambda x: x.get("name"), policy_in.get("subjects")): + logger.warning("Don't write tests in output because, there is no 'admin' user") + return + if "all" not in map(lambda x: x.get("name"), policy_in.get("objects")): + logger.warning("Don't write tests in output because, there is no 'all' object") + return + if "checks" not in policy_in: + policy_out["checks"] = {"granted": [], "denied": []} + if "granted" not in policy_in["checks"]: + policy_out["checks"]["granted"] = [] + if "denied" not in policy_in["checks"]: + policy_out["checks"]["denied"] = [] + for component in rules: + for rule in rules.get(component): + policy_out["checks"]["granted"].append(("admin", "all", rule)) + if "test_user" in map(lambda x: x.get("name"), policy_in.get("subjects")): + for component in rules: + for rule in rules.get(component): + policy_out["checks"]["denied"].append(("test_user", "all", rule)) + + +def write_dict(args): + """ + Write the dictionary in the output filename given in command line + :param args: arguments given in the command line + :return: nothing + """ + json.dump(policy_out, open(args.output, "w"), indent=args.indent) + + +def main(): + """ + Main end point + :return: nothing + """ + args = init() + rules = get_opst_rules(args) + build_dict(rules) + write_tests(rules) + exclude_attrs(args) + write_dict(args) + + +if __name__ == "__main__": + main() diff --git a/moon_utilities/moon_utilities/install.py b/moon_utilities/moon_utilities/install.py new file mode 100644 index 00000000..236dfe06 --- /dev/null +++ b/moon_utilities/moon_utilities/install.py @@ -0,0 +1,155 @@ +# 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. + +""" +Install the Moon platform +""" + +import argparse +import logging +import os +import subprocess # nosec +import sys +import getpass + +try: + import pytest +except ModuleNotFoundError: + subprocess.call([sys.executable, "-m", "pip", "install", "pytest", "--upgrade"]) # nosec + subprocess.call([sys.executable, "-m", "pip", "install", "pytest-cov", "--upgrade"]) # nosec + subprocess.call([sys.executable, "-m", "pip", "install", "cliff", "--upgrade"]) # nosec + subprocess.call([sys.executable, "-m", "pip", "install", "requests_mock", "--upgrade"]) # nosec + import pytest +try: + from git import Repo +except ModuleNotFoundError: + subprocess.call([sys.executable, "-m", "pip", "install", "GitPython", "--upgrade"]) # nosec + from git import Repo + +COMPONENTS = { + "moon_utilities": [], + "moon_cache": [], + "moon_manager": [], + "moon_engine": [], +} + +logger = logging.getLogger(__name__) + + +def init(): + """ + Initialize the application + :return: argument given in the command line + """ + parser = argparse.ArgumentParser() + parser.add_argument("--verbose", '-v', action='store_true', help='verbose mode') + parser.add_argument("--debug", '-d', action='store_true', help='debug mode') + parser.add_argument("--pre", '-p', action='store_true', help='install packages in dev mode') + parser.add_argument("--git", '-g', action='store_true', help='install packages from source tree') + parser.add_argument("--tests", '-t', action='store_true', help='run tests on each package') + parser.add_argument("--username", '-u', help='set the username for the Gitlab server') + parser.add_argument("--password", '-pa', help='set the password for the Gitlab server') + parser.add_argument("--password-file", '-pf', + help='set the filename of the file containing all passwords for the ' + 'Gitlab server') + parser.add_argument("--do-not-clean", '-dnc', action='store_true', + help='do not clean the dev environment') + args = parser.parse_args() + logging_format = "%(levelname)s: %(message)s" + if args.verbose: + logging.basicConfig(level=logging.INFO, format=logging_format) + if args.debug: + logging.basicConfig(level=logging.DEBUG, format=logging_format) + else: + logging.basicConfig(format=logging_format) + + if args.password_file: + logger.info("Using {} as password file".format(args.password_file)) + for line in open(args.password_file): + try: + comp, user, password = line.split(":") + if comp in COMPONENTS: + COMPONENTS[comp] = [user, password.strip()] + else: + logger.error("Unknown component {} in password file".format(comp)) + except ValueError: + # empty line + pass + return args + + +def install_from_pkg(package, args): + logger.info(f"Installing from pkg {package}") + command = [sys.executable, "-m", "pip", "install", package, "--upgrade"] + if args.pre: + command.append("--pre") + subprocess.call(command) # nosec + + +def install_from_src(package, args): + logger.info(f"Installing {package} from source...") + if os.path.isdir(os.path.join("src", package)): + repo = Repo("src/" + package) + repo.remote().pull() + else: + if args.password_file: + Repo.clone_from("https://{}:{}@gitlab.forge.orange-labs.fr/moon/{}.git".format( + COMPONENTS[package][0], COMPONENTS[package][1], package), + to_path=os.path.join(os.getcwd(), "src", package)) + elif args.username: + logger.info(f"installing with {args.username}") + Repo.clone_from("https://{}:{}@gitlab.forge.orange-labs.fr/moon/{}.git".format( + args.username, args.password, package), + to_path=os.path.join(os.getcwd(), "src", package)) + else: + Repo.clone_from("https://gitlab.forge.orange-labs.fr/moon/{}.git".format(package), + to_path=os.path.join(os.getcwd(), "src", package)) + + # logger.info(f"Installing from source {package}") + cur_dir = os.getcwd() + os.chdir(os.path.join("src", package)) + command = [sys.executable, "-m", "pip", "install", "-r", "requirements.txt"] + subprocess.call(command) # nosec + command = [sys.executable, "-m", "pip", "install", "."] + subprocess.call(command) # nosec + + if args.tests: + pytest.main(["tests/unit_python"]) + + os.chdir(cur_dir) + + +def clean_git(): + subprocess.call(["rm", "-rf", "src"]) # nosec + + +def main(): + args = init() + if not args.git: + for component in COMPONENTS: + install_from_pkg(component, args) + else: + try: + try: + os.mkdir("src") + except FileExistsError: + pass + if args.username and not args.password: + args.password = getpass.getpass(f"Give the password for {args.username}Â Gitlab") + for component in COMPONENTS: + install_from_src(component, args) + finally: + if not args.do_not_clean: + clean_git() + + +if __name__ == "__main__": + main() diff --git a/moon_utilities/moon_utilities/invalided_functions.py b/moon_utilities/moon_utilities/invalided_functions.py new file mode 100644 index 00000000..1c24d3f4 --- /dev/null +++ b/moon_utilities/moon_utilities/invalided_functions.py @@ -0,0 +1,440 @@ +# 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 +import requests + +logger = logging.getLogger("moon.utilities." + __name__) + + +def invalidate_assignment_in_slaves(slaves, policy_id, perimeter_id, category_id, data_id, type): + """ + Send a request to one or more slaves to invalidate specific assignments + :param slaves: list of slaves + :param policy_id: the ID of the concerned policy + :param perimeter_id: the ID of the concerned perimeter + :param category_id: the ID of the concerned category + :param data_id: the ID of the concerned data + :return: None + """ + + hostname, port = "", "" + uri = "update/assignment" + result = [] + for key, value in slaves.get('slaves', {}).items(): + if value.get("extra", {}).get("status") != "up": + continue + try: + hostname = value.get("extra", {}).get("server_ip") + port = value.get("extra", {}).get("port") + if policy_id and perimeter_id and category_id and data_id: + update = requests.delete("http://{}:{}/{}/{}/{}/{}/{}/{}".format( + hostname, port, uri, policy_id, type, perimeter_id, category_id, data_id), + timeout=1 + ) + elif policy_id and perimeter_id and category_id: + update = requests.delete("http://{}:{}/{}/{}/{}/{}/{}".format( + hostname, port, uri, policy_id, type, perimeter_id, category_id), + timeout=1 + ) + elif policy_id and perimeter_id: + update = requests.delete("http://{}:{}/{}/{}/{}/{}".format( + hostname, port, uri, policy_id, type, perimeter_id), + timeout=1 + ) + elif policy_id: + update = requests.delete("http://{}:{}/{}/{}/{}".format( + hostname, port, uri, policy_id, type), + timeout=1 + ) + + logger.debug("result {} {}:{} = {}".format( + update.status_code, + hostname, + port, + update.text)) + result.append(value.get("name")) + except requests.exceptions.ConnectionError: + logger.warning( + "Cannot reach {}:{}".format(hostname, port)) + except requests.models.InvalidURL: + logger.warning( + "Invalid URL {}:{}".format(hostname, port)) + return result + + +def invalidate_data_in_slaves(slaves, policy_id, category_id, data_id, type): + """ + Send a request to one or more slaves to invalidate specific data + :param slaves: list of slaves + :param policy_id: the ID of the concerned policy + :param category_id: the ID of the concerned category + :param data_id: the ID of the concerned data + :return: None + """ + + hostname, port = "", "" + uri = "update/data" + result = [] + for key, value in slaves.get('slaves', {}).items(): + if value.get("extra", {}).get("status") != "up": + continue + try: + hostname = value.get("extra", {}).get("server_ip") + port = value.get("extra", {}).get("port") + update = requests.delete("http://{}:{}/{}/{}/{}".format( + hostname, port, uri, data_id, type), + timeout=1 + ) + logger.debug("result {} {}:{} = {}".format( + update.status_code, + hostname, + port, + update.text)) + result.append(value.get("name")) + except requests.exceptions.ConnectionError: + logger.warning( + "Cannot reach {}:{}".format(hostname, port)) + except requests.models.InvalidURL: + logger.warning( + "Invalid URL {}:{}".format(hostname, port)) + return result + + +def invalidate_perimeter_in_slaves(slaves, policy_id, perimeter_id, type, data=None, + is_delete=True): + """ + Send a request to one or more slaves to invalidate specific perimeter + :param slaves: list of slaves + :param policy_id: the ID of the concerned policy + :param perimeter_id: the ID of the concerned perimeter + :return: None + """ + + hostname, port = "", "" + uri = "update/perimeter" + result = [] + for key, value in slaves.get('slaves', {}).items(): + if value.get("extra", {}).get("status") != "up": + continue + try: + hostname = value.get("extra", {}).get("server_ip") + port = value.get("extra", {}).get("port") + if is_delete: + update = requests.delete("http://{}:{}/{}/{}/{}/{}".format( + hostname, port, uri, perimeter_id, policy_id, type), + timeout=1 + ) + else: + update = requests.put("http://{}:{}/{}/{}/{}/{}".format( + hostname, port, uri, perimeter_id, policy_id, type), + data=data, + timeout=1 + ) + logger.debug("result {} {}:{} = {}".format( + update.status_code, + hostname, + port, + update.text)) + result.append(value.get("name")) + except requests.exceptions.ConnectionError: + logger.warning( + "Cannot reach {}:{}".format(hostname, port)) + except requests.models.InvalidURL: + logger.warning( + "Invalid URL {}:{}".format(hostname, port)) + return result + + +def invalidate_pdp_in_slaves(slaves, pdp_id, is_delete=True, data=None): + """ + Send a request to one or more slaves to invalidate specific PDPs + :param slaves: list of slaves + :param pdp_id: the ID of the concerned PDP + :return: None + """ + + hostname, port = "", "" + uri = "update/pdp" + result = [] + for key, value in slaves.get('slaves', {}).items(): + if value.get("extra", {}).get("status") != "up": + continue + try: + hostname = value.get("extra", {}).get("server_ip") + port = value.get("extra", {}).get("port") + if is_delete: + update = requests.delete("http://{}:{}/{}/{}".format( + hostname, port, uri, pdp_id), + timeout=1 + ) + else: + update = requests.put("http://{}:{}/{}/{}".format( + hostname, port, uri, pdp_id), + data=data, + timeout=1 + ) + logger.debug("result {} {}:{} = {}".format( + update.status_code, + hostname, + port, + update.text)) + result.append(value.get("name")) + except requests.exceptions.ConnectionError: + logger.warning( + "Cannot reach {}:{}".format(hostname, port)) + except requests.models.InvalidURL: + logger.warning( + "Invalid URL {}:{}".format(hostname, port)) + return result + + +def invalidate_policy_in_slaves(slaves, policy_id, is_delete=True, data=None): + """ + Send a request to one or more slaves to invalidate specific policies + :param slaves: list of slaves + :param policy_id: the ID of the concerned policy + :return: None + """ + + hostname, port = "", "" + uri = "update/policy" + result = [] + for key, value in slaves.get('slaves', {}).items(): + if value.get("extra", {}).get("status") != "up": + continue + try: + hostname = value.get("extra", {}).get("server_ip") + port = value.get("extra", {}).get("port") + if is_delete: + update = requests.delete("http://{}:{}/{}/{}".format( + hostname, port, uri, policy_id), + timeout=1 + ) + else: + update = requests.put("http://{}:{}/{}/{}".format( + hostname, port, uri, policy_id), + data=data, + timeout=1 + ) + + logger.debug("result {} {}:{} = {}".format( + update.status_code, + hostname, + port, + update.text)) + result.append(value.get("name")) + except requests.exceptions.ConnectionError: + logger.warning( + "Cannot reach {}:{}".format(hostname, port)) + except requests.models.InvalidURL: + logger.warning( + "Invalid URL {}:{}".format(hostname, port)) + return result + + +def invalidate_rules_in_slaves(slaves, policy_id, rule_id): + """ + Send a request to one or more slaves to invalidate specific rules + :param slaves: list of slaves + :param policy_id: the ID of the concerned policy + :param rule_id: the ID of the concerned rule + :return: None + """ + + hostname, port = "", "" + uri = "update/rule" + result = [] + for key, value in slaves.get('slaves', {}).items(): + if value.get("extra", {}).get("status") != "up": + continue + try: + hostname = value.get("extra", {}).get("server_ip") + port = value.get("extra", {}).get("port") + update = requests.delete("http://{}:{}/{}/{}/{}".format( + hostname, port, uri, policy_id, rule_id), + timeout=1 + ) + logger.debug("result {} {}:{} = {}".format( + update.status_code, + hostname, + port, + update.text)) + result.append(value.get("name")) + except requests.exceptions.ConnectionError: + logger.warning( + "Cannot reach {}:{}".format(hostname, port)) + except requests.models.InvalidURL: + logger.warning( + "Invalid URL {}:{}".format(hostname, port)) + return result + + +def invalidate_model_in_slaves(slaves, model_id, is_delete=True, data=None): + """ + Send a request to one or more slaves to invalidate specific models + :param slaves: list of slaves + :param model_id: the ID of the concerned model + :return: None + """ + + hostname, port = "", "" + uri = "update/model" + result = [] + for key, value in slaves.get('slaves', {}).items(): + if value.get("extra", {}).get("status") != "up": + continue + try: + hostname = value.get("extra", {}).get("server_ip") + port = value.get("extra", {}).get("port") + if is_delete: + update = requests.delete("http://{}:{}/{}/{}".format( + hostname, port, uri, model_id), + timeout=1 + ) + else: + update = requests.put("http://{}:{}/{}/{}".format( + hostname, port, uri, model_id), + data=data, + timeout=1 + ) + logger.debug("result {} {}:{} = {}".format( + update.status_code, + hostname, + port, + update.text)) + result.append(value.get("name")) + except requests.exceptions.ConnectionError: + logger.warning( + "Cannot reach {}:{}".format(hostname, port)) + except requests.models.InvalidURL: + logger.warning( + "Invalid URL {}:{}".format(hostname, port)) + return result + + +def invalidate_meta_data_in_slaves(slaves, category_id, type): + """ + Send a request to one or more slaves to invalidate specific meta data + :param slaves: list of slaves + :param category_id: the ID of the concerned category + :return: None + """ + + hostname, port = "", "" + uri = "update/meta_data" + result = [] + for key, value in slaves.get('slaves', {}).items(): + if value.get("extra", {}).get("status") != "up": + continue + try: + hostname = value.get("extra", {}).get("server_ip") + port = value.get("extra", {}).get("port") + update = requests.delete("http://{}:{}/{}/{}/{}".format( + hostname, port, uri, category_id, type), + data={ + "category_id": category_id + }, + timeout=1 + ) + logger.debug("result {} {}:{} = {}".format( + update.status_code, + hostname, + port, + update.text)) + result.append(value.get("name")) + except requests.exceptions.ConnectionError: + logger.warning( + "Cannot reach {}:{}".format(hostname, port)) + except requests.models.InvalidURL: + logger.warning( + "Invalid URL {}:{}".format(hostname, port)) + return result + + +def invalidate_meta_rule_in_slaves(slaves, meta_rule_id, is_delete=True, data=None): + """ + Send a request to one or more slaves to invalidate specific meta rules + :param slaves: list of slaves + :param meta_rule_id: the ID of the concerned policy + :return: None + """ + + hostname, port = "", "" + uri = "update/meta_rule" + result = [] + for key, value in slaves.get('slaves', {}).items(): + if value.get("extra", {}).get("status") != "up": + continue + try: + hostname = value.get("extra", {}).get("server_ip") + port = value.get("extra", {}).get("port") + if is_delete: + update = requests.delete("http://{}:{}/{}/{}".format( + hostname, port, uri, meta_rule_id), + timeout=1 + ) + else: + update = requests.put("http://{}:{}/{}/{}".format( + hostname, port, uri, meta_rule_id), + data=data, + timeout=1 + ) + + logger.debug("result {} {}:{} = {}".format( + update.status_code, + hostname, + port, + update.text)) + result.append(value.get("name")) + except requests.exceptions.ConnectionError: + logger.warning( + "Cannot reach {}:{}".format(hostname, port)) + except requests.models.InvalidURL: + logger.warning( + "Invalid URL {}:{}".format(hostname, port)) + + +def invalidate_attributes_in_slaves(slaves, name, value=None): + """ + Send a request to one or more slaves to invalidate specific data + :param slaves: list of slaves + :param name: the name of the attribute to invalidate + :param value: the value that has changed + :return: a list of updated slaves + """ + + hostname, port = "", "" + uri = "update/attributes" + result = [] + for key, value in slaves.items(): + try: + hostname = value.get("extra", {}).get("server_ip") + port = value.get("extra", {}).get("port") + update = requests.delete("http://{}:{}/{}/{}".format( + hostname, port, uri, name), + headers={"x-api-key": value.get("extra", {}).get("api_key")}, + timeout=1 + ) + if update.status_code in (200, 202, 206, 208): + result.append(value.get("name")) + else: + logger.warning("Error when updating {} ({})".format(key, update.status_code)) + except requests.exceptions.ConnectionError: + logger.warning( + "Cannot reach {}:{}".format(hostname, port)) + except requests.models.InvalidURL: + logger.warning( + "Invalid URL {}:{}".format(hostname, port)) + return result + + diff --git a/moon_utilities/moon_utilities/json_utils.py b/moon_utilities/moon_utilities/json_utils.py new file mode 100644 index 00000000..52ab5be4 --- /dev/null +++ b/moon_utilities/moon_utilities/json_utils.py @@ -0,0 +1,2076 @@ +# 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 html +import json +import logging + +from moon_utilities import exceptions + +LOGGER = logging.getLogger("moon.utilities." + __name__) + + +class Manager: + __policy_manager = None + __model_manager = None + __pdp_manager = None + + def get_meta_rules(self, **kwargs): + raise NotImplementedError # pragma: no cover + + def set_subject_data(self, **kwargs): + raise NotImplementedError # pragma: no cover + + def set_object_data(self, **kwargs): + raise NotImplementedError # pragma: no cover + + def set_action_data(self, **kwargs): + raise NotImplementedError # pragma: no cover + + def get_subject_data(self, **kwargs): + raise NotImplementedError # pragma: no cover + + def get_object_data(self, **kwargs): + raise NotImplementedError # pragma: no cover + + def get_action_data(self, **kwargs): + raise NotImplementedError # pragma: no cover + + def add_rule(self, **kwargs): + raise NotImplementedError # pragma: no cover + + def add_meta_rule(self, **kwargs): + raise NotImplementedError # pragma: no cover + + def add_subject_assignment(self, **kwargs): + raise NotImplementedError # pragma: no cover + + def add_object_assignment(self, **kwargs): + raise NotImplementedError # pragma: no cover + + def add_action_assignment(self, **kwargs): + raise NotImplementedError # pragma: no cover + + def get_subject_assignments(self, **kwargs): + raise NotImplementedError # pragma: no cover + + def get_object_assignments(self, **kwargs): + raise NotImplementedError # pragma: no cover + + def get_action_assignments(self, **kwargs): + raise NotImplementedError # pragma: no cover + + def get_policies(self, **kwargs): + raise NotImplementedError # pragma: no cover + + def add_subject_category(self, **kwargs): + raise NotImplementedError # pragma: no cover + + def add_object_category(self, **kwargs): + raise NotImplementedError # pragma: no cover + + def add_action_category(self, **kwargs): + raise NotImplementedError # pragma: no cover + + def get_subject_categories(self, **kwargs): + raise NotImplementedError # pragma: no cover + + def get_object_categories(self, **kwargs): + raise NotImplementedError # pragma: no cover + + def get_action_categories(self, **kwargs): + raise NotImplementedError # pragma: no cover + + def add_subject(self, **kwargs): + raise NotImplementedError # pragma: no cover + + def add_object(self, **kwargs): + raise NotImplementedError # pragma: no cover + + def add_action(self, **kwargs): + raise NotImplementedError # pragma: no cover + + def get_subjects(self, **kwargs): + raise NotImplementedError # pragma: no cover + + def get_objects(self, **kwargs): + raise NotImplementedError # pragma: no cover + + def get_actions(self, **kwargs): + raise NotImplementedError # pragma: no cover + + def add_policy(self, **kwargs): + raise NotImplementedError # pragma: no cover + + def update_policy(self, **kwargs): + raise NotImplementedError # pragma: no cover + + def get_models(self, **kwargs): + raise NotImplementedError # pragma: no cover + + def update_model(self, **kwargs): + raise NotImplementedError # pragma: no cover + + def add_model(self, **kwargs): + raise NotImplementedError # pragma: no cover + + def get_pdp(self, **kwargs): + raise NotImplementedError # pragma: no cover + + def update_pdp(self, **kwargs): + raise NotImplementedError # pragma: no cover + + def add_pdp(self, **kwargs): + raise NotImplementedError # pragma: no cover + + def get_rules(self, **kwargs): + raise NotImplementedError # pragma: no cover + + +class CacheManager(Manager): + __policy_manager = None + __model_manager = None + __pdp_manager = None + + def __init__(self, cache): + self.__cache = cache + + def get_meta_rules(self, **kwargs): + return self.__cache.meta_rules + + def set_subject_data(self, **kwargs): + value = kwargs.get("value", {}) + value["category_id"] = kwargs.get("category_id", "") + value["policy_id"] = kwargs.get("policy_id", "") + return self.__cache.add_subject_data( + policy_id=kwargs.get("policy_id", ""), + category_id=kwargs.get("category_id", ""), + data=value + ) + + def set_object_data(self, **kwargs): + value = kwargs.get("value", {}) + value["category_id"] = kwargs.get("category_id", "") + value["policy_id"] = kwargs.get("policy_id", "") + return self.__cache.add_object_data( + policy_id=kwargs.get("policy_id", ""), + category_id=kwargs.get("category_id", ""), + data=value + ) + + def set_action_data(self, **kwargs): + value = kwargs.get("value", {}) + value["category_id"] = kwargs.get("category_id", "") + value["policy_id"] = kwargs.get("policy_id", "") + return self.__cache.add_action_data( + policy_id=kwargs.get("policy_id", ""), + category_id=kwargs.get("category_id", ""), + data=value + ) + + def get_subject_data(self, **kwargs): + if "policy_id" in kwargs: + results = [] + for data in self.__cache.subject_data: + if data.get("policy_id") == kwargs["policy_id"]: + if data.get("category_id") == kwargs.get("category_id"): + results.append(data) + elif not kwargs.get("category_id"): + results.append(data) + if "data_id" in kwargs: + for res in results: + if kwargs.get("data_id") in res.get("data"): + return [res, ] + else: + return results + else: + return self.__cache.subject_data + + def get_object_data(self, **kwargs): + if "policy_id" in kwargs: + results = [] + for data in self.__cache.object_data: + if data.get("policy_id") == kwargs["policy_id"]: + if data.get("category_id") == kwargs.get("category_id"): + results.append(data) + elif not kwargs.get("category_id"): + results.append(data) + return results + else: + return self.__cache.object_data + + def get_action_data(self, **kwargs): + if "policy_id" in kwargs: + results = [] + for data in self.__cache.action_data: + if data.get("policy_id") == kwargs["policy_id"]: + if data.get("category_id") == kwargs.get("category_id"): + results.append(data) + elif not kwargs.get("category_id"): + results.append(data) + return results + else: + return self.__cache.action_data + + def add_rule(self, **kwargs): + value = { + 'policy_id': kwargs.get('policy_id'), + 'meta_rule_id': kwargs.get('meta_rule_id'), + 'value': kwargs.get('value') + } + return self.__cache.add_rule(value) + + def add_meta_rule(self, **kwargs): + return self.__cache.add_meta_rule(kwargs.get("value")) + + def add_subject_assignment(self, **kwargs): + return self.__cache.add_subject_assignment( + policy_id=kwargs.get("policy_id"), + perimeter_id=kwargs.get("subject_id"), + category_id=kwargs.get("category_id"), + data_id=kwargs.get("data_id"), + ) + + def add_object_assignment(self, **kwargs): + return self.__cache.add_object_assignment( + policy_id=kwargs.get("policy_id"), + perimeter_id=kwargs.get("object_id"), + category_id=kwargs.get("category_id"), + data_id=kwargs.get("data_id"), + ) + + def add_action_assignment(self, **kwargs): + return self.__cache.add_action_assignment( + policy_id=kwargs.get("policy_id"), + perimeter_id=kwargs.get("action_id"), + category_id=kwargs.get("category_id"), + data_id=kwargs.get("data_id"), + ) + + def get_subject_assignments(self, **kwargs): + return self.__cache.subject_assignments + + def get_object_assignments(self, **kwargs): + return self.__cache.object_assignments + + def get_action_assignments(self, **kwargs): + return self.__cache.action_assignments + + def get_policies(self, **kwargs): + return self.__cache.policies + + def add_subject_category(self, **kwargs): + if kwargs.get("value", {}).get("name") != html.escape(kwargs.get("value", {}).get("name")): + raise exceptions.ValidationContentError('Forbidden characters in string') + if kwargs.get("category_id"): + if kwargs.get("category_id") in self.__cache.subject_categories: + raise exceptions.SubjectCategoryExisting + self.__cache.add_subject_category(kwargs.get("value")) + + def add_object_category(self, **kwargs): + if kwargs.get("value", {}).get("name") != html.escape(kwargs.get("value", {}).get("name")): + raise exceptions.ValidationContentError('Forbidden characters in string') + if kwargs.get("category_id"): + if kwargs.get("category_id") in self.__cache.object_categories: + raise exceptions.ObjectCategoryExisting + self.__cache.add_object_category(kwargs.get("value")) + + def add_action_category(self, **kwargs): + if kwargs.get("value", {}).get("name") != html.escape(kwargs.get("value", {}).get("name")): + raise exceptions.ValidationContentError('Forbidden characters in string') + if kwargs.get("category_id"): + if kwargs.get("category_id") in self.__cache.action_categories: + raise exceptions.ActionCategoryExisting + self.__cache.add_action_category(kwargs.get("value")) + + def get_subject_categories(self, **kwargs): + return self.__cache.subject_categories + + def get_object_categories(self, **kwargs): + return self.__cache.object_categories + + def get_action_categories(self, **kwargs): + return self.__cache.action_categories + + def add_subject(self, **kwargs): + if kwargs.get("value", {}).get("name") != html.escape(kwargs.get("value", {}).get("name")): + raise exceptions.ValidationContentError('Forbidden characters in string') + value = kwargs.get("value") + if kwargs.get("policy_id"): + value["policy_list"] = [kwargs.get("policy_id")] + if kwargs.get("perimeter_id"): + return self.__cache.update_subject(kwargs.get("perimeter_id"), value) + else: + return self.__cache.add_subject(value) + + def add_object(self, **kwargs): + if kwargs.get("value", {}).get("name") != html.escape(kwargs.get("value", {}).get("name")): + raise exceptions.ValidationContentError('Forbidden characters in string') + value = kwargs.get("value") + if kwargs.get("policy_id"): + value["policy_list"] = [kwargs.get("policy_id")] + if kwargs.get("perimeter_id"): + return self.__cache.update_object(kwargs.get("perimeter_id"), value) + else: + return self.__cache.add_object(value) + + def add_action(self, **kwargs): + if kwargs.get("value", {}).get("name") != html.escape(kwargs.get("value", {}).get("name")): + raise exceptions.ValidationContentError('Forbidden characters in string') + value = kwargs.get("value") + if kwargs.get("policy_id"): + value["policy_list"] = [kwargs.get("policy_id")] + if kwargs.get("perimeter_id"): + return self.__cache.update_action(kwargs.get("perimeter_id"), value) + else: + return self.__cache.add_action(value) + + def get_subjects(self, **kwargs): + results = {} + subjects = self.__cache.subjects + for policy_id in subjects: + results.update(subjects[policy_id]) + return results + + def get_objects(self, **kwargs): + results = {} + objects = self.__cache.objects + for policy_id in objects: + results.update(objects[policy_id]) + return results + + def get_actions(self, **kwargs): + results = {} + actions = self.__cache.actions + for policy_id in actions: + results.update(actions[policy_id]) + return results + + def add_policy(self, **kwargs): + return self.__cache.add_policy(kwargs.get("value")) + + def update_policy(self, **kwargs): + self.__cache.update_policy(kwargs.get("policy_id"), kwargs.get("value")) + + def get_models(self, **kwargs): + return self.__cache.models + + def update_model(self, **kwargs): + self.__cache.update_model(kwargs.get("model_id"), kwargs.get("value")) + + def add_model(self, **kwargs): + if kwargs.get("value", {}).get("name") != html.escape(kwargs.get("value", {}).get("name")): + raise exceptions.ValidationContentError('Forbidden characters in string') + self.__cache.add_model(kwargs.get("value")) + + def get_pdp(self, **kwargs): + return self.__cache.pdp + + def update_pdp(self, **kwargs): + self.__cache.add_pdp(pdp_id=kwargs.get("pdp_id"), data=kwargs.get("value")) + + def add_pdp(self, **kwargs): + self.__cache.add_pdp(data=kwargs.get("value")) + + def get_rules(self, **kwargs): + return self.__cache.rules + + +class DBManager(Manager): + __policy_manager = None + __model_manager = None + __pdp_manager = None + + def __init__(self, driver): # pragma: no cover + self.__policy_manager = driver.PolicyManager + self.__model_manager = driver.ModelManager + self.__pdp_manager = driver.PDPManager + + @property + def meta_rules(self): + return self.get_meta_rules() + + def get_meta_rules(self, **kwargs): + return self.__model_manager.get_meta_rules( + moon_user_id=kwargs.get("moon_user_id"), + meta_rule_id=kwargs.get("meta_rule_id") + ) + + def set_subject_data(self, **kwargs): + value = self.__policy_manager.set_subject_data( + moon_user_id=kwargs.get("moon_user_id"), + policy_id=kwargs.get("policy_id"), + category_id=kwargs.get("category_id"), + value=kwargs.get("value") + ) + return value + + def set_object_data(self, **kwargs): + return self.__policy_manager.add_object_data( + moon_user_id=kwargs.get("moon_user_id"), + policy_id=kwargs.get("policy_id"), + category_id=kwargs.get("category_id"), + value=kwargs.get("value") + ) + + def set_action_data(self, **kwargs): + return self.__policy_manager.add_action_data( + moon_user_id=kwargs.get("moon_user_id"), + policy_id=kwargs.get("policy_id"), + category_id=kwargs.get("category_id"), + value=kwargs.get("value") + ) + + @property + def subject_data(self): + _data = [] + for policy in self.__policy_manager.get_policies(moon_user_id="admin"): + for category in self.__model_manager.get_subject_categories(moon_user_id="admin"): + _data += self.__policy_manager.get_subject_data(moon_user_id="admin", + policy_id=policy, + category_id=category) + return _data + + def get_subject_data(self, **kwargs): + return self.__policy_manager.get_subject_data( + moon_user_id=kwargs.get("moon_user_id"), + policy_id=kwargs.get("policy_id"), + data_id=kwargs.get("data_id"), + category_id=kwargs.get("category_id") + ) + + @property + def object_data(self): + _data = [] + for policy in self.__policy_manager.get_policies(moon_user_id="admin"): + _data += self.__policy_manager.get_object_data(moon_user_id="admin", + policy_id=policy) + return _data + + def get_object_data(self, **kwargs): + return self.__policy_manager.get_object_data( + moon_user_id=kwargs.get("moon_user_id"), + policy_id=kwargs.get("policy_id"), + data_id=kwargs.get("data_id"), + category_id=kwargs.get("category_id") + ) + + @property + def action_data(self): + _data = [] + for policy in self.__policy_manager.get_policies(moon_user_id="admin"): + _data += self.__policy_manager.get_action_data(moon_user_id="admin", + policy_id=policy) + return _data + + def get_action_data(self, **kwargs): + return self.__policy_manager.get_action_data( + moon_user_id=kwargs.get("moon_user_id"), + policy_id=kwargs.get("policy_id"), + data_id=kwargs.get("data_id"), + category_id=kwargs.get("category_id") + ) + + def add_rule(self, **kwargs): + return self.__policy_manager.add_rule( + moon_user_id=kwargs.get("moon_user_id"), + policy_id=kwargs.get("policy_id"), + meta_rule_id=kwargs.get("meta_rule_id"), + value=kwargs.get("value") + ) + + def add_meta_rule(self, **kwargs): + return self.__model_manager.add_meta_rule( + moon_user_id=kwargs.get("moon_user_id"), + meta_rule_id=kwargs.get("meta_rule_id"), + value=kwargs.get("value") + ) + + @property + def subject_assignments(self): + _assignments = {} + for policy in self.__policy_manager.get_policies(moon_user_id="admin"): + _assignments.update(self.__policy_manager.get_subject_assignments( + moon_user_id="admin", + policy_id=policy)) + return _assignments + + def add_subject_assignment(self, **kwargs): + return self.__policy_manager.add_subject_assignment( + moon_user_id=kwargs.get("moon_user_id"), + policy_id=kwargs.get("policy_id"), + subject_id=kwargs.get("subject_id"), + category_id=kwargs.get("category_id"), + data_id=kwargs.get("data_id") + ) + + @property + def object_assignments(self): + _assignments = {} + for policy in self.__policy_manager.get_policies(moon_user_id="admin"): + _assignments.update(self.__policy_manager.get_object_assignments( + moon_user_id="admin", + policy_id=policy)) + return _assignments + + def add_object_assignment(self, **kwargs): + return self.__policy_manager.add_object_assignment( + moon_user_id=kwargs.get("moon_user_id"), + policy_id=kwargs.get("policy_id"), + object_id=kwargs.get("object_id"), + category_id=kwargs.get("category_id"), + data_id=kwargs.get("data_id") + ) + + @property + def action_assignments(self): + _assignments = {} + for policy in self.__policy_manager.get_policies(moon_user_id="admin"): + _assignments.update(self.__policy_manager.get_action_assignments( + moon_user_id="admin", + policy_id=policy)) + return _assignments + + def add_action_assignment(self, **kwargs): + return self.__policy_manager.add_action_assignment( + moon_user_id=kwargs.get("moon_user_id"), + policy_id=kwargs.get("policy_id"), + action_id=kwargs.get("action_id"), + category_id=kwargs.get("category_id"), + data_id=kwargs.get("data_id") + ) + + def get_subject_assignments(self, **kwargs): + return self.__policy_manager.get_subject_assignments( + moon_user_id=kwargs.get("moon_user_id"), + policy_id=kwargs.get("policy_id"), + category_id=kwargs.get("category_id") + ) + + def get_object_assignments(self, **kwargs): + return self.__policy_manager.get_object_assignments( + moon_user_id=kwargs.get("moon_user_id"), + policy_id=kwargs.get("policy_id"), + category_id=kwargs.get("category_id") + ) + + def get_action_assignments(self, **kwargs): + return self.__policy_manager.get_action_assignments( + moon_user_id=kwargs.get("moon_user_id"), + policy_id=kwargs.get("policy_id"), + category_id=kwargs.get("category_id") + ) + + def get_policies(self, **kwargs): + return self.__policy_manager.get_policies(moon_user_id=kwargs.get("moon_user_id")) + + @property + def subject_categories(self): + return self.__model_manager.get_subject_categories(moon_user_id="admin") + + def add_subject_category(self, **kwargs): + return self.__model_manager.add_subject_category( + moon_user_id=kwargs.get("moon_user_id"), + category_id=kwargs.get("category_id"), + value=kwargs.get("value") + ) + + @property + def object_categories(self): + return self.__model_manager.get_object_categories(moon_user_id="admin") + + def add_object_category(self, **kwargs): + return self.__model_manager.add_object_category( + moon_user_id=kwargs.get("moon_user_id"), + category_id=kwargs.get("category_id"), + value=kwargs.get("value") + ) + + @property + def action_categories(self): + return self.__model_manager.get_action_categories(moon_user_id="admin") + + def add_action_category(self, **kwargs): + return self.__model_manager.add_action_category( + moon_user_id=kwargs.get("moon_user_id"), + category_id=kwargs.get("category_id"), + value=kwargs.get("value") + ) + + def get_subject_categories(self, **kwargs): + return self.__model_manager.get_subject_categories( + moon_user_id=kwargs.get("moon_user_id") + ) + + def get_object_categories(self, **kwargs): + return self.__model_manager.get_object_categories( + moon_user_id=kwargs.get("moon_user_id") + ) + + def get_action_categories(self, **kwargs): + return self.__model_manager.get_action_categories( + moon_user_id=kwargs.get("moon_user_id") + ) + + @property + def subjects(self): + _perimeter = {} + for policy in self.__policy_manager.get_policies(moon_user_id="admin"): + _perimeter.update(self.__policy_manager.get_subjects(moon_user_id="admin", + policy_id=policy)) + return _perimeter + + def add_subject(self, **kwargs): + if kwargs.get("perimeter_id"): + return self.__policy_manager.update_subject( + moon_user_id=kwargs.get("moon_user_id"), + perimeter_id=kwargs.get("perimeter_id"), + value=kwargs.get("value") + ) + else: + return self.__policy_manager.add_subject( + moon_user_id=kwargs.get("moon_user_id"), + policy_id=kwargs.get("policy_id"), + value=kwargs.get("value") + ) + + @property + def objects(self): + _perimeter = {} + for policy in self.__policy_manager.get_policies(moon_user_id="admin"): + _perimeter.update(self.__policy_manager.get_objects(moon_user_id="admin", + policy_id=policy)) + return _perimeter + + def add_object(self, **kwargs): + if kwargs.get("perimeter_id"): + return self.__policy_manager.update_object( + moon_user_id=kwargs.get("moon_user_id"), + perimeter_id=kwargs.get("perimeter_id"), + value=kwargs.get("value") + ) + else: + return self.__policy_manager.add_object( + moon_user_id=kwargs.get("moon_user_id"), + policy_id=kwargs.get("policy_id"), + value=kwargs.get("value") + ) + + @property + def actions(self): + _perimeter = {} + for policy in self.__policy_manager.get_policies(moon_user_id="admin"): + _perimeter.update(self.__policy_manager.get_actions(moon_user_id="admin", + policy_id=policy)) + return _perimeter + + def add_action(self, **kwargs): + if kwargs.get("perimeter_id"): + return self.__policy_manager.update_action( + moon_user_id=kwargs.get("moon_user_id"), + perimeter_id=kwargs.get("perimeter_id"), + value=kwargs.get("value") + ) + else: + return self.__policy_manager.add_action( + moon_user_id=kwargs.get("moon_user_id"), + policy_id=kwargs.get("policy_id"), + value=kwargs.get("value") + ) + + def get_subjects(self, **kwargs): + return self.__policy_manager.get_subjects( + moon_user_id=kwargs.get("moon_user_id"), + policy_id=kwargs.get("policy_id") + ) + + def get_objects(self, **kwargs): + return self.__policy_manager.get_objects( + moon_user_id=kwargs.get("moon_user_id"), + policy_id=kwargs.get("policy_id") + ) + + def get_actions(self, **kwargs): + return self.__policy_manager.get_actions( + moon_user_id=kwargs.get("moon_user_id"), + policy_id=kwargs.get("policy_id") + ) + + @property + def policies(self): + return self.__policy_manager.get_policies(moon_user_id="admin") + + def add_policy(self, **kwargs): + return self.__policy_manager.add_policy( + moon_user_id=kwargs.get("moon_user_id"), + value=kwargs.get("value") + ) + + def update_policy(self, **kwargs): + return self.__policy_manager.update_policy( + moon_user_id=kwargs.get("moon_user_id"), + policy_id=kwargs.get("policy_id"), + value=kwargs.get("value")) + + @property + def models(self): + return self.get_models() + + def get_models(self, **kwargs): + return self.__model_manager.get_models(moon_user_id=kwargs.get("moon_user_id")) + + def update_model(self, **kwargs): + return self.__model_manager.update_model( + moon_user_id=kwargs.get("moon_user_id"), + model_id=kwargs.get("model_id"), + value=kwargs.get("value") + ) + + def add_model(self, **kwargs): + return self.__model_manager.add_model( + moon_user_id=kwargs.get("moon_user_id"), + value=kwargs.get("value") + ) + + @property + def pdp(self): + return self.get_pdp() + + def get_pdp(self, **kwargs): + return self.__pdp_manager.get_pdp(moon_user_id=kwargs.get("moon_user_id")) + + def update_pdp(self, **kwargs): + return self.__pdp_manager.update_pdp( + moon_user_id=kwargs.get("moon_user_id"), + pdp_id=kwargs.get("pdp_id"), + value=kwargs.get("value") + ) + + def add_pdp(self, **kwargs): + return self.__pdp_manager.add_pdp( + moon_user_id=kwargs.get("moon_user_id"), + value=kwargs.get("value") + ) + + @property + def rules(self): + _rules = [] + for policy in self.__policy_manager.get_policies(moon_user_id="admin"): + _rules.append(self.__policy_manager.get_rules(moon_user_id="admin", + policy_id=policy)) + return _rules + + def get_rules(self, **kwargs): + return self.__policy_manager.get_rules( + moon_user_id=kwargs.get("moon_user_id"), + policy_id=kwargs.get("policy_id") + ) + + +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(moon_user_id=user_id, model_id=element_id) + elif element_type == "policy": + data_db = manager.get_policies(moon_user_id=user_id, policy_id=element_id) + elif element_type == "subject": + data_db = manager.get_subjects(moon_user_id=user_id, policy_id=policy_id, perimeter_id=element_id) + elif element_type == "object": + data_db = manager.get_objects(moon_user_id=user_id, policy_id=policy_id, perimeter_id=element_id) + elif element_type == "action": + data_db = manager.get_actions(moon_user_id=user_id, policy_id=policy_id, perimeter_id=element_id) + elif element_type == "subject_category": + data_db = manager.get_subject_categories(moon_user_id=user_id, category_id=element_id) + elif element_type == "object_category": + data_db = manager.get_object_categories(moon_user_id=user_id, category_id=element_id) + elif element_type == "action_category": + data_db = manager.get_action_categories(moon_user_id=user_id, category_id=element_id) + elif element_type == "meta_rule": + data_db = manager.get_meta_rules(moon_user_id=user_id, meta_rule_id=element_id) + elif element_type == "subject_data": + data_db = manager.get_subject_data(moon_user_id=user_id, policy_id=policy_id, data_id=element_id, + category_id=category_id) + elif element_type == "object_data": + data_db = manager.get_object_data(moon_user_id=user_id, policy_id=policy_id, data_id=element_id, + category_id=category_id) + elif element_type == "action_data": + data_db = manager.get_action_data(moon_user_id=user_id, policy_id=policy_id, + data_id=element_id, + category_id=category_id) + elif element_type == "meta_rule": + data_db = manager.get_meta_rules(moon_user_id=user_id, meta_rule_id=meta_rule_id) + else: + raise Exception("Conversion of {} not implemented yet!".format(element_type)) + + # 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] + 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(moon_user_id=user_id) + elif element_type == "policy": + data_db = manager.get_policies(moon_user_id=user_id) + elif element_type == "subject": + data_db = manager.get_subjects(moon_user_id=user_id, policy_id=policy_id) + elif element_type == "object": + data_db = manager.get_objects(moon_user_id=user_id, policy_id=policy_id) + elif element_type == "action": + data_db = manager.get_actions(moon_user_id=user_id,policy_id= policy_id) + elif element_type == "subject_category": + data_db = manager.get_subject_categories(moon_user_id=user_id) + elif element_type == "object_category": + data_db = manager.get_object_categories(moon_user_id=user_id) + elif element_type == "action_category": + data_db = manager.get_action_categories(moon_user_id=user_id) + elif element_type == "meta_rule": + data_db = manager.get_meta_rules(moon_user_id=user_id) + elif element_type == "subject_data": + data_db = manager.get_subject_data(moon_user_id=user_id, policy_id=policy_id, + category_id=category_id) + elif element_type == "object_data": + data_db = manager.get_object_data(moon_user_id=user_id, policy_id=policy_id, + category_id=category_id) + elif element_type == "action_data": + data_db = manager.get_action_data(moon_user_id=user_id, policy_id=policy_id, + category_id=category_id) + elif element_type == "meta_rule": + data_db = manager.get_meta_rules(moon_user_id=user_id) + elif element_type == "rule": + data_db = manager.get_rules(moon_user_id=user_id, policy_id=policy_id) + else: + raise exceptions.MoonError("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"]: + 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 exceptions.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 exceptions.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 exceptions.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 exceptions.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) + if element is None: + raise exceptions.UnknownId("No {} with id {} found in database".format( + element_type, id_)) + res = JsonUtils.__convert_results_to_element(element) + 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 exceptions.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 exceptions.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: + LOGGER.debug("No {} with name {} found in database".format(element_type, elt["name"])) + raise exceptions.UnknownName( + "No {} with name {} found in database".format(element_type, elt["name"])) + ids.append(id_in_db) + elif "attr" in elt: + ids.append("attributes:" + elt['attr']) + elif field_mandatory is True: + raise exceptions.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 exceptions.UnknownId("No {} with id {} found in database".format( + element_type, id_)) + res = JsonUtils.__convert_results_to_element(element) + 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 + + +class JsonImport(object): + __user_id = None + __manager = None + __driver = None + + def __init__(self, driver_name="db", driver=None): + self.__driver = driver_name + if driver_name == "db": + self.__manager = DBManager(driver) + else: + self.__manager = CacheManager(driver) + + @property + def driver(self): + return self.__manager + + 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) + _exc = None + data = get_function(moon_user_id=self.__user_id, policy_id=policy_id) + for _data in data: + for item in json_data_ids: + if not _data['data']: + continue + if _data.get('data').get(item): + index = ordered_perimeter_categories_ids.index(_data["category_id"]) + if _data["category_id"] not in ordered_perimeter_categories_ids: + _exc = exceptions.InvalidJson( + "The category id {} of the rule {} does not match the meta rule".format( + _data["category_id"], rule)) + continue + if ordered_json_ids[index] is not None: + _exc = exceptions.InvalidJson( + "The category id {} of the rule {} shall not be used " + "twice in the same rule".format( + _data["category_id"], rule)) + ordered_json_ids[index] = item + if None in ordered_json_ids: + for cpt, _id in enumerate(ordered_perimeter_categories_ids): + if _id.startswith("attributes:"): + if not ordered_json_ids[cpt]: + ordered_json_ids[cpt] = json_data_ids[cpt] + + if _exc: + raise _exc + return ordered_json_ids + + def _import_rules(self, json_rules): + if not isinstance(json_rules, list): + raise exceptions.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", + self.__manager, self.__user_id) + JsonUtils.convert_name_to_id(json_rule, json_to_use, "meta_rule", "meta_rule_id", + "meta_rule", self.__manager, 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", self.__manager, + self.__user_id, + json_ids["policy_id"]) + JsonUtils.convert_names_to_ids(json_rule["rule"], json_object_ids, "object_data", + "object", "object_data", self.__manager, + self.__user_id, + json_ids["policy_id"]) + JsonUtils.convert_names_to_ids(json_rule["rule"], json_action_ids, "action_data", + "action", "action_data", self.__manager, + self.__user_id, + json_ids["policy_id"]) + + meta_rule = self.__manager.get_meta_rules( + moon_user_id=self.__user_id, + meta_rule_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"], + self.__manager.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"], + self.__manager.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"], + self.__manager.get_action_data) + json_to_use["rule"] = json_to_use_rule + try: + LOGGER.debug("Adding / updating a rule from json {}".format(json_to_use)) + self.__manager.add_rule( + moon_user_id=self.__user_id, + policy_id=json_ids["policy_id"], + meta_rule_id=json_to_use["meta_rule_id"], + value=json_to_use + ) + except exceptions.RuleExisting as e: + LOGGER.error("rule existing {}".format(e)) + except exceptions.PolicyUnknown: + raise exceptions.PolicyUnknown("Unknown policy with id {}".format( + json_ids["policy_id"])) + + def _import_meta_rules(self, json_meta_rules): + imported_mrule = [] + 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", + self.__manager, + self.__user_id) + JsonUtils.convert_names_to_ids(json_meta_rule, json_to_use, "object_categories", + "object_categories", "object_category", + self.__manager, + self.__user_id) + JsonUtils.convert_names_to_ids(json_meta_rule, json_to_use, "action_categories", + "action_categories", "action_category", + self.__manager, + self.__user_id) + LOGGER.debug("Adding / updating a metarule from json {}".format(json_meta_rule)) + try: + meta_rule = self.__manager.add_meta_rule( + moon_user_id=self.__user_id, + meta_rule_id=None, + value=json_to_use + ) + LOGGER.debug("Added / updated meta rule : {}".format(meta_rule)) + imported_mrule.append(meta_rule) + except exceptions.MetaRuleExisting: + pass + return imported_mrule + + def _import_subject_object_action_assignments(self, json_item_assignments, type_element): + import_method = None + get_method = None + if type_element == "subject": + import_method = self.__manager.add_subject_assignment + get_method = self.__manager.get_subject_data + elif type_element == "object": + import_method = self.__manager.add_object_assignment + get_method = self.__manager.get_object_data + elif type_element == "action": + import_method = self.__manager.add_action_assignment + get_method = self.__manager.get_action_data + + if not isinstance(json_item_assignments, list): + raise exceptions.InvalidJson(type_element + " assignments shall be a list!") + + # get the policy id related to the user + policies = self.__manager.get_policies(moon_user_id=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 exceptions.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", + self.__manager, + 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, + self.__manager, + self.__user_id, policy_id) + JsonUtils.convert_names_to_ids(json_item_assignment, json_data, "assignments", + "data_id", type_element + "_data", + self.__manager, + self.__user_id, policy_id, + json_assignment["category_id"]) + has_found_data = True + except exceptions.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(moon_user_id=self.__user_id, policy_id=policy_id, + data_id=data_id, + category_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)) + args = {"moon_user_id": self.__user_id, "policy_id": policy_id, + type_element + "_id": json_assignment["id"], + "category_id": json_assignment["category_id"], "data_id": data_id} + try: + import_method(**args) + except exceptions.SubjectAssignmentExisting: + pass + except exceptions.ObjectAssignmentExisting: + pass + except exceptions.ActionAssignmentExisting: + pass + else: + raise exceptions.DataUnknown("Unknown data with id {}".format(data_id)) + + # case the data has not been found in any policies + if has_found_data is False: + raise exceptions.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): + import_method = None + if type_element == "subject": + import_method = self.__manager.set_subject_data + elif type_element == "object": + import_method = self.__manager.set_object_data + elif type_element == "action": + import_method = self.__manager.set_action_data + + if not isinstance(json_items_data, list): + raise exceptions.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 exceptions.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", + self.__manager, 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", + self.__manager, 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 exceptions.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 exceptions.InvalidJson( + "Invalid data, the category shall be set when importing {}".format( + json_item_data)) + + for policy_id in mandatory_policy_ids: + try: + import_method(moon_user_id=self.__user_id, policy_id=policy_id, + category_id=category_id, + value=json_to_use) + except exceptions.PolicyUnknown: + raise exceptions.PolicyUnknown("Unknown policy with id {}".format(policy_id)) + except exceptions.SubjectScopeExisting: + pass + except exceptions.ObjectScopeExisting: + pass + except exceptions.ActionScopeExisting: + pass + except Exception as e: + LOGGER.exception(str(e)) + raise e + + def _import_subject_object_action_categories(self, json_item_categories, type_element): + imported_oac = [] + import_method = None + get_method = None + if type_element == "subject": + import_method = self.__manager.add_subject_category + get_method = self.__manager.get_subject_categories + elif type_element == "object": + import_method = self.__manager.add_object_category + get_method = self.__manager.get_object_categories + elif type_element == "action": + import_method = self.__manager.add_action_category + get_method = self.__manager.get_action_categories + + categories = get_method(moon_user_id=self.__user_id) + + if not isinstance(json_item_categories, list): + raise exceptions.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 + + 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 exceptions.ForbiddenOverride( + "{} categories do not support override flag !".format(type_element)) + + try: + import_method(moon_user_id=self.__user_id, category_id=existing_id, + value=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 + imported_oac.append({ + 'category': type_element, + 'name': json_to_use["name"]}) + return imported_oac + + def _import_subject_object_action(self, json_items, mandatory_policy_ids, type_element): + import_method = None + get_method = None + if type_element == "subject": + import_method = self.__manager.add_subject + get_method = self.__manager.get_subjects + elif type_element == "object": + import_method = self.__manager.add_object + get_method = self.__manager.get_objects + elif type_element == "action": + import_method = self.__manager.add_action + get_method = self.__manager.get_actions + + if not isinstance(json_items, list): + raise exceptions.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) + + policy_list_ids = {} + JsonUtils.convert_names_to_ids(json_item, policy_list_ids, "policies", + "policy_list", "policy", self.__manager, + self.__user_id, + field_mandatory=False) + policy_ids = policy_list_ids["policy_list"] + # json_without_policy_name["policies"] = [] + 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 exceptions.ForbiddenOverride("{} does not support override flag !".format( + type_element)) + + if len(policy_ids) == 0: + raise exceptions.PolicyUnknown( + "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(moon_user_id=self.__user_id, policy_id=policy_id) + items_in_db = items_in_db.get(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 + try: + element = import_method(moon_user_id=self.__user_id, policy_id=policy_id, + perimeter_id=key, + value=json_without_policy_name) + LOGGER.debug("Added / updated {} : {}".format(type_element, element)) + except exceptions.PolicyExisting: + pass + + except exceptions.PolicyUnknown: + LOGGER.error("Unknown policy when adding a {}!".format( + type_element)) + raise exceptions.PolicyUnknown("Unknown policy when adding a {}!".format( + type_element)) + except Exception as e: + LOGGER.exception(str(e)) + raise e + + def _import_policies(self, json_policies): + policy_mandatory_ids = [] + policy_mandatory_names = [] + + if not isinstance(json_policies, list): + raise exceptions.InvalidJson("policies shall be a list!") + + for json_policy in json_policies: + # TODO put this in moondb + # policy_in_db = + # self.driver.PolicyManager.get_policies_by_name(json_without_model_name["name"]) + policies = self.__manager.get_policies(moon_user_id=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) + policy_mandatory_names.append(json_policy["name"]) + 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", self.__manager, self.__user_id, + field_mandatory=False) + + if not policy_does_exist: + LOGGER.debug("Creating policy {} ".format(json_without_model_name)) + added_policy = self.__manager.add_policy( + moon_user_id=self.__user_id, + value=json_without_model_name) + if policy_mandatory is True: + keys = list(added_policy.keys()) + policy_mandatory_ids.append(keys[0]) + policy_mandatory_names.append(json_policy["name"]) + elif policy_override is True: + LOGGER.debug("Updating policy {} ".format(json_without_model_name)) + self.__manager.update_policy(moon_user_id=self.__user_id, + policy_id=policy_id, + value=json_without_model_name) + if policy_mandatory is True: + policy_mandatory_ids.append(policy_id) + policy_mandatory_names.append(json_policy["name"]) + return [policy_mandatory_ids, policy_mandatory_names] + + def _import_models_with_new_meta_rules(self, json_models): + if not isinstance(json_models, list): + raise exceptions.InvalidJson("models shall be a list!") + + for json_model in json_models: + models = self.__manager.get_models(moon_user_id=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 exceptions.ModelUnknown("Unknown model") + + json_key = dict() + JsonUtils.convert_names_to_ids(json_model, json_key, "meta_rules", "meta_rule_id", + "meta_rule", self.__manager, 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) + + self.__manager.update_model(moon_user_id=self.__user_id, + model_id=model_id, + value=model_in_db) + + def _import_models_without_new_meta_rules(self, json_models): + if not isinstance(json_models, list): + raise exceptions.InvalidJson("models shall be a list!") + imported_model_names = [] + for json_model in json_models: + json_without_new_metarules = dict() + JsonUtils.copy_field_if_exists(json_model, json_without_new_metarules, "name", str) + + models = self.__manager.get_models(moon_user_id=self.__user_id) + model_in_db = None + model_id = 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 + + 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)) + self.__manager.add_model(moon_user_id=self.__user_id, + value=json_without_new_metarules) + elif model_override is True: + LOGGER.debug( + "Updating model with id {} : {} ".format(model_id, json_without_new_metarules)) + self.__manager.update_model(moon_user_id=self.__user_id, + model_id=model_id, + value=json_without_new_metarules) + if "name" in json_without_new_metarules: + imported_model_names.append(json_without_new_metarules["name"]) + return imported_model_names + + def _import_pdps(self, json_pdps): + if not isinstance(json_pdps, list): + raise exceptions.InvalidJson("pdps shall be a list!") + imported_pdp_names = [] + 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, "vim_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 = self.__manager.get_pdp(moon_user_id=self.__user_id) + exists = False + for pdp_key in pdps: + if pdps[pdp_key]["name"] == json_to_use["name"]: + self.__manager.update_pdp(moon_user_id=self.__user_id, pdp_id=pdp_key, + value=json_to_use) + exists = True + if exists is False: + self.__manager.add_pdp(moon_user_id=self.__user_id, value=json_to_use) + imported_pdp_names.append(json_to_use["name"]) + + def import_json(self, **kwargs): + if self.__driver == "db": + if "body" in kwargs: + return self.__import_json_to_db(kwargs.get("body")).keys() + else: + raise Exception("Bad argument given...") + else: + if "body" in kwargs: + return self.__import_json_to_cache(kwargs.get("body")).keys() + else: + raise Exception("Bad argument given...") + + def __import_json_to_db(self, body): + imported_data = {} + + LOGGER.debug("Importing content: {} ...".format(body)) + + # first import the models without the meta rules as they are not yet defined + if "models" in body: + LOGGER.info("Importing models...") + imported_model_names = self._import_models_without_new_meta_rules(body["models"]) + imported_data['models'] = imported_model_names + + + + # import subjects, object, action_categories + list_element = [{"key": "subject"}, {"key": "object"}, {"key": "action"}] + for elt in list_element: + in_key = elt["key"] + key = in_key + "_categories" + if key in body: + LOGGER.info("Importing {}...".format(key)) + imported_oac = self._import_subject_object_action_categories(body[key], in_key) + imported_data[key] = imported_oac + + # import meta rules + if "meta_rules" in body: + LOGGER.info("Importing meta rules...") + imported_mrules = self._import_meta_rules(body["meta_rules"]) + imported_data["meta_rules"] = imported_mrules + + # add the metarule to model + if "models" in body: + LOGGER.info("Updating models with meta rules...") + self._import_models_with_new_meta_rules(body["models"]) + + # import the policies that depends on the models + mandatory_policy_ids = [] + if "policies" in body: + LOGGER.info("Importing policies...") + mandatory_policy_ids, policy_mandatory_names = self._import_policies(body["policies"]) + imported_data["policies"] = { + 'id': mandatory_policy_ids, + 'name': policy_mandatory_names} + + # import subjects, object, action + for elt in list_element: + in_key = elt["key"] + key = in_key + "s" + if key in body: + LOGGER.info("Importing {}...".format(key)) + imported_sub = self._import_subject_object_action(body[key], mandatory_policy_ids, in_key) + imported_data[key] = imported_sub + + # import subjects, object, action data + for elt in list_element: + in_key = elt["key"] + key = in_key + "_data" + if key in body: + LOGGER.info("Importing {}...".format(key)) + imported_sub =self._import_subject_object_action_datas(body[key], mandatory_policy_ids, + in_key) + imported_data[key] = imported_sub + + # import subjects assignments, idem for object and action + for elt in list_element: + in_key = elt["key"] + key = in_key + "_assignments" + if key in body: + LOGGER.info("Importing {}...".format(key)) + imported_sub = self._import_subject_object_action_assignments(body[key], in_key) + imported_data[key] = imported_sub + + # import rules + if "rules" in body: + LOGGER.info("Importing rules...") + imported_sub = self._import_rules(body["rules"]) + imported_data["rules"] = imported_sub + + # import pdps + if "pdps" in body: + LOGGER.info("Importing pdps...") + imported_sub = self._import_pdps(body["pdps"]) + imported_data["pdps"] = imported_sub + + return imported_data + + def __import_json_to_cache(self, body): + imported_data = {} + + LOGGER.debug("Importing content: {} ...".format(body)) + + # first import the models without the meta rules as they are not yet defined + if "models" in body: + LOGGER.info("Importing models...") + imported_model_names = self._import_models_without_new_meta_rules(body["models"]) + imported_data['models'] = imported_model_names + + + # import subjects, object, action_categories + list_element = [{"key": "subject"}, {"key": "object"}, {"key": "action"}] + for elt in list_element: + in_key = elt["key"] + key = in_key + "_categories" + if key in body: + LOGGER.info("Importing {}...".format(key)) + imported_oac = self._import_subject_object_action_categories(body[key], in_key) + imported_data[key] = imported_oac + + # import meta rules + if "meta_rules" in body: + LOGGER.info("Importing meta rules...") + imported_mrules = self._import_meta_rules(body["meta_rules"]) + imported_data["meta_rules"] = imported_mrules + + # add the metarule to model + if "models" in body: + LOGGER.info("Updating models with meta rules...") + self._import_models_with_new_meta_rules(body["models"]) + + # import the policies that depends on the models + mandatory_policy_ids = [] + if "policies" in body: + LOGGER.info("Importing policies...") + mandatory_policy_ids, policy_mandatory_names = self._import_policies(body["policies"]) + imported_data["policies"] = { + 'id': mandatory_policy_ids, + 'name': policy_mandatory_names} + + # import subjects, object, action + for elt in list_element: + in_key = elt["key"] + key = in_key + "s" + if key in body: + LOGGER.info("Importing {}...".format(key)) + imported_sub = self._import_subject_object_action(body[key], mandatory_policy_ids, in_key) + imported_data[key] = imported_sub + + #import subjects, object, action data + for elt in list_element: + in_key = elt["key"] + key = in_key + "_data" + if key in body: + LOGGER.info("Importing {}...".format(key)) + imported_sub= self._import_subject_object_action_datas(body[key], mandatory_policy_ids, + in_key) + imported_data[key] = imported_sub + + # import subjects assignments, idem for object and action + for elt in list_element: + in_key = elt["key"] + key = in_key + "_assignments" + if key in body: + LOGGER.info("Importing {}...".format(key)) + imported_sub = self._import_subject_object_action_assignments(body[key], in_key) + imported_data[key] = imported_sub + + # import rules + if "rules" in body: + LOGGER.info("Importing rules...") + imported_sub = self._import_rules(body["rules"]) + imported_data["rules"] = imported_sub + + # import pdps + if "pdps" in body: + LOGGER.info("Importing pdps...") + imported_sub = self._import_pdps(body["pdps"]) + imported_data["pdps"] = imported_sub + return imported_data + + +class JsonExport(object): + __user_id = None + __dirver = None + __manager = None + + def __init__(self, driver_name="db", driver=None): + self.__driver = driver_name + if driver_name == "db": + self.__manager = DBManager(driver) + else: + self.__manager = CacheManager(driver) + + def _export_rules(self, json_content): + policies = self.__manager.get_policies(moon_user_id=self.__user_id) + rules_array = [] + + for policy_key in policies: + rules = self.__manager.get_rules(moon_user_id=self.__user_id, policy_id=policy_key) + rules = rules["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", self.__manager, self.__user_id) + JsonUtils.convert_id_to_name(policy_key, rule_dict, "policy", "policy", + self.__manager, self.__user_id) + ids = rule["rule"] + rule_description = dict() + meta_rule = self.__manager.get_meta_rules(moon_user_id=self.__user_id, + meta_rule_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", self.__manager, self.__user_id, + policy_key) + JsonUtils.convert_ids_to_names(ids_object_data, rule_description, "object_data", + "object_data", self.__manager, self.__user_id, + policy_key) + JsonUtils.convert_ids_to_names(ids_action_date, rule_description, "action_data", + "action_data", self.__manager, 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 = self.__manager.get_meta_rules(moon_user_id=self.__user_id) + meta_rules_array = [] + for meta_rule_key in meta_rules: + 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", + self.__manager, self.__user_id) + JsonUtils.convert_ids_to_names(meta_rules[meta_rule_key]["object_categories"], + meta_rule_dict, "object_categories", "object_category", + self.__manager, self.__user_id) + JsonUtils.convert_ids_to_names(meta_rules[meta_rule_key]["action_categories"], + meta_rule_dict, "action_categories", "action_category", + self.__manager, self.__user_id) + meta_rules_array.append(meta_rule_dict) + if len(meta_rules_array) > 0: + json_content['meta_rules'] = meta_rules_array + + def _export_subject_object_action_assignments(self, type_element, json_content): + export_method_data = None + if type_element == "subject": + export_method_data = self.__manager.get_subject_assignments + elif type_element == "object": + export_method_data = self.__manager.get_object_assignments + if type_element == "action": + export_method_data = self.__manager.get_action_assignments + policies = self.__manager.get_policies(moon_user_id=self.__user_id) + element_assignments_array = [] + for policy_key in policies: + assignments = export_method_data(moon_user_id=self.__user_id, policy_id=policy_key) + 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, + self.__manager, self.__user_id, policy_key) + JsonUtils.convert_id_to_name(assignments[assignment_key]["category_id"], + assignment_dict, "category", + type_element + "_category", self.__manager, + self.__user_id, policy_key) + JsonUtils.convert_ids_to_names(assignments[assignment_key]["assignments"], + assignment_dict, "assignments", + type_element + "_data", self.__manager, + 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 + + def _export_subject_object_action_datas(self, type_element, json_content): + export_method_data = None + if type_element == "subject": + export_method_data = self.__manager.get_subject_data + elif type_element == "object": + export_method_data = self.__manager.get_object_data + if type_element == "action": + export_method_data = self.__manager.get_action_data + policies = self.__manager.get_policies(moon_user_id=self.__user_id) + element_datas_array = [] + for policy_key in policies: + datas = export_method_data(moon_user_id=self.__user_id, policy_id=policy_key) + for data_group in datas: + policy_id = data_group["policy_id"] + category_id = data_group["category_id"] + 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) + + JsonUtils.convert_id_to_name(policy_id, data_dict, "policy", "policy", + self.__manager, self.__user_id) + JsonUtils.convert_id_to_name(category_id, data_dict, "category", + type_element + "_category", self.__manager, + 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 = None + if type_element == "subject": + export_method = self.__manager.get_subject_categories + elif type_element == "object": + export_method = self.__manager.get_object_categories + if type_element == "action": + export_method = self.__manager.get_action_categories + element_categories = export_method(moon_user_id=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 = None + if type_element == "subject": + export_method = self.__manager.get_subjects + elif type_element == "object": + export_method = self.__manager.get_objects + if type_element == "action": + export_method = self.__manager.get_actions + policies = self.__manager.get_policies(moon_user_id=self.__user_id) + element_dict = dict() + elements_array = [] + for policy_key in policies: + elements = export_method(moon_user_id=self.__user_id, policy_id=policy_key) + for element_key in elements: + 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", self.__manager, 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 = self.__manager.get_policies(moon_user_id = 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", + self.__manager, 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 = self.__manager.get_models(moon_user_id=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) + JsonUtils.convert_ids_to_names(models[model_key]["meta_rules"], model, "meta_rules", + "meta_rule", self.__manager, 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 = self.__manager.get_pdp(moon_user_id=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 + + def export_json(self, **kwargs): + if self.__driver == "db": + if "moon_user_id" in kwargs: + return self.__export_json_from_db(kwargs.get("moon_user_id")) + else: + raise Exception("Bad argument given...") + else: + if "body" in kwargs: + return self.__export_json_from_db(kwargs.get("body")) + else: + raise Exception("Bad argument given...") + + def __export_json_from_db(self, moon_user_id=None): + self.__user_id = moon_user_id + + json_content = dict() + + 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 diff --git a/moon_utilities/moon_utilities/security_functions.py b/moon_utilities/moon_utilities/security_functions.py new file mode 100644 index 00000000..07aaa965 --- /dev/null +++ b/moon_utilities/moon_utilities/security_functions.py @@ -0,0 +1,83 @@ +# 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_utilities import exceptions +import html +import hug + +LOGGER = logging.getLogger("moon.utilities." + __name__) + + +def enforce(action_names, object_name, **extra): + """Fake version of the enforce decorator""" + def wrapper_func(func): + def wrapper_args(*args, **kwargs): + # TODO: implement the enforce decorator + return func(*args, **kwargs) + return wrapper_args + return wrapper_func + + +def validate_data(data): + def __validate_string(string): + temp_str = html.escape(string) + if string != temp_str: + raise exceptions.ValidationContentError('Forbidden characters in string') + + def __validate_list_or_tuple(container): + for i in container: + validate_data(i) + + def __validate_dict(dictionary): + for key in dictionary: + validate_data(dictionary[key]) + + if isinstance(data, bool): + return True + if data is None: + data = "" + if isinstance(data, str): + __validate_string(data) + elif isinstance(data, list) or isinstance(data, tuple): + __validate_list_or_tuple(data) + elif isinstance(data, dict): + __validate_dict(data) + else: + raise exceptions.ValidationContentError('Value is Not String or Container or Dictionary: {}'.format(data)) + + +def validate_input(*validators): + """Validation only succeeds if all passed in validators return no errors""" + body_state = {"name", "id", "category_id", "data_id"} + + def validate_all_input(fields, **kwargs): + try: + for validator in validators: + # errors = validator(fields) + if validator not in fields: + raise exceptions.ValidationKeyError('Invalid Key :{} not found'.format(validator)) + + for field in body_state: + if field in fields: + try: + validate_data(fields[field]) + except exceptions.ValidationContentError as e: + raise exceptions.ValidationContentError("Key: '{}', [{}]".format(field, str(e))) + except Exception as e: + LOGGER.exception(e) + raise e + return fields + + validate_all_input.__doc__ = " and ".join(validator.__doc__ for validator in validators) + return validate_all_input diff --git a/moon_utilities/moon_utilities/update_opst_policies.py b/moon_utilities/moon_utilities/update_opst_policies.py new file mode 100644 index 00000000..4a629181 --- /dev/null +++ b/moon_utilities/moon_utilities/update_opst_policies.py @@ -0,0 +1,85 @@ +# 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'. +""" +Update policy files of an OpenStack platform +""" + +import argparse +import logging +import os + + +COMPONENTS = [ + "cinder", + "glance", + "keystone", + "neutron", + "nova", +] + + +logger = logging.getLogger(__name__) + + +def init(): + """ + Initialize the application + :return: argument given in the command line + """ + global policy + parser = argparse.ArgumentParser() + parser.add_argument("--verbose", '-v', action='store_true', help='verbose mode') + parser.add_argument("--debug", '-d', action='store_true', help='debug mode') + parser.add_argument("--dir", + help='directory containing policy files, defaults to /etc', + default="/etc") + parser.add_argument("--exclude", "-x", + help="Exclude some components " + "(example: \"nova,neutron\")", + default="") + parser.add_argument("--include", "-i", + help="Only include some components " + "(example: \"nova,neutron\")", + default="") + args = parser.parse_args() + logging_format = "%(levelname)s: %(message)s" + if args.verbose: + logging.basicConfig(level=logging.INFO, format=logging_format) + if args.debug: + logging.basicConfig(level=logging.DEBUG, format=logging_format) + else: + logging.basicConfig(format=logging_format) + + return args + + +def update_component(component, args): + """ + + :param component: + :return: + """ + filename = os.path.join(args.dir, component, "policy.json") + logger.info(f"Updating {component} ({filename})") + if not os.path.isfile(filename): + logger.error(f"Cannot find {filename}") + return + + +def main(): + args = init() + if args.include: + for component in args.include.split(","): + update_component(component, args) + else: + excl_comp = args.exclude.split(",") + for component in COMPONENTS: + if component in excl_comp: + continue + update_component(component, args) + + +if __name__ == "__main__": + main() diff --git a/moon_utilities/requirements.txt b/moon_utilities/requirements.txt new file mode 100644 index 00000000..5c2032c1 --- /dev/null +++ b/moon_utilities/requirements.txt @@ -0,0 +1,3 @@ +requests +hug +tinydb diff --git a/moon_utilities/setup.py b/moon_utilities/setup.py new file mode 100644 index 00000000..f5fa746f --- /dev/null +++ b/moon_utilities/setup.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. + + +from setuptools import setup, find_packages +import moon_utilities + +with open('requirements.txt') as f: + required = list(filter( + lambda s: (len(s.strip()) > 0 and s.strip()[0] != '#'), + f.read().split('\n'))) + +setup( + + name='moon_utilities', + + version=moon_utilities.__version__, + + packages=find_packages(), + + author='Thomas Duval', + + author_email='thomas.duval@orange.com', + + description='Some utilities for all the Moon components', + + long_description=open('README.md').read(), + + install_requires=required, + + include_package_data=True, + + url='', + + classifiers=[ + 'Programming Language :: Python :: 3', + 'Development Status :: 1 - Planning', + 'License :: OSI Approved', + 'Natural Language :: English', + 'Operating System :: OS Independent', + ], + + entry_points={ + 'console_scripts': [ + 'generate_opst_policy = moon_utilities.generate_opst_policy:main', + ], + + } + +) diff --git a/moon_utilities/tests/unit_python/api/__init__.py b/moon_utilities/tests/unit_python/api/__init__.py new file mode 100644 index 00000000..1856aa2c --- /dev/null +++ b/moon_utilities/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_utilities/tests/unit_python/api/test_auth_functions.py b/moon_utilities/tests/unit_python/api/test_auth_functions.py new file mode 100644 index 00000000..70af19c1 --- /dev/null +++ b/moon_utilities/tests/unit_python/api/test_auth_functions.py @@ -0,0 +1,83 @@ +# 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 +from uuid import uuid4 +import pytest +from moon_utilities.auth_functions import xor_encode, xor_decode +from moon_utilities import exceptions +from moon_utilities.auth_functions import init_db, add_user, authenticate_user +from moon_utilities.auth_functions import authenticate_key, get_api_key, del_api_key_for_user + + +def test_xor(): + uuid1 = uuid4().hex + my_key = uuid4().hex + crypted_data = xor_encode(uuid1, my_key) + assert uuid1 != crypted_data + decrypted_data = xor_decode(crypted_data, my_key) + assert uuid1 == decrypted_data + + +def test_decrypt_exceptions(): + with pytest.raises(exceptions.DecryptError): + uuid1 = uuid4().hex + my_key = uuid4().hex + crypted_data = xor_encode(uuid1, my_key) + assert uuid1 != crypted_data + my_key = False + xor_decode(crypted_data, my_key) + with pytest.raises(exceptions.DecryptError): + uuid1 = uuid4().hex + my_key = uuid4().hex + crypted_data = xor_encode(uuid1, my_key) + assert uuid1 != crypted_data + my_key = "" + xor_decode(crypted_data, my_key) + + +def test_encrypt_exceptions(): + with pytest.raises(exceptions.EncryptError): + uuid1 = uuid4().hex + my_key = False + xor_encode(uuid1, my_key) + with pytest.raises(exceptions.EncryptError): + uuid1 = uuid4().hex + my_key = "" + xor_encode(uuid1, my_key) + + +def test_auth_api(): + try: + os.remove("/tmp/test.db") + except FileNotFoundError: + pass + init_db("/tmp/test.db") + # create the user + result = add_user("test_user", "1234567890") + assert result + # trying to auth the user + assert authenticate_user("test_user", "1234567890") + assert not authenticate_user("bad_test_user", "1234567890") + assert not authenticate_key(None) + assert not authenticate_key("") + assert authenticate_key(result['api_key']) == "test_user" + assert get_api_key("test_user", "1234567890") == result['api_key'] + # logout the user + assert del_api_key_for_user("test_user") + assert get_api_key("test_user", "1234567890") != result['api_key'] + assert get_api_key("test_user", "1234567890") is None + # re-authent user + assert authenticate_user("test_user", "1234567890") + # check that the previous api_key is not valid again + assert get_api_key("test_user", "1234567890") != result['api_key'] + assert get_api_key("test_user", "1234567890") diff --git a/moon_utilities/tests/unit_python/api/test_import_to_cache.py b/moon_utilities/tests/unit_python/api/test_import_to_cache.py new file mode 100644 index 00000000..01e717fb --- /dev/null +++ b/moon_utilities/tests/unit_python/api/test_import_to_cache.py @@ -0,0 +1,775 @@ +# 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 helpers.import_export_cache_helper as import_export_helper +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 import json_utils + from moon_cache.cache import Cache + _cache = Cache.getInstance() + import_to_cache = json_utils.JsonImport(driver_name="cache", driver=_cache) + + import_export_helper.clean_all() + counter = 0 + for models_description in MODEL_WITHOUT_META_RULES: + data = import_to_cache.import_json(body=models_description) + assert "models" in data + models = _cache.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 import json_utils + from moon_cache.cache import Cache + _cache = Cache.getInstance() + import_to_cache = json_utils.JsonImport(driver_name="cache", driver=_cache) + + counter = -1 + for policy_description in POLICIES: + counter = counter + 1 + if counter == 2: + with pytest.raises(exceptions.UnknownName): + import_to_cache.import_json(body=policy_description) + continue + else: + data = import_to_cache.import_json(body=policy_description) + assert "policies" in data + if counter == 2: + assert "models" in data + + from moon_cache.cache import Cache + _cache = Cache.getInstance() + policies = _cache.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 + + +def test_import_subject_object_action(): + from moon_utilities import json_utils + from moon_cache.cache import Cache + _cache = Cache.getInstance() + import_to_cache = json_utils.JsonImport(driver_name="cache", driver=_cache) + + 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 = 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() + if counter == 3: + clean_method() + data = import_to_cache.import_json(body=element) + elif counter < 2: + with pytest.raises(exceptions.PolicyUnknown) as exception_info: + import_to_cache.import_json(body=element) + assert '400: Policy Unknown' == str(exception_info.value) + continue + else: + data = import_to_cache.import_json(body=element) + assert data + + if counter != 3: + assert type_element+"s" in data + assert "policies" in data + + get_elements = getattr(_cache, type_element + "s") + + policy_key = list(get_elements.keys())[0] + assert len(list(get_elements[policy_key].keys())) == 1 + values = list(get_elements[policy_key].values()) + assert values[0]["name"] == name + if counter == 2 or counter == 4: + assert values[0]["description"] == "description of the " + type_element + 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 import json_utils + from moon_cache.cache import Cache + _cache = Cache.getInstance() + import_to_cache = json_utils.JsonImport(driver_name="cache", driver=_cache) + + 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 + elif type_element == "object": + elements = OBJECT_CATEGORIES + else: + elements = ACTION_CATEGORIES + + for element in elements: + data = import_to_cache.import_json(body=element) + counter = counter + 1 + assert type_element + "_categories" in data + get_elements = getattr(_cache, 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 import json_utils + from moon_cache.cache import Cache + _cache = Cache.getInstance() + import_to_cache = json_utils.JsonImport(driver_name="cache", driver=_cache) + + import_export_helper.clean_all() + # import some categories + data = import_to_cache.import_json(body=PRE_META_RULES) + for cat in ['subject_categories', 'object_categories', 'action_categories']: + assert cat in data + + counter = -1 + for meta_rule in META_RULES: + counter = counter + 1 + if counter != 3: + with pytest.raises(exceptions.UnknownName) as exception_info: + import_to_cache.import_json(body=meta_rule) + assert '400: Unknown Name.' == str(exception_info.value) + continue + else: + data = import_to_cache.import_json(body=meta_rule) + assert "meta_rules" in data + assert _cache.meta_rules + + meta_rules = _cache.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] + + sub_cat = _cache.subject_categories + assert sub_cat[subject_category_key]["name"] == "test subject categories" + + ob_cat = _cache.object_categories + assert ob_cat[object_category_key]["name"] == "test object categories" + + ac_cat = _cache.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 import json_utils + from moon_cache.cache import Cache + _cache = Cache.getInstance() + import_to_cache = json_utils.JsonImport(driver_name="cache", driver=_cache) + + import_export_helper.clean_all() + + data = import_to_cache.import_json(body=PRE_ASSIGNMENTS) + for item in PRE_ASSIGNMENTS.keys(): + assert item in data + + type_elements = ["subject", "object", "action"] + + for type_element in type_elements: + counter = -1 + if type_element == "subject": + datas = SUBJECT_ASSIGNMENTS + elif type_element == "object": + datas = OBJECT_ASSIGNMENTS + else: + datas = ACTION_ASSIGNMENTS + + for assignments in datas: + counter = counter + 1 + my_exception = assignments.pop("exception") + if my_exception: + with pytest.raises(my_exception) as exception_info: + import_to_cache.import_json(body=assignments) + assert '400:' in str(exception_info.value) + else: + data = import_to_cache.import_json(body=assignments) + assert type_element+"_assignments" in data + assert getattr(_cache, type_element+"_assignments") + + assert len(getattr(_cache, type_element+"_assignments")) == 1 + + +def test_import_rules(): + from moon_utilities import json_utils + from moon_cache.cache import Cache + _cache = Cache.getInstance() + import_to_cache = json_utils.JsonImport(driver_name="cache", driver=_cache) + + import_export_helper.clean_all() + + data = import_to_cache.import_json(body=PRE_ASSIGNMENTS) + for item in PRE_ASSIGNMENTS.keys(): + assert item in data + + counter = -1 + for rule in RULES: + counter = counter + 1 + if counter < 5: + with pytest.raises(exceptions.UnknownName) as exception_info: + import_to_cache.import_json(body=rule) + + assert '400: Unknown Name.' == str(exception_info.value) + continue + data = import_to_cache.import_json(body=rule) + assert "rules" in data + policies = _cache.policies + policy_id = None + for policy in policies: + if policies[policy]['name'] == rule['rules'][0]['policy']['name']: + policy_id = policy + break + + assert policy_id + rules = _cache.rules + assert len(rules) == 1 + rule_content = list(rules.values())[0] + assert policy_id == rule_content["policy_id"] + assert rule_content["rules"] + assert len(rule_content["rules"]) == 1 + assert rule_content["rules"][0]["enabled"] + assert rule_content["rules"][0]["instructions"][0]["decision"] == "grant" + + meta_rules = _cache.meta_rules + assert meta_rules[list(meta_rules.keys())[0]]["name"] == "good meta rule" + + +def test_import_subject_object_action_data(): + from moon_utilities import json_utils + from moon_cache.cache import Cache + _cache = Cache.getInstance() + import_to_cache = json_utils.JsonImport(driver_name="cache", driver=_cache) + + type_elements = ["subject", "object", "action"] + + for type_element in type_elements: + import_export_helper.clean_all() + data = import_to_cache.import_json(body=PRE_DATA) + for key in PRE_DATA.keys(): + assert key in data + counter = -1 + if type_element == "subject": + elements = SUBJECT_DATA + get_method = _cache.subject_data + get_categories = _cache.subject_categories + elif type_element == "object": + elements = OBJECT_DATA + get_method = _cache.object_data + get_categories = _cache.object_categories + else: + elements = ACTION_DATA + get_method = _cache.action_data + get_categories = _cache.action_categories + + for element in elements: + counter = counter + 1 + if counter == 0 or counter == 1: + with pytest.raises(exceptions.MissingIdOrName) as exception_info: + import_to_cache.import_json(body=element) + assert '400: Missing ID or Name.' == str(exception_info.value) + continue + else: + data = import_to_cache.import_json(body=element) + for key in element.keys(): + assert key in data + + policies = _cache.policies + categories = get_categories + case_tested = False + for policy_key in policies.keys(): + policy = policies[policy_key] + for category_key in categories: + get_elements = get_method + _all_data = [] + for _data in get_elements: + if category_key == _data["category_id"] and policy_key == _data["policy_id"]: + _all_data.append(_data) + get_elements = _all_data + if not get_elements: + 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(): + from moon_cache.cache import Cache + _cache = Cache.getInstance() + import_export_helper.clean_all() + assert not _cache.subject_categories + assert not _cache.object_categories + assert not _cache.action_categories + assert not _cache.subjects + assert not _cache.objects + assert not _cache.actions + assert not _cache.subject_data + assert not _cache.object_data + assert not _cache.action_data + assert not _cache.subject_assignments + assert not _cache.object_assignments + assert not _cache.action_assignments + assert not _cache.models + assert not _cache.pdp + assert not _cache.policies diff --git a/moon_utilities/tests/unit_python/api/test_import_to_db.py b/moon_utilities/tests/unit_python/api/test_import_to_db.py new file mode 100644 index 00000000..34479b8c --- /dev/null +++ b/moon_utilities/tests/unit_python/api/test_import_to_db.py @@ -0,0 +1,772 @@ +# 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 helpers.import_export_db_helper as import_export_helper + + +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 import json_utils + from moon_manager import db_driver + import_to_db = json_utils.JsonImport(driver_name="db", driver=db_driver) + _cache = import_to_db.driver + + import_export_helper.clean_all() + counter = 0 + for models_description in MODEL_WITHOUT_META_RULES: + data = import_to_db.import_json(body=models_description) + assert "models" in data + models = _cache.get_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 import json_utils + from moon_manager import db_driver + import_to_db = json_utils.JsonImport(driver_name="db", driver=db_driver) + _cache = import_to_db.driver + + counter = -1 + for policy_description in POLICIES: + counter = counter + 1 + if counter == 2: + with pytest.raises(exceptions.UnknownName): + import_to_db.import_json(body=policy_description) + continue + else: + data = import_to_db.import_json(body=policy_description) + assert "policies" in data + if counter == 2: + assert "models" in data + + policies = db_driver.PolicyManager.get_policies(moon_user_id="admin") + 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 + + +def test_import_subject_object_action(): + from moon_utilities import json_utils + from moon_manager import db_driver + import_to_db = json_utils.JsonImport(driver_name="db", driver=db_driver) + _cache = import_to_db.driver + + 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 = 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() + if counter == 3: + clean_method() + data = import_to_db.import_json(body=element) + elif counter < 2: + with pytest.raises(exceptions.PolicyUnknown) as exception_info: + import_to_db.import_json(body=element) + assert '400: Policy Unknown' == str(exception_info.value) + continue + else: + data = import_to_db.import_json(body=element) + assert data + + if counter != 3: + assert type_element+"s" in data + assert "policies" in data + + get_elements = getattr(_cache, type_element + "s") + + 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 + 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 import json_utils + from moon_manager import db_driver + import_to_db = json_utils.JsonImport(driver_name="db", driver=db_driver) + _cache = import_to_db.driver + + 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 + elif type_element == "object": + elements = OBJECT_CATEGORIES + else: + elements = ACTION_CATEGORIES + + for element in elements: + data = import_to_db.import_json(body=element) + counter = counter + 1 + assert type_element + "_categories" in data + get_elements = getattr(_cache, 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 import json_utils + from moon_manager import db_driver + import_to_db = json_utils.JsonImport(driver_name="db", driver=db_driver) + _cache = import_to_db.driver + + import_export_helper.clean_all() + # import some categories + data = import_to_db.import_json(body=PRE_META_RULES) + for cat in ['subject_categories', 'object_categories', 'action_categories']: + assert cat in data + + counter = -1 + for meta_rule in META_RULES: + counter = counter + 1 + if counter != 3: + with pytest.raises(exceptions.UnknownName) as exception_info: + import_to_db.import_json(body=meta_rule) + assert '400: Unknown Name.' == str(exception_info.value) + continue + else: + data = import_to_db.import_json(body=meta_rule) + assert "meta_rules" in data + assert _cache.meta_rules + + meta_rules = _cache.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] + + sub_cat = _cache.subject_categories + assert sub_cat[subject_category_key]["name"] == "test subject categories" + + ob_cat = _cache.object_categories + assert ob_cat[object_category_key]["name"] == "test object categories" + + ac_cat = _cache.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 import json_utils + from moon_manager import db_driver + import_to_db = json_utils.JsonImport(driver_name="db", driver=db_driver) + _cache = import_to_db.driver + + import_export_helper.clean_all() + + data = import_to_db.import_json(body=PRE_ASSIGNMENTS) + for item in PRE_ASSIGNMENTS.keys(): + assert item in data + + type_elements = ["subject", "object", "action"] + + for type_element in type_elements: + counter = -1 + if type_element == "subject": + datas = SUBJECT_ASSIGNMENTS + elif type_element == "object": + datas = OBJECT_ASSIGNMENTS + else: + datas = ACTION_ASSIGNMENTS + + for assignments in datas: + counter = counter + 1 + my_exception = assignments.pop("exception") + if my_exception: + with pytest.raises(my_exception) as exception_info: + import_to_db.import_json(body=assignments) + assert '400:' in str(exception_info.value) + else: + data = import_to_db.import_json(body=assignments) + assert type_element+"_assignments" in data + assert getattr(_cache, type_element+"_assignments") + + assert len(getattr(_cache, type_element+"_assignments")) == 1 + + +def test_import_rules(): + from moon_utilities import json_utils + from moon_manager import db_driver + import_to_db = json_utils.JsonImport(driver_name="db", driver=db_driver) + _cache = import_to_db.driver + + import_export_helper.clean_all() + + data = import_to_db.import_json(body=PRE_ASSIGNMENTS) + for item in PRE_ASSIGNMENTS.keys(): + assert item in data + + counter = -1 + for rule in RULES: + counter = counter + 1 + if counter < 5: + with pytest.raises(exceptions.UnknownName) as exception_info: + import_to_db.import_json(body=rule) + + assert '400: Unknown Name.' == str(exception_info.value) + continue + data = import_to_db.import_json(body=rule) + assert "rules" in data + policies = _cache.policies + policy_id = None + for policy in policies: + if policies[policy]['name'] == rule['rules'][0]['policy']['name']: + policy_id = policy + break + + assert policy_id + rules = [] + for _rule in _cache.rules: + if policy_id == _rule['policy_id']: + rules.append(_rule) + assert len(rules) == 1 + rule_content = rules[0] + assert policy_id == rule_content["policy_id"] + assert rule_content["rules"] + assert len(rule_content["rules"]) == 1 + # FIXME: this is different from cache tests (where we have a "value" attribute) + assert rule_content["rules"][0]["enabled"] + assert rule_content["rules"][0]["instructions"][0]["decision"] == "grant" + + meta_rules = _cache.meta_rules + assert meta_rules[list(meta_rules.keys())[0]]["name"] == "good meta rule" + + +def test_import_subject_object_action_data(): + from moon_utilities import json_utils + from moon_manager import db_driver + import_to_db = json_utils.JsonImport(driver_name="db", driver=db_driver) + _cache = import_to_db.driver + + type_elements = ["subject", "object", "action"] + + for type_element in type_elements: + import_export_helper.clean_all() + data = import_to_db.import_json(body=PRE_DATA) + for key in PRE_DATA.keys(): + assert key in data + counter = -1 + if type_element == "subject": + elements = SUBJECT_DATA + get_method = _cache.get_subject_data + get_categories = _cache.subject_categories + elif type_element == "object": + elements = OBJECT_DATA + get_method = _cache.get_object_data + get_categories = _cache.object_categories + else: + elements = ACTION_DATA + get_method = _cache.get_action_data + get_categories = _cache.action_categories + + for element in elements: + counter = counter + 1 + if counter == 0 or counter == 1: + with pytest.raises(exceptions.MissingIdOrName) as exception_info: + import_to_db.import_json(body=element) + assert '400: Missing ID or Name.' == str(exception_info.value) + continue + else: + data = import_to_db.import_json(body=element) + for key in element.keys(): + assert key in data + + policies = _cache.policies + categories = get_categories + case_tested = False + for policy_key in policies.keys(): + policy = policies[policy_key] + for category_key in categories: + get_elements = get_method(policy_id=policy_key, category_id=category_key) + _all_data = [] + for _data in get_elements: + if category_key == _data["category_id"] and \ + policy_key == _data["policy_id"]: + _all_data.append(_data) + get_elements = _all_data + if not get_elements: + 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 + break + + 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 + break + + assert case_tested is True + + +def test_clean(): + from moon_utilities import json_utils + from moon_manager import db_driver + import_to_db = json_utils.JsonImport(driver_name="db", driver=db_driver) + _cache = import_to_db.driver + import_export_helper.clean_all() + assert not _cache.subject_categories + assert not _cache.object_categories + assert not _cache.action_categories + assert not _cache.subjects + assert not _cache.objects + assert not _cache.actions + assert not _cache.subject_data + assert not _cache.object_data + assert not _cache.action_data + assert not _cache.subject_assignments + assert not _cache.object_assignments + assert not _cache.action_assignments + assert not _cache.models + assert not _cache.pdp + assert not _cache.policies diff --git a/moon_utilities/tests/unit_python/api/test_invalidate_function.py b/moon_utilities/tests/unit_python/api/test_invalidate_function.py new file mode 100644 index 00000000..ed0357dc --- /dev/null +++ b/moon_utilities/tests/unit_python/api/test_invalidate_function.py @@ -0,0 +1,64 @@ +# 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 moon_utilities.invalided_functions + + +def test_invalidate_assignment_in_slaves(slaves): + result = moon_utilities.invalided_functions.invalidate_assignment_in_slaves( + slaves, "098764321", "098764321", "098764321", "098764321", 'subject') + assert result + assert "slave_test" in list(result) + + +def test_invalidate_data_in_slaves(slaves): + result = moon_utilities.invalided_functions.invalidate_data_in_slaves( + slaves, "__policy_id__", "__category_id__", "098764321", "subject") + assert result + assert "slave_test" in list(result) + + +def test_invalidate_perimeter_in_slaves(slaves): + result = moon_utilities.invalided_functions.invalidate_perimeter_in_slaves( + slaves, "098764321", "098764321", "subject", is_delete=False) + assert result + assert "slave_test" in list(result) + + +def test_invalidate_pdp_in_slaves(slaves): + result = moon_utilities.invalided_functions.invalidate_pdp_in_slaves( + slaves, "098764321", is_delete=False) + assert result + assert "slave_test" in list(result) + + +def test_invalidate_policy_in_slaves(slaves): + result = moon_utilities.invalided_functions.invalidate_policy_in_slaves( + slaves, "098764321", is_delete=False) + assert result + assert "slave_test" in list(result) + + +def test_invalidate_rules_in_slaves(): + pass + + +def test_invalidate_model_in_slaves(): + pass + + +def test_invalidate_meta_data_in_slaves(): + pass + + +def test_invalidate_meta_rule_in_slaves(): + pass diff --git a/moon_utilities/tests/unit_python/api/test_security_functions.py b/moon_utilities/tests/unit_python/api/test_security_functions.py new file mode 100644 index 00000000..469a70a2 --- /dev/null +++ b/moon_utilities/tests/unit_python/api/test_security_functions.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. + + +from moon_utilities.security_functions import enforce + + +def test_enforce(): + # TODO: implement the test + assert True diff --git a/moon_utilities/tests/unit_python/conftest.py b/moon_utilities/tests/unit_python/conftest.py new file mode 100644 index 00000000..da55d3ff --- /dev/null +++ b/moon_utilities/tests/unit_python/conftest.py @@ -0,0 +1,172 @@ +# 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 mock_slaves +import os +import pytest +import requests_mock +import yaml + + +__CONF = """ +debug: true + +database: + url: sqlite:////tmp/database_test.db + driver: moon_manager.plugins.sql + migration_dir: moon_manager.api.db.migrations + +dashboard: + root: ../dashboard/www/ + +management: + url: http://127.0.0.1:8000 + user: admin + password: admin + token_file: db.json + +orchestration: + driver: moon_manager.plugins.pyorchestrator + connection: local + port: 10000...10100 + config_dir: /tmp + +information: + 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: + 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] +""" + + +@pytest.fixture +def slaves(): + return { + "slaves": { + "d464cc58a0cd46dea3191ba70f4e7df8": { + "name": "slave_test", + "address": "", + "description": "...", + "extra": { + "description": "...", + "starttime": 1543851265.76279, + "port": 10000, + "server_ip": "127.0.0.1", + "status": "up", + "api_key": "e58a882a6b658a22660f00a0c273e7f6b4c4eb5abe54eccba2cae307905d67e374" + "6537bd790c41887e11840c2d186b6d6eeec0e426bcfa7a872cc3417a35124a" + } + } + } + } + + +@pytest.fixture(autouse=True) +def no_requests(monkeypatch): + """ Modify the response from Requests module + """ + with requests_mock.Mocker(real_http=True) as 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 + db_driver.init() + + mock_slaves.register_slaves(m) + + print("End registering URI") + + # from moon_manager.pip_driver import InformationManager + # InformationManager.set_auth() + + yield m + + # InformationManager.unset_auth() diff --git a/moon_utilities/tests/unit_python/helpers/__init__.py b/moon_utilities/tests/unit_python/helpers/__init__.py new file mode 100644 index 00000000..2a5459c2 --- /dev/null +++ b/moon_utilities/tests/unit_python/helpers/__init__.py @@ -0,0 +1,13 @@ +# 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_utilities/tests/unit_python/helpers/import_export_cache_helper.py b/moon_utilities/tests/unit_python/helpers/import_export_cache_helper.py new file mode 100644 index 00000000..ff22abe2 --- /dev/null +++ b/moon_utilities/tests/unit_python/helpers/import_export_cache_helper.py @@ -0,0 +1,234 @@ +# 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.manager.test.api." + __name__) + + +def clean_models(): + from moon_cache.cache import Cache + _cache = Cache.getInstance() + keys = list(_cache.models.keys()) + for key in keys: + _cache.delete_model(key) + + +def clean_policies(): + from moon_cache.cache import Cache + _cache = Cache.getInstance() + keys = list(_cache.policies.keys()) + for key in keys: + _cache.delete_policy(key) + + +def clean_subjects(): + from moon_cache.cache import Cache + _cache = Cache.getInstance() + + policy_keys = list(_cache.policies.keys()) + subjects = _cache.subjects + for policy_key in policy_keys: + for key in subjects: + try: + _cache.delete_subject(policy_key, key) + except AttributeError: + pass + _cache.delete_subject() + + +def clean_objects(): + from moon_cache.cache import Cache + _cache = Cache.getInstance() + + policy_keys = list(_cache.policies.keys()) + objects = _cache.objects + for policy_key in policy_keys: + for key in objects: + try: + _cache.delete_object(policy_key, key) + except AttributeError: + pass + _cache.delete_object() + + +def clean_actions(): + from moon_cache.cache import Cache + _cache = Cache.getInstance() + + policy_keys = list(_cache.policies.keys()) + actions = _cache.actions + for policy_key in policy_keys: + for key in actions: + try: + _cache.delete_action(policy_key, key) + except AttributeError: + pass + _cache.delete_action() + + +def clean_subject_categories(): + from moon_cache.cache import Cache + _cache = Cache.getInstance() + + categories = list(_cache.subject_categories.keys()) + for key in categories: + _cache.delete_subject_category(key) + + +def clean_object_categories(): + from moon_cache.cache import Cache + _cache = Cache.getInstance() + + categories = list(_cache.object_categories.keys()) + for key in categories: + _cache.delete_object_category(key) + + +def clean_action_categories(): + from moon_cache.cache import Cache + _cache = Cache.getInstance() + + categories = list(_cache.action_categories.keys()) + for key in categories: + _cache.delete_action_category(key) + + +def clean_subject_data(): + from moon_cache.cache import Cache + _cache = Cache.getInstance() + _cache.delete_subject_data() + + +def clean_object_data(): + from moon_cache.cache import Cache + _cache = Cache.getInstance() + _cache.delete_object_data() + + +def clean_action_data(): + from moon_cache.cache import Cache + _cache = Cache.getInstance() + _cache.delete_action_data() + + +def clean_meta_rule(): + from moon_cache.cache import Cache + _cache = Cache.getInstance() + + categories = list(_cache.meta_rules.keys()) + for key in categories: + _cache.delete_meta_rule(key) + + +def clean_subject_assignments(): + from moon_cache.cache import Cache + _cache = Cache.getInstance() + + if not _cache.subject_assignments: + return + for policy_key in _cache.policies.keys(): + if policy_key not in _cache.subject_assignments: + continue + for key in _cache.subject_assignments[policy_key]: + # policy_key = _cache.subject_assignments[policy_key][key]["policy_id"] + subject_key = _cache.subject_assignments[policy_key][key]["subject_id"] + cat_key = _cache.subject_assignments[policy_key][key]["category_id"] + data_keys = _cache.subject_assignments[policy_key][key]["assignments"] + for data_key in data_keys: + _cache.delete_subject_assignment( + policy_id=policy_key, + perimeter_id=subject_key, + category_id=cat_key, + data_id=data_key + ) + _cache.delete_subject_assignment() + + +def clean_object_assignments(): + from moon_cache.cache import Cache + _cache = Cache.getInstance() + + if not _cache.object_assignments: + return + for policy_key in _cache.policies.keys(): + if policy_key not in _cache.object_assignments: + continue + for key in _cache.object_assignments[policy_key]: + # policy_key = _cache.object_assignments[policy_key][key]["policy_id"] + object_key = _cache.object_assignments[policy_key][key]["object_id"] + cat_key = _cache.object_assignments[policy_key][key]["category_id"] + data_keys = _cache.object_assignments[policy_key][key]["assignments"] + for data_key in data_keys: + _cache.delete_object_assignment( + policy_id=policy_key, + perimeter_id=object_key, + category_id=cat_key, + data_id=data_key + ) + _cache.delete_object_assignment() + + +def clean_action_assignments(): + from moon_cache.cache import Cache + _cache = Cache.getInstance() + + if not _cache.action_assignments: + return + for policy_key in _cache.policies.keys(): + if policy_key not in _cache.action_assignments: + continue + for key in _cache.action_assignments[policy_key]: + action_key = _cache.action_assignments[policy_key][key]["action_id"] + cat_key = _cache.action_assignments[policy_key][key]["category_id"] + data_keys = _cache.action_assignments[policy_key][key]["assignments"] + for data_key in data_keys: + _cache.delete_action_assignment( + policy_id=policy_key, + perimeter_id=action_key, + category_id=cat_key, + data_id=data_key + ) + _cache.delete_action_assignment() + + +def clean_rules(): + from moon_cache.cache import Cache + _cache = Cache.getInstance() + + rules = list(_cache.rules.keys()) + for key in rules: + _cache.delete_rule(key) + + +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_utilities/tests/unit_python/helpers/import_export_db_helper.py b/moon_utilities/tests/unit_python/helpers/import_export_db_helper.py new file mode 100644 index 00000000..ecb9fa26 --- /dev/null +++ b/moon_utilities/tests/unit_python/helpers/import_export_db_helper.py @@ -0,0 +1,178 @@ +# 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.manager.test.api." + __name__) + + +def clean_models(): + from moon_manager import db_driver as driver + keys = driver.ModelManager.get_models(moon_user_id="admin") + for key in keys: + driver.ModelManager.delete_model(moon_user_id="admin", model_id=key) + + +def clean_policies(): + from moon_manager import db_driver as driver + keys = driver.PolicyManager.get_policies(moon_user_id="admin") + for key in keys: + driver.PolicyManager.delete_policy(moon_user_id="admin", policy_id=key) + + +def clean_subjects(): + from moon_manager import db_driver as driver + for policy in driver.PolicyManager.get_policies(moon_user_id="admin"): + subjects = driver.PolicyManager.get_subjects(moon_user_id="admin", policy_id=policy) + for key in subjects: + driver.PolicyManager.delete_subject(moon_user_id="admin", policy_id=policy, + perimeter_id=key) + + +def clean_objects(): + from moon_manager import db_driver as driver + for policy in driver.PolicyManager.get_policies(moon_user_id="admin"): + objects = driver.PolicyManager.get_objects(moon_user_id="admin", policy_id=policy) + for key in objects: + driver.PolicyManager.delete_object(moon_user_id="admin", policy_id=policy, + perimeter_id=key) + + +def clean_actions(): + from moon_manager import db_driver as driver + for policy in driver.PolicyManager.get_policies(moon_user_id="admin"): + actions = driver.PolicyManager.get_actions(moon_user_id="admin", policy_id=policy) + for key in actions: + driver.PolicyManager.delete_action(moon_user_id="admin", policy_id=policy, + perimeter_id=key) + + +def clean_subject_categories(): + from moon_manager import db_driver as driver + categories = driver.ModelManager.get_subject_categories(moon_user_id="admin") + + for key in categories: + driver.ModelManager.delete_subject_category(moon_user_id="admin", category_id=key) + + +def clean_object_categories(): + from moon_manager import db_driver as driver + categories = driver.ModelManager.get_object_categories(moon_user_id="admin") + + for key in categories: + driver.ModelManager.delete_object_category(moon_user_id="admin", category_id=key) + + +def clean_action_categories(): + from moon_manager import db_driver as driver + categories = driver.ModelManager.get_action_categories(moon_user_id="admin") + + for key in categories: + driver.ModelManager.delete_action_category(moon_user_id="admin", category_id=key) + + +def clean_subject_data(): + from moon_manager import db_driver as driver + policies = driver.PolicyManager.get_policies(moon_user_id="admin") + categories = driver.ModelManager.get_subject_categories(moon_user_id="admin") + for policy in policies: + for category in categories: + data_object = driver.PolicyManager.get_subject_data( + moon_user_id="admin", policy_id=policy, category_id=category) + for data_item in data_object: + for data in data_item.get("data", {}): + driver.PolicyManager.delete_subject_data(moon_user_id="admin", policy_id=policy, + category_id=category, data_id=data) + + +def clean_object_data(): + from moon_manager import db_driver as driver + policies = driver.PolicyManager.get_policies(moon_user_id="admin") + categories = driver.ModelManager.get_object_categories(moon_user_id="admin") + for policy in policies: + for category in categories: + data_object = driver.PolicyManager.get_object_data( + moon_user_id="admin", policy_id=policy, category_id=category) + for data_item in data_object: + for data in data_item.get("data", {}): + driver.PolicyManager.delete_object_data(moon_user_id="admin", policy_id=policy, + category_id=category, data_id=data) + + +def clean_action_data(): + from moon_manager import db_driver as driver + policies = driver.PolicyManager.get_policies(moon_user_id="admin") + categories = driver.ModelManager.get_action_categories(moon_user_id="admin") + for policy in policies: + for category in categories: + data_object = driver.PolicyManager.get_action_data( + moon_user_id="admin", policy_id=policy, category_id=category) + for data_item in data_object: + for data in data_item.get("data", {}): + driver.PolicyManager.delete_action_data(moon_user_id="admin", policy_id=policy, + category_id=category, data_id=data) + + +def clean_meta_rule(): + from moon_manager import db_driver as driver + keys = driver.ModelManager.get_meta_rules(moon_user_id="admin") + + for key in keys: + driver.ModelManager.delete_meta_rule(moon_user_id="admin", meta_rule_id=key) + + +def clean_subject_assignments(): + pass + + +def clean_object_assignments(): + pass + + +def clean_action_assignments(): + pass + + +def clean_rules(): + from moon_manager import db_driver as driver + + policies = driver.PolicyManager.get_policies(moon_user_id="admin") + + for policy in policies: + rules = driver.PolicyManager.get_rules(moon_user_id="admin", policy_id=policy) + + for rule in rules: + driver.PolicyManager.delete_rule(moon_user_id="admin", policy_id=policy, rule_id=rule) + + +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_utilities/tests/unit_python/helpers/slaves_helpers.py b/moon_utilities/tests/unit_python/helpers/slaves_helpers.py new file mode 100644 index 00000000..1b2764d2 --- /dev/null +++ b/moon_utilities/tests/unit_python/helpers/slaves_helpers.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. + + + +SLAVES = { + "slaves": { + "d464cc58a0cd46dea3191ba70f4e7df8": { + "name": "slave_test", + "address": "", + "description": "...", + "extra": { + "description": "...", + "starttime": 1543851265.76279, + "port": 10000, + "server_ip": "127.0.0.1", + "status": "down", + "api_key": "e58a882a6b658a22660f00a0c273e7f6b4c4eb5abe54eccba2cae307905d67e3746537" + "bd790c41887e11840c2d186b6d6eeec0e426bcfa7a872cc3417a35124a" + } + } + } +} + diff --git a/moon_utilities/tests/unit_python/mock_slaves.py b/moon_utilities/tests/unit_python/mock_slaves.py new file mode 100644 index 00000000..f3ac04d8 --- /dev/null +++ b/moon_utilities/tests/unit_python/mock_slaves.py @@ -0,0 +1,50 @@ +# 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_slaves(m): + m.register_uri( + 'DELETE', 'http://127.0.0.1:10000/update/assignment/098764321/subject/098764321/098764321/098764321', + json={} + ) + m.register_uri( + 'DELETE', 'http://127.0.0.1:10000/update/data/098764321/subject', + json={} + ) + m.register_uri( + 'PUT', 'http://127.0.0.1:10000/update/perimeter/098764321/098764321/subject', + json={} + ) + m.register_uri( + 'PUT', 'http://127.0.0.1:10000/update/pdp/098764321', + json={} + ) + m.register_uri( + 'PUT', 'http://127.0.0.1:10000/update/policy/098764321', + json={} + ) + m.register_uri( + 'PUT', 'http://127.0.0.1:10000/update/rules/1234567890', + json={} + ) + m.register_uri( + 'PUT', 'http://127.0.0.1:10000/update/model/1234567890', + json={} + ) + m.register_uri( + 'PUT', 'http://127.0.0.1:10000/update/meta_data/1234567890', + json={} + ) + m.register_uri( + 'PUT', 'http://127.0.0.1:10000/update/meta_rule/1234567890', + json={} + ) diff --git a/moon_utilities/tests/unit_python/requirements.txt b/moon_utilities/tests/unit_python/requirements.txt new file mode 100644 index 00000000..91cbc2c0 --- /dev/null +++ b/moon_utilities/tests/unit_python/requirements.txt @@ -0,0 +1,10 @@ +pytest +pbr +pytest-cov +cliff +requests_mock +tinydb +moon_manager +moon_cache +sqlalchemy +pymysql
\ No newline at end of file |