Loading services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/provider_enrolment_details_api.py +4 −1 Original line number Diff line number Diff line Loading @@ -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' ] Loading @@ -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) Loading services/TS29222_CAPIF_Publish_Service_API/published_apis/controllers/default_controller.py +16 −7 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading @@ -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: Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading services/TS29222_CAPIF_Publish_Service_API/published_apis/core/serviceapidescriptions.py +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 Loading @@ -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 Loading @@ -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") Loading Loading @@ -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}) Loading Loading @@ -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) Loading Loading @@ -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) Loading @@ -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) Loading @@ -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) Loading @@ -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) Loading @@ -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) Loading @@ -256,7 +277,6 @@ class PublishServiceOperations(Resource): RedisEvent("SERVICE_API_UNAVAILABLE", "apiIds", [str(service_api_id)]).send_event() return response except Exception as e: Loading services/TS29222_CAPIF_Publish_Service_API/published_apis/core/validate_user.py +24 −6 Original line number Diff line number Diff line Loading @@ -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) Loading @@ -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" Loading tests/features/CAPIF Api Publish Service/capif_api_publish_service.robot +4 −4 Original line number Diff line number Diff line Loading @@ -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 Loading
services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/provider_enrolment_details_api.py +4 −1 Original line number Diff line number Diff line Loading @@ -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' ] Loading @@ -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) Loading
services/TS29222_CAPIF_Publish_Service_API/published_apis/controllers/default_controller.py +16 −7 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading @@ -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: Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading
services/TS29222_CAPIF_Publish_Service_API/published_apis/core/serviceapidescriptions.py +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 Loading @@ -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 Loading @@ -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") Loading Loading @@ -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}) Loading Loading @@ -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) Loading Loading @@ -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) Loading @@ -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) Loading @@ -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) Loading @@ -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) Loading @@ -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) Loading @@ -256,7 +277,6 @@ class PublishServiceOperations(Resource): RedisEvent("SERVICE_API_UNAVAILABLE", "apiIds", [str(service_api_id)]).send_event() return response except Exception as e: Loading
services/TS29222_CAPIF_Publish_Service_API/published_apis/core/validate_user.py +24 −6 Original line number Diff line number Diff line Loading @@ -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) Loading @@ -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" Loading
tests/features/CAPIF Api Publish Service/capif_api_publish_service.robot +4 −4 Original line number Diff line number Diff line Loading @@ -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