Commit 68ec4e06 authored by Jorge Moratinos's avatar Jorge Moratinos
Browse files

Updated all related logic of cert check and authorization on publish, and minor fix on provider

parent a30f7154
Loading
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -84,6 +84,9 @@ class ProviderManagementOperations(Resource):
            if isinstance(result, Response):
                return result

            func_ids = list()
            for provider_func in result["api_prov_funcs"]:
                func_ids.append(provider_func['api_prov_func_id'])
            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' ]
@@ -92,7 +95,7 @@ class ProviderManagementOperations(Resource):
            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)

            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)
+16 −7
Original line number Diff line number Diff line
@@ -30,8 +30,11 @@ def cert_validation():

            if cn != "superadmin":
                cert_signature = cert.signature.hex()
                service_api_id = None
                if 'serviceApiId' in args:
                    service_api_id = args["serviceApiId"]
                result = valid_user.validate_user_cert(
                    args["apfId"], args["serviceApiId"], cert_signature)
                    args["apfId"], cert_signature, service_api_id)

                if result is not None:
                    return result
@@ -46,7 +49,8 @@ def cert_validation():
        return __cert_validation
    return _cert_validation

# @cert_validation()

@cert_validation()
def apf_id_service_apis_get(apf_id):  # noqa: E501
    """apf_id_service_apis_get

@@ -62,7 +66,8 @@ def apf_id_service_apis_get(apf_id): # noqa: E501

    return res

# @cert_validation()

@cert_validation()
def apf_id_service_apis_post(apf_id, body):  # noqa: E501
    """apf_id_service_apis_post

@@ -77,7 +82,8 @@ def apf_id_service_apis_post(apf_id, body): # noqa: E501
    """
    current_app.logger.info("Publishing service")

    supp_feat_dict = ServiceAPIDescription.return_supp_feat_dict(body['supportedFeatures'])
    supp_feat_dict = ServiceAPIDescription.return_supp_feat_dict(
        body['supportedFeatures'])

    vendor_specific = []
    if request.is_json:
@@ -90,7 +96,8 @@ def apf_id_service_apis_post(apf_id, body): # noqa: E501

        body = ServiceAPIDescription.from_dict(request.get_json())

    res = service_operations.add_serviceapidescription(apf_id, body, vendor_specific)
    res = service_operations.add_serviceapidescription(
        apf_id, body, vendor_specific)

    return res

@@ -114,6 +121,7 @@ def apf_id_service_apis_service_api_id_delete(service_api_id, apf_id): # noqa:

    return res


@cert_validation()
def apf_id_service_apis_service_api_id_get(service_api_id, apf_id):  # noqa: E501
    """apf_id_service_apis_service_api_id_get
@@ -132,6 +140,7 @@ def apf_id_service_apis_service_api_id_get(service_api_id, apf_id): # noqa: E50

    return res


