Commit a7e58fb4 authored by Stavros-Anastasios Charismiadis's avatar Stavros-Anastasios Charismiadis
Browse files

Merge with staging, Fix publish according to vendor extensibility testing...

Merge with staging, Fix publish according to vendor extensibility testing plan, fix discover taking suppfeat into consideration
parents 4bb65e78 9c1640e1
Loading
Loading
Loading
Loading
Loading
+58 −32
Original line number Diff line number Diff line
@@ -3,18 +3,21 @@ from pymongo import ReturnDocument
import secrets
import requests
from .responses import bad_request_error, not_found_error, forbidden_error, internal_server_error, make_response
from flask import current_app, Flask, Response
from flask import current_app, Response
import json
from datetime import datetime
from ..util import dict_to_camel_case, clean_empty, serialize_clean_camel_case
from ..util import dict_to_camel_case, serialize_clean_camel_case
from .auth_manager import AuthManager
from .resources import Resource
from ..config import Config
from api_invoker_management.models.api_invoker_enrolment_details import APIInvokerEnrolmentDetails
from .redis_event import RedisEvent
from .redis_internal_event import RedisInternalEvent
from .publisher import Publisher

publisher_ops = Publisher()


class InvokerManagementOperations(Resource):

    def __check_api_invoker_id(self, api_invoker_id):
@@ -41,7 +44,8 @@ class InvokerManagementOperations(Resource):
            'common_name': invoker_id
        }

        response = requests.request("POST", url, headers=headers, data=data, verify = self.config["ca_factory"].get("verify", False))
        response = requests.request("POST", url, headers=headers, data=data,
                                    verify=self.config["ca_factory"].get("verify", False))
        print(response)
        response_payload = json.loads(response.text)

@@ -52,17 +56,18 @@ class InvokerManagementOperations(Resource):
        self.auth_manager = AuthManager()
        self.config = Config().get_config()


    def add_apiinvokerenrolmentdetail(self, apiinvokerenrolmentdetail, username, uuid):

        mycol = self.db.get_col_by_name(self.db.invoker_enrolment_details)

        # try:
        current_app.logger.debug("Creating invoker resource")
        res = mycol.find_one({'onboarding_information.api_invoker_public_key': apiinvokerenrolmentdetail.onboarding_information.api_invoker_public_key})
        res = mycol.find_one({'onboarding_information.api_invoker_public_key':
                             apiinvokerenrolmentdetail.onboarding_information.api_invoker_public_key})

        if res is not None:
            current_app.logger.error("Generating forbbiden error, invoker registered")
            current_app.logger.error(
                "Generating forbbiden error, invoker registered")
            return forbidden_error(detail="Invoker already registered", cause="Identical invoker public key")

        if rfc3987.match(apiinvokerenrolmentdetail.notification_destination, rule="URI") is None:
@@ -72,11 +77,13 @@ class InvokerManagementOperations(Resource):
        current_app.logger.debug("Signing Certificate")

        api_invoker_id = 'INV'+str(secrets.token_hex(15))
        cert = self.__sign_cert(apiinvokerenrolmentdetail.onboarding_information.api_invoker_public_key, api_invoker_id)
        cert = self.__sign_cert(
            apiinvokerenrolmentdetail.onboarding_information.api_invoker_public_key, api_invoker_id)

        apiinvokerenrolmentdetail.api_invoker_id = api_invoker_id
        current_app.logger.debug(cert)
        apiinvokerenrolmentdetail.onboarding_information.api_invoker_certificate = cert['data']['certificate']
        apiinvokerenrolmentdetail.onboarding_information.api_invoker_certificate = cert[
            'data']['certificate']

        # Onboarding Date Record
        invoker_dict = apiinvokerenrolmentdetail.to_dict()
