aboutsummaryrefslogtreecommitdiffstats
path: root/moonv4/moon_interface/moon_interface/api/authz.py
diff options
context:
space:
mode:
Diffstat (limited to 'moonv4/moon_interface/moon_interface/api/authz.py')
-rw-r--r--moonv4/moon_interface/moon_interface/api/authz.py244
1 files changed, 225 insertions, 19 deletions
diff --git a/moonv4/moon_interface/moon_interface/api/authz.py b/moonv4/moon_interface/moon_interface/api/authz.py
index 69de0f80..3847cc73 100644
--- a/moonv4/moon_interface/moon_interface/api/authz.py
+++ b/moonv4/moon_interface/moon_interface/api/authz.py
@@ -6,23 +6,194 @@
Authz is the endpoint to get authorization response
"""
-from uuid import uuid4
-import time
+from flask import request
from flask_restful import Resource
-from oslo_log import log as logging
-from moon_utilities.security_functions import call
+import logging
+import pickle
+import requests
+import time
+from uuid import uuid4
+
+from moon_interface.containers import DockerManager
+from moon_interface.authz_requests import AuthzRequest
+from moon_utilities import configuration
__version__ = "0.1.0"
LOG = logging.getLogger("moon.interface.api." + __name__)
+def pdp_in_cache(cache, uuid):
+ """Check if a PDP exist with this Keystone Project ID in the cache of this component
+
+ :param cache: Cache to use
+ :param uuid: Keystone Project ID
+ :return: True or False
+ """
+ for item_uuid, item_value in cache.pdp.items():
+ if uuid == item_value['keystone_project_id']:
+ return item_uuid, item_value
+ return None, None
+
+
+def pdp_in_manager(cache, uuid):
+ """Check if a PDP exist with this Keystone Project ID in the Manager component
+
+ :param cache: Cache to use
+ :param uuid: Keystone Project ID
+ :return: True or False
+ """
+ cache.update()
+ return pdp_in_cache(cache, uuid)
+
+
+def container_exist(cache, uuid):
+ """Check if a PDP exist with this Keystone Project ID in the Manager component
+
+ :param cache: Cache to use
+ :param uuid: Keystone Project ID
+ :return: True or False
+ """
+ for key, value in cache.containers.items():
+ if "keystone_project_id" not in value:
+ continue
+ if value["keystone_project_id"] == uuid:
+ try:
+ req = requests.head("http://{}:{}/".format(
+ value.get("hostname"),
+ value.get("port")[0].get("PublicPort")))
+ LOG.info("container_exist {}".format(req.status_code))
+ if req.status_code in (200, 201):
+ return value
+ return
+ except requests.exceptions.ConnectionError:
+ pass
+ # maybe hostname is not working so trying with IP address
+ try:
+ req = requests.head("http://{}:{}/".format(
+ value.get("ip"),
+ value.get("port")[0].get("PublicPort")))
+ if req.status_code in (200, 201):
+ return value
+ return
+ except requests.exceptions.ConnectionError:
+ return
+
+
+def build_container(cache, manager_url, uuid, meta_rule_id, plugin_name="authz"):
+ """Create the container and update the cache with the given perimeter elements
+
+ :param cache: Cache to use
+ :param manager_url: URL of the manager
+ :param uuid: Keystone Project ID
+ :param meta_rule_id: UUID of the meta_rule
+ :param plugin_name: name of the plugin to use
+ :return: True or False
+ """
+ LOG.info("Building a new container for {}".format(plugin_name))
+ manager = DockerManager()
+ tcp_port = configuration.increment_port()
+ container_name = configuration.get_plugins()[plugin_name]['container']
+ name = "{}_{}".format(plugin_name, uuid4().hex)
+ policy_id = cache.get_policy_from_meta_rules(meta_rule_id)
+ container_data = {
+ "name": name,
+ "hostname": name,
+ "port": {
+ "PrivatePort": tcp_port,
+ "Type": "tcp",
+ "IP": "0.0.0.0",
+ "PublicPort": tcp_port
+ },
+ "keystone_project_id": uuid,
+ "pdp_id": cache.get_pdp_from_keystone_project(uuid),
+ "meta_rule_id": meta_rule_id,
+ "policy_id": policy_id,
+ "container_name": container_name,
+ "plugin_name": plugin_name
+ }
+ container = manager.create_container(container_data)
+ container_data['container_id'] = container.id
+ container_data['port']["IP"] = container.ip
+ container_data['start_time'] = time.time()
+ req = requests.post("{}/containers".format(manager_url),
+ json=container_data)
+ if req.status_code == 200:
+ cache.add_container(container_data)
+ return True
+
+
+def create_containers(cache, manager_url, uuid, plugin_name="authz"):
+ """Create the container and update the cache with the given perimeter elements
+
+ :param cache: Cache to use
+ :param manager_url: URL of the manager
+ :param uuid: Keystone Project ID
+ :param plugin_name: name of the plugin to use
+ :return: True or False
+ """
+ LOG.info("Need to create some containers for {}".format(uuid))
+ for pdp_id, pdp_value in cache.pdp.items():
+ LOG.info("pdp {}".format(pdp_value))
+ if uuid == pdp_value.get("keystone_project_id", ""):
+ LOG.info("uuid {}".format(uuid))
+ for policy_id in pdp_value.get("security_pipeline", []):
+ LOG.info("policy {}".format(policy_id))
+ model_id = cache.policies[policy_id]["model_id"]
+ model_value = cache.models[model_id]
+ for meta_rule_id in model_value["meta_rules"]:
+ LOG.info("meta_rule {}".format(meta_rule_id))
+ build_container(
+ cache=cache,
+ uuid=uuid,
+ manager_url=manager_url,
+ meta_rule_id=meta_rule_id,
+ plugin_name=plugin_name)
+ return
+
+
+def create_authz_request(cache, interface_name, manager_url, uuid, subject_name, object_name, action_name):
+ """Create the authorization request and make the first call to the Authz function
+
+ :param cache: Cache to use
+ :param interface_name: hostname of the interface
+ :param manager_url: URL of the manager
+ :param uuid: Keystone Project ID
+ :param subject_name: name of the subject
+ :param object_name: name of the object
+ :param action_name: name of the action
+ :return: Authorisation request
+ """
+ req_id = uuid4().hex
+ ctx = {
+ "project_id": uuid,
+ "subject_name": subject_name,
+ "object_name": object_name,
+ "action_name": action_name,
+ "request_id": req_id,
+ "interface_name": interface_name,
+ "manager_url": manager_url,
+ "cookie": uuid4().hex
+ }
+ cache.authz_requests[req_id] = AuthzRequest(ctx)
+ return cache.authz_requests[req_id]
+
+
class Authz(Resource):
"""
Endpoint for authz requests
"""
- __urls__ = ("/authz/<string:uuid>/<string:subject_name>/<string:object_name>/<string:action_name>", )
+ __urls__ = (
+ "/authz/<string:uuid>",
+ "/authz/<string:uuid>/<string:subject_name>/<string:object_name>/<string:action_name>",
+ )
+
+ def __init__(self, **kwargs):
+ self.CACHE = kwargs.get("cache")
+ self.INTERFACE_NAME = kwargs.get("interface_name", "interface")
+ self.MANAGER_URL = kwargs.get("manager_url", "http://manager:8080")
+ self.TIMEOUT = 5
def get(self, uuid=None, subject_name=None, object_name=None, action_name=None):
"""Get a response on an authorization request
@@ -51,17 +222,52 @@ class Authz(Resource):
}
:internal_api: authz
"""
- # Note (asteroide): user_id default to admin to be able to read the database
- # it would be better to have a read-only user.
- start_time = time.time()
- result = call("security_router", ctx={"id": uuid,
- "call_master": False,
- "method": "authz",
- "subject_name": subject_name,
- "object_name": object_name,
- "action_name": action_name,
- "user_id": "admin",
- "request_id": uuid4().hex}, args={})
- end_time = time.time()
- result['time'] = {"start": start_time, "end": end_time}
- return result
+ pdp_id, pdp_value = pdp_in_cache(self.CACHE, uuid)
+ if not pdp_id:
+ pdp_id, pdp_value = pdp_in_manager(self.CACHE, uuid)
+ if not pdp_id:
+ return {
+ "result": False,
+ "message": "Unknown Project ID or "
+ "Project ID is not bind to a PDP."}, 403
+ if not container_exist(self.CACHE, uuid):
+ create_containers(
+ cache=self.CACHE,
+ uuid=uuid,
+ manager_url=self.MANAGER_URL,
+ plugin_name="authz")
+ authz_request = create_authz_request(
+ cache=self.CACHE,
+ uuid=uuid,
+ interface_name=self.INTERFACE_NAME,
+ manager_url=self.MANAGER_URL,
+ subject_name=subject_name,
+ object_name=object_name,
+ action_name=action_name)
+ cpt = 0
+ while True:
+ if cpt > self.TIMEOUT*10:
+ return {"result": False,
+ "message": "Authz request had timed out."}, 500
+ if authz_request.is_authz():
+ if authz_request.final_result == "Grant":
+ return {"result": True, "message": ""}, 200
+ return {"result": False, "message": ""}, 401
+ cpt += 1
+ time.sleep(0.1)
+
+ def patch(self, uuid=None, subject_name=None, object_name=None, action_name=None):
+ """Get a response on an authorization request
+
+ :param uuid: uuid of the authorization request
+ :param subject_name: not used
+ :param object_name: not used
+ :param action_name: not used
+ :request body: a Context object
+ :return: {}
+ :internal_api: authz
+ """
+ if uuid in self.CACHE.authz_requests:
+ self.CACHE.authz_requests[uuid].set_result(pickle.loads(request.data))
+ return "", 201
+ return {"result": False, "message": "The request ID is unknown"}, 500