diff --git a/.github/workflows/gitlab.yml b/.github/workflows/gitlab.yml new file mode 100644 index 0000000000000000000000000000000000000000..68ca39aae391a1674e131aa1ff194b36b3b16c42 --- /dev/null +++ b/.github/workflows/gitlab.yml @@ -0,0 +1,39 @@ +name: Sync GitHub to GitLab + +on: + push: + branches: + - develop # Se activa cuando hay cambios en la rama develop + +jobs: + create-merge-request: + runs-on: ubuntu-latest + + steps: + # 1. Checkout del código desde GitHub + - name: Checkout GitHub repository + uses: actions/checkout@v4 + + # 2. Crear un Merge Request en GitLab + - name: Create Merge Request in GitLab + env: + GITLAB_TOKEN: ${{ secrets.GITLAB_TOKEN }} + run: | + # Información del MR + PROJECT_ID="335" # Reemplaza con el ID del proyecto de GitLab + SOURCE_BRANCH="develop" + TARGET_BRANCH="main" + + # Crear el Merge Request usando la API de GitLab + curl -X POST \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer $GITLAB_TOKEN" \ + -d '{ + "id": "'"${PROJECT_ID}"'", + "source_branch": "'"${SOURCE_BRANCH}"'", + "target_branch": "'"${TARGET_BRANCH}"'", + "title": "Sync develop to main", + "remove_source_branch": false, + "squash": false + }' \ + https://labs.etsi.org/api/v4/projects/${PROJECT_ID}/merge_requests diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml new file mode 100644 index 0000000000000000000000000000000000000000..c96f81f4cb8220c835c5e86a8387bb9b30c828c7 --- /dev/null +++ b/.github/workflows/python-publish.yml @@ -0,0 +1,70 @@ +# This workflow will upload a Python Package to PyPI when a release is created +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries + +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +name: Upload Python Package + +on: + release: + types: [published] + +permissions: + contents: read + +jobs: + release-build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Build release distributions + run: | + # NOTE: put your own distribution build steps here. + python -m pip install build + python -m build + + - name: Upload distributions + uses: actions/upload-artifact@v4 + with: + name: release-dists + path: dist/ + + pypi-publish: + runs-on: ubuntu-latest + needs: + - release-build + permissions: + # IMPORTANT: this permission is mandatory for trusted publishing + id-token: write + + # Dedicated environments with protections for publishing are strongly recommended. + # For more information, see: https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#deployment-protection-rules + environment: + name: pypi + # OPTIONAL: uncomment and update to include your PyPI project URL in the deployment status: + + # + # ALTERNATIVE: if your GitHub Release name is the PyPI project version string + # ALTERNATIVE: exactly, uncomment the following line instead: + url: https://pypi.org/project/opencapif-sdk/${{ github.event.release.name }} + + steps: + - name: Retrieve release distributions + uses: actions/download-artifact@v4 + with: + name: release-dists + path: dist/ + + - name: Publish release distributions to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + packages-dir: dist/ diff --git a/LICENSE b/LICENSE index 8d4113aed5e0485d758cad211a82ad1ab7a0aa26..9f55c857007b9abaa8d9513d06333ffa110f53f8 100644 --- a/LICENSE +++ b/LICENSE @@ -189,7 +189,7 @@ Copyright (c) 2021, Stavros Kolometsos Copyright (c) 2022, Telefónica Innovación Digital Copyright (c) 2022, Fogus Innovations & Services P.C. - Copyright (c) 2024, European Telecommunications Standards Institute (ETSI) + Copyright (c) 2024, ETSI Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000000000000000000000000000000000000..245e6aa15bf01af9f5cb4e884a0d941ae988f9ad --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,2 @@ +include README_pipy.md +include LICENSE \ No newline at end of file diff --git a/README.md b/README.md index 84068878ead2b95461fbe7cfabe614b813f8b527..c1020b01e4707451504118f2f5f14e22565d5536 100644 --- a/README.md +++ b/README.md @@ -163,6 +163,7 @@ Now, it is described in 4 simple steps how a Provider can be developed in just s provider.publish_req['publisher_apf_id'] = APF provider.publish_req['publisher_aefs_ids'] = [AEF1, AEF2] + provider.supported_features ="4" provider.publish_services() ``` diff --git a/doc/README_pipy.md b/README_pipy.md similarity index 96% rename from doc/README_pipy.md rename to README_pipy.md index 57eacbc1799d6b0faa5f8940d6d9376fcf9fec19..908a9e27e5cf7929902ed27213c3ce431b980b34 100644 --- a/doc/README_pipy.md +++ b/README_pipy.md @@ -101,6 +101,7 @@ When configuring the SDK as a **Network App Invoker**, the following fields must For SDK configuration as a **Network App Provider**, the following fields are required: - `provider_folder` +- `suported_features` - `cert_generation` (fields such as `csr_common_name`, `csr_country_name`, etc.) - `APFs` - `AEFs` @@ -133,10 +134,9 @@ If the `publisher_aefs_ids` do not match the `aefProfiles` in the API descriptio ## Descriptions of `capif_sdk_config` Fields -This file can also be populated using [environment variables](../samples/enviroment_variables_sample.txt). - - `invoker_folder`: The path (relative or absolute) where invoker information (certificates, keys, etc.) is stored. - `provider_folder`: The path (relative or absolute) where provider information is stored. +- `supported_features`: A string used to indicate the features supported by an API. The string shall contain a bitmask indicating supported features in hexadecimal representation Each character in the string shall take a value of "0" to "9", "a" to "f" or "A" to "F". [More information](https://github.com/jdegre/5GC_APIs/blob/Rel-18/TS29571_CommonData.yaml) - `capif_host`: The domain name of the CAPIF host. - `register_host`: The domain name of the register host. - `capif_https_port`: The CAPIF host port number. @@ -148,8 +148,8 @@ This file can also be populated using [environment variables](../samples/envirom - `apfs`: The number of APFs to be onboarded as a provider (e.g., `5`). - `aefs`: The number of AEFs to be onboarded as a provider (e.g., `2`). - `debug_mode`: A boolean value to enable or disable SDK logs (e.g., `True` or `False`). -- `discover_filter`: Fields for configuring invoker service discovery. -- `publish_req`: Fields required for API publishing. +- [`discover_filter`](#configuration-of-discover_filter): Fields for configuring invoker service discovery. +- [`publish_req`](#configuration-of-publish_req): Fields required for API publishing. - `api_description_path`: The path to the [ServiceAPIDescription](https://github.com/jdegre/5GC_APIs/blob/Rel-18/TS29222_CAPIF_Publish_Service_API.yaml) JSON file. - `check_authentication_data`: The `ip` and `port` of the target Provider's AEF to get their supported features from. diff --git a/config/capif_sdk_config.json b/config/capif_sdk_config.json index 34844f5a344cae2d12a0110e4ccfc61b4de0ce5f..7096619f0a2c99cf3b9d746298a1eb42506f48be 100644 --- a/config/capif_sdk_config.json +++ b/config/capif_sdk_config.json @@ -10,7 +10,7 @@ "invoker_folder": "", "capif_callback_url": "", "supported_features":"", - "check_authentication":{ + "check_authentication_data":{ "ip":"", "port":"" }, @@ -18,7 +18,7 @@ "csr_common_name": "", "csr_organizational_unit": "", "csr_organization": "", - "crs_locality": "", + "csr_locality": "", "csr_state_or_province_name": "", "csr_country_name": "", "csr_email_address": "" @@ -41,6 +41,7 @@ }, "provider": { "provider_folder": "", + "supported_features": "", "apfs": "", "aefs": "", "publish_req": { @@ -55,7 +56,7 @@ "csr_common_name": "", "csr_organizational_unit": "", "csr_organization": "", - "crs_locality": "", + "csr_locality": "", "csr_state_or_province_name": "", "csr_country_name": "", "csr_email_address": "" diff --git a/doc/sdk_configuration.md b/doc/sdk_configuration.md index d9193cb49086ddfa1b16e9c92f836afa2a23a9b5..97a3dafacbf164cf1088388b85df37fdd620c965 100644 --- a/doc/sdk_configuration.md +++ b/doc/sdk_configuration.md @@ -43,6 +43,7 @@ When configuring the SDK as a **Network App Invoker**, the following fields must For SDK configuration as a **Network App Provider**, the following fields are required: - `provider_folder` +- `supported_features` - `cert_generation` (fields such as `csr_common_name`, `csr_country_name`, etc.) - `APFs` - `AEFs` @@ -80,6 +81,7 @@ This file can also be populated using [environment variables](../samples/envirom - `invoker_folder`: The path (relative or absolute) where invoker information (certificates, keys, etc.) is stored. - `provider_folder`: The path (relative or absolute) where provider information is stored. +- `supported_features`: A string used to indicate the features supported by an API. The string shall contain a bitmask indicating supported features in hexadecimal representation Each character in the string shall take a value of "0" to "9", "a" to "f" or "A" to "F". [More information](https://github.com/jdegre/5GC_APIs/blob/Rel-18/TS29571_CommonData.yaml) - `capif_host`: The domain name of the CAPIF host. - `register_host`: The domain name of the register host. - `capif_https_port`: The CAPIF host port number. diff --git a/network_app_samples/network_app_invoker_sample/capif_sdk_config_sample.json b/network_app_samples/network_app_invoker_sample/capif_sdk_config_sample.json index c68a7ac08d0962dc5216c860d26698b231dc8a07..7096619f0a2c99cf3b9d746298a1eb42506f48be 100644 --- a/network_app_samples/network_app_invoker_sample/capif_sdk_config_sample.json +++ b/network_app_samples/network_app_invoker_sample/capif_sdk_config_sample.json @@ -6,7 +6,7 @@ "capif_username": "", "capif_password": "", "debug_mode": "", - "invoker":{ + "invoker": { "invoker_folder": "", "capif_callback_url": "", "supported_features":"", @@ -14,7 +14,7 @@ "ip":"", "port":"" }, - "cert_generation":{ + "cert_generation": { "csr_common_name": "", "csr_organizational_unit": "", "csr_organization": "", @@ -39,8 +39,9 @@ "service-kpis": "" } }, - "provider":{ + "provider": { "provider_folder": "", + "supported_features": "", "apfs": "", "aefs": "", "publish_req": { @@ -51,7 +52,7 @@ "" ] }, - "cert_generation":{ + "cert_generation": { "csr_common_name": "", "csr_organizational_unit": "", "csr_organization": "", @@ -61,5 +62,5 @@ "csr_email_address": "" }, "api_description_path": "" - } + } } diff --git a/network_app_samples/network_app_provider_sample/capif_sdk_config_sample.json b/network_app_samples/network_app_provider_sample/capif_sdk_config_sample.json index f2c2c796dae3df8f6348c38bef715ea5aaa32040..e6127a99edd6d6083d46c345901d5c77ce887ed0 100644 --- a/network_app_samples/network_app_provider_sample/capif_sdk_config_sample.json +++ b/network_app_samples/network_app_provider_sample/capif_sdk_config_sample.json @@ -6,14 +6,15 @@ "capif_username": "", "capif_password": "", "debug_mode": "", - "invoker":{ + "invoker": { "invoker_folder": "", "capif_callback_url": "", + "supported_features":"", "check_authentication_data":{ "ip":"", "port":"" }, - "cert_generation":{ + "cert_generation": { "csr_common_name": "", "csr_organizational_unit": "", "csr_organization": "", @@ -38,17 +39,9 @@ "service-kpis": "" } }, - "provider":{ + "provider": { "provider_folder": "", - "cert_generation":{ - "csr_common_name": "", - "csr_organizational_unit": "", - "csr_organization": "", - "csr_locality": "", - "csr_state_or_province_name": "", - "csr_country_name": "", - "csr_email_address": "" - }, + "supported_features": "", "apfs": "2", "aefs": "3", "publish_req": { @@ -59,6 +52,15 @@ "" ] }, + "cert_generation": { + "csr_common_name": "", + "csr_organizational_unit": "", + "csr_organization": "", + "csr_locality": "", + "csr_state_or_province_name": "", + "csr_country_name": "", + "csr_email_address": "" + }, "api_description_path": "" - } + } } diff --git a/network_app_samples/network_app_provider_sample/nef_upf_vendor_1.json b/network_app_samples/network_app_provider_sample/nef_upf_vendor_1.json index 8cc2fa42c0ccad2f63b4ba09d6b636db5f8fd791..58ceb6fa03cecf99c22e18707da49c53534c7173 100755 --- a/network_app_samples/network_app_provider_sample/nef_upf_vendor_1.json +++ b/network_app_samples/network_app_provider_sample/nef_upf_vendor_1.json @@ -143,14 +143,14 @@ "protocol": "HTTP_1_1", "dataFormat": "JSON", "securityMethods": [ - "Oauth" + "OAUTH" ], "interfaceDescriptions": [ { "ipv4Addr": "localhost", "port": 8088, "securityMethods": [ - "Oauth" + "OAUTH" ] } ] @@ -297,7 +297,7 @@ "protocol": "HTTP_1_1", "dataFormat": "JSON", "securityMethods": [ - "Oauth", + "OAUTH", "PSK" ], "interfaceDescriptions": [ @@ -305,7 +305,7 @@ "ipv4Addr": "localhost", "port": 8088, "securityMethods": [ - "Oauth" + "OAUTH" ] } ] diff --git a/network_app_samples/network_app_provider_sample/nef_upf_vendor_2.json b/network_app_samples/network_app_provider_sample/nef_upf_vendor_2.json index 5feec72a09b690011fb88feb452d9f30908d1391..5930f5c4a7b6c8638c90b67a4642cf70328f4587 100755 --- a/network_app_samples/network_app_provider_sample/nef_upf_vendor_2.json +++ b/network_app_samples/network_app_provider_sample/nef_upf_vendor_2.json @@ -127,7 +127,7 @@ "protocol": "HTTP_1_1", "dataFormat": "JSON", "securityMethods": [ - "Oauth", + "OAUTH", "PSK" ], "interfaceDescriptions": [ @@ -135,7 +135,7 @@ "ipv4Addr": "localhost", "port": 8888, "securityMethods": [ - "Oauth" + "OAUTH" ] } ] @@ -283,14 +283,14 @@ "protocol": "HTTP_1_1", "dataFormat": "JSON", "securityMethods": [ - "Oauth" + "OAUTH" ], "interfaceDescriptions": [ { "ipv4Addr": "localhost", "port": 8888, "securityMethods": [ - "Oauth" + "OAUTH" ] } ] @@ -421,7 +421,7 @@ "protocol": "HTTP_1_1", "dataFormat": "JSON", "securityMethods": [ - "Oauth", + "OAUTH", "PSK" ], "interfaceDescriptions": [ @@ -429,7 +429,7 @@ "ipv4Addr": "localhost", "port": 8888, "securityMethods": [ - "Oauth" + "OAUTH" ] } ] diff --git a/opencapif_sdk/api_schema_translator.py b/opencapif_sdk/api_schema_translator.py index 7e29a763c7d768da77ad3a676bba63d221139ae3..12519903c5df540483c3b15b12a8c5df686d7aa1 100644 --- a/opencapif_sdk/api_schema_translator.py +++ b/opencapif_sdk/api_schema_translator.py @@ -143,12 +143,12 @@ class api_schema_translator: ], "protocol": "HTTP_1_1", "dataFormat": "JSON", - "securityMethods": ["Oauth"], + "securityMethods": ["OAUTH"], "interfaceDescriptions": [ { "ipv4Addr": ip, "port": port, - "securityMethods": ["Oauth"] + "securityMethods": ["OAUTH"] } ] } diff --git a/opencapif_sdk/capif_invoker_connector.py b/opencapif_sdk/capif_invoker_connector.py index 528fb75d3688c939a231f9641eca2e12af47651c..6a159f11f6b7fa7fe48f0dfacef32e7ccb2ac973 100644 --- a/opencapif_sdk/capif_invoker_connector.py +++ b/opencapif_sdk/capif_invoker_connector.py @@ -82,7 +82,7 @@ class capif_invoker_connector: capif_invoker_password = os.getenv('CAPIF_PASSWORD', config.get('capif_password', '')).strip() capif_callback_url = os.getenv('INVOKER_CAPIF_CALLBACK_URL', invoker_config.get('capif_callback_url', '')).strip() - supported_features = os.getenv('INVOKER_FOLDER', invoker_config.get('supported_features', '')).strip() + supported_features = os.getenv('INVOKER_SUPPORTED_FEATURES', invoker_config.get('supported_features', '')).strip() check_authentication_data = invoker_config.get('check_authentication_data', {}) self.check_authentication = { "ip": os.getenv('INVOKER_CHECK_AUTHENTICATION_DATA_IP', check_authentication_data.get('ip', '')).strip(), @@ -325,7 +325,7 @@ class capif_invoker_connector: url = self.capif_https_url + capif_onboarding_url payload_dict = { "notificationDestination": self.capif_callback_url, - "supportedFeatures": self.supported_features, + "supportedFeatures": f"{self.supported_features}", "apiInvokerInformation": self.csr_common_name, "websockNotifConfig": { "requestWebsocketUri": True, @@ -429,7 +429,7 @@ class capif_invoker_connector: url = self.capif_https_url + capif_onboarding_url + "/" + invokerid payload_dict = { "notificationDestination": self.capif_callback_url, - "supportedFeatures": self.supported_features, + "supportedFeatures": f"{self.supported_features}", "apiInvokerInformation": self.csr_common_name, "websockNotifConfig": { "requestWebsocketUri": True, diff --git a/opencapif_sdk/capif_provider_connector.py b/opencapif_sdk/capif_provider_connector.py index c96578e69977f802b7b5e626e4eda7ec34a54500..a875bd8834f1fc94b6904f231e97c1f11a094a9d 100644 --- a/opencapif_sdk/capif_provider_connector.py +++ b/opencapif_sdk/capif_provider_connector.py @@ -99,6 +99,10 @@ class capif_provider_connector: csr_email_address = os.getenv('PROVIDER_CSR_EMAIL_ADDRESS', cert_generation.get('csr_email_address', '')).strip() # Retrieve provider specific values (APFs, AEFs) + supported_features = os.getenv('PROVIDER_SUPPORTED_FEATURES', provider_config.get('supported_features', '')).strip() + if not supported_features: + supported_features = "0" + apfs = os.getenv('PROVIDER_APFS', provider_config.get('apfs', '')).strip() aefs = os.getenv('PROVIDER_AEFS', provider_config.get('aefs', '')).strip() api_description_path = os.path.abspath(os.getenv('PROVIDER_API_DESCRIPTION_PATH', provider_config.get('api_description_path', '')).strip()) @@ -127,6 +131,7 @@ class capif_provider_connector: self.csr_state_or_province_name = csr_state_or_province_name self.csr_country_name = csr_country_name self.csr_email_address = csr_email_address + self.supported_features = supported_features self.aefs = int(aefs) self.apfs = int(apfs) @@ -276,7 +281,7 @@ class capif_provider_connector: for role in roles ], "apiProvDomInfo": "This is provider", - "suppFeat": "fff", + "suppFeat": self.supported_features, "failReason": "string", "regSec": access_token, } @@ -452,6 +457,7 @@ class capif_provider_connector: with open(service_api_description_json_full_path, "r") as service_file: data = json.load(service_file) + data["supportedFeatures"] = f"{self.supported_features}" # Verifying that the number of AEFs is equal to the aefProfiles if len(AEFs_list) != len(data.get("aefProfiles", [])): self.logger.error( @@ -460,41 +466,45 @@ class capif_provider_connector: "Mismatch between number of AEFs and profiles") # Assigning each AEF + for profile, aef_id in zip(data.get("aefProfiles", []), AEFs_list): - profile["aefId"] = aef_id - for versions in profile["versions"]: - check = True - revoke = True - for custom in versions["custOperations"]: - if custom["custOpName"] == "check-authentication": - check = False - if custom["custOpName"] == "revoke-authentication": - revoke = False - # Si ambas condiciones ya son falsas, salir del bucle - if not check and not revoke: - break - # If 'check-authentication' custom operation doesn't exist, add it - if check: - versions["custOperations"].append({ + if not isinstance(profile, dict): # Verificar que profile sea un diccionario + raise TypeError(f"Expected profile to be a dict, got {type(profile).__name__}") + + profile["aefId"] = aef_id # Asignar el ID de AEF + + versions = profile.get("versions") # Obtener versions + + i = 1 + for version in versions: # Iterar sobre cada versión + if not isinstance(version, dict): # Verificar que cada versión sea un diccionario + raise TypeError(f"Expected each version to be a dict, got {type(version).__name__}") + + # Obtener nombres existentes de operaciones personalizadas + existing_operations = { + op["custOpName"].strip() + for op in version.get("custOperations", []) if isinstance(op, dict) + } + + # Verificar y agregar `check-authentication` si no existe + if "check-authentication" not in existing_operations and i == 1: + version.setdefault("custOperations", []).append({ "commType": "REQUEST_RESPONSE", "custOpName": "check-authentication", - "operations": [ - "POST" - ], + "operations": ["POST"], "description": "Check authentication request." }) - # If 'revoke-authentication' custom operation doesn't exist, add it - if revoke: - versions["custOperations"].append({ + # Verificar y agregar `revoke-authentication` si no existe + if "revoke-authentication" not in existing_operations and i == 1: + version.setdefault("custOperations", []).append({ "commType": "REQUEST_RESPONSE", "custOpName": "revoke-authentication", - "operations": [ - "POST" - ], + "operations": ["POST"], "description": "Revoke authorization for service APIs." }) - + i -= 1 + self.logger.info( "Service API description modified successfully") @@ -901,36 +911,42 @@ class capif_provider_connector: # Asing the chosen AEFs for profile, aef_id in zip(data.get("aefProfiles", []), AEFs_list): - profile["aefId"] = aef_id - for versions in profile["versions"]: - for custom in versions["custOperations"]: - check = True - revoke = True - if custom["custOpName"] == "check-authentication": - check = False - if custom["custOpName"] == "revoke-authentication ": - revoke = False - # If 'check-authentication' custom operation doesn't exist, add it - if check: - versions["custOperations"].append({ + if not isinstance(profile, dict): # Verificar que profile sea un diccionario + raise TypeError(f"Expected profile to be a dict, got {type(profile).__name__}") + + profile["aefId"] = aef_id # Asignar el ID de AEF + + versions = profile.get("versions") # Obtener versions + i = 1 + for version in versions: # Iterar sobre cada versión + if not isinstance(version, dict): # Verificar que cada versión sea un diccionario + raise TypeError(f"Expected each version to be a dict, got {type(version).__name__}") + + # Obtener nombres existentes de operaciones personalizadas + existing_operations = { + op["custOpName"].strip() + for op in version.get("custOperations", []) if isinstance(op, dict) + } + + # Verificar y agregar `check-authentication` si no existe + if "check-authentication" not in existing_operations and i == 1: + version.setdefault("custOperations", []).append({ "commType": "REQUEST_RESPONSE", "custOpName": "check-authentication", - "operations": [ - "POST" - ], + "operations": ["POST"], "description": "Check authentication request." }) - # If 'revoke-authentication' custom operation doesn't exist, add it - if revoke: - versions["custOperations"].append({ + # Verificar y agregar `revoke-authentication` si no existe + if "revoke-authentication" not in existing_operations and i == 1: + version.setdefault("custOperations", []).append({ "commType": "REQUEST_RESPONSE", "custOpName": "revoke-authentication", - "operations": [ - "POST" - ], + "operations": ["POST"], "description": "Revoke authorization for service APIs." }) + i -= 1 + self.logger.info( "Service API description modified successfully") @@ -1262,7 +1278,7 @@ class capif_provider_connector: for role in roles ], "apiProvDomInfo": "This is provider", - "suppFeat": "fff", + "suppFeat": self.supported_features, "failReason": "string", "regSec": access_token, } diff --git a/opencapif_sdk/service_discoverer.py b/opencapif_sdk/service_discoverer.py index 9f079a17dd43ce117836c54b1581289566b7722e..6272e94ca7e9b6988c0d5a3a4a3b6694ebc8ad2f 100644 --- a/opencapif_sdk/service_discoverer.py +++ b/opencapif_sdk/service_discoverer.py @@ -213,7 +213,7 @@ class service_discoverer: "websocketUri": "string", "requestWebsocketUri": True }, - "supportedFeatures": "fff" + "supportedFeatures": f"{self.supported_features}" } number_of_apis = len( @@ -227,7 +227,7 @@ class service_discoverer: aef_id = self.invoker_capif_details["registered_security_contexes"][i]['aef_profiles'][n]['aef_id'] security_info = { - "prefSecurityMethods": ["Oauth"], + "prefSecurityMethods": ["OAUTH"], "authenticationInfo": "string", "authorizationInfo": "string", "aefId": aef_id, @@ -274,7 +274,7 @@ class service_discoverer: "websocketUri": "string", "requestWebsocketUri": True }, - "supportedFeatures": "fff" + "supportedFeatures": f"{self.supported_features}" } number_of_apis = len( @@ -286,9 +286,8 @@ class service_discoverer: api_id = self.invoker_capif_details["registered_security_contexes"][i]['api_id'] for n in range(0, len(aef_profiles)): aef_id = self.invoker_capif_details["registered_security_contexes"][i]['aef_profiles'][n]['aef_id'] - security_info = { - "prefSecurityMethods": ["Oauth"], + "prefSecurityMethods": ["OAUTH"], "authenticationInfo": "string", "authorizationInfo": "string", "aefId": aef_id, @@ -296,8 +295,6 @@ class service_discoverer: } payload["securityInfo"].append(security_info) - payload["securityInfo"].append(security_info) - try: response = requests.put(url, json=payload, @@ -509,7 +506,6 @@ class service_discoverer: raise def check_authentication(self): - print("hola") self.logger.info("Checking authentication") try: invoker_details = self.__load_provider_api_details() @@ -521,7 +517,6 @@ class service_discoverer: "apiInvokerId": f"{invoker_id}", "supportedFeatures": f"{self.supported_features}" } - print(self.supported_features) headers = { "Authorization": "Bearer {}".format(self.token), @@ -535,7 +530,6 @@ class service_discoverer: json=payload ) - print(response.text) response.raise_for_status() self.logger.info("Authentication of supported_features checked") diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index 4434717117c6d031790d0be354ad745160896999..0000000000000000000000000000000000000000 --- a/pyproject.toml +++ /dev/null @@ -1,51 +0,0 @@ -[build-system] -requires = ["setuptools>=61.0"] -build-backend = "setuptools.build_meta" - -[project] -name = "opencapif_sdk" -version = "0.1.15" -authors = [ - { name="JorgeEcheva", email="jorge.echevarriauribarri.practicas@telefonica.com" }, - { name="dgs-cgm", email="daniel.garciasanchez@telefonica.com" } -] -description = "This repository develops a Python Software Development Kit(SDK) which focuses on connecting to OpenCAPIF (Common API Framework for 3GPP Northbound APIs) in a simple way, lowering integration complexity and allowing developers to focus on Network Applications (Network Apps) or services development." -readme = "./doc/README_pipy.md" -license = { file="LICENSE" } -requires-python = ">=3.9" -keywords = ["pesp_capif_sdk","capif","sdk capif","opencapif_sdk"] -dependencies = [ - "requests==2.32.3", - "PyYAML==6.0.1", - "cryptography==38.0.4", - "pyOpenSSL==22.1.0", - "urllib3==2.2.2", - "certifi==2024.7.4", - "idna==3.7", - "Flask==3.0.3", - "Flask-JWT-Extended==4.6.0", - "Jinja2==3.1.4", - "MarkupSafe==2.1.5", - "six==1.16.0", - "typing-extensions>=4.8.0", - "Werkzeug==3.0.4", - "pytest==8.3.2", - "flake8==3.9.2", - "coverage==4.5.4", - "mccabe==0.6.1", - "pycodestyle==2.7.0", - "pyflakes==2.3.1", - "python-dateutil==2.9.0.post0", - "jinja2-time==0.2.0", - "text-unidecode==1.3", - "binaryornot==0.4.4" -] - - -classifiers = [ - "Programming Language :: Python :: 3", - "Operating System :: OS Independent", -] - -[project.urls] -"Homepage" = "https://github.com/Telefonica/pesp_capif_sdk" diff --git a/samples/config_sample.json b/samples/config_sample.json index 1a75d7da7835b30ae7c2a0f20c0eb7824f5beb5d..7096619f0a2c99cf3b9d746298a1eb42506f48be 100644 --- a/samples/config_sample.json +++ b/samples/config_sample.json @@ -39,9 +39,9 @@ "service-kpis": "" } }, - "provider": { "provider_folder": "", + "supported_features": "", "apfs": "", "aefs": "", "publish_req": { @@ -52,7 +52,7 @@ "" ] }, - "cert_generation":{ + "cert_generation": { "csr_common_name": "", "csr_organizational_unit": "", "csr_organization": "", @@ -62,5 +62,5 @@ "csr_email_address": "" }, "api_description_path": "" - } + } } diff --git a/samples/provider_api_description_sample.json b/samples/provider_api_description_sample.json index 02d872f572fd2b2b245f883b15cd92ad77e2fcac..954426989c236f6c4c45a550e26c23eab4bbdce8 100755 --- a/samples/provider_api_description_sample.json +++ b/samples/provider_api_description_sample.json @@ -47,14 +47,14 @@ "protocol": "HTTP_1_1", "dataFormat": "JSON", "securityMethods": [ - "Oauth" + "OAUTH" ], "interfaceDescriptions": [ { "ipv4Addr": "127.0.0.1", "port": 8888, "securityMethods": [ - "Oauth" + "OAUTH" ] } ] @@ -122,14 +122,14 @@ "protocol": "HTTP_1_1", "dataFormat": "JSON", "securityMethods": [ - "Oauth" + "OAUTH" ], "interfaceDescriptions": [ { "ipv4Addr": "127.0.0.1", "port": 8899, "securityMethods": [ - "Oauth" + "OAUTH" ] } ] diff --git a/setup.py b/setup.py index ace150b0f9af230197c46cf70069740407c99245..85a43dc9f362e987b101240220b3fd47013e2b76 100644 --- a/setup.py +++ b/setup.py @@ -1,9 +1,57 @@ -"""The setup script.""" - from setuptools import setup, find_packages +import os + +this_directory = os.path.abspath(os.path.dirname(__file__)) +with open(os.path.join(this_directory, "README_pipy.md"), encoding="utf-8") as f: + long_description = f.read() setup( - name='opencapif_sdk', - packages=find_packages(include=["opencapif_sdk"]), - version="0.1.15", -) \ No newline at end of file + name="opencapif_sdk", + version="0.1.17.3", + author="JorgeEcheva, dgs-cgm", + author_email="jorge.echevarriauribarri.practicas@telefonica.com, daniel.garciasanchez@telefonica.com", + description=( + "This repository develops a Python Software Development Kit(SDK) which focuses on " + "connecting to OpenCAPIF (Common API Framework for 3GPP Northbound APIs) in a simple way, " + "lowering integration complexity and allowing developers to focus on Network Applications (Network Apps) or services development." + ), + long_description=long_description, + long_description_content_type="text/markdown", + license="LICENSE", + python_requires=">=3.9", + keywords=[ + "pesp_capif_sdk", "capif", "sdk capif", "opencapif_sdk" + ], + classifiers=[ + "Programming Language :: Python :: 3", + "Operating System :: OS Independent", + ], + packages=find_packages(include=["opencapif_sdk", "opencapif_sdk.*"]), # Ajusta según tus necesidades + install_requires=[ + "requests==2.32.3", + "PyYAML==6.0.1", + "cryptography==38.0.4", + "pyOpenSSL==22.1.0", + "urllib3==2.2.2", + "certifi==2024.7.4", + "idna==3.7", + "Flask==3.0.3", + "Flask-JWT-Extended==4.6.0", + "Jinja2==3.1.4", + "MarkupSafe==2.1.5", + "six==1.16.0", + "typing-extensions>=4.8.0", + "Werkzeug==3.0.4", + "pytest==8.3.2", + "flake8==3.9.2", + "coverage==4.5.4", + "mccabe==0.6.1", + "pycodestyle==2.7.0", + "pyflakes==2.3.1", + "python-dateutil==2.9.0.post0", + "jinja2-time==0.2.0", + "text-unidecode==1.3", + "binaryornot==0.4.4", + ], + url="https://github.com/Telefonica/pesp_capif_sdk", +) diff --git a/test/capif_sdk_config_sample_test.json b/test/capif_sdk_config_sample_test.json index 49502a95d15470f10cd2c65a27b234f26ff1303f..7096619f0a2c99cf3b9d746298a1eb42506f48be 100644 --- a/test/capif_sdk_config_sample_test.json +++ b/test/capif_sdk_config_sample_test.json @@ -1,27 +1,27 @@ { - "capif_host": "capif-prev.mobilesandbox.cloud", - "register_host": "registercapif-prev.mobilesandbox.cloud", - "capif_https_port": "36212", - "capif_register_port": "36211", - "capif_username": "echeva_0", - "capif_password": "echevapass", - "debug_mode": "True", - "invoker":{ - "invoker_folder": "/Users/IDB0128/Documents/OpenCapif/test_invoker_certificate_folder", - "capif_callback_url": "http://localhost:5000", - "supported_features":"fffffff", - "check_authorization":{ + "capif_host": "", + "register_host": "", + "capif_https_port": "", + "capif_register_port": "", + "capif_username": "", + "capif_password": "", + "debug_mode": "", + "invoker": { + "invoker_folder": "", + "capif_callback_url": "", + "supported_features":"", + "check_authentication_data":{ "ip":"", "port":"" }, - "cert_generation":{ - "csr_common_name": "Echeva", - "csr_organizational_unit": "discovery", - "csr_organization": "telefonica", - "csr_locality": "madrid", - "csr_state_or_province_name": "madrid", - "csr_country_name": "ES", - "csr_email_address": "adios@gmail.com" + "cert_generation": { + "csr_common_name": "", + "csr_organizational_unit": "", + "csr_organization": "", + "csr_locality": "", + "csr_state_or_province_name": "", + "csr_country_name": "", + "csr_email_address": "" }, "discover_filter": { "api-name": "", @@ -39,19 +39,11 @@ "service-kpis": "" } }, - "provider":{ - "provider_folder": "/Users/IDB0128/Documents/OpenCapif/test_provider_certificate_folder", - "cert_generation":{ - "csr_common_name": "provider", - "csr_organizational_unit": "discovery", - "csr_organization": "telefonica", - "csr_locality": "madrid", - "csr_state_or_province_name": "madrid", - "csr_country_name": "ES", - "csr_email_address": "hola@gmail.com" - }, - "apfs": "2", - "aefs": "3", + "provider": { + "provider_folder": "", + "supported_features": "", + "apfs": "", + "aefs": "", "publish_req": { "service_api_id": "", "publisher_apf_id": "", @@ -60,6 +52,15 @@ "" ] }, + "cert_generation": { + "csr_common_name": "", + "csr_organizational_unit": "", + "csr_organization": "", + "csr_locality": "", + "csr_state_or_province_name": "", + "csr_country_name": "", + "csr_email_address": "" + }, "api_description_path": "" - } + } } diff --git a/test/network_app_provider_api_spec.json b/test/network_app_provider_api_spec.json index 9672934e439809185e2165e97e9bb1dd8404a673..5cf40654214dcde228a5b85c5d7e3c6441a93d18 100755 --- a/test/network_app_provider_api_spec.json +++ b/test/network_app_provider_api_spec.json @@ -47,7 +47,7 @@ "protocol": "HTTP_1_1", "dataFormat": "JSON", "securityMethods": [ - "Oauth", + "OAUTH", "PSK" ], "interfaceDescriptions": [ @@ -55,7 +55,7 @@ "ipv4Addr": "127.0.0.1", "port": 8888, "securityMethods": [ - "Oauth" + "OAUTH" ] } ] @@ -123,14 +123,14 @@ "protocol": "HTTP_1_1", "dataFormat": "JSON", "securityMethods": [ - "Oauth" + "OAUTH" ], "interfaceDescriptions": [ { "ipv4Addr": "127.0.0.1", "port": 8899, "securityMethods": [ - "Oauth" + "OAUTH" ] } ] diff --git a/test/network_app_provider_api_spec_2.json b/test/network_app_provider_api_spec_2.json index 0d54904cfb24ee79280504484ebfc7529d4f9fd1..94175bdcf3e1c29b993d30a91e99a1f4ced2b64f 100755 --- a/test/network_app_provider_api_spec_2.json +++ b/test/network_app_provider_api_spec_2.json @@ -47,7 +47,7 @@ "protocol": "HTTP_1_1", "dataFormat": "JSON", "securityMethods": [ - "Oauth", + "OAUTH", "PSK" ], "interfaceDescriptions": [ @@ -55,7 +55,7 @@ "ipv4Addr": "127.0.0.1", "port": 8888, "securityMethods": [ - "Oauth" + "OAUTH" ] } ] @@ -123,14 +123,14 @@ "protocol": "HTTP_1_1", "dataFormat": "JSON", "securityMethods": [ - "Oauth" + "OAUTH" ], "interfaceDescriptions": [ { "ipv4Addr": "127.0.0.1", "port": 8899, "securityMethods": [ - "Oauth" + "OAUTH" ] } ] @@ -181,7 +181,7 @@ "protocol": "HTTP_1_1", "dataFormat": "JSON", "securityMethods": [ - "Oauth", + "OAUTH", "PSK" ], "interfaceDescriptions": [ @@ -189,7 +189,7 @@ "ipv4Addr": "127.0.0.1", "port": 8888, "securityMethods": [ - "Oauth" + "OAUTH" ] } ] diff --git a/test/network_app_provider_api_spec_3.json b/test/network_app_provider_api_spec_3.json index 548b7408262c54241bb0fb81466339410e41d6bc..7b9fbe4f167620a2fb673fa02612b6af2b0b9364 100755 --- a/test/network_app_provider_api_spec_3.json +++ b/test/network_app_provider_api_spec_3.json @@ -47,7 +47,7 @@ "protocol": "HTTP_1_1", "dataFormat": "JSON", "securityMethods": [ - "Oauth", + "OAUTH", "PSK" ], "interfaceDescriptions": [ @@ -55,7 +55,7 @@ "ipv4Addr": "127.0.0.1", "port": 8888, "securityMethods": [ - "Oauth" + "OAUTH" ] } ] @@ -123,14 +123,14 @@ "protocol": "HTTP_1_1", "dataFormat": "JSON", "securityMethods": [ - "Oauth" + "OAUTH" ], "interfaceDescriptions": [ { "ipv4Addr": "127.0.0.1", "port": 8899, "securityMethods": [ - "Oauth" + "OAUTH" ] } ] diff --git a/test/test.py b/test/test.py index 143558a062a5ad51983b22f43a89727f847a7e2c..7332dc666f073311259fb843e27c0df1461f7d24 100644 --- a/test/test.py +++ b/test/test.py @@ -119,6 +119,8 @@ if __name__ == "__main__": print("INVOKER ONBOARDING COMPLETED") discoverer = service_discoverer(config_file=capif_sdk_config_path) + + discoverer.discover_filter["api-name"]= "Testtrece" discoverer.discover()