@@ -89,14 +96,19 @@ class InvokerManagementOperations(Resource):
        current_app.logger.debug("Invoker inserted in database")
        current_app.logger.debug("Netapp onboarded sucessfuly")

        self.auth_manager.add_auth_invoker(cert['data']['certificate'], api_invoker_id)
        self.auth_manager.add_auth_invoker(
            cert['data']['certificate'], api_invoker_id)

        res = make_response(object=serialize_clean_camel_case(apiinvokerenrolmentdetail), status=201)
        res.headers['Location'] = "/api-invoker-management/v1/onboardedInvokers/" + str(api_invoker_id)
        res = make_response(object=serialize_clean_camel_case(
            apiinvokerenrolmentdetail), status=201)
        res.headers['Location'] = "/api-invoker-management/v1/onboardedInvokers/" + \
            str(api_invoker_id)

        if res.status_code == 201:
            current_app.logger.info("Invoker Created")
            RedisEvent("API_INVOKER_ONBOARDED", ["apiInvokerIds"], [[str(api_invoker_id)]]).send_event()
            RedisEvent("API_INVOKER_ONBOARDED",
                       ["apiInvokerIds"],
                       [[str(api_invoker_id)]]).send_event()
        return res

    def update_apiinvokerenrolmentdetail(self, onboard_id, apiinvokerenrolmentdetail):
