From 52df4829d9707080e2e544d563a39582d384f81c Mon Sep 17 00:00:00 2001 From: "claudia.carballo" Date: Fri, 19 Dec 2025 13:09:25 +0100 Subject: [PATCH 01/14] added visibility control api to helper --- services/helper/config.yaml | 4 +- .../openapi_helper_visibility_control.yaml | 533 +++++ .../helper/helper_service/openapitools.json | 7 + .../services/visibility_control/__init__.py | 0 .../services/visibility_control/__main__.py | 19 + .../controllers/__init__.py | 0 .../controllers/decision_controller.py | 21 + .../controllers/rules_controller.py | 49 + .../controllers/security_controller.py | 2 + .../visibility_control/core/__init__.py | 0 .../core/visibility_control_core.py | 44 + .../services/visibility_control/encoder.py | 19 + .../visibility_control/models/__init__.py | 30 + .../visibility_control/models/aef_location.py | 61 + .../visibility_control/models/aef_profile.py | 345 +++ .../visibility_control/models/api_status.py | 63 + .../visibility_control/models/base_model.py | 68 + .../models/communication_type.py | 39 + .../models/custom_operation.py | 147 ++ .../visibility_control/models/data_format.py | 40 + .../models/discovered_apis.py | 95 + .../visibility_control/models/error.py | 117 + .../models/interface_description.py | 221 ++ .../models/invoker_selector.py | 91 + .../models/ip_addr_range.py | 63 + ...ip_addr_range_ue_ipv4_addr_ranges_inner.py | 87 + .../models/o_auth_grant_type.py | 40 + .../visibility_control/models/operation.py | 42 + .../models/patch_provider_selector.py | 147 ++ .../visibility_control/models/protocol.py | 41 + .../models/provider_selector.py | 177 ++ .../models/published_api_path.py | 61 + .../visibility_control/models/resource.py | 201 ++ .../visibility_control/models/rule.py | 309 +++ .../models/rule_create_request.py | 229 ++ .../models/rule_patch_request.py | 227 ++ .../models/rules_get200_response.py | 91 + .../models/security_method.py | 40 + .../models/service_api_description.py | 365 ++++ .../visibility_control/models/service_kpis.py | 191 ++ .../models/shareable_information.py | 89 + .../visibility_control/models/version.py | 145 ++ .../visibility_control/openapi/openapi.yaml | 1938 +++++++++++++++++ .../visibility_control/typing_utils.py | 30 + .../services/visibility_control/util.py | 147 ++ 45 files changed, 6674 insertions(+), 1 deletion(-) create mode 100644 services/helper/helper_service/openapi_helper_visibility_control.yaml create mode 100644 services/helper/helper_service/openapitools.json create mode 100644 services/helper/helper_service/services/visibility_control/__init__.py create mode 100644 services/helper/helper_service/services/visibility_control/__main__.py create mode 100644 services/helper/helper_service/services/visibility_control/controllers/__init__.py create mode 100644 services/helper/helper_service/services/visibility_control/controllers/decision_controller.py create mode 100644 services/helper/helper_service/services/visibility_control/controllers/rules_controller.py create mode 100644 services/helper/helper_service/services/visibility_control/controllers/security_controller.py create mode 100644 services/helper/helper_service/services/visibility_control/core/__init__.py create mode 100644 services/helper/helper_service/services/visibility_control/core/visibility_control_core.py create mode 100644 services/helper/helper_service/services/visibility_control/encoder.py create mode 100644 services/helper/helper_service/services/visibility_control/models/__init__.py create mode 100644 services/helper/helper_service/services/visibility_control/models/aef_location.py create mode 100644 services/helper/helper_service/services/visibility_control/models/aef_profile.py create mode 100644 services/helper/helper_service/services/visibility_control/models/api_status.py create mode 100644 services/helper/helper_service/services/visibility_control/models/base_model.py create mode 100644 services/helper/helper_service/services/visibility_control/models/communication_type.py create mode 100644 services/helper/helper_service/services/visibility_control/models/custom_operation.py create mode 100644 services/helper/helper_service/services/visibility_control/models/data_format.py create mode 100644 services/helper/helper_service/services/visibility_control/models/discovered_apis.py create mode 100644 services/helper/helper_service/services/visibility_control/models/error.py create mode 100644 services/helper/helper_service/services/visibility_control/models/interface_description.py create mode 100644 services/helper/helper_service/services/visibility_control/models/invoker_selector.py create mode 100644 services/helper/helper_service/services/visibility_control/models/ip_addr_range.py create mode 100644 services/helper/helper_service/services/visibility_control/models/ip_addr_range_ue_ipv4_addr_ranges_inner.py create mode 100644 services/helper/helper_service/services/visibility_control/models/o_auth_grant_type.py create mode 100644 services/helper/helper_service/services/visibility_control/models/operation.py create mode 100644 services/helper/helper_service/services/visibility_control/models/patch_provider_selector.py create mode 100644 services/helper/helper_service/services/visibility_control/models/protocol.py create mode 100644 services/helper/helper_service/services/visibility_control/models/provider_selector.py create mode 100644 services/helper/helper_service/services/visibility_control/models/published_api_path.py create mode 100644 services/helper/helper_service/services/visibility_control/models/resource.py create mode 100644 services/helper/helper_service/services/visibility_control/models/rule.py create mode 100644 services/helper/helper_service/services/visibility_control/models/rule_create_request.py create mode 100644 services/helper/helper_service/services/visibility_control/models/rule_patch_request.py create mode 100644 services/helper/helper_service/services/visibility_control/models/rules_get200_response.py create mode 100644 services/helper/helper_service/services/visibility_control/models/security_method.py create mode 100644 services/helper/helper_service/services/visibility_control/models/service_api_description.py create mode 100644 services/helper/helper_service/services/visibility_control/models/service_kpis.py create mode 100644 services/helper/helper_service/services/visibility_control/models/shareable_information.py create mode 100644 services/helper/helper_service/services/visibility_control/models/version.py create mode 100644 services/helper/helper_service/services/visibility_control/openapi/openapi.yaml create mode 100644 services/helper/helper_service/services/visibility_control/typing_utils.py create mode 100644 services/helper/helper_service/services/visibility_control/util.py diff --git a/services/helper/config.yaml b/services/helper/config.yaml index 2cf3193d..1147d571 100644 --- a/services/helper/config.yaml +++ b/services/helper/config.yaml @@ -44,4 +44,6 @@ package_paths: configuration_api: path: /configuration openapi_file: configuration/openapi/openapi.yaml - + visibility_control: + path: /visibility-control + openapi_file: visibility_control/openapi/openapi.yaml diff --git a/services/helper/helper_service/openapi_helper_visibility_control.yaml b/services/helper/helper_service/openapi_helper_visibility_control.yaml new file mode 100644 index 00000000..4d386230 --- /dev/null +++ b/services/helper/helper_service/openapi_helper_visibility_control.yaml @@ -0,0 +1,533 @@ +openapi: 3.0.3 +info: + title: OpenCAPIF Access Control + version: 1.0.0 + description: | + Access-control API to manage visibility rules and evaluate decisions for API discovery and + security-context access within OpenCAPIF. This API controls whether APIs are visible to invokers + (discovery) and whether invokers are allowed to create a security context to access them. + - Rules are global and evaluated with "more specific wins" precedence. + - If no rule matches, the decision uses OpenCAPIF's global default (outside this API). + - Provider selector is mandatory in rules and must contain at least one selector field. +servers: + - url: https://capif.example.com/access-control + description: Production + - url: https://sandbox.capif.example.com/access-control + description: Sandbox + +tags: + - name: Rules + description: Manage visibility rules + - name: Decision + description: Evaluate discovery and access decisions + +paths: + /rules: + get: + tags: [Rules] + summary: List rules + responses: + '200': + description: List of rules + content: + application/json: + schema: + type: object + properties: + items: + type: array + items: + $ref: '#/components/schemas/Rule' + nextPageToken: + type: string + required: [items] + post: + tags: [Rules] + summary: Create a rule + description: Server generates the ruleId. Provider selector must include at least one field. + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/RuleCreateRequest' + examples: + allow_except_some_invokers: + value: + providerSelector: + createdByUser: "userA" + apiProviderId: [ "capif-prov-01", "capif-prov-02" ] + apiName: [ "apiName-001" ] + apiId: [ "apiId-001" ] + aefId: [ "aef-001" ] + invokerExceptions: + apiInvokerId: [ "invk-123", "invk-999" ] + default_access: ALLOW + enabled: true + responses: + '201': + description: Rule created + content: + application/json: + schema: + $ref: '#/components/schemas/Rule' + '400': + description: Invalid input + content: + application/json: + schema: { $ref: '#/components/schemas/Error' } + + /rules/{ruleId}: + get: + tags: [Rules] + summary: Get a rule + parameters: + - $ref: '#/components/parameters/RuleId' + responses: + '200': + description: Rule + content: + application/json: + schema: + $ref: '#/components/schemas/Rule' + '404': + description: Rule not found + content: + application/json: + schema: { $ref: '#/components/schemas/Error' } + patch: + tags: [Rules] + summary: Update a rule (partial) + parameters: + - $ref: '#/components/parameters/RuleId' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/RulePatchRequest' + responses: + '200': + description: Rule updated + content: + application/json: + schema: + $ref: '#/components/schemas/Rule' + '400': + description: Invalid input + content: + application/json: + schema: { $ref: '#/components/schemas/Error' } + '404': + description: Rule not found + content: + application/json: + schema: { $ref: '#/components/schemas/Error' } + delete: + tags: [Rules] + summary: Delete a rule + parameters: + - $ref: '#/components/parameters/RuleId' + responses: + '204': + description: Deleted + '404': + description: Rule not found + content: + application/json: + schema: { $ref: '#/components/schemas/Error' } + + /decision/invokers/{apiInvokerId}/discoverable-apis: + get: + tags: [Decision] + summary: Get discoverable APIs filter for an invoker (global scope) + description: | + Returns a filtered list of APIs for the API Invoker. + parameters: + - $ref: '#/components/parameters/ApiInvokerId' + responses: + '200': + description: Discover filter + content: + application/json: + schema: + $ref: '#/components/schemas/DiscoveredAPIs' + '400': + description: Invalid input + content: + application/json: + schema: { $ref: '#/components/schemas/Error' } + '404': + description: Invoker not found (optional behavior) + content: + application/json: + schema: { $ref: '#/components/schemas/Error' } + +components: + parameters: + RuleId: + in: path + name: ruleId + required: true + schema: + type: string + description: Server-generated rule identifier + ApiInvokerId: + in: path + name: apiInvokerId + required: true + schema: + type: string + description: CAPIF API Invoker identifier + + schemas: + # ---------- Core Rule Schemas ---------- + RuleCreateRequest: + type: object + required: [providerSelector, default_access] + properties: + providerSelector: + $ref: '#/components/schemas/ProviderSelector' + invokerExceptions: + $ref: '#/components/schemas/InvokerSelector' + default_access: + type: string + enum: [ALLOW, DENY] + enabled: + type: boolean + default: true + startsAt: + type: string + format: date-time + endsAt: + type: string + format: date-time + notes: + type: string + description: | + Create a new rule. Provider selector is mandatory and must include at least one field. + If both startsAt and endsAt are present, endsAt must be greater than startsAt. + + RulePatchRequest: + type: object + properties: + providerSelector: + $ref: '#/components/schemas/PatchProviderSelector' + invokerExceptions: + $ref: '#/components/schemas/InvokerSelector' + default_access: + type: string + enum: [ALLOW, DENY] + enabled: + type: boolean + startsAt: + type: string + format: date-time + endsAt: + type: string + format: date-time + notes: + type: string + description: Partial update. Any omitted field remains unchanged. + + Rule: + type: object + properties: + ruleId: + type: string + providerSelector: + $ref: '#/components/schemas/ProviderSelector' + invokerExceptions: + $ref: '#/components/schemas/InvokerSelector' + default_access: + type: string + enum: [ALLOW, DENY] + enabled: + type: boolean + default: true + startsAt: + type: string + format: date-time + endsAt: + type: string + format: date-time + notes: + type: string + updatedAt: + type: string + format: date-time + updatedBy: + type: string + required: [ruleId, providerSelector, default_access] + + PatchProviderSelector: + type: object + description: | + Patch Provider-side selector. + properties: + apiProviderId: + type: array + items: { type: string } + minItems: 0 + uniqueItems: true + apiName: + type: array + items: { type: string } + minItems: 0 + uniqueItems: true + apiId: + type: array + items: { type: string } + minItems: 0 + uniqueItems: true + aefId: + type: array + items: { type: string } + minItems: 0 + uniqueItems: true + additionalProperties: false + + ProviderSelector: + type: object + description: | + Provider-side selector. Arrays apply OR within the field; AND across fields. + At least one of these fields must be present. + required: + - createdByUser + properties: + createdByUser: + type: string + minLength: 1 + apiProviderId: + type: array + items: { type: string } + minItems: 0 + uniqueItems: true + apiName: + type: array + items: { type: string } + minItems: 0 + uniqueItems: true + apiId: + type: array + items: { type: string } + minItems: 0 + uniqueItems: true + aefId: + type: array + items: { type: string } + minItems: 0 + uniqueItems: true + additionalProperties: false + + InvokerSelector: + type: object + description: Invoker-side selector used for exceptions. Optional; arrays use OR within the field; AND across fields. + properties: + invokerOnboardedByUser: + type: array + items: { type: string } + minItems: 0 + uniqueItems: true + apiInvokerId: + type: array + items: { type: string } + minItems: 0 + uniqueItems: true + additionalProperties: false + + # ---------- Decision Schemas (3GPP Based) ---------- + DiscoveredAPIs: + type: object + properties: + serviceAPIDescriptions: + type: array + items: + $ref: '#/components/schemas/ServiceAPIDescription' + minItems: 1 + suppFeat: + $ref: '#/components/schemas/SupportedFeatures' + + ServiceAPIDescription: + type: object + required: [apiName] + properties: + apiName: { type: string } + apiId: { type: string } + apiStatus: { $ref: '#/components/schemas/ApiStatus' } + aefProfiles: + type: array + items: { $ref: '#/components/schemas/AefProfile' } + minItems: 1 + description: { type: string } + supportedFeatures: { $ref: '#/components/schemas/SupportedFeatures' } + shareableInfo: { $ref: '#/components/schemas/ShareableInformation' } + serviceAPICategory: { type: string } + apiSuppFeats: { $ref: '#/components/schemas/SupportedFeatures' } + pubApiPath: { $ref: '#/components/schemas/PublishedApiPath' } + ccfId: { type: string } + apiProvName: { type: string } + #apiProvName is apiProviderId? + + + AefProfile: + type: object + required: [aefId, versions] + properties: + aefId: { type: string } + versions: + type: array + items: { $ref: '#/components/schemas/Version' } + minItems: 1 + protocol: { $ref: '#/components/schemas/Protocol' } + dataFormat: { $ref: '#/components/schemas/DataFormat' } + securityMethods: + type: array + items: { $ref: '#/components/schemas/SecurityMethod' } + grantTypes: + type: array + items: { $ref: '#/components/schemas/OAuthGrantType' } + domainName: { type: string } + interfaceDescriptions: + type: array + items: { $ref: '#/components/schemas/InterfaceDescription' } + aefLocation: { $ref: '#/components/schemas/AefLocation' } + serviceKpis: { $ref: '#/components/schemas/ServiceKpis' } + ueIpRange: { $ref: '#/components/schemas/IpAddrRange' } + + Version: + type: object + required: [apiVersion] + properties: + apiVersion: { type: string } + expiry: { type: string, format: date-time } + resources: + type: array + items: { $ref: '#/components/schemas/Resource' } + custOperations: + type: array + items: { $ref: '#/components/schemas/CustomOperation' } + + Resource: + type: object + required: [commType, resourceName, uri] + properties: + resourceName: { type: string } + commType: { $ref: '#/components/schemas/CommunicationType' } + uri: { type: string } + custOpName: { type: string } + operations: + type: array + items: { $ref: '#/components/schemas/Operation' } + description: { type: string } + + CustomOperation: + type: object + required: [commType, custOpName] + properties: + commType: { $ref: '#/components/schemas/CommunicationType' } + custOpName: { type: string } + operations: + type: array + items: { $ref: '#/components/schemas/Operation' } + description: { type: string } + + ApiStatus: + type: object + required: [aefIds] + properties: + aefIds: + type: array + items: { type: string } + + InterfaceDescription: + type: object + properties: + ipv4Addr: { type: string } + ipv6Addr: { type: string } + fqdn: { type: string } + port: { type: integer } + apiPrefix: { type: string } + securityMethods: + type: array + items: { $ref: '#/components/schemas/SecurityMethod' } + grantTypes: + type: array + items: { $ref: '#/components/schemas/OAuthGrantType' } + + # ---------- Supporting 3GPP Types ---------- + SupportedFeatures: + type: string + pattern: "^[A-Fa-f0-9]*$" + CommunicationType: + type: string + enum: [REQUEST_RESPONSE, SUBSCRIBE_NOTIFY] + Protocol: + type: string + enum: [HTTP_1_1, HTTP_2, MQTT, WEBSOCKET] + DataFormat: + type: string + enum: [JSON, XML, PROTOBUF3] + Operation: + type: string + enum: [GET, POST, PUT, PATCH, DELETE] + SecurityMethod: + type: string + enum: [PSK, PKI, OAUTH] + OAuthGrantType: + type: string + enum: [CLIENT_CREDENTIALS, AUTHORIZATION_CODE, AUTHORIZATION_CODE_WITH_PKCE] + + ShareableInformation: + type: object + required: [isShareable] + properties: + isShareable: { type: boolean } + capifProvDoms: + type: array + items: { type: string } + + PublishedApiPath: + type: object + properties: + ccfIds: + type: array + items: { type: string } + + AefLocation: + type: object + properties: + dcId: { type: string } + # Simplified for brevity, you can add GeographicArea/CivicAddress if needed + + ServiceKpis: + type: object + properties: + maxReqRate: { type: integer } + maxRestime: { type: integer } + availability: { type: integer } + avalComp: { type: string } + avalMem: { type: string } + avalStor: { type: string } + + IpAddrRange: + type: object + properties: + ueIpv4AddrRanges: + type: array + items: + type: object + properties: + start: { type: string } + end: { type: string } + + # ---------- Errors ---------- + Error: + type: object + required: [code, message] + properties: + code: { type: string } + message: { type: string } + details: + type: object + additionalProperties: true \ No newline at end of file diff --git a/services/helper/helper_service/openapitools.json b/services/helper/helper_service/openapitools.json new file mode 100644 index 00000000..f8d07ce1 --- /dev/null +++ b/services/helper/helper_service/openapitools.json @@ -0,0 +1,7 @@ +{ + "$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json", + "spaces": 2, + "generator-cli": { + "version": "7.10.0" + } +} diff --git a/services/helper/helper_service/services/visibility_control/__init__.py b/services/helper/helper_service/services/visibility_control/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/services/helper/helper_service/services/visibility_control/__main__.py b/services/helper/helper_service/services/visibility_control/__main__.py new file mode 100644 index 00000000..346127a6 --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/__main__.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 + +import connexion + +from visibility_control import encoder + + +def main(): + app = connexion.App(__name__, specification_dir='./openapi/') + app.app.json_encoder = encoder.JSONEncoder + app.add_api('openapi.yaml', + arguments={'title': 'OpenCAPIF Access Control'}, + pythonic_params=True) + + app.run(port=8080) + + +if __name__ == '__main__': + main() diff --git a/services/helper/helper_service/services/visibility_control/controllers/__init__.py b/services/helper/helper_service/services/visibility_control/controllers/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/services/helper/helper_service/services/visibility_control/controllers/decision_controller.py b/services/helper/helper_service/services/visibility_control/controllers/decision_controller.py new file mode 100644 index 00000000..4bfdeaff --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/controllers/decision_controller.py @@ -0,0 +1,21 @@ +import connexion +from typing import Dict +from typing import Tuple +from typing import Union + +from visibility_control.models.discovered_apis import DiscoveredAPIs # noqa: E501 +from visibility_control.models.error import Error # noqa: E501 +from visibility_control import util + + +def decision_invokers_api_invoker_id_discoverable_apis_get(api_invoker_id): # noqa: E501 + """Get discoverable APIs filter for an invoker (global scope) + + Returns a filtered list of APIs for the API Invoker. # noqa: E501 + + :param api_invoker_id: CAPIF API Invoker identifier + :type api_invoker_id: str + + :rtype: Union[DiscoveredAPIs, Tuple[DiscoveredAPIs, int], Tuple[DiscoveredAPIs, int, Dict[str, str]] + """ + return 'do some magic!' diff --git a/services/helper/helper_service/services/visibility_control/controllers/rules_controller.py b/services/helper/helper_service/services/visibility_control/controllers/rules_controller.py new file mode 100644 index 00000000..bc0a3014 --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/controllers/rules_controller.py @@ -0,0 +1,49 @@ +import connexion +from typing import Dict, Tuple, Union + +# Importamos la lógica del CORE (Asegúrate de crear este archivo después) +from ..core.visibility_control_core import ( + get_all_rules, + create_new_rule, + get_rule_by_id, + delete_rule_by_id, + update_rule_patch +) + +from visibility_control.models.error import Error +from visibility_control.models.rule import Rule +from visibility_control.models.rule_create_request import RuleCreateRequest +from visibility_control.models.rule_patch_request import RulePatchRequest +from visibility_control.models.rules_get200_response import RulesGet200Response +from visibility_control import util + +def rules_get(): + """List rules""" + return get_all_rules() + +def rules_post(body): + """ + Create a rule + """ + if body is not None: + return create_new_rule(body) + if connexion.request.is_json: + body = connexion.request.get_json() + return create_new_rule(body) + + return Error(title="Bad Request", detail="JSON body required", status=400), 400 + +def rules_rule_id_delete(rule_id): + """Delete a rule""" + return delete_rule_by_id(rule_id) + +def rules_rule_id_get(rule_id): + """Get a rule""" + return get_rule_by_id(rule_id) + +def rules_rule_id_patch(rule_id, rule_patch_request): + """Update a rule (partial)""" + if connexion.request.is_json: + body = connexion.request.get_json() + return update_rule_patch(rule_id, body) + return Error(title="Bad Request", detail="JSON body required", status=400), 400 \ No newline at end of file diff --git a/services/helper/helper_service/services/visibility_control/controllers/security_controller.py b/services/helper/helper_service/services/visibility_control/controllers/security_controller.py new file mode 100644 index 00000000..6d294ffd --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/controllers/security_controller.py @@ -0,0 +1,2 @@ +from typing import List + diff --git a/services/helper/helper_service/services/visibility_control/core/__init__.py b/services/helper/helper_service/services/visibility_control/core/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/services/helper/helper_service/services/visibility_control/core/visibility_control_core.py b/services/helper/helper_service/services/visibility_control/core/visibility_control_core.py new file mode 100644 index 00000000..6d3af076 --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/core/visibility_control_core.py @@ -0,0 +1,44 @@ +import uuid +from db.db import get_mongo +from config import Config + +def get_all_rules(): + db = get_mongo() + # Usamos la colección configurada en el helper + col = db.get_col_by_name("visibility_rules") + rules = list(col.find({}, {"_id": 0})) + return {"rules": rules}, 200 + +def create_new_rule(body): + db = get_mongo() + col = db.get_col_by_name("visibility_rules") + + # Generamos el ruleId (Server generates it, según tu comentario) + body['ruleId'] = str(uuid.uuid4()) + + col.insert_one(body) + body.pop('_id', None) + return body, 201 + +def get_rule_by_id(rule_id): + db = get_mongo() + col = db.get_col_by_name("visibility_rules") + rule = col.find_one({"ruleId": rule_id}, {"_id": 0}) + if rule: + return rule, 200 + return {"title": "Not Found", "detail": "Rule not found"}, 404 + +def delete_rule_by_id(rule_id): + db = get_mongo() + col = db.get_col_by_name("visibility_rules") + res = col.delete_one({"ruleId": rule_id}) + if res.deleted_count > 0: + return None, 204 + return {"title": "Not Found", "detail": "Rule not found"}, 404 + +def update_rule_patch(rule_id, body): + db = get_mongo() + col = db.get_col_by_name("visibility_rules") + col.update_one({"ruleId": rule_id}, {"$set": body}) + updated_rule = col.find_one({"ruleId": rule_id}, {"_id": 0}) + return updated_rule, 200 \ No newline at end of file diff --git a/services/helper/helper_service/services/visibility_control/encoder.py b/services/helper/helper_service/services/visibility_control/encoder.py new file mode 100644 index 00000000..740bbe7d --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/encoder.py @@ -0,0 +1,19 @@ +from connexion.apps.flask_app import FlaskJSONEncoder + +from visibility_control.models.base_model import Model + + +class JSONEncoder(FlaskJSONEncoder): + include_nulls = False + + def default(self, o): + if isinstance(o, Model): + dikt = {} + for attr in o.openapi_types: + value = getattr(o, attr) + if value is None and not self.include_nulls: + continue + attr = o.attribute_map[attr] + dikt[attr] = value + return dikt + return FlaskJSONEncoder.default(self, o) diff --git a/services/helper/helper_service/services/visibility_control/models/__init__.py b/services/helper/helper_service/services/visibility_control/models/__init__.py new file mode 100644 index 00000000..8ba41842 --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/models/__init__.py @@ -0,0 +1,30 @@ +# flake8: noqa +# import models into model package +from visibility_control.models.aef_location import AefLocation +from visibility_control.models.aef_profile import AefProfile +from visibility_control.models.api_status import ApiStatus +from visibility_control.models.communication_type import CommunicationType +from visibility_control.models.custom_operation import CustomOperation +from visibility_control.models.data_format import DataFormat +from visibility_control.models.discovered_apis import DiscoveredAPIs +from visibility_control.models.error import Error +from visibility_control.models.interface_description import InterfaceDescription +from visibility_control.models.invoker_selector import InvokerSelector +from visibility_control.models.ip_addr_range import IpAddrRange +from visibility_control.models.ip_addr_range_ue_ipv4_addr_ranges_inner import IpAddrRangeUeIpv4AddrRangesInner +from visibility_control.models.o_auth_grant_type import OAuthGrantType +from visibility_control.models.operation import Operation +from visibility_control.models.patch_provider_selector import PatchProviderSelector +from visibility_control.models.protocol import Protocol +from visibility_control.models.provider_selector import ProviderSelector +from visibility_control.models.published_api_path import PublishedApiPath +from visibility_control.models.resource import Resource +from visibility_control.models.rule import Rule +from visibility_control.models.rule_create_request import RuleCreateRequest +from visibility_control.models.rule_patch_request import RulePatchRequest +from visibility_control.models.rules_get200_response import RulesGet200Response +from visibility_control.models.security_method import SecurityMethod +from visibility_control.models.service_api_description import ServiceAPIDescription +from visibility_control.models.service_kpis import ServiceKpis +from visibility_control.models.shareable_information import ShareableInformation +from visibility_control.models.version import Version diff --git a/services/helper/helper_service/services/visibility_control/models/aef_location.py b/services/helper/helper_service/services/visibility_control/models/aef_location.py new file mode 100644 index 00000000..fa0d4275 --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/models/aef_location.py @@ -0,0 +1,61 @@ +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from visibility_control.models.base_model import Model +from visibility_control import util + + +class AefLocation(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, dc_id=None): # noqa: E501 + """AefLocation - a model defined in OpenAPI + + :param dc_id: The dc_id of this AefLocation. # noqa: E501 + :type dc_id: str + """ + self.openapi_types = { + 'dc_id': str + } + + self.attribute_map = { + 'dc_id': 'dcId' + } + + self._dc_id = dc_id + + @classmethod + def from_dict(cls, dikt) -> 'AefLocation': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The AefLocation of this AefLocation. # noqa: E501 + :rtype: AefLocation + """ + return util.deserialize_model(dikt, cls) + + @property + def dc_id(self) -> str: + """Gets the dc_id of this AefLocation. + + + :return: The dc_id of this AefLocation. + :rtype: str + """ + return self._dc_id + + @dc_id.setter + def dc_id(self, dc_id: str): + """Sets the dc_id of this AefLocation. + + + :param dc_id: The dc_id of this AefLocation. + :type dc_id: str + """ + + self._dc_id = dc_id diff --git a/services/helper/helper_service/services/visibility_control/models/aef_profile.py b/services/helper/helper_service/services/visibility_control/models/aef_profile.py new file mode 100644 index 00000000..8d9535c2 --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/models/aef_profile.py @@ -0,0 +1,345 @@ +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from visibility_control.models.base_model import Model +from visibility_control.models.aef_location import AefLocation +from visibility_control.models.data_format import DataFormat +from visibility_control.models.interface_description import InterfaceDescription +from visibility_control.models.ip_addr_range import IpAddrRange +from visibility_control.models.o_auth_grant_type import OAuthGrantType +from visibility_control.models.protocol import Protocol +from visibility_control.models.security_method import SecurityMethod +from visibility_control.models.service_kpis import ServiceKpis +from visibility_control.models.version import Version +from visibility_control import util + +from visibility_control.models.aef_location import AefLocation # noqa: E501 +from visibility_control.models.data_format import DataFormat # noqa: E501 +from visibility_control.models.interface_description import InterfaceDescription # noqa: E501 +from visibility_control.models.ip_addr_range import IpAddrRange # noqa: E501 +from visibility_control.models.o_auth_grant_type import OAuthGrantType # noqa: E501 +from visibility_control.models.protocol import Protocol # noqa: E501 +from visibility_control.models.security_method import SecurityMethod # noqa: E501 +from visibility_control.models.service_kpis import ServiceKpis # noqa: E501 +from visibility_control.models.version import Version # noqa: E501 + +class AefProfile(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, aef_id=None, versions=None, protocol=None, data_format=None, security_methods=None, grant_types=None, domain_name=None, interface_descriptions=None, aef_location=None, service_kpis=None, ue_ip_range=None): # noqa: E501 + """AefProfile - a model defined in OpenAPI + + :param aef_id: The aef_id of this AefProfile. # noqa: E501 + :type aef_id: str + :param versions: The versions of this AefProfile. # noqa: E501 + :type versions: List[Version] + :param protocol: The protocol of this AefProfile. # noqa: E501 + :type protocol: Protocol + :param data_format: The data_format of this AefProfile. # noqa: E501 + :type data_format: DataFormat + :param security_methods: The security_methods of this AefProfile. # noqa: E501 + :type security_methods: List[SecurityMethod] + :param grant_types: The grant_types of this AefProfile. # noqa: E501 + :type grant_types: List[OAuthGrantType] + :param domain_name: The domain_name of this AefProfile. # noqa: E501 + :type domain_name: str + :param interface_descriptions: The interface_descriptions of this AefProfile. # noqa: E501 + :type interface_descriptions: List[InterfaceDescription] + :param aef_location: The aef_location of this AefProfile. # noqa: E501 + :type aef_location: AefLocation + :param service_kpis: The service_kpis of this AefProfile. # noqa: E501 + :type service_kpis: ServiceKpis + :param ue_ip_range: The ue_ip_range of this AefProfile. # noqa: E501 + :type ue_ip_range: IpAddrRange + """ + self.openapi_types = { + 'aef_id': str, + 'versions': List[Version], + 'protocol': Protocol, + 'data_format': DataFormat, + 'security_methods': List[SecurityMethod], + 'grant_types': List[OAuthGrantType], + 'domain_name': str, + 'interface_descriptions': List[InterfaceDescription], + 'aef_location': AefLocation, + 'service_kpis': ServiceKpis, + 'ue_ip_range': IpAddrRange + } + + self.attribute_map = { + 'aef_id': 'aefId', + 'versions': 'versions', + 'protocol': 'protocol', + 'data_format': 'dataFormat', + 'security_methods': 'securityMethods', + 'grant_types': 'grantTypes', + 'domain_name': 'domainName', + 'interface_descriptions': 'interfaceDescriptions', + 'aef_location': 'aefLocation', + 'service_kpis': 'serviceKpis', + 'ue_ip_range': 'ueIpRange' + } + + self._aef_id = aef_id + self._versions = versions + self._protocol = protocol + self._data_format = data_format + self._security_methods = security_methods + self._grant_types = grant_types + self._domain_name = domain_name + self._interface_descriptions = interface_descriptions + self._aef_location = aef_location + self._service_kpis = service_kpis + self._ue_ip_range = ue_ip_range + + @classmethod + def from_dict(cls, dikt) -> 'AefProfile': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The AefProfile of this AefProfile. # noqa: E501 + :rtype: AefProfile + """ + return util.deserialize_model(dikt, cls) + + @property + def aef_id(self) -> str: + """Gets the aef_id of this AefProfile. + + + :return: The aef_id of this AefProfile. + :rtype: str + """ + return self._aef_id + + @aef_id.setter + def aef_id(self, aef_id: str): + """Sets the aef_id of this AefProfile. + + + :param aef_id: The aef_id of this AefProfile. + :type aef_id: str + """ + if aef_id is None: + raise ValueError("Invalid value for `aef_id`, must not be `None`") # noqa: E501 + + self._aef_id = aef_id + + @property + def versions(self) -> List[Version]: + """Gets the versions of this AefProfile. + + + :return: The versions of this AefProfile. + :rtype: List[Version] + """ + return self._versions + + @versions.setter + def versions(self, versions: List[Version]): + """Sets the versions of this AefProfile. + + + :param versions: The versions of this AefProfile. + :type versions: List[Version] + """ + if versions is None: + raise ValueError("Invalid value for `versions`, must not be `None`") # noqa: E501 + if versions is not None and len(versions) < 1: + raise ValueError("Invalid value for `versions`, number of items must be greater than or equal to `1`") # noqa: E501 + + self._versions = versions + + @property + def protocol(self) -> Protocol: + """Gets the protocol of this AefProfile. + + + :return: The protocol of this AefProfile. + :rtype: Protocol + """ + return self._protocol + + @protocol.setter + def protocol(self, protocol: Protocol): + """Sets the protocol of this AefProfile. + + + :param protocol: The protocol of this AefProfile. + :type protocol: Protocol + """ + + self._protocol = protocol + + @property + def data_format(self) -> DataFormat: + """Gets the data_format of this AefProfile. + + + :return: The data_format of this AefProfile. + :rtype: DataFormat + """ + return self._data_format + + @data_format.setter + def data_format(self, data_format: DataFormat): + """Sets the data_format of this AefProfile. + + + :param data_format: The data_format of this AefProfile. + :type data_format: DataFormat + """ + + self._data_format = data_format + + @property + def security_methods(self) -> List[SecurityMethod]: + """Gets the security_methods of this AefProfile. + + + :return: The security_methods of this AefProfile. + :rtype: List[SecurityMethod] + """ + return self._security_methods + + @security_methods.setter + def security_methods(self, security_methods: List[SecurityMethod]): + """Sets the security_methods of this AefProfile. + + + :param security_methods: The security_methods of this AefProfile. + :type security_methods: List[SecurityMethod] + """ + + self._security_methods = security_methods + + @property + def grant_types(self) -> List[OAuthGrantType]: + """Gets the grant_types of this AefProfile. + + + :return: The grant_types of this AefProfile. + :rtype: List[OAuthGrantType] + """ + return self._grant_types + + @grant_types.setter + def grant_types(self, grant_types: List[OAuthGrantType]): + """Sets the grant_types of this AefProfile. + + + :param grant_types: The grant_types of this AefProfile. + :type grant_types: List[OAuthGrantType] + """ + + self._grant_types = grant_types + + @property + def domain_name(self) -> str: + """Gets the domain_name of this AefProfile. + + + :return: The domain_name of this AefProfile. + :rtype: str + """ + return self._domain_name + + @domain_name.setter + def domain_name(self, domain_name: str): + """Sets the domain_name of this AefProfile. + + + :param domain_name: The domain_name of this AefProfile. + :type domain_name: str + """ + + self._domain_name = domain_name + + @property + def interface_descriptions(self) -> List[InterfaceDescription]: + """Gets the interface_descriptions of this AefProfile. + + + :return: The interface_descriptions of this AefProfile. + :rtype: List[InterfaceDescription] + """ + return self._interface_descriptions + + @interface_descriptions.setter + def interface_descriptions(self, interface_descriptions: List[InterfaceDescription]): + """Sets the interface_descriptions of this AefProfile. + + + :param interface_descriptions: The interface_descriptions of this AefProfile. + :type interface_descriptions: List[InterfaceDescription] + """ + + self._interface_descriptions = interface_descriptions + + @property + def aef_location(self) -> AefLocation: + """Gets the aef_location of this AefProfile. + + + :return: The aef_location of this AefProfile. + :rtype: AefLocation + """ + return self._aef_location + + @aef_location.setter + def aef_location(self, aef_location: AefLocation): + """Sets the aef_location of this AefProfile. + + + :param aef_location: The aef_location of this AefProfile. + :type aef_location: AefLocation + """ + + self._aef_location = aef_location + + @property + def service_kpis(self) -> ServiceKpis: + """Gets the service_kpis of this AefProfile. + + + :return: The service_kpis of this AefProfile. + :rtype: ServiceKpis + """ + return self._service_kpis + + @service_kpis.setter + def service_kpis(self, service_kpis: ServiceKpis): + """Sets the service_kpis of this AefProfile. + + + :param service_kpis: The service_kpis of this AefProfile. + :type service_kpis: ServiceKpis + """ + + self._service_kpis = service_kpis + + @property + def ue_ip_range(self) -> IpAddrRange: + """Gets the ue_ip_range of this AefProfile. + + + :return: The ue_ip_range of this AefProfile. + :rtype: IpAddrRange + """ + return self._ue_ip_range + + @ue_ip_range.setter + def ue_ip_range(self, ue_ip_range: IpAddrRange): + """Sets the ue_ip_range of this AefProfile. + + + :param ue_ip_range: The ue_ip_range of this AefProfile. + :type ue_ip_range: IpAddrRange + """ + + self._ue_ip_range = ue_ip_range diff --git a/services/helper/helper_service/services/visibility_control/models/api_status.py b/services/helper/helper_service/services/visibility_control/models/api_status.py new file mode 100644 index 00000000..9c00fa2d --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/models/api_status.py @@ -0,0 +1,63 @@ +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from visibility_control.models.base_model import Model +from visibility_control import util + + +class ApiStatus(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, aef_ids=None): # noqa: E501 + """ApiStatus - a model defined in OpenAPI + + :param aef_ids: The aef_ids of this ApiStatus. # noqa: E501 + :type aef_ids: List[str] + """ + self.openapi_types = { + 'aef_ids': List[str] + } + + self.attribute_map = { + 'aef_ids': 'aefIds' + } + + self._aef_ids = aef_ids + + @classmethod + def from_dict(cls, dikt) -> 'ApiStatus': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The ApiStatus of this ApiStatus. # noqa: E501 + :rtype: ApiStatus + """ + return util.deserialize_model(dikt, cls) + + @property + def aef_ids(self) -> List[str]: + """Gets the aef_ids of this ApiStatus. + + + :return: The aef_ids of this ApiStatus. + :rtype: List[str] + """ + return self._aef_ids + + @aef_ids.setter + def aef_ids(self, aef_ids: List[str]): + """Sets the aef_ids of this ApiStatus. + + + :param aef_ids: The aef_ids of this ApiStatus. + :type aef_ids: List[str] + """ + if aef_ids is None: + raise ValueError("Invalid value for `aef_ids`, must not be `None`") # noqa: E501 + + self._aef_ids = aef_ids diff --git a/services/helper/helper_service/services/visibility_control/models/base_model.py b/services/helper/helper_service/services/visibility_control/models/base_model.py new file mode 100644 index 00000000..ad4a3fb5 --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/models/base_model.py @@ -0,0 +1,68 @@ +import pprint + +import typing + +from visibility_control import util + +T = typing.TypeVar('T') + + +class Model: + # openapiTypes: The key is attribute name and the + # value is attribute type. + openapi_types: typing.Dict[str, type] = {} + + # attributeMap: The key is attribute name and the + # value is json key in definition. + attribute_map: typing.Dict[str, str] = {} + + @classmethod + def from_dict(cls: typing.Type[T], dikt) -> T: + """Returns the dict as a model""" + return util.deserialize_model(dikt, cls) + + def to_dict(self): + """Returns the model properties as a dict + + :rtype: dict + """ + result = {} + + for attr in self.openapi_types: + value = getattr(self, attr) + if isinstance(value, list): + result[attr] = list(map( + lambda x: x.to_dict() if hasattr(x, "to_dict") else x, + value + )) + elif hasattr(value, "to_dict"): + result[attr] = value.to_dict() + elif isinstance(value, dict): + result[attr] = dict(map( + lambda item: (item[0], item[1].to_dict()) + if hasattr(item[1], "to_dict") else item, + value.items() + )) + else: + result[attr] = value + + return result + + def to_str(self): + """Returns the string representation of the model + + :rtype: str + """ + return pprint.pformat(self.to_dict()) + + def __repr__(self): + """For `print` and `pprint`""" + return self.to_str() + + def __eq__(self, other): + """Returns true if both objects are equal""" + return self.__dict__ == other.__dict__ + + def __ne__(self, other): + """Returns true if both objects are not equal""" + return not self == other diff --git a/services/helper/helper_service/services/visibility_control/models/communication_type.py b/services/helper/helper_service/services/visibility_control/models/communication_type.py new file mode 100644 index 00000000..5ef1f973 --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/models/communication_type.py @@ -0,0 +1,39 @@ +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from visibility_control.models.base_model import Model +from visibility_control import util + + +class CommunicationType(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + """ + allowed enum values + """ + REQUEST_RESPONSE = 'REQUEST_RESPONSE' + SUBSCRIBE_NOTIFY = 'SUBSCRIBE_NOTIFY' + def __init__(self): # noqa: E501 + """CommunicationType - a model defined in OpenAPI + + """ + self.openapi_types = { + } + + self.attribute_map = { + } + + @classmethod + def from_dict(cls, dikt) -> 'CommunicationType': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The CommunicationType of this CommunicationType. # noqa: E501 + :rtype: CommunicationType + """ + return util.deserialize_model(dikt, cls) diff --git a/services/helper/helper_service/services/visibility_control/models/custom_operation.py b/services/helper/helper_service/services/visibility_control/models/custom_operation.py new file mode 100644 index 00000000..9699385d --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/models/custom_operation.py @@ -0,0 +1,147 @@ +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from visibility_control.models.base_model import Model +from visibility_control.models.communication_type import CommunicationType +from visibility_control.models.operation import Operation +from visibility_control import util + +from visibility_control.models.communication_type import CommunicationType # noqa: E501 +from visibility_control.models.operation import Operation # noqa: E501 + +class CustomOperation(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, comm_type=None, cust_op_name=None, operations=None, description=None): # noqa: E501 + """CustomOperation - a model defined in OpenAPI + + :param comm_type: The comm_type of this CustomOperation. # noqa: E501 + :type comm_type: CommunicationType + :param cust_op_name: The cust_op_name of this CustomOperation. # noqa: E501 + :type cust_op_name: str + :param operations: The operations of this CustomOperation. # noqa: E501 + :type operations: List[Operation] + :param description: The description of this CustomOperation. # noqa: E501 + :type description: str + """ + self.openapi_types = { + 'comm_type': CommunicationType, + 'cust_op_name': str, + 'operations': List[Operation], + 'description': str + } + + self.attribute_map = { + 'comm_type': 'commType', + 'cust_op_name': 'custOpName', + 'operations': 'operations', + 'description': 'description' + } + + self._comm_type = comm_type + self._cust_op_name = cust_op_name + self._operations = operations + self._description = description + + @classmethod + def from_dict(cls, dikt) -> 'CustomOperation': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The CustomOperation of this CustomOperation. # noqa: E501 + :rtype: CustomOperation + """ + return util.deserialize_model(dikt, cls) + + @property + def comm_type(self) -> CommunicationType: + """Gets the comm_type of this CustomOperation. + + + :return: The comm_type of this CustomOperation. + :rtype: CommunicationType + """ + return self._comm_type + + @comm_type.setter + def comm_type(self, comm_type: CommunicationType): + """Sets the comm_type of this CustomOperation. + + + :param comm_type: The comm_type of this CustomOperation. + :type comm_type: CommunicationType + """ + if comm_type is None: + raise ValueError("Invalid value for `comm_type`, must not be `None`") # noqa: E501 + + self._comm_type = comm_type + + @property + def cust_op_name(self) -> str: + """Gets the cust_op_name of this CustomOperation. + + + :return: The cust_op_name of this CustomOperation. + :rtype: str + """ + return self._cust_op_name + + @cust_op_name.setter + def cust_op_name(self, cust_op_name: str): + """Sets the cust_op_name of this CustomOperation. + + + :param cust_op_name: The cust_op_name of this CustomOperation. + :type cust_op_name: str + """ + if cust_op_name is None: + raise ValueError("Invalid value for `cust_op_name`, must not be `None`") # noqa: E501 + + self._cust_op_name = cust_op_name + + @property + def operations(self) -> List[Operation]: + """Gets the operations of this CustomOperation. + + + :return: The operations of this CustomOperation. + :rtype: List[Operation] + """ + return self._operations + + @operations.setter + def operations(self, operations: List[Operation]): + """Sets the operations of this CustomOperation. + + + :param operations: The operations of this CustomOperation. + :type operations: List[Operation] + """ + + self._operations = operations + + @property + def description(self) -> str: + """Gets the description of this CustomOperation. + + + :return: The description of this CustomOperation. + :rtype: str + """ + return self._description + + @description.setter + def description(self, description: str): + """Sets the description of this CustomOperation. + + + :param description: The description of this CustomOperation. + :type description: str + """ + + self._description = description diff --git a/services/helper/helper_service/services/visibility_control/models/data_format.py b/services/helper/helper_service/services/visibility_control/models/data_format.py new file mode 100644 index 00000000..1e4c3549 --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/models/data_format.py @@ -0,0 +1,40 @@ +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from visibility_control.models.base_model import Model +from visibility_control import util + + +class DataFormat(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + """ + allowed enum values + """ + JSON = 'JSON' + XML = 'XML' + PROTOBUF3 = 'PROTOBUF3' + def __init__(self): # noqa: E501 + """DataFormat - a model defined in OpenAPI + + """ + self.openapi_types = { + } + + self.attribute_map = { + } + + @classmethod + def from_dict(cls, dikt) -> 'DataFormat': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The DataFormat of this DataFormat. # noqa: E501 + :rtype: DataFormat + """ + return util.deserialize_model(dikt, cls) diff --git a/services/helper/helper_service/services/visibility_control/models/discovered_apis.py b/services/helper/helper_service/services/visibility_control/models/discovered_apis.py new file mode 100644 index 00000000..37b336f6 --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/models/discovered_apis.py @@ -0,0 +1,95 @@ +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from visibility_control.models.base_model import Model +from visibility_control.models.service_api_description import ServiceAPIDescription +import re +from visibility_control import util + +from visibility_control.models.service_api_description import ServiceAPIDescription # noqa: E501 +import re # noqa: E501 + +class DiscoveredAPIs(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, service_api_descriptions=None, supp_feat=None): # noqa: E501 + """DiscoveredAPIs - a model defined in OpenAPI + + :param service_api_descriptions: The service_api_descriptions of this DiscoveredAPIs. # noqa: E501 + :type service_api_descriptions: List[ServiceAPIDescription] + :param supp_feat: The supp_feat of this DiscoveredAPIs. # noqa: E501 + :type supp_feat: str + """ + self.openapi_types = { + 'service_api_descriptions': List[ServiceAPIDescription], + 'supp_feat': str + } + + self.attribute_map = { + 'service_api_descriptions': 'serviceAPIDescriptions', + 'supp_feat': 'suppFeat' + } + + self._service_api_descriptions = service_api_descriptions + self._supp_feat = supp_feat + + @classmethod + def from_dict(cls, dikt) -> 'DiscoveredAPIs': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The DiscoveredAPIs of this DiscoveredAPIs. # noqa: E501 + :rtype: DiscoveredAPIs + """ + return util.deserialize_model(dikt, cls) + + @property + def service_api_descriptions(self) -> List[ServiceAPIDescription]: + """Gets the service_api_descriptions of this DiscoveredAPIs. + + + :return: The service_api_descriptions of this DiscoveredAPIs. + :rtype: List[ServiceAPIDescription] + """ + return self._service_api_descriptions + + @service_api_descriptions.setter + def service_api_descriptions(self, service_api_descriptions: List[ServiceAPIDescription]): + """Sets the service_api_descriptions of this DiscoveredAPIs. + + + :param service_api_descriptions: The service_api_descriptions of this DiscoveredAPIs. + :type service_api_descriptions: List[ServiceAPIDescription] + """ + if service_api_descriptions is not None and len(service_api_descriptions) < 1: + raise ValueError("Invalid value for `service_api_descriptions`, number of items must be greater than or equal to `1`") # noqa: E501 + + self._service_api_descriptions = service_api_descriptions + + @property + def supp_feat(self) -> str: + """Gets the supp_feat of this DiscoveredAPIs. + + + :return: The supp_feat of this DiscoveredAPIs. + :rtype: str + """ + return self._supp_feat + + @supp_feat.setter + def supp_feat(self, supp_feat: str): + """Sets the supp_feat of this DiscoveredAPIs. + + + :param supp_feat: The supp_feat of this DiscoveredAPIs. + :type supp_feat: str + """ + if supp_feat is not None and not re.search(r'^[A-Fa-f0-9]*$', supp_feat): # noqa: E501 + raise ValueError(r"Invalid value for `supp_feat`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 + + self._supp_feat = supp_feat diff --git a/services/helper/helper_service/services/visibility_control/models/error.py b/services/helper/helper_service/services/visibility_control/models/error.py new file mode 100644 index 00000000..de24c323 --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/models/error.py @@ -0,0 +1,117 @@ +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from visibility_control.models.base_model import Model +from visibility_control import util + + +class Error(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, code=None, message=None, details=None): # noqa: E501 + """Error - a model defined in OpenAPI + + :param code: The code of this Error. # noqa: E501 + :type code: str + :param message: The message of this Error. # noqa: E501 + :type message: str + :param details: The details of this Error. # noqa: E501 + :type details: Dict[str, object] + """ + self.openapi_types = { + 'code': str, + 'message': str, + 'details': Dict[str, object] + } + + self.attribute_map = { + 'code': 'code', + 'message': 'message', + 'details': 'details' + } + + self._code = code + self._message = message + self._details = details + + @classmethod + def from_dict(cls, dikt) -> 'Error': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The Error of this Error. # noqa: E501 + :rtype: Error + """ + return util.deserialize_model(dikt, cls) + + @property + def code(self) -> str: + """Gets the code of this Error. + + + :return: The code of this Error. + :rtype: str + """ + return self._code + + @code.setter + def code(self, code: str): + """Sets the code of this Error. + + + :param code: The code of this Error. + :type code: str + """ + if code is None: + raise ValueError("Invalid value for `code`, must not be `None`") # noqa: E501 + + self._code = code + + @property + def message(self) -> str: + """Gets the message of this Error. + + + :return: The message of this Error. + :rtype: str + """ + return self._message + + @message.setter + def message(self, message: str): + """Sets the message of this Error. + + + :param message: The message of this Error. + :type message: str + """ + if message is None: + raise ValueError("Invalid value for `message`, must not be `None`") # noqa: E501 + + self._message = message + + @property + def details(self) -> Dict[str, object]: + """Gets the details of this Error. + + + :return: The details of this Error. + :rtype: Dict[str, object] + """ + return self._details + + @details.setter + def details(self, details: Dict[str, object]): + """Sets the details of this Error. + + + :param details: The details of this Error. + :type details: Dict[str, object] + """ + + self._details = details diff --git a/services/helper/helper_service/services/visibility_control/models/interface_description.py b/services/helper/helper_service/services/visibility_control/models/interface_description.py new file mode 100644 index 00000000..477ebd82 --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/models/interface_description.py @@ -0,0 +1,221 @@ +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from visibility_control.models.base_model import Model +from visibility_control.models.o_auth_grant_type import OAuthGrantType +from visibility_control.models.security_method import SecurityMethod +from visibility_control import util + +from visibility_control.models.o_auth_grant_type import OAuthGrantType # noqa: E501 +from visibility_control.models.security_method import SecurityMethod # noqa: E501 + +class InterfaceDescription(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, ipv4_addr=None, ipv6_addr=None, fqdn=None, port=None, api_prefix=None, security_methods=None, grant_types=None): # noqa: E501 + """InterfaceDescription - a model defined in OpenAPI + + :param ipv4_addr: The ipv4_addr of this InterfaceDescription. # noqa: E501 + :type ipv4_addr: str + :param ipv6_addr: The ipv6_addr of this InterfaceDescription. # noqa: E501 + :type ipv6_addr: str + :param fqdn: The fqdn of this InterfaceDescription. # noqa: E501 + :type fqdn: str + :param port: The port of this InterfaceDescription. # noqa: E501 + :type port: int + :param api_prefix: The api_prefix of this InterfaceDescription. # noqa: E501 + :type api_prefix: str + :param security_methods: The security_methods of this InterfaceDescription. # noqa: E501 + :type security_methods: List[SecurityMethod] + :param grant_types: The grant_types of this InterfaceDescription. # noqa: E501 + :type grant_types: List[OAuthGrantType] + """ + self.openapi_types = { + 'ipv4_addr': str, + 'ipv6_addr': str, + 'fqdn': str, + 'port': int, + 'api_prefix': str, + 'security_methods': List[SecurityMethod], + 'grant_types': List[OAuthGrantType] + } + + self.attribute_map = { + 'ipv4_addr': 'ipv4Addr', + 'ipv6_addr': 'ipv6Addr', + 'fqdn': 'fqdn', + 'port': 'port', + 'api_prefix': 'apiPrefix', + 'security_methods': 'securityMethods', + 'grant_types': 'grantTypes' + } + + self._ipv4_addr = ipv4_addr + self._ipv6_addr = ipv6_addr + self._fqdn = fqdn + self._port = port + self._api_prefix = api_prefix + self._security_methods = security_methods + self._grant_types = grant_types + + @classmethod + def from_dict(cls, dikt) -> 'InterfaceDescription': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The InterfaceDescription of this InterfaceDescription. # noqa: E501 + :rtype: InterfaceDescription + """ + return util.deserialize_model(dikt, cls) + + @property + def ipv4_addr(self) -> str: + """Gets the ipv4_addr of this InterfaceDescription. + + + :return: The ipv4_addr of this InterfaceDescription. + :rtype: str + """ + return self._ipv4_addr + + @ipv4_addr.setter + def ipv4_addr(self, ipv4_addr: str): + """Sets the ipv4_addr of this InterfaceDescription. + + + :param ipv4_addr: The ipv4_addr of this InterfaceDescription. + :type ipv4_addr: str + """ + + self._ipv4_addr = ipv4_addr + + @property + def ipv6_addr(self) -> str: + """Gets the ipv6_addr of this InterfaceDescription. + + + :return: The ipv6_addr of this InterfaceDescription. + :rtype: str + """ + return self._ipv6_addr + + @ipv6_addr.setter + def ipv6_addr(self, ipv6_addr: str): + """Sets the ipv6_addr of this InterfaceDescription. + + + :param ipv6_addr: The ipv6_addr of this InterfaceDescription. + :type ipv6_addr: str + """ + + self._ipv6_addr = ipv6_addr + + @property + def fqdn(self) -> str: + """Gets the fqdn of this InterfaceDescription. + + + :return: The fqdn of this InterfaceDescription. + :rtype: str + """ + return self._fqdn + + @fqdn.setter + def fqdn(self, fqdn: str): + """Sets the fqdn of this InterfaceDescription. + + + :param fqdn: The fqdn of this InterfaceDescription. + :type fqdn: str + """ + + self._fqdn = fqdn + + @property + def port(self) -> int: + """Gets the port of this InterfaceDescription. + + + :return: The port of this InterfaceDescription. + :rtype: int + """ + return self._port + + @port.setter + def port(self, port: int): + """Sets the port of this InterfaceDescription. + + + :param port: The port of this InterfaceDescription. + :type port: int + """ + + self._port = port + + @property + def api_prefix(self) -> str: + """Gets the api_prefix of this InterfaceDescription. + + + :return: The api_prefix of this InterfaceDescription. + :rtype: str + """ + return self._api_prefix + + @api_prefix.setter + def api_prefix(self, api_prefix: str): + """Sets the api_prefix of this InterfaceDescription. + + + :param api_prefix: The api_prefix of this InterfaceDescription. + :type api_prefix: str + """ + + self._api_prefix = api_prefix + + @property + def security_methods(self) -> List[SecurityMethod]: + """Gets the security_methods of this InterfaceDescription. + + + :return: The security_methods of this InterfaceDescription. + :rtype: List[SecurityMethod] + """ + return self._security_methods + + @security_methods.setter + def security_methods(self, security_methods: List[SecurityMethod]): + """Sets the security_methods of this InterfaceDescription. + + + :param security_methods: The security_methods of this InterfaceDescription. + :type security_methods: List[SecurityMethod] + """ + + self._security_methods = security_methods + + @property + def grant_types(self) -> List[OAuthGrantType]: + """Gets the grant_types of this InterfaceDescription. + + + :return: The grant_types of this InterfaceDescription. + :rtype: List[OAuthGrantType] + """ + return self._grant_types + + @grant_types.setter + def grant_types(self, grant_types: List[OAuthGrantType]): + """Sets the grant_types of this InterfaceDescription. + + + :param grant_types: The grant_types of this InterfaceDescription. + :type grant_types: List[OAuthGrantType] + """ + + self._grant_types = grant_types diff --git a/services/helper/helper_service/services/visibility_control/models/invoker_selector.py b/services/helper/helper_service/services/visibility_control/models/invoker_selector.py new file mode 100644 index 00000000..b2dbae7f --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/models/invoker_selector.py @@ -0,0 +1,91 @@ +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from visibility_control.models.base_model import Model +from visibility_control import util + + +class InvokerSelector(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, invoker_onboarded_by_user=None, api_invoker_id=None): # noqa: E501 + """InvokerSelector - a model defined in OpenAPI + + :param invoker_onboarded_by_user: The invoker_onboarded_by_user of this InvokerSelector. # noqa: E501 + :type invoker_onboarded_by_user: list[str] + :param api_invoker_id: The api_invoker_id of this InvokerSelector. # noqa: E501 + :type api_invoker_id: list[str] + """ + self.openapi_types = { + 'invoker_onboarded_by_user': list[str], + 'api_invoker_id': list[str] + } + + self.attribute_map = { + 'invoker_onboarded_by_user': 'invokerOnboardedByUser', + 'api_invoker_id': 'apiInvokerId' + } + + self._invoker_onboarded_by_user = invoker_onboarded_by_user + self._api_invoker_id = api_invoker_id + + @classmethod + def from_dict(cls, dikt) -> 'InvokerSelector': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The InvokerSelector of this InvokerSelector. # noqa: E501 + :rtype: InvokerSelector + """ + return util.deserialize_model(dikt, cls) + + @property + def invoker_onboarded_by_user(self) -> list[str]: + """Gets the invoker_onboarded_by_user of this InvokerSelector. + + + :return: The invoker_onboarded_by_user of this InvokerSelector. + :rtype: list[str] + """ + return self._invoker_onboarded_by_user + + @invoker_onboarded_by_user.setter + def invoker_onboarded_by_user(self, invoker_onboarded_by_user: list[str]): + """Sets the invoker_onboarded_by_user of this InvokerSelector. + + + :param invoker_onboarded_by_user: The invoker_onboarded_by_user of this InvokerSelector. + :type invoker_onboarded_by_user: list[str] + """ + if invoker_onboarded_by_user is not None and len(invoker_onboarded_by_user) < 0: + raise ValueError("Invalid value for `invoker_onboarded_by_user`, number of items must be greater than or equal to `0`") # noqa: E501 + + self._invoker_onboarded_by_user = invoker_onboarded_by_user + + @property + def api_invoker_id(self) -> list[str]: + """Gets the api_invoker_id of this InvokerSelector. + + + :return: The api_invoker_id of this InvokerSelector. + :rtype: list[str] + """ + return self._api_invoker_id + + @api_invoker_id.setter + def api_invoker_id(self, api_invoker_id: list[str]): + """Sets the api_invoker_id of this InvokerSelector. + + + :param api_invoker_id: The api_invoker_id of this InvokerSelector. + :type api_invoker_id: list[str] + """ + if api_invoker_id is not None and len(api_invoker_id) < 0: + raise ValueError("Invalid value for `api_invoker_id`, number of items must be greater than or equal to `0`") # noqa: E501 + + self._api_invoker_id = api_invoker_id diff --git a/services/helper/helper_service/services/visibility_control/models/ip_addr_range.py b/services/helper/helper_service/services/visibility_control/models/ip_addr_range.py new file mode 100644 index 00000000..e1eddcf6 --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/models/ip_addr_range.py @@ -0,0 +1,63 @@ +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from visibility_control.models.base_model import Model +from visibility_control.models.ip_addr_range_ue_ipv4_addr_ranges_inner import IpAddrRangeUeIpv4AddrRangesInner +from visibility_control import util + +from visibility_control.models.ip_addr_range_ue_ipv4_addr_ranges_inner import IpAddrRangeUeIpv4AddrRangesInner # noqa: E501 + +class IpAddrRange(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, ue_ipv4_addr_ranges=None): # noqa: E501 + """IpAddrRange - a model defined in OpenAPI + + :param ue_ipv4_addr_ranges: The ue_ipv4_addr_ranges of this IpAddrRange. # noqa: E501 + :type ue_ipv4_addr_ranges: List[IpAddrRangeUeIpv4AddrRangesInner] + """ + self.openapi_types = { + 'ue_ipv4_addr_ranges': List[IpAddrRangeUeIpv4AddrRangesInner] + } + + self.attribute_map = { + 'ue_ipv4_addr_ranges': 'ueIpv4AddrRanges' + } + + self._ue_ipv4_addr_ranges = ue_ipv4_addr_ranges + + @classmethod + def from_dict(cls, dikt) -> 'IpAddrRange': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The IpAddrRange of this IpAddrRange. # noqa: E501 + :rtype: IpAddrRange + """ + return util.deserialize_model(dikt, cls) + + @property + def ue_ipv4_addr_ranges(self) -> List[IpAddrRangeUeIpv4AddrRangesInner]: + """Gets the ue_ipv4_addr_ranges of this IpAddrRange. + + + :return: The ue_ipv4_addr_ranges of this IpAddrRange. + :rtype: List[IpAddrRangeUeIpv4AddrRangesInner] + """ + return self._ue_ipv4_addr_ranges + + @ue_ipv4_addr_ranges.setter + def ue_ipv4_addr_ranges(self, ue_ipv4_addr_ranges: List[IpAddrRangeUeIpv4AddrRangesInner]): + """Sets the ue_ipv4_addr_ranges of this IpAddrRange. + + + :param ue_ipv4_addr_ranges: The ue_ipv4_addr_ranges of this IpAddrRange. + :type ue_ipv4_addr_ranges: List[IpAddrRangeUeIpv4AddrRangesInner] + """ + + self._ue_ipv4_addr_ranges = ue_ipv4_addr_ranges diff --git a/services/helper/helper_service/services/visibility_control/models/ip_addr_range_ue_ipv4_addr_ranges_inner.py b/services/helper/helper_service/services/visibility_control/models/ip_addr_range_ue_ipv4_addr_ranges_inner.py new file mode 100644 index 00000000..d92d5e9d --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/models/ip_addr_range_ue_ipv4_addr_ranges_inner.py @@ -0,0 +1,87 @@ +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from visibility_control.models.base_model import Model +from visibility_control import util + + +class IpAddrRangeUeIpv4AddrRangesInner(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, start=None, end=None): # noqa: E501 + """IpAddrRangeUeIpv4AddrRangesInner - a model defined in OpenAPI + + :param start: The start of this IpAddrRangeUeIpv4AddrRangesInner. # noqa: E501 + :type start: str + :param end: The end of this IpAddrRangeUeIpv4AddrRangesInner. # noqa: E501 + :type end: str + """ + self.openapi_types = { + 'start': str, + 'end': str + } + + self.attribute_map = { + 'start': 'start', + 'end': 'end' + } + + self._start = start + self._end = end + + @classmethod + def from_dict(cls, dikt) -> 'IpAddrRangeUeIpv4AddrRangesInner': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The IpAddrRange_ueIpv4AddrRanges_inner of this IpAddrRangeUeIpv4AddrRangesInner. # noqa: E501 + :rtype: IpAddrRangeUeIpv4AddrRangesInner + """ + return util.deserialize_model(dikt, cls) + + @property + def start(self) -> str: + """Gets the start of this IpAddrRangeUeIpv4AddrRangesInner. + + + :return: The start of this IpAddrRangeUeIpv4AddrRangesInner. + :rtype: str + """ + return self._start + + @start.setter + def start(self, start: str): + """Sets the start of this IpAddrRangeUeIpv4AddrRangesInner. + + + :param start: The start of this IpAddrRangeUeIpv4AddrRangesInner. + :type start: str + """ + + self._start = start + + @property + def end(self) -> str: + """Gets the end of this IpAddrRangeUeIpv4AddrRangesInner. + + + :return: The end of this IpAddrRangeUeIpv4AddrRangesInner. + :rtype: str + """ + return self._end + + @end.setter + def end(self, end: str): + """Sets the end of this IpAddrRangeUeIpv4AddrRangesInner. + + + :param end: The end of this IpAddrRangeUeIpv4AddrRangesInner. + :type end: str + """ + + self._end = end diff --git a/services/helper/helper_service/services/visibility_control/models/o_auth_grant_type.py b/services/helper/helper_service/services/visibility_control/models/o_auth_grant_type.py new file mode 100644 index 00000000..5536af03 --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/models/o_auth_grant_type.py @@ -0,0 +1,40 @@ +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from visibility_control.models.base_model import Model +from visibility_control import util + + +class OAuthGrantType(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + """ + allowed enum values + """ + CLIENT_CREDENTIALS = 'CLIENT_CREDENTIALS' + AUTHORIZATION_CODE = 'AUTHORIZATION_CODE' + AUTHORIZATION_CODE_WITH_PKCE = 'AUTHORIZATION_CODE_WITH_PKCE' + def __init__(self): # noqa: E501 + """OAuthGrantType - a model defined in OpenAPI + + """ + self.openapi_types = { + } + + self.attribute_map = { + } + + @classmethod + def from_dict(cls, dikt) -> 'OAuthGrantType': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The OAuthGrantType of this OAuthGrantType. # noqa: E501 + :rtype: OAuthGrantType + """ + return util.deserialize_model(dikt, cls) diff --git a/services/helper/helper_service/services/visibility_control/models/operation.py b/services/helper/helper_service/services/visibility_control/models/operation.py new file mode 100644 index 00000000..3b06d35a --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/models/operation.py @@ -0,0 +1,42 @@ +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from visibility_control.models.base_model import Model +from visibility_control import util + + +class Operation(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + """ + allowed enum values + """ + GET = 'GET' + POST = 'POST' + PUT = 'PUT' + PATCH = 'PATCH' + DELETE = 'DELETE' + def __init__(self): # noqa: E501 + """Operation - a model defined in OpenAPI + + """ + self.openapi_types = { + } + + self.attribute_map = { + } + + @classmethod + def from_dict(cls, dikt) -> 'Operation': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The Operation of this Operation. # noqa: E501 + :rtype: Operation + """ + return util.deserialize_model(dikt, cls) diff --git a/services/helper/helper_service/services/visibility_control/models/patch_provider_selector.py b/services/helper/helper_service/services/visibility_control/models/patch_provider_selector.py new file mode 100644 index 00000000..c5b83c5b --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/models/patch_provider_selector.py @@ -0,0 +1,147 @@ +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from visibility_control.models.base_model import Model +from visibility_control import util + + +class PatchProviderSelector(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, api_provider_id=None, api_name=None, api_id=None, aef_id=None): # noqa: E501 + """PatchProviderSelector - a model defined in OpenAPI + + :param api_provider_id: The api_provider_id of this PatchProviderSelector. # noqa: E501 + :type api_provider_id: list[str] + :param api_name: The api_name of this PatchProviderSelector. # noqa: E501 + :type api_name: list[str] + :param api_id: The api_id of this PatchProviderSelector. # noqa: E501 + :type api_id: list[str] + :param aef_id: The aef_id of this PatchProviderSelector. # noqa: E501 + :type aef_id: list[str] + """ + self.openapi_types = { + 'api_provider_id': list[str], + 'api_name': list[str], + 'api_id': list[str], + 'aef_id': list[str] + } + + self.attribute_map = { + 'api_provider_id': 'apiProviderId', + 'api_name': 'apiName', + 'api_id': 'apiId', + 'aef_id': 'aefId' + } + + self._api_provider_id = api_provider_id + self._api_name = api_name + self._api_id = api_id + self._aef_id = aef_id + + @classmethod + def from_dict(cls, dikt) -> 'PatchProviderSelector': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The PatchProviderSelector of this PatchProviderSelector. # noqa: E501 + :rtype: PatchProviderSelector + """ + return util.deserialize_model(dikt, cls) + + @property + def api_provider_id(self) -> list[str]: + """Gets the api_provider_id of this PatchProviderSelector. + + + :return: The api_provider_id of this PatchProviderSelector. + :rtype: list[str] + """ + return self._api_provider_id + + @api_provider_id.setter + def api_provider_id(self, api_provider_id: list[str]): + """Sets the api_provider_id of this PatchProviderSelector. + + + :param api_provider_id: The api_provider_id of this PatchProviderSelector. + :type api_provider_id: list[str] + """ + if api_provider_id is not None and len(api_provider_id) < 0: + raise ValueError("Invalid value for `api_provider_id`, number of items must be greater than or equal to `0`") # noqa: E501 + + self._api_provider_id = api_provider_id + + @property + def api_name(self) -> list[str]: + """Gets the api_name of this PatchProviderSelector. + + + :return: The api_name of this PatchProviderSelector. + :rtype: list[str] + """ + return self._api_name + + @api_name.setter + def api_name(self, api_name: list[str]): + """Sets the api_name of this PatchProviderSelector. + + + :param api_name: The api_name of this PatchProviderSelector. + :type api_name: list[str] + """ + if api_name is not None and len(api_name) < 0: + raise ValueError("Invalid value for `api_name`, number of items must be greater than or equal to `0`") # noqa: E501 + + self._api_name = api_name + + @property + def api_id(self) -> list[str]: + """Gets the api_id of this PatchProviderSelector. + + + :return: The api_id of this PatchProviderSelector. + :rtype: list[str] + """ + return self._api_id + + @api_id.setter + def api_id(self, api_id: list[str]): + """Sets the api_id of this PatchProviderSelector. + + + :param api_id: The api_id of this PatchProviderSelector. + :type api_id: list[str] + """ + if api_id is not None and len(api_id) < 0: + raise ValueError("Invalid value for `api_id`, number of items must be greater than or equal to `0`") # noqa: E501 + + self._api_id = api_id + + @property + def aef_id(self) -> list[str]: + """Gets the aef_id of this PatchProviderSelector. + + + :return: The aef_id of this PatchProviderSelector. + :rtype: list[str] + """ + return self._aef_id + + @aef_id.setter + def aef_id(self, aef_id: list[str]): + """Sets the aef_id of this PatchProviderSelector. + + + :param aef_id: The aef_id of this PatchProviderSelector. + :type aef_id: list[str] + """ + if aef_id is not None and len(aef_id) < 0: + raise ValueError("Invalid value for `aef_id`, number of items must be greater than or equal to `0`") # noqa: E501 + + self._aef_id = aef_id diff --git a/services/helper/helper_service/services/visibility_control/models/protocol.py b/services/helper/helper_service/services/visibility_control/models/protocol.py new file mode 100644 index 00000000..ef8c55c7 --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/models/protocol.py @@ -0,0 +1,41 @@ +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from visibility_control.models.base_model import Model +from visibility_control import util + + +class Protocol(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + """ + allowed enum values + """ + HTTP_1_1 = 'HTTP_1_1' + HTTP_2 = 'HTTP_2' + MQTT = 'MQTT' + WEBSOCKET = 'WEBSOCKET' + def __init__(self): # noqa: E501 + """Protocol - a model defined in OpenAPI + + """ + self.openapi_types = { + } + + self.attribute_map = { + } + + @classmethod + def from_dict(cls, dikt) -> 'Protocol': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The Protocol of this Protocol. # noqa: E501 + :rtype: Protocol + """ + return util.deserialize_model(dikt, cls) diff --git a/services/helper/helper_service/services/visibility_control/models/provider_selector.py b/services/helper/helper_service/services/visibility_control/models/provider_selector.py new file mode 100644 index 00000000..975d96cc --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/models/provider_selector.py @@ -0,0 +1,177 @@ +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from visibility_control.models.base_model import Model +from visibility_control import util + + +class ProviderSelector(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, created_by_user=None, api_provider_id=None, api_name=None, api_id=None, aef_id=None): # noqa: E501 + """ProviderSelector - a model defined in OpenAPI + + :param created_by_user: The created_by_user of this ProviderSelector. # noqa: E501 + :type created_by_user: str + :param api_provider_id: The api_provider_id of this ProviderSelector. # noqa: E501 + :type api_provider_id: list[str] + :param api_name: The api_name of this ProviderSelector. # noqa: E501 + :type api_name: list[str] + :param api_id: The api_id of this ProviderSelector. # noqa: E501 + :type api_id: list[str] + :param aef_id: The aef_id of this ProviderSelector. # noqa: E501 + :type aef_id: list[str] + """ + self.openapi_types = { + 'created_by_user': str, + 'api_provider_id': list[str], + 'api_name': list[str], + 'api_id': list[str], + 'aef_id': list[str] + } + + self.attribute_map = { + 'created_by_user': 'createdByUser', + 'api_provider_id': 'apiProviderId', + 'api_name': 'apiName', + 'api_id': 'apiId', + 'aef_id': 'aefId' + } + + self._created_by_user = created_by_user + self._api_provider_id = api_provider_id + self._api_name = api_name + self._api_id = api_id + self._aef_id = aef_id + + @classmethod + def from_dict(cls, dikt) -> 'ProviderSelector': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The ProviderSelector of this ProviderSelector. # noqa: E501 + :rtype: ProviderSelector + """ + return util.deserialize_model(dikt, cls) + + @property + def created_by_user(self) -> str: + """Gets the created_by_user of this ProviderSelector. + + + :return: The created_by_user of this ProviderSelector. + :rtype: str + """ + return self._created_by_user + + @created_by_user.setter + def created_by_user(self, created_by_user: str): + """Sets the created_by_user of this ProviderSelector. + + + :param created_by_user: The created_by_user of this ProviderSelector. + :type created_by_user: str + """ + if created_by_user is None: + raise ValueError("Invalid value for `created_by_user`, must not be `None`") # noqa: E501 + if created_by_user is not None and len(created_by_user) < 1: + raise ValueError("Invalid value for `created_by_user`, length must be greater than or equal to `1`") # noqa: E501 + + self._created_by_user = created_by_user + + @property + def api_provider_id(self) -> list[str]: + """Gets the api_provider_id of this ProviderSelector. + + + :return: The api_provider_id of this ProviderSelector. + :rtype: list[str] + """ + return self._api_provider_id + + @api_provider_id.setter + def api_provider_id(self, api_provider_id: list[str]): + """Sets the api_provider_id of this ProviderSelector. + + + :param api_provider_id: The api_provider_id of this ProviderSelector. + :type api_provider_id: list[str] + """ + if api_provider_id is not None and len(api_provider_id) < 0: + raise ValueError("Invalid value for `api_provider_id`, number of items must be greater than or equal to `0`") # noqa: E501 + + self._api_provider_id = api_provider_id + + @property + def api_name(self) -> list[str]: + """Gets the api_name of this ProviderSelector. + + + :return: The api_name of this ProviderSelector. + :rtype: list[str] + """ + return self._api_name + + @api_name.setter + def api_name(self, api_name: list[str]): + """Sets the api_name of this ProviderSelector. + + + :param api_name: The api_name of this ProviderSelector. + :type api_name: list[str] + """ + if api_name is not None and len(api_name) < 0: + raise ValueError("Invalid value for `api_name`, number of items must be greater than or equal to `0`") # noqa: E501 + + self._api_name = api_name + + @property + def api_id(self) -> list[str]: + """Gets the api_id of this ProviderSelector. + + + :return: The api_id of this ProviderSelector. + :rtype: list[str] + """ + return self._api_id + + @api_id.setter + def api_id(self, api_id: list[str]): + """Sets the api_id of this ProviderSelector. + + + :param api_id: The api_id of this ProviderSelector. + :type api_id: list[str] + """ + if api_id is not None and len(api_id) < 0: + raise ValueError("Invalid value for `api_id`, number of items must be greater than or equal to `0`") # noqa: E501 + + self._api_id = api_id + + @property + def aef_id(self) -> list[str]: + """Gets the aef_id of this ProviderSelector. + + + :return: The aef_id of this ProviderSelector. + :rtype: list[str] + """ + return self._aef_id + + @aef_id.setter + def aef_id(self, aef_id: list[str]): + """Sets the aef_id of this ProviderSelector. + + + :param aef_id: The aef_id of this ProviderSelector. + :type aef_id: list[str] + """ + if aef_id is not None and len(aef_id) < 0: + raise ValueError("Invalid value for `aef_id`, number of items must be greater than or equal to `0`") # noqa: E501 + + self._aef_id = aef_id diff --git a/services/helper/helper_service/services/visibility_control/models/published_api_path.py b/services/helper/helper_service/services/visibility_control/models/published_api_path.py new file mode 100644 index 00000000..629df636 --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/models/published_api_path.py @@ -0,0 +1,61 @@ +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from visibility_control.models.base_model import Model +from visibility_control import util + + +class PublishedApiPath(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, ccf_ids=None): # noqa: E501 + """PublishedApiPath - a model defined in OpenAPI + + :param ccf_ids: The ccf_ids of this PublishedApiPath. # noqa: E501 + :type ccf_ids: List[str] + """ + self.openapi_types = { + 'ccf_ids': List[str] + } + + self.attribute_map = { + 'ccf_ids': 'ccfIds' + } + + self._ccf_ids = ccf_ids + + @classmethod + def from_dict(cls, dikt) -> 'PublishedApiPath': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The PublishedApiPath of this PublishedApiPath. # noqa: E501 + :rtype: PublishedApiPath + """ + return util.deserialize_model(dikt, cls) + + @property + def ccf_ids(self) -> List[str]: + """Gets the ccf_ids of this PublishedApiPath. + + + :return: The ccf_ids of this PublishedApiPath. + :rtype: List[str] + """ + return self._ccf_ids + + @ccf_ids.setter + def ccf_ids(self, ccf_ids: List[str]): + """Sets the ccf_ids of this PublishedApiPath. + + + :param ccf_ids: The ccf_ids of this PublishedApiPath. + :type ccf_ids: List[str] + """ + + self._ccf_ids = ccf_ids diff --git a/services/helper/helper_service/services/visibility_control/models/resource.py b/services/helper/helper_service/services/visibility_control/models/resource.py new file mode 100644 index 00000000..a7b3f90a --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/models/resource.py @@ -0,0 +1,201 @@ +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from visibility_control.models.base_model import Model +from visibility_control.models.communication_type import CommunicationType +from visibility_control.models.operation import Operation +from visibility_control import util + +from visibility_control.models.communication_type import CommunicationType # noqa: E501 +from visibility_control.models.operation import Operation # noqa: E501 + +class Resource(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, resource_name=None, comm_type=None, uri=None, cust_op_name=None, operations=None, description=None): # noqa: E501 + """Resource - a model defined in OpenAPI + + :param resource_name: The resource_name of this Resource. # noqa: E501 + :type resource_name: str + :param comm_type: The comm_type of this Resource. # noqa: E501 + :type comm_type: CommunicationType + :param uri: The uri of this Resource. # noqa: E501 + :type uri: str + :param cust_op_name: The cust_op_name of this Resource. # noqa: E501 + :type cust_op_name: str + :param operations: The operations of this Resource. # noqa: E501 + :type operations: List[Operation] + :param description: The description of this Resource. # noqa: E501 + :type description: str + """ + self.openapi_types = { + 'resource_name': str, + 'comm_type': CommunicationType, + 'uri': str, + 'cust_op_name': str, + 'operations': List[Operation], + 'description': str + } + + self.attribute_map = { + 'resource_name': 'resourceName', + 'comm_type': 'commType', + 'uri': 'uri', + 'cust_op_name': 'custOpName', + 'operations': 'operations', + 'description': 'description' + } + + self._resource_name = resource_name + self._comm_type = comm_type + self._uri = uri + self._cust_op_name = cust_op_name + self._operations = operations + self._description = description + + @classmethod + def from_dict(cls, dikt) -> 'Resource': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The Resource of this Resource. # noqa: E501 + :rtype: Resource + """ + return util.deserialize_model(dikt, cls) + + @property + def resource_name(self) -> str: + """Gets the resource_name of this Resource. + + + :return: The resource_name of this Resource. + :rtype: str + """ + return self._resource_name + + @resource_name.setter + def resource_name(self, resource_name: str): + """Sets the resource_name of this Resource. + + + :param resource_name: The resource_name of this Resource. + :type resource_name: str + """ + if resource_name is None: + raise ValueError("Invalid value for `resource_name`, must not be `None`") # noqa: E501 + + self._resource_name = resource_name + + @property + def comm_type(self) -> CommunicationType: + """Gets the comm_type of this Resource. + + + :return: The comm_type of this Resource. + :rtype: CommunicationType + """ + return self._comm_type + + @comm_type.setter + def comm_type(self, comm_type: CommunicationType): + """Sets the comm_type of this Resource. + + + :param comm_type: The comm_type of this Resource. + :type comm_type: CommunicationType + """ + if comm_type is None: + raise ValueError("Invalid value for `comm_type`, must not be `None`") # noqa: E501 + + self._comm_type = comm_type + + @property + def uri(self) -> str: + """Gets the uri of this Resource. + + + :return: The uri of this Resource. + :rtype: str + """ + return self._uri + + @uri.setter + def uri(self, uri: str): + """Sets the uri of this Resource. + + + :param uri: The uri of this Resource. + :type uri: str + """ + if uri is None: + raise ValueError("Invalid value for `uri`, must not be `None`") # noqa: E501 + + self._uri = uri + + @property + def cust_op_name(self) -> str: + """Gets the cust_op_name of this Resource. + + + :return: The cust_op_name of this Resource. + :rtype: str + """ + return self._cust_op_name + + @cust_op_name.setter + def cust_op_name(self, cust_op_name: str): + """Sets the cust_op_name of this Resource. + + + :param cust_op_name: The cust_op_name of this Resource. + :type cust_op_name: str + """ + + self._cust_op_name = cust_op_name + + @property + def operations(self) -> List[Operation]: + """Gets the operations of this Resource. + + + :return: The operations of this Resource. + :rtype: List[Operation] + """ + return self._operations + + @operations.setter + def operations(self, operations: List[Operation]): + """Sets the operations of this Resource. + + + :param operations: The operations of this Resource. + :type operations: List[Operation] + """ + + self._operations = operations + + @property + def description(self) -> str: + """Gets the description of this Resource. + + + :return: The description of this Resource. + :rtype: str + """ + return self._description + + @description.setter + def description(self, description: str): + """Sets the description of this Resource. + + + :param description: The description of this Resource. + :type description: str + """ + + self._description = description diff --git a/services/helper/helper_service/services/visibility_control/models/rule.py b/services/helper/helper_service/services/visibility_control/models/rule.py new file mode 100644 index 00000000..1aa6de1c --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/models/rule.py @@ -0,0 +1,309 @@ +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from visibility_control.models.base_model import Model +from visibility_control.models.invoker_selector import InvokerSelector +from visibility_control.models.provider_selector import ProviderSelector +from visibility_control import util + +from visibility_control.models.invoker_selector import InvokerSelector # noqa: E501 +from visibility_control.models.provider_selector import ProviderSelector # noqa: E501 + +class Rule(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, rule_id=None, provider_selector=None, invoker_exceptions=None, default_access=None, enabled=True, starts_at=None, ends_at=None, notes=None, updated_at=None, updated_by=None): # noqa: E501 + """Rule - a model defined in OpenAPI + + :param rule_id: The rule_id of this Rule. # noqa: E501 + :type rule_id: str + :param provider_selector: The provider_selector of this Rule. # noqa: E501 + :type provider_selector: ProviderSelector + :param invoker_exceptions: The invoker_exceptions of this Rule. # noqa: E501 + :type invoker_exceptions: InvokerSelector + :param default_access: The default_access of this Rule. # noqa: E501 + :type default_access: str + :param enabled: The enabled of this Rule. # noqa: E501 + :type enabled: bool + :param starts_at: The starts_at of this Rule. # noqa: E501 + :type starts_at: datetime + :param ends_at: The ends_at of this Rule. # noqa: E501 + :type ends_at: datetime + :param notes: The notes of this Rule. # noqa: E501 + :type notes: str + :param updated_at: The updated_at of this Rule. # noqa: E501 + :type updated_at: datetime + :param updated_by: The updated_by of this Rule. # noqa: E501 + :type updated_by: str + """ + self.openapi_types = { + 'rule_id': str, + 'provider_selector': ProviderSelector, + 'invoker_exceptions': InvokerSelector, + 'default_access': str, + 'enabled': bool, + 'starts_at': datetime, + 'ends_at': datetime, + 'notes': str, + 'updated_at': datetime, + 'updated_by': str + } + + self.attribute_map = { + 'rule_id': 'ruleId', + 'provider_selector': 'providerSelector', + 'invoker_exceptions': 'invokerExceptions', + 'default_access': 'default_access', + 'enabled': 'enabled', + 'starts_at': 'startsAt', + 'ends_at': 'endsAt', + 'notes': 'notes', + 'updated_at': 'updatedAt', + 'updated_by': 'updatedBy' + } + + self._rule_id = rule_id + self._provider_selector = provider_selector + self._invoker_exceptions = invoker_exceptions + self._default_access = default_access + self._enabled = enabled + self._starts_at = starts_at + self._ends_at = ends_at + self._notes = notes + self._updated_at = updated_at + self._updated_by = updated_by + + @classmethod + def from_dict(cls, dikt) -> 'Rule': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The Rule of this Rule. # noqa: E501 + :rtype: Rule + """ + return util.deserialize_model(dikt, cls) + + @property + def rule_id(self) -> str: + """Gets the rule_id of this Rule. + + + :return: The rule_id of this Rule. + :rtype: str + """ + return self._rule_id + + @rule_id.setter + def rule_id(self, rule_id: str): + """Sets the rule_id of this Rule. + + + :param rule_id: The rule_id of this Rule. + :type rule_id: str + """ + if rule_id is None: + raise ValueError("Invalid value for `rule_id`, must not be `None`") # noqa: E501 + + self._rule_id = rule_id + + @property + def provider_selector(self) -> ProviderSelector: + """Gets the provider_selector of this Rule. + + + :return: The provider_selector of this Rule. + :rtype: ProviderSelector + """ + return self._provider_selector + + @provider_selector.setter + def provider_selector(self, provider_selector: ProviderSelector): + """Sets the provider_selector of this Rule. + + + :param provider_selector: The provider_selector of this Rule. + :type provider_selector: ProviderSelector + """ + if provider_selector is None: + raise ValueError("Invalid value for `provider_selector`, must not be `None`") # noqa: E501 + + self._provider_selector = provider_selector + + @property + def invoker_exceptions(self) -> InvokerSelector: + """Gets the invoker_exceptions of this Rule. + + + :return: The invoker_exceptions of this Rule. + :rtype: InvokerSelector + """ + return self._invoker_exceptions + + @invoker_exceptions.setter + def invoker_exceptions(self, invoker_exceptions: InvokerSelector): + """Sets the invoker_exceptions of this Rule. + + + :param invoker_exceptions: The invoker_exceptions of this Rule. + :type invoker_exceptions: InvokerSelector + """ + + self._invoker_exceptions = invoker_exceptions + + @property + def default_access(self) -> str: + """Gets the default_access of this Rule. + + + :return: The default_access of this Rule. + :rtype: str + """ + return self._default_access + + @default_access.setter + def default_access(self, default_access: str): + """Sets the default_access of this Rule. + + + :param default_access: The default_access of this Rule. + :type default_access: str + """ + allowed_values = ["ALLOW", "DENY"] # noqa: E501 + if default_access not in allowed_values: + raise ValueError( + "Invalid value for `default_access` ({0}), must be one of {1}" + .format(default_access, allowed_values) + ) + + self._default_access = default_access + + @property + def enabled(self) -> bool: + """Gets the enabled of this Rule. + + + :return: The enabled of this Rule. + :rtype: bool + """ + return self._enabled + + @enabled.setter + def enabled(self, enabled: bool): + """Sets the enabled of this Rule. + + + :param enabled: The enabled of this Rule. + :type enabled: bool + """ + + self._enabled = enabled + + @property + def starts_at(self) -> datetime: + """Gets the starts_at of this Rule. + + + :return: The starts_at of this Rule. + :rtype: datetime + """ + return self._starts_at + + @starts_at.setter + def starts_at(self, starts_at: datetime): + """Sets the starts_at of this Rule. + + + :param starts_at: The starts_at of this Rule. + :type starts_at: datetime + """ + + self._starts_at = starts_at + + @property + def ends_at(self) -> datetime: + """Gets the ends_at of this Rule. + + + :return: The ends_at of this Rule. + :rtype: datetime + """ + return self._ends_at + + @ends_at.setter + def ends_at(self, ends_at: datetime): + """Sets the ends_at of this Rule. + + + :param ends_at: The ends_at of this Rule. + :type ends_at: datetime + """ + + self._ends_at = ends_at + + @property + def notes(self) -> str: + """Gets the notes of this Rule. + + + :return: The notes of this Rule. + :rtype: str + """ + return self._notes + + @notes.setter + def notes(self, notes: str): + """Sets the notes of this Rule. + + + :param notes: The notes of this Rule. + :type notes: str + """ + + self._notes = notes + + @property + def updated_at(self) -> datetime: + """Gets the updated_at of this Rule. + + + :return: The updated_at of this Rule. + :rtype: datetime + """ + return self._updated_at + + @updated_at.setter + def updated_at(self, updated_at: datetime): + """Sets the updated_at of this Rule. + + + :param updated_at: The updated_at of this Rule. + :type updated_at: datetime + """ + + self._updated_at = updated_at + + @property + def updated_by(self) -> str: + """Gets the updated_by of this Rule. + + + :return: The updated_by of this Rule. + :rtype: str + """ + return self._updated_by + + @updated_by.setter + def updated_by(self, updated_by: str): + """Sets the updated_by of this Rule. + + + :param updated_by: The updated_by of this Rule. + :type updated_by: str + """ + + self._updated_by = updated_by diff --git a/services/helper/helper_service/services/visibility_control/models/rule_create_request.py b/services/helper/helper_service/services/visibility_control/models/rule_create_request.py new file mode 100644 index 00000000..76aa429c --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/models/rule_create_request.py @@ -0,0 +1,229 @@ +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from visibility_control.models.base_model import Model +from visibility_control.models.invoker_selector import InvokerSelector +from visibility_control.models.provider_selector import ProviderSelector +from visibility_control import util + +from visibility_control.models.invoker_selector import InvokerSelector # noqa: E501 +from visibility_control.models.provider_selector import ProviderSelector # noqa: E501 + +class RuleCreateRequest(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, provider_selector=None, invoker_exceptions=None, default_access=None, enabled=True, starts_at=None, ends_at=None, notes=None): # noqa: E501 + """RuleCreateRequest - a model defined in OpenAPI + + :param provider_selector: The provider_selector of this RuleCreateRequest. # noqa: E501 + :type provider_selector: ProviderSelector + :param invoker_exceptions: The invoker_exceptions of this RuleCreateRequest. # noqa: E501 + :type invoker_exceptions: InvokerSelector + :param default_access: The default_access of this RuleCreateRequest. # noqa: E501 + :type default_access: str + :param enabled: The enabled of this RuleCreateRequest. # noqa: E501 + :type enabled: bool + :param starts_at: The starts_at of this RuleCreateRequest. # noqa: E501 + :type starts_at: datetime + :param ends_at: The ends_at of this RuleCreateRequest. # noqa: E501 + :type ends_at: datetime + :param notes: The notes of this RuleCreateRequest. # noqa: E501 + :type notes: str + """ + self.openapi_types = { + 'provider_selector': ProviderSelector, + 'invoker_exceptions': InvokerSelector, + 'default_access': str, + 'enabled': bool, + 'starts_at': datetime, + 'ends_at': datetime, + 'notes': str + } + + self.attribute_map = { + 'provider_selector': 'providerSelector', + 'invoker_exceptions': 'invokerExceptions', + 'default_access': 'default_access', + 'enabled': 'enabled', + 'starts_at': 'startsAt', + 'ends_at': 'endsAt', + 'notes': 'notes' + } + + self._provider_selector = provider_selector + self._invoker_exceptions = invoker_exceptions + self._default_access = default_access + self._enabled = enabled + self._starts_at = starts_at + self._ends_at = ends_at + self._notes = notes + + @classmethod + def from_dict(cls, dikt) -> 'RuleCreateRequest': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The RuleCreateRequest of this RuleCreateRequest. # noqa: E501 + :rtype: RuleCreateRequest + """ + return util.deserialize_model(dikt, cls) + + @property + def provider_selector(self) -> ProviderSelector: + """Gets the provider_selector of this RuleCreateRequest. + + + :return: The provider_selector of this RuleCreateRequest. + :rtype: ProviderSelector + """ + return self._provider_selector + + @provider_selector.setter + def provider_selector(self, provider_selector: ProviderSelector): + """Sets the provider_selector of this RuleCreateRequest. + + + :param provider_selector: The provider_selector of this RuleCreateRequest. + :type provider_selector: ProviderSelector + """ + if provider_selector is None: + raise ValueError("Invalid value for `provider_selector`, must not be `None`") # noqa: E501 + + self._provider_selector = provider_selector + + @property + def invoker_exceptions(self) -> InvokerSelector: + """Gets the invoker_exceptions of this RuleCreateRequest. + + + :return: The invoker_exceptions of this RuleCreateRequest. + :rtype: InvokerSelector + """ + return self._invoker_exceptions + + @invoker_exceptions.setter + def invoker_exceptions(self, invoker_exceptions: InvokerSelector): + """Sets the invoker_exceptions of this RuleCreateRequest. + + + :param invoker_exceptions: The invoker_exceptions of this RuleCreateRequest. + :type invoker_exceptions: InvokerSelector + """ + + self._invoker_exceptions = invoker_exceptions + + @property + def default_access(self) -> str: + """Gets the default_access of this RuleCreateRequest. + + + :return: The default_access of this RuleCreateRequest. + :rtype: str + """ + return self._default_access + + @default_access.setter + def default_access(self, default_access: str): + """Sets the default_access of this RuleCreateRequest. + + + :param default_access: The default_access of this RuleCreateRequest. + :type default_access: str + """ + allowed_values = ["ALLOW", "DENY"] # noqa: E501 + if default_access not in allowed_values: + raise ValueError( + "Invalid value for `default_access` ({0}), must be one of {1}" + .format(default_access, allowed_values) + ) + + self._default_access = default_access + + @property + def enabled(self) -> bool: + """Gets the enabled of this RuleCreateRequest. + + + :return: The enabled of this RuleCreateRequest. + :rtype: bool + """ + return self._enabled + + @enabled.setter + def enabled(self, enabled: bool): + """Sets the enabled of this RuleCreateRequest. + + + :param enabled: The enabled of this RuleCreateRequest. + :type enabled: bool + """ + + self._enabled = enabled + + @property + def starts_at(self) -> datetime: + """Gets the starts_at of this RuleCreateRequest. + + + :return: The starts_at of this RuleCreateRequest. + :rtype: datetime + """ + return self._starts_at + + @starts_at.setter + def starts_at(self, starts_at: datetime): + """Sets the starts_at of this RuleCreateRequest. + + + :param starts_at: The starts_at of this RuleCreateRequest. + :type starts_at: datetime + """ + + self._starts_at = starts_at + + @property + def ends_at(self) -> datetime: + """Gets the ends_at of this RuleCreateRequest. + + + :return: The ends_at of this RuleCreateRequest. + :rtype: datetime + """ + return self._ends_at + + @ends_at.setter + def ends_at(self, ends_at: datetime): + """Sets the ends_at of this RuleCreateRequest. + + + :param ends_at: The ends_at of this RuleCreateRequest. + :type ends_at: datetime + """ + + self._ends_at = ends_at + + @property + def notes(self) -> str: + """Gets the notes of this RuleCreateRequest. + + + :return: The notes of this RuleCreateRequest. + :rtype: str + """ + return self._notes + + @notes.setter + def notes(self, notes: str): + """Sets the notes of this RuleCreateRequest. + + + :param notes: The notes of this RuleCreateRequest. + :type notes: str + """ + + self._notes = notes diff --git a/services/helper/helper_service/services/visibility_control/models/rule_patch_request.py b/services/helper/helper_service/services/visibility_control/models/rule_patch_request.py new file mode 100644 index 00000000..a53a0e6a --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/models/rule_patch_request.py @@ -0,0 +1,227 @@ +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from visibility_control.models.base_model import Model +from visibility_control.models.invoker_selector import InvokerSelector +from visibility_control.models.patch_provider_selector import PatchProviderSelector +from visibility_control import util + +from visibility_control.models.invoker_selector import InvokerSelector # noqa: E501 +from visibility_control.models.patch_provider_selector import PatchProviderSelector # noqa: E501 + +class RulePatchRequest(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, provider_selector=None, invoker_exceptions=None, default_access=None, enabled=None, starts_at=None, ends_at=None, notes=None): # noqa: E501 + """RulePatchRequest - a model defined in OpenAPI + + :param provider_selector: The provider_selector of this RulePatchRequest. # noqa: E501 + :type provider_selector: PatchProviderSelector + :param invoker_exceptions: The invoker_exceptions of this RulePatchRequest. # noqa: E501 + :type invoker_exceptions: InvokerSelector + :param default_access: The default_access of this RulePatchRequest. # noqa: E501 + :type default_access: str + :param enabled: The enabled of this RulePatchRequest. # noqa: E501 + :type enabled: bool + :param starts_at: The starts_at of this RulePatchRequest. # noqa: E501 + :type starts_at: datetime + :param ends_at: The ends_at of this RulePatchRequest. # noqa: E501 + :type ends_at: datetime + :param notes: The notes of this RulePatchRequest. # noqa: E501 + :type notes: str + """ + self.openapi_types = { + 'provider_selector': PatchProviderSelector, + 'invoker_exceptions': InvokerSelector, + 'default_access': str, + 'enabled': bool, + 'starts_at': datetime, + 'ends_at': datetime, + 'notes': str + } + + self.attribute_map = { + 'provider_selector': 'providerSelector', + 'invoker_exceptions': 'invokerExceptions', + 'default_access': 'default_access', + 'enabled': 'enabled', + 'starts_at': 'startsAt', + 'ends_at': 'endsAt', + 'notes': 'notes' + } + + self._provider_selector = provider_selector + self._invoker_exceptions = invoker_exceptions + self._default_access = default_access + self._enabled = enabled + self._starts_at = starts_at + self._ends_at = ends_at + self._notes = notes + + @classmethod + def from_dict(cls, dikt) -> 'RulePatchRequest': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The RulePatchRequest of this RulePatchRequest. # noqa: E501 + :rtype: RulePatchRequest + """ + return util.deserialize_model(dikt, cls) + + @property + def provider_selector(self) -> PatchProviderSelector: + """Gets the provider_selector of this RulePatchRequest. + + + :return: The provider_selector of this RulePatchRequest. + :rtype: PatchProviderSelector + """ + return self._provider_selector + + @provider_selector.setter + def provider_selector(self, provider_selector: PatchProviderSelector): + """Sets the provider_selector of this RulePatchRequest. + + + :param provider_selector: The provider_selector of this RulePatchRequest. + :type provider_selector: PatchProviderSelector + """ + + self._provider_selector = provider_selector + + @property + def invoker_exceptions(self) -> InvokerSelector: + """Gets the invoker_exceptions of this RulePatchRequest. + + + :return: The invoker_exceptions of this RulePatchRequest. + :rtype: InvokerSelector + """ + return self._invoker_exceptions + + @invoker_exceptions.setter + def invoker_exceptions(self, invoker_exceptions: InvokerSelector): + """Sets the invoker_exceptions of this RulePatchRequest. + + + :param invoker_exceptions: The invoker_exceptions of this RulePatchRequest. + :type invoker_exceptions: InvokerSelector + """ + + self._invoker_exceptions = invoker_exceptions + + @property + def default_access(self) -> str: + """Gets the default_access of this RulePatchRequest. + + + :return: The default_access of this RulePatchRequest. + :rtype: str + """ + return self._default_access + + @default_access.setter + def default_access(self, default_access: str): + """Sets the default_access of this RulePatchRequest. + + + :param default_access: The default_access of this RulePatchRequest. + :type default_access: str + """ + allowed_values = ["ALLOW", "DENY"] # noqa: E501 + if default_access not in allowed_values: + raise ValueError( + "Invalid value for `default_access` ({0}), must be one of {1}" + .format(default_access, allowed_values) + ) + + self._default_access = default_access + + @property + def enabled(self) -> bool: + """Gets the enabled of this RulePatchRequest. + + + :return: The enabled of this RulePatchRequest. + :rtype: bool + """ + return self._enabled + + @enabled.setter + def enabled(self, enabled: bool): + """Sets the enabled of this RulePatchRequest. + + + :param enabled: The enabled of this RulePatchRequest. + :type enabled: bool + """ + + self._enabled = enabled + + @property + def starts_at(self) -> datetime: + """Gets the starts_at of this RulePatchRequest. + + + :return: The starts_at of this RulePatchRequest. + :rtype: datetime + """ + return self._starts_at + + @starts_at.setter + def starts_at(self, starts_at: datetime): + """Sets the starts_at of this RulePatchRequest. + + + :param starts_at: The starts_at of this RulePatchRequest. + :type starts_at: datetime + """ + + self._starts_at = starts_at + + @property + def ends_at(self) -> datetime: + """Gets the ends_at of this RulePatchRequest. + + + :return: The ends_at of this RulePatchRequest. + :rtype: datetime + """ + return self._ends_at + + @ends_at.setter + def ends_at(self, ends_at: datetime): + """Sets the ends_at of this RulePatchRequest. + + + :param ends_at: The ends_at of this RulePatchRequest. + :type ends_at: datetime + """ + + self._ends_at = ends_at + + @property + def notes(self) -> str: + """Gets the notes of this RulePatchRequest. + + + :return: The notes of this RulePatchRequest. + :rtype: str + """ + return self._notes + + @notes.setter + def notes(self, notes: str): + """Sets the notes of this RulePatchRequest. + + + :param notes: The notes of this RulePatchRequest. + :type notes: str + """ + + self._notes = notes diff --git a/services/helper/helper_service/services/visibility_control/models/rules_get200_response.py b/services/helper/helper_service/services/visibility_control/models/rules_get200_response.py new file mode 100644 index 00000000..28530b7b --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/models/rules_get200_response.py @@ -0,0 +1,91 @@ +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from visibility_control.models.base_model import Model +from visibility_control.models.rule import Rule +from visibility_control import util + +from visibility_control.models.rule import Rule # noqa: E501 + +class RulesGet200Response(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, items=None, next_page_token=None): # noqa: E501 + """RulesGet200Response - a model defined in OpenAPI + + :param items: The items of this RulesGet200Response. # noqa: E501 + :type items: List[Rule] + :param next_page_token: The next_page_token of this RulesGet200Response. # noqa: E501 + :type next_page_token: str + """ + self.openapi_types = { + 'items': List[Rule], + 'next_page_token': str + } + + self.attribute_map = { + 'items': 'items', + 'next_page_token': 'nextPageToken' + } + + self._items = items + self._next_page_token = next_page_token + + @classmethod + def from_dict(cls, dikt) -> 'RulesGet200Response': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The _rules_get_200_response of this RulesGet200Response. # noqa: E501 + :rtype: RulesGet200Response + """ + return util.deserialize_model(dikt, cls) + + @property + def items(self) -> List[Rule]: + """Gets the items of this RulesGet200Response. + + + :return: The items of this RulesGet200Response. + :rtype: List[Rule] + """ + return self._items + + @items.setter + def items(self, items: List[Rule]): + """Sets the items of this RulesGet200Response. + + + :param items: The items of this RulesGet200Response. + :type items: List[Rule] + """ + if items is None: + raise ValueError("Invalid value for `items`, must not be `None`") # noqa: E501 + + self._items = items + + @property + def next_page_token(self) -> str: + """Gets the next_page_token of this RulesGet200Response. + + + :return: The next_page_token of this RulesGet200Response. + :rtype: str + """ + return self._next_page_token + + @next_page_token.setter + def next_page_token(self, next_page_token: str): + """Sets the next_page_token of this RulesGet200Response. + + + :param next_page_token: The next_page_token of this RulesGet200Response. + :type next_page_token: str + """ + + self._next_page_token = next_page_token diff --git a/services/helper/helper_service/services/visibility_control/models/security_method.py b/services/helper/helper_service/services/visibility_control/models/security_method.py new file mode 100644 index 00000000..4ceae5be --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/models/security_method.py @@ -0,0 +1,40 @@ +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from visibility_control.models.base_model import Model +from visibility_control import util + + +class SecurityMethod(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + """ + allowed enum values + """ + PSK = 'PSK' + PKI = 'PKI' + OAUTH = 'OAUTH' + def __init__(self): # noqa: E501 + """SecurityMethod - a model defined in OpenAPI + + """ + self.openapi_types = { + } + + self.attribute_map = { + } + + @classmethod + def from_dict(cls, dikt) -> 'SecurityMethod': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The SecurityMethod of this SecurityMethod. # noqa: E501 + :rtype: SecurityMethod + """ + return util.deserialize_model(dikt, cls) diff --git a/services/helper/helper_service/services/visibility_control/models/service_api_description.py b/services/helper/helper_service/services/visibility_control/models/service_api_description.py new file mode 100644 index 00000000..bbbb3a54 --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/models/service_api_description.py @@ -0,0 +1,365 @@ +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from visibility_control.models.base_model import Model +from visibility_control.models.aef_profile import AefProfile +from visibility_control.models.api_status import ApiStatus +from visibility_control.models.published_api_path import PublishedApiPath +from visibility_control.models.shareable_information import ShareableInformation +import re +from visibility_control import util + +from visibility_control.models.aef_profile import AefProfile # noqa: E501 +from visibility_control.models.api_status import ApiStatus # noqa: E501 +from visibility_control.models.published_api_path import PublishedApiPath # noqa: E501 +from visibility_control.models.shareable_information import ShareableInformation # noqa: E501 +import re # noqa: E501 + +class ServiceAPIDescription(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, api_name=None, api_id=None, api_status=None, aef_profiles=None, description=None, supported_features=None, shareable_info=None, service_api_category=None, api_supp_feats=None, pub_api_path=None, ccf_id=None, api_prov_name=None): # noqa: E501 + """ServiceAPIDescription - a model defined in OpenAPI + + :param api_name: The api_name of this ServiceAPIDescription. # noqa: E501 + :type api_name: str + :param api_id: The api_id of this ServiceAPIDescription. # noqa: E501 + :type api_id: str + :param api_status: The api_status of this ServiceAPIDescription. # noqa: E501 + :type api_status: ApiStatus + :param aef_profiles: The aef_profiles of this ServiceAPIDescription. # noqa: E501 + :type aef_profiles: List[AefProfile] + :param description: The description of this ServiceAPIDescription. # noqa: E501 + :type description: str + :param supported_features: The supported_features of this ServiceAPIDescription. # noqa: E501 + :type supported_features: str + :param shareable_info: The shareable_info of this ServiceAPIDescription. # noqa: E501 + :type shareable_info: ShareableInformation + :param service_api_category: The service_api_category of this ServiceAPIDescription. # noqa: E501 + :type service_api_category: str + :param api_supp_feats: The api_supp_feats of this ServiceAPIDescription. # noqa: E501 + :type api_supp_feats: str + :param pub_api_path: The pub_api_path of this ServiceAPIDescription. # noqa: E501 + :type pub_api_path: PublishedApiPath + :param ccf_id: The ccf_id of this ServiceAPIDescription. # noqa: E501 + :type ccf_id: str + :param api_prov_name: The api_prov_name of this ServiceAPIDescription. # noqa: E501 + :type api_prov_name: str + """ + self.openapi_types = { + 'api_name': str, + 'api_id': str, + 'api_status': ApiStatus, + 'aef_profiles': List[AefProfile], + 'description': str, + 'supported_features': str, + 'shareable_info': ShareableInformation, + 'service_api_category': str, + 'api_supp_feats': str, + 'pub_api_path': PublishedApiPath, + 'ccf_id': str, + 'api_prov_name': str + } + + self.attribute_map = { + 'api_name': 'apiName', + 'api_id': 'apiId', + 'api_status': 'apiStatus', + 'aef_profiles': 'aefProfiles', + 'description': 'description', + 'supported_features': 'supportedFeatures', + 'shareable_info': 'shareableInfo', + 'service_api_category': 'serviceAPICategory', + 'api_supp_feats': 'apiSuppFeats', + 'pub_api_path': 'pubApiPath', + 'ccf_id': 'ccfId', + 'api_prov_name': 'apiProvName' + } + + self._api_name = api_name + self._api_id = api_id + self._api_status = api_status + self._aef_profiles = aef_profiles + self._description = description + self._supported_features = supported_features + self._shareable_info = shareable_info + self._service_api_category = service_api_category + self._api_supp_feats = api_supp_feats + self._pub_api_path = pub_api_path + self._ccf_id = ccf_id + self._api_prov_name = api_prov_name + + @classmethod + def from_dict(cls, dikt) -> 'ServiceAPIDescription': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The ServiceAPIDescription of this ServiceAPIDescription. # noqa: E501 + :rtype: ServiceAPIDescription + """ + return util.deserialize_model(dikt, cls) + + @property + def api_name(self) -> str: + """Gets the api_name of this ServiceAPIDescription. + + + :return: The api_name of this ServiceAPIDescription. + :rtype: str + """ + return self._api_name + + @api_name.setter + def api_name(self, api_name: str): + """Sets the api_name of this ServiceAPIDescription. + + + :param api_name: The api_name of this ServiceAPIDescription. + :type api_name: str + """ + if api_name is None: + raise ValueError("Invalid value for `api_name`, must not be `None`") # noqa: E501 + + self._api_name = api_name + + @property + def api_id(self) -> str: + """Gets the api_id of this ServiceAPIDescription. + + + :return: The api_id of this ServiceAPIDescription. + :rtype: str + """ + return self._api_id + + @api_id.setter + def api_id(self, api_id: str): + """Sets the api_id of this ServiceAPIDescription. + + + :param api_id: The api_id of this ServiceAPIDescription. + :type api_id: str + """ + + self._api_id = api_id + + @property + def api_status(self) -> ApiStatus: + """Gets the api_status of this ServiceAPIDescription. + + + :return: The api_status of this ServiceAPIDescription. + :rtype: ApiStatus + """ + return self._api_status + + @api_status.setter + def api_status(self, api_status: ApiStatus): + """Sets the api_status of this ServiceAPIDescription. + + + :param api_status: The api_status of this ServiceAPIDescription. + :type api_status: ApiStatus + """ + + self._api_status = api_status + + @property + def aef_profiles(self) -> List[AefProfile]: + """Gets the aef_profiles of this ServiceAPIDescription. + + + :return: The aef_profiles of this ServiceAPIDescription. + :rtype: List[AefProfile] + """ + return self._aef_profiles + + @aef_profiles.setter + def aef_profiles(self, aef_profiles: List[AefProfile]): + """Sets the aef_profiles of this ServiceAPIDescription. + + + :param aef_profiles: The aef_profiles of this ServiceAPIDescription. + :type aef_profiles: List[AefProfile] + """ + if aef_profiles is not None and len(aef_profiles) < 1: + raise ValueError("Invalid value for `aef_profiles`, number of items must be greater than or equal to `1`") # noqa: E501 + + self._aef_profiles = aef_profiles + + @property + def description(self) -> str: + """Gets the description of this ServiceAPIDescription. + + + :return: The description of this ServiceAPIDescription. + :rtype: str + """ + return self._description + + @description.setter + def description(self, description: str): + """Sets the description of this ServiceAPIDescription. + + + :param description: The description of this ServiceAPIDescription. + :type description: str + """ + + self._description = description + + @property + def supported_features(self) -> str: + """Gets the supported_features of this ServiceAPIDescription. + + + :return: The supported_features of this ServiceAPIDescription. + :rtype: str + """ + return self._supported_features + + @supported_features.setter + def supported_features(self, supported_features: str): + """Sets the supported_features of this ServiceAPIDescription. + + + :param supported_features: The supported_features of this ServiceAPIDescription. + :type supported_features: str + """ + if supported_features is not None and not re.search(r'^[A-Fa-f0-9]*$', supported_features): # noqa: E501 + raise ValueError(r"Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 + + self._supported_features = supported_features + + @property + def shareable_info(self) -> ShareableInformation: + """Gets the shareable_info of this ServiceAPIDescription. + + + :return: The shareable_info of this ServiceAPIDescription. + :rtype: ShareableInformation + """ + return self._shareable_info + + @shareable_info.setter + def shareable_info(self, shareable_info: ShareableInformation): + """Sets the shareable_info of this ServiceAPIDescription. + + + :param shareable_info: The shareable_info of this ServiceAPIDescription. + :type shareable_info: ShareableInformation + """ + + self._shareable_info = shareable_info + + @property + def service_api_category(self) -> str: + """Gets the service_api_category of this ServiceAPIDescription. + + + :return: The service_api_category of this ServiceAPIDescription. + :rtype: str + """ + return self._service_api_category + + @service_api_category.setter + def service_api_category(self, service_api_category: str): + """Sets the service_api_category of this ServiceAPIDescription. + + + :param service_api_category: The service_api_category of this ServiceAPIDescription. + :type service_api_category: str + """ + + self._service_api_category = service_api_category + + @property + def api_supp_feats(self) -> str: + """Gets the api_supp_feats of this ServiceAPIDescription. + + + :return: The api_supp_feats of this ServiceAPIDescription. + :rtype: str + """ + return self._api_supp_feats + + @api_supp_feats.setter + def api_supp_feats(self, api_supp_feats: str): + """Sets the api_supp_feats of this ServiceAPIDescription. + + + :param api_supp_feats: The api_supp_feats of this ServiceAPIDescription. + :type api_supp_feats: str + """ + if api_supp_feats is not None and not re.search(r'^[A-Fa-f0-9]*$', api_supp_feats): # noqa: E501 + raise ValueError(r"Invalid value for `api_supp_feats`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 + + self._api_supp_feats = api_supp_feats + + @property + def pub_api_path(self) -> PublishedApiPath: + """Gets the pub_api_path of this ServiceAPIDescription. + + + :return: The pub_api_path of this ServiceAPIDescription. + :rtype: PublishedApiPath + """ + return self._pub_api_path + + @pub_api_path.setter + def pub_api_path(self, pub_api_path: PublishedApiPath): + """Sets the pub_api_path of this ServiceAPIDescription. + + + :param pub_api_path: The pub_api_path of this ServiceAPIDescription. + :type pub_api_path: PublishedApiPath + """ + + self._pub_api_path = pub_api_path + + @property + def ccf_id(self) -> str: + """Gets the ccf_id of this ServiceAPIDescription. + + + :return: The ccf_id of this ServiceAPIDescription. + :rtype: str + """ + return self._ccf_id + + @ccf_id.setter + def ccf_id(self, ccf_id: str): + """Sets the ccf_id of this ServiceAPIDescription. + + + :param ccf_id: The ccf_id of this ServiceAPIDescription. + :type ccf_id: str + """ + + self._ccf_id = ccf_id + + @property + def api_prov_name(self) -> str: + """Gets the api_prov_name of this ServiceAPIDescription. + + + :return: The api_prov_name of this ServiceAPIDescription. + :rtype: str + """ + return self._api_prov_name + + @api_prov_name.setter + def api_prov_name(self, api_prov_name: str): + """Sets the api_prov_name of this ServiceAPIDescription. + + + :param api_prov_name: The api_prov_name of this ServiceAPIDescription. + :type api_prov_name: str + """ + + self._api_prov_name = api_prov_name diff --git a/services/helper/helper_service/services/visibility_control/models/service_kpis.py b/services/helper/helper_service/services/visibility_control/models/service_kpis.py new file mode 100644 index 00000000..16abcd92 --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/models/service_kpis.py @@ -0,0 +1,191 @@ +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from visibility_control.models.base_model import Model +from visibility_control import util + + +class ServiceKpis(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, max_req_rate=None, max_restime=None, availability=None, aval_comp=None, aval_mem=None, aval_stor=None): # noqa: E501 + """ServiceKpis - a model defined in OpenAPI + + :param max_req_rate: The max_req_rate of this ServiceKpis. # noqa: E501 + :type max_req_rate: int + :param max_restime: The max_restime of this ServiceKpis. # noqa: E501 + :type max_restime: int + :param availability: The availability of this ServiceKpis. # noqa: E501 + :type availability: int + :param aval_comp: The aval_comp of this ServiceKpis. # noqa: E501 + :type aval_comp: str + :param aval_mem: The aval_mem of this ServiceKpis. # noqa: E501 + :type aval_mem: str + :param aval_stor: The aval_stor of this ServiceKpis. # noqa: E501 + :type aval_stor: str + """ + self.openapi_types = { + 'max_req_rate': int, + 'max_restime': int, + 'availability': int, + 'aval_comp': str, + 'aval_mem': str, + 'aval_stor': str + } + + self.attribute_map = { + 'max_req_rate': 'maxReqRate', + 'max_restime': 'maxRestime', + 'availability': 'availability', + 'aval_comp': 'avalComp', + 'aval_mem': 'avalMem', + 'aval_stor': 'avalStor' + } + + self._max_req_rate = max_req_rate + self._max_restime = max_restime + self._availability = availability + self._aval_comp = aval_comp + self._aval_mem = aval_mem + self._aval_stor = aval_stor + + @classmethod + def from_dict(cls, dikt) -> 'ServiceKpis': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The ServiceKpis of this ServiceKpis. # noqa: E501 + :rtype: ServiceKpis + """ + return util.deserialize_model(dikt, cls) + + @property + def max_req_rate(self) -> int: + """Gets the max_req_rate of this ServiceKpis. + + + :return: The max_req_rate of this ServiceKpis. + :rtype: int + """ + return self._max_req_rate + + @max_req_rate.setter + def max_req_rate(self, max_req_rate: int): + """Sets the max_req_rate of this ServiceKpis. + + + :param max_req_rate: The max_req_rate of this ServiceKpis. + :type max_req_rate: int + """ + + self._max_req_rate = max_req_rate + + @property + def max_restime(self) -> int: + """Gets the max_restime of this ServiceKpis. + + + :return: The max_restime of this ServiceKpis. + :rtype: int + """ + return self._max_restime + + @max_restime.setter + def max_restime(self, max_restime: int): + """Sets the max_restime of this ServiceKpis. + + + :param max_restime: The max_restime of this ServiceKpis. + :type max_restime: int + """ + + self._max_restime = max_restime + + @property + def availability(self) -> int: + """Gets the availability of this ServiceKpis. + + + :return: The availability of this ServiceKpis. + :rtype: int + """ + return self._availability + + @availability.setter + def availability(self, availability: int): + """Sets the availability of this ServiceKpis. + + + :param availability: The availability of this ServiceKpis. + :type availability: int + """ + + self._availability = availability + + @property + def aval_comp(self) -> str: + """Gets the aval_comp of this ServiceKpis. + + + :return: The aval_comp of this ServiceKpis. + :rtype: str + """ + return self._aval_comp + + @aval_comp.setter + def aval_comp(self, aval_comp: str): + """Sets the aval_comp of this ServiceKpis. + + + :param aval_comp: The aval_comp of this ServiceKpis. + :type aval_comp: str + """ + + self._aval_comp = aval_comp + + @property + def aval_mem(self) -> str: + """Gets the aval_mem of this ServiceKpis. + + + :return: The aval_mem of this ServiceKpis. + :rtype: str + """ + return self._aval_mem + + @aval_mem.setter + def aval_mem(self, aval_mem: str): + """Sets the aval_mem of this ServiceKpis. + + + :param aval_mem: The aval_mem of this ServiceKpis. + :type aval_mem: str + """ + + self._aval_mem = aval_mem + + @property + def aval_stor(self) -> str: + """Gets the aval_stor of this ServiceKpis. + + + :return: The aval_stor of this ServiceKpis. + :rtype: str + """ + return self._aval_stor + + @aval_stor.setter + def aval_stor(self, aval_stor: str): + """Sets the aval_stor of this ServiceKpis. + + + :param aval_stor: The aval_stor of this ServiceKpis. + :type aval_stor: str + """ + + self._aval_stor = aval_stor diff --git a/services/helper/helper_service/services/visibility_control/models/shareable_information.py b/services/helper/helper_service/services/visibility_control/models/shareable_information.py new file mode 100644 index 00000000..997f424a --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/models/shareable_information.py @@ -0,0 +1,89 @@ +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from visibility_control.models.base_model import Model +from visibility_control import util + + +class ShareableInformation(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, is_shareable=None, capif_prov_doms=None): # noqa: E501 + """ShareableInformation - a model defined in OpenAPI + + :param is_shareable: The is_shareable of this ShareableInformation. # noqa: E501 + :type is_shareable: bool + :param capif_prov_doms: The capif_prov_doms of this ShareableInformation. # noqa: E501 + :type capif_prov_doms: List[str] + """ + self.openapi_types = { + 'is_shareable': bool, + 'capif_prov_doms': List[str] + } + + self.attribute_map = { + 'is_shareable': 'isShareable', + 'capif_prov_doms': 'capifProvDoms' + } + + self._is_shareable = is_shareable + self._capif_prov_doms = capif_prov_doms + + @classmethod + def from_dict(cls, dikt) -> 'ShareableInformation': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The ShareableInformation of this ShareableInformation. # noqa: E501 + :rtype: ShareableInformation + """ + return util.deserialize_model(dikt, cls) + + @property + def is_shareable(self) -> bool: + """Gets the is_shareable of this ShareableInformation. + + + :return: The is_shareable of this ShareableInformation. + :rtype: bool + """ + return self._is_shareable + + @is_shareable.setter + def is_shareable(self, is_shareable: bool): + """Sets the is_shareable of this ShareableInformation. + + + :param is_shareable: The is_shareable of this ShareableInformation. + :type is_shareable: bool + """ + if is_shareable is None: + raise ValueError("Invalid value for `is_shareable`, must not be `None`") # noqa: E501 + + self._is_shareable = is_shareable + + @property + def capif_prov_doms(self) -> List[str]: + """Gets the capif_prov_doms of this ShareableInformation. + + + :return: The capif_prov_doms of this ShareableInformation. + :rtype: List[str] + """ + return self._capif_prov_doms + + @capif_prov_doms.setter + def capif_prov_doms(self, capif_prov_doms: List[str]): + """Sets the capif_prov_doms of this ShareableInformation. + + + :param capif_prov_doms: The capif_prov_doms of this ShareableInformation. + :type capif_prov_doms: List[str] + """ + + self._capif_prov_doms = capif_prov_doms diff --git a/services/helper/helper_service/services/visibility_control/models/version.py b/services/helper/helper_service/services/visibility_control/models/version.py new file mode 100644 index 00000000..5752d1cf --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/models/version.py @@ -0,0 +1,145 @@ +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from visibility_control.models.base_model import Model +from visibility_control.models.custom_operation import CustomOperation +from visibility_control.models.resource import Resource +from visibility_control import util + +from visibility_control.models.custom_operation import CustomOperation # noqa: E501 +from visibility_control.models.resource import Resource # noqa: E501 + +class Version(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, api_version=None, expiry=None, resources=None, cust_operations=None): # noqa: E501 + """Version - a model defined in OpenAPI + + :param api_version: The api_version of this Version. # noqa: E501 + :type api_version: str + :param expiry: The expiry of this Version. # noqa: E501 + :type expiry: datetime + :param resources: The resources of this Version. # noqa: E501 + :type resources: List[Resource] + :param cust_operations: The cust_operations of this Version. # noqa: E501 + :type cust_operations: List[CustomOperation] + """ + self.openapi_types = { + 'api_version': str, + 'expiry': datetime, + 'resources': List[Resource], + 'cust_operations': List[CustomOperation] + } + + self.attribute_map = { + 'api_version': 'apiVersion', + 'expiry': 'expiry', + 'resources': 'resources', + 'cust_operations': 'custOperations' + } + + self._api_version = api_version + self._expiry = expiry + self._resources = resources + self._cust_operations = cust_operations + + @classmethod + def from_dict(cls, dikt) -> 'Version': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The Version of this Version. # noqa: E501 + :rtype: Version + """ + return util.deserialize_model(dikt, cls) + + @property + def api_version(self) -> str: + """Gets the api_version of this Version. + + + :return: The api_version of this Version. + :rtype: str + """ + return self._api_version + + @api_version.setter + def api_version(self, api_version: str): + """Sets the api_version of this Version. + + + :param api_version: The api_version of this Version. + :type api_version: str + """ + if api_version is None: + raise ValueError("Invalid value for `api_version`, must not be `None`") # noqa: E501 + + self._api_version = api_version + + @property + def expiry(self) -> datetime: + """Gets the expiry of this Version. + + + :return: The expiry of this Version. + :rtype: datetime + """ + return self._expiry + + @expiry.setter + def expiry(self, expiry: datetime): + """Sets the expiry of this Version. + + + :param expiry: The expiry of this Version. + :type expiry: datetime + """ + + self._expiry = expiry + + @property + def resources(self) -> List[Resource]: + """Gets the resources of this Version. + + + :return: The resources of this Version. + :rtype: List[Resource] + """ + return self._resources + + @resources.setter + def resources(self, resources: List[Resource]): + """Sets the resources of this Version. + + + :param resources: The resources of this Version. + :type resources: List[Resource] + """ + + self._resources = resources + + @property + def cust_operations(self) -> List[CustomOperation]: + """Gets the cust_operations of this Version. + + + :return: The cust_operations of this Version. + :rtype: List[CustomOperation] + """ + return self._cust_operations + + @cust_operations.setter + def cust_operations(self, cust_operations: List[CustomOperation]): + """Sets the cust_operations of this Version. + + + :param cust_operations: The cust_operations of this Version. + :type cust_operations: List[CustomOperation] + """ + + self._cust_operations = cust_operations diff --git a/services/helper/helper_service/services/visibility_control/openapi/openapi.yaml b/services/helper/helper_service/services/visibility_control/openapi/openapi.yaml new file mode 100644 index 00000000..eeaeafcc --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/openapi/openapi.yaml @@ -0,0 +1,1938 @@ +openapi: 3.0.3 +info: + description: | + Access-control API to manage visibility rules and evaluate decisions for API discovery and + security-context access within OpenCAPIF. This API controls whether APIs are visible to invokers + (discovery) and whether invokers are allowed to create a security context to access them. + - Rules are global and evaluated with "more specific wins" precedence. + - If no rule matches, the decision uses OpenCAPIF's global default (outside this API). + - Provider selector is mandatory in rules and must contain at least one selector field. + title: OpenCAPIF Access Control + version: 1.0.0 +servers: +- description: Production + url: https://capif.example.com/access-control +- description: Sandbox + url: https://sandbox.capif.example.com/access-control +tags: +- description: Manage visibility rules + name: Rules +- description: Evaluate discovery and access decisions + name: Decision +paths: + /decision/invokers/{apiInvokerId}/discoverable-apis: + get: + description: | + Returns a filtered list of APIs for the API Invoker. + operationId: decision_invokers_api_invoker_id_discoverable_apis_get + parameters: + - description: CAPIF API Invoker identifier + explode: false + in: path + name: apiInvokerId + required: true + schema: + type: string + style: simple + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/DiscoveredAPIs' + description: Discover filter + "400": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Invalid input + "404": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Invoker not found (optional behavior) + summary: Get discoverable APIs filter for an invoker (global scope) + tags: + - Decision + x-openapi-router-controller: visibility_control.controllers.decision_controller + /rules: + get: + operationId: rules_get + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/_rules_get_200_response' + description: List of rules + summary: List rules + tags: + - Rules + x-openapi-router-controller: visibility_control.controllers.rules_controller + post: + description: Server generates the ruleId. Provider selector must include at + least one field. + operationId: rules_post + requestBody: + content: + application/json: + examples: + allow_except_some_invokers: + value: + providerSelector: + createdByUser: userA + apiProviderId: + - capif-prov-01 + - capif-prov-02 + apiName: + - apiName-001 + apiId: + - apiId-001 + aefId: + - aef-001 + invokerExceptions: + apiInvokerId: + - invk-123 + - invk-999 + default_access: ALLOW + enabled: true + schema: + $ref: '#/components/schemas/RuleCreateRequest' + required: true + responses: + "201": + content: + application/json: + schema: + $ref: '#/components/schemas/Rule' + description: Rule created + "400": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Invalid input + summary: Create a rule + tags: + - Rules + x-openapi-router-controller: visibility_control.controllers.rules_controller + /rules/{ruleId}: + delete: + operationId: rules_rule_id_delete + parameters: + - description: Server-generated rule identifier + explode: false + in: path + name: ruleId + required: true + schema: + type: string + style: simple + responses: + "204": + description: Deleted + "404": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Rule not found + summary: Delete a rule + tags: + - Rules + x-openapi-router-controller: visibility_control.controllers.rules_controller + get: + operationId: rules_rule_id_get + parameters: + - description: Server-generated rule identifier + explode: false + in: path + name: ruleId + required: true + schema: + type: string + style: simple + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/Rule' + description: Rule + "404": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Rule not found + summary: Get a rule + tags: + - Rules + x-openapi-router-controller: visibility_control.controllers.rules_controller + patch: + operationId: rules_rule_id_patch + parameters: + - description: Server-generated rule identifier + explode: false + in: path + name: ruleId + required: true + schema: + type: string + style: simple + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/RulePatchRequest' + required: true + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/Rule' + description: Rule updated + "400": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Invalid input + "404": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Rule not found + summary: Update a rule (partial) + tags: + - Rules + x-openapi-router-controller: visibility_control.controllers.rules_controller +components: + parameters: + RuleId: + description: Server-generated rule identifier + explode: false + in: path + name: ruleId + required: true + schema: + type: string + style: simple + ApiInvokerId: + description: CAPIF API Invoker identifier + explode: false + in: path + name: apiInvokerId + required: true + schema: + type: string + style: simple + schemas: + RuleCreateRequest: + description: | + Create a new rule. Provider selector is mandatory and must include at least one field. + If both startsAt and endsAt are present, endsAt must be greater than startsAt. + example: + default_access: ALLOW + notes: notes + startsAt: 2000-01-23T04:56:07.000+00:00 + invokerExceptions: + invokerOnboardedByUser: + - invokerOnboardedByUser + - invokerOnboardedByUser + apiInvokerId: + - apiInvokerId + - apiInvokerId + providerSelector: + apiProviderId: + - apiProviderId + - apiProviderId + apiName: + - apiName + - apiName + createdByUser: createdByUser + aefId: + - aefId + - aefId + apiId: + - apiId + - apiId + endsAt: 2000-01-23T04:56:07.000+00:00 + enabled: true + properties: + providerSelector: + $ref: '#/components/schemas/ProviderSelector' + invokerExceptions: + $ref: '#/components/schemas/InvokerSelector' + default_access: + enum: + - ALLOW + - DENY + title: default_access + type: string + enabled: + default: true + title: enabled + type: boolean + startsAt: + format: date-time + title: startsAt + type: string + endsAt: + format: date-time + title: endsAt + type: string + notes: + title: notes + type: string + required: + - default_access + - providerSelector + title: RuleCreateRequest + type: object + RulePatchRequest: + description: Partial update. Any omitted field remains unchanged. + example: + default_access: ALLOW + notes: notes + startsAt: 2000-01-23T04:56:07.000+00:00 + invokerExceptions: + invokerOnboardedByUser: + - invokerOnboardedByUser + - invokerOnboardedByUser + apiInvokerId: + - apiInvokerId + - apiInvokerId + providerSelector: + apiProviderId: + - apiProviderId + - apiProviderId + apiName: + - apiName + - apiName + aefId: + - aefId + - aefId + apiId: + - apiId + - apiId + endsAt: 2000-01-23T04:56:07.000+00:00 + enabled: true + properties: + providerSelector: + $ref: '#/components/schemas/PatchProviderSelector' + invokerExceptions: + $ref: '#/components/schemas/InvokerSelector' + default_access: + enum: + - ALLOW + - DENY + title: default_access + type: string + enabled: + title: enabled + type: boolean + startsAt: + format: date-time + title: startsAt + type: string + endsAt: + format: date-time + title: endsAt + type: string + notes: + title: notes + type: string + title: RulePatchRequest + type: object + Rule: + example: + default_access: ALLOW + notes: notes + updatedBy: updatedBy + startsAt: 2000-01-23T04:56:07.000+00:00 + invokerExceptions: + invokerOnboardedByUser: + - invokerOnboardedByUser + - invokerOnboardedByUser + apiInvokerId: + - apiInvokerId + - apiInvokerId + providerSelector: + apiProviderId: + - apiProviderId + - apiProviderId + apiName: + - apiName + - apiName + createdByUser: createdByUser + aefId: + - aefId + - aefId + apiId: + - apiId + - apiId + ruleId: ruleId + endsAt: 2000-01-23T04:56:07.000+00:00 + enabled: true + updatedAt: 2000-01-23T04:56:07.000+00:00 + properties: + ruleId: + title: ruleId + type: string + providerSelector: + $ref: '#/components/schemas/ProviderSelector' + invokerExceptions: + $ref: '#/components/schemas/InvokerSelector' + default_access: + enum: + - ALLOW + - DENY + title: default_access + type: string + enabled: + default: true + title: enabled + type: boolean + startsAt: + format: date-time + title: startsAt + type: string + endsAt: + format: date-time + title: endsAt + type: string + notes: + title: notes + type: string + updatedAt: + format: date-time + title: updatedAt + type: string + updatedBy: + title: updatedBy + type: string + required: + - default_access + - providerSelector + - ruleId + title: Rule + type: object + PatchProviderSelector: + additionalProperties: false + description: | + Patch Provider-side selector. + example: + apiProviderId: + - apiProviderId + - apiProviderId + apiName: + - apiName + - apiName + aefId: + - aefId + - aefId + apiId: + - apiId + - apiId + properties: + apiProviderId: + items: + type: string + minItems: 0 + title: apiProviderId + type: array + uniqueItems: true + apiName: + items: + type: string + minItems: 0 + title: apiName + type: array + uniqueItems: true + apiId: + items: + type: string + minItems: 0 + title: apiId + type: array + uniqueItems: true + aefId: + items: + type: string + minItems: 0 + title: aefId + type: array + uniqueItems: true + title: PatchProviderSelector + type: object + ProviderSelector: + additionalProperties: false + description: | + Provider-side selector. Arrays apply OR within the field; AND across fields. + At least one of these fields must be present. + example: + apiProviderId: + - apiProviderId + - apiProviderId + apiName: + - apiName + - apiName + createdByUser: createdByUser + aefId: + - aefId + - aefId + apiId: + - apiId + - apiId + properties: + createdByUser: + minLength: 1 + title: createdByUser + type: string + apiProviderId: + items: + type: string + minItems: 0 + title: apiProviderId + type: array + uniqueItems: true + apiName: + items: + type: string + minItems: 0 + title: apiName + type: array + uniqueItems: true + apiId: + items: + type: string + minItems: 0 + title: apiId + type: array + uniqueItems: true + aefId: + items: + type: string + minItems: 0 + title: aefId + type: array + uniqueItems: true + required: + - createdByUser + title: ProviderSelector + type: object + InvokerSelector: + additionalProperties: false + description: Invoker-side selector used for exceptions. Optional; arrays use + OR within the field; AND across fields. + example: + invokerOnboardedByUser: + - invokerOnboardedByUser + - invokerOnboardedByUser + apiInvokerId: + - apiInvokerId + - apiInvokerId + properties: + invokerOnboardedByUser: + items: + type: string + minItems: 0 + title: invokerOnboardedByUser + type: array + uniqueItems: true + apiInvokerId: + items: + type: string + minItems: 0 + title: apiInvokerId + type: array + uniqueItems: true + title: InvokerSelector + type: object + DiscoveredAPIs: + example: + serviceAPIDescriptions: + - serviceAPICategory: serviceAPICategory + ccfId: ccfId + apiName: apiName + shareableInfo: + capifProvDoms: + - capifProvDoms + - capifProvDoms + isShareable: true + apiProvName: apiProvName + supportedFeatures: supportedFeatures + description: description + apiSuppFeats: apiSuppFeats + apiId: apiId + apiStatus: + aefIds: + - aefIds + - aefIds + aefProfiles: + - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS + ueIpRange: + ueIpv4AddrRanges: + - start: start + end: end + - start: start + end: end + securityMethods: + - PSK + - PSK + versions: + - apiVersion: apiVersion + resources: + - operations: + - GET + - GET + commType: REQUEST_RESPONSE + description: description + resourceName: resourceName + custOpName: custOpName + uri: uri + - operations: + - GET + - GET + commType: REQUEST_RESPONSE + description: description + resourceName: resourceName + custOpName: custOpName + uri: uri + custOperations: + - operations: + - null + - null + commType: null + description: description + custOpName: custOpName + - operations: + - null + - null + commType: null + description: description + custOpName: custOpName + expiry: 2000-01-23T04:56:07.000+00:00 + - apiVersion: apiVersion + resources: + - operations: + - GET + - GET + commType: REQUEST_RESPONSE + description: description + resourceName: resourceName + custOpName: custOpName + uri: uri + - operations: + - GET + - GET + commType: REQUEST_RESPONSE + description: description + resourceName: resourceName + custOpName: custOpName + uri: uri + custOperations: + - operations: + - null + - null + commType: null + description: description + custOpName: custOpName + - operations: + - null + - null + commType: null + description: description + custOpName: custOpName + expiry: 2000-01-23T04:56:07.000+00:00 + dataFormat: JSON + domainName: domainName + aefLocation: + dcId: dcId + aefId: aefId + interfaceDescriptions: + - ipv6Addr: ipv6Addr + grantTypes: + - null + - null + securityMethods: + - null + - null + fqdn: fqdn + port: 0 + apiPrefix: apiPrefix + ipv4Addr: ipv4Addr + - ipv6Addr: ipv6Addr + grantTypes: + - null + - null + securityMethods: + - null + - null + fqdn: fqdn + port: 0 + apiPrefix: apiPrefix + ipv4Addr: ipv4Addr + serviceKpis: + avalMem: avalMem + avalStor: avalStor + avalComp: avalComp + maxRestime: 1 + availability: 5 + maxReqRate: 6 + - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS + ueIpRange: + ueIpv4AddrRanges: + - start: start + end: end + - start: start + end: end + securityMethods: + - PSK + - PSK + versions: + - apiVersion: apiVersion + resources: + - operations: + - GET + - GET + commType: REQUEST_RESPONSE + description: description + resourceName: resourceName + custOpName: custOpName + uri: uri + - operations: + - GET + - GET + commType: REQUEST_RESPONSE + description: description + resourceName: resourceName + custOpName: custOpName + uri: uri + custOperations: + - operations: + - null + - null + commType: null + description: description + custOpName: custOpName + - operations: + - null + - null + commType: null + description: description + custOpName: custOpName + expiry: 2000-01-23T04:56:07.000+00:00 + - apiVersion: apiVersion + resources: + - operations: + - GET + - GET + commType: REQUEST_RESPONSE + description: description + resourceName: resourceName + custOpName: custOpName + uri: uri + - operations: + - GET + - GET + commType: REQUEST_RESPONSE + description: description + resourceName: resourceName + custOpName: custOpName + uri: uri + custOperations: + - operations: + - null + - null + commType: null + description: description + custOpName: custOpName + - operations: + - null + - null + commType: null + description: description + custOpName: custOpName + expiry: 2000-01-23T04:56:07.000+00:00 + dataFormat: JSON + domainName: domainName + aefLocation: + dcId: dcId + aefId: aefId + interfaceDescriptions: + - ipv6Addr: ipv6Addr + grantTypes: + - null + - null + securityMethods: + - null + - null + fqdn: fqdn + port: 0 + apiPrefix: apiPrefix + ipv4Addr: ipv4Addr + - ipv6Addr: ipv6Addr + grantTypes: + - null + - null + securityMethods: + - null + - null + fqdn: fqdn + port: 0 + apiPrefix: apiPrefix + ipv4Addr: ipv4Addr + serviceKpis: + avalMem: avalMem + avalStor: avalStor + avalComp: avalComp + maxRestime: 1 + availability: 5 + maxReqRate: 6 + pubApiPath: + ccfIds: + - ccfIds + - ccfIds + - serviceAPICategory: serviceAPICategory + ccfId: ccfId + apiName: apiName + shareableInfo: + capifProvDoms: + - capifProvDoms + - capifProvDoms + isShareable: true + apiProvName: apiProvName + supportedFeatures: supportedFeatures + description: description + apiSuppFeats: apiSuppFeats + apiId: apiId + apiStatus: + aefIds: + - aefIds + - aefIds + aefProfiles: + - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS + ueIpRange: + ueIpv4AddrRanges: + - start: start + end: end + - start: start + end: end + securityMethods: + - PSK + - PSK + versions: + - apiVersion: apiVersion + resources: + - operations: + - GET + - GET + commType: REQUEST_RESPONSE + description: description + resourceName: resourceName + custOpName: custOpName + uri: uri + - operations: + - GET + - GET + commType: REQUEST_RESPONSE + description: description + resourceName: resourceName + custOpName: custOpName + uri: uri + custOperations: + - operations: + - null + - null + commType: null + description: description + custOpName: custOpName + - operations: + - null + - null + commType: null + description: description + custOpName: custOpName + expiry: 2000-01-23T04:56:07.000+00:00 + - apiVersion: apiVersion + resources: + - operations: + - GET + - GET + commType: REQUEST_RESPONSE + description: description + resourceName: resourceName + custOpName: custOpName + uri: uri + - operations: + - GET + - GET + commType: REQUEST_RESPONSE + description: description + resourceName: resourceName + custOpName: custOpName + uri: uri + custOperations: + - operations: + - null + - null + commType: null + description: description + custOpName: custOpName + - operations: + - null + - null + commType: null + description: description + custOpName: custOpName + expiry: 2000-01-23T04:56:07.000+00:00 + dataFormat: JSON + domainName: domainName + aefLocation: + dcId: dcId + aefId: aefId + interfaceDescriptions: + - ipv6Addr: ipv6Addr + grantTypes: + - null + - null + securityMethods: + - null + - null + fqdn: fqdn + port: 0 + apiPrefix: apiPrefix + ipv4Addr: ipv4Addr + - ipv6Addr: ipv6Addr + grantTypes: + - null + - null + securityMethods: + - null + - null + fqdn: fqdn + port: 0 + apiPrefix: apiPrefix + ipv4Addr: ipv4Addr + serviceKpis: + avalMem: avalMem + avalStor: avalStor + avalComp: avalComp + maxRestime: 1 + availability: 5 + maxReqRate: 6 + - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS + ueIpRange: + ueIpv4AddrRanges: + - start: start + end: end + - start: start + end: end + securityMethods: + - PSK + - PSK + versions: + - apiVersion: apiVersion + resources: + - operations: + - GET + - GET + commType: REQUEST_RESPONSE + description: description + resourceName: resourceName + custOpName: custOpName + uri: uri + - operations: + - GET + - GET + commType: REQUEST_RESPONSE + description: description + resourceName: resourceName + custOpName: custOpName + uri: uri + custOperations: + - operations: + - null + - null + commType: null + description: description + custOpName: custOpName + - operations: + - null + - null + commType: null + description: description + custOpName: custOpName + expiry: 2000-01-23T04:56:07.000+00:00 + - apiVersion: apiVersion + resources: + - operations: + - GET + - GET + commType: REQUEST_RESPONSE + description: description + resourceName: resourceName + custOpName: custOpName + uri: uri + - operations: + - GET + - GET + commType: REQUEST_RESPONSE + description: description + resourceName: resourceName + custOpName: custOpName + uri: uri + custOperations: + - operations: + - null + - null + commType: null + description: description + custOpName: custOpName + - operations: + - null + - null + commType: null + description: description + custOpName: custOpName + expiry: 2000-01-23T04:56:07.000+00:00 + dataFormat: JSON + domainName: domainName + aefLocation: + dcId: dcId + aefId: aefId + interfaceDescriptions: + - ipv6Addr: ipv6Addr + grantTypes: + - null + - null + securityMethods: + - null + - null + fqdn: fqdn + port: 0 + apiPrefix: apiPrefix + ipv4Addr: ipv4Addr + - ipv6Addr: ipv6Addr + grantTypes: + - null + - null + securityMethods: + - null + - null + fqdn: fqdn + port: 0 + apiPrefix: apiPrefix + ipv4Addr: ipv4Addr + serviceKpis: + avalMem: avalMem + avalStor: avalStor + avalComp: avalComp + maxRestime: 1 + availability: 5 + maxReqRate: 6 + pubApiPath: + ccfIds: + - ccfIds + - ccfIds + suppFeat: suppFeat + properties: + serviceAPIDescriptions: + items: + $ref: '#/components/schemas/ServiceAPIDescription' + minItems: 1 + title: serviceAPIDescriptions + type: array + suppFeat: + pattern: "^[A-Fa-f0-9]*$" + title: SupportedFeatures + type: string + title: DiscoveredAPIs + type: object + ServiceAPIDescription: + example: + serviceAPICategory: serviceAPICategory + ccfId: ccfId + apiName: apiName + shareableInfo: + capifProvDoms: + - capifProvDoms + - capifProvDoms + isShareable: true + apiProvName: apiProvName + supportedFeatures: supportedFeatures + description: description + apiSuppFeats: apiSuppFeats + apiId: apiId + apiStatus: + aefIds: + - aefIds + - aefIds + aefProfiles: + - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS + ueIpRange: + ueIpv4AddrRanges: + - start: start + end: end + - start: start + end: end + securityMethods: + - PSK + - PSK + versions: + - apiVersion: apiVersion + resources: + - operations: + - GET + - GET + commType: REQUEST_RESPONSE + description: description + resourceName: resourceName + custOpName: custOpName + uri: uri + - operations: + - GET + - GET + commType: REQUEST_RESPONSE + description: description + resourceName: resourceName + custOpName: custOpName + uri: uri + custOperations: + - operations: + - null + - null + commType: null + description: description + custOpName: custOpName + - operations: + - null + - null + commType: null + description: description + custOpName: custOpName + expiry: 2000-01-23T04:56:07.000+00:00 + - apiVersion: apiVersion + resources: + - operations: + - GET + - GET + commType: REQUEST_RESPONSE + description: description + resourceName: resourceName + custOpName: custOpName + uri: uri + - operations: + - GET + - GET + commType: REQUEST_RESPONSE + description: description + resourceName: resourceName + custOpName: custOpName + uri: uri + custOperations: + - operations: + - null + - null + commType: null + description: description + custOpName: custOpName + - operations: + - null + - null + commType: null + description: description + custOpName: custOpName + expiry: 2000-01-23T04:56:07.000+00:00 + dataFormat: JSON + domainName: domainName + aefLocation: + dcId: dcId + aefId: aefId + interfaceDescriptions: + - ipv6Addr: ipv6Addr + grantTypes: + - null + - null + securityMethods: + - null + - null + fqdn: fqdn + port: 0 + apiPrefix: apiPrefix + ipv4Addr: ipv4Addr + - ipv6Addr: ipv6Addr + grantTypes: + - null + - null + securityMethods: + - null + - null + fqdn: fqdn + port: 0 + apiPrefix: apiPrefix + ipv4Addr: ipv4Addr + serviceKpis: + avalMem: avalMem + avalStor: avalStor + avalComp: avalComp + maxRestime: 1 + availability: 5 + maxReqRate: 6 + - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS + ueIpRange: + ueIpv4AddrRanges: + - start: start + end: end + - start: start + end: end + securityMethods: + - PSK + - PSK + versions: + - apiVersion: apiVersion + resources: + - operations: + - GET + - GET + commType: REQUEST_RESPONSE + description: description + resourceName: resourceName + custOpName: custOpName + uri: uri + - operations: + - GET + - GET + commType: REQUEST_RESPONSE + description: description + resourceName: resourceName + custOpName: custOpName + uri: uri + custOperations: + - operations: + - null + - null + commType: null + description: description + custOpName: custOpName + - operations: + - null + - null + commType: null + description: description + custOpName: custOpName + expiry: 2000-01-23T04:56:07.000+00:00 + - apiVersion: apiVersion + resources: + - operations: + - GET + - GET + commType: REQUEST_RESPONSE + description: description + resourceName: resourceName + custOpName: custOpName + uri: uri + - operations: + - GET + - GET + commType: REQUEST_RESPONSE + description: description + resourceName: resourceName + custOpName: custOpName + uri: uri + custOperations: + - operations: + - null + - null + commType: null + description: description + custOpName: custOpName + - operations: + - null + - null + commType: null + description: description + custOpName: custOpName + expiry: 2000-01-23T04:56:07.000+00:00 + dataFormat: JSON + domainName: domainName + aefLocation: + dcId: dcId + aefId: aefId + interfaceDescriptions: + - ipv6Addr: ipv6Addr + grantTypes: + - null + - null + securityMethods: + - null + - null + fqdn: fqdn + port: 0 + apiPrefix: apiPrefix + ipv4Addr: ipv4Addr + - ipv6Addr: ipv6Addr + grantTypes: + - null + - null + securityMethods: + - null + - null + fqdn: fqdn + port: 0 + apiPrefix: apiPrefix + ipv4Addr: ipv4Addr + serviceKpis: + avalMem: avalMem + avalStor: avalStor + avalComp: avalComp + maxRestime: 1 + availability: 5 + maxReqRate: 6 + pubApiPath: + ccfIds: + - ccfIds + - ccfIds + properties: + apiName: + title: apiName + type: string + apiId: + title: apiId + type: string + apiStatus: + $ref: '#/components/schemas/ApiStatus' + aefProfiles: + items: + $ref: '#/components/schemas/AefProfile' + minItems: 1 + title: aefProfiles + type: array + description: + title: description + type: string + supportedFeatures: + pattern: "^[A-Fa-f0-9]*$" + title: SupportedFeatures + type: string + shareableInfo: + $ref: '#/components/schemas/ShareableInformation' + serviceAPICategory: + title: serviceAPICategory + type: string + apiSuppFeats: + pattern: "^[A-Fa-f0-9]*$" + title: SupportedFeatures + type: string + pubApiPath: + $ref: '#/components/schemas/PublishedApiPath' + ccfId: + title: ccfId + type: string + apiProvName: + title: apiProvName + type: string + required: + - apiName + title: ServiceAPIDescription + type: object + AefProfile: + example: + protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS + ueIpRange: + ueIpv4AddrRanges: + - start: start + end: end + - start: start + end: end + securityMethods: + - PSK + - PSK + versions: + - apiVersion: apiVersion + resources: + - operations: + - GET + - GET + commType: REQUEST_RESPONSE + description: description + resourceName: resourceName + custOpName: custOpName + uri: uri + - operations: + - GET + - GET + commType: REQUEST_RESPONSE + description: description + resourceName: resourceName + custOpName: custOpName + uri: uri + custOperations: + - operations: + - null + - null + commType: null + description: description + custOpName: custOpName + - operations: + - null + - null + commType: null + description: description + custOpName: custOpName + expiry: 2000-01-23T04:56:07.000+00:00 + - apiVersion: apiVersion + resources: + - operations: + - GET + - GET + commType: REQUEST_RESPONSE + description: description + resourceName: resourceName + custOpName: custOpName + uri: uri + - operations: + - GET + - GET + commType: REQUEST_RESPONSE + description: description + resourceName: resourceName + custOpName: custOpName + uri: uri + custOperations: + - operations: + - null + - null + commType: null + description: description + custOpName: custOpName + - operations: + - null + - null + commType: null + description: description + custOpName: custOpName + expiry: 2000-01-23T04:56:07.000+00:00 + dataFormat: JSON + domainName: domainName + aefLocation: + dcId: dcId + aefId: aefId + interfaceDescriptions: + - ipv6Addr: ipv6Addr + grantTypes: + - null + - null + securityMethods: + - null + - null + fqdn: fqdn + port: 0 + apiPrefix: apiPrefix + ipv4Addr: ipv4Addr + - ipv6Addr: ipv6Addr + grantTypes: + - null + - null + securityMethods: + - null + - null + fqdn: fqdn + port: 0 + apiPrefix: apiPrefix + ipv4Addr: ipv4Addr + serviceKpis: + avalMem: avalMem + avalStor: avalStor + avalComp: avalComp + maxRestime: 1 + availability: 5 + maxReqRate: 6 + properties: + aefId: + title: aefId + type: string + versions: + items: + $ref: '#/components/schemas/Version' + minItems: 1 + title: versions + type: array + protocol: + $ref: '#/components/schemas/Protocol' + dataFormat: + $ref: '#/components/schemas/DataFormat' + securityMethods: + items: + $ref: '#/components/schemas/SecurityMethod' + title: securityMethods + type: array + grantTypes: + items: + $ref: '#/components/schemas/OAuthGrantType' + title: grantTypes + type: array + domainName: + title: domainName + type: string + interfaceDescriptions: + items: + $ref: '#/components/schemas/InterfaceDescription' + title: interfaceDescriptions + type: array + aefLocation: + $ref: '#/components/schemas/AefLocation' + serviceKpis: + $ref: '#/components/schemas/ServiceKpis' + ueIpRange: + $ref: '#/components/schemas/IpAddrRange' + required: + - aefId + - versions + title: AefProfile + type: object + Version: + example: + apiVersion: apiVersion + resources: + - operations: + - GET + - GET + commType: REQUEST_RESPONSE + description: description + resourceName: resourceName + custOpName: custOpName + uri: uri + - operations: + - GET + - GET + commType: REQUEST_RESPONSE + description: description + resourceName: resourceName + custOpName: custOpName + uri: uri + custOperations: + - operations: + - null + - null + commType: null + description: description + custOpName: custOpName + - operations: + - null + - null + commType: null + description: description + custOpName: custOpName + expiry: 2000-01-23T04:56:07.000+00:00 + properties: + apiVersion: + title: apiVersion + type: string + expiry: + format: date-time + title: expiry + type: string + resources: + items: + $ref: '#/components/schemas/Resource' + title: resources + type: array + custOperations: + items: + $ref: '#/components/schemas/CustomOperation' + title: custOperations + type: array + required: + - apiVersion + title: Version + type: object + Resource: + example: + operations: + - GET + - GET + commType: REQUEST_RESPONSE + description: description + resourceName: resourceName + custOpName: custOpName + uri: uri + properties: + resourceName: + title: resourceName + type: string + commType: + $ref: '#/components/schemas/CommunicationType' + uri: + title: uri + type: string + custOpName: + title: custOpName + type: string + operations: + items: + $ref: '#/components/schemas/Operation' + title: operations + type: array + description: + title: description + type: string + required: + - commType + - resourceName + - uri + title: Resource + type: object + CustomOperation: + example: + operations: + - null + - null + commType: null + description: description + custOpName: custOpName + properties: + commType: + $ref: '#/components/schemas/CommunicationType' + custOpName: + title: custOpName + type: string + operations: + items: + $ref: '#/components/schemas/Operation' + title: operations + type: array + description: + title: description + type: string + required: + - commType + - custOpName + title: CustomOperation + type: object + ApiStatus: + example: + aefIds: + - aefIds + - aefIds + properties: + aefIds: + items: + type: string + title: aefIds + type: array + required: + - aefIds + title: ApiStatus + type: object + InterfaceDescription: + example: + ipv6Addr: ipv6Addr + grantTypes: + - null + - null + securityMethods: + - null + - null + fqdn: fqdn + port: 0 + apiPrefix: apiPrefix + ipv4Addr: ipv4Addr + properties: + ipv4Addr: + title: ipv4Addr + type: string + ipv6Addr: + title: ipv6Addr + type: string + fqdn: + title: fqdn + type: string + port: + title: port + type: integer + apiPrefix: + title: apiPrefix + type: string + securityMethods: + items: + $ref: '#/components/schemas/SecurityMethod' + title: securityMethods + type: array + grantTypes: + items: + $ref: '#/components/schemas/OAuthGrantType' + title: grantTypes + type: array + title: InterfaceDescription + type: object + SupportedFeatures: + pattern: "^[A-Fa-f0-9]*$" + title: SupportedFeatures + type: string + CommunicationType: + enum: + - REQUEST_RESPONSE + - SUBSCRIBE_NOTIFY + title: CommunicationType + type: string + Protocol: + enum: + - HTTP_1_1 + - HTTP_2 + - MQTT + - WEBSOCKET + title: Protocol + type: string + DataFormat: + enum: + - JSON + - XML + - PROTOBUF3 + title: DataFormat + type: string + Operation: + enum: + - GET + - POST + - PUT + - PATCH + - DELETE + title: Operation + type: string + SecurityMethod: + enum: + - PSK + - PKI + - OAUTH + title: SecurityMethod + type: string + OAuthGrantType: + enum: + - CLIENT_CREDENTIALS + - AUTHORIZATION_CODE + - AUTHORIZATION_CODE_WITH_PKCE + title: OAuthGrantType + type: string + ShareableInformation: + example: + capifProvDoms: + - capifProvDoms + - capifProvDoms + isShareable: true + properties: + isShareable: + title: isShareable + type: boolean + capifProvDoms: + items: + type: string + title: capifProvDoms + type: array + required: + - isShareable + title: ShareableInformation + type: object + PublishedApiPath: + example: + ccfIds: + - ccfIds + - ccfIds + properties: + ccfIds: + items: + type: string + title: ccfIds + type: array + title: PublishedApiPath + type: object + AefLocation: + example: + dcId: dcId + properties: + dcId: + title: dcId + type: string + title: AefLocation + type: object + ServiceKpis: + example: + avalMem: avalMem + avalStor: avalStor + avalComp: avalComp + maxRestime: 1 + availability: 5 + maxReqRate: 6 + properties: + maxReqRate: + title: maxReqRate + type: integer + maxRestime: + title: maxRestime + type: integer + availability: + title: availability + type: integer + avalComp: + title: avalComp + type: string + avalMem: + title: avalMem + type: string + avalStor: + title: avalStor + type: string + title: ServiceKpis + type: object + IpAddrRange: + example: + ueIpv4AddrRanges: + - start: start + end: end + - start: start + end: end + properties: + ueIpv4AddrRanges: + items: + $ref: '#/components/schemas/IpAddrRange_ueIpv4AddrRanges_inner' + title: ueIpv4AddrRanges + type: array + title: IpAddrRange + type: object + Error: + example: + code: code + details: + key: "" + message: message + properties: + code: + title: code + type: string + message: + title: message + type: string + details: + additionalProperties: true + title: details + type: object + required: + - code + - message + title: Error + type: object + _rules_get_200_response: + example: + nextPageToken: nextPageToken + items: + - default_access: ALLOW + notes: notes + updatedBy: updatedBy + startsAt: 2000-01-23T04:56:07.000+00:00 + invokerExceptions: + invokerOnboardedByUser: + - invokerOnboardedByUser + - invokerOnboardedByUser + apiInvokerId: + - apiInvokerId + - apiInvokerId + providerSelector: + apiProviderId: + - apiProviderId + - apiProviderId + apiName: + - apiName + - apiName + createdByUser: createdByUser + aefId: + - aefId + - aefId + apiId: + - apiId + - apiId + ruleId: ruleId + endsAt: 2000-01-23T04:56:07.000+00:00 + enabled: true + updatedAt: 2000-01-23T04:56:07.000+00:00 + - default_access: ALLOW + notes: notes + updatedBy: updatedBy + startsAt: 2000-01-23T04:56:07.000+00:00 + invokerExceptions: + invokerOnboardedByUser: + - invokerOnboardedByUser + - invokerOnboardedByUser + apiInvokerId: + - apiInvokerId + - apiInvokerId + providerSelector: + apiProviderId: + - apiProviderId + - apiProviderId + apiName: + - apiName + - apiName + createdByUser: createdByUser + aefId: + - aefId + - aefId + apiId: + - apiId + - apiId + ruleId: ruleId + endsAt: 2000-01-23T04:56:07.000+00:00 + enabled: true + updatedAt: 2000-01-23T04:56:07.000+00:00 + properties: + items: + items: + $ref: '#/components/schemas/Rule' + title: items + type: array + nextPageToken: + title: nextPageToken + type: string + required: + - items + title: _rules_get_200_response + type: object + IpAddrRange_ueIpv4AddrRanges_inner: + example: + start: start + end: end + properties: + start: + title: start + type: string + end: + title: end + type: string + title: IpAddrRange_ueIpv4AddrRanges_inner + type: object diff --git a/services/helper/helper_service/services/visibility_control/typing_utils.py b/services/helper/helper_service/services/visibility_control/typing_utils.py new file mode 100644 index 00000000..74e3c913 --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/typing_utils.py @@ -0,0 +1,30 @@ +import sys + +if sys.version_info < (3, 7): + import typing + + def is_generic(klass): + """ Determine whether klass is a generic class """ + return type(klass) == typing.GenericMeta + + def is_dict(klass): + """ Determine whether klass is a Dict """ + return klass.__extra__ == dict + + def is_list(klass): + """ Determine whether klass is a List """ + return klass.__extra__ == list + +else: + + def is_generic(klass): + """ Determine whether klass is a generic class """ + return hasattr(klass, '__origin__') + + def is_dict(klass): + """ Determine whether klass is a Dict """ + return klass.__origin__ == dict + + def is_list(klass): + """ Determine whether klass is a List """ + return klass.__origin__ == list diff --git a/services/helper/helper_service/services/visibility_control/util.py b/services/helper/helper_service/services/visibility_control/util.py new file mode 100644 index 00000000..bc420a26 --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/util.py @@ -0,0 +1,147 @@ +import datetime + +import typing +from visibility_control import typing_utils + + +def _deserialize(data, klass): + """Deserializes dict, list, str into an object. + + :param data: dict, list or str. + :param klass: class literal, or string of class name. + + :return: object. + """ + if data is None: + return None + + if klass in (int, float, str, bool, bytearray): + return _deserialize_primitive(data, klass) + elif klass == object: + return _deserialize_object(data) + elif klass == datetime.date: + return deserialize_date(data) + elif klass == datetime.datetime: + return deserialize_datetime(data) + elif typing_utils.is_generic(klass): + if typing_utils.is_list(klass): + return _deserialize_list(data, klass.__args__[0]) + if typing_utils.is_dict(klass): + return _deserialize_dict(data, klass.__args__[1]) + else: + return deserialize_model(data, klass) + + +def _deserialize_primitive(data, klass): + """Deserializes to primitive type. + + :param data: data to deserialize. + :param klass: class literal. + + :return: int, long, float, str, bool. + :rtype: int | long | float | str | bool + """ + try: + value = klass(data) + except UnicodeEncodeError: + value = data + except TypeError: + value = data + return value + + +def _deserialize_object(value): + """Return an original value. + + :return: object. + """ + return value + + +def deserialize_date(string): + """Deserializes string to date. + + :param string: str. + :type string: str + :return: date. + :rtype: date + """ + if string is None: + return None + + try: + from dateutil.parser import parse + return parse(string).date() + except ImportError: + return string + + +def deserialize_datetime(string): + """Deserializes string to datetime. + + The string should be in iso8601 datetime format. + + :param string: str. + :type string: str + :return: datetime. + :rtype: datetime + """ + if string is None: + return None + + try: + from dateutil.parser import parse + return parse(string) + except ImportError: + return string + + +def deserialize_model(data, klass): + """Deserializes list or dict to model. + + :param data: dict, list. + :type data: dict | list + :param klass: class literal. + :return: model object. + """ + instance = klass() + + if not instance.openapi_types: + return data + + for attr, attr_type in instance.openapi_types.items(): + if data is not None \ + and instance.attribute_map[attr] in data \ + and isinstance(data, (list, dict)): + value = data[instance.attribute_map[attr]] + setattr(instance, attr, _deserialize(value, attr_type)) + + return instance + + +def _deserialize_list(data, boxed_type): + """Deserializes a list and its elements. + + :param data: list to deserialize. + :type data: list + :param boxed_type: class literal. + + :return: deserialized list. + :rtype: list + """ + return [_deserialize(sub_data, boxed_type) + for sub_data in data] + + +def _deserialize_dict(data, boxed_type): + """Deserializes a dict and its elements. + + :param data: dict to deserialize. + :type data: dict + :param boxed_type: class literal. + + :return: deserialized dict. + :rtype: dict + """ + return {k: _deserialize(v, boxed_type) + for k, v in data.items() } -- GitLab From 9320d11654bc997a3632488477dda9467c48359b Mon Sep 17 00:00:00 2001 From: "claudia.carballo" Date: Thu, 22 Jan 2026 19:35:00 +0100 Subject: [PATCH 02/14] fix: nginx routes and helper communication --- services/nginx/nginx.conf | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/services/nginx/nginx.conf b/services/nginx/nginx.conf index dfea48b8..4b543afe 100644 --- a/services/nginx/nginx.conf +++ b/services/nginx/nginx.conf @@ -1,6 +1,6 @@ worker_processes auto; -error_log /var/log/nginx/error.log ${LOG_LEVEL}; +error_log /var/log/nginx/error.log warn; pid /tmp/nginx.pid; events { @@ -183,6 +183,12 @@ http { proxy_pass http://helper:8080/; } + location /visibility-control/ { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_pass http://helper:8080/visibility-control/; + } } } -- GitLab From 060e2bf8d8a992001944758e90cfda9ef6a5bfef Mon Sep 17 00:00:00 2001 From: "claudia.carballo" Date: Fri, 23 Jan 2026 11:18:33 +0100 Subject: [PATCH 03/14] feat: add UTC date validation and rule timestamps to response (startsAt/updatedAt) --- .../core/visibility_control_core.py | 97 ++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) diff --git a/services/helper/helper_service/services/visibility_control/core/visibility_control_core.py b/services/helper/helper_service/services/visibility_control/core/visibility_control_core.py index 6d3af076..22e78f65 100644 --- a/services/helper/helper_service/services/visibility_control/core/visibility_control_core.py +++ b/services/helper/helper_service/services/visibility_control/core/visibility_control_core.py @@ -1,4 +1,5 @@ import uuid +from datetime import datetime, timezone from db.db import get_mongo from config import Config @@ -9,15 +10,72 @@ def get_all_rules(): rules = list(col.find({}, {"_id": 0})) return {"rules": rules}, 200 +# def create_new_rule(body): +# db = get_mongo() +# col = db.get_col_by_name("visibility_rules") + +# # Generamos el ruleId (Server generates it, según tu comentario) +# body['ruleId'] = str(uuid.uuid4()) + +# col.insert_one(body) +# body.pop('_id', None) +# return body, 201 + def create_new_rule(body): db = get_mongo() col = db.get_col_by_name("visibility_rules") - # Generamos el ruleId (Server generates it, según tu comentario) + # 1. Generate a unique ruleId body['ruleId'] = str(uuid.uuid4()) + # 2. Generate current timestamp in UTC ISO 8601 format with 'Z' + now = datetime.now(timezone.utc).isoformat().replace('+00:00', 'Z') + + # 3. Handle and validate 'startsAt' + if 'startsAt' not in body or not body['startsAt']: + # If not provided, default to current time + body['startsAt'] = now + else: + # If provided, validate ISO 8601 format + try: + datetime.fromisoformat(body['startsAt'].replace('Z', '+00:00')) + except ValueError: + return { + "title": "Bad Request", + "detail": "Invalid startsAt format. Please use ISO 8601 (e.g., 2026-01-23T10:00:00Z)" + }, 400 + + # 4. 'updatedAt' is always set to current time during creation + body['updatedAt'] = now + + # 5. Logic validation: endsAt must be greater than startsAt + if 'endsAt' in body and body['endsAt']: + try: + # Convert strings to datetime objects for comparison + start_dt = datetime.fromisoformat(body['startsAt'].replace('Z', '+00:00')) + end_dt = datetime.fromisoformat(body['endsAt'].replace('Z', '+00:00')) + + if end_dt <= start_dt: + return { + "title": "Bad Request", + "detail": "Validation Error: endsAt must be later than startsAt" + }, 400 + except ValueError: + return { + "title": "Bad Request", + "detail": "Invalid endsAt format." + }, 400 + + # 6. Set 'updatedBy' metadata from providerSelector + ps = body.get('providerSelector', {}) + body['updatedBy'] = ps.get('createdByUser', 'system') + + # Save to MongoDB col.insert_one(body) + + # Remove Mongo internal ID before returning the response body.pop('_id', None) + return body, 201 def get_rule_by_id(rule_id): @@ -36,9 +94,46 @@ def delete_rule_by_id(rule_id): return None, 204 return {"title": "Not Found", "detail": "Rule not found"}, 404 +# def update_rule_patch(rule_id, body): +# db = get_mongo() +# col = db.get_col_by_name("visibility_rules") +# col.update_one({"ruleId": rule_id}, {"$set": body}) +# updated_rule = col.find_one({"ruleId": rule_id}, {"_id": 0}) +# return updated_rule, 200 + def update_rule_patch(rule_id, body): db = get_mongo() col = db.get_col_by_name("visibility_rules") + + # Fetch existing rule for comparison + existing_rule = col.find_one({"ruleId": rule_id}) + if not existing_rule: + return {"title": "Not Found", "detail": "Rule not found"}, 404 + + # Always update 'updatedAt' timestamp + now = datetime.now(timezone.utc).isoformat().replace('+00:00', 'Z') + body['updatedAt'] = now + + # Re-validate date logic if dates are being modified + new_start = body.get('startsAt', existing_rule.get('startsAt')) + new_end = body.get('endsAt', existing_rule.get('endsAt')) + + if new_start and new_end: + try: + s = datetime.fromisoformat(new_start.replace('Z', '+00:00')) + e = datetime.fromisoformat(new_end.replace('Z', '+00:00')) + if e <= s: + return { + "title": "Bad Request", + "detail": "Validation Error: endsAt must be later than startsAt" + }, 400 + except ValueError: + return {"title": "Bad Request", "detail": "Invalid date format."}, 400 + + # Update metadata if user info is provided + if 'providerSelector' in body and 'createdByUser' in body['providerSelector']: + body['updatedBy'] = body['providerSelector']['createdByUser'] + col.update_one({"ruleId": rule_id}, {"$set": body}) updated_rule = col.find_one({"ruleId": rule_id}, {"_id": 0}) return updated_rule, 200 \ No newline at end of file -- GitLab From 8dfd230e895ef64efc318d2a2161b71f6f55f233 Mon Sep 17 00:00:00 2001 From: "claudia.carballo" Date: Mon, 26 Jan 2026 16:48:48 +0100 Subject: [PATCH 04/14] add client certificate validation and API authorization logic --- .../services/visibility_control/auth.py | 63 +++++++++++++++++ .../controllers/rules_controller.py | 11 ++- .../visibility_control/core/validate_user.py | 31 +++++++++ .../core/visibility_control_core.py | 69 +++++++++++++++++-- 4 files changed, 168 insertions(+), 6 deletions(-) create mode 100644 services/helper/helper_service/services/visibility_control/auth.py create mode 100644 services/helper/helper_service/services/visibility_control/core/validate_user.py diff --git a/services/helper/helper_service/services/visibility_control/auth.py b/services/helper/helper_service/services/visibility_control/auth.py new file mode 100644 index 00000000..20fcf423 --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/auth.py @@ -0,0 +1,63 @@ +from functools import wraps +from cryptography import x509 +from cryptography.hazmat.backends import default_backend +from flask import request +import connexion +#from ..core.validate_user import ControlAccess + +from visibility_control.core.validate_user import ControlAccess +valid_user = ControlAccess() + +def cert_validation(): + def _cert_validation(f): + @wraps(f) + def __cert_validation(*args, **kwargs): + # 1. Get certificate header safely + cert_tmp = request.headers.get('X-Ssl-Client-Cert') + + if not cert_tmp: + return {"title": "Unauthorized", "detail": "Certificate header missing"}, 401 + + try: + # 2. Process certificate + cert_raw = cert_tmp.replace('\\t', '') + cert = x509.load_pem_x509_certificate(str.encode(cert_raw), default_backend()) + cn = cert.subject.get_attributes_for_oid(x509.OID_COMMON_NAME)[0].value.strip() + + # 3. Store identity for the Core logic + request.user_cn = cn + request.cert_signature = cert.signature.hex() + + return f(**kwargs) + except Exception: + return {"title": "Unauthorized", "detail": "Invalid certificate format"}, 401 + return __cert_validation + return _cert_validation + +# def cert_validation(): +# def _cert_validation(f): +# @wraps(f) +# def __cert_validation(*args, **kwargs): +# # 1. Validación de existencia de certificado (Literal del ejemplo) +# cert_tmp = request.headers['X-Ssl-Client-Cert'] + +# cert_raw = cert_tmp.replace('\\t', '') +# cert = x509.load_pem_x509_certificate(str.encode(cert_raw), default_backend()) +# cn = cert.subject.get_attributes_for_oid(x509.OID_COMMON_NAME)[0].value.strip() + +# # Guardamos para que el Core los vea +# request.user_cn = cn +# request.cert_signature = cert.signature.hex() + +# if cn != "superadmin": +# cert_signature = cert.signature.hex() +# # Aquí, si hay un ID en la URL (como rule_id), podríamos validar. +# # Pero para el POST, como el ID está en el cuerpo, +# # simplemente dejamos que el Core lo gestione para no romper el wrap. + +# # Si quieres que el wrap sea universal, lo dejamos pasar tras validar el CN +# pass + +# return f(**kwargs) +# return __cert_validation +# return _cert_validation \ No newline at end of file diff --git a/services/helper/helper_service/services/visibility_control/controllers/rules_controller.py b/services/helper/helper_service/services/visibility_control/controllers/rules_controller.py index bc0a3014..07ac3cd4 100644 --- a/services/helper/helper_service/services/visibility_control/controllers/rules_controller.py +++ b/services/helper/helper_service/services/visibility_control/controllers/rules_controller.py @@ -1,7 +1,11 @@ import connexion from typing import Dict, Tuple, Union -# Importamos la lógica del CORE (Asegúrate de crear este archivo después) +#from ..auth import cert_validation + +from visibility_control.auth import cert_validation + +# Importamos la lógica del CORE from ..core.visibility_control_core import ( get_all_rules, create_new_rule, @@ -17,10 +21,12 @@ from visibility_control.models.rule_patch_request import RulePatchRequest from visibility_control.models.rules_get200_response import RulesGet200Response from visibility_control import util +@cert_validation() def rules_get(): """List rules""" return get_all_rules() +@cert_validation() def rules_post(body): """ Create a rule @@ -33,14 +39,17 @@ def rules_post(body): return Error(title="Bad Request", detail="JSON body required", status=400), 400 +@cert_validation() def rules_rule_id_delete(rule_id): """Delete a rule""" return delete_rule_by_id(rule_id) +@cert_validation() def rules_rule_id_get(rule_id): """Get a rule""" return get_rule_by_id(rule_id) +@cert_validation() def rules_rule_id_patch(rule_id, rule_patch_request): """Update a rule (partial)""" if connexion.request.is_json: diff --git a/services/helper/helper_service/services/visibility_control/core/validate_user.py b/services/helper/helper_service/services/visibility_control/core/validate_user.py new file mode 100644 index 00000000..750bb9d5 --- /dev/null +++ b/services/helper/helper_service/services/visibility_control/core/validate_user.py @@ -0,0 +1,31 @@ +import json +from flask import Response, current_app + +class Resource: + def __init__(self): + # We use the existing mongo helper from your service + from db.db import get_mongo + self.db = get_mongo() + +class ControlAccess(Resource): + def validate_user_cert(self, api_provider_id, cert_signature): + # Access the certificates collection in CAPIF database + cert_col = self.db.get_col_by_name("certs") + try: + # Check if provider_id matches the certificate signature + my_query = {'provider_id': api_provider_id} + cert_entry = cert_col.find_one(my_query) + + if cert_entry is not None: + if cert_entry["cert_signature"] != cert_signature: + # Return 401 if signatures don't match + prob = { + "title": "Unauthorized", + "detail": "User not authorized", + "cause": "You are not the owner of this resource" + } + return Response(json.dumps(prob), status=401, mimetype="application/json") + return None + except Exception as e: + current_app.logger.error("Error in validate_user_cert: " + str(e)) + return Response(json.dumps({"title": "Internal Server Error", "detail": str(e)}), status=500, mimetype="application/json") \ No newline at end of file diff --git a/services/helper/helper_service/services/visibility_control/core/visibility_control_core.py b/services/helper/helper_service/services/visibility_control/core/visibility_control_core.py index 22e78f65..894eb1d1 100644 --- a/services/helper/helper_service/services/visibility_control/core/visibility_control_core.py +++ b/services/helper/helper_service/services/visibility_control/core/visibility_control_core.py @@ -3,6 +3,11 @@ from datetime import datetime, timezone from db.db import get_mongo from config import Config +from flask import request +from visibility_control.core.validate_user import ControlAccess + +valid_user = ControlAccess() + def get_all_rules(): db = get_mongo() # Usamos la colección configurada en el helper @@ -24,6 +29,31 @@ def get_all_rules(): def create_new_rule(body): db = get_mongo() col = db.get_col_by_name("visibility_rules") + + # Get identity extracted by the decorator + cn = request.user_cn + cert_sig = request.cert_signature + + # Security check: If not superadmin, validate the mandatory identity + if cn != "superadmin": + ps = body.get('providerSelector', {}) + + # We check apiProviderId if it exists, but we focus on the mandatory identity + api_id = ps.get('apiProviderId', [None])[0] + created_by = ps.get('createdByUser') + + # Use the available ID to validate ownership via certificate signature + # We prioritize apiProviderId, then createdByUser as fallback for validation + user_to_validate = api_id if api_id else created_by + + if user_to_validate: + result = valid_user.validate_user_cert(user_to_validate, cert_sig) + if result is not None: + return result + else: + # If even createdByUser is missing (despite being mandatory in your logic), + # we block it or handle it as a Bad Request + return {"title": "Bad Request", "detail": "createdByUser is mandatory"}, 400 # 1. Generate a unique ruleId body['ruleId'] = str(uuid.uuid4()) @@ -67,8 +97,10 @@ def create_new_rule(body): }, 400 # 6. Set 'updatedBy' metadata from providerSelector - ps = body.get('providerSelector', {}) - body['updatedBy'] = ps.get('createdByUser', 'system') + # ps = body.get('providerSelector', {}) + # body['updatedBy'] = ps.get('createdByUser', 'system') + # This prevents a user from putting "User_A" in the JSON while using "User_B" certificate + body['updatedBy'] = cn # Save to MongoDB col.insert_one(body) @@ -82,16 +114,39 @@ def get_rule_by_id(rule_id): db = get_mongo() col = db.get_col_by_name("visibility_rules") rule = col.find_one({"ruleId": rule_id}, {"_id": 0}) - if rule: - return rule, 200 - return {"title": "Not Found", "detail": "Rule not found"}, 404 + # if rule: + # return rule, 200 + # return {"title": "Not Found", "detail": "Rule not found"}, 404 + if not rule: + return {"title": "Not Found", "detail": "Rule not found"}, 404 + + # SECURITY CHECK: Only Superadmin or the actual owner (CN) can view + if request.user_cn != "superadmin" and rule.get('updatedBy') != request.user_cn: + return {"title": "Unauthorized", "detail": "You do not have permission to view this rule"}, 401 + + rule.pop('_id', None) + return rule, 200 def delete_rule_by_id(rule_id): db = get_mongo() col = db.get_col_by_name("visibility_rules") + # 1. Fetch the rule first to check ownership + rule = col.find_one({"ruleId": rule_id}) + if not rule: + return {"title": "Not Found", "detail": "Rule not found"}, 404 + + # 2. SECURITY CHECK: Only Superadmin or the actual owner (CN) can delete + # We compare the current certificate CN against the stored 'updatedBy' + if request.user_cn != "superadmin" and rule.get('updatedBy') != request.user_cn: + return {"title": "Unauthorized", "detail": "You do not have permission to delete this rule"}, 401 + + # 3. Perform the actual deletion res = col.delete_one({"ruleId": rule_id}) + + # 4. Final check on the operation result if res.deleted_count > 0: return None, 204 + return {"title": "Not Found", "detail": "Rule not found"}, 404 # def update_rule_patch(rule_id, body): @@ -109,6 +164,10 @@ def update_rule_patch(rule_id, body): existing_rule = col.find_one({"ruleId": rule_id}) if not existing_rule: return {"title": "Not Found", "detail": "Rule not found"}, 404 + + # SECURITY CHECK: Only Superadmin or the actual owner (CN) can update + if request.user_cn != "superadmin" and existing_rule.get('updatedBy') != request.user_cn: + return {"title": "Unauthorized", "detail": "You do not have permission to modify this rule"}, 401 # Always update 'updatedAt' timestamp now = datetime.now(timezone.utc).isoformat().replace('+00:00', 'Z') -- GitLab From 3cdde44c43faad59195f4e92f8ade654054711b9 Mon Sep 17 00:00:00 2001 From: "claudia.carballo" Date: Mon, 26 Jan 2026 16:56:26 +0100 Subject: [PATCH 05/14] changes on the openapi name and description --- .../services/visibility_control/openapi/openapi.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/services/helper/helper_service/services/visibility_control/openapi/openapi.yaml b/services/helper/helper_service/services/visibility_control/openapi/openapi.yaml index eeaeafcc..12953fd1 100644 --- a/services/helper/helper_service/services/visibility_control/openapi/openapi.yaml +++ b/services/helper/helper_service/services/visibility_control/openapi/openapi.yaml @@ -1,13 +1,13 @@ openapi: 3.0.3 info: description: | - Access-control API to manage visibility rules and evaluate decisions for API discovery and + Visibility control API manages visibility rules and evaluate decisions for API discovery and security-context access within OpenCAPIF. This API controls whether APIs are visible to invokers (discovery) and whether invokers are allowed to create a security context to access them. - Rules are global and evaluated with "more specific wins" precedence. - If no rule matches, the decision uses OpenCAPIF's global default (outside this API). - - Provider selector is mandatory in rules and must contain at least one selector field. - title: OpenCAPIF Access Control + - Provider selector is mandatory in rules and must contain at least one selector field (createdByUser is mandatory). + title: OpenCAPIF Visibility Control version: 1.0.0 servers: - description: Production -- GitLab From 05728e3817563068105eccc79fb3d7907b5cd0f0 Mon Sep 17 00:00:00 2001 From: Jorge Moratinos Salcines Date: Tue, 3 Feb 2026 15:36:29 +0100 Subject: [PATCH 06/14] New tests and some minor fixes over helper new api and nginx --- .../visibility_control/openapi/openapi.yaml | 14 ++- services/nginx/nginx.conf | 21 ++-- .../features/Helper/visibility_control.robot | 96 +++++++++++++++++++ tests/libraries/bodyRequests.py | 1 + .../libraries/helper_service/bodyRequests.py | 28 ++++++ tests/resources/common/basicRequests.robot | 2 +- 6 files changed, 147 insertions(+), 15 deletions(-) create mode 100644 tests/features/Helper/visibility_control.robot create mode 100644 tests/libraries/helper_service/bodyRequests.py diff --git a/services/helper/helper_service/services/visibility_control/openapi/openapi.yaml b/services/helper/helper_service/services/visibility_control/openapi/openapi.yaml index 12953fd1..76ed307b 100644 --- a/services/helper/helper_service/services/visibility_control/openapi/openapi.yaml +++ b/services/helper/helper_service/services/visibility_control/openapi/openapi.yaml @@ -9,11 +9,17 @@ info: - Provider selector is mandatory in rules and must contain at least one selector field (createdByUser is mandatory). title: OpenCAPIF Visibility Control version: 1.0.0 +# servers: +# - description: Production +# url: https://capif.example.com/access-control +# - description: Sandbox +# url: https://sandbox.capif.example.com/access-control servers: -- description: Production - url: https://capif.example.com/access-control -- description: Sandbox - url: https://sandbox.capif.example.com/access-control +- url: "{apiRoot}/visibility-control" + variables: + apiRoot: + default: http://localhost:8080 + description: Base URL of the Helper service. tags: - description: Manage visibility rules name: Rules diff --git a/services/nginx/nginx.conf b/services/nginx/nginx.conf index 4b543afe..33260144 100644 --- a/services/nginx/nginx.conf +++ b/services/nginx/nginx.conf @@ -14,7 +14,7 @@ http { } map "$request_method:$uri:$ssl_client_s_dn_cn" $helper_error_message { default 'SUCCESS'; - "~*(GET|DELETE):.*:(?!(superadmin))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be superadmin"}'; + "~*(GET|DELETE|POST):.*:(?!(superadmin))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be superadmin"}'; } map "$request_method:$uri:$ssl_client_s_dn_cn" $invoker_error_message { default 'SUCCESS'; @@ -177,18 +177,19 @@ http { add_header Content-Type 'application/problem+json'; return 401 $helper_error_message; } - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + # proxy_set_header Host $host; + # proxy_set_header X-Real-IP $remote_addr; + # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-SSL-Client-Cert $ssl_client_cert; proxy_pass http://helper:8080/; } - location /visibility-control/ { - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_pass http://helper:8080/visibility-control/; - } + # location /visibility-control/ { + # proxy_set_header Host $host; + # proxy_set_header X-Real-IP $remote_addr; + # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + # proxy_pass http://helper:8080/visibility-control/; + # } } } diff --git a/tests/features/Helper/visibility_control.robot b/tests/features/Helper/visibility_control.robot new file mode 100644 index 00000000..24e05e55 --- /dev/null +++ b/tests/features/Helper/visibility_control.robot @@ -0,0 +1,96 @@ +*** Settings *** +Resource /opt/robot-tests/tests/resources/common.resource +Library /opt/robot-tests/tests/libraries/bodyRequests.py +Library XML +Library String +Resource /opt/robot-tests/tests/resources/common/basicRequests.robot +Resource ../../resources/common.resource +Resource ../../resources/common/basicRequests.robot + +Suite Teardown Reset Testing Environment +Test Setup Reset Testing Environment +Test Teardown Reset Testing Environment + + +*** Variables *** +${API_INVOKER_NOT_REGISTERED} not-valid +${SUBSCRIBER_ID_NOT_VALID} not-valid +${SUBSCRIPTION_ID_NOT_VALID} not-valid + + +*** Test Cases *** +Get Visibility Control Rules as Superadmin + [Tags] visibility_control_1 + + ${resp}= Get Request Capif + ... /helper/visibility-control/rules + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${SUPERADMIN_USERNAME} + + Length Should Be ${resp.json()['rules']} 0 + +Create Visibility Control Rule Invalid Dates as Superadmin + [Tags] visibility_control_2 + + ${body}= Create Visibility Control Rule Body Invalid Dates + + ${resp}= Post Request Capif + ... /helper/visibility-control/rules + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${SUPERADMIN_USERNAME} + ... json=${body} + + Status Should Be ${resp} 400 + +Create Visibility Control Rule + [Tags] visibility_control_3 + ${body}= Create Visibility Control Rule Body + + ${resp}= Post Request Capif + ... /helper/visibility-control/rules + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${SUPERADMIN_USERNAME} + ... json=${body} + + ${rule_id}= Set Variable ${resp.json()['ruleId']} + + ${resp}= Get Request Capif + ... /helper/visibility-control/rules + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${SUPERADMIN_USERNAME} + + Length Should Be ${resp.json()['rules']} 1 + + ${resp}= Delete Request Capif + ... /helper/visibility-control/rules/${rule_id} + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${SUPERADMIN_USERNAME} + + ${resp}= Get Request Capif + ... /helper/visibility-control/rules + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${SUPERADMIN_USERNAME} + + Length Should Be ${resp.json()['rules']} 0 + +Create Visibility Control Rule by Provider + [Tags] visibility_control_4 + + ${register_user_info}= Provider Default Registration + + ${body}= Create Visibility Control Rule Body + + ${resp}= Post Request Capif + ... /helper/visibility-control/rules + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${AMF_PROVIDER_USERNAME} + ... json=${body} + + diff --git a/tests/libraries/bodyRequests.py b/tests/libraries/bodyRequests.py index 450ca5ae..cc909bcd 100644 --- a/tests/libraries/bodyRequests.py +++ b/tests/libraries/bodyRequests.py @@ -7,3 +7,4 @@ from security_api.bodyRequests import * from api_provider_management.bodyRequests import * from vendor_extensibility.bodyRequests import * from vault_requests.bodyRequests import * +from helper_service.bodyRequests import * diff --git a/tests/libraries/helper_service/bodyRequests.py b/tests/libraries/helper_service/bodyRequests.py new file mode 100644 index 00000000..6f3cdc50 --- /dev/null +++ b/tests/libraries/helper_service/bodyRequests.py @@ -0,0 +1,28 @@ +def create_visibility_control_rule_body_invalid_dates(): + return { + "default_access": "ALLOW", + "enabled": True, + "startsAt": "2026-01-23T12:00:00Z", + "endsAt": "2025-01-23T08:00:00Z", + "providerSelector": { + "apiName": ["api-test-error"], + "createdByUser": "claudia" + } + } + + +def create_visibility_control_rule_body(): + return { + "default_access": "ALLOW", + "enabled": True, + "invokerExceptions": { + "apiInvokerId": ["invk-X77"] + }, + "providerSelector": { + "aefId": ["aef-002"], + "apiId": ["apiId-999"], + "apiName": ["api-test-cli"], + "apiProviderId": ["capif-prov-01"], + "createdByUser": "claudia" + } + } diff --git a/tests/resources/common/basicRequests.robot b/tests/resources/common/basicRequests.robot index b1b350e2..e02a9c93 100644 --- a/tests/resources/common/basicRequests.robot +++ b/tests/resources/common/basicRequests.robot @@ -970,7 +970,7 @@ Get Number Of Services Get Capif Ccf Id ${resp}= Get Request Capif - ... /helper/getCcfId + ... /helper/api/getCcfId ... server=${CAPIF_HTTPS_URL} ... verify=ca.crt ... username=${SUPERADMIN_USERNAME} -- GitLab From 28aa9989491382b2b47ad542de31e060ad34e379 Mon Sep 17 00:00:00 2001 From: Jorge Moratinos Salcines Date: Tue, 3 Feb 2026 15:52:54 +0100 Subject: [PATCH 07/14] Minor fix nginx.conf and visibility tests --- services/nginx/nginx.conf | 2 +- .../features/Helper/visibility_control.robot | 27 +++++++++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/services/nginx/nginx.conf b/services/nginx/nginx.conf index 33260144..9fbe7031 100644 --- a/services/nginx/nginx.conf +++ b/services/nginx/nginx.conf @@ -14,7 +14,7 @@ http { } map "$request_method:$uri:$ssl_client_s_dn_cn" $helper_error_message { default 'SUCCESS'; - "~*(GET|DELETE|POST):.*:(?!(superadmin))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be superadmin"}'; + "~*(GET|DELETE|POST):.*:(?!(superadmin|AMF))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be superadmin"}'; } map "$request_method:$uri:$ssl_client_s_dn_cn" $invoker_error_message { default 'SUCCESS'; diff --git a/tests/features/Helper/visibility_control.robot b/tests/features/Helper/visibility_control.robot index 24e05e55..8253eafa 100644 --- a/tests/features/Helper/visibility_control.robot +++ b/tests/features/Helper/visibility_control.robot @@ -42,7 +42,7 @@ Create Visibility Control Rule Invalid Dates as Superadmin ... username=${SUPERADMIN_USERNAME} ... json=${body} - Status Should Be ${resp} 400 + Status Should Be 400 ${resp} Create Visibility Control Rule [Tags] visibility_control_3 @@ -79,9 +79,22 @@ Create Visibility Control Rule Length Should Be ${resp.json()['rules']} 0 -Create Visibility Control Rule by Provider +Get Visibility Control Rule by AMF Provider [Tags] visibility_control_4 + ${register_user_info}= Provider Default Registration + + ${resp}= Get Request Capif + ... /helper/visibility-control/rules + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${AMF_PROVIDER_USERNAME} + + Status Should Be 200 ${resp} + +Create Visibility Control Rule by AMF Provider + [Tags] visibility_control_5 + ${register_user_info}= Provider Default Registration ${body}= Create Visibility Control Rule Body @@ -93,4 +106,14 @@ Create Visibility Control Rule by Provider ... username=${AMF_PROVIDER_USERNAME} ... json=${body} + Status Should Be 201 ${resp} + + ${rule_id}= Set Variable ${resp.json()['ruleId']} + + ${resp}= Delete Request Capif + ... /helper/visibility-control/rules/${rule_id} + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${SUPERADMIN_USERNAME} + -- GitLab From 61041929c97d2d4472b0a3fa6392678d5db33c45 Mon Sep 17 00:00:00 2001 From: Jorge Moratinos Salcines Date: Tue, 3 Feb 2026 16:26:30 +0100 Subject: [PATCH 08/14] Improvement of testing organization --- tests/features/Helper/Control Api/__init__.robot | 2 ++ .../features/Helper/{helper.robot => Control Api/api.robot} | 6 +++--- tests/features/Helper/Visibility Control Api/__init__.robot | 2 ++ .../{ => Visibility Control Api}/visibility_control.robot | 4 ++-- 4 files changed, 9 insertions(+), 5 deletions(-) create mode 100644 tests/features/Helper/Control Api/__init__.robot rename tests/features/Helper/{helper.robot => Control Api/api.robot} (80%) create mode 100644 tests/features/Helper/Visibility Control Api/__init__.robot rename tests/features/Helper/{ => Visibility Control Api}/visibility_control.robot (95%) diff --git a/tests/features/Helper/Control Api/__init__.robot b/tests/features/Helper/Control Api/__init__.robot new file mode 100644 index 00000000..f9d8bb13 --- /dev/null +++ b/tests/features/Helper/Control Api/__init__.robot @@ -0,0 +1,2 @@ +*** Settings *** +Force Tags api \ No newline at end of file diff --git a/tests/features/Helper/helper.robot b/tests/features/Helper/Control Api/api.robot similarity index 80% rename from tests/features/Helper/helper.robot rename to tests/features/Helper/Control Api/api.robot index b9f8300d..cf7101c9 100644 --- a/tests/features/Helper/helper.robot +++ b/tests/features/Helper/Control Api/api.robot @@ -4,8 +4,8 @@ Library /opt/robot-tests/tests/libraries/bodyRequests.py Library XML Library String Resource /opt/robot-tests/tests/resources/common/basicRequests.robot -Resource ../../resources/common.resource -Resource ../../resources/common/basicRequests.robot +Resource /opt/robot-tests/tests/resources/common.resource +Resource /opt/robot-tests/tests/resources/common/basicRequests.robot Suite Teardown Reset Testing Environment Test Setup Reset Testing Environment @@ -20,7 +20,7 @@ ${SUBSCRIPTION_ID_NOT_VALID} not-valid *** Test Cases *** Obtain ccfId - [Tags] helper_1 smoke + [Tags] api_1 smoke ${ccfId}= Get Capif Ccf Id diff --git a/tests/features/Helper/Visibility Control Api/__init__.robot b/tests/features/Helper/Visibility Control Api/__init__.robot new file mode 100644 index 00000000..18227ad2 --- /dev/null +++ b/tests/features/Helper/Visibility Control Api/__init__.robot @@ -0,0 +1,2 @@ +*** Settings *** +Force Tags visibility_control \ No newline at end of file diff --git a/tests/features/Helper/visibility_control.robot b/tests/features/Helper/Visibility Control Api/visibility_control.robot similarity index 95% rename from tests/features/Helper/visibility_control.robot rename to tests/features/Helper/Visibility Control Api/visibility_control.robot index 8253eafa..bcf688c7 100644 --- a/tests/features/Helper/visibility_control.robot +++ b/tests/features/Helper/Visibility Control Api/visibility_control.robot @@ -4,8 +4,8 @@ Library /opt/robot-tests/tests/libraries/bodyRequests.py Library XML Library String Resource /opt/robot-tests/tests/resources/common/basicRequests.robot -Resource ../../resources/common.resource -Resource ../../resources/common/basicRequests.robot +Resource /opt/robot-tests/tests/resources/common.resource +Resource /opt/robot-tests/tests/resources/common/basicRequests.robot Suite Teardown Reset Testing Environment Test Setup Reset Testing Environment -- GitLab From 46699bd8e4ef622c3f448c366be1943b1de8d7af Mon Sep 17 00:00:00 2001 From: "claudia.carballo" Date: Mon, 9 Feb 2026 18:01:21 +0100 Subject: [PATCH 09/14] improving visibility control logic (authorization) and adding new tests --- .gitignore | 6 +- .../openapi_helper_visibility_control.yaml | 6 +- .../services/visibility_control/auth.py | 27 -- .../core/visibility_control_core.py | 284 ++++++++++++++---- .../visibility_control/openapi/openapi.yaml | 20 +- .../visibility_control.robot | 73 ++++- .../libraries/helper_service/bodyRequests.py | 4 +- 7 files changed, 320 insertions(+), 100 deletions(-) diff --git a/.gitignore b/.gitignore index ddc84e3d..c7737031 100644 --- a/.gitignore +++ b/.gitignore @@ -37,4 +37,8 @@ results helm/capif/*.lock helm/capif/charts/tempo* -*.bak \ No newline at end of file +*.bakresults/ +.venv/ +tests/features/Helper/Visibility Control Api/*.html +tests/features/Helper/Visibility Control Api/*.xml +*.bak diff --git a/services/helper/helper_service/openapi_helper_visibility_control.yaml b/services/helper/helper_service/openapi_helper_visibility_control.yaml index 4d386230..fc4817e7 100644 --- a/services/helper/helper_service/openapi_helper_visibility_control.yaml +++ b/services/helper/helper_service/openapi_helper_visibility_control.yaml @@ -55,7 +55,7 @@ paths: allow_except_some_invokers: value: providerSelector: - createdByUser: "userA" + userName: "userA" apiProviderId: [ "capif-prov-01", "capif-prov-02" ] apiName: [ "apiName-001" ] apiId: [ "apiId-001" ] @@ -293,9 +293,9 @@ components: Provider-side selector. Arrays apply OR within the field; AND across fields. At least one of these fields must be present. required: - - createdByUser + - userName properties: - createdByUser: + userName: type: string minLength: 1 apiProviderId: diff --git a/services/helper/helper_service/services/visibility_control/auth.py b/services/helper/helper_service/services/visibility_control/auth.py index 20fcf423..de01e3c0 100644 --- a/services/helper/helper_service/services/visibility_control/auth.py +++ b/services/helper/helper_service/services/visibility_control/auth.py @@ -34,30 +34,3 @@ def cert_validation(): return __cert_validation return _cert_validation -# def cert_validation(): -# def _cert_validation(f): -# @wraps(f) -# def __cert_validation(*args, **kwargs): -# # 1. Validación de existencia de certificado (Literal del ejemplo) -# cert_tmp = request.headers['X-Ssl-Client-Cert'] - -# cert_raw = cert_tmp.replace('\\t', '') -# cert = x509.load_pem_x509_certificate(str.encode(cert_raw), default_backend()) -# cn = cert.subject.get_attributes_for_oid(x509.OID_COMMON_NAME)[0].value.strip() - -# # Guardamos para que el Core los vea -# request.user_cn = cn -# request.cert_signature = cert.signature.hex() - -# if cn != "superadmin": -# cert_signature = cert.signature.hex() -# # Aquí, si hay un ID en la URL (como rule_id), podríamos validar. -# # Pero para el POST, como el ID está en el cuerpo, -# # simplemente dejamos que el Core lo gestione para no romper el wrap. - -# # Si quieres que el wrap sea universal, lo dejamos pasar tras validar el CN -# pass - -# return f(**kwargs) -# return __cert_validation -# return _cert_validation \ No newline at end of file diff --git a/services/helper/helper_service/services/visibility_control/core/visibility_control_core.py b/services/helper/helper_service/services/visibility_control/core/visibility_control_core.py index 894eb1d1..14ad7a09 100644 --- a/services/helper/helper_service/services/visibility_control/core/visibility_control_core.py +++ b/services/helper/helper_service/services/visibility_control/core/visibility_control_core.py @@ -8,23 +8,63 @@ from visibility_control.core.validate_user import ControlAccess valid_user = ControlAccess() +# def get_all_rules(): +# db = get_mongo() +# # Usamos la colección configurada en el helper +# col = db.get_col_by_name("visibility_rules") +# rules = list(col.find({}, {"_id": 0})) +# return {"rules": rules}, 200 + +# def get_all_rules(): +# """ +# Retrieve visibility rules. +# - If superadmin: Returns all rules without filtering. +# - If provider: Returns only rules matching the certificate identity (CN). +# """ +# db = get_mongo() +# col = db.get_col_by_name("visibility_rules") + +# # Safely retrieve identity from request object +# cn = request.user_cn + +# # Professional logic tree: +# # 1. Bypass security filters for Superadmin +# if cn != "superadmin": +# rules = list(col.find({"userName": cn}, {"_id": 0})) +# return {"rules": rules}, 200 + +# rules = list(col.find({}, {"_id": 0})) +# return {"rules": rules}, 200 + def get_all_rules(): db = get_mongo() - # Usamos la colección configurada en el helper col = db.get_col_by_name("visibility_rules") - rules = list(col.find({}, {"_id": 0})) - return {"rules": rules}, 200 + + # The ID from the certificate (e.g., AMFe9d24...) + cn = getattr(request, 'user_cn', None) -# def create_new_rule(body): -# db = get_mongo() -# col = db.get_col_by_name("visibility_rules") + # 1. Superadmin: No filters, returns everything + if cn != "superadmin": + # We look into CAPIF's provider registration to find the friendly name + # assigned to this specific Certificate ID (CN) + prov_col = db.get_col_by_name("provider_details") + provider = prov_col.find_one({"apiProvFuncs.apiProvFuncId": cn}) + + friendly_name = provider.get('userName') if provider else None + + # The query uses an $or operator to ensure visibility: + # - Rules where I am the owner (friendly_name) + # - Rules I created or updated myself (cn) + query_conditions = [{"updatedBy": cn}] + if friendly_name: + query_conditions.append({"providerSelector.userName": friendly_name}) + + rules = list(col.find({"$or": query_conditions}, {"_id": 0})) + return {"rules": rules}, 200 -# # Generamos el ruleId (Server generates it, según tu comentario) -# body['ruleId'] = str(uuid.uuid4()) + rules = list(col.find({}, {"_id": 0})) + return {"rules": rules}, 200 -# col.insert_one(body) -# body.pop('_id', None) -# return body, 201 def create_new_rule(body): db = get_mongo() @@ -40,20 +80,20 @@ def create_new_rule(body): # We check apiProviderId if it exists, but we focus on the mandatory identity api_id = ps.get('apiProviderId', [None])[0] - created_by = ps.get('createdByUser') + user_name = ps.get('userName') # Use the available ID to validate ownership via certificate signature - # We prioritize apiProviderId, then createdByUser as fallback for validation - user_to_validate = api_id if api_id else created_by + # We prioritize apiProviderId, then userName as fallback for validation + user_to_validate = api_id if api_id else user_name if user_to_validate: result = valid_user.validate_user_cert(user_to_validate, cert_sig) if result is not None: return result else: - # If even createdByUser is missing (despite being mandatory in your logic), + # If even userName is missing (despite being mandatory in your logic), # we block it or handle it as a Bad Request - return {"title": "Bad Request", "detail": "createdByUser is mandatory"}, 400 + return {"title": "Bad Request", "detail": "userName is mandatory"}, 400 # 1. Generate a unique ruleId body['ruleId'] = str(uuid.uuid4()) @@ -95,11 +135,8 @@ def create_new_rule(body): "title": "Bad Request", "detail": "Invalid endsAt format." }, 400 - - # 6. Set 'updatedBy' metadata from providerSelector - # ps = body.get('providerSelector', {}) - # body['updatedBy'] = ps.get('createdByUser', 'system') - # This prevents a user from putting "User_A" in the JSON while using "User_B" certificate + + body['createdBy'] = cn body['updatedBy'] = cn # Save to MongoDB @@ -111,69 +148,214 @@ def create_new_rule(body): return body, 201 def get_rule_by_id(rule_id): + """ + Retrieve a specific visibility rule by its ID. + - Superadmin: Can view any rule. + - Providers: Can view rules they own (userName) or created (updatedBy). + """ db = get_mongo() col = db.get_col_by_name("visibility_rules") + cn = request.user_cn + + # 1. Fetch the rule from the database + # We exclude the MongoDB internal _id field immediately rule = col.find_one({"ruleId": rule_id}, {"_id": 0}) - # if rule: - # return rule, 200 - # return {"title": "Not Found", "detail": "Rule not found"}, 404 + if not rule: return {"title": "Not Found", "detail": "Rule not found"}, 404 - # SECURITY CHECK: Only Superadmin or the actual owner (CN) can view - if request.user_cn != "superadmin" and rule.get('updatedBy') != request.user_cn: - return {"title": "Unauthorized", "detail": "You do not have permission to view this rule"}, 401 + # 2. Authorization Check: Superadmin bypass + if cn == "superadmin": + return rule, 200 + + # 3. Identity Translation for Providers + # Link the certificate CN to the registered Friendly Username + prov_col = db.get_col_by_name("provider_details") + provider = prov_col.find_one({"apiProvFuncs.apiProvFuncId": cn}) + friendly_name = provider.get('userName') if provider else None + + # 4. Permission Validation + # is_owner: Checks the logical owner in the rule (userName) + # is_creator: Checks the cryptographic signer (updatedBy) + is_owner = rule.get('providerSelector', {}).get('userName') == friendly_name + is_creator = rule.get('updatedBy') == cn + + if is_owner or is_creator: + return rule, 200 + + # 5. Deny access if the requester is neither the owner nor the creator + return { + "title": "Unauthorized", + "detail": "You do not have permission to view this rule" + }, 401 + +# def get_rule_by_id(rule_id): +# db = get_mongo() +# col = db.get_col_by_name("visibility_rules") +# cn = request.user_cn +# rule = col.find_one({"ruleId": rule_id}, {"_id": 0}) +# # if rule: +# # return rule, 200 +# # return {"title": "Not Found", "detail": "Rule not found"}, 404 +# if not rule: +# return {"title": "Not Found", "detail": "Rule not found"}, 404 + +# # SECURITY CHECK: Only Superadmin or the actual owner (CN) can view +# if request.user_cn != "superadmin" and rule.get('updatedBy') != request.user_cn: +# return {"title": "Unauthorized", "detail": "You do not have permission to view this rule"}, 401 - rule.pop('_id', None) - return rule, 200 +# rule.pop('_id', None) +# return rule, 200 + +# def delete_rule_by_id(rule_id): +# db = get_mongo() +# col = db.get_col_by_name("visibility_rules") +# cn = request.user_cn +# # 1. Fetch the rule first to check ownership +# rule = col.find_one({"ruleId": rule_id}) +# if not rule: +# return {"title": "Not Found", "detail": "Rule not found"}, 404 + +# # 2. SECURITY CHECK: Only Superadmin or the actual owner (CN) can delete +# # We compare the current certificate CN against the stored 'updatedBy' +# if request.user_cn != "superadmin" and rule.get('userName') != request.user_cn: +# return {"title": "Unauthorized", "detail": "You do not have permission to delete this rule"}, 401 + +# # 3. Perform the actual deletion +# res = col.delete_one({"ruleId": rule_id}) + +# # 4. Final check on the operation result +# if res.deleted_count > 0: +# return None, 204 + +# return {"title": "Not Found", "detail": "Rule not found"}, 404 def delete_rule_by_id(rule_id): + """ + Delete a specific visibility rule after verifying ownership. + - Superadmin: Can delete any rule. + - Providers: Can only delete rules assigned to them or created by them. + """ db = get_mongo() col = db.get_col_by_name("visibility_rules") - # 1. Fetch the rule first to check ownership + cn = request.user_cn + + # 1. Retrieve the rule to check metadata rule = col.find_one({"ruleId": rule_id}) if not rule: return {"title": "Not Found", "detail": "Rule not found"}, 404 - # 2. SECURITY CHECK: Only Superadmin or the actual owner (CN) can delete - # We compare the current certificate CN against the stored 'updatedBy' - if request.user_cn != "superadmin" and rule.get('updatedBy') != request.user_cn: - return {"title": "Unauthorized", "detail": "You do not have permission to delete this rule"}, 401 + # 2. Authorization Check: Superadmin bypass + if cn == "superadmin": + col.delete_one({"ruleId": rule_id}) + return None, 204 + + # 3. Identity Translation for Providers + # Resolve the certificate ID to the registered friendly username + prov_col = db.get_col_by_name("provider_details") + provider = prov_col.find_one({"apiProvFuncs.apiProvFuncId": cn}) + friendly_name = provider.get('userName') if provider else None + + # 4. Permissions Validation + # is_owner: Checks if the rule's userName matches the provider's registered name. + # is_creator: Checks if the rule was signed by the current certificate ID. + is_owner = rule.get('providerSelector', {}).get('userName') == friendly_name + is_creator = rule.get('updatedBy') == cn - # 3. Perform the actual deletion - res = col.delete_one({"ruleId": rule_id}) + if is_owner or is_creator: + res = col.delete_one({"ruleId": rule_id}) + if res.deleted_count > 0: + return None, 204 - # 4. Final check on the operation result - if res.deleted_count > 0: - return None, 204 - - return {"title": "Not Found", "detail": "Rule not found"}, 404 + # 5. Deny access if no ownership is proven + return { + "title": "Unauthorized", + "detail": "You do not have permission to delete this rule" + }, 401 # def update_rule_patch(rule_id, body): # db = get_mongo() # col = db.get_col_by_name("visibility_rules") +# cn = request.user_cn +# # Fetch existing rule for comparison +# existing_rule = col.find_one({"ruleId": rule_id}) +# if not existing_rule: +# return {"title": "Not Found", "detail": "Rule not found"}, 404 + +# # SECURITY CHECK: Only Superadmin or the actual owner (CN) can update +# if request.user_cn != "superadmin" and existing_rule.get('userName') != request.user_cn: +# return {"title": "Unauthorized", "detail": "You do not have permission to modify this rule"}, 401 + +# # Always update 'updatedAt' timestamp +# now = datetime.now(timezone.utc).isoformat().replace('+00:00', 'Z') +# body['updatedAt'] = now + +# # Re-validate date logic if dates are being modified +# new_start = body.get('startsAt', existing_rule.get('startsAt')) +# new_end = body.get('endsAt', existing_rule.get('endsAt')) + +# if new_start and new_end: +# try: +# s = datetime.fromisoformat(new_start.replace('Z', '+00:00')) +# e = datetime.fromisoformat(new_end.replace('Z', '+00:00')) +# if e <= s: +# return { +# "title": "Bad Request", +# "detail": "Validation Error: endsAt must be later than startsAt" +# }, 400 +# except ValueError: +# return {"title": "Bad Request", "detail": "Invalid date format."}, 400 + +# # # Update metadata if user info is provided +# # if 'providerSelector' in body and 'createdByUser' in body['providerSelector']: +# # body['updatedBy'] = body['providerSelector']['createdByUser'] +# body['updatedBy'] = cn + # col.update_one({"ruleId": rule_id}, {"$set": body}) # updated_rule = col.find_one({"ruleId": rule_id}, {"_id": 0}) # return updated_rule, 200 def update_rule_patch(rule_id, body): + """ + Update a specific visibility rule using PATCH logic. + - Superadmin: Can modify any rule. + - Providers: Can only modify rules they own or created. + """ db = get_mongo() col = db.get_col_by_name("visibility_rules") + cn = request.user_cn - # Fetch existing rule for comparison + # 1. Fetch existing rule to verify existence and check ownership existing_rule = col.find_one({"ruleId": rule_id}) if not existing_rule: return {"title": "Not Found", "detail": "Rule not found"}, 404 - # SECURITY CHECK: Only Superadmin or the actual owner (CN) can update - if request.user_cn != "superadmin" and existing_rule.get('updatedBy') != request.user_cn: - return {"title": "Unauthorized", "detail": "You do not have permission to modify this rule"}, 401 + # 2. Authorization Check: Superadmin bypass + if cn != "superadmin": + # Resolve Certificate CN to the registered Friendly Username + prov_col = db.get_col_by_name("provider_details") + provider = prov_col.find_one({"apiProvFuncs.apiProvFuncId": cn}) + friendly_name = provider.get('userName') if provider else None - # Always update 'updatedAt' timestamp + # Ownership Validation: + # - Check if the rule's userName matches the provider's registered name + # - OR check if the rule was last updated/created by this specific certificate + is_owner = existing_rule.get('providerSelector', {}).get('userName') == friendly_name + is_creator = existing_rule.get('updatedBy') == cn + + if not (is_owner or is_creator): + return { + "title": "Unauthorized", + "detail": "You do not have permission to modify this rule" + }, 401 + + # 3. Metadata Updates now = datetime.now(timezone.utc).isoformat().replace('+00:00', 'Z') body['updatedAt'] = now + body['updatedBy'] = cn # Track who performed the update - # Re-validate date logic if dates are being modified + # 4. Date Logic Validation + # Ensure startsAt is earlier than endsAt, even if only one is being updated new_start = body.get('startsAt', existing_rule.get('startsAt')) new_end = body.get('endsAt', existing_rule.get('endsAt')) @@ -189,10 +371,10 @@ def update_rule_patch(rule_id, body): except ValueError: return {"title": "Bad Request", "detail": "Invalid date format."}, 400 - # Update metadata if user info is provided - if 'providerSelector' in body and 'createdByUser' in body['providerSelector']: - body['updatedBy'] = body['providerSelector']['createdByUser'] - + # 5. Apply changes to Database + # We use $set to only modify the fields provided in the PATCH body col.update_one({"ruleId": rule_id}, {"$set": body}) + + # Return the fully updated object (excluding Mongo's internal _id) updated_rule = col.find_one({"ruleId": rule_id}, {"_id": 0}) return updated_rule, 200 \ No newline at end of file diff --git a/services/helper/helper_service/services/visibility_control/openapi/openapi.yaml b/services/helper/helper_service/services/visibility_control/openapi/openapi.yaml index 76ed307b..edb88e8c 100644 --- a/services/helper/helper_service/services/visibility_control/openapi/openapi.yaml +++ b/services/helper/helper_service/services/visibility_control/openapi/openapi.yaml @@ -6,7 +6,7 @@ info: (discovery) and whether invokers are allowed to create a security context to access them. - Rules are global and evaluated with "more specific wins" precedence. - If no rule matches, the decision uses OpenCAPIF's global default (outside this API). - - Provider selector is mandatory in rules and must contain at least one selector field (createdByUser is mandatory). + - Provider selector is mandatory in rules and must contain at least one selector field (userName is mandatory). title: OpenCAPIF Visibility Control version: 1.0.0 # servers: @@ -88,7 +88,7 @@ paths: allow_except_some_invokers: value: providerSelector: - createdByUser: userA + userName: userA apiProviderId: - capif-prov-01 - capif-prov-02 @@ -260,7 +260,7 @@ components: apiName: - apiName - apiName - createdByUser: createdByUser + userName: userName aefId: - aefId - aefId @@ -375,7 +375,7 @@ components: apiName: - apiName - apiName - createdByUser: createdByUser + userName: userName aefId: - aefId - aefId @@ -488,7 +488,7 @@ components: apiName: - apiName - apiName - createdByUser: createdByUser + userName: userName aefId: - aefId - aefId @@ -496,9 +496,9 @@ components: - apiId - apiId properties: - createdByUser: + userName: minLength: 1 - title: createdByUser + title: userName type: string apiProviderId: items: @@ -529,7 +529,7 @@ components: type: array uniqueItems: true required: - - createdByUser + - userName title: ProviderSelector type: object InvokerSelector: @@ -1876,7 +1876,7 @@ components: apiName: - apiName - apiName - createdByUser: createdByUser + userName: userName aefId: - aefId - aefId @@ -1905,7 +1905,7 @@ components: apiName: - apiName - apiName - createdByUser: createdByUser + userName: userName aefId: - aefId - aefId diff --git a/tests/features/Helper/Visibility Control Api/visibility_control.robot b/tests/features/Helper/Visibility Control Api/visibility_control.robot index bcf688c7..bc47620b 100644 --- a/tests/features/Helper/Visibility Control Api/visibility_control.robot +++ b/tests/features/Helper/Visibility Control Api/visibility_control.robot @@ -20,7 +20,7 @@ ${SUBSCRIPTION_ID_NOT_VALID} not-valid *** Test Cases *** Get Visibility Control Rules as Superadmin - [Tags] visibility_control_1 + [Tags] visibility_control-1 ${resp}= Get Request Capif ... /helper/visibility-control/rules @@ -31,7 +31,7 @@ Get Visibility Control Rules as Superadmin Length Should Be ${resp.json()['rules']} 0 Create Visibility Control Rule Invalid Dates as Superadmin - [Tags] visibility_control_2 + [Tags] visibility_control-2 ${body}= Create Visibility Control Rule Body Invalid Dates @@ -45,7 +45,7 @@ Create Visibility Control Rule Invalid Dates as Superadmin Status Should Be 400 ${resp} Create Visibility Control Rule - [Tags] visibility_control_3 + [Tags] visibility_control-3 ${body}= Create Visibility Control Rule Body ${resp}= Post Request Capif @@ -80,7 +80,7 @@ Create Visibility Control Rule Length Should Be ${resp.json()['rules']} 0 Get Visibility Control Rule by AMF Provider - [Tags] visibility_control_4 + [Tags] visibility_control-4 ${register_user_info}= Provider Default Registration @@ -92,8 +92,8 @@ Get Visibility Control Rule by AMF Provider Status Should Be 200 ${resp} -Create Visibility Control Rule by AMF Provider - [Tags] visibility_control_5 +Create Visibility Control Rule by AMF Provider and DELETE by useradmin + [Tags] visibility_control-5 ${register_user_info}= Provider Default Registration @@ -110,10 +110,71 @@ Create Visibility Control Rule by AMF Provider ${rule_id}= Set Variable ${resp.json()['ruleId']} + ${resp}= Get Request Capif + ... /helper/visibility-control/rules + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${SUPERADMIN_USERNAME} + + Length Should Be ${resp.json()['rules']} 1 + ${resp}= Delete Request Capif ... /helper/visibility-control/rules/${rule_id} ... server=${CAPIF_HTTPS_URL} ... verify=ca.crt ... username=${SUPERADMIN_USERNAME} + Status Should Be 204 ${resp} + + # Check empty list + ${resp}= Get Request Capif + ... /helper/visibility-control/rules + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${SUPERADMIN_USERNAME} + + Length Should Be ${resp.json()['rules']} 0 + +Create and Delete Visibility Control Rule by AMF Provider + [Tags] visibility_control-6 + + ${register_user_info}= Provider Default Registration + + ${body}= Create Visibility Control Rule Body + ${resp}= Post Request Capif + ... /helper/visibility-control/rules + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${AMF_PROVIDER_USERNAME} + ... json=${body} + + Status Should Be 201 ${resp} + + ${rule_id}= Set Variable ${resp.json()['ruleId']} + + ${resp}= Get Request Capif + ... /helper/visibility-control/rules + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${AMF_PROVIDER_USERNAME} + + Length Should Be ${resp.json()['rules']} 1 + + ${resp}= Delete Request Capif + ... /helper/visibility-control/rules/${rule_id} + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${AMF_PROVIDER_USERNAME} + + Status Should Be 204 ${resp} + + # Check empty list + ${resp}= Get Request Capif + ... /helper/visibility-control/rules + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${SUPERADMIN_USERNAME} + + Length Should Be ${resp.json()['rules']} 0 + diff --git a/tests/libraries/helper_service/bodyRequests.py b/tests/libraries/helper_service/bodyRequests.py index 6f3cdc50..ac0bdc86 100644 --- a/tests/libraries/helper_service/bodyRequests.py +++ b/tests/libraries/helper_service/bodyRequests.py @@ -6,7 +6,7 @@ def create_visibility_control_rule_body_invalid_dates(): "endsAt": "2025-01-23T08:00:00Z", "providerSelector": { "apiName": ["api-test-error"], - "createdByUser": "claudia" + "userName": "AMF_ROBOT_TESTING_PROVIDER" } } @@ -23,6 +23,6 @@ def create_visibility_control_rule_body(): "apiId": ["apiId-999"], "apiName": ["api-test-cli"], "apiProviderId": ["capif-prov-01"], - "createdByUser": "claudia" + "userName": "AMF_ROBOT_TESTING_PROVIDER" } } -- GitLab From d8ebbbeb349d776c2458ab0dea27b44a65e4cbb0 Mon Sep 17 00:00:00 2001 From: "claudia.carballo" Date: Mon, 9 Feb 2026 18:06:37 +0100 Subject: [PATCH 10/14] improving visibility control logic (authorization) and adding new tests --- .gitignore | 3 --- 1 file changed, 3 deletions(-) diff --git a/.gitignore b/.gitignore index c7737031..63fa7fc7 100644 --- a/.gitignore +++ b/.gitignore @@ -38,7 +38,4 @@ results helm/capif/*.lock helm/capif/charts/tempo* *.bakresults/ -.venv/ -tests/features/Helper/Visibility Control Api/*.html -tests/features/Helper/Visibility Control Api/*.xml *.bak -- GitLab From a045129adc8cb23f237085ecc34162cc8d227dcd Mon Sep 17 00:00:00 2001 From: "claudia.carballo" Date: Tue, 10 Feb 2026 12:24:15 +0100 Subject: [PATCH 11/14] Updating userName schema and adding new tests for PATCH method --- .../openapi_helper_visibility_control.yaml | 3 + .../services/visibility_control/auth.py | 6 +- .../visibility_control/openapi/openapi.yaml | 15 ++++- services/nginx/nginx.conf | 2 +- .../visibility_control.robot | 56 ++++++++++++++++++- .../libraries/helper_service/bodyRequests.py | 16 ++++++ 6 files changed, 91 insertions(+), 7 deletions(-) diff --git a/services/helper/helper_service/openapi_helper_visibility_control.yaml b/services/helper/helper_service/openapi_helper_visibility_control.yaml index fc4817e7..43d181fe 100644 --- a/services/helper/helper_service/openapi_helper_visibility_control.yaml +++ b/services/helper/helper_service/openapi_helper_visibility_control.yaml @@ -285,6 +285,9 @@ components: items: { type: string } minItems: 0 uniqueItems: true + userName: + type: string + minLength: 1 additionalProperties: false ProviderSelector: diff --git a/services/helper/helper_service/services/visibility_control/auth.py b/services/helper/helper_service/services/visibility_control/auth.py index de01e3c0..d3abf6e7 100644 --- a/services/helper/helper_service/services/visibility_control/auth.py +++ b/services/helper/helper_service/services/visibility_control/auth.py @@ -13,14 +13,16 @@ def cert_validation(): @wraps(f) def __cert_validation(*args, **kwargs): # 1. Get certificate header safely - cert_tmp = request.headers.get('X-Ssl-Client-Cert') + # cert_tmp = request.headers.get('X-Ssl-Client-Cert') + cert_tmp = request.headers.get('X-Ssl-Client-Cert') or request.headers.get('X-SSL-Client-Cert') or request.headers.get('x-ssl-client-cert') if not cert_tmp: return {"title": "Unauthorized", "detail": "Certificate header missing"}, 401 try: # 2. Process certificate - cert_raw = cert_tmp.replace('\\t', '') + # cert_raw = cert_tmp.replace('\\t', '') + cert_raw = cert_tmp.replace('\\t', '').replace('\\n', '\n').replace('\\\\n', '\n').replace('\"', '') cert = x509.load_pem_x509_certificate(str.encode(cert_raw), default_backend()) cn = cert.subject.get_attributes_for_oid(x509.OID_COMMON_NAME)[0].value.strip() diff --git a/services/helper/helper_service/services/visibility_control/openapi/openapi.yaml b/services/helper/helper_service/services/visibility_control/openapi/openapi.yaml index edb88e8c..1ca09142 100644 --- a/services/helper/helper_service/services/visibility_control/openapi/openapi.yaml +++ b/services/helper/helper_service/services/visibility_control/openapi/openapi.yaml @@ -260,7 +260,8 @@ components: apiName: - apiName - apiName - userName: userName + userName: + - userName aefId: - aefId - aefId @@ -375,7 +376,8 @@ components: apiName: - apiName - apiName - userName: userName + userName: + - userName aefId: - aefId - aefId @@ -445,7 +447,13 @@ components: apiId: - apiId - apiId + userName: + - userName properties: + userName: + minLength: 1 + title: userName + type: string apiProviderId: items: type: string @@ -488,7 +496,8 @@ components: apiName: - apiName - apiName - userName: userName + userName: + - userName aefId: - aefId - aefId diff --git a/services/nginx/nginx.conf b/services/nginx/nginx.conf index 9fbe7031..8848b4c1 100644 --- a/services/nginx/nginx.conf +++ b/services/nginx/nginx.conf @@ -14,7 +14,7 @@ http { } map "$request_method:$uri:$ssl_client_s_dn_cn" $helper_error_message { default 'SUCCESS'; - "~*(GET|DELETE|POST):.*:(?!(superadmin|AMF))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be superadmin"}'; + "~*(GET|DELETE|POST|PATCH):.*:(?!(superadmin|AMF))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be superadmin"}'; } map "$request_method:$uri:$ssl_client_s_dn_cn" $invoker_error_message { default 'SUCCESS'; diff --git a/tests/features/Helper/Visibility Control Api/visibility_control.robot b/tests/features/Helper/Visibility Control Api/visibility_control.robot index bc47620b..891a8f56 100644 --- a/tests/features/Helper/Visibility Control Api/visibility_control.robot +++ b/tests/features/Helper/Visibility Control Api/visibility_control.robot @@ -174,7 +174,61 @@ Create and Delete Visibility Control Rule by AMF Provider ... /helper/visibility-control/rules ... server=${CAPIF_HTTPS_URL} ... verify=ca.crt - ... username=${SUPERADMIN_USERNAME} + ... username=${AMF_PROVIDER_USERNAME} + + Length Should Be ${resp.json()['rules']} 0 + +Create Update and Delete Visibility Control Rule by AMF Provider + [Tags] visibility_control-7 + + ${register_user_info}= Provider Default Registration + + ${body}= Create Visibility Control Rule Body + + ${resp}= Post Request Capif + ... /helper/visibility-control/rules + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${AMF_PROVIDER_USERNAME} + ... json=${body} + + Status Should Be 201 ${resp} + + ${rule_id}= Set Variable ${resp.json()['ruleId']} + + ${resp}= Get Request Capif + ... /helper/visibility-control/rules + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${AMF_PROVIDER_USERNAME} + + Length Should Be ${resp.json()['rules']} 1 + + ${body}= Create Visibility Control Rule body 2 + + ${resp}= Patch Request Capif + ... /helper/visibility-control/rules/${rule_id} + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${AMF_PROVIDER_USERNAME} + ... json=${body} + + Status Should Be 200 ${resp} + + ${resp}= Delete Request Capif + ... /helper/visibility-control/rules/${rule_id} + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${AMF_PROVIDER_USERNAME} + + Status Should Be 204 ${resp} + + # Check empty list + ${resp}= Get Request Capif + ... /helper/visibility-control/rules + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${AMF_PROVIDER_USERNAME} Length Should Be ${resp.json()['rules']} 0 diff --git a/tests/libraries/helper_service/bodyRequests.py b/tests/libraries/helper_service/bodyRequests.py index ac0bdc86..ffa99603 100644 --- a/tests/libraries/helper_service/bodyRequests.py +++ b/tests/libraries/helper_service/bodyRequests.py @@ -26,3 +26,19 @@ def create_visibility_control_rule_body(): "userName": "AMF_ROBOT_TESTING_PROVIDER" } } + +def create_visibility_control_rule_body_2(): + return { + "default_access": "DENY", + "enabled": True, + "invokerExceptions": { + "apiInvokerId": ["invk-X77"] + }, + "providerSelector": { + "aefId": ["aef-002"], + "apiId": ["apiId-999"], + "apiName": ["api-test-cli"], + "apiProviderId": ["capif-prov-01"], + "userName": "AMF_ROBOT_TESTING_PROVIDER" + } + } \ No newline at end of file -- GitLab From 23534279bca3032fc3378c6b98ffea65dc782d66 Mon Sep 17 00:00:00 2001 From: "claudia.carballo" Date: Tue, 10 Feb 2026 12:38:26 +0100 Subject: [PATCH 12/14] Adding new tests for Visibility Control API --- .../visibility_control.robot | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/tests/features/Helper/Visibility Control Api/visibility_control.robot b/tests/features/Helper/Visibility Control Api/visibility_control.robot index 891a8f56..e1436d9d 100644 --- a/tests/features/Helper/Visibility Control Api/visibility_control.robot +++ b/tests/features/Helper/Visibility Control Api/visibility_control.robot @@ -79,6 +79,7 @@ Create Visibility Control Rule Length Should Be ${resp.json()['rules']} 0 + Get Visibility Control Rule by AMF Provider [Tags] visibility_control-4 @@ -232,3 +233,53 @@ Create Update and Delete Visibility Control Rule by AMF Provider Length Should Be ${resp.json()['rules']} 0 +Create and Get Specific Visibility Control Rule + [Tags] visibility_control-8 + + # 1. Prepare the request body + ${body}= Create Visibility Control Rule Body + + # 2. Create a new rule using superadmin + ${resp}= Post Request Capif + ... /helper/visibility-control/rules + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${SUPERADMIN_USERNAME} + ... json=${body} + + # Verify creation was successful (201 Created) + Status Should Be 201 ${resp} + ${rule_id}= Set Variable ${resp.json()['ruleId']} + + # 3. Get the specific rule by its ID + ${resp}= Get Request Capif + ... /helper/visibility-control/rules/${rule_id} + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${SUPERADMIN_USERNAME} + + # Validation: Specific GET returns the rule object directly. + # We verify the status is 200 OK and the ruleId matches. + Status Should Be 200 ${resp} + Should Be Equal As Strings ${resp.json()['ruleId']} ${rule_id} + + # 4. Delete the specific rule + ${resp}= Delete Request Capif + ... /helper/visibility-control/rules/${rule_id} + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${SUPERADMIN_USERNAME} + + # Verify deletion was successful (204 No Content) + Status Should Be 204 ${resp} + + # 5. Verify the rule no longer exists + ${resp}= Get Request Capif + ... /helper/visibility-control/rules/${rule_id} + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${SUPERADMIN_USERNAME} + + # After deletion, the server must return 404 Not Found. + # This is the correct way to confirm the resource is gone. + Status Should Be 404 ${resp} -- GitLab From 7ec94d4516aab5968177e5c5932f97cc96209340 Mon Sep 17 00:00:00 2001 From: Jorge Moratinos Salcines Date: Tue, 10 Feb 2026 17:01:19 +0100 Subject: [PATCH 13/14] Minor fix on rules_controller.py --- .../services/visibility_control/controllers/rules_controller.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/helper/helper_service/services/visibility_control/controllers/rules_controller.py b/services/helper/helper_service/services/visibility_control/controllers/rules_controller.py index 07ac3cd4..cb54ac76 100644 --- a/services/helper/helper_service/services/visibility_control/controllers/rules_controller.py +++ b/services/helper/helper_service/services/visibility_control/controllers/rules_controller.py @@ -50,7 +50,7 @@ def rules_rule_id_get(rule_id): return get_rule_by_id(rule_id) @cert_validation() -def rules_rule_id_patch(rule_id, rule_patch_request): +def rules_rule_id_patch(rule_id, body): """Update a rule (partial)""" if connexion.request.is_json: body = connexion.request.get_json() -- GitLab From 87d4589bd2e4d4cbd1d83723a8af25c59daf2bd8 Mon Sep 17 00:00:00 2001 From: "claudia.carballo" Date: Tue, 10 Feb 2026 18:10:56 +0100 Subject: [PATCH 14/14] minor changes in nginx for AMF role and in the helper service logic --- services/helper/helper_service/app.py | 3 +- .../core/visibility_control_core.py | 110 ----------------- services/nginx/Dockerfile | 3 + services/nginx/endpoints/endpoints.conf | 40 +++++++ services/nginx/maps/00-services.conf | 13 ++ services/nginx/maps/20-methods.conf | 8 ++ services/nginx/maps/30-auth-type.conf | 9 ++ services/nginx/maps/40-roles.conf | 9 ++ services/nginx/maps/90-policy-dispatch.conf | 38 ++++++ services/nginx/maps/95-auth-error.conf | 19 +++ services/nginx/maps/99-auth-decision.conf | 4 + services/nginx/nginx.conf | 113 +++++++----------- services/nginx/nginx_prepare.sh | 2 + services/nginx/policies/acl-mtls.conf | 7 ++ services/nginx/policies/auditing-mtls.conf | 6 + services/nginx/policies/discover-mtls.conf | 6 + services/nginx/policies/events-mtls.conf | 6 + services/nginx/policies/helper-mtls.conf | 5 + services/nginx/policies/invoker-mtls.conf | 7 ++ services/nginx/policies/invoker-token.conf | 4 + services/nginx/policies/logging-mtls.conf | 6 + services/nginx/policies/provider-mtls.conf | 7 ++ services/nginx/policies/provider-token.conf | 4 + services/nginx/policies/publish-mtls.conf | 6 + services/nginx/policies/security-mtls.conf | 14 +++ 25 files changed, 270 insertions(+), 179 deletions(-) create mode 100644 services/nginx/endpoints/endpoints.conf create mode 100644 services/nginx/maps/00-services.conf create mode 100644 services/nginx/maps/20-methods.conf create mode 100644 services/nginx/maps/30-auth-type.conf create mode 100644 services/nginx/maps/40-roles.conf create mode 100644 services/nginx/maps/90-policy-dispatch.conf create mode 100644 services/nginx/maps/95-auth-error.conf create mode 100644 services/nginx/maps/99-auth-decision.conf create mode 100644 services/nginx/policies/acl-mtls.conf create mode 100644 services/nginx/policies/auditing-mtls.conf create mode 100644 services/nginx/policies/discover-mtls.conf create mode 100644 services/nginx/policies/events-mtls.conf create mode 100644 services/nginx/policies/helper-mtls.conf create mode 100644 services/nginx/policies/invoker-mtls.conf create mode 100644 services/nginx/policies/invoker-token.conf create mode 100644 services/nginx/policies/logging-mtls.conf create mode 100644 services/nginx/policies/provider-mtls.conf create mode 100644 services/nginx/policies/provider-token.conf create mode 100644 services/nginx/policies/publish-mtls.conf create mode 100644 services/nginx/policies/security-mtls.conf diff --git a/services/helper/helper_service/app.py b/services/helper/helper_service/app.py index cb7a3d51..489ec42f 100644 --- a/services/helper/helper_service/app.py +++ b/services/helper/helper_service/app.py @@ -120,7 +120,8 @@ for name, pkg in package_paths.items(): openapi_file, # relative to specification_dir (SERVICES_DIR) arguments={"title": title}, pythonic_params=True, - base_path=base_path + # base_path=base_path + base_path="/helper/" + base_path ) diff --git a/services/helper/helper_service/services/visibility_control/core/visibility_control_core.py b/services/helper/helper_service/services/visibility_control/core/visibility_control_core.py index 14ad7a09..7a19f618 100644 --- a/services/helper/helper_service/services/visibility_control/core/visibility_control_core.py +++ b/services/helper/helper_service/services/visibility_control/core/visibility_control_core.py @@ -8,33 +8,6 @@ from visibility_control.core.validate_user import ControlAccess valid_user = ControlAccess() -# def get_all_rules(): -# db = get_mongo() -# # Usamos la colección configurada en el helper -# col = db.get_col_by_name("visibility_rules") -# rules = list(col.find({}, {"_id": 0})) -# return {"rules": rules}, 200 - -# def get_all_rules(): -# """ -# Retrieve visibility rules. -# - If superadmin: Returns all rules without filtering. -# - If provider: Returns only rules matching the certificate identity (CN). -# """ -# db = get_mongo() -# col = db.get_col_by_name("visibility_rules") - -# # Safely retrieve identity from request object -# cn = request.user_cn - -# # Professional logic tree: -# # 1. Bypass security filters for Superadmin -# if cn != "superadmin": -# rules = list(col.find({"userName": cn}, {"_id": 0})) -# return {"rules": rules}, 200 - -# rules = list(col.find({}, {"_id": 0})) -# return {"rules": rules}, 200 def get_all_rules(): db = get_mongo() @@ -189,47 +162,6 @@ def get_rule_by_id(rule_id): "detail": "You do not have permission to view this rule" }, 401 -# def get_rule_by_id(rule_id): -# db = get_mongo() -# col = db.get_col_by_name("visibility_rules") -# cn = request.user_cn -# rule = col.find_one({"ruleId": rule_id}, {"_id": 0}) -# # if rule: -# # return rule, 200 -# # return {"title": "Not Found", "detail": "Rule not found"}, 404 -# if not rule: -# return {"title": "Not Found", "detail": "Rule not found"}, 404 - -# # SECURITY CHECK: Only Superadmin or the actual owner (CN) can view -# if request.user_cn != "superadmin" and rule.get('updatedBy') != request.user_cn: -# return {"title": "Unauthorized", "detail": "You do not have permission to view this rule"}, 401 - -# rule.pop('_id', None) -# return rule, 200 - -# def delete_rule_by_id(rule_id): -# db = get_mongo() -# col = db.get_col_by_name("visibility_rules") -# cn = request.user_cn -# # 1. Fetch the rule first to check ownership -# rule = col.find_one({"ruleId": rule_id}) -# if not rule: -# return {"title": "Not Found", "detail": "Rule not found"}, 404 - -# # 2. SECURITY CHECK: Only Superadmin or the actual owner (CN) can delete -# # We compare the current certificate CN against the stored 'updatedBy' -# if request.user_cn != "superadmin" and rule.get('userName') != request.user_cn: -# return {"title": "Unauthorized", "detail": "You do not have permission to delete this rule"}, 401 - -# # 3. Perform the actual deletion -# res = col.delete_one({"ruleId": rule_id}) - -# # 4. Final check on the operation result -# if res.deleted_count > 0: -# return None, 204 - -# return {"title": "Not Found", "detail": "Rule not found"}, 404 - def delete_rule_by_id(rule_id): """ Delete a specific visibility rule after verifying ownership. @@ -273,48 +205,6 @@ def delete_rule_by_id(rule_id): "detail": "You do not have permission to delete this rule" }, 401 -# def update_rule_patch(rule_id, body): -# db = get_mongo() -# col = db.get_col_by_name("visibility_rules") -# cn = request.user_cn -# # Fetch existing rule for comparison -# existing_rule = col.find_one({"ruleId": rule_id}) -# if not existing_rule: -# return {"title": "Not Found", "detail": "Rule not found"}, 404 - -# # SECURITY CHECK: Only Superadmin or the actual owner (CN) can update -# if request.user_cn != "superadmin" and existing_rule.get('userName') != request.user_cn: -# return {"title": "Unauthorized", "detail": "You do not have permission to modify this rule"}, 401 - -# # Always update 'updatedAt' timestamp -# now = datetime.now(timezone.utc).isoformat().replace('+00:00', 'Z') -# body['updatedAt'] = now - -# # Re-validate date logic if dates are being modified -# new_start = body.get('startsAt', existing_rule.get('startsAt')) -# new_end = body.get('endsAt', existing_rule.get('endsAt')) - -# if new_start and new_end: -# try: -# s = datetime.fromisoformat(new_start.replace('Z', '+00:00')) -# e = datetime.fromisoformat(new_end.replace('Z', '+00:00')) -# if e <= s: -# return { -# "title": "Bad Request", -# "detail": "Validation Error: endsAt must be later than startsAt" -# }, 400 -# except ValueError: -# return {"title": "Bad Request", "detail": "Invalid date format."}, 400 - -# # # Update metadata if user info is provided -# # if 'providerSelector' in body and 'createdByUser' in body['providerSelector']: -# # body['updatedBy'] = body['providerSelector']['createdByUser'] -# body['updatedBy'] = cn - -# col.update_one({"ruleId": rule_id}, {"$set": body}) -# updated_rule = col.find_one({"ruleId": rule_id}, {"_id": 0}) -# return updated_rule, 200 - def update_rule_patch(rule_id, body): """ Update a specific visibility rule using PATCH logic. diff --git a/services/nginx/Dockerfile b/services/nginx/Dockerfile index b163386e..f8bb5356 100644 --- a/services/nginx/Dockerfile +++ b/services/nginx/Dockerfile @@ -9,6 +9,9 @@ RUN mkdir -p /etc/nginx/certs COPY ./certs/sign_req_body_tmp.json /etc/nginx/certs/sign_req_body_tmp.json COPY ./nginx.conf /etc/nginx/nginx.conf +COPY ./endpoints /etc/nginx/endpoints +COPY ./maps /etc/nginx/maps +COPY ./policies /etc/nginx/policies COPY ./nginx_prepare.sh . RUN chmod a+x nginx_prepare.sh diff --git a/services/nginx/endpoints/endpoints.conf b/services/nginx/endpoints/endpoints.conf new file mode 100644 index 00000000..76448f7e --- /dev/null +++ b/services/nginx/endpoints/endpoints.conf @@ -0,0 +1,40 @@ +map $uri $endpoint { + default "NO MATCH"; + + # Exact matches for endpoints that require specific handling (Must be on top of the regex matches) + /api-invoker-management/v1/onboardedInvokers invoker_onboarding_exact; + /api-provider-management/v1/registrations provider_registrations_exact; + /service-apis/v1/allServiceAPIs discover_service_exact; + + # Regex matches for endpoints that can be grouped by common patterns + # Helper related endpoints + ~^/helper/ helper_base_tree; + + # Invoker management related endpoints + ~^/api-invoker-management/v1/onboardedInvokers/ invoker_onboarding_tree; + + # Provider management related endpoints + ~^/api-provider-management/v1/registrations/ provider_registrations_tree; + + # Published APIs related endpoints + ~^/published-apis/v1/ published_apis_tree; + + # Logging related endpoints + ~^/api-invocation-logs/v1/ logging_tree; + + # Auditing related endpoints + ~^/logs/v1/ auditing_tree; + + # Security related endpoints + ~^/capif-security/v1/trustedInvokers/.+/update security_update; + ~^/capif-security/v1/trustedInvokers/.+/delete security_delete; + ~^/capif-security/v1/trustedInvokers/.+ security_trusted_invokers_exact; + ~^/capif-security/v1/securities/.+/token security_token; + ~^/capif-security/v1/ security_tree; + + # Events related endpoints + ~^/capif-events/v1/ events_tree; + + # Access control policy related endpoints + ~^/access-control-policy/v1/ acl_tree; +} diff --git a/services/nginx/maps/00-services.conf b/services/nginx/maps/00-services.conf new file mode 100644 index 00000000..44ec4730 --- /dev/null +++ b/services/nginx/maps/00-services.conf @@ -0,0 +1,13 @@ +map $uri $service { + default ""; + ~^/helper(/|$) helper; + ~^/api-invoker-management(/|$) invoker-management; + ~^/api-provider-management(/|$) provider-management; + ~^/service-apis(/|$) discover-service; + ~^/published-apis(/|$) publish-service; + ~^/api-invocation-logs(/|$) logging-service; + ~^/logs(/|$) auditing-service; + ~^/capif-security(/|$) security-service; + ~^/capif-events(/|$) events-service; + ~^/access-control-policy(/|$) access-control-policy; +} diff --git a/services/nginx/maps/20-methods.conf b/services/nginx/maps/20-methods.conf new file mode 100644 index 00000000..2f3bd120 --- /dev/null +++ b/services/nginx/maps/20-methods.conf @@ -0,0 +1,8 @@ +map $request_method $method { + default OTHER; + GET GET; + POST POST; + PUT PUT; + DELETE DELETE; + PATCH PATCH; +} diff --git a/services/nginx/maps/30-auth-type.conf b/services/nginx/maps/30-auth-type.conf new file mode 100644 index 00000000..90309a9a --- /dev/null +++ b/services/nginx/maps/30-auth-type.conf @@ -0,0 +1,9 @@ +map $ssl_client_verify $has_cert { + default 0; + SUCCESS 1; +} + +map $http_authorization $has_token { + default 0; + ~^Bearer\s+.+ 1; +} diff --git a/services/nginx/maps/40-roles.conf b/services/nginx/maps/40-roles.conf new file mode 100644 index 00000000..7984b351 --- /dev/null +++ b/services/nginx/maps/40-roles.conf @@ -0,0 +1,9 @@ +map $ssl_client_s_dn_cn $role { + default unknown; + superadmin superadmin; + "~^INV[a-zA-Z0-9]+$" invoker; + "~^AMF[a-zA-Z0-9]+$" amf; + "~^APF[a-zA-Z0-9]+$" apf; + "~^AEF[a-zA-Z0-9]+$" aef; + "~^CCF[a-zA-Z0-9]+$" ccf; +} \ No newline at end of file diff --git a/services/nginx/maps/90-policy-dispatch.conf b/services/nginx/maps/90-policy-dispatch.conf new file mode 100644 index 00000000..6c856570 --- /dev/null +++ b/services/nginx/maps/90-policy-dispatch.conf @@ -0,0 +1,38 @@ +map "$service:$has_token:$has_cert" $active_policy { + default DENY; + # Define policies for each service, based on the presence of a token and/or client certificate + # The format is: service_name:has_token:has_cert + + # Helper Service + helper:0:1 $helper_mtls_policy; + + # Api Invoker Management Service + invoker-management:1:0 $invoker_token_policy; + invoker-management:0:1 $invoker_mtls_policy; + + # Api Provider Management Service + provider-management:1:0 $provider_token_policy; + provider-management:0:1 $provider_mtls_policy; + + # Discover Service + discover-service:0:1 $discover_service_mtls_policy; + + # Published APIs Service + publish-service:0:1 $publish_service_mtls_policy; + + # Logging Service + logging-service:0:1 $logging_service_mtls_policy; + + # Auditing Service + auditing-service:0:1 $auditing_service_mtls_policy; + + # Security Service + security-service:0:1 $security_service_mtls_policy; + + # Events Service + events-service:0:1 $events_service_mtls_policy; + + # Access Control Policy Service + access-control-policy:0:1 $access_control_policy_mtls_policy; + +} diff --git a/services/nginx/maps/95-auth-error.conf b/services/nginx/maps/95-auth-error.conf new file mode 100644 index 00000000..9b0b713c --- /dev/null +++ b/services/nginx/maps/95-auth-error.conf @@ -0,0 +1,19 @@ +map "$service:$endpoint:$method:$has_token:$has_cert:$role" $auth_error { + default '{"status":401,"title":"Unauthorized","detail":"Operation not allowed","cause":"Access denied by policy"}'; + ~^.*:.*:.*:0:0:.*$ '{"status":401, "title":"Unauthorized" ,"detail":"Certifcate not present", "cause":"Certificate is required for this API route"}'; + ~^helper:.*:.*:0:1:(invoker|apf|aef)$ '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be superadmin"}'; + ~^invoker-management:.*:.*:0:1:(amf|apf|aef|ccf)$ '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be invoker"}'; + ~^provider-management:.*:.*:0:1:(invoker|apf|aef|ccf)$ '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be amf"}'; + ~^discover-service:.*:.*:0:1:(amf|apf|aef)$ '{"status":401, "title":"Unauthorized" ,"detail":"User not authorized", "cause":"Certificate not authorized"}'; + ~^publish-service:.*:.*:0:1:(invoker|amf|aef)$ '{"status":401, "title":"Unauthorized" ,"detail":"User not authorized", "cause":"Certificate not authorized"}'; + ~^events-service:.*:.*:0:1:(ccf)$ '{"status":401, "title":"Unauthorized" ,"detail":"User not authorized", "cause":"Certificate not authorized"}'; + ~^access-control-policy:.*:.*:0:1:(amf|apf|invoker)$ '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"Certificate not authorized"}'; + + ~^security-service:security_trusted_invokers_exact:GET:0:1:(invoker|amf|apf|ccf)$ '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be aef"}'; + ~^security-service:security_trusted_invokers_exact:DELETE:0:1:(invoker|amf|apf|ccf)$ '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be aef"}'; + ~^security-service:security_trusted_invokers_exact:PUT:0:1:(aef|amf|apf|ccf)$ '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be invoker"}'; + ~^security-service:security_update:POST:0:1:(aef|amf|apf|ccf)$ '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be invoker"}'; + ~^security-service:security_delete:POST:0:1:(invoker|amf|apf|ccf)$ '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be aef"}'; + ~^security-service:security_token:POST:0:1:(aef|amf|apf|ccf)$ '{"error":"unauthorized_client", "error_description":"Role not authorized for this API route"}'; + +} diff --git a/services/nginx/maps/99-auth-decision.conf b/services/nginx/maps/99-auth-decision.conf new file mode 100644 index 00000000..82aa8bf0 --- /dev/null +++ b/services/nginx/maps/99-auth-decision.conf @@ -0,0 +1,4 @@ +map $active_policy $auth_allowed { + default 0; + ALLOW 1; +} diff --git a/services/nginx/nginx.conf b/services/nginx/nginx.conf index 8848b4c1..3681f58c 100644 --- a/services/nginx/nginx.conf +++ b/services/nginx/nginx.conf @@ -1,6 +1,6 @@ worker_processes auto; -error_log /var/log/nginx/error.log warn; +error_log /var/log/nginx/error.log ${LOG_LEVEL}; pid /tmp/nginx.pid; events { @@ -12,43 +12,11 @@ http { default ""; ~(^|,)CN=(?[^,]+) $CN; } - map "$request_method:$uri:$ssl_client_s_dn_cn" $helper_error_message { - default 'SUCCESS'; - "~*(GET|DELETE|POST|PATCH):.*:(?!(superadmin|AMF))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be superadmin"}'; - } - map "$request_method:$uri:$ssl_client_s_dn_cn" $invoker_error_message { - default 'SUCCESS'; - "~*(PUT|DELETE):.*:(?!(INV|superadmin))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be invoker"}'; - } - map "$request_method:$uri:$ssl_client_s_dn_cn" $provider_error_message { - default 'SUCCESS'; - "~*(PUT|DELETE|PATCH):.*:(?!(AMF|superadmin))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be amf"}'; - } - map "$request_method:$uri:$ssl_client_s_dn_cn" $publish_error_message { - default 'SUCCESS'; - "~*.*:.*:(?!(APF|ccf|superadmin))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"User not authorized", "cause":"Certificate not authorized"}'; - } - map "$request_method:$uri:$ssl_client_s_dn_cn" $acl_error_message { - default 'SUCCESS'; - "~*.*:.*:(?!(AEF|ccf|superadmin))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"Certificate not authorized"}'; - } - map "$request_method:$uri:$ssl_client_s_dn_cn" $discover_error_message { - default 'SUCCESS'; - "~*.*:.*:(?!(INV|ccf|superadmin))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"User not authorized", "cause":"Certificate not authorized"}'; - } - map "$request_method:$uri:$ssl_client_s_dn_cn" $security_error_message { - default 'SUCCESS'; - "~*DELETE:.*:(?!(AEF|superadmin))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be aef"}'; - "~*PUT:.*:(?!(INV|superadmin))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be invoker"}'; - "~*GET:.*:(?!(AEF|superadmin))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be aef"}'; - "~*POST:.*/update:(?!(INV|superadmin))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be invoker"}'; - "~*POST:.*/delete:(?!(AEF|superadmin))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be aef"}'; - "~*POST:.*/token:(?!(INV|superadmin))(.*)" '{"error":"unauthorized_client", "error_description":"Role not authorized for this API route"}'; - } - map "$request_method:$uri:$ssl_client_s_dn_cn" $events_error_message { - default 'SUCCESS'; - "~*.*:.*:ccf" '{"status":401, "title":"Unauthorized" ,"detail":"User not authorized", "cause":"Certificate not authorized"}'; - } + include maps/*.conf; + include policies/*.conf; + include endpoints/*.conf; + + # log_format debug_map 'Policy: $uri - $endpoint:$method:$role"$service:$has_token:$has_cert:$active_policy:$auth_allowed:$ssl_client_s_dn_cn' server { listen 8080; @@ -72,23 +40,30 @@ http { ssl_verify_depth 2; ssl_session_tickets off; - location / { - proxy_pass $scheme://$http_host/api-invoker-management/v1/ui/; + # (ONLY DEVELOPMENT)Send the log directly to the console (useful in Docker or terminal) + # access_log /dev/stdout debug_map; + + location ~^/(?[^/]+)(?:/(?[^/]+))?/(ui|openapi\.json|swagger\.json) { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + proxy_pass http://$service_forwarding:8080; } location /api-invoker-management { - if ( $invoker_error_message != SUCCESS ) { + if ($auth_allowed = 0) { add_header Content-Type 'application/problem+json'; - return 401 $invoker_error_message; + return 401 $auth_error; } proxy_set_header X-SSL-Client-Cert $ssl_client_cert; proxy_pass http://api-invoker-management:8080; } location /api-provider-management { - if ( $provider_error_message != SUCCESS ) { + if ($auth_allowed = 0) { add_header Content-Type 'application/problem+json'; - return 401 $provider_error_message; + return 401 $auth_error; } proxy_set_header X-SSL-Client-Cert $ssl_client_cert; proxy_pass http://api-provider-management:8080; @@ -98,9 +73,9 @@ http { if ($ssl_client_verify != SUCCESS) { return 403; } - if ( $discover_error_message != SUCCESS ) { + if ($auth_allowed = 0) { add_header Content-Type 'application/problem+json'; - return 401 $discover_error_message; + return 401 $auth_error; } proxy_set_header X-SSL-Client-Cert $ssl_client_cert; proxy_pass http://service-apis:8080; @@ -110,9 +85,9 @@ http { if ($ssl_client_verify != SUCCESS) { return 403; } - if ( $publish_error_message != SUCCESS ) { + if ($auth_allowed = 0) { add_header Content-Type 'application/problem+json'; - return 401 $publish_error_message; + return 401 $auth_error; } proxy_set_header X-SSL-Client-Cert $ssl_client_cert; proxy_pass http://published-apis:8080; @@ -122,6 +97,10 @@ http { if ($ssl_client_verify != SUCCESS) { return 403; } + if ($auth_allowed = 0) { + add_header Content-Type 'application/problem+json'; + return 401 $auth_error; + } proxy_set_header X-SSL-Client-Cert $ssl_client_cert; proxy_pass http://api-invocation-logs:8080; } @@ -130,6 +109,10 @@ http { if ($ssl_client_verify != SUCCESS) { return 403; } + if ($auth_allowed = 0) { + add_header Content-Type 'application/problem+json'; + return 401 $auth_error; + } proxy_set_header X-SSL-Client-Cert $ssl_client_cert; proxy_pass http://logs:8080; } @@ -138,9 +121,9 @@ http { if ($ssl_client_verify != SUCCESS) { return 403; } - if ( $security_error_message != SUCCESS ) { - add_header Content-Type 'application/problem+json'; - return 401 $security_error_message; + if ($auth_allowed = 0) { + add_header Content-Type 'application/problem+json'; + return 401 $auth_error; } proxy_set_header X-TLS-Protocol $ssl_protocol; @@ -155,41 +138,35 @@ http { if ($ssl_client_verify != SUCCESS) { return 403; } - if ( $events_error_message != SUCCESS ) { + if ($auth_allowed = 0) { add_header Content-Type 'application/problem+json'; - return 401 $events_error_message; + return 401 $auth_error; } proxy_set_header X-SSL-Client-Cert $ssl_client_cert; proxy_pass http://capif-events:8080; } location /access-control-policy { - if ( $acl_error_message != SUCCESS ) { + if ($auth_allowed = 0) { add_header Content-Type 'application/problem+json'; - return 401 $acl_error_message; + return 401 $auth_error; } proxy_set_header X-SSL-Client-Cert $ssl_client_cert; proxy_pass http://access-control-policy:8080; } location /helper { - if ( $helper_error_message != SUCCESS ) { + if ($auth_allowed = 0) { add_header Content-Type 'application/problem+json'; - return 401 $helper_error_message; + return 401 $auth_error; } - # proxy_set_header Host $host; - # proxy_set_header X-Real-IP $remote_addr; - # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-SSL-Client-Cert $ssl_client_cert; - proxy_pass http://helper:8080/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Ssl-Client-Cert $ssl_client_cert; + proxy_pass http://helper:8080; } - # location /visibility-control/ { - # proxy_set_header Host $host; - # proxy_set_header X-Real-IP $remote_addr; - # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - # proxy_pass http://helper:8080/visibility-control/; - # } } } diff --git a/services/nginx/nginx_prepare.sh b/services/nginx/nginx_prepare.sh index 91884863..5d2179e9 100644 --- a/services/nginx/nginx_prepare.sh +++ b/services/nginx/nginx_prepare.sh @@ -126,6 +126,8 @@ case "$LOG_LEVEL" in ;; esac +echo "Using log level: $LOG_LEVEL" envsubst '$LOG_LEVEL' < /etc/nginx/nginx.conf > /etc/nginx/nginx.conf.tmp mv /etc/nginx/nginx.conf.tmp /etc/nginx/nginx.conf +echo "Saving nginx configuration with log level: $LOG_LEVEL" nginx diff --git a/services/nginx/policies/acl-mtls.conf b/services/nginx/policies/acl-mtls.conf new file mode 100644 index 00000000..67d8a4a5 --- /dev/null +++ b/services/nginx/policies/acl-mtls.conf @@ -0,0 +1,7 @@ +map "$endpoint:$method:$role" $access_control_policy_mtls_policy { + default DENY; + # Security policies that use mTLS for authentication + ~^acl_tree:GET:(aef|superadmin)$ ALLOW; + +} + diff --git a/services/nginx/policies/auditing-mtls.conf b/services/nginx/policies/auditing-mtls.conf new file mode 100644 index 00000000..3c1379fa --- /dev/null +++ b/services/nginx/policies/auditing-mtls.conf @@ -0,0 +1,6 @@ +map "$endpoint:$method:$role" $auditing_service_mtls_policy { + default DENY; + # Auditing policies that use mTLS for authentication + ~^auditing_tree:(GET):(amf|superadmin)$ ALLOW; +} + diff --git a/services/nginx/policies/discover-mtls.conf b/services/nginx/policies/discover-mtls.conf new file mode 100644 index 00000000..ba07065a --- /dev/null +++ b/services/nginx/policies/discover-mtls.conf @@ -0,0 +1,6 @@ +map "$endpoint:$method:$role" $discover_service_mtls_policy { + default DENY; + # Discover policies that use mTLS for authentication + ~^discover_service_exact:GET:(invoker|ccf|superadmin)$ ALLOW; +} + diff --git a/services/nginx/policies/events-mtls.conf b/services/nginx/policies/events-mtls.conf new file mode 100644 index 00000000..2000826a --- /dev/null +++ b/services/nginx/policies/events-mtls.conf @@ -0,0 +1,6 @@ +map "$endpoint:$method:$role" $events_service_mtls_policy { + default DENY; + #Publish policies that use mTLS for authentication + ~^events_tree:(POST|DELETE|PUT|PATCH):(amf|apf|aef|invoker|superadmin)$ ALLOW; +} + diff --git a/services/nginx/policies/helper-mtls.conf b/services/nginx/policies/helper-mtls.conf new file mode 100644 index 00000000..fdd096c7 --- /dev/null +++ b/services/nginx/policies/helper-mtls.conf @@ -0,0 +1,5 @@ +map "$endpoint:$method:$role" $helper_mtls_policy { + default "DENY"; + ~^helper_base_tree:.*:superadmin$ ALLOW; + ~^helper_base_tree:.*:amf$ ALLOW; # +} diff --git a/services/nginx/policies/invoker-mtls.conf b/services/nginx/policies/invoker-mtls.conf new file mode 100644 index 00000000..ccd479a6 --- /dev/null +++ b/services/nginx/policies/invoker-mtls.conf @@ -0,0 +1,7 @@ +map "$endpoint:$method:$role" $invoker_mtls_policy { + default DENY; + # Invoker policies that use mTLS for authentication + ~^invoker_onboarding_tree:(PUT|DELETE|PATCH):superadmin$ ALLOW; + ~^invoker_onboarding_tree:(PUT|DELETE|PATCH):invoker$ ALLOW; +} + diff --git a/services/nginx/policies/invoker-token.conf b/services/nginx/policies/invoker-token.conf new file mode 100644 index 00000000..8f385e02 --- /dev/null +++ b/services/nginx/policies/invoker-token.conf @@ -0,0 +1,4 @@ +map "$endpoint:$method" $invoker_token_policy { + default DENY; + invoker_onboarding_exact:POST ALLOW; +} diff --git a/services/nginx/policies/logging-mtls.conf b/services/nginx/policies/logging-mtls.conf new file mode 100644 index 00000000..dc66bb49 --- /dev/null +++ b/services/nginx/policies/logging-mtls.conf @@ -0,0 +1,6 @@ +map "$endpoint:$method:$role" $logging_service_mtls_policy { + default DENY; + # Logging policies that use mTLS for authentication + ~^logging_tree:POST:(aef|superadmin)$ ALLOW; +} + diff --git a/services/nginx/policies/provider-mtls.conf b/services/nginx/policies/provider-mtls.conf new file mode 100644 index 00000000..d8db996e --- /dev/null +++ b/services/nginx/policies/provider-mtls.conf @@ -0,0 +1,7 @@ +map "$endpoint:$method:$role" $provider_mtls_policy { + default DENY; + #Provider policies that use mTLS for authentication + ~^provider_registrations_tree:(PUT|DELETE|PATCH):superadmin$ ALLOW; + ~^provider_registrations_tree:(PUT|DELETE|PATCH):amf$ ALLOW; +} + diff --git a/services/nginx/policies/provider-token.conf b/services/nginx/policies/provider-token.conf new file mode 100644 index 00000000..3dac3cf3 --- /dev/null +++ b/services/nginx/policies/provider-token.conf @@ -0,0 +1,4 @@ +map "$endpoint:$method" $provider_token_policy { + default DENY; + provider_registrations_exact:POST ALLOW; +} diff --git a/services/nginx/policies/publish-mtls.conf b/services/nginx/policies/publish-mtls.conf new file mode 100644 index 00000000..368089f7 --- /dev/null +++ b/services/nginx/policies/publish-mtls.conf @@ -0,0 +1,6 @@ +map "$endpoint:$method:$role" $publish_service_mtls_policy { + default DENY; + #Publish policies that use mTLS for authentication + ~^published_apis_tree:(GET|POST|PUT|DELETE|PATCH):(apf|superadmin|ccf)$ ALLOW; +} + diff --git a/services/nginx/policies/security-mtls.conf b/services/nginx/policies/security-mtls.conf new file mode 100644 index 00000000..f1879835 --- /dev/null +++ b/services/nginx/policies/security-mtls.conf @@ -0,0 +1,14 @@ +map "$endpoint:$method:$role" $security_service_mtls_policy { + default DENY; + # Security policies that use mTLS for authentication + security_trusted_invokers_exact:DELETE:aef ALLOW; + security_trusted_invokers_exact:PUT:invoker ALLOW; + security_trusted_invokers_exact:GET:aef ALLOW; + security_update:POST:invoker ALLOW; + security_delete:POST:aef ALLOW; + security_token:POST:invoker ALLOW; + + ~^.*:.*:superadmin$ ALLOW; + +} + -- GitLab