@cert_validation()
def apf_id_service_apis_service_api_id_put(service_api_id, apf_id, body):  # noqa: E501
    """apf_id_service_apis_service_api_id_put
+65 −45
Original line number Diff line number Diff line
from pymongo import ReturnDocument
import secrets
from flask import current_app, Flask, Response
from flask import current_app

from .resources import Resource
from datetime import datetime
from ..util import dict_to_camel_case, clean_empty, serialize_clean_camel_case,clean_n_camel_case
from ..util import dict_to_camel_case, clean_empty, clean_n_camel_case
from .responses import internal_server_error, forbidden_error, not_found_error, unauthorized_error, make_response
from .auth_manager import AuthManager
from .redis_event import RedisEvent
@@ -27,13 +27,17 @@ class PublishServiceOperations(Resource):

        if provider is None:
            current_app.logger.error("Publisher not exist")
            return unauthorized_error(detail="Publisher not existing", cause="Publisher id not found")
            return unauthorized_error(
                detail="Publisher not existing",
                cause="Publisher id not found")

        list_apf_ids = [func["api_prov_func_id"]
                        for func in provider["api_prov_funcs"] if func["api_prov_func_role"] == "APF"]
        if apf_id not in list_apf_ids:
            current_app.logger.debug("This id not belongs to APF")
            return unauthorized_error(detail="You are not a publisher", cause="This API is only available for publishers")
            return unauthorized_error(
                detail="You are not a publisher",
                cause="This API is only available for publishers")

        return None

@@ -49,13 +53,19 @@ class PublishServiceOperations(Resource):

            current_app.logger.debug("Geting service apis")

            # result = self.__check_apf(apf_id)

            # if result != None:
            #     return result

            service = mycol.find({"apf_id": apf_id}, {"_id": 0, "api_name": 1, "api_id": 1, "aef_profiles": 1, "description": 1,
                                 "supported_features": 1, "shareable_info": 1, "service_api_category": 1, "api_supp_feats": 1, "pub_api_path": 1, "ccf_id": 1})
            service = mycol.find(
                {"apf_id": apf_id},
                {"_id": 0,
                 "api_name": 1,
                 "api_id": 1,
                 "aef_profiles": 1,
                 "description": 1,
                 "supported_features": 1,
                 "shareable_info": 1,
                 "service_api_category": 1,
                 "api_supp_feats": 1,
                 "pub_api_path": 1,
                 "ccf_id": 1})
            current_app.logger.debug(service)
            if service is None:
                current_app.logger.error("Not found services for this apf id")
@@ -83,12 +93,7 @@ class PublishServiceOperations(Resource):
        mycol = self.db.get_col_by_name(self.db.service_api_descriptions)

        try:

            current_app.logger.debug("Publishing service")
            # result = self.__check_apf(apf_id)

            # if result != None:
            #     return result

            service = mycol.find_one(
                {"api_name": serviceapidescription.api_name})
@@ -116,7 +121,8 @@ class PublishServiceOperations(Resource):

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

            res = make_response(object=clean_n_camel_case(serviceapidescription_dict), status=201)
            res = make_response(object=clean_n_camel_case(
                serviceapidescription_dict), status=201)
            res.headers['Location'] = "http://localhost:8080/published-apis/v1/" + \
                str(apf_id) + "/service-apis/" + str(api_id)

@@ -144,17 +150,24 @@ class PublishServiceOperations(Resource):
        try:
            current_app.logger.debug(
                "Geting service api with id: " + service_api_id)
            # result = self.__check_apf(apf_id)

            # if result != None:
            #     return result

            my_query = {'apf_id': apf_id, 'api_id': service_api_id}
            service_api = mycol.find_one(my_query, {"_id": 0, "api_name": 1, "api_id": 1, "aef_profiles": 1, "description": 1,
                                         "supported_features": 1, "shareable_info": 1, "service_api_category": 1, "api_supp_feats": 1, "pub_api_path": 1, "ccf_id": 1})
            service_api = mycol.find_one(my_query, {"_id": 0,
                                                    "api_name": 1,
                                                    "api_id": 1,
                                                    "aef_profiles": 1,
                                                    "description": 1,
                                                    "supported_features": 1,
                                                    "shareable_info": 1,
                                                    "service_api_category": 1,
                                                    "api_supp_feats": 1,
                                                    "pub_api_path": 1,
                                                    "ccf_id": 1})
            if service_api is None:
                current_app.logger.error(service_api_not_found_message)
                return not_found_error(detail=service_api_not_found_message, cause="No Service with specific credentials exists")
                return not_found_error(
                    detail=service_api_not_found_message,
                    cause="No Service with specific credentials exists")

            my_service_api = dict_to_camel_case(service_api)
            my_service_api = clean_empty(my_service_api)
@@ -176,17 +189,15 @@ class PublishServiceOperations(Resource):

            current_app.logger.debug(
                "Removing api service with id: " + service_api_id)
            # result = self.__check_apf(apf_id)

            # if result != None:
            #     return result

            my_query = {'apf_id': apf_id, 'api_id': service_api_id}
            serviceapidescription = mycol.find_one(my_query)

            if serviceapidescription is None:
                current_app.logger.error(service_api_not_found_message)
                return not_found_error(detail="Service API not existing", cause="Service API id not found")
                return not_found_error(
                    detail="Service API not existing",
                    cause="Service API id not found")

            mycol.delete_one(my_query)

@@ -208,7 +219,9 @@ class PublishServiceOperations(Resource):
            current_app.logger.error(exception + "::" + str(e))
            return internal_server_error(detail=exception, cause=str(e))

    def update_serviceapidescription(self, service_api_id, apf_id, service_api_description):
    def update_serviceapidescription(self,
                                     service_api_id, apf_id,
                                     service_api_description):

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

@@ -217,11 +230,6 @@ class PublishServiceOperations(Resource):
            current_app.logger.debug(
                "Updating service api with id: " + service_api_id)

            # result = self.__check_apf(apf_id)

            # if result != None:
            #     return result

            my_query = {'apf_id': apf_id, 'api_id': service_api_id}
            serviceapidescription = mycol.find_one(my_query)

@@ -232,8 +240,21 @@ class PublishServiceOperations(Resource):
            service_api_description = service_api_description.to_dict()
            service_api_description = clean_empty(service_api_description)

            result = mycol.find_one_and_update(serviceapidescription, {"$set": service_api_description}, projection={"_id": 0, "api_name": 1, "api_id": 1, "aef_profiles": 1, "description": 1,
                                               "supported_features": 1, "shareable_info": 1, "service_api_category": 1, "api_supp_feats": 1, "pub_api_path": 1, "ccf_id": 1}, return_document=ReturnDocument.AFTER, upsert=False)
            result = mycol.find_one_and_update(
                serviceapidescription,
                {"$set": service_api_description},
                projection={"_id": 0,
                            "api_name": 1,
                            "api_id": 1,
                            "aef_profiles": 1,
                            "description": 1,
                            "supported_features": 1,
                            "shareable_info": 1,
                            "service_api_category": 1,
                            "api_supp_feats": 1,
                            "pub_api_path": 1,
                            "ccf_id": 1},
                return_document=ReturnDocument.AFTER, upsert=False)

            result = clean_empty(result)

@@ -256,7 +277,6 @@ class PublishServiceOperations(Resource):
                    RedisEvent("SERVICE_API_UNAVAILABLE", "apiIds",
                               [str(service_api_id)]).send_event()


            return response

        except Exception as e:
+24 −6
Original line number Diff line number Diff line
@@ -9,7 +9,7 @@ from ..util import serialize_clean_camel_case

class ControlAccess(Resource):

    def validate_user_cert(self, apf_id, service_id, cert_signature):
    def validate_user_cert(self, apf_id, cert_signature, service_id=None):

        cert_col = self.db.get_col_by_name(self.db.certs_col)

@@ -18,10 +18,28 @@ class ControlAccess(Resource):
            cert_entry = cert_col.find_one(my_query)

            if cert_entry is not None:
                if cert_entry["cert_signature"] != cert_signature or "services" not in cert_entry["resources"] or service_id not in cert_entry["resources"]["services"]:
                    prob = ProblemDetails(title="Unauthorized", detail="User not authorized", cause="You are not the owner of this resource")
                is_user_owner = True
                if cert_entry["cert_signature"] != cert_signature:
                    is_user_owner = False
                elif service_id:
                    if "services" not in cert_entry["resources"]:
                        is_user_owner = False
                    elif cert_entry.get("resources") and cert_entry["resources"].get("services"):
                        if service_id not in cert_entry["resources"].get("services"):
                            is_user_owner = False
                if is_user_owner == False:
                    current_app.logger.info("STEP3")
                    prob = ProblemDetails(
                        title="Unauthorized",
                        detail="User not authorized",
                        cause="You are not the owner of this resource")
                    current_app.logger.info("STEP4")
                    prob = serialize_clean_camel_case(prob)
                    return Response(json.dumps(prob, cls=CustomJSONEncoder), status=401, mimetype="application/json")
                    current_app.logger.info("STEP5")
                    return Response(
                        json.dumps(prob, cls=CustomJSONEncoder),
                        status=401,
                        mimetype="application/json")

        except Exception as e:
            exception = "An exception occurred in validate apf"
+4 −4
Original line number Diff line number Diff line
@@ -284,10 +284,10 @@ Delete API Published by Authorised apfId with valid serviceApiId
    ...    verify=ca.crt
    ...    username=${APF_PROVIDER_USERNAME}

    Check Response Variable Type And Values    ${resp}    401    ProblemDetails
    ...    title=Unauthorized
    ...    detail=User not authorized
    ...    cause=You are not the owner of this resource
    Check Response Variable Type And Values    ${resp}    404    ProblemDetails
    ...    title=Not Found
    ...    detail=Service API not found
    ...    cause=No Service with specific credentials exists

Delete APIs Published by Authorised apfId with invalid serviceApiId
    [Tags]    capif_api_publish_service-12
Loading