@@ -111,16 +123,23 @@ class InvokerManagementOperations(Resource):
                return result

            if apiinvokerenrolmentdetail.onboarding_information.api_invoker_public_key != result["onboarding_information"]["api_invoker_public_key"]:
                cert = self.__sign_cert(apiinvokerenrolmentdetail.onboarding_information.api_invoker_public_key, result["api_invoker_id"])
                apiinvokerenrolmentdetail.onboarding_information.api_invoker_certificate = cert['data']['certificate']
                self.auth_manager.update_auth_invoker(cert['data']["certificate"], onboard_id)
                cert = self.__sign_cert(
                    apiinvokerenrolmentdetail.onboarding_information.api_invoker_public_key, result["api_invoker_id"])
                apiinvokerenrolmentdetail.onboarding_information.api_invoker_certificate = cert[
                    'data']['certificate']
                self.auth_manager.update_auth_invoker(
                    cert['data']["certificate"], onboard_id)

            apiinvokerenrolmentdetail_update = apiinvokerenrolmentdetail.to_dict()
            apiinvokerenrolmentdetail_update = {
                key: value for key, value in apiinvokerenrolmentdetail_update.items() if value is not None
            }

            result = mycol.find_one_and_update(result, {"$set":apiinvokerenrolmentdetail_update}, projection={'_id': 0},return_document=ReturnDocument.AFTER ,upsert=False)
            result = mycol.find_one_and_update(result,
                                               {"$set": apiinvokerenrolmentdetail_update},
                                               projection={'_id': 0},
                                               return_document=ReturnDocument.AFTER,
                                               upsert=False)

            result = {
                key: value for key, value in result.items() if value is not None
@@ -130,10 +149,13 @@ class InvokerManagementOperations(Resource):

            invoker_updated = APIInvokerEnrolmentDetails().from_dict(dict_to_camel_case(result))

            res = make_response(object=serialize_clean_camel_case(invoker_updated), status=200)
            res = make_response(object=serialize_clean_camel_case(
                invoker_updated), status=200)
            if res.status_code == 200:
                current_app.logger.info("Invoker Updated")
                RedisEvent("API_INVOKER_UPDATED", ["apiInvokerIds"], [[onboard_id]]).send_event()
                RedisEvent("API_INVOKER_UPDATED",
                           ["apiInvokerIds"],
                           [[onboard_id]]).send_event()
            return res

        except Exception as e:
@@ -160,13 +182,17 @@ class InvokerManagementOperations(Resource):
            res = make_response(out, status=204)
            if res.status_code == 204:
                current_app.logger.info("Invoker Removed")
                RedisEvent("API_INVOKER_OFFBOARDED", ["apiInvokerIds"], [[onboard_id]]).send_event()
                publisher_ops.publish_message("internal-messages", f"invoker-removed:{onboard_id}")
                RedisEvent("API_INVOKER_OFFBOARDED",
                           ["apiInvokerIds"],
                           [[onboard_id]]).send_event()
                RedisInternalEvent("INVOKER-REMOVED",
                                   "invokerId",
                                   {
                                       "api_invoker_id": onboard_id
                                   }).send_event()
            return res

        except Exception as e:
            exception = "An exception occurred in remove invoker"
            current_app.logger.error(exception + "::" + str(e))
            return internal_server_error(detail=exception, cause=str(e))

+37 −10
Original line number Diff line number Diff line
@@ -2,6 +2,8 @@
import redis
from .invoker_internal_ops import InvokerInternalOperations
from flask import current_app
import json


class Subscriber():

@@ -14,13 +16,38 @@ class Subscriber():
    def listen(self):
        for raw_message in self.p.listen():
            if raw_message["type"] == "message" and raw_message["channel"].decode('utf-8') == "internal-messages":
                message, invoker_id, api_id = raw_message["data"].decode('utf-8').split(":")
                if message == "security-context-created":
                    current_app.logger.debug("Internal message received, updating Api list on invoker")
                    self.invoker_ops.update_services_list(invoker_id, api_id)
                if message == "security-context-removed":
                    current_app.logger.debug("Internal message received, removing service in  Api list of invoker")
                    self.invoker_ops.remove_services_list(invoker_id, api_id)


                current_app.logger.info("New internal event received")
                internal_redis_event = json.loads(
                    raw_message["data"].decode('utf-8'))
                if internal_redis_event.get('event') == "SECURITY-CONTEXT-CREATED":
                    current_app.logger.debug(
                        "Internal message received, updating Api list on invoker")
                    security_context_information = internal_redis_event.get(
                        'information', None)
                    if security_context_information is not None:
                        api_invoker_id = security_context_information.get(
                            'api_invoker_id')
                        api_id = security_context_information.get('api_id')
                        self.invoker_ops.update_services_list(
                            api_invoker_id, api_id)
                elif internal_redis_event.get('event') == "SECURITY-CONTEXT-REMOVED":
                    current_app.logger.debug(
                        "Internal message received, removing service in  Api list of invoker")
                    security_context_information = internal_redis_event.get(
                        'information', None)
                    if security_context_information is not None:
                        api_invoker_id = security_context_information.get(
                            'api_invoker_id')
                        api_id = security_context_information.get('api_id')
                        self.invoker_ops.remove_services_list(
                            api_invoker_id, api_id)
                elif internal_redis_event.get('event') == "INVOKER-REMOVED":
                    api_invoker_id = internal_redis_event.get(
                        'information', {"api_invoker_id": None}).get('api_invoker_id')
                    if api_invoker_id is not None:
                        self.acls_ops.remove_invoker_acl(api_invoker_id)
                elif internal_redis_event.get('event') == "PROVIDER-REMOVED":
                    aef_ids = internal_redis_event.get(
                        'information', {"aef_ids": []}).get('aef_ids')
                    if len(aef_ids) > 0:
                        self.acls_ops.remove_provider_acls(aef_ids[0])
+35 −0
Original line number Diff line number Diff line
from ..encoder import JSONEncoder
from .publisher import Publisher
import json

publisher_ops = Publisher()


class RedisInternalEvent():
    def __init__(self, event, event_detail_key=None, information=None) -> None:
        self.INTERNAL_MESSAGES = [
            'INVOKER-REMOVED',
            'PROVIDER-REMOVED',
            'SECURITY-CONTEXT-CREATED',
            'SECURITY-CONTEXT-REMOVED',
            'create-acl',
            'remove-acl',
        ]
        if event not in self.INTERNAL_MESSAGES:
            raise Exception(
                "Internal Message (" + event + ") is not on INTERNAL_MESSAGES enum (" + ','.join(self.INTERNAL_MESSAGES) + ")")
        self.redis_event = {
            "event": event
        }
        if event_detail_key is not None and information is not None:
            self.redis_event['key'] = event_detail_key
            self.redis_event['information'] = information

    def to_string(self):
        return json.dumps(self.redis_event, cls=JSONEncoder)

    def send_event(self):
        publisher_ops.publish_message("internal-messages", self.to_string())

    def __call__(self):
        return self.redis_event
+57 −25
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@ from .resources import Resource
from .auth_manager import AuthManager

from api_provider_management.models.api_provider_enrolment_details import APIProviderEnrolmentDetails  # noqa: E501
from .redis_internal_event import RedisInternalEvent


class ProviderManagementOperations(Resource):
@@ -40,19 +41,24 @@ class ProviderManagementOperations(Resource):
            my_provider_enrolment_details = mycol.find_one(search_filter)

            if my_provider_enrolment_details is not None:
                current_app.logger.error("Found provider registered with same id")
                current_app.logger.error(
                    "Found provider registered with same id")
                return forbidden_error(detail="Provider already registered", cause="Identical provider reg sec")

            api_provider_enrolment_details.api_prov_dom_id = secrets.token_hex(15)
            api_provider_enrolment_details.api_prov_dom_id = secrets.token_hex(
                15)

            current_app.logger.debug("Generating certs to api prov funcs")

            for api_provider_func in api_provider_enrolment_details.api_prov_funcs:
                api_provider_func.api_prov_func_id = api_provider_func.api_prov_func_role + str(secrets.token_hex(15))
                certificate = sign_certificate(api_provider_func.reg_info.api_prov_pub_key, api_provider_func.api_prov_func_id)
                api_provider_func.api_prov_func_id = api_provider_func.api_prov_func_role + \
                    str(secrets.token_hex(15))
                certificate = sign_certificate(
                    api_provider_func.reg_info.api_prov_pub_key, api_provider_func.api_prov_func_id)
                api_provider_func.reg_info.api_prov_cert = certificate

                self.auth_manager.add_auth_provider(certificate, api_provider_func.api_prov_func_id, api_provider_func.api_prov_func_role, api_provider_enrolment_details.api_prov_dom_id)
                self.auth_manager.add_auth_provider(certificate, api_provider_func.api_prov_func_id,
                                                    api_provider_func.api_prov_func_role, api_provider_enrolment_details.api_prov_dom_id)

            # Onboarding Date Record
            provider_dict = api_provider_enrolment_details.to_dict()
@@ -64,9 +70,11 @@ class ProviderManagementOperations(Resource):

            current_app.logger.debug("Provider inserted in database")

            res = make_response(object=serialize_clean_camel_case(api_provider_enrolment_details), status=201)
            res = make_response(object=serialize_clean_camel_case(
                api_provider_enrolment_details), status=201)

            res.headers['Location'] = "/api-provider-management/v1/registrations/" + str(api_provider_enrolment_details.api_prov_dom_id)
            res.headers['Location'] = "/api-provider-management/v1/registrations/" + \
                str(api_provider_enrolment_details.api_prov_dom_id)
            return res

        except Exception as e:
@@ -84,17 +92,32 @@ class ProviderManagementOperations(Resource):
            if isinstance(result, Response):
                return result

            apf_id = [ provider_func['api_prov_func_id'] for provider_func in result["api_prov_funcs"] if provider_func['api_prov_func_role'] == 'APF' ]
            aef_id = [ provider_func['api_prov_func_id'] for provider_func in result["api_prov_funcs"] if provider_func['api_prov_func_role'] == 'AEF' ]
            amf_id = [ provider_func['api_prov_func_id'] for provider_func in result["api_prov_funcs"] if provider_func['api_prov_func_role'] == 'AMF' ]
            func_ids = list()
            for provider_func in result["api_prov_funcs"]:
                func_ids.append(provider_func['api_prov_func_id'])
            apf_ids = [provider_func['api_prov_func_id']
                       for provider_func in result["api_prov_funcs"] if provider_func['api_prov_func_role'] == 'APF']
            aef_ids = [provider_func['api_prov_func_id']
                       for provider_func in result["api_prov_funcs"] if provider_func['api_prov_func_role'] == 'AEF']
            amf_ids = [provider_func['api_prov_func_id']
                       for provider_func in result["api_prov_funcs"] if provider_func['api_prov_func_role'] == 'AMF']

            mycol.delete_one({'api_prov_dom_id': api_prov_dom_id})
            out =  "The provider matching apiProvDomainId  " + api_prov_dom_id + " was offboarded."
            out = "The provider matching apiProvDomainId  " + \
                api_prov_dom_id + " was offboarded."
            current_app.logger.debug("Removed provider domain from database")

            self.auth_manager.remove_auth_provider([apf_id[0], aef_id[0], amf_id[0]])
            self.auth_manager.remove_auth_provider(func_ids)

            RedisInternalEvent("PROVIDER-REMOVED",
                               "providerIds",
                               {
                                   "apf_ids": apf_ids,
                                   "aef_ids": aef_ids,
                                   "amf_ids": amf_ids,
                                   "all_ids": apf_ids + aef_ids + amf_ids
                               }).send_event()

            self.publish_ops.publish_message("internal-messages", f"provider-removed:{aef_id[0]}:{apf_id[0]}:{amf_id[0]}")
            return make_response(object=out, status=204)

        except Exception as e:
@@ -114,11 +137,14 @@ class ProviderManagementOperations(Resource):

            for func in api_provider_enrolment_details.api_prov_funcs:
                if func.api_prov_func_id is None:
                    func.api_prov_func_id = func.api_prov_func_role + str(secrets.token_hex(15))
                    certificate = sign_certificate(func.reg_info.api_prov_pub_key, func.api_prov_func_id)
                    func.api_prov_func_id = func.api_prov_func_role + \
                        str(secrets.token_hex(15))
                    certificate = sign_certificate(
                        func.reg_info.api_prov_pub_key, func.api_prov_func_id)
                    func.reg_info.api_prov_cert = certificate

                    self.auth_manager.update_auth_provider(certificate, func.api_prov_func_id, api_prov_dom_id, func.api_prov_func_role)
                    self.auth_manager.update_auth_provider(
                        certificate, func.api_prov_func_id, api_prov_dom_id, func.api_prov_func_role)
                else:
                    api_prov_funcs = result["api_prov_funcs"]
                    for api_func in api_prov_funcs:
@@ -126,14 +152,18 @@ class ProviderManagementOperations(Resource):
                            if func.api_prov_func_role != api_func["api_prov_func_role"]:
                                return bad_request_error(detail="Bad Role in provider", cause="Different role in update reqeuest", invalid_params=[{"param": "api_prov_func_role", "reason": "different role with same id"}])
                            if func.reg_info.api_prov_pub_key != api_func["reg_info"]["api_prov_pub_key"]:
                                certificate = sign_certificate(func.reg_info.api_prov_pub_key, api_func["api_prov_func_id"])
                                certificate = sign_certificate(
                                    func.reg_info.api_prov_pub_key, api_func["api_prov_func_id"])
                                func.reg_info.api_prov_cert = certificate
                                self.auth_manager.update_auth_provider(certificate, func.api_prov_func_id, api_prov_dom_id, func.api_prov_func_role)
                                self.auth_manager.update_auth_provider(
                                    certificate, func.api_prov_func_id, api_prov_dom_id, func.api_prov_func_role)

            api_provider_enrolment_details = api_provider_enrolment_details.to_dict()
            api_provider_enrolment_details = clean_empty(api_provider_enrolment_details)
            api_provider_enrolment_details = clean_empty(
                api_provider_enrolment_details)

            result = mycol.find_one_and_update(result, {"$set":api_provider_enrolment_details}, projection={'_id': 0},return_document=ReturnDocument.AFTER ,upsert=False)
            result = mycol.find_one_and_update(result, {"$set": api_provider_enrolment_details}, projection={
                                               '_id': 0}, return_document=ReturnDocument.AFTER, upsert=False)
            result = clean_empty(result)

            current_app.logger.debug("Provider domain updated in database")
@@ -157,9 +187,11 @@ class ProviderManagementOperations(Resource):
                return result

            api_provider_enrolment_details_patch = api_provider_enrolment_details_patch.to_dict()
            api_provider_enrolment_details_patch = clean_empty(api_provider_enrolment_details_patch)
            api_provider_enrolment_details_patch = clean_empty(
                api_provider_enrolment_details_patch)

            result = mycol.find_one_and_update(result, {"$set":api_provider_enrolment_details_patch}, projection={'_id': 0},return_document=ReturnDocument.AFTER ,upsert=False)
            result = mycol.find_one_and_update(result, {"$set": api_provider_enrolment_details_patch}, projection={
                                               '_id': 0}, return_document=ReturnDocument.AFTER, upsert=False)

            result = clean_empty(result)

+35 −0
Original line number Diff line number Diff line
from ..encoder import JSONEncoder
from .publisher import Publisher
import json

publisher_ops = Publisher()


class RedisInternalEvent():
    def __init__(self, event, event_detail_key=None, information=None) -> None:
        self.INTERNAL_MESSAGES = [
            'INVOKER-REMOVED',
            'PROVIDER-REMOVED',
            'SECURITY-CONTEXT-CREATED',
            'SECURITY-CONTEXT-REMOVED',
            'create-acl',
            'remove-acl',
        ]
        if event not in self.INTERNAL_MESSAGES:
            raise Exception(
                "Internal Message (" + event + ") is not on INTERNAL_MESSAGES enum (" + ','.join(self.INTERNAL_MESSAGES) + ")")
        self.redis_event = {
            "event": event
        }
        if event_detail_key is not None and information is not None:
            self.redis_event['key'] = event_detail_key
            self.redis_event['information'] = information

    def to_string(self):
        return json.dumps(self.redis_event, cls=JSONEncoder)

    def send_event(self):
        publisher_ops.publish_message("internal-messages", self.to_string())

    def __call__(self):
        return self.redis_event
Loading