From 57b89d8143cec494b1aba966b7118f44552cb0fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20=C3=81ngel=20Adorna=20Ruiz?= Date: Thu, 23 Oct 2025 17:43:17 +0200 Subject: [PATCH 1/2] Resolve "Supported Features mandatory on POST and PUT Requests" --- .../core/apiinvokerenrolmentdetails.py | 14 ++++ .../api_invoker_management/core/responses.py | 2 +- .../core/provider_enrolment_details_api.py | 16 ++++- .../api_provider_management/core/responses.py | 2 +- .../capif_api_invoker_managenet.robot | 55 +++++++++++++++ .../capif_api_provider_management.robot | 67 +++++++++++++++++++ .../api_invoker_management/bodyRequests.py | 6 +- .../api_provider_management/bodyRequests.py | 6 +- 8 files changed, 161 insertions(+), 7 deletions(-) diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/core/apiinvokerenrolmentdetails.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/core/apiinvokerenrolmentdetails.py index 381df7b7..7c5f74e0 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/core/apiinvokerenrolmentdetails.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/core/apiinvokerenrolmentdetails.py @@ -100,6 +100,13 @@ class InvokerManagementOperations(Resource): current_app.logger.error("Bad url format") return bad_request_error(detail="Bad Param", cause="Detected Bad formar of param", invalid_params=[{"param": "notificationDestination", "reason": "Not valid URL format"}]) + if not apiinvokerenrolmentdetail.supported_features: + return bad_request_error( + detail="supportedFeatures not present in request", + cause="supportedFeatures not present", + invalid_params=[{"param": "supportedFeatures", "reason": "not defined"}] + ) + current_app.logger.debug("Signing Certificate") api_invoker_id = 'INV'+str(secrets.token_hex(15)) @@ -148,6 +155,13 @@ class InvokerManagementOperations(Resource): if isinstance(result, Response): return result + if not apiinvokerenrolmentdetail.supported_features: + return bad_request_error( + detail="supportedFeatures not present in request", + cause="supportedFeatures not present", + invalid_params=[{"param": "supportedFeatures", "reason": "not defined"}] + ) + 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"]) diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/core/responses.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/core/responses.py index 8f975cbf..ad4e191d 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/core/responses.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/core/responses.py @@ -40,4 +40,4 @@ def not_found_error(detail, cause): prob = ProblemDetails(title="Not Found", status=404, detail=detail, cause=cause) prob = serialize_clean_camel_case(prob) - return Response(json.dumps(prob, cls=CustomJSONEncoder), status=404, mimetype=mimetype) \ No newline at end of file + return Response(json.dumps(prob, cls=CustomJSONEncoder), status=404, mimetype=mimetype) diff --git a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/provider_enrolment_details_api.py b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/provider_enrolment_details_api.py index 60b89b14..ac19a496 100644 --- a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/provider_enrolment_details_api.py +++ b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/provider_enrolment_details_api.py @@ -57,6 +57,13 @@ class ProviderManagementOperations(Resource): "Found provider registered with same id") return forbidden_error(detail="Provider already registered", cause="Identical provider reg sec") + if not api_provider_enrolment_details.supp_feat: + return bad_request_error( + detail="suppFeat not present in request", + cause="suppFeat not present", + invalid_params=[{"param": "suppFeat", "reason": "not defined"}] + ) + api_provider_enrolment_details.api_prov_dom_id = secrets.token_hex( 15) @@ -148,7 +155,14 @@ class ProviderManagementOperations(Resource): if isinstance(result, Response): return result - + + if not api_provider_enrolment_details.supp_feat: + return bad_request_error( + detail="suppFeat not present in request", + cause="suppFeat not present", + invalid_params=[{"param": "suppFeat", "reason": "not defined"}] + ) + negotiated_supported_features = return_negotiated_supp_feat_dict(api_provider_enrolment_details.supp_feat) api_provider_enrolment_details.supp_feat = negotiated_supported_features["Final"] diff --git a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/responses.py b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/responses.py index 8f975cbf..ad4e191d 100644 --- a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/responses.py +++ b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/responses.py @@ -40,4 +40,4 @@ def not_found_error(detail, cause): prob = ProblemDetails(title="Not Found", status=404, detail=detail, cause=cause) prob = serialize_clean_camel_case(prob) - return Response(json.dumps(prob, cls=CustomJSONEncoder), status=404, mimetype=mimetype) \ No newline at end of file + return Response(json.dumps(prob, cls=CustomJSONEncoder), status=404, mimetype=mimetype) diff --git a/tests/features/CAPIF Api Invoker Management/capif_api_invoker_managenet.robot b/tests/features/CAPIF Api Invoker Management/capif_api_invoker_managenet.robot index 57005b56..be86dbb7 100644 --- a/tests/features/CAPIF Api Invoker Management/capif_api_invoker_managenet.robot +++ b/tests/features/CAPIF Api Invoker Management/capif_api_invoker_managenet.robot @@ -182,3 +182,58 @@ Update Onboarded Network App Certificate # Check Results Check Response Variable Type And Values ${resp} 200 APIInvokerEnrolmentDetails ... notificationDestination=${new_notification_destination} + +Onboard invoker without supported_features + [Tags] capif_api_invoker_management-8 + # Default Invoker Registration and Onboarding + ${register_user_info}= Register User At Jwt Auth + ... username=${invoker_username} role=${INVOKER_ROLE} + + ${request_body}= Create Onboarding Notification Body + ... http://${CAPIF_CALLBACK_IP}:${CAPIF_CALLBACK_PORT}/netapp_callback + ... ${register_user_info['csr_request']} + ... ${invoker_username} + ... supported_features=${None} + + ${resp}= Post Request Capif + ... ${register_user_info['ccf_onboarding_url']} + ... json=${request_body} + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... access_token=${register_user_info['access_token']} + + # Check Results + Check Response Variable Type And Values ${resp} 400 ProblemDetails + ... status=400 + ... title=Bad Request + ... detail=supportedFeatures not present in request + ... cause=supportedFeatures not present + +Update Onboarded Network App without supported_features + [Tags] capif_api_invoker_management-10 + ${new_notification_destination}= Set Variable + ... http://${CAPIF_CALLBACK_IP}:${CAPIF_CALLBACK_PORT}/netapp_new_callback + # Default Invoker Registration and Onboarding + ${register_user_info} ${url} ${request_body}= Invoker Default Onboarding + + Set To Dictionary + ... ${request_body} + ... notificationDestination=${new_notification_destination} + + Remove From Dictionary + ... ${request_body} + ... supportedFeatures + + ${resp}= Put Request Capif + ... ${url.path} + ... ${request_body} + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${INVOKER_USERNAME} + + # Check Results + Check Response Variable Type And Values ${resp} 400 ProblemDetails + ... status=400 + ... title=Bad Request + ... detail=supportedFeatures not present in request + ... cause=supportedFeatures not present diff --git a/tests/features/CAPIF Api Provider Management/capif_api_provider_management.robot b/tests/features/CAPIF Api Provider Management/capif_api_provider_management.robot index bda73735..44ba9ffe 100644 --- a/tests/features/CAPIF Api Provider Management/capif_api_provider_management.robot +++ b/tests/features/CAPIF Api Provider Management/capif_api_provider_management.robot @@ -203,3 +203,70 @@ Delete Not Registered Api Provider ... title=Not Found ... detail=Not Exist Provider Enrolment Details ... cause=Not found registrations to send this api provider details + +Onboard provider without supported_features + [Tags] capif_api_provider_management-9 + # Default Provider Registration and Onboarding + ${register_user_info}= Register User At Jwt Auth Provider + ... username=${PROVIDER_USERNAME} + + # Create provider Registration Body + ${apf_func_details}= Create Api Provider Function Details + ... ${register_user_info['apf_username']} + ... ${register_user_info['apf_csr_request']} + ... APF + ${aef_func_details}= Create Api Provider Function Details + ... ${register_user_info['aef_username']} + ... ${register_user_info['aef_csr_request']} + ... AEF + ${amf_func_details}= Create Api Provider Function Details + ... ${register_user_info['amf_username']} + ... ${register_user_info['amf_csr_request']} + ... AMF + ${api_prov_funcs}= Create List ${apf_func_details} ${aef_func_details} ${amf_func_details} + + ${request_body}= Create Api Provider Enrolment Details Body + ... ${register_user_info['access_token']} + ... ${api_prov_funcs} + ... suppFeat=${None} + + # Register Provider + ${resp}= Post Request Capif + ... /api-provider-management/v1/registrations + ... json=${request_body} + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... access_token=${register_user_info['access_token']} + + # Check Results + Check Response Variable Type And Values ${resp} 400 ProblemDetails + ... status=400 + ... title=Bad Request + ... detail=suppFeat not present in request + ... cause=suppFeat not present + +Update Registered Api Provider + [Tags] capif_api_provider_management-10 + ${register_user_info}= Provider Default Registration + + ${request_body}= Set Variable ${register_user_info['provider_enrollment_details']} + + Set To Dictionary ${request_body} apiProvDomInfo=ROBOT_TESTING_MOD + + Remove From Dictionary + ... ${request_body} + ... suppFeat + + ${resp}= Put Request Capif + ... ${register_user_info['resource_url'].path} + ... json=${request_body} + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${AMF_PROVIDER_USERNAME} + + # Check Results + Check Response Variable Type And Values ${resp} 400 ProblemDetails + ... status=400 + ... title=Bad Request + ... detail=suppFeat not present in request + ... cause=suppFeat not present diff --git a/tests/libraries/api_invoker_management/bodyRequests.py b/tests/libraries/api_invoker_management/bodyRequests.py index 37b9456d..aebcff7c 100644 --- a/tests/libraries/api_invoker_management/bodyRequests.py +++ b/tests/libraries/api_invoker_management/bodyRequests.py @@ -1,7 +1,6 @@ -def create_onboarding_notification_body(notification_destination="https://host.docker.internal/netapp_callback", api_invoker_public_key="ApiInvokerPublicKey",api_invoker_information='ROBOT_TESTING', api_invoker_id=None): +def create_onboarding_notification_body(notification_destination="https://host.docker.internal/netapp_callback", api_invoker_public_key="ApiInvokerPublicKey",api_invoker_information='ROBOT_TESTING', api_invoker_id=None, supported_features="0"): data = { "notificationDestination": notification_destination, - "supportedFeatures": "fffffff", "apiInvokerInformation": api_invoker_information, "websockNotifConfig": { "requestWebsocketUri": True, @@ -17,4 +16,7 @@ def create_onboarding_notification_body(notification_destination="https://host.d if api_invoker_id != None: data['apiInvokerId'] = api_invoker_id + if supported_features != None: + data['supportedFeatures'] = supported_features + return (data) diff --git a/tests/libraries/api_provider_management/bodyRequests.py b/tests/libraries/api_provider_management/bodyRequests.py index e024a5b9..b80330b4 100644 --- a/tests/libraries/api_provider_management/bodyRequests.py +++ b/tests/libraries/api_provider_management/bodyRequests.py @@ -1,12 +1,14 @@ -def create_api_provider_enrolment_details_body(regSec, api_prov_funcs, apiProvDomInfo="ROBOT_TESTING"): +def create_api_provider_enrolment_details_body(regSec, api_prov_funcs, apiProvDomInfo="ROBOT_TESTING", suppFeat="0"): data = { "regSec": regSec, "apiProvFuncs": api_prov_funcs, "apiProvDomInfo": apiProvDomInfo, - "suppFeat": "fffffff", "failReason": "string" } + if suppFeat != None: + data['suppFeat'] = suppFeat + return (data) -- GitLab From 4616f80b99971474bd74567f10ff017e8f6b19b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20=C3=81ngel=20Adorna=20Ruiz?= Date: Tue, 28 Oct 2025 11:40:54 +0100 Subject: [PATCH 2/2] fix test ID --- .../capif_api_invoker_managenet.robot | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/features/CAPIF Api Invoker Management/capif_api_invoker_managenet.robot b/tests/features/CAPIF Api Invoker Management/capif_api_invoker_managenet.robot index be86dbb7..3052e194 100644 --- a/tests/features/CAPIF Api Invoker Management/capif_api_invoker_managenet.robot +++ b/tests/features/CAPIF Api Invoker Management/capif_api_invoker_managenet.robot @@ -210,7 +210,7 @@ Onboard invoker without supported_features ... cause=supportedFeatures not present Update Onboarded Network App without supported_features - [Tags] capif_api_invoker_management-10 + [Tags] capif_api_invoker_management-9 ${new_notification_destination}= Set Variable ... http://${CAPIF_CALLBACK_IP}:${CAPIF_CALLBACK_PORT}/netapp_new_callback # Default Invoker Registration and Onboarding -- GitLab