diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..1320f90e5ba859dec9b8b7a0ea08b509eabb3ee1 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +site diff --git a/doc/FAQ.md b/doc/FAQ.md new file mode 100644 index 0000000000000000000000000000000000000000..a4f9b87b35b8d666b107df5d76eb18406b7df8fd --- /dev/null +++ b/doc/FAQ.md @@ -0,0 +1,83 @@ +# Frequently Asked Questions (FAQ) + +### Does the user have to develop the 3 elements of the provider (AEF, AMF and APF)? +No, you only have to make the request to the "/onboarding" endpoint. In it you must specify a CSR for the AEF, APF and AMF and you will receive the certificates for each of them in the response. + +### There is one party that publishes the API and another that exposes it, what is the difference? +There are different services, the APF, intended for publishing the APIs, and the AEF, intended so that the invoker can call it. The APF is what connects to the Capif Core Function to publish the service and when the service is up, you need the AEF service so that invokers can connect to it. + + +### Before publishing an API, do you have to be registered in CAPIF? +Yes, before publishing an API you must register using the POST /register endpoint. + + +### Where is the registration done? +Registration is done in a REST API outside of the CAPIF specification taht we have implemented. + + +### Is the username and password chosen by the user when registering or is it assigned when requesting registration to CAPIF public instance? +When you make the request to the "/endpoint" of register, you will be returned a username and a password determined by CAPIF. + + +### What is a CSR? +A CSR is a Certificate Signing Request. It is a generated data block where the certificate is planned to be installed and contains key information such as public key, organization, and location, and is used to request a certificate from a certificate authority (CA). In CAPIF, 3 CSRs are necessary to register a provider, for AEF, APF and AMF. + + +### When doing the register_provider where can I find the CSRs that are generated? +When using the "register_provider" command, if you add the "debug" option, it shows you a json with the data used to register the provider. There we can find in the body a list of 3 elements corresponding to AEF, APF and AMF. IN each of them, the apiProbPubKey field corresponds to the CSR. + + +### How to use the example client (CAPIF_INVOKER_GUI)? +First you have to make a "./run.sh host:port" indicating the address of the public CAPIF. Once the Docker containers are up, you have to do a "./terminal_to_py_netapp.sh" and then a "python main.py". At this point we will find ourselves in a console with some predefined commands to use the Client. If we press tab twice it will bring up the list of available commands. + + +### Where is the CAPIF public instance located? +The CAPIF public instance can be found at the following URLs: +- capif.mobilesandbox.cloud:37211 (HTTPS) +- capif.mobilesandbox.cloud:37212 (HTTP) + + +### Do you have to publish 3 APIs? one for each instance? +No, you only have to publish a single API but each component is responsible for a specific service, whether publishing or exposing. + + +### Once the API is published, is it always active? Or do you have to republish it every time you want to use it? +It is better to unsubscribe the API every time you exit the application since otherwise it could be republished and it would be double. + + +### Would the same username and password be valid for different invokers? +Yes, a user can have multiple invokers at the same time, and as such, the username and password would be the same. + + +### What is the notfication destination field in the register_invoker request? +This is the callback URL used to notify events. CAPIF has an Event service to subscribe to that notifies actions such as a subscription to an API, a change in the state of an API... + + +### Is the notification_destination a required field in the register_invoker +No, it is not mandatory, but if you do not enter it you will not receive any CAPIF events. For example, the APF may delete the API, you will not be notified that the API is no longer available. + + +### What is the purpose of the "discover_service" function in the invoker client? +The discover_service returns a json with all the services that exist exposed in CAPIF at that moment. + + +### What is the purpose of the "get_security_auth" function in the invoker client? +Sirve para pedir el token o para refrescarlo en caso de que haya caducado. You have to use that token to call the API from the invoker. + + +### What is the purpose of the "register_security_context" function in the invoker client? +To consume the API it is necessary to have a Security Context registered with the data and the authentication method. + + +### Is a user the same as an exposer? +No, a user registers in CAPIF and once done can have the role of invoker, provider or both. + + +### Where can I put my endpoint? +You have to set your endpoint when doing the "publish_service" functionality: + ``` + publish_service capif_ops/config_files/service_api_description_hello.json + ``` + +In the file "service_api_description_hello.json" you configure the service that is going to be exposed and by developing one to suit you, you expose your API. + diff --git a/doc/architecture/architecture.md b/doc/architecture/architecture.md deleted file mode 100644 index 9181348600e7706d51ec95802c023ccc68a3982b..0000000000000000000000000000000000000000 --- a/doc/architecture/architecture.md +++ /dev/null @@ -1,49 +0,0 @@ -# Architecture - - -Openslice offers the following main functionalities: - -* Service Catalog Management: A CSP will have the ability to manage the Service Catalog Items, their attributes , organize in categories and decide what to make available to Customers -* Services Specifications: A CSP will be able to manage Service Specifications -* Service Catalog Exposure: A CSP will be able to expose catalog to customers and related parties -* Service Catalog to Service Catalog: Openslice able to consume and provide Service Catalog items to other catalogs -* Service Order: The Customer will be able to place a Service Order -* Service Inventory: The Customer and Provider will be able to view deployed Services status - - -The following figure displays the overall architecture of Openslice. - -[](../images/architecture.png) - - -Openslice allows Vertical Customers browsing the available offered service specifications. It consists of: - -* Web frontend UIs that consist of mainly two portals: i) a NFV portal allowing users self-service management and onboarding VNFDs/NSDs to facility’s NFVO ii) a Services Portal, which allows users to browse the Service Catalog, Service Blueprints specifications and the Service Inventory -* An API gateway that proxies the internal APIs and used by the web front end as well as any other 3rd party service -* A Message Bus where all microservices use it to exchange messages either via message queues or via publish/subscribe topics -* An authentication server implementing Oauth2 authentication scheme -* A microservice offering TMF compliant API services (eg Service Catalog API, Service Ordering APIetc) -* A microservice offering NFV API services (eg VNF/NSD onboarding etc) and allows to store VNFDs and NSDs in a catalog -* A microservice that is capable to interface to an issue management system. For example it raises an issue to all related stakeholders (CSP, NOP, CSC) that a new Service Order is requested -* Central logging microservice that is capable to log all distributed actions in to an Elasticsearch cluster -* A Service Orchestrator solution that will propagate Service Ordering requests to the equivalent SOs and NFVOs - - -The following figure depicts how Openslice microservices are deployed - -[](../images/microservices_network_deployment.png) - - - -## Deploying Openslice in multi domain scenarios - -A typical deployment across domains, involves today some typical components: i) an OSS/BSS to allow customers access the service catalog and perform service orders, ii) a Service Orchestrator (SO) component for executing the service order workflow, as well as iii) a Network Functions Virtualization Orchestrator (NFVO) for configuring the iv) network resources. - -TMF Open APIs are introduced not only for exposing catalogues and accepting service orders, but also implementing the East-West interfaces between the domains, fulfilling also the LSO requirements as introduced by MEF. - -The following figure shows how openslice could be used in such scenarios: - -[](../images/multi-domain-architecture.png) - - -See more [Consuming Services From External Partner Organizations](./consumingServicesFromExternalPartners.md) diff --git a/doc/architecture/centrallog.md b/doc/architecture/centrallog.md deleted file mode 100644 index a6cbc2b8f2572e1dabf61324306b4c7326998e13..0000000000000000000000000000000000000000 --- a/doc/architecture/centrallog.md +++ /dev/null @@ -1,5 +0,0 @@ -# Central Logging - -Openslice follows the centralized log management concept, i.e. a type of logging solution system that consolidates the log data from different services and pushes it to a central, accessible and easy-to-use interface. - -For that reason, Elasticsearch is elected as an open-source centralized logging solution for collecting, parsing and storing logs towards a real-time data analytics tool that provides insights from any type of structured and unstructured data source. \ No newline at end of file diff --git a/doc/architecture/consumingServicesFromExternalPartners.md b/doc/architecture/consumingServicesFromExternalPartners.md deleted file mode 100644 index 090a9f754b059ee4dd5251f9bfc7ccfcca15063f..0000000000000000000000000000000000000000 --- a/doc/architecture/consumingServicesFromExternalPartners.md +++ /dev/null @@ -1,185 +0,0 @@ -# Consuming Services From External Partner Organizations - -A typical deployment across domains, involves today some typical components: i) an OSS/BSS to allow customers access the service catalog and perform service orders, ii) a Service Orchestrator (SO) component for executing the service order workflow, as well as iii) a Network Functions Virtualization Orchestrator (NFVO) for configuring the iv) network resources. - -TMF Open APIs are introduced not only for exposing catalogues and accepting service orders, but also implementing the East-West interfaces between the domains, fulfilling also the LSO requirements as introduced by MEF. - -The following figure shows how openslice could be used in such scenarios: - -[](../images/multi-domain-architecture.png) - - -In Openslice we can consume services from 3rd parties via Open APIs. - -We use the TMF 632 Party Management model to specify Organizations that we can exchange items and other information such as: - -- Import Service Specifications -- Create a Service Order -- Use the Service Inventory to query the status of the service ordered to the external partner organization - -## Define an Organization as 3rd party to consume services East-West - -An organization must have the following characteristics in openslice catalog, like for example: - -"EXTERNAL_TMFAPI_BASEURL", "http://portal.openslice.io" - -"EXTERNAL_TMFAPI_CLIENTREGISTRATIONID", "authOpensliceProvider" - -"EXTERNAL_TMFAPI_OAUTH2CLIENTID", "osapiWebClientId" - -"EXTERNAL_TMFAPI_OAUTH2CLIENTSECRET", "secret" - -"EXTERNAL_TMFAPI_OAUTH2SCOPES", scopes - -"EXTERNAL_TMFAPI_OAUTH2TOKENURI", "http://portal.openslice.io/osapi-oauth-server/oauth/token" - -"EXTERNAL_TMFAPI_USERNAME", "admin" - -"EXTERNAL_TMFAPI_PASSWORD", "openslice" - -"EXTERNAL_TMFAPI_SERVICE_CATALOG_URLS" = "/tmf-api/serviceCatalogManagement/v4/serviceSpecification?type=CustomerFacingServiceSpecification" (this is optional, fetch a list of service specs it will be relative with the BASEURL. If the url is empty then no specs will be fetched, the EXTERNAL_TMFAPI_SERVICE_CATEGORY_URLS might be used) - -"EXTERNAL_TMFAPI_SERVICE_CATEGORY_URLS" = "/tmf-api/serviceCatalogManagement/v4/serviceCategory/{categoryid}" (this example will fetch all specs in a category. You may define comma separated URLs of categories API URL . This will fetch specifications of every defined category. If you want only one specific category put for example the uuid only of one category: "/tmf-api/serviceCatalogManagement/v4/serviceCategory/bda02821-bc4d-4bd6-b64b-d9c2aa5f8e6d". multiple urls should be "/tmf-api/serviceCatalogManagement/v4/serviceCategory/bda02821-bc4d-4bd6-b64b-d9c2aa5f8e6d,/tmf-api/serviceCatalogManagement/v4/serviceCategory/9b6d8bf3-abd2-43c4-8154-c8c6fe5545b2") - -"EXTERNAL_TMFAPI_SERVICE_SPEC" = "/tmf-api/serviceCatalogManagement/v4/serviceSpecification" - -"EXTERNAL_TMFAPI_SERVICE_ORDER_URLS"= "/test/v1/serviceorder" (this is optional) - - -An example Organization defined example in json: -``` - -{ - "uuid": "1a09a8b5-6bd5-444b-b0b9-a73c69eb42ae", - "@baseType": "BaseEntity", - "@schemaLocation": null, - "@type": null, - "href": null, - "name": "Openslice.io", - "id": "1a09a8b5-6bd5-444b-b0b9-a73c69eb42ae", - "isHeadOffice": null, - "isLegalEntity": null, - "nameType": null, - "organizationType": null, - "tradingName": null, - "contactMedium": [], - "creditRating": [], - "existsDuring": null, - "externalReference": [], - "organizationChildRelationship": [], - "organizationIdentification": [], - "organizationParentRelationship": null, - "otherName": [], - "partyCharacteristic": [ - { - "uuid": "3a2f7221-e0a2-4a6b-88d1-534c8e1963f6", - "@baseType": "BaseEntity", - "@schemaLocation": null, - "@type": null, - "href": null, - "name": "EXTERNAL_TMFAPI_CLIENTREGISTRATIONID", - "valueType": null, - "value": { - "value": "authOpensliceProvider", - "alias": null - } - }, - { - "uuid": "c24bb527-f178-4d38-9b93-2027c1732876", - "@baseType": "BaseEntity", - "@schemaLocation": null, - "@type": null, - "href": null, - "name": "EXTERNAL_TMFAPI_USERNAME", - "valueType": null, - "value": { - "value": "admin", - "alias": null - } - }, - { - "uuid": "27e45df8-414b-44c6-a5d5-3f064e2cfd3b", - "@baseType": "BaseEntity", - "@schemaLocation": null, - "@type": null, - "href": null, - "name": "EXTERNAL_TMFAPI_PASSWORD", - "valueType": null, - "value": { - "value": "openslice", - "alias": null - } - }, - { - "uuid": "e0e470b8-6024-4014-8a18-2333e5465ce1", - "@baseType": "BaseEntity", - "@schemaLocation": null, - "@type": null, - "href": null, - "name": "EXTERNAL_TMFAPI_OAUTH2CLIENTSECRET", - "valueType": null, - "value": { - "value": "secret", - "alias": null - } - }, - { - "uuid": "3e0de762-ac80-4c1e-a0a1-f265ff0899b4", - "@baseType": "BaseEntity", - "@schemaLocation": null, - "@type": null, - "href": null, - "name": "EXTERNAL_TMFAPI_OAUTH2SCOPES", - "valueType": null, - "value": { - "value": "admin;read", - "alias": null - } - }, - { - "uuid": "0bbb8314-f7f2-420d-9fed-ba054b15f886", - "@baseType": "BaseEntity", - "@schemaLocation": null, - "@type": null, - "href": null, - "name": "EXTERNAL_TMFAPI_OAUTH2TOKENURI", - "valueType": null, - "value": { - "value": "http://portal.openslice.io/osapi-oauth-server/oauth/token", - "alias": null - } - }, - { - "uuid": "3a567de4-79eb-4006-a500-3e5229b44175", - "@baseType": "BaseEntity", - "@schemaLocation": null, - "@type": null, - "href": null, - "name": "EXTERNAL_TMFAPI_OAUTH2CLIENTID", - "valueType": null, - "value": { - "value": "osapiWebClientId", - "alias": null - } - }, - { - "uuid": "6dca729f-dbe1-46b7-89f1-5c4f9fe89d4e", - "@baseType": "BaseEntity", - "@schemaLocation": null, - "@type": null, - "href": null, - "name": "EXTERNAL_TMFAPI_BASEURL", - "valueType": null, - "value": { - "value": "http://portal.openslice.io", - "alias": null - } - } - ], - "relatedParty": [], - "status": null, - "taxExemptionCertificate": [] -} - -``` - \ No newline at end of file diff --git a/doc/architecture/issuemgt.md b/doc/architecture/issuemgt.md deleted file mode 100644 index b50f5459a186f1eff82bebcb5e805c0752d6dde8..0000000000000000000000000000000000000000 --- a/doc/architecture/issuemgt.md +++ /dev/null @@ -1,7 +0,0 @@ -# Issue Management - -For issue management support, Openslice relies on Bugzilla. Bugzilla is a ticketing tool that allows issue reporting and tracking via tickets to all relevant stakeholders. - -The figure below displays the overall issue management service architecture integrating Bugzilla as its core and how this tool interacts with other Openslice services presenting some distinctive scenarios. It should be noted that Bugzilla tickets will not only be used for bugs/errors, but also for general requests, e.g. Service Order procedure. - -[](../images/issue_management.png) \ No newline at end of file diff --git a/doc/architecture/messagebus.md b/doc/architecture/messagebus.md deleted file mode 100644 index a228afb52670b03e7036a2199cbfecd1454a2d50..0000000000000000000000000000000000000000 --- a/doc/architecture/messagebus.md +++ /dev/null @@ -1,816 +0,0 @@ -# Message Bus and exchanged Messages - -Openslice has a Message bus which allows Openslice services to exchange messages via queues and topics. - -It is based on ActiveMQ. - -3rd party services can be attached to bus and subscribe to message topics or request resources via queues. - - -## QUEUE MESSAGES - -| Message | | -| ------------- |----------------| -|**Alias** | CATALOG_GET_SERVICEORDERS | -|**Name** | jms:queue:CATALOG.GET.SERVICEORDERS | -|**Type** | queue | -|**Destination** | TMF API service | -|**Producers** | OSOM | -|**Body** | | -|**Description** | Return a List<ServiceOrder> as String Json| - ---- - -| Message | | -| ------------- |----------------| -|**Alias** | CATALOG_GET_SERVICEORDER_BY_ID | -|**Name** | jms:queue:CATALOG.GET.SERVICEORDER_BY_ID | -|**Type** | queue | -|**Destination** | TMF API service | -|**Producers** | OSOM | -|**Body** | String orderid | -|**Description** | Return a ServiceOrder as String Json | - ---- - - -| Message | | -| ------------- |----------------| -|**Alias** | CATALOG_UPD_SERVICEORDER_BY_ID | -|**Name** | jms:queue:CATALOG.UPD.SERVICEORDER_BY_ID | -|**Type** | queue | -|**Destination** | TMF API service | -|**Producers** | OSOM | -|**Body** | ServiceOrderUpdate serviceOrder | -|**Headers** | "orderid"= orderid | -|**Description** | Returns a ServiceOrder as String | - - ---- - -| Message | | -| ------------- |----------------| -|**Alias** | CATALOG_GET_SERVICESPEC_BY_ID | -|**Name** | jms:queue:CATALOG.GET.SERVICESPEC_BY_ID | -|**Type** | queue | -|**Destination** | TMF API service | -|**Producers** | OSOM | -|**Body** | specid | -|**Description** | Return a ServiceSpecification | - ---- - - -| Message | | -| ------------- |----------------| -|**Alias** | CATALOG_ADD_SERVICESPEC | -|**Name** | jms:queue:CATALOG.ADD.SERVICESPEC | -|**Type** | queue | -|**Destination** | TMF API service | -|**Producers** | CRIDGE | -|**Body** | ServiceSpecCreate | -|**Description** | Creates a ServiceSpecification and returns a ServiceSpecification as String | - ---- - - -| Message | | -| ------------- |----------------| -|**Alias** | CATALOG_UPD_SERVICESPEC | -|**Name** | jms:queue:CATALOG.UPD.SERVICESPEC | -|**Type** | queue | -|**Destination** | TMF API service | -|**Producers** | CRIDGE | -|**Body** | ServiceSpecUpdate | -|**Headers** | "serviceSpecid" = serviceSpecId| -|**Description** | Updates a ServiceSpecification and returns a ServiceSpecification as String. | ---- - - -| Message | | -| ------------- |----------------| -|**Alias** | CATALOG_UPDADD_SERVICESPEC | -|**Name** | jms:queue:CATALOG.UPDADD.SERVICESPEC | -|**Type** | queue | -|**Destination** | TMF API service | -|**Producers** | CRIDGE | -|**Body** | ServiceSpecUpdate | -|**Headers** | "serviceSpecid" = serviceSpecId, "forceId"=forceId | -|**Description** | Updates a ServiceSpecification and returns a ServiceSpecification as String. If forceId is true then tries to assign the requested ID to the spec | - ---- - -| Message | | -| ------------- |----------------| -|**Alias** | CATALOG_ADD_SERVICEORDER | -|**Name** | jms:queue:CATALOG.ADD.SERVICEORDER | -|**Type** | queue | -|**Destination** | TMF API service | -|**Producers** | OSOM | -|**Body** | ServiceOrderCreate serviceOrder | -|**Headers** | | -|**Description** | Creates a ServiceOrder and returns a ServiceOrder as String | - ---- - - - -| Message | | -| ------------- |----------------| -|**Alias** | CATALOG_GET_INITIAL_SERVICEORDERS_IDS | -|**Name** | jms:queue:CATALOG.GET.INITIAL_SERVICEORDERS | -|**Type** | queue | -|**Destination** | TMF API service | -|**Producers** | | -|**Body** | | -|**Description** | Return a List<ServiceOrder> as String Json| - ---- - - -| Message | | -| ------------- |----------------| -|**Alias** | CATALOG_GET_SERVICEORDER_IDS_BY_STATE | -|**Name** | jms:queue:CATALOG.GET.ACKNOWLEDGED_SERVICEORDERS | -|**Type** | queue | -|**Destination** | TMF API service | -|**Producers** | OSOM | -|**Body** | | -|**Headers** | "orderstate"= orderState | -|**Description** | String Json ArrayList of ServiceOrders | - ---- - - -| Message | | -| ------------- |----------------| -|**Alias** | CATALOG_ADD_SERVICE | -|**Name** | jms:queue:CATALOG.ADD.SERVICE | -|**Type** | queue | -|**Destination** | TMF API service | -|**Producers** | OSOM | -|**Body** | ServiceCreate String json | -|**Headers** | "orderid"=orderid, "serviceSpecid"= specid | -|**Description** | Creates Service based an a Service Spec, Returns a Service object | - ---- - - -| Message | | -| ------------- |----------------| -|**Alias** | CATALOG_UPD_SERVICE | -|**Name** | jms:queue:CATALOG.UPD.SERVICE | -|**Type** | queue | -|**Destination** | TMF API service | -|**Producers** | | -|**Body** | ServiceUpdate | -|**Headers** | "serviceid" = serviceId, "propagateToSO" = true/false | -|**Description** | will update a service by id and return the service instance. If propagateToSO=true then any service change will be handled by OSOM. This is needed to be controlled in order to avoid update loops| - ---- - - -| Message | | -| ------------- |----------------| -|**Alias** | CATALOG_GET_SERVICE_BY_ID | -|**Name** | jms:queue:CATALOG.GET.SERVICE | -|**Type** | queue | -|**Destination** | TMF API service | -|**Producers** | OSOM | -|**Body** | String serviceID | -|**Description** | returns a Service instance | - ----| Message | | -| ------------- |----------------| -|**Alias** | CATALOG_GET_SERVICE_BY_ORDERID | -|**Name** | jms:queue:CATALOG.GET.SERVICE_BY_ORDERID | -|**Type** | queue | -|**Destination** | TMF API service | -|**Producers** | | -|**Body** | String serviceID | -|**Description** | returns Service IDs of a specific order given then order id | - ---- - - -| Message | | -| ------------- |----------------| -|**Alias** | CATALOG_SERVICE_QUEUE_ITEMS_GET | -|**Name** | jms:queue:CATALOG.SERVICEQUEUEITEMS.GET | -|**Type** | queue | -|**Destination** | TMF API service | -|**Producers** | OSOM | -|**Body** | | -|**Description** | returns a LIST OF Service Queue Items | ---- - -| Message | | -| ------------- |----------------| -|**Alias** | CATALOG_SERVICE_QUEUE_ITEM_UPD | -|**Name** | jms:queue:CATALOG.SERVICEQUEUEITEM.UPDATE | -|**Type** | queue | -|**Destination** | TMF API service | -|**Producers** | OSOM | -|**Body** | String SERVICEQUEUEITEM | -|**Headers** | "itemid" = SERVICEQUEUEITEM id | -|**Description** | ill update a service queue item by id and return the instance | ---- - -| Message | | -| ------------- |----------------| -|**Alias** | CATALOG_SERVICE_QUEUE_ITEM_DELETE | -|**Name** | jms:queue:CATALOG.SERVICEQUEUEITEM.DELETE | -|**Type** | queue | -|**Destination** | TMF API service | -|**Producers** | OSOM | -|**Body** | | -|**Headers** | "itemid" = SERVICEQUEUEITEM id | -|**Description** | ill delete a service queue item by id | - ---- - -| Message | | -| ------------- |----------------| -|**Alias** | CATALOG_SERVICES_TO_TERMINATE | -|**Name** | jms:queue:CATALOG.GET.SERVICETOTERMINATE | -|**Type** | queue | -|**Destination** | TMF API service | -|**Producers** | OSOM | -|**Body** | | -|**Headers** | | -|**Description** | Get a list of ACTIVE services with END DAte in the past | ---- - -| Message | | -| ------------- |----------------| -|**Alias** | CATALOG_SERVICES_OF_PARTNERS | -|**Name** | jms:queue:CATALOG.GET.SERVICESOFPARTNERS | -|**Type** | queue | -|**Destination** | TMF API service | -|**Producers** | OSOM | -|**Body** | | -|**Headers** | | -|**Description** | Get a list of ACTIVE services from the inventory of partners | - - - ---- - -| Message | | -| ------------- |----------------| -|**Alias** | NFV_CATALOG_GET_NSD_BY_ID | -|**Name** | jms:queue:NFVCATALOG.GET.NSD_BY_ID | -|**Type** | queue | -|**Destination** | NFV Catalog service | -|**Producers** | TMF API, OSOM | -|**Body** | NSDid | -|**Description** | Returns a NetworkServiceDescriptor object | - ---- - -| Message | | -| ------------- |----------------| -|**Alias** | NFV_CATALOG_DEPLOY_NSD_REQ | -|**Name** | jms:queue:NFVCATALOG.DEPLOY.NSD_REQ | -|**Type** | queue | -|**Destination** | NFV Catalog service | -|**Producers** | OSOM | -|**Body** | DeploymentDescriptor as Json String | -|**Headers** | NSD id | -|**Description** | Returns a DeploymentDescriptor object as json string containing deployment info| - ---- - -| Message | | -| ------------- |----------------| -|**Alias** | NFV_CATALOG_UPD_DEPLOYMENT_BY_ID | -|**Name** | jms:queue:NFVCATALOG.UPD.DEPLOYMENT_BY_ID | -|**Type** | queue | -|**Destination** | NFV Catalog service | -|**Producers** | OSOM | -|**Body** | DeploymentDescriptor as Json String | -|**Headers** | DeploymentDescriptor id | -|**Description** | Updates and Returns a DeploymentDescriptor object as json string containing deployment info| - ---- - - - -| Message | | -| ------------- |----------------| -|**Alias** | GET_USER_BY_USERNAME | -|**Name** | jms:queue:GET.USER_BY_USERNAME | -|**Type** | queue | -|**Destination** | NFV Catalog service (this is temproary for now) | -|**Producers** | TMF API | -|**Body** | username | -|**Headers** | | -|**Description** | Returns a PortalUser object as json string containing user info| - ---- - -| Message | | -| ------------- |----------------| -|**Alias** | NFV_CATALOG_GET_DEPLOYMENT_BY_ID | -|**Name** | jms:queue:NFVCATALOG.GET.DEPLOYMENT_BY_ID | -|**Type** | queue | -|**Destination** | NFV Catalog service | -|**Producers** | OSOM | -|**Body** | Deployment ID | -|**Description** | Returns a DeploymentDescriptor object | - ---- - -| Message | | -| ------------- |----------------| -|**Alias** | CATALOG_GET_EXTERNAL_SERVICE_PARTNERS | -|**Name** | jms:queue:CATALOG.GET.EXTERNALSERVICEPARTNERS | -|**Type** | queue | -|**Destination** | TMF API service | -|**Producers** | OSOM | -|**Body** | | -|**Headers** | | -|**Description** | As a String Json ArrayList of Organizaton objects containing the characteristic name **EXTERNAL_TMFAPI** | - ---- - - - -| Message | | -| ------------- |----------------| -|**Alias** | CATALOG_UPD_EXTERNAL_SERVICESPEC | -|**Name** | jms:queue:CATALOG.UPD.EXTERNAL_SERVICESPEC | -|**Type** | queue | -|**Destination** | TMF API service | -|**Producers** | OSOM or maybe used by others that would like to update a Service Spec | -|**Body** | A serviceSpecification as json string | -|**Headers** | servicespecification id, orgid id | -|**Description** | Updates (or inserts if does not exist in catalog) an external service specification) | - ---- - - - - -| Message | | -| ------------- |----------------| -|**Alias** | NFV_CATALOG_NSACTIONS_SCALE | -|**Name** | jms:queue:NSACTIONS.SCALE | -|**Type** | queue | -|**Destination** | TMF API service | -|**Producers** | OSOM or maybe used by others that would like scale a NS | -|**Body** | A ScaleDescriptor as json string | -|**Headers** | none | -|**Description** | performs a scale | - ---- - - -| Message | | -| ------------- |----------------| -|**Alias** | NFV_CATALOG_NS_LCMCHANGED | -|**Name** | NFV_CATALOG_NS_LCMCHANGED | -|**Type** | topic | -|**Destination** | any | -|**Producers** | MANO client | -|**Body** | A json string | -|**Headers** | none | -|**Description** | A NFV_CATALOG_NS_LCMCHANGED message is published when LCM of a running NS is changed | - ---- - -#ALARMS - - -| Message | | -| ------------- |----------------| -|**Alias** | ALARMS_ADD_ALARM | -|**Name** | jms:queue:ALARMS.ADD.ALARM | -|**Type** | queue | -|**Publishers** | | -|**Consumers** | TMF API | -|**Body** | AlarmCreate | -|**Headers** | | -|**Description** | Add an alarm | - ---- - -| Message | | -| ------------- |----------------| -|**Alias** | ALARMS_UPDATE_ALARM | -|**Name** | jms:queue:ALARMS.UPDATE.ALARM | -|**Type** | queue | -|**Publishers** | | -|**Consumers** | TMF API | -|**Body** | AlarmUpdate | -|**Headers** | alarmid = alarm id, body (AlarmUpdate object) | -|**Description** | Update an alarm | - ---- - -| Message | | -| ------------- |----------------| -|**Alias** | ALARMS_GET_ALARM | -|**Name** | jms:queue:ALARMS.GET.ALARM | -|**Type** | queue | -|**Publishers** | | -|**Consumers** | TMF API | -|**Body** | | -|**Headers** | alarmid = alarm id | -|**Description** | get an alarm | - ---- - -## EVENT TOPICS IN Message Bus -| Message | | -| ------------- |----------------| -|**Alias** | EVENT_SERVICE_CREATE | -|**Name** | jms:topic:EVENT.SERVICE.CREATE | -|**Type** | topic | -|**Publishers** | TMF API | -|**Consumers** | - | -|**Body** | Notification object | -|**Headers** | "eventid"=eventid, "objId"= objId | -|**Description** | xx | - ---- -| Message | | -| ------------- |----------------| -|**Alias** | EVENT_SERVICE_STATE_CHANGED | -|**Name** | jms:topic:EVENT.SERVICE.STATECHANGED | -|**Type** | topic | -|**Publishers** | TMF API | -|**Consumers** | - | -|**Body** | Notification object | -|**Headers** | "eventid"=eventid, "objId"= objId | -|**Description** | xx | - ---- -| Message | | -| ------------- |----------------| -|**Alias** | EVENT_SERVICE_DELETE | -|**Name** | jms:topic:EVENT.SERVICE.DELETE | -|**Type** | topic | -|**Publishers** | TMF API | -|**Consumers** | - | -|**Body** | Notification object. Can be one of ServiceOrderCreateNotification, ServiceOrderStateChangeNotification, ServiceOrderAttributeValueChangeNotification, ServiceOrderDeleteNotification, etc | -|**Headers** | "eventid"=eventid, "objId"= objId | -|**Description** | xx | - ---- - -| Message | | -| ------------- |----------------| -|**Alias** | EVENT_SERVICE_ATTRIBUTE_VALUE_CHANGED | -|**Name** | jms:topic:EVENT.SERVICE.ATTRCHANGED | -|**Type** | topic | -|**Publishers** | TMF API | -|**Consumers** | - | -|**Body** | Notification object. Can be one of ServiceOrderCreateNotification, ServiceOrderStateChangeNotification, ServiceOrderAttributeValueChangeNotification, ServiceOrderDeleteNotification, etc | -|**Headers** | "eventid"=eventid, "objId"= objId | -|**Description** | xx | - ---- - -| Message | | -| ------------- |----------------| -|**Alias** | EVENT_SERVICE_ORDER_CREATE | -|**Name** | jms:topic:EVENT.SERVICEORDER.CREATE | -|**Type** | topic | -|**Publishers** | TMF API | -|**Consumers** | BUGZILLA Service, CentralLog Service | -|**Body** | Notification object. Can be one of ServiceOrderCreateNotification, ServiceOrderStateChangeNotification, ServiceOrderAttributeValueChangeNotification, ServiceOrderDeleteNotification, etc | -|**Headers** | "eventid"=eventid, "objId"= objId | -|**Description** | The Event of the Notification object contains the ServiceOrder object. Bugzilla service for example uses this to create a new issue | - ---- - -| Message | | -| ------------- |----------------| -|**Alias** | EVENT_SERVICE_ORDER_STATE_CHANGED | -|**Name** | jms:topic:EVENT.SERVICEORDER.STATECHANGED | -|**Type** | topic | -|**Publishers** | TMF API | -|**Consumers** | BUGZILLA Service, CentralLog Service | -|**Body** | Notification object. Can be one of ServiceOrderCreateNotification, ServiceOrderStateChangeNotification, ServiceOrderAttributeValueChangeNotification, ServiceOrderDeleteNotification, etc | -|**Headers** | "eventid"=eventid, "objId"= objId | -|**Description** | The Event of the Notification object contains the ServiceOrder object. Bugzilla service for example uses this to update an issue | - ---- - -| Message | | -| ------------- |----------------| -|**Alias** | EVENT_SERVICE_ORDER_DELETE | -|**Name** | jms:topic:EVENT.SERVICEORDER.DELETE | -|**Type** | topic | -|**Publishers** | TMF API | -|**Consumers** | BUGZILLA Service, CentralLog Service | -|**Body** | Notification object. Can be one of ServiceOrderCreateNotification, ServiceOrderStateChangeNotification, ServiceOrderAttributeValueChangeNotification, ServiceOrderDeleteNotification, etc | -|**Headers** | "eventid"=eventid, "objId"= objId | -|**Description** | The Event of the Notification object contains the ServiceOrder object | - ---- - -| Message | | -| ------------- |----------------| -|**Alias** | EVENT_SERVICE_ORDER_ATTRIBUTE_VALUE_CHANGED | -|**Name** | jms:topic:EVENT.SERVICEORDER.ATTRCHANGED | -|**Type** | topic | -|**Publishers** | TMF API | -|**Consumers** | BUGZILLA Service, CentralLog Service | -|**Body** | Notification object. Can be one of ServiceOrderCreateNotification, ServiceOrderStateChangeNotification, ServiceOrderAttributeValueChangeNotification, ServiceOrderDeleteNotification, etc | -|**Headers** | "eventid"=eventid, "objId"= objId | -|**Description** | The Event of the Notification object contains the ServiceOrder object | - ---- - -| Message | | -| ------------- |----------------| -|**Alias** | EVENT_ALARM_CREATE | -|**Name** | jms:topic:EVENT.ALARM.CREATE | -|**Type** | topic | -|**Publishers** | TMF API | -|**Consumers** | OAS, BUGZILLA Service, CentralLog Service | -|**Body** | AlarmCreateEvent | -|**Headers** | | -|**Description** | The Event contains the Alarm object in payload | - ---- - -| Message | | -| ------------- |----------------| -|**Alias** | CATALOG_ADD_RESOURCE | -|**Name** | jms:queue:CATALOG.ADD.RESOURCE | -|**Type** | topic | -|**Publishers** | TMF API | -|**Consumers** | any | -|**Body** | ResourceCreate | -|**Headers** | | -|**Description** | The Body contains the ResourceCreate object to add | - ---- - -| Message | | -| ------------- |----------------| -|**Alias** | CATALOG_UPD_RESOURCE | -|**Name** | jms:queue:CATALOG.UPD.RESOURCE | -|**Type** | topic | -|**Publishers** | TMF API | -|**Consumers** | any | -|**Body** | ResourceUpdate | -|**Headers** | resourceid , propagateToSO | -|**Description** | The Body contains the ResourceCreate object to update | - ---- - - -| Message | | -| ------------- |----------------| -|**Alias** | CATALOG_GET_RESOURCE_BY_ID | -|**Name** | jms:queue:CATALOG.GET.RESOURCE | -|**Type** | topic | -|**Publishers** | TMF API | -|**Consumers** | any | -|**Body** | resourceid | -|**Headers** | | -|**Description** | The Body contains the ResourceCreate object to update | - ---- - -| Message | | -| ------------- |----------------| -|**Alias** | CATALOG_RESOURCES_OF_PARTNERS | -|**Name** | jms:queue:CATALOG.GET.SERVICESOFPARTNERS | -|**Type** | topic | -|**Publishers** | TMF API | -|**Consumers** | any | -|**Body** | none | -|**Headers** | none | -|**Description** | retrieve all active services of partners | - ---- -| Message | | -| ------------- |----------------| -|**Alias** | CATALOG_ADD_RESOURCESPEC | -|**Name** | jms:queue:CATALOG.ADD.RESOURCESPEC | -|**Type** | topic | -|**Publishers** | TMF API | -|**Consumers** | any | -|**Body** | ResourceSpecificationCreate | -|**Headers** | | -|**Description** | The Body contains the ResourceSpecificationCreate object to add | - ---- -| Message | | -| ------------- |----------------| -|**Alias** | CATALOG_UPD_RESOURCESPEC | -|**Name** | jms:queue:CATALOG.UPD.RESOURCESPEC | -|**Type** | topic | -|**Publishers** | TMF API | -|**Consumers** | any | -|**Body** | ResourceSpecificationUpdate | -|**Headers** | resourceSpecId | -|**Description** | The Body contains the ResourceSpecificationCreate object to update | - - ---- -| Message | | -| ------------- |----------------| -|**Alias** | CATALOG_GET_RESOURCESPEC_BY_ID | -|**Name** | jms:queue:CATALOG.GET.RESOURCESPEC_BY_ID | -|**Type** | topic | -|**Publishers** | TMF API | -|**Consumers** | any | -|**Body** | resourceSpecid | -|**Headers** | | -|**Description** | The Body contains the object id to find | - ---- - -| Message | | -| ------------- |----------------| -|**Alias** | CATALOG_UPDADD_RESOURCESPEC | -|**Name** | jms:queue:CATALOG.UPDADD.RESOURCESPEC | -|**Type** | topic | -|**Publishers** | TMF API | -|**Consumers** | any | -|**Body** | resourceid | -|**Headers** | | -|**Description** | The Body contains the ResourceSpecificationCreate object to update or create if not exist | - ---- - -| Message | | -| ------------- |----------------| -|**Alias** | EVENT_RESOURCE_CREATE | -|**Name** | jms:topic:EVENT.RESOURCE.CREATE | -|**Type** | topic | -|**Publishers** | TMF API | -|**Consumers** | BUGZILLA Service, CentralLog Service, other | -|**Body** | Notification object. | -|**Headers** | "eventid"=eventid, "objId"= objId | -|**Description** | The Event of the Notification object contains the Resource object | - ---- - -| Message | | -| ------------- |----------------| -|**Alias** | EVENT_RESOURCE_STATE_CHANGED | -|**Name** | jms:topic:EVENT.RESOURCE.STATECHANGED | -|**Type** | topic | -|**Publishers** | TMF API | -|**Consumers** | BUGZILLA Service, CentralLog Service, other | -|**Body** | Notification object. | -|**Headers** | "eventid"=eventid, "objId"= objId | -|**Description** | The Event of the Notification object contains the Resource object | - ---- - -| Message | | -| ------------- |----------------| -|**Alias** | EVENT_RESOURCE_DELETE | -|**Name** | jms:topic:EVENT.SERVICE.RESOURCE | -|**Type** | topic | -|**Publishers** | TMF API | -|**Consumers** | BUGZILLA Service, CentralLog Service, other | -|**Body** | Notification object. | -|**Headers** | "eventid"=eventid, "objId"= objId | -|**Description** | The Event of the Notification object contains the Resource object | - ---- - -| Message | | -| ------------- |----------------| -|**Alias** | EVENT_RESOURCE_ATTRIBUTE_VALUE_CHANGED | -|**Name** | jms:topic:EVENT.RESOURCE.ATTRCHANGED | -|**Type** | topic | -|**Publishers** | TMF API | -|**Consumers** | BUGZILLA Service, CentralLog Service, other | -|**Body** | Notification object. | -|**Headers** | "eventid"=eventid, "objId"= objId | -|**Description** | The Event of the Notification object contains the Resource object | - ---- - - -| Message | | -| ------------- |----------------| -|**Alias** | CATALOG_GET_LCMRULE_BY_ID | -|**Name** | jms:queue:CATALOG.GET.LCMRULE | -|**Type** | topic | -|**Publishers** | TMF API | -|**Consumers** | any | -|**Body** | lcmid | -|**Headers** | | -|**Description** | The Body contains the LCMRuleSpec object | - ---- - - -| Message | | -| ------------- |----------------| -|**Alias** | CATALOG_GET_LCMRULES_BY_SPECID_PHASE | -|**Name** | jms:queue:CATALOG.GET.LCMRULES_BY_SPECID_PHASE | -|**Type** | topic | -|**Publishers** | TMF API | -|**Consumers** | any | -|**Body** | | -|**Headers** | header.servicespecid, header.phasename | -|**Description** | The Body contains the LCMRuleSpec objects of the specific Service Spec and the specific phase | - - - - - -| Message | | -| ------------- |----------------| -|**Alias** | CATALOG_GET_SERVICETESTSPEC_BY_ID | -|**Name** | jms:queue:CATALOG.GET.SERVICETESTSPEC_BY_ID | -|**Type** | queue | -|**Destination** | TMF API service | -|**Producers** | OSOM | -|**Body** | specid | -|**Description** | Return a ServiceTestSpecification | - ---- - - -| Message | | -| ------------- |----------------| -|**Alias** | CATALOG_ADD_SERVICETEST | -|**Name** | jms:queue:CATALOG.ADD.SERVICETEST | -|**Type** | queue | -|**Destination** | TMF API service | -|**Producers** | OSOM | -|**Body** | ServiceTestCreate String json | -|**Headers** | "orderid"=orderid, "serviceTestSpecid"= specid | -|**Description** | Creates Service Test based an a Service Test Spec, Returns a ServiceTest object | - ---- - - - - - -| Message | | -| ------------- |----------------| -|**Alias** | CATALOG_UPD_SERVICETEST | -|**Name** | jms:queue:CATALOG.UPD.SERVICETEST | -|**Type** | queue | -|**Destination** | TMF API service | -|**Producers** | | -|**Body** | ServiceTestUpdate | -|**Headers** | "serviceid" = serviceId, "propagateToSO" = true/false | -|**Description** | will update a service test by id and return the service instance. If propagateToSO=true then any service change will be handled by OSOM. This is needed to be controlled in order to avoid update loops| - ---- - - -| Message | | -| ------------- |----------------| -|**Alias** | CATALOG_GET_SERVICETEST_BY_ID | -|**Name** | jms:queue:CATALOG.GET.SERVICETEST | -|**Type** | queue | -|**Destination** | TMF API service | -|**Producers** | OSOM | -|**Body** | String serviceID | -|**Description** | returns a Service TEST instance | - - ---- - -| Message | | -| ------------- |----------------| -|**Alias** | CRD_DEPLOY_CR_REQ | -|**Name** | jms:queue:CRD.DEPLOY.CR_REQ | -|**Type** | queue | -|**Destination** | CRD service | -|**Producers** | OSOM | -|**Body** | CR spec as String | -|**Headers** | related service id | -|**Description** | Returns a String object containing deployment info| - ---- - -| Message | | -| ------------- |----------------| -|**Alias** | CRD_PATCH_CR_REQ | -|**Name** | jms:queue:CRD.PATCH.CR_REQ | -|**Type** | queue | -|**Destination** | CRD service | -|**Producers** | OSOM | -|**Body** | CR as String | -|**Headers** | related service id | -|**Description** | Returns a String object containing PATCH info| - - -| Message | | -| ------------- |----------------| -|**Alias** | CRD_DELETE_CR_REQ | -|**Name** | jms:queue:CRD.DELETE.CR_REQ | -|**Type** | queue | -|**Destination** | CRD service | -|**Producers** | OSOM | -|**Body** | CR as String | -|**Headers** | related service id | -|**Description** | Returns a String object containing deletion info| \ No newline at end of file diff --git a/doc/architecture/nfvapi.md b/doc/architecture/nfvapi.md deleted file mode 100644 index f31f195812fda0c41cf8165c5448c32a4931884c..0000000000000000000000000000000000000000 --- a/doc/architecture/nfvapi.md +++ /dev/null @@ -1,207 +0,0 @@ -# API interaction - -## OAuth token - -See [oauth](./oauth.md) - -## Request a protected API resource - -Example: Get all vxfs (check the `Authorization:Bearer` to be correct) - -``` -curl -H "Authorization:Bearer eybGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbIm9wZW5hcGkiLCJhZG1pbiIsInJlYWQiLCJ3cml0ZSJdLCJvcmdhbml6YXRpb24iOiJteW9yZ2FuaXp0aW9uIiwiZXhwIjoxNTcxOTI0MjU2LCJhdXRob3JpdGllcyI6WyJST0xFX01FTlRPUiIsIlJPTEVfQURNSU4iXSwianRpIjoiNzNkZmIxODEtNTMwOS00MmExLThkOWUtOGM3YmQ0YTE1YmU0IiwiY2xpZW50X2lkIjoib3NhcGlXZWJDbGllbnRJZE91dCJ9.Pj_hxnyMGhFhN8avU_DiAw1-LlcaIz5Hp9HNqalw-X4" http://localhost:13000/osapi/admin/vxfs -``` -Example response: - -``` -[ - { - "id": 1, - "owner": { - "id": 1, - "organization": "ee", - "name": "Portal Administrator", - "email": "", - "username": "admin", - "createdAt": null - }, - "uuid": "a954daf2-16da-4b7e-ae42-4825936d453c", - "name": "cirros_vnfd", - "iconsrc": "/osapi/images/a954daf2-16da-4b7e-ae42-4825936d453c/cirros-64.png", - "shortDescription": "cirros_vnfd", - "longDescription": "Simple VNF example with a cirros", - "version": "1.0", - "packageLocation": "/osapi/packages/a954daf2-16da-4b7e-ae42-4825936d453c/cirros_vnf.tar.gz", - "dateCreated": 1568971426000, - "dateUpdated": 1568981107000, - "categories": [ - { - "id": 3, - "name": "Service", - "productsCount": 1, - "appscount": 0, - "vxFscount": 1 - }, - { - "id": 2, - "name": "Networking", - "productsCount": 1, - "appscount": 0, - "vxFscount": 1 - } - ], - "extensions": [], - "validationJobs": [], - "screenshots": "", - "vendor": "OSM", - "published": false, - "termsOfUse": null, - "descriptor": "vnfd-catalog:\n vnfd:\n - connection-point:\n - name: eth0\n type: VPORT\n description: Simple VNF example with a cirros\n id: cirros_vnfd\n logo: cirros-64.png\n mgmt-interface:\n cp: eth0\n name: cirros_vnfd\n short-name: cirros_vnfd\n vdu:\n - count: 1\n description: cirros_vnfd-VM\n id: cirros_vnfd-VM\n image: cirros034\n interface:\n - external-connection-point-ref: eth0\n name: eth0\n position: '1'\n type: EXTERNAL\n virtual-interface:\n bandwidth: '0'\n type: VIRTIO\n vpci: 0000:00:0a.0\n name: cirros_vnfd-VM\n vm-flavor:\n memory-mb: 512\n storage-gb: 1\n vcpu-count: 1\n vendor: OSM\n version: '1.0'\n", - "descriptorHTML": "<h3>cirros_vnfd</h3><br><b>Vendor: </b>OSM<br><b>Version: </b>1.0<br><b>Description: </b>Simple VNF example with a cirros<br><b>VM Count: </b>1<br><b>vCPU Count: </b>1<br><b>Memory: </b>512 MB<br><b>Storage: </b>1 GB<br>", - "certified": false, - "certifiedBy": null, - "validationStatus": "UNDER_REVIEW", - "packagingFormat": "OSMvFIVE", - "supportedMANOPlatforms": [ - { - "id": 1, - "name": "osm fivee", - "version": "osm fivee", - "description": "osm five" - } - ], - "vxfOnBoardedDescriptors": [], - "vfimagesVDU": [ - { - "id": 1, - "name": "cirros034", - "uuid": "d4549610-8abd-42ad-97f4-0a64e1c93977", - "shortDescription": "Automatically created during vxf cirros_vnfd submission. Owner must update.", - "packageLocation": null, - "publicURL": null, - "dateCreated": 1568971426000, - "dateUpdated": null, - "refVxFs": [ - { - "id": 1, - "name": "cirros_vnfd" - } - ], - "owner": { - "id": 1, - "organization": "ee", - "name": "Portal Administrator", - "email": "", - "username": "admin", - "active": true, - "currentSessionID": null, - "apikey": "e41c1cc4-aa56-4b7e-9f4d-64589549d768", - "createdAt": 1568711859000, - "roles": [ - "ADMIN", - "MENTOR" - ] - }, - "published": false, - "termsOfUse": null, - "deployedInfrastructures": [] - } - ] - }, - { - "id": 2, - "owner": { - "id": 1, - "organization": "ee", - "name": "Portal Administrator", - "email": "", - "username": "admin", - "createdAt": null - }, - "uuid": "4ab80095-a63e-4fe7-8598-e1c7e880706e", - "name": "cirros_sriov_vnfd", - "iconsrc": null, - "shortDescription": "cirros_sriov_vnf", - "longDescription": "Simple VNF example with a cirros SRIOV interface", - "version": "1.0", - "packageLocation": "/osapi/packages/4ab80095-a63e-4fe7-8598-e1c7e880706e/cirros_sriov.tar.gz", - "dateCreated": 1568971740000, - "dateUpdated": 1568981100000, - "categories": [ - { - "id": 4, - "name": "tyu", - "productsCount": 1, - "appscount": 0, - "vxFscount": 1 - }, - { - "id": 5, - "name": "tyi", - "productsCount": 1, - "appscount": 0, - "vxFscount": 1 - } - ], - "extensions": [], - "validationJobs": [], - "screenshots": "", - "vendor": "OSM", - "published": false, - "termsOfUse": null, - "descriptor": "vnfd:vnfd-catalog:\n vnfd:\n - connection-point:\n - name: eth0\n type: VPORT\n - name: eth1\n type: VPORT\n description: Simple VNF example with a cirros SRIOV interface\n id: cirros_sriov_vnfd\n logo: cirros-64.png\n mgmt-interface:\n cp: eth0\n name: cirros_sriov_vnf\n short-name: cirros_sriov_vnf\n vdu:\n - count: 1\n description: cirros_sriov_vnfd-VM\n guest-epa:\n cpu-pinning-policy: DEDICATED\n cpu-thread-pinning-policy: PREFER\n mempage-size: SMALL\n numa-node-policy:\n mem-policy: STRICT\n node:\n - id: '1'\n node-cnt: '1'\n id: cirros_sriov_vnfd-VM\n image: cirros-0.3.6-x86_64\n interface:\n - external-connection-point-ref: eth0\n name: eth0\n position: '1'\n type: EXTERNAL\n virtual-interface:\n bandwidth: '0'\n type: VIRTIO\n vpci: 0000:00:0a.0\n - external-connection-point-ref: eth1\n name: eth1\n position: '2'\n type: EXTERNAL\n virtual-interface:\n type: SR-IOV\n name: cirros_sriov_vnfd-VM\n vm-flavor:\n memory-mb: 4096\n storage-gb: 10\n vcpu-count: 4\n vendor: OSM\n version: '1.0'\n", - "descriptorHTML": "<h3>cirros_sriov_vnf</h3><br><b>Vendor: </b>OSM<br><b>Version: </b>1.0<br><b>Description: </b>Simple VNF example with a cirros SRIOV interface<br><b>VM Count: </b>1<br><b>vCPU Count: </b>1<br><b>Memory: </b>4096 MB<br><b>Storage: </b>10 GB<br>", - "certified": false, - "certifiedBy": null, - "validationStatus": "UNDER_REVIEW", - "packagingFormat": "OSMvFIVE", - "supportedMANOPlatforms": [ - { - "id": 1, - "name": "osm fivee", - "version": "osm fivee", - "description": "osm five" - } - ], - "vxfOnBoardedDescriptors": [], - "vfimagesVDU": [ - { - "id": 2, - "name": "cirros-0.3.6-x86_64", - "uuid": "be121176-1d62-4a1b-a3c1-7dce2e069d22", - "shortDescription": "Automatically created during vxf cirros_sriov_vnfd submission. Owner must update.", - "packageLocation": null, - "publicURL": null, - "dateCreated": 1568971740000, - "dateUpdated": null, - "refVxFs": [ - { - "id": 2, - "name": "cirros_sriov_vnfd" - } - ], - "owner": { - "id": 1, - "organization": "ee", - "name": "Portal Administrator", - "email": "", - "username": "admin", - "active": true, - "currentSessionID": null, - "apikey": "e41c1cc4-aa56-4b7e-9f4d-64589549d768", - "createdAt": 1568711859000, - "roles": [ - "ROLE_ADMIN", - "ROLE_MENTOR" - ] - }, - "published": false, - "termsOfUse": null, - "deployedInfrastructures": [] - } - ] - } -] -``` - - diff --git a/doc/architecture/nfvweb.md b/doc/architecture/nfvweb.md deleted file mode 100644 index b96dee34a9662e14f4c5eb3f41f507817686b094..0000000000000000000000000000000000000000 --- a/doc/architecture/nfvweb.md +++ /dev/null @@ -1,11 +0,0 @@ -# Openslice NFV Web Portal - -The [NFV Web Portal](http://portal.openslice.io/nfvportal) offers a domain-specific UI to manage NFV Services. - -Indicatively, the portal can be used to: -- Register new a new MANO provider (e.g. OSM) -- Synchronize the onboarded VNF/NS packages, and the VIMs of the registered MANO provider -- Onboard/Delete VNF/NS packages on specific MANO provider -- Deploy a NS to a target MANO provider - -More information can be found at [NFV Services](../nfvcatalogs.md). \ No newline at end of file diff --git a/doc/architecture/oauth.md b/doc/architecture/oauth.md deleted file mode 100644 index e836842620424d03e68971f2406eba6d11269d7c..0000000000000000000000000000000000000000 --- a/doc/architecture/oauth.md +++ /dev/null @@ -1,35 +0,0 @@ -# Authentication Server - -Authentication is based on oAuth2. Our authentication service is a Keycloak server which is deployed with Openslice deployment - -API users needs to authenticate. -All APIs (except grant token request) must include Bearer token in request Authorization header. - - - -##OAuth token - -Get first an oauth token, using your username and password. -``` -curl -X POST http://portal.openslice.io/auth/realms/openslice/protocol/openid-connect/token -H 'Content-Type: application/x-www-form-urlencoded' -d 'username=demouser' -d 'password=demouser' -d 'grant_type=password' -d 'client_id=osapiWebClientId' -``` -response: - -``` - {"access_token":"eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJHZFRjQnpxczg2VW10NTRVZV8ybTJyWHJkV3dzaWdSZE9EUldMYm1memNvIn0.eyJleHAiOjE1ODgyNDA1NzAsImlhdCI6MTU4ODI0MDI3MCwianRpIjoiOGI2ZTU0NWUtNDIyYy00NzFiLWEwN2UtYTUzYzY1NDQ0MzZmIiwiaXNzIjoiaHR0cDovL3BvcnRhbC5vcGVuc2xpY2UuaW8vYXV0aC9yZWFsbXMvb3BlbnNsaWNlIiwiYXVkIjoiYWNjb3VudCIsInN1YiI6ImExYTI3NjVhLWVjODMtNDQ1Ni1iN2IyLTIwNzMxOTg2ZTAzNSIsInR5cCI6IkJlYXJlciIsImF6cCI6Im9zYXBpV2ViQ2xpZW50SWQiLCJzZXNzaW9uX3N0YXRlIjoiMzM1MGY0OTMtNjYyNy00MzczLTg1NDQtZGVmZDI3YWQzYzc0IiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyJodHRwOi8vbG9jYWxob3N0OjEzMDgyIiwiaHR0cDovL2xvY2FsaG9zdCIsImh0dHA6Ly9vcGVuc2xpY2UuaW8iLCJodHRwOi8vbG9jYWxob3N0OjEzMDAwIiwiaHR0cDovL2xvY2FsaG9zdDo0MjAwIiwiaHR0cDovL3BvcnRhbC5vcGVuc2xpY2UuaW8iXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbIk5GVl9ERVZFTE9QRVIiLCJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIiwiRVhQRVJJTUVOVEVSIiwiVVNFUiJdfSwicmVzb3VyY2VfYWNjZXNzIjp7ImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyIsInZpZXctcHJvZmlsZSJdfX0sInNjb3BlIjoicHJvZmlsZSBlbWFpbCIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJkZW1vdXNlciJ9.TnzzpRLMD94UTKpT5_wkr1h4_3KUQmr4TGvFLpJ7cZx-Klrv8tB_eRkWnPqqzCAM9G21a1qXboL8MLMW8ECzG7HYKpobKOGr7LSczMOTdA2ZDyBCRUSOdW77pchu54tJ0ITEkFaDwSKMKKt04V_Sy4U-eIndj0XzzRlkDolWDnK4Z2lRaXAI6fMwOKx1Toa6RfOcemxtzl3pdtjPx92zo6MaKlbIqHK82lxdK0k8aQQaT6TmIrXbZKV2dU_1d3O0q0dVUEZJ_1kzwqOFkmxr9w0EnndC6ccYJlDAr_-GgUhhhNOn5v6tjYLUQdj5e4KEAsxIPzaCreK4un7mEAPmDw","expires_in":300,"refresh_expires_in":1800,"refresh_token":"eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICIwZjUxMDk5Yy0wNTIzLTRjNGQtODM0Zi1iNDc0YzBjOTA1MzkifQ.eyJleHAiOjE1ODgyNDIwNzAsImlhdCI6MTU4ODI0MDI3MCwianRpIjoiZmViOTg5NWEtOTY5ZS00MzIzLWJjY2QtZTY2YzQ0NGE1MzJlIiwiaXNzIjoiaHR0cDovL3BvcnRhbC5vcGVuc2xpY2UuaW8vYXV0aC9yZWFsbXMvb3BlbnNsaWNlIiwiYXVkIjoiaHR0cDovL3BvcnRhbC5vcGVuc2xpY2UuaW8vYXV0aC9yZWFsbXMvb3BlbnNsaWNlIiwic3ViIjoiYTFhMjc2NWEtZWM4My00NDU2LWI3YjItMjA3MzE5ODZlMDM1IiwidHlwIjoiUmVmcmVzaCIsImF6cCI6Im9zYXBpV2ViQ2xpZW50SWQiLCJzZXNzaW9uX3N0YXRlIjoiMzM1MGY0OTMtNjYyNy00MzczLTg1NDQtZGVmZDI3YWQzYzc0Iiwic2NvcGUiOiJwcm9maWxlIGVtYWlsIn0.cDTx9BE1Df8EfGYm3VLr_MNFeymxZtJhMtlK7PVbIuk","token_type":"bearer","not-before-policy":1586797346,"session_state":"3350f493-6627-4373-8544-defd27ad3c74","scope":"profile email"} - -``` - -The `access_token` will be used next as a Bearer. - -``` -curl http://portal.openslice.io/tmf-api/serviceCatalogManagement/v4/serviceCatalog -H 'Authorization: Bearer yJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJHZFRjQnpxczg2VW10NTRVZV8ybTJyWHJkV3dzaWdSZE9EUldMYm1memNvIn0.eyJleHAiOjE1ODgyNDA1MjQsImlhdCI6MTU4ODI0MDIyNCwianRpIjoiYjg0NGYxZDAtMzk3Mi00YTMyLThiMWEtZDAxMDY3OGZjMTQ4IiwiaXNzIjoiaHR0cDovL3BvcnRhbC5vcGVuc2xpY2UuaW8vYXV0aC9yZWFsbXMvb3BlbnNsaWNlIiwic3ViIjoiYTFhMjc2NWEtZWM4My00NDU2LWI3YjItMjA3MzE5ODZlMDM1IiwidHlwIjoiQmVhcmVyIiwiYXpwIjoiYWRtaW4tY2xpIiwic2Vzc2lvbl9zdGF0ZSI6ImFmMmMzZmY1LTE4YWQtNDFkNC1hYTAyLTFlMGJkNzNmOTM5MSIsImFjciI6IjEiLCJzY29wZSI6InByb2ZpbGUgZW1haWwiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwicHJlZmVycmVkX3VzZXJuYW1lIjoiZGVtb3VzZXIifQ.SMtgV1E44_K_MQumGXZtWsLGVhYNaoM8Pk-DiFIZtUP4Zu-ervOsxHVQMX1frgVERR4jJidBcSshy9TnJ3UjF4l33WujHltbs-1UPy-gaIufVuEpl8RmbjOti3Up70vLfLXbzb6kN6WaahgobWXlbJsSXXwaBPQP6vSX5KigCa8TmzXcuqom14lOrlU-RB2zQTlJ30p7d9ag-a7o3I5m9GZWLJCZW2UYMl1JkskTHKgilA8HFQY4C9DYwWu8YDMyzqQSNumrTlURalBFidFbZvb1kp4dAyct8TysSWSbxxiwaL2RX1PWUqk-5Fpc1Q6BnBC8muMheiukFuoSkuADAg'^C -ubuntu@portal:~$ curl http://portal.openslice.io/tmf-api/serviceCatalogManagement/v4/serviceCatalog -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJHZFRjQnpxczg2VW10NTRVZV8ybTJyWHJkV3dzaWdSZE9EUldMYm1memNvIn0.eyJleHAiOjE1ODgyNDA1NzAsImlhdCI6MTU4ODI0MDI3MCwianRpIjoiOGI2ZTU0NWUtNDIyYy00NzFiLWEwN2UtYTUzYzY1NDQ0MzZmIiwiaXNzIjoiaHR0cDovL3BvcnRhbC5vcGVuc2xpY2UuaW8vYXV0aC9yZWFsbXMvb3BlbnNsaWNlIiwiYXVkIjoiYWNjb3VudCIsInN1YiI6ImExYTI3NjVhLWVjODMtNDQ1Ni1iN2IyLTIwNzMxOTg2ZTAzNSIsInR5cCI6IkJlYXJlciIsImF6cCI6Im9zYXBpV2ViQ2xpZW50SWQiLCJzZXNzaW9uX3N0YXRlIjoiMzM1MGY0OTMtNjYyNy00MzczLTg1NDQtZGVmZDI3YWQzYzc0IiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyJodHRwOi8vbG9jYWxob3N0OjEzMDgyIiwiaHR0cDovL2xvY2FsaG9zdCIsImh0dHA6Ly9vcGVuc2xpY2UuaW8iLCJodHRwOi8vbG9jYWxob3N0OjEzMDAwIiwiaHR0cDovL2xvY2FsaG9zdDo0MjAwIiwiaHR0cDovL3BvcnRhbC5vcGVuc2xpY2UuaW8iXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbIk5GVl9ERVZFTE9QRVIiLCJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIiwiRVhQRVJJTUVOVEVSIiwiVVNFUiJdfSwicmVzb3VyY2VfYWNjZXNzIjp7ImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyIsInZpZXctcHJvZmlsZSJdfX0sInNjb3BlIjoicHJvZmlsZSBlbWFpbCIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJkZW1vdXNlciJ9.TnzzpRLMD94UTKpT5_wkr1h4_3KUQmr4TGvFLpJ7cZx-Klrv8tB_eRkWnPqqzCAM9G21a1qXboL8MLMW8ECzG7HYKpobKOGr7LSczMOTdA2ZDyBCRUSOdW77pchu54tJ0ITEkFaDwSKMKKt04V_Sy4U-eIndj0XzzRlkDolWDnK4Z2lRaXAI6fMwOKx1Toa6RfOcemxtzl3pdtjPx92zo6MaKlbIqHK82lxdK0k8aQQaT6TmIrXbZKV2dU_1d3O0q0dVUEZJ_1kzwqOFkmxr9w0EnndC6ccYJlDAr_-GgUhhhNOn5v6tjYLUQdj5e4KEAsxIPzaCreK4un7mEAPmDw' - -Response: - - -[{"uuid":"9e186cd5-b2b2-4a06-b1d6-895720193bc9","lastUpdate":"2020-03-11T23:19:05Z","@baseType":"BaseEntity","@schemaLocation":null,"@type":"ServiceCatalog","href":null,"name":"Example Facility Services","description":"Example Facility Services","lifecycleStatus":"Active","version":"1.0","validFor":{"endDateTime":"2039-11-20T23:07:21Z","startDateTime":"2019-11-20T23:07:21Z"},"relatedParty":null,"id":"9e186cd5-b2b2-4a06-b1d6-895720193bc9","category":[{"@baseType":"org.etsi.osl.tmf.scm633.model.ServiceCategoryRef","@schemaLocation":null,"@type":"org.etsi.osl.tmf.scm633.model.ServiceCategoryRef","href":null,"name":"Generic Services","@referredType":null,"id":"98b9adf1-a1d6-4165-855f-153ddc2131b1"},{"@baseType":"org.etsi.osl.tmf.scm633.model.ServiceCategoryRef","@schemaLocation":null,"@type":"org.etsi.osl.tmf.scm633.model.ServiceCategoryRef","href":null,"name":"External","@referredType":null,"id":"08ffdb3c-6237-45d0-9f3a-d43b5fc5f0b6"},{"@baseType":"org.etsi.osl.tmf.scm633.model.ServiceCategoryRef","@schemaLocation":null,"@type":"org.etsi.osl.tmf.scm633.model.ServiceCategoryRef","href":null,"name":"eMBB","@referredType":null,"id":"ef2c90dd-b65e-4a9f-a9c3-427c9fb0219b"}]}] - - -``` \ No newline at end of file diff --git a/doc/architecture/osom.md b/doc/architecture/osom.md deleted file mode 100644 index 173aa8017d603bb3854eb6b4c0e9baa905e512f6..0000000000000000000000000000000000000000 --- a/doc/architecture/osom.md +++ /dev/null @@ -1,137 +0,0 @@ -# Openslice Service Orchestration and Order Management - OSOM - -OSOM is a service responsible for: - -* Service Order Management (SOM) -* Service Orchestration (SO) - -It uses open source Flowable Business process engine (https://www.flowable.org) . - -A Service Order follows the states as defined in TMF641 specification: - -[](../images/service_order_states.png) - - -## Initial state - -When a new order is created, it goes into the Initial state. It is stored in the repository and triggers an Event. - -[](../images/service_order_initial_state.png) - -Administrators are notified usually from the Ticketing System of a new order. They login to Openslice and change the State of the order either to ACKNOWLEDGED or REJECTED. If ACKNOWLEDGED they can Propose a startDate, add Notes, and add any additional service items - -## Order scheduler - -A process checks every 1 minute for ACKNOWLEDGED orders. - -[](../images/order_scheduler_bpm.png) - -[](../images/order_scheduler_diagram.png) - -It retrieves all orders that are in ACKNOWLEDGED state and if the start date is in time it will initialize the process by settingn the order in IN_PROGRESS state. Finally the Start Order Process will start. - - -## Start order process - -This process for now is a draft simple prototype to make a simple orchestration via NFVO. Here the actual Services (TMF638/640 model) are created and attached to Service Order and Service Inventory. - -[](../images/start_order_process_bpm.png) - -[](../images/start_order_process_diagram.png) - -We expect here to check which tasks can be orchestrated by NFVO and which by human. We create the equivalent Services(TMF638/640 model) for this order. - -1. During check it should decide to create Service(s) for this service order O1 and send it to ServiceInventory -2. The Services(TMF638 model) are assigned to the Order O1 In supportService List -3. Each OrderItem OI1 is related to one serviceSpecification -4. Each ServiceSpecification has also related serviceSpecRelationships -5. So if we receive an order O1 for a ServiceSpec A which relates to (a bundle of) 3 specs(2 CFS, 1 RFS) we do the following: - 1. Create a Service S_A(TMF638 model) for ServiceSpec A for Order O1 - 2. We create also 3 Services S_C1, S_C2 and S_R1 equivalent to the serviceSpecRelationships (2 CFS, 1 RFS) - 3. At this point the order will have 1 Local Service Orchestration Process(S_A), 2 supportingServices refs(S_C1, S_C2) and 1 supportingResource(S_R1) - 4. The 3 supportingServices and 1 supportingResource correspond to total 4 Services in ServiceInventory - 5. Service S_A will have: - 1. startMode 1: Automatically by the managed environment - 2. State: RESERVED and the Lifecycle will be handled by OSOM - 6. Services S_C1 and S_C2 we decide that cannot be orchestrated then they have - 1. startMode: 3: Manually by the Provider of the Service - 2. State: RESERVED and the Lifecycle will be handled by OSOM - 3. If the CFS is a bundle spec it is further recursively orchestrated - 7. Service S_R1 will have - 1. startMode 1: Automatically by the managed environment. - 2. State: RESERVED - 3. IF The Service has the characteristic CharacteristicByName( "NSDID") it will be further processed by the NFVO - - -There will be two instances of task "User Task Manual Complete Service" each for Services S_C1 and S_C2. The task is Transient for now. It displays only the services that are not automated! -Here is a flow for future: - -1. We wait here for human decision. -2. From API we get a result: - a. If set to ACTIVE/TERMINATED then we complete the task - b. In any other state we stay in this task until it is resolved as in step a - c. The Status of ORDER O1 is also updated to PARTIAL - -There will be an instance of NFVODeploymentRequest process each for Service S_R1. (see later) - -1. This process is related with the NFVO orchestration -2. It will send a msg to NFVO(s?) for a specific deployment request - - -All services in "Order Complete" are in a status: - -1. Depending on the result the service S_A is either ACTIVE or INACTIVE or TERMINATED -2. The Status of ORDER O1 is also updated to COMPLETED or PARTIAL (in case we have some services running) or FAILED (in cases we have errors) - - -A Service follows the states as defined in TMF638 Service Inventory specification: - -[](../images/service_states.png) - - - -## NFVODeploymentRequest process - - -[](../images/NFVODeploymentReq_process.png) - -This process is related with the NFVO orchestration -It will send a msg to NFVO(s?) for a specific deployment request -Then it checks the deployment status. It will wait 30 secs each time until the deployment is running (or failed) - - - -## Check In Progress orders process - -Every 1 minute the "Check In Progress Orders" process is executed checking if a supported Service changed state (i.e. to ACTIVE) then the whole Order will change state (e.g. go to COMPLETED) - -[](../images/check_inProgress_orders.png) - - -## External Service Provider Deployment Request process - -[](../images/externalSPDeploymentReq.png) - -This process contains tasks for submitting order requests to external partners. -- Submit Order To External Service Provider Task: This task creates automatically a Service Order request to a 3rd party provider SO that hosts the Service Specification -- Check external service order fulfillment task: This task Check external partner for Service creations and updates our local inventory of services the service characteristics of remote Service Inventory - - -## Fetch Partner Services Process - - -[](../images/fetchPartnerServices.png) - -Every 2 minutes the "fetchPartnerServicesProcess" process is executed checking remote Partner Organizations for changes in the published catalogues. -The Fetch and Update External Partner Services Task is executed in paralle l for each Partner Organization - - -## Local Service Orchestration Process - - -[](../images/LocalServiceOrchestrationProcess.png) - -This process handles automatically services that need to be further orchestrated or processed by OSOM. For example, for a CFS Bundled service we create such automated service instances that just aggregate the underlying services. - - - \ No newline at end of file diff --git a/doc/architecture/tmfapi.md b/doc/architecture/tmfapi.md deleted file mode 100644 index f7944969741681c840db830a70fc688a0224295e..0000000000000000000000000000000000000000 --- a/doc/architecture/tmfapi.md +++ /dev/null @@ -1,65 +0,0 @@ -# TMF OpenAPI specification - -PLease check the complete specification [here](http://portal.openslice.io/tmf-api/swagger-ui/index.html). - -## API interaction - -### OAuth token - -See [oauth](./oauth.md) - -### Request a protected API resource - -Example: Get all Service Catalogs (check the `Authorization:Bearer` to be correct) - -``` -curl -H "Authorization:Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbIm9wZW5hcGkiLCJhZG1pbiIsInJlYWQiLCJ3cml0ZSJdLCJvcmdhbml6YXRpb24iOiJteW9yZ2FuaXp0aW9uIiwiZXhwIjoxNTc4NTA1MDcyLCJhdXRob3JpdGllcyI6WyJST0xFX01FTlRPUiIsIlJPTEVfQURNSU4iXSwianRpIjoiMTFlNGYxYTUtZDY0Ny00YzA1LWE0ZGMtYWFhYzUyMjk4YzMwIiwiY2xpZW50X2lkIjoib3NhcGlXZWJDbGllbnRJZE91dCJ9.gm7cKdusDrdMRkxEiFU5sENKGRC1xwVj2SgPRmE9xxx" -H "accept: application/json;charset=utf-8" -X GET "http://portal.openslice.io/tmf-api/serviceCatalogManagement/v4/serviceCatalog" - -``` - - -response: - - -``` -[ - { - "uuid": "9e186cd5-b2b2-4a06-b1d6-895720193bc9", - "lastUpdate": "2019-12-19T10:45:55Z", - "@baseType": "BaseEntity", - "@schemaLocation": null, - "@type": "ServiceCatalog", - "href": null, - "name": "Example Facility Services", - "description": "Example Facility Services", - "lifecycleStatus": "Active", - "version": "1.0", - "validFor": { - "endDateTime": "2039-11-20T23:07:21Z", - "startDateTime": "2019-11-20T23:07:21Z" - }, - "relatedParty": null, - "id": "9e186cd5-b2b2-4a06-b1d6-895720193bc9", - "category": [ - { - "@baseType": "org.etsi.osl.tmf.scm633.model.ServiceCategoryRef", - "@schemaLocation": null, - "@type": "org.etsi.osl.tmf.scm633.model.ServiceCategoryRef", - "href": null, - "name": "eMBB", - "@referredType": null, - "id": "ef2c90dd-b65e-4a9f-a9c3-427c9fb0219b" - }, - { - "@baseType": "org.etsi.osl.tmf.scm633.model.ServiceCategoryRef", - "@schemaLocation": null, - "@type": "org.etsi.osl.tmf.scm633.model.ServiceCategoryRef", - "href": null, - "name": "Generic Services", - "@referredType": null, - "id": "98b9adf1-a1d6-4165-855f-153ddc2131b1" - } - ] - } -] -``` \ No newline at end of file diff --git a/doc/architecture/tmfweb.md b/doc/architecture/tmfweb.md deleted file mode 100644 index 729eed65fa1833982885623ca9108e67b44ab20c..0000000000000000000000000000000000000000 --- a/doc/architecture/tmfweb.md +++ /dev/null @@ -1,39 +0,0 @@ -# Openslice TMF Web Portal - -Openslice comprises of a [web landing page](http://portal.openslice.io/) that navigates to the respective TMF Portal. - -- [Services Portal](http://portal.openslice.io/services) -- [Products Portal](http://portal.openslice.io/products) -- [Testing Portal](http://portal.openslice.io/testing) -- [Resources Portal](http://portal.openslice.io/resources) - -The landing page and the TMF portals (Services, Products, Testing, Resources) are written in Angular and are maintained under the same Angular project. - -Following you may find the scope each portal focuses on and the main TMF APIs it supports. - -**Services Portal** is a designated portal for the: -- Service Designer - To design Customer Facing Services as bundles of Resource Facing Services that map to specific Resourses (e.g. NFV, Testing, General Resources). Then, it is charged with the designed Services' exposure to public Service Catalogs. -- Service Customer - To browse the public Service Catalogs and order the offered Services. The fulfilment process of the Service Order is also captured and the final deployed Services are exposed to the Customer. - -**Products Portal** is a designated portal for the: -- Product Designer - To design Products as bundles of available Services. Then, it is charged with the designed Products' exposure to public Product Catalogs. -- Product Customer - To browse the public Product Catalogs and navigate to the respective offered Services. - -**Testing Portal** is a designated portal for the: -- Testing Designer - To design Tests and provide the testing scripts as attachments to the latter. The Tests can be imported as Services at the Services Portal, and can be included in a Service Bundle. - -**Resources Portal** is a designated portal for the: -- Resource Administrator - To view the available Resources that are being synchronized from the underlying infrastructure. - - - - -| | TMF620 | TMF632 | TMF633 | TMF634 | TMF638 | TMF639 | TMF640 | TMF641 | TMF642 | TMF653 | TMF685 | -| ------------- |:------:|:------:|:------:|:------:|:------:|:------:|:------:|:------:|:------:|:------:|:------:| -|**Services Portal** | |x |x | |x | |x |x |x | | | -|**Products Portal** |x |x | | | | | | | | | | -|**Testing Portal** | |x | | | | | | | |x | | -|**Resources Portal** | |x | |x | |x | | | | |x | - - -From the landing page, the user can also navigate towards the NFV portal. See [NFV WEB](./nfvweb.md). \ No newline at end of file diff --git a/doc/contributing/developing.md b/doc/contributing/developing.md deleted file mode 100644 index e8939eeca651aadf2bedef512ed8009df305b4aa..0000000000000000000000000000000000000000 --- a/doc/contributing/developing.md +++ /dev/null @@ -1,89 +0,0 @@ - -# Developing - -OpenSlice backend services are mainly implemented with Java 17 or above and Spring boot. - -OpenSlice uses various subsystems and depending on the module would you like to work, other subsystems must be present (you can disable them though in the code, e.g. at docker-compose.yaml file). - -To get the latest development branch: -```bash -wget https://labs.etsi.org/rep/osl/code/org.etsi.osl.main/-/raw/develop/compose/deploy.sh -sudo ./deploy.sh develop #[or replace develop with other branch name] -``` - -You may follow the [installation process](https://osl.etsi.org/documentation/develop/deployment/), as described at "develop" tagged documentation. - -To work on a specific subsystem e.g. org.etsi.osl.tmf.api, you must: - -1a - Deploy only the core necessary subsystems through: -```bash -sudo docker compose --profile dev down;sudo docker compose --profile dev up -d --build -``` -> Note **--profile dev** that will only deploy the core dependency subsystems, instead of the whole OpenSlice. - -1b - Or alternatively, commend out the respective container from the docker-compose.yaml file, so as to deploy the whole OpenSlice, except the subsystem you want to work on, following the provided installation steps. - -2 - Clone the respective repository, e.g. https://labs.etsi.org/rep/osl/code/org.etsi.osl.tmf.api/-/tree/develop - -3 - Code :) - -## General requirements - -- Docker should be installed in your development environment -- Run the core subsystems (see above section) - - -## Slack - -Feel free to join OpenSlice [Slack](https://openslice.slack.com) for any development oriented questions. - -## Examples of developing on specific subsystems - -### VNF/NSD Catalog Management and NSD Deployment API service - -Clone the repository: https://labs.etsi.org/rep/osl/code/org.etsi.osl.portal.api/-/tree/develop - -Check the docker-compose.yml file. Default port is 13080. Check specifically the datasource username/password, server port. - -Make sure that the core subsystems are up and running. - -Execute it with -```bash -mvn spring-boot:run -``` - -For verification, Swagger API of the service is at `http://localhost:13000/osapi/swagger-ui/index.html`. - -There, you may try there various REST actions and authenticate via the OAuth server without the use of the UI. - - -### VNF/NSD Catalog Management and NSD Deployment WEB UI service - -The Web UI is written in AngularJS. - -Clone the repository: https://labs.etsi.org/rep/osl/code/org.etsi.osl.portal.web/-/tree/develop - -By default the project org.etsi.osl.portal.api exposes the folder ../org.etsi.osl.portal.web/src/ in a folder testweb (Check class MvcConfig.java in org.etsi.osl.portal.api) for development. (In production nginx is used). Point your browser to `http://localhost:13000/osapi/testweb/index.html/` - -## Version/release management - -Check this nice article on how we develop and release versions. - -https://nvie.com/posts/a-successful-git-branching-model/ - -We develop in the develop branch and follow a issue driven development model. - ---- -## Wishlist - -Check also our wishlist of new features. You can add your own. - -See [Wishlist](./wishlist.md). - - - - - - - - diff --git a/doc/contributing/wishlist.md b/doc/contributing/wishlist.md deleted file mode 100644 index de91c7741f0ed1a31bf6cd0e0802c2dccdf114aa..0000000000000000000000000000000000000000 --- a/doc/contributing/wishlist.md +++ /dev/null @@ -1,59 +0,0 @@ -# TMF API - -- RBAC of API endpoints -- TMF Ticketing API support -- TMF Product -- HATEOAS integration -- Select Specs that can be exposed to partners (maybe with a characteristic?) - -## resource management - -- Resource Activation and Configuration API TMF702 (NEW) (https://projects.tmforum.org/wiki/pages/viewpage.action?pageId=128855518) - -# TMF WEB - - -# OSOM - -- Actions on service order item and acknowledge order status will define the lifecycle -- action shutdown on specific date for service order -- action edit on service order item - -## Dynamic attribute transformation - -- DTM decision tables support per Service Specification -- Schedule Termination of completed order on running services - - - -# NFVO connectivity - -## OSM Client - -- VNF/NSD config params Day 2 -- NSD Lifcecylce -- NST support - -# NFV API - - -# NFV WEB - - -# 3rd party connectivity - -## FlowOne connector - - -## Openstack connector - - -## Kubernetes connector - - -# CentralLog - -- Events from TMF to be written to Central Log - -# Authentication - diff --git a/doc/deployment.md b/doc/deployment.md deleted file mode 100644 index df703d7c45cd06a954bcd341db50c587f4dbf5be..0000000000000000000000000000000000000000 --- a/doc/deployment.md +++ /dev/null @@ -1,646 +0,0 @@ -## Requirements - -### Hardware requirements: - - -| **Minimum Hardware Requirements** | **Recomended Hardware Requirements** | -| --------------------------------- | ------------------------------------ | -| 4 CPU cores | 8 CPU cores | -| 8 GB RAM | 16 GB RAM | -| 20 GB storage | 40 GB storage | - -### Software Requirements: - -* Docker (Docker Compose installation) -* Kubernetes (Kubernetes installation - experimental) - - -## Preparing the environment - -> See the [Kubernetes section](#Kubernetes-installation), if you would like to deploy OpenSlice in a Kubernetes cluster. - - -### 1. Backup your previous database if necessary: -```bash -sudo docker exec amysql /usr/bin/mysqldump -u root --password=letmein ostmfdb > backup_ostmfdb.sql -``` -### 2. Install docker - -> Since July 2023 Docker Compose V1 stopped receiving updates. OpenSlice fully reverted to Compose V2, which is integrated in the Docker installation. - -### 3. Configure containers to properly resolve the DNS of your domain (optional) - -``` -sudo nano /etc/docker/daemon.json -``` - -and add: - -``` -{ - "dns": ["8.8.8.8", "8.8.4.4"] -} -``` -After editing daemon.json restart docker daemon for the changes to take place - -```bash -sudo systemctl restart docker -``` - -## Downloading the project - -### 1. Create a new folder to download the project - -```bash -mkdir openslice -``` -```bash -cd openslice -``` - -### 2. Download the deployment script - -Download the deployment / environment preparation script - -```bash -wget https://labs.etsi.org/rep/osl/code/org.etsi.osl.main/-/raw/main/compose/deploy.sh -``` -Make it executable -```bash -sudo chmod +x deploy.sh -``` - -### 3. Run the deployment script - -OpenSlice is a multi repo project. This script selects the same branch for all repositories of the project to pull from. - -After that it builds the respective jar files locally and installs all the npm packages needed for the UI. - -If you run the script without selecting a branch the the main branch is going to be selected. - -We recommend: - -* main branch for the most stable experience and -* develop branch for an experience with the latest features (for develop branch installation, it is strongly advisable that you may as well follow the [develop documentation](https://osl.etsi.org/documentation/develop/deployment/)) - -```bash -sudo ./deploy.sh main #[or replace main with other branch name] -``` - -> **We recommend running the deploy.sh script with root permissions! In other case, some directories may not be accessible by the project building tools and hinder the smooth installation.** - - -## Configure docker-compose services - -### 1. Create configuration specific Docker Compose file from the template - -```bash -cd org.etsi.osl.main/compose/ -``` -```bash -sudo cp docker-compose.yaml.configure docker-compose.yaml -``` -### 2. Configure mysql-portal container *(optional)* - -1. In folder `org.etsi.osl.main/compose/mysql-init` edit the file `01-databases.sql`. -2. In the `org.etsi.osl.main/compose/docker-compose.yaml` edit the credentials of the users that services use to connect to the databases, if you wish. - * portaluser (default is 12345) and - * keycloak (default is password) - - -### 3. Configure keycloak container *(optional)* - -1. If you made changes to keycloak's mysql credentials: - - In folder `org.etsi.osl.main/compose/` edit the file `docker-compose.yaml`. - -``` -DB_DATABASE: keycloak -DB_USER: keycloak -DB_PASSWORD: password -``` - -2. If you want to change the keycloak admin password: - - In folder `org.etsi.osl.main/compose/` edit the file `docker-compose.yaml` - -``` -KEYCLOAK_PASSWORD: Pa55w0rd -``` - -### 4. Configure bugzilla container *(optional)* - -If you want to utilise the Bugzilla connector: - -In folder `org.etsi.osl.main/compose/` edit the file `docker-compose.yaml` - -``` -SPRING_APPLICATION_JSON: '{ - "spring.activemq.brokerUrl": "tcp://anartemis:61616?jms.watchTopicAdvisories=false", - "spring.activemq.user": "artemis", - "spring.activemq.password": "artemis", - "bugzillaurl":"", - "bugzillakey":"", - "main_operations_product":"" -}' -``` - -And add the provided Bugzilla installation information: - -``` -"bugzillaurl":"bugzillaurl.xx:443/bugzilla/", -"bugzillakey":"exampleKeyeqNNwxBlgxZgMEIne0Oeq0Bz", -"main_operations_product":"Main Site Operations" // this is the default product to issue tickets -``` - -Bugzilla should have the following components under the specified product: - -* NSD Deployment Request: Component used to schedule deployment req -* Onboarding: Issues related to VNF/NSD Onboarding -* Operations Support: Default component for operations support -* Validation: Use to track validation processes of VNFs and NSDs -* VPN Credentials/Access: Used for requesting VPN Credentials/Access - -Also in the 'Main Site Operations' product, a version named 'unspecified' must be created. - -### 5. Configure osportalapi container (NFV services) *(conditional)* - -Change the respective fields: - -- If you made changes to mysql and keycloak credentials. -- If you want to change logging level (TRACE / DEBUG / INFO / WARN / ERROR). - -> ***If you are using a non-local domain, replace everywhere the http://keycloak:8080 with the respective {{protocol://domain.name}}, as well as "spring.portal.main.domain" property.*** - -In folder `org.etsi.osl.main/compose/` edit the file `docker-compose.yaml` - -``` -SPRING_APPLICATION_JSON: '{ - "spring.datasource.username":"root", - "spring.datasource.password":"letmein", - "spring-addons.issuers[0].uri": "http://keycloak:8080/auth/realms/openslice", - "spring.security.oauth2.resourceserver.jwt.issuer-uri": "http://keycloak:8080/auth/realms/openslice", - "springdoc.oAuthFlow.authorizationUrl": "http://keycloak:8080/auth/realms/openslice/protocol/openid-connect/auth", - "springdoc.oAuthFlow.tokenUrl": "http://keycloak:8080/auth/realms/openslice/protocol/openid-connect/token", - "spring.portal.main.domain": "http://localhost", - "logging.level.org.springframework" : "INFO" -}' -``` - -### 6. osscapi container (TMF API service) *(conditional)* - -Change the respective fields: - -- If you made changes to mysql and keycloak credentials. -- If you want to change logging level (TRACE / DEBUG / INFO / WARN / ERROR). - -> **If you are using a non-local domain, replace everywhere the http://keycloak:8080 with the respective {{protocol://domain.name}}.** - -In folder `org.etsi.osl.main/compose/` edit the file `docker-compose.yaml` - -``` -SPRING_APPLICATION_JSON: '{ - "spring.datasource.username":"root", - "spring.datasource.password":"letmein", - "spring-addons.issuers[0].uri": "http://keycloak:8080/auth/realms/openslice", - "spring.security.oauth2.resourceserver.jwt.issuer-uri": "http://keycloak:8080/auth/realms/openslice", - "springdoc.oAuthFlow.authorizationUrl": "http://keycloak:8080/auth/realms/openslice/protocol/openid-connect/auth", - "springdoc.oAuthFlow.tokenUrl": "http://keycloak:8080/auth/realms/openslice/protocol/openid-connect/token", - "logging.level.org.springframework" : "INFO" -}' -``` - -## Configure nginx - -In folder `org.etsi.osl.main/compose/nginx` create a configuration specific `nginx.conf` file. - - -```bash -cd org.etsi.osl.main/compose/nginx/ -``` - -```bash -sudo cp nginx.conf.default nginx.conf -``` - -If needed, in the nginx.conf file, edit the server_name for an non-local deployment. - - - -## Configure Web UI - -In folder `org.etsi.osl.portal.web/src/js/` create a configuration specific `config.js` file. - -```bash -cd org.etsi.osl.portal.web/src/js -``` - -```bash -sudo cp config.js.default config.js -``` - -Edit the `config.js` file with the information of your domain - - -``` -{ - TITLE: "OpenSlice by ETSI", - WIKI: "https://openslice.readthedocs.io/en/stable/", - BUGZILLA: "ROOTURL/bugzilla/", - STATUS: "ROOTURL/status/", - APIURL: "http://localost:13000", - WEBURL: "ROOTURL/nfvportal", - APIOAUTHURL: "ROOTURL/auth/realms/openslice", - APITMFURL: "ROOTURL/tmf-api/serviceCatalogManagement/v4" -} -``` - -## Configure TMF Web UI - -In the folder `org.etsi.osl.tmf.web/src/assets/config` there are 3 files available for configuration: - -* config.prod.json (Basic information + API configuration) -* theming.scss (CSS color palette theming) -* config.theming.json (HTML configuration - Logo, Favicon, Footer) - - -The first 2 files above (i.e. config.prod.json, theming.scss) are essential for the successful deployment of OpenSlice, thus created automatically during the initial deployment at `org.etsi.osl.tmf.web/src/assets/config` directory as a copy of the default ones from the remote repository. - -Ensure that you check the `config.prod.json` and `theming.scss` files and readjust to your deployment if needed. - -```bash -# Starting from the root project directory -cd org.etsi.osl.tmf.web/src/assets/config -``` - -E.g. Edit "TITLE", "WIKI", etc properties with your domain title. Also configure TMF's API and Keycloak's location for the web application, if needed. - - -``` -{ - "TITLE": "OpenSlice by ETSI", - "PORTALVERSION":"2024-Q2 1.0.0-SNAPSHOT", - "WIKI": "https://osl.etsi.org/documentation", - "BUGZILLA": "{BASEURL}/bugzilla/", - "STATUS": "http://status.localhost/", - "WEBURL": "{BASEURL}", - "PORTAL_REPO_APIURL": "{BASEURL}/osapi", - "ASSURANCE_SERVICE_MGMT_APIURL": "{BASEURL}/oas-api", - "APITMFURL": "{BASEURL}/tmf-api", - "OAUTH_CONFIG" : { - "issuer": "{BASEURL}/auth/realms/openslice", - "loginUrl": "{BASEURL}/auth/realms/openslice/protocol/openid-connect/auth", - "tokenEndpoint": "{BASEURL}/auth/realms/openslice/protocol/openid-connect/token", - "userinfoEndpoint": "{BASEURL}/auth/realms/openslice/protocol/openid-connect/userinfo", - "redirectUri": "{BASEURL}/redirect", - "logoutUrl": "{BASEURL}/auth/realms/openslice/protocol/openid-connect/logout", - "postLogoutRedirectUri": "{BASEURL}", - - "responseType": "code", - "oidc": false, - "clientId": "osapiWebClientId", - "dummyClientSecret": "secret", - - "requireHttps": false, - "useHttpBasicAuth": true, - "clearHashAfterLogin": false, - - "showDebugInformation": true - } -} -``` - - -> The {BASEURL} placeholder in the file automatically detects the Origin (Protocol://Domain:Port) of the deployment and applies it to every respective property. E.g. If you are attempting a local deployment of Openslice, then {BASEURL} is automatically translated to "http://localhost". Similarly, you may use {BASEURL} to translate to a public deployment configuration, e.g. "https://portal.openslice.io". - -If further customization, apart from the default provided, is needed for branding (Logo, Footer) then `config.theming.json` needs to be created in io.openslice.tmf.web/src/assets/config directory, as follows: - -```bash -# Starting from the root project directory -cd org.etsi.osl.tmf.web/src/assets/config -``` - -```bash -sudo cp config.theming.default.json config.theming.json -``` - -> ***IMPORTANT NOTE:*** -If you want to apply changes to the JSON configuration files without the need to rebuild the application, you have to apply the changes at the `org.etsi.osl.tmf.web/dist/io-openslice-portal-web/assets/config` directory. Although, it is <u>mandatory</u> to also apply these changes to the `org.etsi.osl.tmf.web/src/assets/config` for <u>persistancy</u>, as after any future rebuild of OpenSlice the `/dist` directory is being overwritten along with its contents. The OpenSlice team strongly recommends to always apply your changes to the TMF web UI configuration files at `org.etsi.osl.tmf.web/src/assets/config` and rebuild the application. - -## Deploy OpenSlice via Docker Compose - -After configuring the services, and editing the docker compose file accordingly, the docker compose instantiation command can be performed. - -```bash -# Starting from the root project directory -cd org.etsi.osl.main/compose/ -``` - -```bash -sudo docker compose --profile prod down;sudo docker compose --profile prod up -d --build -``` - -> Depending on your machine, this process might take time. if for any reason the deployment fails during first time, please rerun the above before any further measures. - - -## Validating deployments and container monitoring - -You can monitor containers' status with portainer at port 9000 (http://your-ip:9000). - -Initially, you may monitor the local machine at portainer. - -Please check that all containers are in running state. - - -## Post installation steps - -After the successful deployment of OpenSlice, to ensure the E2E user experience, **this section is mandatory**. It contains crucial configuration in regard of authentication and user creation. - -### Configure Keycloak server - -The Keycloack server is managing authentication and running on a container at port 8080. It is also proxied to your host via nginx under http://localhost/auth. - -- Navigate to http://domain.com/auth/ or https://domain.com/auth/, (http://ipaddress:8080/auth/ or https://ipaddress:8443/auth/ which are directly accessible without proxy) - -- Navigate to Administration Console - -- Login with the credentials from section [Configure keycloak container](#3-configure-keycloak-container-optional). Default values are: - - user: admin and - - password: KEYCLOAK_PASSWORD - -> if you are running in HTTP you will get a message: HTTPS required. - -To resolve this issue <u>when running in HTTP</u>: - -- Select the master realm from top left corner -- Go to login Tab and select "Require SSL": None -- Repeat for realm Openslice - - -> If you are running in HTTPS, then "Require SSL" can be left unchanged to external requests. - -#### 1. Configure redirects - -Navigate to realm Openslice > client > osapiWebClientId and change the Root URL to your domain. - -Also, insert your domain, e.g. http://example.org/*, at: -* Valid Redirect URIs -* Web Origins - -#### 2. Configure email - -Keycloak allows new users to register. Subsequently, this will also allow new users to register to the OpenSlice portal. - -On Tab Login > check User registration, Verify email, Forgot password etc. - -Also, enter the details on Realm > Email > Enable Authentication. - -#### 3. Add an OpenSlice admin user - -This step is mandatory so as to access the OpenSlice Web UI. To add an OpenSlice admin user you must: -- Navigate to manage/users and add an OpenSlice admin user, e.g. username=admin. -- Set a password -- Navigate to Role Mappings and add ADMIN and MENTOR to Assigned Roles. - -> That user is different from the Keycloak admin user. It is required to login and browse the OpenSlice Web UI. The Roles ADMIN and MENTOR guarantee full access through the Openslice UI, thus such a user is always required. - -### Keycloak at localhost - -> **This is an important step if you run Keycloak on localhost!** - -1 - Edit your Hosts File, adding the line below - -```127.0.0.1 keycloak``` - -Hosts File Location: - - - In Linux/Unix, the file's location is at /etc/hosts - - - In Windows, its location is at c:\Windows\System32\Drivers\etc\hosts - -2 - Replace http://localhost/auth/ with http://keycloak:8080/auth/ in your Keycloak config for AngularJS and Angular (see examples below). - - -> Explanation - -Nginx uses the http://keycloak:8080 URL, which is accessible via the internal docker system's network. -The Front-end (TS/Angular) shall also use the http://keycloak:8080. -This way, you will not get the invalid token error, as the API is acquiring the token from http://keycloak:8080 (internally) and the Front-end is getting verified by an issuer at the same URL, as well. - - - -2.1 - For the Angular configuration (TMF portal UI), navigate to org.etsi.osl.tmf.web/src/assets/config and edit config.prod.json - -```bash -# Starting from the root project directory -cd org.etsi.osl.tmf.web/src/assets/config -``` - -```bash -nano config.prod.json -``` - -After editing it should look like the example bellow: - -```yaml -{ - "TITLE": "OpenSlice by ETSI", - "PORTALVERSION":"2023-Q3 1.2.0-SNAPSHOT", - "WIKI": "https://openslice.readthedocs.io/en/stable/", - "BUGZILLA": "{BASEURL}/bugzilla/", - "STATUS": "http://status.localhost/", - "WEBURL": "{BASEURL}", - "PORTAL_REPO_APIURL": "{BASEURL}/osapi", - "ASSURANCE_SERVICE_MGMT_APIURL": "{BASEURL}/oas-api", - "APITMFURL": "{BASEURL}/tmf-api", - "OAUTH_CONFIG" : { - "issuer": "http://keycloak:8080/auth/realms/openslice", - "loginUrl": "http://keycloak:8080/auth/realms/openslice/protocol/openid-connect/auth", - "tokenEndpoint": "http://keycloak:8080/auth/realms/openslice/protocol/openid-connect/token", - "userinfoEndpoint": "http://keycloak:8080/auth/realms/openslice/protocol/openid-connect/userinfo", - "redirectUri": "{BASEURL}/redirect", - "logoutUrl": "http://keycloak:8080/auth/realms/openslice/protocol/openid-connect/logout", - "postLogoutRedirectUri": "{BASEURL}", - - "responseType": "code", - "oidc": false, - "clientId": "osapiWebClientId", - "dummyClientSecret": "secret", - - "requireHttps": false, - "useHttpBasicAuth": true, - clearHashAfterLogin": false, - - "showDebugInformation": true - } -} -``` - -> Note the difference in changing {BASEURL} -> http://keycloak:8080 - -> If you want the changes to take place immediately without rebuilding the project, then repeat the process for org.etsi.osl.tmf.web/dist/org.etsi.osl.tmf.web/assets/config/config.prod.json - -2.2 - For the AngularJS configuration (NVF portal UI), navigate to org.etsi.osl.portal.web/src/js and edit config.js - -```bash -# Starting from the root project directory -cd org.etsi.osl.portal.web/src/js -``` - -```bash -nano config.js -``` - -after editing it should look like the example bellow: - -``` -var appConfig = angular.module('portalwebapp.config',[]); - - -appConfig.factory('APIEndPointService', function() { - return { - TITLE: "OpenSlice by ETSI", - WIKI: "https://openslice.readthedocs.io/en/stable/", - BUGZILLA: "ROOTURL/bugzilla/", - STATUS: "ROOTURL/status/", - APIURL: "http://localost:13000", - WEBURL: "ROOTURL/nfvportal", - APIOAUTHURL: "ROOTURL/auth/realms/openslice", - APITMFURL: "ROOTURL/tmf-api/serviceCatalogManagement/v4" - }; -}); -``` - -> Note the difference in "APIOAUTHURL" property - - -### NFV Orchestrator Configuration - -After successfully deploying and configuring OpenSlice, you may configure its environment (e.g. the NFVO) that will facilitate the deployment of NFV artifacts. - -See [NFV Orchestrator Configuration](./nfvoconfig.md). - - -<br> - -## Kubernetes installation - -Openslice can be installed in a Kubernetes cluster. - -**This is a work in progress, and should be used for stable deployments!**. - -Please reference "develop" tagged documentation for any latest progress. - -The related scripts are inside the kubernetes folder. Follow these steps along the lines. You need to configure the ingress properly depending on how you want to expose Openslice. - -1 - Create an openslice namespace - -```bash -kubectl create namespace openslice -``` - -2 - Apply or create an ingress. Ingress exposes HTTP and HTTPS routes from outside the cluster to services within the cluster. Traffic routing is controlled by rules defined on the Ingress resource. -An Ingress may be configured to give Services externally-reachable URLs, load balance traffic, terminate SSL / TLS, and offer name-based virtual hosting. An Ingress controller is responsible for fulfilling the Ingress, usually with a load balancer, though it may also configure your edge router or additional frontends to help handle the traffic. You must have an Ingress controller to satisfy an Ingress. -You may need to deploy an Ingress controller such as ingress-nginx. - -You can also adapt it to connect to public cloud load balancers depending on your needs. - -The following will expose an ingress resource from one of your a k8s nodes on port 80. - -```bash - kubectl apply -f openslice-ingress.yaml -``` - - -Finding the ingress IP: - - -```bash - -kubectl describe -f openslice-ingress.yaml - - -Name: openslice-ingress -Namespace: openslice -Address: 10.10.10.35 -Default backend: default-http-backend:80 (<error: endpoints "default-http-backend" not found>) -Rules: - Host Path Backends - ---- ---- -------- - * - /services tmfweb:80 (<error: endpoints "tmfweb" not found>) - /tmf-api osscapi:13082 (<error: endpoints "osscapi" not found>) - /auth keycloak:8080 (<error: endpoints "keycloak" not found>) - /osapi osportalapi:13000 (<error: endpoints "osportalapi" not found>) - / portalweb:80 (<error: endpoints "portalweb" not found>) -Annotations: kubernetes.io/ingress.class: nginx -Events: - Type Reason Age From Message - ---- ------ ---- ---- ------- - Normal Sync 9m29s (x2 over 9m58s) nginx-ingress-controller Scheduled for sync - -``` - -From the above example, our exposed ingress is at Address: 10.10.10.35 - -3 - We need to configure the expose address and deploy openslice (IP or URL e.g. http://myopenslice.xxx) - -```bash -./k8sdeploy.sh 10.10.10.35 -``` - - -4 - Check the status of Openslice in the cluster. Should be similar to the following: - -```bash - -kubectl get pods --namespace=openslice -o wide - -NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES -activemq-59d4bfdb4b-bvjqr 1/1 Running 0 109s 192.168.43.97 kc-2 <none> <none> -bugzilla-client-7dd7cb47cb-8qb8m 1/1 Running 0 100s 192.168.12.114 kc-3 <none> <none> -centrallog-95bbf7867-k8fpt 1/1 Running 0 100s 192.168.12.107 kc-3 <none> <none> -consul-b5dd76b76-64dzk 1/1 Running 0 107s 192.168.43.90 kc-2 <none> <none> -keycloak-7c5b6bbc95-k2qfl 1/1 Running 0 105s 192.168.12.106 kc-3 <none> <none> -manoclient-95f68f4c9-c9t6r 1/1 Running 0 104s 192.168.12.113 kc-3 <none> <none> -mysql-portal-0 1/1 Running 0 107s 192.168.43.99 kc-2 <none> <none> -osom-6d548cf555-q8ptj 1/1 Running 0 104s 192.168.43.93 kc-2 <none> <none> -osportalapi-5fff744db8-5g4zs 1/1 Running 0 103s 192.168.43.98 kc-2 <none> <none> -osscapi-6d68b54d97-jn8tz 0/1 Running 0 102s 192.168.12.104 kc-3 <none> <none> -portalweb-8469d57df4-94tfj 1/1 Running 0 101s 192.168.48.44 kc-nfs <none> <none> -tmfweb-868f7bb9c5-x4lfh 1/1 Running 0 102s 192.168.48.43 kc-nfs <none> <none> -``` -```bash -kubectl get deployments --namespace=openslice -o wide - -NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR -activemq 1/1 1 1 2m15s anactivemq webcenter/activemq:5.14.3 org.etsi.osl.service=activemq -bugzilla-client 1/1 1 1 2m6s bugzilla-client openslice/org.etsi.osl.bugzilla:latest org.etsi.osl.service=bugzilla-client -centrallog 1/1 1 1 2m6s centrallog openslice/org.etsi.osl.centrallog.service org.etsi.osl.service=centrallog -consul 1/1 1 1 2m13s aconsul consul org.etsi.osl.service=consul -keycloak 1/1 1 1 2m11s keycloak quay.io/keycloak/keycloak:11.0.3 org.etsi.osl.service=keycloak -manoclient 1/1 1 1 2m10s manoclient openslice/org.etsi.osl.mano:latest org.etsi.osl.service=manoclient -osom 1/1 1 1 2m10s openslice-osom openslice/org.etsi.osl.osom:latest org.etsi.osl.service=osom -osportalapi 1/1 1 1 2m9s openslice-portalapi openslice/org.etsi.osl.portal.api:latest org.etsi.osl.service=osportalapi -osscapi 1/1 1 1 2m8s openslice-scapi openslice/org.etsi.osl.tmf.api:latest org.etsi.osl.service=osscapi -portalweb 1/1 1 1 2m7s openslice-portalweb openslice/org.etsi.osl.portal.web:latest org.etsi.osl.service=portalweb -tmfweb 1/1 1 1 2m8s openslice-tmfweb openslice/org.etsi.osl.tmf.web:latest org.etsi.osl.service=tmfweb -``` -```bash -kubectl get services --namespace=openslice -o wide - -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR -activemq ClusterIP 10.111.160.120 <none> 8161/TCP,61616/TCP 2m22s org.etsi.osl.service=activemq -bugzilla-client ClusterIP 10.101.43.28 <none> 13010/TCP 2m14s org.etsi.osl.service=bugzilla-client -centrallog ClusterIP 10.109.15.151 <none> 13013/TCP 2m14s org.etsi.osl.service=centrallog -consul ClusterIP 10.101.103.240 <none> 8500/TCP,8600/TCP 2m21s org.etsi.osl.service=consul -keycloak ClusterIP 10.110.216.62 <none> 8080/TCP,8443/TCP 2m19s org.etsi.osl.service=keycloak -manoclient ClusterIP 10.108.112.84 <none> 13011/TCP 2m18s org.etsi.osl.service=manoclient -mysql-portal ClusterIP None <none> 3306/TCP 2m19s org.etsi.osl.service=mysql-portal -osom ClusterIP 10.105.173.85 <none> 13100/TCP 2m18s org.etsi.osl.service=osom -osportalapi ClusterIP 10.104.121.164 <none> 13000/TCP 2m17s org.etsi.osl.service=osportalapi -osscapi ClusterIP 10.108.6.161 <none> 13082/TCP 2m16s org.etsi.osl.service=osscapi -portalweb ClusterIP 10.97.126.98 <none> 80/TCP 2m15s org.etsi.osl.service=portalweb -tmfweb ClusterIP 10.98.56.82 <none> 80/TCP 2m15s org.etsi.osl.service=tmfweb - -``` \ No newline at end of file diff --git a/doc/gettingstarted/howto.md b/doc/gettingstarted/howto.md deleted file mode 100644 index fae73134d5e05d9d18173f7cf05129a277f61323..0000000000000000000000000000000000000000 --- a/doc/gettingstarted/howto.md +++ /dev/null @@ -1,11 +0,0 @@ -# How To - - - - - - - - - - diff --git a/doc/gettingstarted/howtorun.md b/doc/gettingstarted/howtorun.md new file mode 100644 index 0000000000000000000000000000000000000000..59839df10464fbd9b7a438a9cfa057a9f7f0ae94 --- /dev/null +++ b/doc/gettingstarted/howtorun.md @@ -0,0 +1,104 @@ +- [Run All CAPIF Services locally with Docker images](#run-all-capif-services-locally-with-docker-images) +- [Run All CAPIF Services locally with Docker images and deploy monitoring stack](#run-all-capif-services-locally-with-docker-images-and-deploy-monitoring-stack) +- [Run each service using Docker](#run-each-service-using-docker) +- [Run each service using Python](#run-each-service-using-python) + +Capif services are developed under [services folder](https://labs.etsi.org/rep/ocf/capif/-/tree/main/services). + +### Run All CAPIF Services locally with Docker images +To run using docker and docker compose, version 2.10 or higher, you must ensure you have that tools installed at your machine. Also to simplify the process, we have 3 script to control docker images to deploy, check and cleanup. + +To run all CAPIF APIs locally using docker and docker-compose you can execute: +``` +cd services/ + +./run.sh +``` +This will build and run all services using docker images, including mongodb and nginx locally and in background, and import ca.crt to nginx. + +Nginx deployed by default use **capifcore** hostname, but can add a parameter when run.sh is executed setting a different hostname, for example, +``` +./run.sh -c openshift.evolved-5g.eu +``` + +Also you can run monitoring just using option -m true, for example: +``` +./run.sh -m true +./run.sh -m true -c openshift.evolved-5g.eu +``` + +If you want to check if all CAPIF services are running properly in local machine after execute run.sh, we can use: +``` +./check_services_are_running.sh +``` +This shell script will return 0 if all services are running properly. + +When we need to stop all CAPIF services, we can use next bash script: +``` +./clean_capif_docker_services.sh -a +``` + +NOTE: You can use different flags if you only want to stop some of them, please check help using +``` +./clean_capif_docker_services.sh -h + +Usage: clean_capif_docker_services.sh <options> + -c : clean capif services + -v : clean vault service + -r : clean register service + -m : clean monitoring service + -a : clean all services + -h : show this help +``` + +This shell script will remove and clean all CAPIF services started previously with run.sh + +On the other hand you can check logs using show_logs.sh script, please check options: +``` +./show_logs.sh +You must specify an option before run script. +Usage: ./show_logs.sh <options> + -c : Show capif services + -v : Show vault service + -r : Show register service + -m : Show monitoring service + -a : Show all services + -f : Follow log output + -h : Show this help +``` +You can also use option -f in order to live follow log output + +### Run All CAPIF Services locally with Docker images and deploy monitoring stack +It is now possible to deploy a monitoring stack for CAPIF with Grafana, Prometheus, FluentBit, Loki, Cadvisor, Tempo and Opentelemetry. + +To deploy CAPIF together with the monitoring stack, it is only necessary to execute the following. + +``` +./run.sh -m true +``` + +After they have been built, the different panels can be consulted in Grafana at the url + +``` +http://localhost:3000 +``` + +By default, the monitoring option is set to false. Once up, all data sources and dashboards are automatically provisioned + +### Run each service using Docker + +Also you can run service by service using docker: +``` +cd <Service> +docker build -t capif_security . +docker run -p 8080:8080 capif_security +``` + +### Run each service using Python + +Run using python +``` +cd <Service> +pip3 install -r requirements.txt +python3 -m <service> +``` \ No newline at end of file diff --git a/doc/gettingstarted/repository.md b/doc/gettingstarted/repository.md new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/doc/images/architecture/CAPIF Core Function.png b/doc/images/architecture/CAPIF Core Function.png new file mode 100644 index 0000000000000000000000000000000000000000..cc790ca60cb40a631a0fcc83d3530f62e51b28e3 Binary files /dev/null and b/doc/images/architecture/CAPIF Core Function.png differ diff --git a/doc/images/architecture/CAPIF_Core_Function.png b/doc/images/architecture/CAPIF_Core_Function.png new file mode 100644 index 0000000000000000000000000000000000000000..cc790ca60cb40a631a0fcc83d3530f62e51b28e3 Binary files /dev/null and b/doc/images/architecture/CAPIF_Core_Function.png differ diff --git a/doc/images/architecture/msg_flow.png b/doc/images/architecture/msg_flow.png new file mode 100644 index 0000000000000000000000000000000000000000..7163f87ea381ab5e63169d8722fea4c259c10a42 Binary files /dev/null and b/doc/images/architecture/msg_flow.png differ diff --git a/doc/images/flows/01_Register_of_AEF.png b/doc/images/flows/01_Register_of_AEF.png new file mode 100644 index 0000000000000000000000000000000000000000..391cb43fe8657f9965c66391f716cfc06a5e9eb0 Binary files /dev/null and b/doc/images/flows/01_Register_of_AEF.png differ diff --git a/doc/images/flows/01a_Register_(Only)_AEF.png b/doc/images/flows/01a_Register_(Only)_AEF.png new file mode 100644 index 0000000000000000000000000000000000000000..5b6d17b181408b74fb3e15bc8276d79bf1290c39 Binary files /dev/null and b/doc/images/flows/01a_Register_(Only)_AEF.png differ diff --git a/doc/images/flows/01b_Register_of_AEF_GetAuth.png b/doc/images/flows/01b_Register_of_AEF_GetAuth.png new file mode 100644 index 0000000000000000000000000000000000000000..8cb5cb75839e340aeedf3349c8032fcae1fc3ce4 Binary files /dev/null and b/doc/images/flows/01b_Register_of_AEF_GetAuth.png differ diff --git a/doc/images/flows/02_AEF_API_Provider_registration.png b/doc/images/flows/02_AEF_API_Provider_registration.png new file mode 100644 index 0000000000000000000000000000000000000000..3b42e21185ae36c97f3c6504624757a80e282ef6 Binary files /dev/null and b/doc/images/flows/02_AEF_API_Provider_registration.png differ diff --git a/doc/images/flows/03_AEF_Publish.png b/doc/images/flows/03_AEF_Publish.png new file mode 100644 index 0000000000000000000000000000000000000000..dfe3a3e09ff3183fa93eab95e1df107a2dfa9638 Binary files /dev/null and b/doc/images/flows/03_AEF_Publish.png differ diff --git a/doc/images/flows/04_Invoker_Register.png b/doc/images/flows/04_Invoker_Register.png new file mode 100644 index 0000000000000000000000000000000000000000..571f2af8098ba390a31cf5676ba0cd180b55d983 Binary files /dev/null and b/doc/images/flows/04_Invoker_Register.png differ diff --git a/doc/images/flows/04a_Invoker_(Only)_Register.png b/doc/images/flows/04a_Invoker_(Only)_Register.png new file mode 100644 index 0000000000000000000000000000000000000000..535d8b5baf23f43060231d20ca82c077e0959bab Binary files /dev/null and b/doc/images/flows/04a_Invoker_(Only)_Register.png differ diff --git a/doc/images/flows/04b_Invoker_Register_GetAuth.png b/doc/images/flows/04b_Invoker_Register_GetAuth.png new file mode 100644 index 0000000000000000000000000000000000000000..2cb2349e0378c18f874da9442852ca1eb79deb6b Binary files /dev/null and b/doc/images/flows/04b_Invoker_Register_GetAuth.png differ diff --git a/doc/images/flows/05_Invoker_Onboarding.png b/doc/images/flows/05_Invoker_Onboarding.png new file mode 100644 index 0000000000000000000000000000000000000000..9cd4b2d9fc99daa0f285a0f9e5cf77d9c51ea17c Binary files /dev/null and b/doc/images/flows/05_Invoker_Onboarding.png differ diff --git a/doc/images/flows/06_Invoker_Discover_AEF.png b/doc/images/flows/06_Invoker_Discover_AEF.png new file mode 100644 index 0000000000000000000000000000000000000000..20b2f04f94444833bbea04832620434593f89bc0 Binary files /dev/null and b/doc/images/flows/06_Invoker_Discover_AEF.png differ diff --git a/doc/images/flows/07_Invoker_Create_Security_Context.png b/doc/images/flows/07_Invoker_Create_Security_Context.png new file mode 100644 index 0000000000000000000000000000000000000000..bb655e0e38e8394b3aaa024ada0f13c2f21c2b4c Binary files /dev/null and b/doc/images/flows/07_Invoker_Create_Security_Context.png differ diff --git a/doc/images/flows/08_Invoker_Get_Token.png b/doc/images/flows/08_Invoker_Get_Token.png new file mode 100644 index 0000000000000000000000000000000000000000..2e39f52a3d12efa8c19ea3032957e9f48d890d0e Binary files /dev/null and b/doc/images/flows/08_Invoker_Get_Token.png differ diff --git a/doc/images/flows/09_Invoker_Send_Request_to_AEF_Service_API.png b/doc/images/flows/09_Invoker_Send_Request_to_AEF_Service_API.png new file mode 100644 index 0000000000000000000000000000000000000000..1e4a87c54b04d2d6524da2617fa615dab7318dc7 Binary files /dev/null and b/doc/images/flows/09_Invoker_Send_Request_to_AEF_Service_API.png differ diff --git a/doc/index.md b/doc/index.md index 95d378a21e82d95f73a62a9e3bf61b58b29888f4..1f8bec32339af64515eaf1df1da5b18d9adc7b15 100644 --- a/doc/index.md +++ b/doc/index.md @@ -1,8 +1,139 @@ -<img src="images/openCAPIF.png" alt="drawing" width="200"/> +<img src="images/logos/OpenCAPIF.png" alt="drawing" width="200"/> -version: Release 0 +# Release 0 -OpenCAPIF +The APIs included in release 0.0 are: +- JWT Authentication APIs +- CAPIF Invoker Management API +- CAPIF Publish API +- CAPIF Discover API +- CAPIF Security API +- CAPIF Events API +- CAPIF Provider Management API -## Usage \ No newline at end of file +Testing Suite of all services with robot. +Also Postman suite to a simple test. + +## What is OpenCAPIF? + +CAPIF is the “Common API Framework†defined by 3GPP to manage the APIs exposed by 3GPP networks in their northbound interfaces. + +CAPIF defines three types of entities: + +* API Providers, which are the entities exposing APIs (e.g., NEF) +* API Invokers, which are the entities that consume APIs (e.g., Applications), and +* the CAPIF Core Function, that manages the relationships between the other two. + + + +The CAPIF Core Function is the cornerstone of the Common API Framework and provides the following capabilities: + +* Authenticating the API Invoker based on its identity and other information; +* Supporting mutual authentication with the API Invoker; +* Providing authorization for the API Invoker prior to accessing the exposed APIs; +* Publishing, storing, and supporting the discovery of service APIs information; +* Controlling the service API access based on PLMN operator configured policies; +* Storing the logs for the service API invocations and providing the service API invocation logs to authorized entities; +* Charging based on the logs of the service API invocations; +* Monitoring the service API invocations; +* Onboarding a new API Invoker and offboarding an API Invoker; +* Storing policy configurations related to CAPIF and service APIs; +* Support accessing the logs for auditing (e.g., detecting abuse); and +* Support publishing and discovery of service APIs information among CAPIF Core Function (CAPIF interconnection). + +The following diagram shows how API Invokers and API Providers interact with the CAPIF Core Function to Register in CAPIF, Publish APIs, Discover APIs and Consume APIs. It is important to highlight that the CAPIF Core Function is not a classical API Gateway. The API consumption takes place directly between the API Invoker and the API Provider. Therefore, CAPIF does not impact API performance in API consumption between API Invokers and API Providers. + + + +If you want to know more about OpenCAPIF check [The story behind openCAPIF](https://ocf.etsi.org/news/20240110_the_story_behind_opencapif/) + + +## Repository structure + +You can check the code at [OpenCAPIF Repository] + +``` +CAPIF_API_Services +└───docs +│ └───test_plan +│ └───testing_with_postman +└───services +└───tests +└───tools + └───robot + └───open_api_script +``` +* **services**: Services developed following CAPIF API specifications. Also, other complementary services (e.g., NGINX and JWTauth services for the authentication of API consuming entities). +* **tools**: Auxiliary tools. Robot Framework related code and OpenAPI scripts. +* **test**: Tests developed using Robot Framework. + +* **docs**: Documents related to the code in the repository. + * images: images used in the repository + * test_plan: test plan descriptions for each API service referring to the test that are executed with the Robot Framework. + * testing_with_postman: auxiliary JSON file needed for the Postman-based examples. + +## CAPIF_API_Services + +This repository has the python-flask Mockup servers created with openapi-generator related with CAPIF APIS defined here: +[Open API Descriptions of 3GPP 5G APIs] + + +## How to test CAPIF APIs + +The above APIs can be tested either with POSTMAN tool or running developed tests with Robot Framework. + +## Test Plan Documentation + +Complete documentation of tests is here: [Test Plan Directory] + +## Robot Framework + +In order to ensure modifications over CAPIF services still accomplish the required functionality, Robot Framework test suite must be success. + +Test suite implemented accomplish requirements described under test plan at [Test Plan Directory] folder. + +Please go to [Testing with Robot Framework] Section + +## Using PostMan + +You can test the CAPIF flow using the Postman tool. To do this, we have created a collection with some examples of CAPIF requests with everything necessary to carry them out. + +For more information on how to test the APIs with POSTMAN, go to this [POSTMAN Section]. + +## Important urls: + +## Mongo CAPIF's DB Dashboard +``` +http://localhost:8082/ (if accessed from localhost) + +or + +http://<Mongo CAPIF Express Host IP>:8082/ (if accessed from another host) +``` + +## Mongo Register's DB Dashboard +``` +http://localhost:8083/ (if accessed from localhost) + +or + +http://<Mongo Register Express Host IP>:8083/ (if accessed from another host) +``` + +## FAQ Documentation + +Frequently asked questions can be found here: [FAQ Section] + + + + + + +[Test Plan Directory]: ./testing/testplan/README.md "Test Plan Directory" +[Testing with Robot Framework]: ./testing/robotframework/README.md "Testing with Robot Framework" +[FAQ Section]: ./FAQ.md "FAQ Section" + +[Open API Descriptions of 3GPP 5G APIs]: https://forge.3gpp.org/rep/all/5G_APIs "Open API Descriptions of 3GPP 5G APIs" +[OpenCAPIF Repository]: https://labs.etsi.org/rep/ocf/capif "OpenCAPIF Repository" +[POSTMAN Section]: ./testing/postman/README.md "POSTMAN Section" \ No newline at end of file diff --git a/doc/testing/postman.md b/doc/testing/postman.md deleted file mode 100644 index 730e2d24b1b114f1776eeb5cdc5cf69f6981e7dd..0000000000000000000000000000000000000000 --- a/doc/testing/postman.md +++ /dev/null @@ -1 +0,0 @@ -# Postman \ No newline at end of file diff --git a/doc/testing/postman/CAPIF.postman_collection.json b/doc/testing/postman/CAPIF.postman_collection.json new file mode 100644 index 0000000000000000000000000000000000000000..e65c826994c986b46367eeb223d65444a38cebf9 --- /dev/null +++ b/doc/testing/postman/CAPIF.postman_collection.json @@ -0,0 +1,982 @@ +{ + "info": { + "_postman_id": "5cfdf0d7-3b3c-4961-9cb9-84c2bf85056c", + "name": "CAPIF", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "31608242", + "_collection_link": "https://red-comet-993867.postman.co/workspace/Team-Workspace~bfc7c442-a60c-4bb1-8730-fdabc2df89b9/collection/31608242-5cfdf0d7-3b3c-4961-9cb9-84c2bf85056c?action=share&source=collection_link&creator=31608242" + }, + "item": [ + { + "name": "01-register_user_provider", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var res = JSON.parse(responseBody);", + "pm.environment.set('ONBOARDING_URL', res.ccf_api_onboarding_url);", + "pm.environment.set('PUBLISH_URL', res.ccf_publish_url);", + "pm.environment.set('USER_ID', res.id);", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n\"password\": \"{{PASSWORD}}\",\n\"username\": \"{{USERNAME}}\",\n\"description\": \"provider\",\n\"role\": \"provider\",\n\"cn\": \"provider\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://{{REGISTER_HOSTNAME}}:{{REGISTER_PORT}}/register", + "protocol": "https", + "host": [ + "{{REGISTER_HOSTNAME}}" + ], + "port": "{{REGISTER_PORT}}", + "path": [ + "register" + ] + } + }, + "response": [] + }, + { + "name": "02-getauth_provider", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var res = JSON.parse(responseBody);", + "", + "pm.environment.set('CA_ROOT', res.ca_root);", + "pm.environment.set('ACCESS_TOKEN', res.access_token);", + "", + "setTimeout(() => {", + " pm.sendRequest({", + " url: 'http://localhost:3000/write_ca',", + " method: 'POST',", + " header: 'Content-Type:application/json',", + " encoding: 'binary',", + " body: {", + " mode: 'raw',", + " raw: res", + " }", + " }, function (err, res) {", + " console.log(res);", + " });", + " }, 5000);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n\"password\": \"{{PASSWORD}}\",\n\"username\": \"{{USERNAME}}\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://{{REGISTER_HOSTNAME}}:{{REGISTER_PORT}}/getauth", + "protocol": "https", + "host": [ + "{{REGISTER_HOSTNAME}}" + ], + "port": "{{REGISTER_PORT}}", + "path": [ + "getauth" + ] + } + }, + "response": [] + }, + { + "name": "03-onboard_provider", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var res = JSON.parse(responseBody);", + "if (pm.response.code == 201){", + " ", + " pm.environment.set('PROVIDER_ID', res.apiProvDomId);", + "", + " const roleVariableMapping = {", + " \"AEF\": { id: 'AEF_ID', cert: 'AEF_CERT' },", + " \"APF\": { id: 'APF_ID', cert: 'APF_CERT' },", + " \"AMF\": { id: 'AMF_ID', cert: 'AMF_CERT' }", + " };", + "", + " res.apiProvFuncs.forEach(function(elemento) {", + " const role = elemento.apiProvFuncRole;", + " if (roleVariableMapping.hasOwnProperty(role)) {", + " const variables = roleVariableMapping[role];", + " pm.environment.set(variables.id, elemento.apiProvFuncId);", + " pm.environment.set(variables.cert, elemento.regInfo.apiProvCert);", + "", + " }", + " });", + "", + "}", + "", + "", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "", + "var res = JSON.parse(pm.request.body.raw);", + "", + "res.apiProvFuncs.forEach(function(elemento) {", + "", + " setTimeout(() => {", + " pm.sendRequest({", + " url: 'http://localhost:3000/generate_csr',", + " method: 'POST',", + " header: 'Content-Type:application/json',", + " encoding: 'binary',", + " body: {", + " mode: 'raw',", + " raw: elemento", + " }", + " }, function (err, response) {", + " j_file = JSON.parse(response.text());", + " elemento.regInfo.apiProvPubKey = j_file.csr;", + " pm.environment.set(elemento.apiProvFuncRole+'_KEY', j_file.key);", + " });", + " }, 5000);", + "", + "});", + "", + "pm.request.body.raw = res;" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{ACCESS_TOKEN}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [ + { + "key": "", + "value": "", + "type": "text", + "disabled": true + } + ], + "body": { + "mode": "raw", + "raw": "{\n\"apiProvFuncs\": [\n {\n \"regInfo\": {\n \"apiProvPubKey\": \"\"\n },\n \"apiProvFuncRole\": \"AEF\",\n \"apiProvFuncInfo\": \"dummy_aef\"\n },\n {\n \"regInfo\": {\n \"apiProvPubKey\": \"\"\n },\n \"apiProvFuncRole\": \"APF\",\n \"apiProvFuncInfo\": \"dummy_apf\"\n },\n {\n \"regInfo\": {\n \"apiProvPubKey\": \"\"\n },\n \"apiProvFuncRole\": \"AMF\",\n \"apiProvFuncInfo\": \"dummy_amf\"\n }\n],\n\"apiProvDomInfo\": \"This is provider\",\n\"suppFeat\": \"fff\",\n\"failReason\": \"string\",\n\"regSec\": \"{{ACCESS_TOKEN}}\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://{{CAPIF_HOSTNAME}}/{{ONBOARDING_URL}}", + "protocol": "https", + "host": [ + "{{CAPIF_HOSTNAME}}" + ], + "path": [ + "{{ONBOARDING_URL}}" + ] + } + }, + "response": [] + }, + { + "name": "04-publish_api", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "setTimeout(() => {", + " pm.sendRequest({", + " url: 'http://localhost:3000/write_cert',", + " method: 'POST',", + " header: 'Content-Type:application/json',", + " encoding: 'binary',", + " body: {", + " mode: 'raw',", + " raw: {cert: pm.environment.get('APF_CERT'), key:pm.environment.get('APF_KEY')}", + " }", + " }, function (err, response) {", + " console.log(response)", + " });", + " }, 5000);", + "", + "", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "strictSSL": true + }, + "request": { + "auth": { + "type": "noauth" + }, + "method": "POST", + "header": [ + { + "key": "", + "value": "", + "type": "text", + "disabled": true + } + ], + "body": { + "mode": "raw", + "raw": "\n{\n \"apiName\": \"hello_api_demo_v2\",\n \"aefProfiles\": [\n {\n \"aefId\": \"{{AEF_ID}}\",\n \"versions\": [\n {\n \"apiVersion\": \"v1\",\n \"expiry\": \"2021-11-30T10:32:02.004Z\",\n \"resources\": [\n {\n \"resourceName\": \"hello-endpoint\",\n \"commType\": \"REQUEST_RESPONSE\",\n \"uri\": \"/hello\",\n \"custOpName\": \"string\",\n \"operations\": [\n \"POST\"\n ],\n \"description\": \"Endpoint to receive a welcome message\"\n }\n ],\n \"custOperations\": [\n {\n \"commType\": \"REQUEST_RESPONSE\",\n \"custOpName\": \"string\",\n \"operations\": [\n \"POST\"\n ],\n \"description\": \"string\"\n }\n ]\n }\n ],\n \"protocol\": \"HTTP_1_1\",\n \"dataFormat\": \"JSON\",\n \"securityMethods\": [\"Oauth\"],\n \"interfaceDescriptions\": [\n {\n \"ipv4Addr\": \"localhost\",\n \"port\": 8088,\n \"securityMethods\": [\"Oauth\"]\n }\n ]\n }\n ],\n \"description\": \"Hello api services\",\n \"supportedFeatures\": \"fffff\",\n \"shareableInfo\": {\n \"isShareable\": true,\n \"capifProvDoms\": [\n \"string\"\n ]\n },\n \"serviceAPICategory\": \"string\",\n \"apiSuppFeats\": \"fffff\",\n \"pubApiPath\": {\n \"ccfIds\": [\n \"string\"\n ]\n },\n \"ccfId\": \"string\"\n }", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://{{CAPIF_HOSTNAME}}/published-apis/v1/{{APF_ID}}/service-apis", + "protocol": "https", + "host": [ + "{{CAPIF_HOSTNAME}}" + ], + "path": [ + "published-apis", + "v1", + "{{APF_ID}}", + "service-apis" + ] + } + }, + "response": [] + }, + { + "name": "05-register_user_invoker", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var res = JSON.parse(responseBody);", + "pm.environment.set('ONBOARDING_URL_INVOKER', res.ccf_onboarding_url);", + "pm.environment.set('DISCOVER_URL', res.ccf_discover_url);", + "pm.environment.set('USER_INVOKER_ID', res.id);", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n\"password\": \"{{PASSWORD}}\",\n\"username\": \"{{USERNAME_INVOKER}}\",\n\"description\": \"invoker\",\n\"role\": \"invoker\",\n\"cn\": \"invoker\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://{{REGISTER_HOSTNAME}}:{{REGISTER_PORT}}/register", + "protocol": "https", + "host": [ + "{{REGISTER_HOSTNAME}}" + ], + "port": "{{REGISTER_PORT}}", + "path": [ + "register" + ] + } + }, + "response": [] + }, + { + "name": "06-getauth_invoker", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var res = JSON.parse(responseBody);", + "", + "pm.environment.set('CA_ROOT', res.ca_root);", + "pm.environment.set('ACCESS_TOKEN_INVOKER', res.access_token);", + "", + "setTimeout(() => {", + " pm.sendRequest({", + " url: 'http://localhost:3000/write_ca',", + " method: 'POST',", + " header: 'Content-Type:application/json',", + " encoding: 'binary',", + " body: {", + " mode: 'raw',", + " raw: res", + " }", + " }, function (err, res) {", + " console.log(res);", + " });", + " }, 5000);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n\"password\": \"{{PASSWORD}}\",\n\"username\": \"{{USERNAME_INVOKER}}\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://{{REGISTER_HOSTNAME}}:{{REGISTER_PORT}}/getauth", + "protocol": "https", + "host": [ + "{{REGISTER_HOSTNAME}}" + ], + "port": "{{REGISTER_PORT}}", + "path": [ + "getauth" + ] + } + }, + "response": [] + }, + { + "name": "07-onboard_invoker", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var res = JSON.parse(responseBody);", + "if (pm.response.code == 201){", + " ", + " pm.environment.set('INVOKER_ID', res.apiInvokerId);", + " pm.environment.set('INVOKER_CERT', res.onboardingInformation.apiInvokerCertificate);", + "}", + "", + "", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "", + "var res = JSON.parse(pm.request.body.raw);", + "", + "", + "setTimeout(() => {", + " pm.sendRequest({", + " url: 'http://localhost:3000/generate_csr_invoker',", + " method: 'POST',", + " header: 'Content-Type:application/json',", + " encoding: 'binary',", + " body: {", + " mode: 'raw',", + " raw: {}", + " }", + " }, function (err, response) {", + " j_file = JSON.parse(response.text());", + " res.onboardingInformation.apiInvokerPublicKey = j_file.csr;", + " pm.environment.set('INVOKER_KEY', j_file.key);", + " });", + " }, 5000);", + "", + "", + "pm.request.body.raw = res;" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{ACCESS_TOKEN_INVOKER}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [ + { + "key": "", + "value": "", + "type": "text", + "disabled": true + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"notificationDestination\" : \"http://host.docker.internal:8086/netapp_callback\",\n \"supportedFeatures\" : \"fffffff\",\n \"apiInvokerInformation\" : \"dummy\",\n \"websockNotifConfig\" : {\n \"requestWebsocketUri\" : true,\n \"websocketUri\" : \"websocketUri\"\n },\n \"onboardingInformation\" : {\n \"apiInvokerPublicKey\" : \"\"\n },\n \"requestTestNotification\" : true\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://{{CAPIF_HOSTNAME}}/{{ONBOARDING_URL_INVOKER}}", + "protocol": "https", + "host": [ + "{{CAPIF_HOSTNAME}}" + ], + "path": [ + "{{ONBOARDING_URL_INVOKER}}" + ] + } + }, + "response": [] + }, + { + "name": "08-discover", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "setTimeout(() => {", + " pm.sendRequest({", + " url: 'http://localhost:3000/write_cert',", + " method: 'POST',", + " header: 'Content-Type:application/json',", + " encoding: 'binary',", + " body: {", + " mode: 'raw',", + " raw: {cert: pm.environment.get('INVOKER_CERT'), key:pm.environment.get('INVOKER_KEY')}", + " }", + " }, function (err, response) {", + " console.log(response)", + " });", + " }, 5000);", + "", + "", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "var res = JSON.parse(responseBody);", + "if (pm.response.code == 200){", + "", + " res.serviceAPIDescriptions.forEach(function(api) {", + " pm.environment.set('API_SERVICE_ID', api.apiId);", + " pm.environment.set('API_NAME', api.apiName);", + " pm.environment.set('API_AEF_ID', api.aefProfiles[0].aefId);", + " pm.environment.set('IPV4ADDR', api.aefProfiles[0].interfaceDescriptions[0].ipv4Addr);", + " pm.environment.set('PORT', api.aefProfiles[0].interfaceDescriptions[0].port);", + " pm.environment.set('URI', api.aefProfiles[0].versions[0].resources[0].uri);", + " });", + "}" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true, + "strictSSL": true + }, + "request": { + "auth": { + "type": "noauth" + }, + "method": "GET", + "header": [ + { + "key": "", + "value": "", + "type": "text", + "disabled": true + } + ], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://{{CAPIF_HOSTNAME}}/{{DISCOVER_URL}}{{INVOKER_ID}}", + "protocol": "https", + "host": [ + "{{CAPIF_HOSTNAME}}" + ], + "path": [ + "{{DISCOVER_URL}}{{INVOKER_ID}}" + ] + } + }, + "response": [] + }, + { + "name": "09-security_context", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "setTimeout(() => {", + " pm.sendRequest({", + " url: 'http://localhost:3000/write_cert',", + " method: 'POST',", + " header: 'Content-Type:application/json',", + " encoding: 'binary',", + " body: {", + " mode: 'raw',", + " raw: {cert: pm.environment.get('INVOKER_CERT'), key:pm.environment.get('INVOKER_KEY')}", + " }", + " }, function (err, response) {", + " console.log(response)", + " });", + " }, 5000);", + "", + "", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "strictSSL": true + }, + "request": { + "auth": { + "type": "noauth" + }, + "method": "PUT", + "header": [ + { + "key": "", + "value": "", + "type": "text", + "disabled": true + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"securityInfo\": [\n {\n \"prefSecurityMethods\": [\n \"Oauth\"\n ],\n \"authenticationInfo\": \"string\",\n \"authorizationInfo\": \"string\",\n \"aefId\": \"{{API_AEF_ID}}\",\n \"apiId\": \"{{API_SERVICE_ID}}\"\n }\n ],\n \"notificationDestination\": \"https://mynotificationdest.com\",\n \"requestTestNotification\": true,\n \"websockNotifConfig\": {\n \"websocketUri\": \"string\",\n \"requestWebsocketUri\": true\n },\n \"supportedFeatures\": \"fff\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://{{CAPIF_HOSTNAME}}/capif-security/v1/trustedInvokers/{{INVOKER_ID}}", + "protocol": "https", + "host": [ + "{{CAPIF_HOSTNAME}}" + ], + "path": [ + "capif-security", + "v1", + "trustedInvokers", + "{{INVOKER_ID}}" + ] + } + }, + "response": [] + }, + { + "name": "10-get_token", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "setTimeout(() => {", + " pm.sendRequest({", + " url: 'http://localhost:3000/write_cert',", + " method: 'POST',", + " header: 'Content-Type:application/json',", + " encoding: 'binary',", + " body: {", + " mode: 'raw',", + " raw: {cert: pm.environment.get('INVOKER_CERT'), key:pm.environment.get('INVOKER_KEY')}", + " }", + " }, function (err, response) {", + " console.log(response)", + " });", + " }, 5000);", + "", + "", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "var res = JSON.parse(responseBody);", + "if (pm.response.code == 200){", + " pm.environment.set('NETAPP_SERVICE_TOKEN', res.access_token);", + "}" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "strictSSL": true, + "disabledSystemHeaders": {} + }, + "request": { + "auth": { + "type": "noauth" + }, + "method": "POST", + "header": [ + { + "key": "", + "value": "", + "type": "text", + "disabled": true + } + ], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "client_id", + "value": "{{INVOKER_ID}}", + "type": "text" + }, + { + "key": "grant_type", + "value": "client_credentials", + "type": "text" + }, + { + "key": "client_secret", + "value": "string", + "type": "text" + }, + { + "key": "scope", + "value": "3gpp#{{API_AEF_ID}}:{{API_NAME}}", + "type": "text" + } + ] + }, + "url": { + "raw": "https://{{CAPIF_HOSTNAME}}/capif-security/v1/securities/{{INVOKER_ID}}/token", + "protocol": "https", + "host": [ + "{{CAPIF_HOSTNAME}}" + ], + "path": [ + "capif-security", + "v1", + "securities", + "{{INVOKER_ID}}", + "token" + ] + } + }, + "response": [] + }, + { + "name": "11-call_service", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "strictSSL": false + }, + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{NETAPP_SERVICE_TOKEN}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [ + { + "key": "", + "value": "", + "type": "text", + "disabled": true + } + ], + "body": { + "mode": "raw", + "raw": "{\n\"name\": {{USERNAME_INVOKER}}\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://{{IPV4ADDR}}:{{PORT}}{{URI}}", + "protocol": "http", + "host": [ + "{{IPV4ADDR}}" + ], + "port": "{{PORT}}{{URI}}" + } + }, + "response": [] + }, + { + "name": "offboard_provider", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "setTimeout(() => {", + " pm.sendRequest({", + " url: 'http://localhost:3000/write_cert',", + " method: 'POST',", + " header: 'Content-Type:application/json',", + " encoding: 'binary',", + " body: {", + " mode: 'raw',", + " raw: {cert: pm.environment.get('AMF_CERT'), key:pm.environment.get('AMF_KEY')}", + " }", + " }, function (err, response) {", + " console.log(response)", + " });", + " }, 5000);" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "strictSSL": true + }, + "request": { + "auth": { + "type": "noauth" + }, + "method": "DELETE", + "header": [], + "url": { + "raw": "https://{{CAPIF_HOSTNAME}}/{{ONBOARDING_URL}}/{{PROVIDER_ID}}", + "protocol": "https", + "host": [ + "{{CAPIF_HOSTNAME}}" + ], + "path": [ + "{{ONBOARDING_URL}}", + "{{PROVIDER_ID}}" + ] + } + }, + "response": [] + }, + { + "name": "offboard_invoker", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "setTimeout(() => {", + " pm.sendRequest({", + " url: 'http://localhost:3000/write_cert',", + " method: 'POST',", + " header: 'Content-Type:application/json',", + " encoding: 'binary',", + " body: {", + " mode: 'raw',", + " raw: {cert: pm.environment.get('INVOKER_CERT'), key:pm.environment.get('INVOKER_KEY')}", + " }", + " }, function (err, response) {", + " console.log(response)", + " });", + " }, 5000);" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "strictSSL": true + }, + "request": { + "auth": { + "type": "noauth" + }, + "method": "DELETE", + "header": [], + "url": { + "raw": "https://{{CAPIF_HOSTNAME}}/{{ONBOARDING_URL_INVOKER}}/{{INVOKER_ID}}", + "protocol": "https", + "host": [ + "{{CAPIF_HOSTNAME}}" + ], + "path": [ + "{{ONBOARDING_URL_INVOKER}}", + "{{INVOKER_ID}}" + ] + } + }, + "response": [] + }, + { + "name": "remove_user_invoker", + "request": { + "method": "DELETE", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n\"password\": \"{{PASSWORD}}\",\n\"username\": \"{{USERNAME_INVOKER}}\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://{{REGISTER_HOSTNAME}}:{{REGISTER_PORT}}/remove", + "protocol": "https", + "host": [ + "{{REGISTER_HOSTNAME}}" + ], + "port": "{{REGISTER_PORT}}", + "path": [ + "remove" + ] + } + }, + "response": [] + }, + { + "name": "remove_user_provider", + "request": { + "method": "DELETE", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n\"password\": \"{{PASSWORD}}\",\n\"username\": \"{{USERNAME}}\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://{{REGISTER_HOSTNAME}}:{{REGISTER_PORT}}/remove", + "protocol": "https", + "host": [ + "{{REGISTER_HOSTNAME}}" + ], + "port": "{{REGISTER_PORT}}", + "path": [ + "remove" + ] + } + }, + "response": [] + } + ] +} \ No newline at end of file diff --git a/doc/testing/postman/CAPIF.postman_environment.json b/doc/testing/postman/CAPIF.postman_environment.json new file mode 100644 index 0000000000000000000000000000000000000000..ab3839e9e78b498312a14db675316a76455747b0 --- /dev/null +++ b/doc/testing/postman/CAPIF.postman_environment.json @@ -0,0 +1,237 @@ +{ + "id": "f2daf431-63c4-4275-8755-4cc5de2e566d", + "name": "CAPIF", + "values": [ + { + "key": "CAPIF_HOSTNAME", + "value": "capifcore", + "type": "default", + "enabled": true + }, + { + "key": "CAPIF_PORT", + "value": "8080", + "type": "default", + "enabled": true + }, + { + "key": "REGISTER_HOSTNAME", + "value": "localhost", + "type": "default", + "enabled": true + }, + { + "key": "REGISTER_PORT", + "value": "8084", + "type": "default", + "enabled": true + }, + { + "key": "USERNAME", + "value": "ProviderONE", + "type": "default", + "enabled": true + }, + { + "key": "PASSWORD", + "value": "pass", + "type": "default", + "enabled": true + }, + { + "key": "CALLBACK_IP", + "value": "host.docker.internal", + "type": "default", + "enabled": true + }, + { + "key": "CALLBACK_PORT", + "value": "8087", + "type": "default", + "enabled": true + }, + { + "key": "ONBOARDING_URL", + "value": "", + "type": "any", + "enabled": true + }, + { + "key": "PUBLISH_URL", + "value": "", + "type": "any", + "enabled": true + }, + { + "key": "USER_ID", + "value": "", + "type": "any", + "enabled": true + }, + { + "key": "CA_ROOT", + "value": "", + "type": "any", + "enabled": true + }, + { + "key": "ACCESS_TOKEN", + "value": "", + "type": "any", + "enabled": true + }, + { + "key": "APF_KEY", + "value": "", + "type": "any", + "enabled": true + }, + { + "key": "AMF_KEY", + "value": "", + "type": "any", + "enabled": true + }, + { + "key": "AEF_KEY", + "value": "", + "type": "any", + "enabled": true + }, + { + "key": "PROVIDER_ID", + "value": "", + "type": "any", + "enabled": true + }, + { + "key": "AEF_ID", + "value": "", + "type": "any", + "enabled": true + }, + { + "key": "AEF_CERT", + "value": "", + "type": "any", + "enabled": true + }, + { + "key": "APF_ID", + "value": "", + "type": "any", + "enabled": true + }, + { + "key": "APF_CERT", + "value": "", + "type": "any", + "enabled": true + }, + { + "key": "AMF_ID", + "value": "", + "type": "any", + "enabled": true + }, + { + "key": "AMF_CERT", + "value": "", + "type": "any", + "enabled": true + }, + { + "key": "ONBOARDING_URL_INVOKER", + "value": "", + "type": "any", + "enabled": true + }, + { + "key": "DISCOVER_URL", + "value": "", + "type": "any", + "enabled": true + }, + { + "key": "USER_INVOKER_ID", + "value": "", + "type": "any", + "enabled": true + }, + { + "key": "ACCESS_TOKEN_INVOKER", + "value": "", + "type": "any", + "enabled": true + }, + { + "key": "INVOKER_KEY", + "value": "", + "type": "any", + "enabled": true + }, + { + "key": "INVOKER_ID", + "value": "", + "type": "any", + "enabled": true + }, + { + "key": "INVOKER_CERT", + "value": "", + "type": "any", + "enabled": true + }, + { + "key": "API_ID", + "value": "", + "type": "any", + "enabled": true + }, + { + "key": "API_NAME", + "value": "", + "type": "any", + "enabled": true + }, + { + "key": "IPV4ADDR", + "value": "", + "type": "any", + "enabled": true + }, + { + "key": "PORT", + "value": "", + "type": "any", + "enabled": true + }, + { + "key": "URI", + "value": "", + "type": "any", + "enabled": true + }, + { + "key": "API_SERVICE_ID", + "value": "", + "type": "any", + "enabled": true + }, + { + "key": "API_AEF_ID", + "value": "", + "type": "any", + "enabled": true + }, + { + "key": "NETAPP_SERVICE_TOKEN", + "value": "", + "type": "any", + "enabled": true + } + ], + "_postman_variable_scope": "environment", + "_postman_exported_at": "2023-12-20T10:47:32.128Z", + "_postman_exported_using": "Postman/10.21.4" +} \ No newline at end of file diff --git a/doc/testing/postman/README.md b/doc/testing/postman/README.md new file mode 100644 index 0000000000000000000000000000000000000000..fbe18f44d7744f1c45a18a9c944838a53332ab17 --- /dev/null +++ b/doc/testing/postman/README.md @@ -0,0 +1,135 @@ +# Postman +In this section we can use Postman to publish an API as a provider and use it as an invoker. + +## Requisites + +- We will need to have Node.js installed since we will use a small script to create the CSRs of the certificates. +- An instance of CAPIF (If it is not local, certain variables would have to be modified both in the Node.js script and in the Postman environment variables). + +## First steps + +1. Install the Node dependencies <a href="./package.json" download>package.json</a> to run the script with: + +``` +npm i +``` + +1. Run the <a href="./script.js" download>script.js</a> with the following command: + +``` +node script.js +``` + +3. Import Postman collection and environment variables (<a href="./CAPIF.postman_collection.json" download>CAPIF.postman_collection.json</a> and <a href="./CAPIF.postman_environment.json" download>CAPIF.postman_environment.json</a>) +4. Select CAPIF Environment before start testing. + +## Remote CAPIF + +If the CAPIF is not local, the host and port of both the CAPIF and the register would have to be specified in the variables, and the CAPIF_HOSTNAME in the script, necessary to obtain the server certificate. + +**Enviroments in Postman** +``` +CAPIF_HOSTNAME capifcore +CAPIF_PORT 8080 +REGISTER_HOSTNAME register +REGISTER_PORT 8084 +``` + +**Const in script.js** +``` +CAPIF_HOSTNAME capifcore +``` + +## CAPIF Flows +Once the first steps have been taken, we can now use Postman requests. These requests are numbered in the order that must be followed to obtain everything necessary from CAPIF. + +### Publication of an API + +#### **01-register_user_provider** + +_AEF.png) + +#### **02-getauth_provider** + + + +#### **03-onboard_provider** + + + +At this point we move on to using certificate authentication in CAPIF. In Postman it is necessary to add the certificates manually and using more than one certificate for the same host as we do in CAPIF complicates things. For this reason, we use the script to overwrite a certificate and a key when it is necessary to have a specific one. + +To configure go to **settings** in Postman and open the **certificates** section. + +- Here, activate the **CA certificates** option and add the **ca_cert.pem** file found in the **Responses** folder. +- Adds a client certificate specifying the CAPIF host being used and the files **client_cert.crt** and **client_key.key** in the **Responses** folder. + + +Once this is done, the node script will be in charge of changing the certificate that is necessary in each request. + +#### **04-publish_api** + + + +Once the api is published, we can start it. In this case we have a test one created in python called <a href="./hello_api.py" download>hello_api.py</a> that can be executed with the following command: + +``` +python3 hello_api.py +``` + +The API publication interface is set to localhost with port 8088, so the service must be set up locally. If you wanted to build it on another site, you would have to change the interface description in the body of publish_api. + +With this the provider part would be finished. + +### Calling the API + +#### **05-register_user_invoker** + +_Register.png) + +#### **06-getauth_invoker** + + + +#### **07-onboard_invoker** + + + +At this point we move on to using certificate authentication in CAPIF. **If you did not configure the provider's certificates, you would have to do it now**. + +#### **08-discover** + + + +#### **09-security_context** + + + +#### **10-get_token** + + + +#### **11-call_service** + + + +With this, we would have made the API call and finished the flow. + +### Other requests + +Other requests that we have added are the following: + +- **offboard_provider** Performs offboarding of the provider, thereby eliminating the published APIs. +- **offboard_invoker** Offboards the invoker, also eliminating access to the APIs of that invoker. +- **remove_user_invoker** Delete the user created for the invoker. +- **remove_user_provider** Delete the user created for the provider. + +## Notes + +- This process is designed to teach how requests are made in Postman and the flow that should be followed to publish and use an API. +- It is possible that if external CAPIFs are used (Public CAPIF) the test data may already be used or the API already registered. +- It is necessary to have the Node service running to make the certificate change for the requests, otherwise it will not work. +- We are working on adding more requests to the Postman collection. +- This collection is a testing guide and is recommended for testing purposes only. + + diff --git a/doc/testing/postman/hello_api.py b/doc/testing/postman/hello_api.py new file mode 100644 index 0000000000000000000000000000000000000000..0b2a35989ecfaa144489d1b6012f61453c91bd68 --- /dev/null +++ b/doc/testing/postman/hello_api.py @@ -0,0 +1,38 @@ +from flask import Flask, jsonify, request +from flask_jwt_extended import jwt_required, JWTManager, get_jwt_identity, get_jwt +import ssl +from werkzeug import serving +import socket, ssl +import OpenSSL +from OpenSSL import crypto +import jwt +import pyone + +app = Flask(__name__) + +jwt_flask = JWTManager(app) + + +with open("Responses/cert_server.pem", "rb") as cert_file: + cert= cert_file.read() + +crtObj = crypto.load_certificate(crypto.FILETYPE_PEM, cert) +pubKeyObject = crtObj.get_pubkey() +pubKeyString = crypto.dump_publickey(crypto.FILETYPE_PEM,pubKeyObject) + +app.config['JWT_ALGORITHM'] = 'RS256' +app.config['JWT_PUBLIC_KEY'] = pubKeyString + + +@app.route("/hello", methods=["POST"]) +@jwt_required() +def hello(): + + request_data = request.get_json() + + user_name = request_data['name'] + + return jsonify(f"Hello: {user_name}, welcome to CAPIF.") + +if __name__ == '__main__': + serving.run_simple("0.0.0.0", 8088, app) diff --git a/doc/testing/postman/package.json b/doc/testing/postman/package.json new file mode 100644 index 0000000000000000000000000000000000000000..6d612a702d5a9fa9a112f1a2f47c44f75725fa00 --- /dev/null +++ b/doc/testing/postman/package.json @@ -0,0 +1,16 @@ +{ + "name": "node-server", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "body-parser": "^1.18.3", + "express": "^4.16.3", + "shelljs": "^0.8.2" + } + } \ No newline at end of file diff --git a/doc/testing/postman/script.js b/doc/testing/postman/script.js new file mode 100644 index 0000000000000000000000000000000000000000..980f81f33b4bda4f48f55dcd13d8f436dface9a5 --- /dev/null +++ b/doc/testing/postman/script.js @@ -0,0 +1,199 @@ +// Change this variable if another host is used for CAPIF +const CAPIF_HOSTNAME = 'capifcore'; + +const express = require('express'), + app = express(), + fs = require('fs'), + shell = require('shelljs'), + + + folderPath = './Responses/', + bodyParser = require('body-parser'), + path = require('path'); + +const { exec } = require('child_process'); + +// Create the folder path in case it doesn't exist +shell.mkdir('-p', folderPath); + + // Change the limits according to your response size +app.use(bodyParser.json({limit: '50mb', extended: true})); +app.use(bodyParser.urlencoded({ limit: '50mb', extended: true })); +var opensslCommand = '' + +if (CAPIF_HOSTNAME.includes(':')){ + opensslCommand = `openssl s_client -connect ${CAPIF_HOSTNAME} | openssl x509 -text > ./Responses/cert_server.pem`; +} +else{ + opensslCommand = `openssl s_client -connect ${CAPIF_HOSTNAME}:443 | openssl x509 -text > ./Responses/cert_server.pem`; +} + +exec(opensslCommand, (error, stdout, stderr) => { + if (error) { + console.error(`Error generating CSR: ${stderr}`); + } +}); + +fs.writeFileSync('./Responses/client_cert.crt', ''); +fs.writeFileSync('./Responses/client_key.key', ''); + +app.get('/', (req, res) => res.send('Hello, I write data to file. Send them requests!')); + +app.post('/generate_csr', (req, res) => { + + console.log(req.body); + const csrFilePath = 'Responses/'+req.body.apiProvFuncRole+'_csr.pem'; + const privateKeyFilePath = 'Responses/'+req.body.apiProvFuncRole+'_key.key'; + + const subjectInfo = { + country: 'ES', + state: 'Madrid', + locality: 'Madrid', + organization: 'Telefonica I+D', + organizationalUnit: 'IT Department', + emailAddress: 'admin@example.com', + }; + + const opensslCommand = `openssl req -newkey rsa:2048 -nodes -keyout ${privateKeyFilePath} -out ${csrFilePath} -subj "/C=${subjectInfo.country}/ST=${subjectInfo.state}/L=${subjectInfo.locality}/O=${subjectInfo.organization}/OU=${subjectInfo.organizationalUnit}/emailAddress=${subjectInfo.emailAddress}"`; + + exec(opensslCommand, (error, stdout, stderr) => { + if (error) { + console.error(`Error generating CSR: ${stderr}`); + } else { + console.log('CSR generated successfully:'); + fs.readFile(csrFilePath, 'utf8', (readError, csrContent) => { + if (readError) { + console.error(`Error reading CSR: ${readError}`); + res.status(500).send('Error reading CSR'); + } else { + console.log('CSR read successfully:'); + // Send the CSR content in the response + fs.readFile(privateKeyFilePath, 'utf8', (readError, keyContent) => { + if (readError) { + console.error(`Error reading KEY: ${readError}`); + res.status(500).send('Error reading KEY'); + } else { + console.log('KEY read successfully:'); + // Send the CSR content in the response + fs.unlink(csrFilePath, (err) => { + if (err) { + console.error(`Error deleting file: ${err.message}`); + } + }); + fs.unlink(privateKeyFilePath, (err) => { + if (err) { + console.error(`Error deleting file: ${err.message}`); + } + }); + res.send({csr: csrContent, key: keyContent}); + } + }); + } + }); + } + }); +}); + +app.post('/generate_csr_invoker', (req, res) => { + + console.log(req.body); + const csrFilePath = 'Responses/invoker_csr.pem'; + const privateKeyFilePath = 'Responses/invoker_key.key'; + + const subjectInfo = { + country: 'ES', + state: 'Madrid', + locality: 'Madrid', + organization: 'Telefonica I+D', + organizationalUnit: 'IT Department', + emailAddress: 'admin@example.com', + }; + + const opensslCommand = `openssl req -newkey rsa:2048 -nodes -keyout ${privateKeyFilePath} -out ${csrFilePath} -subj "/C=${subjectInfo.country}/ST=${subjectInfo.state}/L=${subjectInfo.locality}/O=${subjectInfo.organization}/OU=${subjectInfo.organizationalUnit}/emailAddress=${subjectInfo.emailAddress}"`; + + exec(opensslCommand, (error, stdout, stderr) => { + if (error) { + console.error(`Error generating CSR: ${stderr}`); + } else { + console.log('CSR generated successfully:'); + fs.readFile(csrFilePath, 'utf8', (readError, csrContent) => { + if (readError) { + console.error(`Error reading CSR: ${readError}`); + res.status(500).send('Error reading CSR'); + } else { + console.log('CSR read successfuly:'); + // Send the CSR content in the response + fs.readFile(privateKeyFilePath, 'utf8', (readError, keyContent) => { + if (readError) { + console.error(`Error reading KEY: ${readError}`); + res.status(500).send('Error reading KEY'); + } else { + console.log('KEY read successfully:'); + // Send the CSR content in the response + fs.unlink(csrFilePath, (err) => { + if (err) { + console.error(`Error deleting file: ${err.message}`); + } + }); + fs.unlink(privateKeyFilePath, (err) => { + if (err) { + console.error(`Error deleting file: ${err.message}`); + } + }); + res.send({csr: csrContent, key: keyContent}); + } + }); + } + }); + } + }); +}); + + +app.post('/write_cert', (req, res) => { + let extension = 'crt', + fsMode = 'writeFile', + filename = "client_cert", + filePath = `${path.join(folderPath, filename)}.${extension}`, + options = {encoding: 'binary'}; + fs[fsMode](filePath, req.body.cert, options, (err) => { + if (err) { + console.log(err); + res.send('Error'); + } + }); + extension = 'key'; + filename = "client_key"; + filePath = `${path.join(folderPath, filename)}.${extension}`; + fs[fsMode](filePath, req.body.key, options, (err) => { + if (err) { + console.log(err); + res.send('Error'); + } + else { + res.send('Success'); + } + }); +}); + +app.post('/write_ca', (req, res) => { + let extension = 'pem', + fsMode = 'writeFile', + filename = "ca_cert", + filePath = `${path.join(folderPath, filename)}.${extension}`, + options = {encoding: 'binary'}; + fs[fsMode](filePath, req.body.ca_root, options, (err) => { + if (err) { + console.log(err); + res.send('Error'); + } + else { + res.send('Success'); + } + }); +}); + +app.listen(3000, () => { + console.log('ResponsesToFile App is listening now! Send them requests my way!'); + console.log(`Data is being stored at location: ${path.join(process.cwd(), folderPath)}`); +}); \ No newline at end of file diff --git a/doc/testing/robotframework/README.md b/doc/testing/robotframework/README.md new file mode 100644 index 0000000000000000000000000000000000000000..7eb83dd48697fafb4973b9bdc3da19c264dd2f91 --- /dev/null +++ b/doc/testing/robotframework/README.md @@ -0,0 +1,74 @@ +# Robot Framework + +## Steps to Test + +To run any test locally you will need *docker* and *docker-compose* installed in order run services and execute test plan. Steps will be: + +* **Run All Services**: See section [Run All CAPIF Services](../../gettingstarted/howtorun.md#run-all-capif-services-locally-with-docker-images) + +* **Run desired tests**: At this point we have 2 options: + + * **Using helper script**: [Script Test Execution](#script-test-execution) + * **Build robot docker image and execute manually robot docker**: [Manual Build And Test Execution](#manual-build-and-test-execution) + + +## Script Test Execution +This script will build robot docker image if it's need and execute tests selected by "include" option. Just go to service folder, execute and follow steps. +``` +./runCapifTests.sh --include <TAG> +``` +Results will be stored at <REPOSITORY_FOLDER>/results + +Please check parameters (include) under *Test Execution* at [Manual Build And Test Execution](#manual-build-and-test-execution). + +## Manual Build And Test Execution + +* **Build Robot docker image**: +``` +cd tools/robot +docker build . -t 5gnow-robot-test:latest +``` + +* **Tests Execution**: + +Execute all tests locally: +``` +<PATH_TO_REPOSITORY>=path in local machine to repository cloned. +<PATH_RESULT_FOLDER>=path to a folder on local machine to store results of Robot Framework execution. +<CAPIF_HOSTNAME>=Is the hostname set when run.sh is executed, by default it will be capifcore. +<CAPIF_HTTP_PORT>=This is the port to reach when robot framework want to reach CAPIF deployment using http, this should be set to port without TLS set on Nginx, 8080 by default. + +To execute all tests run : +docker run -ti --rm --network="host" -v <PATH_TO_REPOSITORY>/tests:/opt/robot-tests/tests -v <PATH_RESULT_FOLDER>:/opt/robot-tests/results 5gnow-robot-test:latest --variable CAPIF_HOSTNAME:capifcore --variable CAPIF_HTTP_PORT:8080 --include all +``` + +Execute specific tests locally: +``` +To run more specific tests, for example, only one functionality: +<TAG>=Select one from list: + "capif_api_acl", + "capif_api_auditing_service", + "capif_api_discover_service", + "capif_api_events", + "capif_api_invoker_management", + "capif_api_logging_service", + "capif_api_provider_management", + "capif_api_publish_service", + "capif_security_api + +And Run: +docker run -ti --rm --network="host" -v <PATH_TO_REPOSITORY>/tests:/opt/robot-tests/tests -v <PATH_RESULT_FOLDER>:/opt/robot-tests/results 5gnow-robot-test:latest --variable CAPIF_HOSTNAME:capifcore --variable CAPIF_HTTP_PORT:8080 --include <TAG> +``` + +## Test result review + +In order to Review results after tests, you can check general report at <PATH_RESULT_FOLDER>/report.html or if you need more detailed information <PATH_RESULT_FOLDER>/log.html, example: + +* Report: + + +* Detailed information: + + +**NOTE: If you need more detail at Robot Framework Logs you can set log level option just adding to command --loglevel DEBUG** + diff --git a/doc/testing/robotframework/robot_log_example.png b/doc/testing/robotframework/robot_log_example.png new file mode 100644 index 0000000000000000000000000000000000000000..6c15a031e26eae47fed53b21a1e69e2f7bfa89db Binary files /dev/null and b/doc/testing/robotframework/robot_log_example.png differ diff --git a/doc/testing/robotframework/robot_report_example.png b/doc/testing/robotframework/robot_report_example.png new file mode 100644 index 0000000000000000000000000000000000000000..1cf36d8766753d08938be73c87e958f4c8d56068 Binary files /dev/null and b/doc/testing/robotframework/robot_report_example.png differ diff --git a/doc/testing/robotframwork.md b/doc/testing/robotframwork.md deleted file mode 100644 index 9f11a15a581466e1f12524f063ead9b7c015a858..0000000000000000000000000000000000000000 --- a/doc/testing/robotframwork.md +++ /dev/null @@ -1,2 +0,0 @@ -# Robot Framework - diff --git a/doc/testing/testing.md b/doc/testing/testing.md deleted file mode 100644 index fd198fa0583830f46de803858b1057d372097b8a..0000000000000000000000000000000000000000 --- a/doc/testing/testing.md +++ /dev/null @@ -1,2 +0,0 @@ -# Testing - diff --git a/doc/testing/testplan.md b/doc/testing/testplan.md deleted file mode 100644 index 18f8f2cad1cfba2d9a4da80d6d965b450437a0e8..0000000000000000000000000000000000000000 --- a/doc/testing/testplan.md +++ /dev/null @@ -1 +0,0 @@ -# Test Plan diff --git a/doc/testing/testplan/README.md b/doc/testing/testplan/README.md new file mode 100644 index 0000000000000000000000000000000000000000..2031569738a2ae34529a68bd4568f996813b90bc --- /dev/null +++ b/doc/testing/testplan/README.md @@ -0,0 +1,12 @@ +# Test Plan Index +List of Common API Services implemented: + +* [Api Invoker Management](./api_invoker_management/README.md) +* [Api Provider Management](./api_provider_management/README.md) +* [Api Publish Service](./api_publish_service/README.md) +* [Api Discover Service](./api_discover_service/README.md) +* [Api Events Service](./api_events_service/README.md) +* [Api Security Service](./api_security_service/README.md) +* [Api Logging Service](./api_logging_service/README.md) +* [Api Auditing Service](./api_auditing_service/README.md) +* [Api Access Control Policy](./api_access_control_policy/README.md) diff --git a/doc/testing/testplan/api_access_control_policy/README.md b/doc/testing/testplan/api_access_control_policy/README.md new file mode 100644 index 0000000000000000000000000000000000000000..dae28c55aae6c70c18883abeeed8a351284c6984 --- /dev/null +++ b/doc/testing/testplan/api_access_control_policy/README.md @@ -0,0 +1,829 @@ +# Test Plan for CAPIF Api Access Control Policy +At this documentation you will have all information and related files and examples of test plan for this API. + +## Test Case 1: Retrieve ACL + +**Test ID**: ***capif_api_acl-1*** + +**Description**: + + This test case will check that an API Provider can retrieve ACL from CAPIF + +**Pre-Conditions**: + + * API Provider had a Service API Published on CAPIF + * API Invoker had a Security Context for Service API published. + +**Information of Test**: + + 1. Perform [Provider Registration] + + 2. Publish Service API at CCF: + * Send Post to ccf_publish_url *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis* + * body [service api description] with apiName service_1 + * Store *serviceApiId* + * Use APF Certificate + + 3. Perform [Invoker Onboarding] store apiInvokerId + 4. Discover published APIs + 5. Create Security Context for this Invoker + * Send PUT *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * body [service security body] + * Use Invoker Certificate + + 6. Provider Retrieve ACL + * Send GET *https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId}?aef-id=${aef_id}* + * Use *serviceApiId* and *aefId* + * Use AEF Provider Certificate + +**Execution Steps**: + + 1. Register and onboard Provider at CCF. + 2. Publish a provider API with name service_1 + 3. Register and onboard Invoker at CCF + 4. Store signed Certificate + 5. Create Security Context + 6. Provider Get ACL information. + +**Expected Result**: + + 1. ACL Response: + 1. **200 OK** Response. + 2. body returned must accomplish **AccessControlPolicyList** data structure. + 3. apiInvokerPolicies must: + 1. contain only one object. + 2. apiInvokerId must match apiInvokerId registered previously. + + +## Test Case 2: Retrieve ACL with 2 Service APIs published + +**Test ID**: ***capif_api_acl-2*** + +**Description**: + + This test case will check that an API Provider can retrieve ACL from CAPIF for 2 different serviceApis published. + +**Pre-Conditions**: + + * API Provider had two Service API Published on CAPIF + * API Invoker had a Security Context for both Service APIs published. + +**Information of Test**: + + 1. Perform [Provider Registration] + + 2. Publish Service API at CCF: + * Send Post to ccf_publish_url *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis* + * body [service api description] with apiName service_1 + * Store *serviceApiId* + * Use APF Certificate + + 3. Publish Service API at CCF: + * Send Post to ccf_publish_url *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis* + * body [service api description] with apiName service_2 + * Store *serviceApiId* + * Use APF Certificate + + 4. Perform [Invoker Onboarding] store apiInvokerId + 5. Discover published APIs + 6. Create Security Context for this Invoker for both published APIs + * Send PUT *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * body [service security body] + * Use Invoker Certificate + + 7. Provider Retrieve ACL for serviceApiId1 + * Send GET *https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId1}?aef-id=${aef_id}* + * Use *serviceApiId* and *aefId* + * Use AEF Provider Certificate + + 8. Provider Retrieve ACL for serviceApiId2 + * Send GET *https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId2}?aef-id=${aef_id}* + * Use *serviceApiId* and *aefId* + * Use AEF Provider Certificate + +**Execution Steps**: + + 1. Register and onboard Provider at CCF. + 2. Publish a provider API with name service_1 and service_2 + 3. Register and onboard Invoker at CCF + 4. Store signed Certificate + 5. Create Security Context + 6. Provider Get ACL information for service_1. + 7. Provider Get ACL information for service_2. + +**Expected Result**: + + 1. ACL Response: + 1. **200 OK** Response. + 2. body returned must accomplish **AccessControlPolicyList** data structure. + 3. apiInvokerPolicies must: + 1. contain one object. + 2. apiInvokerId must match apiInvokerId registered previously. + +## Test Case 3: Retrieve ACL with security context created by two different Invokers + +**Test ID**: ***capif_api_acl-3*** + +**Description**: + + This test case will check that an API Provider can retrieve ACL from CAPIF containing 2 objects. + +**Pre-Conditions**: + + * API Provider had a Service API Published on CAPIF + * Two API Invokers had a Security Context for same Service API published by provider. + +**Information of Test**: + + 1. Perform [Provider Registration] + + 2. Publish Service API at CCF: + * Send Post to ccf_publish_url *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis* + * body [service api description] with apiName service_1 + * Store *serviceApiId* + * Use APF Certificate + + 3. Perform [Invoker Onboarding] store apiInvokerId + 4. Discover published APIs + 5. Create Security Context for this Invoker for both published APIs + * Send PUT *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * body [service security body] + * Use Invoker Certificate + + 6. Repeat previous 3 steps in order to have a new Invoker. + + 7. Provider Retrieve ACL for serviceApiId + * Send GET *https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId1}?aef-id=${aef_id}* + * Use *serviceApiId* and *aefId* + * Use AEF Provider Certificate + +**Execution Steps**: + + 1. Register and onboard Provider at CCF. + 2. Publish a provider API with name service_1 and service_2 + 3. Register and onboard Invoker at CCF + 4. Store signed Certificate + 5. Create Security Context + 6. Provider Get ACL information. + +**Expected Result**: + + 1. ACL Response: + 1. **200 OK** Response. + 2. body returned must accomplish **AccessControlPolicyList** data structure. + 3. apiInvokerPolicies must: + 1. Contain two objects. + 2. One object must match with apiInvokerId1 and the other one with apiInvokerId2 an registered previously. + +## Test Case 4: Retrieve ACL filtered by api-invoker-id + +**Test ID**: ***capif_api_acl-4*** + +**Description**: + + This test case will check that an API Provider can retrieve ACL filtering by apiInvokerId from CAPIF containing 1 objects. + +**Pre-Conditions**: + + * API Provider had a Service API Published on CAPIF + * Two API Invokers had a Security Context for same Service API published by provider. + +**Information of Test**: + + 1. Perform [Provider Registration] + + 2. Publish Service API at CCF: + * Send Post to ccf_publish_url *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis* + * body [service api description] with apiName service_1 + * Store *serviceApiId* + * Use APF Certificate + + 4. Perform [Invoker Onboarding] store apiInvokerId + 6. Discover published APIs + 7. Create Security Context for this Invoker for both published APIs + * Send PUT *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * body [service security body] + * Use Invoker Certificate + + 8. Repeat previous 3 steps in order to have a new Invoker. + + 9. Provider Retrieve ACL for serviceApiId + * Send GET *https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId1}?aef-id=${aef_id}&api-invoker-id={apiInvokerId1}* + * Use *serviceApiId*, *aefId* and apiInvokerId1 + * Use AEF Provider Certificate + + 10. Provider Retrieve ACL for serviceApiId + * Send GET *https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId1}?aef-id=${aef_id}&api-invoker-id={apiInvokerId2}* + * Use *serviceApiId*, *aefId* and apiInvokerId2 + * Use AEF Provider Certificate + +**Execution Steps**: + + 1. Register and onboard Provider at CCF. + 2. Publish a provider API with name service_1 and service_2 + 3. Register and onboard Invoker at CCF + 4. Store signed Certificate + 5. Create Security Context + 6. Provider Get ACL information with query parameter indicating first api-invoker-id. + 7. Provider Get ACL information with query parameter indicating second api-invoker-id. + +**Expected Result**: + + 1. ACL Response: + 1. **200 OK** Response. + 2. body returned must accomplish **AccessControlPolicyList** data structure. + 3. apiInvokerPolicies must: + 1. Contain one objects. + 2. Object must match with apiInvokerId1. + + 2. ACL Response: + 1. **200 OK** Response. + 2. body returned must accomplish **AccessControlPolicyList** data structure. + 3. apiInvokerPolicies must: + 1. Contain one objects. + 2. Object must match with apiInvokerId2. + +## Test Case 5: Retrieve ACL filtered by supported-features + +**Test ID**: ***capif_api_acl-5*** + +**Description**: + + **CURRENTLY NOT SUPPORTED FEATURE** + + This test case will check that an API Provider can retrieve ACL filtering by supportedFeatures from CAPIF containing 1 objects. + +**Pre-Conditions**: + + * API Provider had a Service API Published on CAPIF + * Two API Invokers had a Security Context for same Service API published by provider. + +**Information of Test**: + + 1. Perform [Provider Registration] + + 2. Publish Service API at CCF: + * Send Post to ccf_publish_url *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis* + * body [service api description] with apiName service_1 + * Store *serviceApiId* + * Use APF Certificate + + 3. Perform [Invoker Onboarding] store apiInvokerId + 4. Discover published APIs + 5. Create Security Context for this Invoker for both published APIs + * Send PUT *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * body [service security body] + * Use Invoker Certificate + + 6. Repeat previous 3 steps in order to have a new Invoker. + + 7. Provider Retrieve ACL for serviceApiId + * Send GET *https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId1}?aef-id=${aef_id}&supported-features={apiInvokerId1}* + * Use *serviceApiId*, *aefId* and apiInvokerId1 + * Use AEF Provider Certificate + + 8. Provider Retrieve ACL for serviceApiId + * Send GET *https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId1}?aef-id=${aef_id}&supported-features={apiInvokerId2}* + * Use *serviceApiId*, *aefId* and apiInvokerId2 + * Use AEF Provider Certificate + +**Execution Steps**: + + 1. Register and onboard Provider at CCF. + 2. Publish a provider API with name service_1 and service_2 + 3. Register and onboard Invoker at CCF + 4. Store signed Certificate + 5. Create Security Context + 6. Provider Get ACL information with query parameter indicating first supported-features. + 7. Provider Get ACL information with query parameter indicating second supported-features. + +**Expected Result**: + + 1. ACL Response: + 1. **200 OK** Response. + 2. body returned must accomplish **AccessControlPolicyList** data structure. + 3. apiInvokerPolicies must: + 1. Contain one objects. + 2. Object must match with supportedFeatures1. + + 2. ACL Response: + 1. **200 OK** Response. + 2. body returned must accomplish **AccessControlPolicyList** data structure. + 3. apiInvokerPolicies must: + 1. Contain one objects. + 2. Object must match with supportedFeatures1. + + +## Test Case 6: Retrieve ACL with aef-id not valid + +**Test ID**: ***capif_api_acl-6*** + +**Description**: + + This test case will check that an API Provider can't retrieve ACL from CAPIF if aef-id is not valid + +**Pre-Conditions**: + + * API Provider had a Service API Published on CAPIF + * API Invoker had a Security Context for Service API published. + +**Information of Test**: + + 1. Perform [Provider Registration] + + 2. Publish Service API at CCF: + * Send Post to ccf_publish_url *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis* + * body [service api description] with apiName service_1 + * Store *serviceApiId* + * Use APF Certificate + + 3. Perform [Invoker Onboarding] store apiInvokerId + 4. Discover published APIs + 5. Create Security Context for this Invoker + * Send PUT *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * body [service security body] + * Use Invoker Certificate + + 6. Provider Retrieve ACL + * Send GET *https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId}?aef-id=${AEF_ID_NOT_VALID}* + * Use *serviceApiId* and *AEF_ID_NOT_VALID* + * Use AEF Provider Certificate + +**Execution Steps**: + + 1. Register and onboard Provider at CCF. + 2. Publish a provider API with name service_1 + 3. Register and onboard Invoker at CCF + 4. Store signed Certificate + 5. Create Security Context + 6. Provider Get ACL information. + +**Expected Result**: + + 1. ACL Response: + 1. **404 Not Found** Response. + 2. body returned must accomplish **Problem Details** data structure. + 3. apiInvokerPolicies must: + * status **404** + * title with message "Not Found" + * detail with message "No ACLs found for the requested service: {service_api_id}, aef_id: {aef_id}, invoker: {api_invoker_id} and supportedFeatures: {supported_features}". + * cause with message "Wrong id". + + +## Test Case 7: Retrieve ACL with service-id not valid + +**Test ID**: ***capif_api_acl-7*** + +**Description**: + + This test case will check that an API Provider can't retrieve ACL from CAPIF if service-api-id is not valid + +**Pre-Conditions**: + + * API Provider had a Service API Published on CAPIF + * API Invoker had a Security Context for Service API published. + +**Information of Test**: + + 1. Perform [Provider Registration] + + 2. Publish Service API at CCF: + * Send Post to ccf_publish_url *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis* + * body [service api description] with apiName service_1 + * Store *serviceApiId* + * Use APF Certificate + + 3. Perform [Invoker Onboarding] store apiInvokerId + 4. Discover published APIs + 5. Create Security Context for this Invoker + * Send PUT *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * body [service security body] + * Use Invoker Certificate + + 6. Provider Retrieve ACL + * Send GET *https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${NOT_VALID_SERVICE_API_ID}?aef-id=${aef_id}* + * Use *NOT_VALID_SERVICE_API_ID* and *aef_id* + * Use AEF Provider Certificate + +**Execution Steps**: + + 1. Register and onboard Provider at CCF. + 2. Publish a provider API with name service_1 + 3. Register and onboard Invoker at CCF + 4. Store signed Certificate + 5. Create Security Context + 6. Provider Get ACL information. + +**Expected Result**: + + 1. ACL Response: + 1. **404 Not Found** Response. + 2. body returned must accomplish **Problem Details** data structure. + 3. apiInvokerPolicies must: + * status **404** + * title with message "Not Found" + * detail with message "No ACLs found for the requested service: {service_api_id}, aef_id: {aef_id}, invoker: {api_invoker_id} and supportedFeatures: {supported_features}". + * cause with message "Wrong id". + +## Test Case 8: Retrieve ACL with service-api-id and aef-id not valid + +**Test ID**: ***capif_api_acl-8*** + +**Description**: + + This test case will check that an API Provider can't retrieve ACL from CAPIF if service-api-id and aef-id are not valid + +**Pre-Conditions**: + + * API Provider had a Service API Published on CAPIF + * API Invoker had a Security Context for Service API published. + +**Information of Test**: + + 1. Perform [Provider Registration] + + 2. Publish Service API at CCF: + * Send Post to ccf_publish_url *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis* + * body [service api description] with apiName service_1 + * Store *serviceApiId* + * Use APF Certificate + + 3. Perform [Invoker Onboarding] store apiInvokerId + 4. Discover published APIs + 5. Create Security Context for this Invoker + * Send PUT *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * body [service security body] + * Use Invoker Certificate + + 6. Provider Retrieve ACL + * Send GET *https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${NOT_VALID_SERVICE_API_ID}?aef-id=${AEF_ID_NOT_VALID}* + * Use *NOT_VALID_SERVICE_API_ID* and *aef_id* + * Use AEF Provider Certificate + +**Execution Steps**: + + 1. Register and onboard Provider at CCF. + 2. Publish a provider API with name service_1 + 3. Register and onboard Invoker at CCF + 4. Store signed Certificate + 5. Create Security Context + 6. Provider Get ACL information. + +**Expected Result**: + + 1. ACL Response: + 1. **404 Not Found** Response. + 2. body returned must accomplish **Problem Details** data structure. + 3. apiInvokerPolicies must: + * status **404** + * title with message "Not Found" + * detail with message "No ACLs found for the requested service: {NOT_VALID_SERVICE_API_ID}, aef_id: {AEF_ID_NOT_VALID}, invoker: {api_invoker_id} and supportedFeatures: {supported_features}". + * cause with message "Wrong id". + + +## Test Case 9: Retrieve ACL without SecurityContext created previously by Invoker + +**Test ID**: ***capif_api_acl-9*** + +**Description**: + + This test case will check that an API Provider can't retrieve ACL if no invoker had requested Security Context to CAPIF + +**Pre-Conditions**: + + * API Provider had a Service API Published on CAPIF + * API Invoker created but no Security Context for Service API published had been requested. + +**Information of Test**: + + 1. Perform [Provider Registration] + + 2. Publish Service API at CCF: + * Send Post to ccf_publish_url *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis* + * body [service api description] with apiName service_1 + * Store *serviceApiId* + * Use APF Certificate + + 3. Perform [Invoker Onboarding] store apiInvokerId + 4. Discover published APIs + + 5. Provider Retrieve ACL + * Send GET *https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId}?aef-id=${aef_id}* + * Use *serviceApiId* and *aefId* + * Use AEF Provider Certificate + +**Execution Steps**: + + 1. Register and onboard Provider at CCF. + 2. Publish a provider API with name service_1 + 3. Register and onboard Invoker at CCF + 4. Store signed Certificate + 5. Create Security Context + 6. Provider Get ACL information. + +**Expected Result**: + + 1. ACL Response: + 1. **404 Not Found** Response. + 2. body returned must accomplish **Problem Details** data structure. + 3. apiInvokerPolicies must: + * status **404** + * title with message "Not Found" + * detail with message "No ACLs found for the requested service: {NOT_VALID_SERVICE_API_ID}, aef_id: {AEF_ID_NOT_VALID}, invoker: {api_invoker_id} and supportedFeatures: {supported_features}". + * cause with message "Wrong id". + +## Test Case 10: Retrieve ACL filtered by api-invoker-id not present + +**Test ID**: ***capif_api_acl-10*** + +**Description**: + + This test case will check that an API Provider get not found response if filter by not valid api-invoker-id doesn't match any registered ACL. + +**Pre-Conditions**: + + * API Provider had a Service API Published on CAPIF + * API Invoker had a Security Context for Service API published. + +**Information of Test**: + + 1. Perform [Provider Registration] + + 2. Publish Service API at CCF: + * Send Post to ccf_publish_url *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis* + * body [service api description] with apiName service_1 + * Store *serviceApiId* + * Use APF Certificate + + 3. Perform [Invoker Onboarding] store apiInvokerId + 4. Discover published APIs + 5. Create Security Context for this Invoker + * Send PUT *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * body [service security body] + * Use Invoker Certificate + + 6. Provider Retrieve ACL + * Send GET *https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId}?aef-id=${aef_id}&api-invoker-id={NOT_VALID_API_INVOKER_ID}* + * Use *serviceApiId*, *aefId* and *NOT_VALID_API_INVOKER_ID* + * Use AEF Provider Certificate + +**Execution Steps**: + + 1. Register and onboard Provider at CCF. + 2. Publish a provider API with name service_1 + 3. Register and onboard Invoker at CCF + 4. Store signed Certificate + 5. Create Security Context + 6. Provider Get ACL information. + +**Expected Result**: + + 1. ACL Response: + 1. **404 Not Found** Response. + 2. body returned must accomplish **Problem Details** data structure. + 3. apiInvokerPolicies must: + * status **404** + * title with message "Not Found" + * detail with message "No ACLs found for the requested service: {NOT_VALID_SERVICE_API_ID}, aef_id: {AEF_ID_NOT_VALID}, invoker: {api_invoker_id} and supportedFeatures: {supported_features}". + * cause with message "Wrong id". + +## Test Case 11: Retrieve ACL with APF Certificate + +**Test ID**: ***capif_api_acl-11*** + +**Description**: + + This test case will check that an API Provider can't retrieve ACL from CAPIF using APF Certificate + +**Pre-Conditions**: + + * API Provider had a Service API Published on CAPIF + * API Invoker had a Security Context for Service API published. + +**Information of Test**: + + 1. Perform [Provider Registration] + + 2. Publish Service API at CCF: + * Send Post to ccf_publish_url *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis* + * body [service api description] with apiName service_1 + * Store *serviceApiId* + * Use APF Certificate + + 3. Perform [Invoker Onboarding] store apiInvokerId + 4. Discover published APIs + 5. Create Security Context for this Invoker + * Send PUT *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * body [service security body] + * Use Invoker Certificate + + 6. Provider Retrieve ACL + * Send GET *https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId}?aef-id=${aef_id}* + * Use *serviceApiId* and *aefId* + * Use APF Provider Certificate + +**Execution Steps**: + + 1. Register and onboard Provider at CCF. + 2. Publish a provider API with name service_1 + 3. Register and onboard Invoker at CCF + 4. Store signed Certificate + 5. Create Security Context + 6. Provider Get ACL information. + +**Expected Result**: + + 1. Response to Logging Service must accomplish: + 1. **401 Unauthorized** + 2. Error Response Body must accomplish with **ProblemDetails** data structure with: + * status 401 + * title with message "Unauthorized" + * detail with message "Role not authorized for this API route". + * cause with message "Certificate not authorized". + +## Test Case 12: Retrieve ACL with AMF Certificate + +**Test ID**: ***capif_api_acl-12*** + +**Description**: + + This test case will check that an API Provider can't retrieve ACL from CAPIF using AMF Certificate + +**Pre-Conditions**: + + * API Provider had a Service API Published on CAPIF + * API Invoker had a Security Context for Service API published. + +**Information of Test**: + + 1. Perform [Provider Registration] + + 2. Publish Service API at CCF: + * Send Post to ccf_publish_url *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis* + * body [service api description] with apiName service_1 + * Store *serviceApiId* + * Use APF Certificate + + 3. Perform [Invoker Onboarding] store apiInvokerId + 4. Discover published APIs + 5. Create Security Context for this Invoker + * Send PUT *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * body [service security body] + * Use Invoker Certificate + + 6. Provider Retrieve ACL + * Send GET *https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId}?aef-id=${aef_id}* + * Use *serviceApiId* and *aefId* + * Use AMF Provider Certificate + +**Execution Steps**: + + 1. Register and onboard Provider at CCF. + 2. Publish a provider API with name service_1 + 3. Register and onboard Invoker at CCF + 4. Store signed Certificate + 5. Create Security Context + 6. Provider Get ACL information. + +**Expected Result**: + + 1. Response to Logging Service must accomplish: + 1. **401 Unauthorized** + 2. Error Response Body must accomplish with **ProblemDetails** data structure with: + * status 401 + * title with message "Unauthorized" + * detail with message "Role not authorized for this API route". + * cause with message "Certificate not authorized". + +## Test Case 13: Retrieve ACL with Invoker Certificate + +**Test ID**: ***capif_api_acl-13*** + +**Description**: + + This test case will check that an API Provider can't retrieve ACL from CAPIF using Invoker Certificate + +**Pre-Conditions**: + + * API Provider had a Service API Published on CAPIF + * API Invoker had a Security Context for Service API published. + +**Information of Test**: + + 1. Perform [Provider Registration] + + 2. Publish Service API at CCF: + * Send Post to ccf_publish_url *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis* + * body [service api description] with apiName service_1 + * Store *serviceApiId* + * Use APF Certificate + + 3. Perform [Invoker Onboarding] store apiInvokerId + 4. Discover published APIs + 5. Create Security Context for this Invoker + * Send PUT *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * body [service security body] + * Use Invoker Certificate + + 6. Provider Retrieve ACL + * Send GET *https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId}?aef-id=${aef_id}* + * Use *serviceApiId* and *aefId* + * Use Invoker Certificate + +**Execution Steps**: + + 1. Register and onboard Provider at CCF. + 2. Publish a provider API with name service_1 + 3. Register and onboard Invoker at CCF + 4. Store signed Certificate + 5. Create Security Context + 6. Provider Get ACL information. + +**Expected Result**: + + 1. Response to Logging Service must accomplish: + 1. **401 Unauthorized** + 2. Error Response Body must accomplish with **ProblemDetails** data structure with: + * status 401 + * title with message "Unauthorized" + * detail with message "Role not authorized for this API route". + * cause with message "Certificate not authorized". + +## Test Case 14: No ACL for invoker after be removed + +**Test ID**: ***capif_api_acl-14*** + +**Description**: + + This test case will check that ACLs are removed after invoker is removed. + +**Pre-Conditions**: + + * API Provider had a Service API Published on CAPIF + * API Invoker had a Security Context for Service API published and ACL is present + +**Information of Test**: + + 1. Perform [Provider Registration] + + 2. Publish Service API at CCF: + * Send Post to ccf_publish_url *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis* + * body [service api description] with apiName service_1 + * Store *serviceApiId* + * Use APF Certificate + + 3. Perform [Invoker Onboarding] store apiInvokerId + 4. Discover published APIs + 5. Create Security Context for this Invoker + * Send PUT *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * body [service security body] + * Use Invoker Certificate + + 6. Provider Retrieve ACL + * Send GET *https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId}?aef-id=${aef_id}&api-invoker-id={api-invoker-id}* + * Use *serviceApiId*, *aefId* and *api-invoker-id* + * Use AEF Provider Certificate + 7. Remove Invoker from CAPIF + 8. Provider Retrieve ACL + * Send GET *https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId}?aef-id=${aef_id}&api-invoker-id={api-invoker-id}* + * Use *serviceApiId*, *aefId* and *api-invoker-id* + * Use AEF Provider Certificate + +**Execution Steps**: + + 1. Register and onboard Provider at CCF. + 2. Publish a provider API with name service_1 + 3. Register and onboard Invoker at CCF + 4. Store signed Certificate + 5. Create Security Context + 6. Provider Get ACL information of invoker. + 7. Remove Invoker from CAPIF. + 8. Provider Get ACL information of invoker. + +**Expected Result**: + 1. ACL Response: + 1. **200 OK** Response. + 2. body returned must accomplish **AccessControlPolicyList** data structure. + 3. apiInvokerPolicies must: + 1. contain only one object. + 2. apiInvokerId must match apiInvokerId registered previously. + + 2. ACL Response: + 1. **404 Not Found** Response. + 2. body returned must accomplish **Problem Details** data structure. + 3. apiInvokerPolicies must: + * status **404** + * title with message "Not Found" + * detail with message "No ACLs found for the requested service: {NOT_VALID_SERVICE_API_ID}, aef_id: {AEF_ID_NOT_VALID}, invoker: None and supportedFeatures: None". + * cause with message "Wrong id". + + + +[service api description]: ../api_publish_service/service_api_description_post_example.json "Service API Description Request" +[publisher register body]: ../api_publish_service/publisher_register_body.json "Publish register Body" +[service security body]: ../api_security_service/service_security.json "Service Security Request" +[security notification body]: ./security_notification.json "Security Notification Request" +[access token req body]: ./access_token_req.json "Access Token Request" +[example]: ./access_token_req.json "Access Token Request Example" +[invoker onboarding]: ../common_operations/README.md#register-an-invoker "Invoker Onboarding" +[provider registration]: ../common_operations/README.md#register-a-provider "Provider Registration" diff --git a/doc/testing/testplan/api_access_control_policy/service_api_description_post_example.json b/doc/testing/testplan/api_access_control_policy/service_api_description_post_example.json new file mode 100644 index 0000000000000000000000000000000000000000..b725b428629509bf39a79c030f1bf93f4b6f18f6 --- /dev/null +++ b/doc/testing/testplan/api_access_control_policy/service_api_description_post_example.json @@ -0,0 +1,113 @@ +{ + "apiName": "service_1", + "aefProfiles": [ + { + "aefId": "string", + "versions": [ + { + "apiVersion": "v1", + "expiry": "2021-11-30T10:32:02.004Z", + "resources": [ + { + "resourceName": "string", + "commType": "REQUEST_RESPONSE", + "uri": "string", + "custOpName": "string", + "operations": [ + "GET" + ], + "description": "string" + } + ], + "custOperations": [ + { + "commType": "REQUEST_RESPONSE", + "custOpName": "string", + "operations": [ + "GET" + ], + "description": "string" + } + ] + } + ], + "protocol": "HTTP_1_1", + "dataFormat": "JSON", + "securityMethods": ["PSK"], + "interfaceDescriptions": [ + { + "ipv4Addr": "string", + "port": 65535, + "securityMethods": ["PSK"] + }, + { + "ipv4Addr": "string", + "port": 65535, + "securityMethods": ["PSK"] + } + ] + }, + { + "aefId": "string", + "versions": [ + { + "apiVersion": "v1", + "expiry": "2021-11-30T10:32:02.004Z", + "resources": [ + { + "resourceName": "string", + "commType": "REQUEST_RESPONSE", + "uri": "string", + "custOpName": "string", + "operations": [ + "GET" + ], + "description": "string" + } + ], + "custOperations": [ + { + "commType": "REQUEST_RESPONSE", + "custOpName": "string", + "operations": [ + "GET" + ], + "description": "string" + } + ] + } + ], + "protocol": "HTTP_1_1", + "dataFormat": "JSON", + "securityMethods": ["PSK"], + "interfaceDescriptions": [ + { + "ipv4Addr": "string", + "port": 65535, + "securityMethods": ["PSK"] + }, + { + "ipv4Addr": "string", + "port": 65535, + "securityMethods": ["PSK"] + } + ] + } + ], + "description": "string", + "supportedFeatures": "fffff", + "shareableInfo": { + "isShareable": true, + "capifProvDoms": [ + "string" + ] + }, + "serviceAPICategory": "string", + "apiSuppFeats": "fffff", + "pubApiPath": { + "ccfIds": [ + "string" + ] + }, + "ccfId": "string" +} \ No newline at end of file diff --git a/doc/testing/testplan/api_auditing_service/README.md b/doc/testing/testplan/api_auditing_service/README.md new file mode 100644 index 0000000000000000000000000000000000000000..add1a9d7775aee028f7d197fe1cf7e0cd3509048 --- /dev/null +++ b/doc/testing/testplan/api_auditing_service/README.md @@ -0,0 +1,247 @@ +# Test Plan for CAPIF Api Auditing Service +At this documentation you will have all information and related files and examples of test plan for this API. + +## Test Case 1: Get CAPIF Log Entry. + +**Test ID**: ***capif_api_auditing-1*** + +**Description**: + + This test case will check that a CAPIF AMF can get log entry to Logging Service + +**Pre-Conditions**: + + * CAPIF provider is pre-authorised (has valid AMF cert from CAPIF Authority) + * Service exist in CAPIF + * Invoker exist in CAPIF + * Log Entry exist in CAPIF + +**Information of Test**: + + 1. Perform [provider onboarding], [invoker onboarding] + + 2. Publish Service API at CCF: + - Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis + - body [service api description] with apiName service_1 + - Use APF Certificate + + 3. Create Log Entry: + - Send POST to *https://{CAPIF_HOSTNAME}/api-invocation-logs/v1/{aefId}/logs* + - body [log entry request body] + - Use AEF Certificate + + 4. Get Log: + 1. Send GET to *https://{CAPIF_HOSTNAME}/logs/v1/apiInvocationLogs?aef-id={aefId}&api-invoker-id={api-invoker-id}* + 2. Use AMF Certificate + +**Execution Steps**: + 1. Register Provider and Invoker CCF + 2. Publish Service + 3. Create Log Entry + 4. Get Log Entry + +**Expected Result**: + + 1. Response to Logging Service must accomplish: + 1. **200 OK** + 2. Response Body must follow **InvocationLog** data structure with: + * aefId + * apiInvokerId + * logs + +## Test Case 2: Get CAPIF Log Entry With no Log entry in CAPIF. + +**Test ID**: ***capif_api_auditing-2*** + +**Description**: + + This test case will check that a CAPIF AEF can create log entry to Logging Service + +**Pre-Conditions**: + + * CAPIF provider is pre-authorised (has valid AMF cert from CAPIF Authority) + * Service exist in CAPIF + * Invoker exist in CAPIF + +**Information of Test**: + + 1. Perform [provider onboarding], [invoker onboarding] + + 2. Publish Service API at CCF: + - Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis + - body [service api description] with apiName service_1 + - Use APF Certificate + + 4. Get Log: + 1. Send GET to *https://{CAPIF_HOSTNAME}/logs/v1/apiInvocationLogs?aef-id={aefId}&api-invoker-id={api-invoker-id}* + 2. Use AMF Certificate + +**Execution Steps**: + 1. Register Provider and Invoker CCF + 2. Publish Service + 3. Get Log Entry + +**Expected Result**: + + 1. Response to Logging Service must accomplish: + 1. **404 Not Found** + 2. Error Response Body must accomplish with **ProblemDetails** data structure with: + * status 404 + * title with message "Not Found Log Entry in CAPIF". + * cause with message "Not Exist Logs with the filters applied". + + +## Test Case 3: Get CAPIF Log Entry without aef-id and api-invoker-id. + +**Test ID**: ***capif_api_auditing-3*** + +**Description**: + + This test case will check that a CAPIF AEF can create log entry to Logging Service + +**Pre-Conditions**: + + * CAPIF provider is no pre-authorised (has no valid AMF cert from CAPIF Authority) + * Service exist in CAPIF + * Invoker exist in CAPIF + * Log Entry exist in CAPIF + +**Information of Test**: + + 1. Perform [provider onboarding], [invoker onboarding] + + 2. Publish Service API at CCF: + - Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis + - body [service api description] with apiName service_1 + - Use APF Certificate + + 3. Create Log Entry: + - Send POST to *https://{CAPIF_HOSTNAME}/api-invocation-logs/v1/{aefId}/logs* + - body [log entry request body] + - Use AEF Certificate + + 4. Get Log: + 1. Send GET to *https://{CAPIF_HOSTNAME}/logs/v1/apiInvocationLogs + 2. Use AMF Certificate + +**Execution Steps**: + 1. Register Provider and Invoker CCF + 2. Publish Service + 3. Create Log Entry + 4. Get Log Entry + +**Expected Result**: + + 1. Response to Logging Service must accomplish: + 1. **400 Bad Request** + 2. Error Response Body must accomplish with **ProblemDetails** data structure with: + * status 400 + * title with message "Bad Request" + * detail with message "aef_id and api_invoker_id parameters are mandatory". + * cause with message "Mandatory parameters missing". + + +## Test Case 4: Get CAPIF Log Entry with filtter api-version. + +**Test ID**: ***capif_api_auditing-4*** + +**Description**: + + This test case will check that a CAPIF AMF can get log entry to Logging Service + +**Pre-Conditions**: + + * CAPIF provider is pre-authorised (has valid AMF cert from CAPIF Authority) + * Service exist in CAPIF + * Invoker exist in CAPIF + * Log Entry exist in CAPIF + +**Information of Test**: + + 1. Perform [provider onboarding], [invoker onboarding] + + 2. Publish Service API at CCF: + - Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis + - body [service api description] with apiName service_1 + - Use APF Certificate + + 3. Create Log Entry: + - Send POST to *https://{CAPIF_HOSTNAME}/api-invocation-logs/v1/{aefId}/logs* + - body [log entry request body] + - Use AEF Certificate + + 4. Get Log: + 1. Send GET to *https://{CAPIF_HOSTNAME}/logs/v1/apiInvocationLogs?aef-id={aefId}&api-invoker-id={api-invoker-id}&api-version={v1}* + 2. Use AMF Certificate + +**Execution Steps**: + 1. Register Provider and Invoker CCF + 2. Publish Service + 3. Create Log Entry + 4. Get Log Entry + +**Expected Result**: + + 1. Response to Logging Service must accomplish: + 1. **200 OK** + 2. Response Body must follow **InvocationLog** data structure with: + * aefId + * apiInvokerId + * logs + + +## Test Case 5: Get CAPIF Log Entry with filter api-version but not exist in log entry. + +**Test ID**: ***capif_api_auditing-4*** + +**Description**: + + This test case will check that a CAPIF AMF can get log entry to Logging Service + +**Pre-Conditions**: + + * CAPIF provider is pre-authorised (has valid AMF cert from CAPIF Authority) + * Service exist in CAPIF + * Invoker exist in CAPIF + * Log Entry exist in CAPIF + +**Information of Test**: + + 1. Perform [provider onboarding], [invoker onboarding] + + 2. Publish Service API at CCF: + - Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis + - body [service api description] with apiName service_1 + - Use APF Certificate + + 3. Create Log Entry: + - Send POST to *https://{CAPIF_HOSTNAME}/api-invocation-logs/v1/{aefId}/logs* + - body [log entry request body] + - Use AEF Certificate + + 4. Get Log: + 1. Send GET to *https://{CAPIF_HOSTNAME}/logs/v1/apiInvocationLogs?aef-id={aefId}&api-invoker-id={api-invoker-id}&api-version={v58}* + 2. Use AMF Certificate + +**Execution Steps**: + 1. Register Provider and Invoker CCF + 2. Publish Service + 3. Create Log Entry + 4. Get Log Entry + +**Expected Result**: + + 1. Response to Logging Service must accomplish: + 1. **404 Not Found** + 2. Error Response Body must accomplish with **ProblemDetails** data structure with: + * status 404 + * detail with message "Parameters do not match any log entry" + * cause with message "No logs found". + + + +[log entry request body]: ../api_logging_service/invocation_log.json "Log Request Body" + +[invoker onboarding]: ../common_operations/README.md#register-an-invoker "Invoker Onboarding" + +[provider onboarding]: ../common_operations/README.md#register-a-provider "Provider Onboarding" diff --git a/doc/testing/testplan/api_discover_service/README.md b/doc/testing/testplan/api_discover_service/README.md new file mode 100644 index 0000000000000000000000000000000000000000..4c5c8f280e7d476bf7b15dcf5c7e47aaa57880df --- /dev/null +++ b/doc/testing/testplan/api_discover_service/README.md @@ -0,0 +1,356 @@ +# Test Plan for CAPIF Discover Service +At this documentation you will have all information and related files and examples of test plan for this API. + +## Test Case 1: Discover Published service APIs by Authorised API Invoker + +**Test ID**: ***capif_api_discover_service-1*** + +**Description**: + + This test case will check if NetApp (Invoker) can discover published service APIs. + +**Pre-Conditions**: + + * Service APIs are published. + * NetApp was registered previously + * NetApp was onboarded previously with {onboardingId} + +**Information of Test**: + + 1. Perform [Provider Registration] and [Invoker Onboarding] + 2. Publish Service API at CCF: + * Send Post to ccf_publish_url *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis* + * body [service api description] with apiName service_1 + * Use APF Certificate + 3. Request Discover Published APIs: + * Send GET to *https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}* + * Param api-invoker-id is mandatory + * Use Invoker Certificate + +**Execution Steps**: + + 1. Register Provider at CCF, store certificates and Publish Service API at CCF + 2. Register Invoker and Onboard Invoker at CCF + 3. Discover Service APIs by Invoker + +**Expected Result**: + + 1. Response to Publish request must accomplish: + 1. **201 Created** + 2. Response Body must follow **ServiceAPIDescription** data structure with: + * apiId + 3. Response Header **Location** must be received with URI to new resource created, following this structure: *{apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId}* + + 2. Response to Onboard request must accomplish: + 1. **201 Created** + 2. Response Body must follow **APIInvokerEnrolmentDetails** data structure with: + * apiInvokerId + * onboardingInformation->apiInvokerCertificate must contain the public key signed. + 3. Response Header **Location** must be received with URI to new resource created, following this structure: *{apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}* + 3. Response to Discover Request By Invoker: + 1. **200 OK** response. + 2. Response body must follow **DiscoveredAPIs** data structure: + * Check if DiscoveredAPIs contains the API Published previously + + +## Test Case 2: Discover Published service APIs by Non Authorised API Invoker + +**Test ID**: ***capif_api_discover_service-2*** + +**Description**: + + This test case will check that an API Publisher can't discover published APIs because is not authorized. + +**Pre-Conditions**: + + * Service APIs are published. + +**Information of Test**: + + 1. Perform [Provider Registration] and [Invoker Onboarding] + 2. Publish Service API at CCF: + * Send Post to ccf_publish_url *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis* + * body [service api description] with apiName service_1 + * Use APF Certificate + 3. Request Discover Published APIs by no invoker entity: + * Send GET to *https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}* + * Param api-invoker-id is mandatory + * Use not Invoker Certificate + +**Execution Steps**: + + 1. Register Provider at CCF, store certificates and Publish Service API at CCF + 2. Register Invoker and Onboard Invoker at CCF + 3. Discover Service APIs by no invoker entity + +**Expected Result**: + + 1. Response to Publish request must accomplish: + 1. **201 Created** + 2. Response Body must follow **ServiceAPIDescription** data structure with: + * apiId + 3. Response Header **Location** must be received with URI to new resource created, following this structure: *{apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId}* + + 2. Response to Onboard request must accomplish: + 1. **201 Created** + 2. Response Body must follow **APIInvokerEnrolmentDetails** data structure with: + * apiInvokerId + * onboardingInformation->apiInvokerCertificate must contain the public key signed. + 3. Response Header **Location** must be received with URI to new resource created, following this structure: *{apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}* + + 3. Response to Discover Request By no invoker entity: + 1. **401 Unauthorized** + 2. Error Response Body must accomplish with **ProblemDetails** data structure with: + * status 401 + * title with message "Unauthorized" + * detail with message "User not authorized". + * cause with message "Certificate not authorized". + + +## Test Case 3: Discover Published service APIs by not registered API Invoker + +**Test ID**: ***capif_api_discover_service-3*** + +**Description**: + + This test case will check that a not registered invoker is forbidden to discover published APIs. + +**Pre-Conditions**: + + * Service APIs are published. + +**Information of Test**: + + 1. Perform [Provider Registration] and [Invoker Onboarding] + 2. Publish Service API at CCF: + * Send Post to ccf_publish_url *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis* + * body [service api description] with apiName service_1 + * Use APF Certificate + 3. Request Discover Published APIs with not valid apiInvoker: + * Send GET to *https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={INVOKER_NOT_REGISTERED}* + * Param api-invoker-id is mandatory + * Using invoker certificate + +**Execution Steps**: + + 1. Register Provider at CCF, store certificates and Publish Service API at CCF + 2. Register Invoker and Onboard Invoker at CCF + 3. Discover Service APIs by Publisher + +**Expected Result**: + + 1. Response to Publish request must accomplish: + 1. **201 Created** + 2. Response Body must follow **ServiceAPIDescription** data structure with: + * apiId + 3. Response Header **Location** must be received with URI to new resource created, following this structure: *{apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId}* + + 2. Response to Onboard request must accomplish: + 1. **201 Created** + 2. Response Body must follow **APIInvokerEnrolmentDetails** data structure with: + * apiInvokerId + * onboardingInformation->apiInvokerCertificate must contain the public key signed. + 3. Response Header **Location** must be received with URI to new resource created, following this structure: *{apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}* + + 3. Response to Discover Request By Invoker: + 1. **404 Not Found** + 2. Error Response Body must accomplish with **ProblemDetails** data structure with: + * status 404 + * title with message "Not Found" + * detail with message "API Invoker does not exist". + * cause with message "API Invoker id not found". + + +## Test Case 4: Discover Published service APIs by registered API Invoker with 1 result filtered + +**Test ID**: ***capif_api_discover_service-4*** + +**Description**: + + This test case will check if NetApp (Invoker) can discover published service APIs. + +**Pre-Conditions**: + + * At least 2 Service APIs are published. + * NetApp was registered previously + * NetApp was onboarded previously with {onboardingId} + +**Information of Test**: + + 1. Perform [Provider Registration] and [Invoker Onboarding] + 2. Publish Service API at CCF: + * Send Post to ccf_publish_url *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis* + * body [service api description] with apiName service_1 + * Use APF Certificate + 3. Publish Service API at CCF: + * Send Post to ccf_publish_url *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis* + * body [service api description] with apiName service_2 + * Use APF Certificate + 4. Request Discover Published APIs filtering by api-name: + * Send GET to ccf_discover_url *https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}&api-name=service_1* + * Param api-invoker-id is mandatory + * Using invoker certificate + * filter by api-name service_1 + +**Execution Steps**: + + 1. Register Provider at CCF, store certificates and Publish Service API service_1 and service_2 at CCF + 2. Register Invoker and Onboard Invoker at CCF + 3. Discover Service APIs by Invoker. + 4. Discover filtered by api-name service_1 Service APIs by Invoker + +**Expected Result**: + + 1. Response to Publish request must accomplish: + 1. **201 Created** + 2. Response Body must follow **ServiceAPIDescription** data structure with: + * apiId + 3. Response Header **Location** must be received with URI to new resource created, following this structure: *{apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId}* + 2. Response to Onboard request must accomplish: + 1. **201 Created** + 2. Response Body must follow **APIInvokerEnrolmentDetails** data structure with: + * apiInvokerId + * onboardingInformation->apiInvokerCertificate must contain the public key signed. + 3. Response Header **Location** must be received with URI to new resource created, following this structure: *{apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}* + 3. Response to Discover Request By Invoker: + 1. **200 OK** response. + 2. Response body must follow **DiscoveredAPIs** data structure: + * Check if DiscoveredAPIs contains previously registered Service APIs published. + 4. Response to Discover Request By Invoker: + 1. **200 OK** response. + 2. Response body must follow **DiscoveredAPIs** data structure: + * Check if DiscoveredAPIs contains only Service API published with api-name service_1 + + +## Test Case 5: Discover Published service APIs by registered API Invoker filtered with no match + +**Test ID**: ***capif_api_discover_service-5*** + +**Description**: + + This test case will check if NetApp (Invoker) can discover published service APIs. + +**Pre-Conditions**: + + * At least 2 Service APIs are published. + * NetApp was registered previously + * NetApp was onboarded previously with {onboardingId} + +**Information of Test**: + + 1. Perform [Provider Registration] and [Invoker Onboarding] + 2. Publish Service API at CCF: + * Send Post to ccf_publish_url *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis* + * body [service api description] with apiName service_1 + * Use APF Certificate + 3. Publish Service API at CCF: + * Send Post to ccf_publish_url *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis* + * body [service api description] with apiName service_2 + * Use APF Certificate + 4. Request Discover Published APIs filtering by api-name not published: + * Send GET to ccf_discover_url *https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}&api-name=NOT_VALID_NAME* + * Param api-invoker-id is mandatory + * Using invoker certificate + * filter by api-name NOT_VALID_NAME + +**Execution Steps**: + + 1. Register Provider at CCF, store certificates and Publish Service API service_1 and service_2 at CCF + 2. Register Invoker and Onboard Invoker at CCF + 3. Discover Service APIs by Invoker. + 4. Discover filtered by api-name not published Service APIs by Invoker + +**Expected Result**: + + 1. Response to Publish request must accomplish: + 1. **201 Created** + 2. Response Body must follow **ServiceAPIDescription** data structure with: + * apiId + 3. Response Header **Location** must be received with URI to new resource created, following this structure: *{apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId}* + 2. Response to Onboard request must accomplish: + 1. **201 Created** + 2. Response Body must follow **APIInvokerEnrolmentDetails** data structure with: + * apiInvokerId + * onboardingInformation->apiInvokerCertificate must contain the public key signed. + 3. Response Header **Location** must be received with URI to new resource created, following this structure: *{apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}* + 3. Response to Discover Request By Invoker: + 1. **200 OK** response. + 2. Response body must follow **DiscoveredAPIs** data structure: + * Check if DiscoveredAPIs contains previously registered Service APIs published. + 4. Response to Discover Request By Invoker: + 1. **404 Not Found** response. + 2. Error Response Body must accomplish with **ProblemDetails** data structure with: + * status 404 + * title with message "Not Found" + * detail with message "API Invoker {api_invoker_id} has no API Published that accomplish filter conditions". + * cause with message "No API Published accomplish filter conditions". + + +## Test Case 6: Discover Published service APIs by registered API Invoker not filtered + +**Test ID**: ***capif_api_discover_service-6*** + +**Description**: + + This test case will check if NetApp (Invoker) can discover published service APIs. + +**Pre-Conditions**: + + * 2 Service APIs are published. + * NetApp was registered previously + * NetApp was onboarded previously with {onboardingId} + +**Information of Test**: + + 1. Perform [Provider Registration] and [Invoker Onboarding] + 2. Publish Service API at CCF: + * Send Post to ccf_publish_url *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis* + * body [service api description] with apiName service_1 + * Use APF Certificate + 3. Publish Service API at CCF: + * Send Post to ccf_publish_url *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis* + * body [service api description] with apiName service_2 + * Use APF Certificate + 4. Request Discover Published APIs not filtered: + * Send GET to ccf_discover_url *https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}* + * Param api-invoker-id is mandatory + * Using invoker certificate + +**Execution Steps**: + + 1. Register Provider at CCF, store certificates and Publish Service API service_1 and service_2 at CCF + 2. Register Invoker and Onboard Invoker at CCF + 3. Discover Service APIs by Invoker. + 4. Discover without filter by Invoker + +**Expected Result**: + + 1. Response to Publish request must accomplish: + 1. **201 Created** + 2. Response Body must follow **ServiceAPIDescription** data structure with: + * apiId + 3. Response Header **Location** must be received with URI to new resource created, following this structure: *{apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId}* + + 2. Response to Onboard request must accomplish: + 1. **201 Created** + 2. Response Body must follow **APIInvokerEnrolmentDetails** data structure with: + * apiInvokerId + * onboardingInformation->apiInvokerCertificate must contain the public key signed. + 3. Response Header **Location** must be received with URI to new resource created, following this structure: *{apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}* + + 3. Response to Discover Request By Invoker: + 1. **200 OK** response. + 2. Response body must follow **DiscoveredAPIs** data structure: + * Check if DiscoveredAPIs contains the 2 previously registered Service APIs published. + + + + [service api description]: ../api_publish_service/service_api_description_post_example.json "Service API **Description** Request" + [publisher register body]: ../api_publish_service/publisher_register_body.json "Publish register Body" + [invoker onboarding body]: ../api_invoker_management/invoker_details_post_example.json "API Invoker Request" + [invoker register body]: ../api_invoker_management/invoker_register_body.json "Invoker Register Body" + [provider request body]: ../api_provider_management/provider_details_post_example.json "API Provider Enrolment Request" + [provider request patch body]: ../api_provider_management/provider_details_enrolment_details_patch_example.json "API Provider Enrolment Patch Request" + [provider getauth body]: ../api_provider_management/provider_getauth_example.json "Get Auth Example" + [invoker onboarding]: ../common_operations/README.md#register-an-invoker "Invoker Onboarding" + [provider registration]: ../common_operations/README.md#register-a-provider "Provider Registration" diff --git a/doc/testing/testplan/api_events_service/README.md b/doc/testing/testplan/api_events_service/README.md new file mode 100644 index 0000000000000000000000000000000000000000..ca259ac3f38efe8b19f63995569f1020269238ac --- /dev/null +++ b/doc/testing/testplan/api_events_service/README.md @@ -0,0 +1,267 @@ +# Test Plan for CAPIF Api Events Service +At this documentation you will have all information and related files and examples of test plan for this API. + +## Tests + +## Test Case 1: Creates a new individual CAPIF Event Subscription. + +**Test ID**: ***capif_api_events-1*** + +**Description**: + + This test case will check that a CAPIF subscriber (Invoker or Publisher) can Subscribe to Events +**Pre-Conditions**: + + * CAPIF subscriber is pre-authorised (has valid InvokerId or apfId from CAPIF Authority) + +**Information of Test**: + + 1. Perform [Invoker Onboarding] + + 2. Event Subscription: + 1. Send POST to *https://{CAPIF_HOSTNAME}/capif-events/v1/{subscriberId}/subscriptions* + 2. body [event subscription request body] + 3. Use Invoker Certificate + +**Execution Steps**: + + 1. Register Invoker and Onboard Invoker at CCF + 2. Subscribe to Events + 3. Retrieve {subscriberId} and {subscriptionId} from Location Header + +**Expected Result**: + + 1. Response to Onboard request must accomplish: + 1. **201 Created** + 2. Response Body must follow **APIInvokerEnrolmentDetails** data structure with: + * apiInvokerId + * onboardingInformation->apiInvokerCertificate must contain the public key signed. + 3. Response Header **Location** must be received with URI to new resource created, following this structure: *{apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}* + + 2. Response to Event Subscription must accomplish: + 1. **201 Created** + 2. The URI of the created resource shall be returned in the "Location" HTTP header, following this structure: *{apiRoot}/capif-events/{apiVersion}/{subscriberId}/subscriptions/{subscriptionId} + 3. Response Body must follow **EventSubscription** data structure. + + 3. Event Subscriptions are stored in CAPIF Database + + +## Test Case 2: Creates a new individual CAPIF Event Subscription with Invalid SubscriberId + +**Test ID**: ***capif_api_events-2*** + +**Description**: + + This test case will check that a CAPIF subscriber (Invoker or Publisher) cannot Subscribe to Events without valid SubcriberId + +**Pre-Conditions**: + + * CAPIF subscriber is not pre-authorised (has invalid InvokerId or apfId) + +**Information of Test**: + + 1. Perform [Invoker Onboarding] + + 2. Event Subscription: + 1. Send POST to *https://{CAPIF_HOSTNAME}/capif-events/v1/{SUBSCRIBER_NOT_REGISTERED}/subscriptions* + 2. body [event subscription request body] + 3. Use Invoker Certificate + +**Execution Steps**: + + 1. Register Invoker and Onboard Invoker at CCF + 2. Subscribe to Events + +**Expected Result**: + + 1. Response to Onboard request must accomplish: + 1. **201 Created** + 2. Response Body must follow **APIInvokerEnrolmentDetails** data structure with: + * apiInvokerId + * onboardingInformation->apiInvokerCertificate must contain the public key signed. + 3. Response Header **Location** must be received with URI to new resource created, following this structure: *{apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}* + + 2. Response to Event Subscription must accomplish: + 1. **404 Not Found** + 2. Error Response Body must accomplish with **ProblemDetails** data structure with: + * status 404 + * title with message "Not Found" + * detail with message "Invoker or APF or AEF or AMF Not found". + * cause with message "Subscriber Not Found". + + 3. Event Subscriptions are not stored in CAPIF Database + + +## Test Case 3: Deletes an individual CAPIF Event Subscription + +**Test ID**: ***capif_api_events-3*** + +**Description**: + + This test case will check that a CAPIF subscriber (Invoker or Publisher) can Delete an Event Subscription + +**Pre-Conditions**: + + * CAPIF subscriber is pre-authorised (has valid InvokerId or apfId from CAPIF Authority) + +**Information of Test**: + + 1. Perform [Invoker Onboarding] + + 2. Event Subscription: + 1. Send POST to *https://{CAPIF_HOSTNAME}/capif-events/v1/{subscriberId}/subscriptions* + 2. body [event subscription request body] + 3. Use Invoker Certificate + + 3. Remove Event Subscription: + 1. Send DELETE to *https://{CAPIF_HOSTNAME}/capif-events/v1/{subscriberId}/subscriptions* + 2. Use Invoker Certificate + +**Execution Steps**: + + 1. Register Invoker and Onboard Invoker at CCF + 2. Subscribe to Events + 3. Retrieve {subscriberId} and {subscriptionId} from Location Header + 4. Remove Event Subscription + +**Expected Result**: + + 1. Response to Onboard request must accomplish: + 1. **201 Created** + 2. Response Body must follow **APIInvokerEnrolmentDetails** data structure with: + * apiInvokerId + * onboardingInformation->apiInvokerCertificate must contain the public key signed. + 3. Response Header **Location** must be received with URI to new resource created, following this structure: *{apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}* + + 2. Response to Event Subscription must accomplish: + 1. **201 Created** + 2. The URI of the created resource shall be returned in the "Location" HTTP header, following this structure: *{apiRoot}/capif-events/{apiVersion}/{subscriberId}/subscriptions/{subscriptionId} + 3. Response Body must follow **EventSubscription** data structure. + + 3. Event Subscriptions are stored in CAPIF Database + 4. Remove Event Subscription: + 1. **204 No Content** + + 5. Event Subscription is not present at CAPIF Database. + + +## Test Case 4: Deletes an individual CAPIF Event Subscription with invalid SubscriberId + +**Test ID**: ***capif_api_events-4*** + +**Description**: + + This test case will check that a CAPIF subscriber (Invoker or Publisher) cannot Delete to Events without valid SubcriberId + +**Pre-Conditions**: + + * CAPIF subscriber is pre-authorised (has valid InvokerId or apfId). + * CAPIF subscriber is subscribed to Events. + +**Information of Test**: + + 1. Perform [Invoker Onboarding] + + 2. Event Subscription: + 1. Send POST to https://{CAPIF_HOSTNAME}/capif-events/v1/{subscriberId}/subscriptions + 2. body [event subscription request body] + 3. Use Invoker Certificate + + 3. Remove Event Subcription with not valid subscriber: + 1. Send DELETE to to https://{CAPIF_HOSTNAME}/capif-events/v1/{SUBSCRIBER_ID_NOT_VALID}/subscriptions/{subcriptionId} + 2. Use Invoker Certificate + +**Execution Steps**: + + 1. Register Invoker and Onboard Invoker at CCF + 2. Subscribe to Events + 3. Retrieve Location Header with subscriptionId. + 4. Remove Event Subscribed with not valid Subscriber. + +**Expected Result**: + + 1. Response to Onboard request must accomplish: + 1. **201 Created** + 2. Response Body must follow **APIInvokerEnrolmentDetails** data structure with: + * apiInvokerId + * onboardingInformation->apiInvokerCertificate must contain the public key signed. + 3. Response Header **Location** must be received with URI to new resource created, following this structure: *{apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}* + + 2. Response to Event Subscription must accomplish: + 1. 201 Created + 2. The URI of the created resource shall be returned in the "Location" HTTP header, following this structure: *{apiRoot}/capif-events/{apiVersion}/{subscriberId}/subscriptions/{subscriptionId} + 3. Response Body must follow **EventSubscription** data structure. + + 3. Event Subscriptions are stored in CAPIF Database + 4. Error Response Body must accomplish with **ProblemDetails** data structure with: + * status 404 + * title with message "Not Found" + * detail with message "Invoker or APF or AEF or AMF Not found". + * cause with message "Subscriber Not Found". + + +## Test Case 5: Deletes an individual CAPIF Event Subscription with invalid SubscriptionId + +**Test ID**: ***capif_api_events-5*** + +**Description**: + + This test case will check that a CAPIF subscriber (Invoker or Publisher) cannot Delete an Event Subscription without valid SubscriptionId + +**Pre-Conditions**: + + * CAPIF subscriber is pre-authorised (has invalid InvokerId or apfId). + * CAPIF subscriber is subscribed to Events. + +**Information of Test**: + + 1. Perform [Invoker Onboarding] + + 2. Event Subscription: + 1. Send POST to https://{CAPIF_HOSTNAME}/capif-events/v1/{subscriberId}/subscriptions + 2. body [event subscription request body] + 3. Use Invoker Certificate + + 3. Remove Event Subcription with not valid subscriber: + 1. Send DELETE to to https://{CAPIF_HOSTNAME}/capif-events/v1/{subcriberId}/subscriptions/{SUBSCRIPTION_ID_NOT_VALID} + 2. Use Invoker Certificate + +**Execution Steps**: + + 1. Register Invoker and Onboard Invoker at CCF + 2. Subscribe to Events + 3. Retrieve Location Header with subscriptionId. + 4. Remove Event Subscribed with not valid Subscriber. + +**Expected Result**: + + 1. Response to Onboard request must accomplish: + 1. **201 Created** + 2. Response Body must follow **APIInvokerEnrolmentDetails** data structure with: + * apiInvokerId + * onboardingInformation->apiInvokerCertificate must contain the public key signed. + 3. Response Header **Location** must be received with URI to new resource created, following this structure: *{apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}* + + 2. Response to Event Subscription must accomplish: + 1. **201 Created** + 2. The URI of the created resource shall be returned in the "Location" HTTP header, following this structure: *{apiRoot}/capif-events/{apiVersion}/{subscriberId}/subscriptions/{subscriptionId} + 3. Response Body must follow **EventSubscription** data structure. + + 3. Event Subscriptions are stored in CAPIF Database + 4. Remove Event Subscription with not valid subscriber: + 1. **404 Not Found** + 2. Error Response Body must accomplish with **ProblemDetails** data structure with: + * status 404 + * detail with message "Service API not existing". + * cause with message "Event API subscription id not found". + + + + +[invoker register body]: ../api_invoker_management/invoker_register_body.json "Invoker Register Body" +[invoker onboard request body]: ../api_invoker_management/invoker_details_post_example.json "API Invoker Request" +[event subscription request body]: ./event_subscription.json "Event Subscription Request" +[invoker onboarding]: ../common_operations/README.md#register-an-invoker "Invoker Onboarding" + + +[Return To All Test Plans]: ../README.md diff --git a/doc/testing/testplan/api_events_service/event_subscription.json b/doc/testing/testplan/api_events_service/event_subscription.json new file mode 100644 index 0000000000000000000000000000000000000000..40dc09bb1ca5236fa9cb23ff1a25ad5dccd28844 --- /dev/null +++ b/doc/testing/testplan/api_events_service/event_subscription.json @@ -0,0 +1,31 @@ +{ + "eventFilters": [ + { + "aefIds": ["aefIds", "aefIds"], + "apiIds": ["apiIds", "apiIds"], + "apiInvokerIds": ["apiInvokerIds", "apiInvokerIds"] + }, + { + "aefIds": ["aefIds", "aefIds"], + "apiIds": ["apiIds", "apiIds"], + "apiInvokerIds": ["apiInvokerIds", "apiInvokerIds"] + } + ], + "eventReq": { + "grpRepTime": 5, + "immRep": true, + "maxReportNbr": 0, + "monDur": "2000-01-23T04:56:07+00:00", + "partitionCriteria": ["string1", "string2"], + "repPeriod": 6, + "sampRatio": 15 + }, + "events": ["SERVICE_API_AVAILABLE", "API_INVOKER_ONBOARDED"], + "notificationDestination": "http://robot.testing", + "requestTestNotification": true, + "supportedFeatures": "aaa", + "websockNotifConfig": { + "requestWebsocketUri": true, + "websocketUri": "websocketUri" + } +} diff --git a/doc/testing/testplan/api_invoker_management/README.md b/doc/testing/testplan/api_invoker_management/README.md new file mode 100644 index 0000000000000000000000000000000000000000..3b4e13031db427b109f0f8acaaa9d37f141a1815 --- /dev/null +++ b/doc/testing/testplan/api_invoker_management/README.md @@ -0,0 +1,312 @@ +# Test Plan for CAPIF Api Invoker Management +At this documentation you will have all information and related files and examples of test plan for this API. + +## Test Case 1: Onboard NetApp + +**Test ID**: ***capif_api_invoker_management-1*** + +**Description**: + + This test will try to register new NetApp at CAPIF Core. + +**Pre-Conditions**: + + * NetApp was not registered previously + * NetApp was not onboarded previously + +**Information of Test**: + + 1. Create public and private key at invoker + + 2. Register of Invoker at CCF: + * Send POST to *http://{CAPIF_HOSTNAME}:{CAPIF_HTTP_PORT}/register* + * body [invoker register body] + + 3. Obtain Access Token: + * Send POST to *http://{CAPIF_HOSTNAME}/getauth* + * Body [invoker getauth body] + + 4. Onboard Invoker: + * Send POST to *https://{CAPIF_HOSTNAME}/api-invoker-management/v1/onboardedInvokers* + * Reference Request Body: [invoker onboarding body] + * "onboardingInformation"->"apiInvokerPublicKey": must contain public key generated by Invoker. + * Send at Authorization Header the Bearer access_token obtained previously (Authorization:Bearer ${access_token}) + +**Execution Steps**: + + 1. Register Invoker at CCF + 2. Onboard Invoker at CCF + 3. Store signed Certificate + +**Expected Result**: + + 1. Response to Onboard request must accomplish: + 1. **201 Created** + 2. Response Body must follow **APIInvokerEnrolmentDetails** data structure with: + * apiInvokerId + * onboardingInformation->apiInvokerCertificate must contain the public key signed. + 3. Response Header **Location** must be received with URI to new resource created, following this structure: *{apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}* + + +## Test Case 2: Onboard NetApp Already onboarded + +**Test ID**: ***capif_api_invoker_management-2*** + +**Description**: + + This test will check second onboard of same NetApp is not allowed. + +**Pre-Conditions**: + + * NetApp was registered previously + * NetApp was onboarded previously + +**Information of Test**: + + 1. Perform [Invoker Onboarding] + + 2. Repeat Onboard Invoker: + * Send POST to *https://{CAPIF_HOSTNAME}/api-invoker-management/v1/onboardedInvokers* + * Reference Request Body: [invoker onboarding body] + * "onboardingInformation"->"apiInvokerPublicKey": must contain public key generated by Invoker. + * Send at Authorization Header the Bearer access_token obtained previously (Authorization:Bearer ${access_token}) + +**Execution Steps**: + + 1. Register NetApp at CCF + 2. Onboard NetApp at CCF + 3. Store signed Certificate at NetApp + 4. Onboard Again the NetApp at CCF + +**Expected Result**: + + 1. Response to Onboard request must accomplish: + 1. **201 Created** + 2. Response Body must follow **APIInvokerEnrolmentDetails** data structure with: + * apiInvokerId + * onboardingInformation->apiInvokerCertificate must contain the public key signed. + 3. Response Header **Location** must be received with URI to new resource created, following this structure: *{apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}* + 2. Response to Second Onboard of NetApp must accomplish: + 1. **403 Forbidden** + 2. Error Response Body must accomplish with **ProblemDetails** data structure with: + * status 403 + * title with message "Forbidden" + * detail with message "Invoker Already registered". + * cause with message "Identical invoker public key". + + +## Test Case 3: Update Onboarded NetApp + +**Test ID**: ***capif_api_invoker_management-3*** + +**Description**: + + This test will try to update information of previous onboard NetApp at CAPIF Core. + +**Pre-Conditions**: + + * NetApp was registered previously + * NetApp was onboarded previously with {onboardingId} + +**Information of Test**: + + 1. Perform [Invoker Onboarding] + + 2. Update information of previously onboarded Invoker: + * Send PUT to *https://{CAPIF_HOSTNAME}/api-invoker-management/v1/onboardedInvokers/{onboardingId}* + * Reference Request Body is: [put invoker onboarding body] + * "notificationDestination": "*http://host.docker.internal:8086/netapp_new_callback*", + +**Execution Steps**: + + 1. Register Invoker at CCF + 2. Onboard Invoker at CCF + 3. Store signed Certificate + 4. Update Onboarding Information at CCF with a minor change on "notificationDestination" + +**Expected Result**: + + 1. Response to Onboard request must accomplish: + 1. **201 Created** + 2. Response Body must follow **APIInvokerEnrolmentDetails** data structure with: + * apiInvokerId + * onboardingInformation->apiInvokerCertificate must contain the public key signed. + 3. Response Header **Location** must be received with URI to new resource created, following this structure: *{apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}* + 2. Response to Update Request (PUT) with minor change must contain: + 1. **200 OK** response. + 2. notificationDestination on response must contain the new value + + +## Test Case 4: Update Not Onboarded NetApp + +**Test ID**: ***capif_api_invoker_management-4*** + +**Description**: + + This test will try to update information of not onboarded NetApp at CAPIF Core. + +**Pre-Conditions**: + + * NetApp was registered previously + * NetApp was not onboarded previously + +**Information of Test**: + + 1. Perform [Invoker Onboarding] + + 2. Update information of not onboarded Invoker: + * Send PUT to *https://{CAPIF_HOSTNAME}/api-invoker-management/v1/onboardedInvokers/{INVOKER_NOT_REGISTERED}* + * Reference Request Body is: [put invoker onboarding body] + +**Execution Steps**: + + 1. Register Invoker at CCF + 2. Onboard Invoker at CCF + 3. Update Onboarding Information at CCF of not onboarded + +**Expected Result**: + + 1. Response to Onboard request must accomplish: + 1. **201 Created** + 2. Response to Update Request (PUT) must contain: + 1. **404 Not Found** + 2. Error Response Body must accomplish with **ProblemDetails** data structure with: + * status 404 + * title with message "Not Found" + * detail with message "Please provide an existing Netapp ID". + * cause with message "Not exist NetappID". + + + +## Test Case 5: Offboard NetApp + +**Test ID**: ***capif_api_invoker_management-5*** + +**Description**: + + This test case will check that a Registered NetApp can be deleted. + +**Pre-Conditions**: + + * NetApp was registered previously + * NetApp was onboarded previously + +**Information of Test**: + + 1. Perform [Invoker Onboarding] + + 2. Offboard: + * Send Delete to *https://{CAPIF_HOSTNAME}/api-invoker-management/v1/onboardedInvokers/{onboardingId}* + +**Execution Steps**: + + 1. Register Invoker at CCF + 2. Onboard Invoker at CCF + 3. Offboard Invoker at CCF + +**Expected Result**: + + 1. Response to Onboard request must accomplish: + 1. **201 Created** + 2. Response to Offboard Request (DELETE) must contain: + 1. **204 No Content** + + +## Test Case 6: Offboard Not previsouly Onboarded NetApp + +**Test ID**: ***capif_api_invoker_management-6*** + +**Description**: + + This test case will check that a Non-Registered NetApp cannot be deleted + +**Pre-Conditions**: + + * NetApp was registered previously + * NetApp was not onboarded previously + +**Information of Test**: + + 1. Perform [Invoker Onboarding] + + 2. Offboard: + * Send Delete to *https://{CAPIF_HOSTNAME}/api-invoker-management/v1/onboardedInvokers/{INVOKER_NOT_REGISTERED}* + +**Execution Steps**: + + 1. Register Invoker at CCF + 2. Offboard Invoker at CCF + +**Expected Result**: + + 1. Response to Offboard Request (DELETE) must contain: + 1. **404 Not Found** + 2. Error Response Body must accomplish with **ProblemDetails** data structure with: + * status 404 + * title with message "Not Found" + * detail with message "Please provide an existing Netapp ID". + * cause with message "Not exist NetappID". + +## Test Case 7: Update Onboarded NetApp Certificate + +**Test ID**: ***capif_api_invoker_management-7*** + +**Description**: + + This test will try to update public key and get a new signed certificate by CAPIF Core. + +**Pre-Conditions**: + + * NetApp was registered previously + * NetApp was onboarded previously with {onboardingId} and {public_key_1} + +**Information of Test**: + + 1. Perform [Invoker Onboarding] with public_key_1. + + 2. Create {public_key_2} + + 3. Update information of previously onboarded Invoker: + * Send PUT to *https://{CAPIF_HOSTNAME}/api-invoker-management/v1/onboardedInvokers/{onboardingId}* + * Reference Request Body is: [put invoker onboarding body] + * ["onboardingInformation"]["apiInvokerPublicKey"]: {public_key_2}, + * Store new certificate. + + 4. Update information of previously onboarded Invoker Using new certificate: + * Send PUT to *https://{CAPIF_HOSTNAME}/api-invoker-management/v1/onboardedInvokers/{onboardingId}* + * Reference Request Body is: [put invoker onboarding body] + * "notificationDestination": "*http://host.docker.internal:8086/netapp_new_callback*", + * Use new invoker certificate + +**Execution Steps**: + + 1. Register Invoker at CCF + 2. Onboard Invoker at CCF + 3. Store signed Certificate + 4. Update Onboarding Information at CCF with new public key + 5. Update Onboarding Information at CCF with minor change + +**Expected Result**: + + 1. Response to Onboard request must accomplish: + 1. **201 Created** + 2. Response Body must follow **APIInvokerEnrolmentDetails** data structure with: + * apiInvokerId + * onboardingInformation->apiInvokerCertificate must contain the public key signed. + 3. Response Header **Location** must be received with URI to new resource created, following this structure: *{apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}* + 2. Response to Update Request (PUT) with new public key: + 1. **200 OK** response. + 2. apiInvokerCertificate with new certificate on response -> store to use. + 3. Response to Update Request (PUT) with minor change must contain: + 1. **200 OK** response. + 2. notificationDestination on response must contain the new value + + + + +[invoker onboarding body]: ./invoker_details_post_example.json "API Invoker Request" +[invoker register body]: ./invoker_register_body.json "Invoker Register Body" +[put register body]: ./invoker_details_put_example.json "API Invoker Update Request" +[invoker getauth body]: ./invoker_getauth_example.json "Get Auth Example" + +[invoker onboarding]: ../common_operations/README.md#register-an-invoker "Invoker Onboarding" diff --git a/doc/testing/testplan/api_invoker_management/invoker_details_post_example.json b/doc/testing/testplan/api_invoker_management/invoker_details_post_example.json new file mode 100644 index 0000000000000000000000000000000000000000..c306a17e2d04f55da35a5b3638775af9d63e769f --- /dev/null +++ b/doc/testing/testplan/api_invoker_management/invoker_details_post_example.json @@ -0,0 +1,15 @@ +{ + "notificationDestination": "http://host.docker.internal:8086/netapp_callback", + "supportedFeatures": "fffffff", + "apiInvokerInformation": "ROBOT_TESTING_INVOKER", + "websockNotifConfig": { + "requestWebsocketUri": true, + "websocketUri": "websocketUri" + }, + "onboardingInformation": { + "apiInvokerPublicKey": "{PUBLIC_KEY}", + "onboardingSecret": "onboardingSecret", + "apiInvokerCertificate": "apiInvokerCertificate" + }, + "requestTestNotification": true +} diff --git a/doc/testing/testplan/api_invoker_management/invoker_details_put_example.json b/doc/testing/testplan/api_invoker_management/invoker_details_put_example.json new file mode 100644 index 0000000000000000000000000000000000000000..37a1eefbb05a2df1058b20429477cbf17f412cb8 --- /dev/null +++ b/doc/testing/testplan/api_invoker_management/invoker_details_put_example.json @@ -0,0 +1,393 @@ +{ + "notificationDestination": "http://host.docker.internal:8086/netapp_new_callback", + "supportedFeatures": "fffffff", + "apiInvokerInformation": "ROBOT_TESTING_INVOKER", + "websockNotifConfig": { + "requestWebsocketUri": true, + "websocketUri": "websocketUri" + }, + "onboardingInformation": { + "apiInvokerPublicKey": "{PUBLIC_KEY}", + "onboardingSecret": "onboardingSecret", + "apiInvokerCertificate": "apiInvokerCertificate" + }, + "requestTestNotification": true, + "apiList": [ + { + "serviceAPICategory": "serviceAPICategory", + "ccfId": "ccfId", + "apiName": "apiName", + "shareableInfo": { + "capifProvDoms": ["capifProvDoms", "capifProvDoms"], + "isShareable": true + }, + "supportedFeatures": "fffffff", + "description": "description", + "apiSuppFeats": "fffffff", + "apiId": "apiId", + "aefProfiles": [ + { + "securityMethods": ["PSK"], + "versions": [ + { + "apiVersion": "apiVersion", + "resources": [ + { + "operations": ["GET"], + "description": "description", + "resourceName": "resourceName", + "custOpName": "custOpName", + "uri": "uri", + "commType": "REQUEST_RESPONSE" + }, + { + "operations": ["GET"], + "description": "description", + "resourceName": "resourceName", + "custOpName": "custOpName", + "uri": "uri", + "commType": "REQUEST_RESPONSE" + } + ], + "custOperations": [ + { + "operations": ["GET"], + "description": "description", + "custOpName": "custOpName", + "commType": "REQUEST_RESPONSE" + }, + { + "operations": ["GET"], + "description": "description", + "custOpName": "custOpName", + "commType": "REQUEST_RESPONSE" + } + ], + "expiry": "2000-01-23T04:56:07.000+00:00" + }, + { + "apiVersion": "apiVersion", + "resources": [ + { + "operations": ["GET"], + "description": "description", + "resourceName": "resourceName", + "custOpName": "custOpName", + "uri": "uri", + "commType": "REQUEST_RESPONSE" + }, + { + "operations": ["GET"], + "description": "description", + "resourceName": "resourceName", + "custOpName": "custOpName", + "uri": "uri", + "commType": "REQUEST_RESPONSE" + } + ], + "custOperations": [ + { + "operations": ["GET"], + "description": "description", + "custOpName": "custOpName", + "commType": "REQUEST_RESPONSE" + }, + { + "operations": ["GET"], + "description": "description", + "custOpName": "custOpName", + "commType": "REQUEST_RESPONSE" + } + ], + "expiry": "2000-01-23T04:56:07.000+00:00" + } + ], + "aefId": "aefId", + "interfaceDescriptions": [ + { + "securityMethods": ["PSK"], + "port": 5248, + "ipv4Addr": "ipv4Addr" + }, + { "securityMethods": ["PSK"], "port": 5248, "ipv4Addr": "ipv4Addr" } + ] + }, + { + "securityMethods": ["PSK"], + "versions": [ + { + "apiVersion": "apiVersion", + "resources": [ + { + "operations": ["GET"], + "description": "description", + "resourceName": "resourceName", + "custOpName": "custOpName", + "uri": "uri", + "commType": "REQUEST_RESPONSE" + }, + { + "operations": ["GET"], + "description": "description", + "resourceName": "resourceName", + "custOpName": "custOpName", + "uri": "uri", + "commType": "REQUEST_RESPONSE" + } + ], + "custOperations": [ + { + "operations": ["GET"], + "description": "description", + "custOpName": "custOpName", + "commType": "REQUEST_RESPONSE" + }, + { + "operations": ["GET"], + "description": "description", + "custOpName": "custOpName", + "commType": "REQUEST_RESPONSE" + } + ], + "expiry": "2000-01-23T04:56:07.000+00:00" + }, + { + "apiVersion": "apiVersion", + "resources": [ + { + "operations": ["GET"], + "description": "description", + "resourceName": "resourceName", + "custOpName": "custOpName", + "uri": "uri", + "commType": "REQUEST_RESPONSE" + }, + { + "operations": ["GET"], + "description": "description", + "resourceName": "resourceName", + "custOpName": "custOpName", + "uri": "uri", + "commType": "REQUEST_RESPONSE" + } + ], + "custOperations": [ + { + "operations": ["GET"], + "description": "description", + "custOpName": "custOpName", + "commType": "REQUEST_RESPONSE" + }, + { + "operations": ["GET"], + "description": "description", + "custOpName": "custOpName", + "commType": "REQUEST_RESPONSE" + } + ], + "expiry": "2000-01-23T04:56:07.000+00:00" + } + ], + "aefId": "aefId", + "interfaceDescriptions": [ + { + "securityMethods": ["PSK"], + "port": 5248, + "ipv4Addr": "ipv4Addr" + }, + { "securityMethods": ["PSK"], "port": 5248, "ipv4Addr": "ipv4Addr" } + ] + } + ], + "pubApiPath": { "ccfIds": ["ccfIds", "ccfIds"] } + }, + { + "serviceAPICategory": "serviceAPICategory", + "ccfId": "ccfId", + "apiName": "apiName2", + "shareableInfo": { + "capifProvDoms": ["capifProvDoms", "capifProvDoms"], + "isShareable": true + }, + "supportedFeatures": "fffffff", + "description": "description", + "apiSuppFeats": "fffffff", + "apiId": "apiId", + "aefProfiles": [ + { + "securityMethods": ["PSK"], + "versions": [ + { + "apiVersion": "apiVersion", + "resources": [ + { + "operations": ["GET"], + "description": "description", + "resourceName": "resourceName", + "custOpName": "custOpName", + "uri": "uri", + "commType": "REQUEST_RESPONSE" + }, + { + "operations": ["GET"], + "description": "description", + "resourceName": "resourceName", + "custOpName": "custOpName", + "uri": "uri", + "commType": "REQUEST_RESPONSE" + } + ], + "custOperations": [ + { + "operations": ["GET"], + "description": "description", + "custOpName": "custOpName", + "commType": "REQUEST_RESPONSE" + }, + { + "operations": ["GET"], + "description": "description", + "custOpName": "custOpName", + "commType": "REQUEST_RESPONSE" + } + ], + "expiry": "2000-01-23T04:56:07.000+00:00" + }, + { + "apiVersion": "apiVersion", + "resources": [ + { + "operations": ["GET"], + "description": "description", + "resourceName": "resourceName", + "custOpName": "custOpName", + "uri": "uri", + "commType": "REQUEST_RESPONSE" + }, + { + "operations": ["GET"], + "description": "description", + "resourceName": "resourceName", + "custOpName": "custOpName", + "uri": "uri", + "commType": "REQUEST_RESPONSE" + } + ], + "custOperations": [ + { + "operations": ["GET"], + "description": "description", + "custOpName": "custOpName", + "commType": "REQUEST_RESPONSE" + }, + { + "operations": ["GET"], + "description": "description", + "custOpName": "custOpName", + "commType": "REQUEST_RESPONSE" + } + ], + "expiry": "2000-01-23T04:56:07.000+00:00" + } + ], + "aefId": "aefId", + "interfaceDescriptions": [ + { + "securityMethods": ["PSK"], + "port": 5248, + "ipv4Addr": "ipv4Addr" + }, + { "securityMethods": ["PSK"], "port": 5248, "ipv4Addr": "ipv4Addr" } + ] + }, + { + "securityMethods": ["PSK"], + "versions": [ + { + "apiVersion": "apiVersion", + "resources": [ + { + "operations": ["GET"], + "description": "description", + "resourceName": "resourceName", + "custOpName": "custOpName", + "uri": "uri", + "commType": "REQUEST_RESPONSE" + }, + { + "operations": ["GET"], + "description": "description", + "resourceName": "resourceName", + "custOpName": "custOpName", + "uri": "uri", + "commType": "REQUEST_RESPONSE" + } + ], + "custOperations": [ + { + "operations": ["GET"], + "description": "description", + "custOpName": "custOpName", + "commType": "REQUEST_RESPONSE" + }, + { + "operations": ["GET"], + "description": "description", + "custOpName": "custOpName", + "commType": "REQUEST_RESPONSE" + } + ], + "expiry": "2000-01-23T04:56:07.000+00:00" + }, + { + "apiVersion": "apiVersion", + "resources": [ + { + "operations": ["GET"], + "description": "description", + "resourceName": "resourceName", + "custOpName": "custOpName", + "uri": "uri", + "commType": "REQUEST_RESPONSE" + }, + { + "operations": ["GET"], + "description": "description", + "resourceName": "resourceName", + "custOpName": "custOpName", + "uri": "uri", + "commType": "REQUEST_RESPONSE" + } + ], + "custOperations": [ + { + "operations": ["GET"], + "description": "description", + "custOpName": "custOpName", + "commType": "REQUEST_RESPONSE" + }, + { + "operations": ["GET"], + "description": "description", + "custOpName": "custOpName", + "commType": "REQUEST_RESPONSE" + } + ], + "expiry": "2000-01-23T04:56:07.000+00:00" + } + ], + "aefId": "aefId", + "interfaceDescriptions": [ + { + "securityMethods": ["PSK"], + "port": 5248, + "ipv4Addr": "ipv4Addr" + }, + { "securityMethods": ["PSK"], "port": 5248, "ipv4Addr": "ipv4Addr" } + ] + } + ], + "pubApiPath": { "ccfIds": ["ccfIds", "ccfIds"] } + } + ] +} diff --git a/doc/testing/testplan/api_invoker_management/invoker_getauth_example.json b/doc/testing/testplan/api_invoker_management/invoker_getauth_example.json new file mode 100644 index 0000000000000000000000000000000000000000..a66dad58adb1894b70b802193164301a429abdc1 --- /dev/null +++ b/doc/testing/testplan/api_invoker_management/invoker_getauth_example.json @@ -0,0 +1,4 @@ +{ + "username": "ROBOT_TESTING_INVOKER", + "password": "password" +} diff --git a/doc/testing/testplan/api_invoker_management/invoker_register_body.json b/doc/testing/testplan/api_invoker_management/invoker_register_body.json new file mode 100644 index 0000000000000000000000000000000000000000..e5bf1fc5b89682c56416c62530a95a5a86037885 --- /dev/null +++ b/doc/testing/testplan/api_invoker_management/invoker_register_body.json @@ -0,0 +1,7 @@ +{ + "password": "password", + "username": "ROBOT_TESTING_INVOKER", + "role": "invoker", + "description": "Testing", + "cn": "ROBOT_TESTING_INVOKER" +} diff --git a/doc/testing/testplan/api_logging_service/README.md b/doc/testing/testplan/api_logging_service/README.md new file mode 100644 index 0000000000000000000000000000000000000000..f22795a4faea72b64e0d3be0d2b2a252128d73b7 --- /dev/null +++ b/doc/testing/testplan/api_logging_service/README.md @@ -0,0 +1,241 @@ +# Test Plan for CAPIF Api Logging Service +At this documentation you will have all information and related files and examples of test plan for this API. + +## Test Case 1: Creates a new individual CAPIF Log Entry. + +**Test ID**: ***capif_api_logging-1*** + +**Description**: + + This test case will check that a CAPIF AEF can create log entry to Logging Service + +**Pre-Conditions**: + + * CAPIF provider is pre-authorised (has valid aefId from CAPIF Authority) + * Service exist in CAPIF + * Invoker exist in CAPIF + +**Information of Test**: + + 1. Perform [provider onboarding] and [invoker onboarding] + + 2. Publish Service API at CCF: + - Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis + - body [service api description] with apiName service_1 + - Use APF Certificate + + 3. Log Entry: + 1. Send POST to *https://{CAPIF_HOSTNAME}/api-invocation-logs/v1/{aefId}/logs* + 2. body [log entry request body] + 3. Use AEF Certificate + +**Execution Steps**: + 1. Register Provider and Invoker CCF + 2. Publish Service + 3. Create Log Entry + +**Expected Result**: + + 1. Response to Logging Service must accomplish: + 1. **201 Created** + 2. Response Body must follow **InvocationLog** data structure with: + * aefId + * apiInvokerId + * logs + 3. Response Header **Location** must be received with URI to new resource created, following this structure: *{apiRoot}/api-invocation-logs/v1/{aefId}/logs/{logId}* + + + + +## Test Case 2: Creates a new individual CAPIF Log Entry with Invalid aefId + +**Test ID**: ***capif_api_logging-2*** + +**Description**: + + This test case will check that a CAPIF subscriber (AEF) cannot create Log Entry without valid aefId + +**Pre-Conditions**: + + * CAPIF provider is not pre-authorised (has not valid aefId from CAPIF Authority) + * Service exist in CAPIF + * Invoker exist in CAPIF + +**Information of Test**: + + 1. Perform [provider onboarding] and [invoker onboarding] + + 2. Publish Service API at CCF: + - Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis + - body [service api description] with apiName service_1 + - Use APF Certificate + + 3. Log Entry: + 1. Send POST to *https://{CAPIF_HOSTNAME}/api-invocation-logs/v1/{not-valid-aefId}/logs* + 2. body [log entry request body] + 3. Use AEF Certificate + +**Execution Steps**: + 1. Register Provider and Invoker CCF + 2. Publish Service + 3. Create Log Entry + +**Expected Result**: + + 1. Response to Logging Service must accomplish: + 1. **404 Not Found** + 2. Error Response Body must accomplish with **ProblemDetails** data structure with: + * status 404 + * title with message "Not Found" + * detail with message "Exposer not exist". + * cause with message "Exposer id not found". + +## Test Case 3: Creates a new individual CAPIF Log Entry with Invalid serviceAPI + +**Test ID**: ***capif_api_logging-3*** + +**Description**: + + This test case will check that a CAPIF subscriber (AEF) cannot create Log Entry without valid aefId + +**Pre-Conditions**: + + * CAPIF subscriber is pre-authorised (has valid aefId from CAPIF Authority) + +**Information of Test**: + + 1. Perform [provider onboarding] and [invoker onboarding] + + 2. Publish Service API at CCF: + - Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis + - body [service api description] with apiName service_1 + - Use APF Certificate + + 3. Log Entry: + 1. Send POST to *https://{CAPIF_HOSTNAME}/api-invocation-logs/v1/{aefId}/logs* + 2. body [log entry request body with serviceAPI apiName apiId not valid] + 3. Use AEF Certificate + +**Execution Steps**: + 1. Register Provider and Invoker CCF + 2. Publish Service + 3. Create Log Entry + +**Expected Result**: + + 1. Response to Logging Service must accomplish: + 1. **404 Not Found** + 2. Error Response Body must accomplish with **ProblemDetails** data structure with: + * status 404 + * title with message "Not Found" + * detail with message "Invoker not exist". + * cause with message "Invoker id not found". + + + +## Test Case 4: Creates a new individual CAPIF Log Entry with Invalid apiInvokerId + +**Test ID**: ***capif_api_logging-4*** + +**Description**: + + This test case will check that a CAPIF subscriber (AEF) cannot create Log Entry without valid aefId + +**Pre-Conditions**: + + * CAPIF subscriber is pre-authorised (has valid aefId from CAPIF Authority) + +**Information of Test**: + + 1. Perform [provider onboarding] and [invoker onboarding] + + 2. Publish Service API at CCF: + - Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis + - body [service api description] with apiName service_1 + - Use APF Certificate + + 3. Log Entry: + 1. Send POST to *https://{CAPIF_HOSTNAME}/api-invocation-logs/v1/{aefId}/logs* + 2. body [log entry request body with invokerId not valid] + 3. Use AEF Certificate + +**Execution Steps**: + 1. Register Provider and Invoker CCF + 2. Publish Service + 3. Create Log Entry + +**Expected Result**: + + 1. Response to Onboard request must accomplish: + 1. **201 Created** response. + 2. body returned must accomplish **APIProviderEnrolmentDetails** data structure. + 3. For each **apiProvFuncs**, we must check: + 1. **apiProvFuncId** is set + 2. **apiProvCert** under **regInfo** is set properly + 5. Location Header must contain the new resource URL *{apiRoot}/api-provider-management/v1/registrations/{registrationId}* + + 2. Response to Logging Service must accomplish: + 1. **404 Not Found** + 2. Error Response Body must accomplish with **ProblemDetails** data structure with: + * status 404 + * title with message "Not Found" + * detail with message "Invoker not exist". + * cause with message "Invoker id not found". + + 3. Log Entry are not stored in CAPIF Database + + +## Test Case 5: Creates a new individual CAPIF Log Entry with Invalid aefId in body + +**Test ID**: ***capif_api_logging-5*** + +**Description**: + + This test case will check that a CAPIF subscriber (AEF) cannot create Log Entry without valid aefId in body + +**Pre-Conditions**: + + * CAPIF provider is pre-authorised (has valid apfId from CAPIF Authority) + * Service exist in CAPIF + * Invoker exist in CAPIF + +**Information of Test**: + + 1. Perform [provider onboarding] and [invoker onboarding] + + 2. Publish Service API at CCF: + - Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis + - body [service api description] with apiName service_1 + - Use APF Certificate + + 3. Log Entry: + 1. Send POST to *https://{CAPIF_HOSTNAME}/api-invocation-logs/v1/{aefId}/logs* + 2. body [log entry request body with bad aefId] + 3. Use AEF Certificate + +**Execution Steps**: + 1. Register Provider and Invoker CCF + 2. Publish Service + 3. Create Log Entry + +**Expected Result**: + + 1. Response to Logging Service must accomplish: + 1. **401 Unauthorized** + 2. Error Response Body must accomplish with **ProblemDetails** data structure with: + * status 401 + * title with message "Unauthorized" + * detail with message "AEF id not matching in request and body". + * cause with message "Not identical AEF id". + + + + + + +[log entry request body]: ./invocation_log.json "Log Request Body" + +[invoker onboarding]: ../common_operations/README.md#register-an-invoker "Invoker Onboarding" + +[provider onboarding]: ../common_operations/README.md#register-a-provider "Provider Onboarding" + diff --git a/doc/testing/testplan/api_logging_service/invocation_log.json b/doc/testing/testplan/api_logging_service/invocation_log.json new file mode 100644 index 0000000000000000000000000000000000000000..ceabcf02016e116566cd2b13c99a87a6adcef5d3 --- /dev/null +++ b/doc/testing/testplan/api_logging_service/invocation_log.json @@ -0,0 +1,45 @@ +{ + "aefId": "aefId", + "apiInvokerId": "apiInvokerId", + "logs": [ + { + "apiId": "apiId", + "apiName": "apiName", + "apiVersion": "string", + "resourceName": "string", + "uri": "string", + "protocol": "HTTP_1_1", + "operation": "GET", + "result": "string", + "invocationTime": "2023-03-30T10:30:21.404Z", + "invocationLatency": 0, + "inputParameters": "string", + "outputParameters": "string", + "srcInterface": { + "ipv4Addr": "string", + "ipv6Addr": "string", + "fqdn": "string", + "port": 65535, + "apiPrefix": "string", + "securityMethods": [ + "PSK", + "Oauth" + ] + }, + "destInterface": { + "ipv4Addr": "string", + "ipv6Addr": "string", + "fqdn": "string", + "port": 65535, + "apiPrefix": "string", + "securityMethods": [ + "PSK", + "string" + ] + }, + "fwdInterface": "string" + } + ], + "supportedFeatures": "string" + } + \ No newline at end of file diff --git a/doc/testing/testplan/api_provider_management/README.md b/doc/testing/testplan/api_provider_management/README.md new file mode 100644 index 0000000000000000000000000000000000000000..d20f83944fc6a1b7ae505377628dd670e7c93d8e --- /dev/null +++ b/doc/testing/testplan/api_provider_management/README.md @@ -0,0 +1,405 @@ +# Test Plan for CAPIF Api Provider Management +At this documentation you will have all information and related files and examples of test plan for this API. + +## Test Case 1: Register Api Provider + +**Test ID**: ***capif_api_provider_management-1*** + +**Description**: + + This test case will check that Api Provider can be registered con CCF + +**Pre-Conditions**: + + * Provider is pre-authorised (has valid certificate from CAPIF Authority) + +**Information of Test**: + + 1. Create public and private key at provider for provider itself and each function (apf, aef and amf) + + 2. Register of Provider at CCF: + * Send POST to *http://{CAPIF_HOSTNAME}:{CAPIF_HTTP_PORT}/register* + * body [provider register body] + + 3. Obtain Access Token: + * Send POST to *http://{CAPIF_HOSTNAME}/getauth* + * Body [provider getauth body] + + 4. Register Provider: + * Send POST *https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations* + * body [provider request body] + * Authentication Bearer with access_token + * Store each cert in a file with according name. + +**Execution Steps**: + + 1. Create private and public key for provider and each function to register. + 2. Register Provider. + +**Expected Result**: + + 1. Register Provider at Provider Management: + 1. **201 Created** response. + 2. body returned must accomplish **APIProviderEnrolmentDetails** data structure. + 3. For each **apiProvFuncs**, we must check: + 1. **apiProvFuncId** is set + 2. **apiProvCert** under **regInfo** is set properly + 5. Location Header must contain the new resource URL *{apiRoot}/api-provider-management/v1/registrations/{registrationId}* + +## Test Case 2: Register Api Provider Already registered + +**Test ID**: ***capif_api_provider_management-2*** + +**Description**: + + This test case will check that a Api Provider previously registered cannot be re-registered + +**Pre-Conditions**: + + * Api Provider was registered previously and there is a {registerId} for his Api Provider in the DB + +**Information of Test**: + + 1. Create public and private key at provider for provider itself and each function (apf, aef and amf) + + 2. Register of Provider at CCF: + * Send POST to *http://{CAPIF_HOSTNAME}:{CAPIF_HTTP_PORT}/register* + * body [provider register body] + + 3. Obtain Access Token: + * Send POST to *http://{CAPIF_HOSTNAME}/getauth* + * Body [provider getauth body] + + 4. Register Provider: + * Send POST *https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations* + * body [provider request body] + * Authentication Bearer with access_token + * Store each cert in a file with according name. + + 5. Re-Register Provider: + * Same regSec than Previous registration + +**Execution Steps**: + + 1. Create private and public key for provider and each function to register. + 2. Register Provider. + 3. Re-Register Provider. + +**Expected Result**: + + 1. Re-Register Provider: + 1. **403 Forbidden** response. + 2. body returned must accomplish **ProblemDetails** data structure, with: + * status 403 + * title with message "Forbidden" + * detail with message "Provider already registered". + * cause with message "Identical provider reg sec". + +## Test Case 3: Update Registered Api Provider + +**Test ID**: ***capif_api_provider_management-3*** + +**Description**: + + This test case will check that a Registered Api Provider can be updated + +**Pre-Conditions**: + + * Api Provider was registered previously and there is a {registerId} for his Api Provider in the DB + +**Information of Test**: + + 1. Create public and private key at provider for provider itself and each function (apf, aef and amf) + + 2. Register of Provider at CCF: + * Send POST to *http://{CAPIF_HOSTNAME}:{CAPIF_HTTP_PORT}/register* + * body [provider register body] + + 3. Obtain Access Token: + * Send POST to *http://{CAPIF_HOSTNAME}/getauth* + * Body [provider getauth body] + + 4. Register Provider: + * Send POST *https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations* + * body [provider request body] + * Authentication Bearer with access_token + * Get Resource URL from Location + + 5. Update Provider: + * Send PUT to Resource URL returned at registration *https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations/{registrationId}* + * body [provider request body] with apiProvDomInfo set to ROBOT_TESTING_MOD + * Use AMF Certificate. + + +**Execution Steps**: + + 1. Create private and public key for provider and each function to register. + 2. Register Provider + 3. Update Provider + +**Expected Result**: + + 1. Register Provider: + 1. **201 Created** response. + 2. body returned must accomplish **APIProviderEnrolmentDetails** data structure. + 3. Location Header must contain the new resource URL *{apiRoot}/api-provider-management/v1/registrations/{registrationId}* + + + 2. Update Provider: + 1. **200 OK** response. + 2. body returned must accomplish **APIProviderEnrolmentDetails** data structure, with: + * apiProvDomInfo set to ROBOT_TESTING_MOD + + +## Test Case 4: Update Not Registered Api Provider + +**Test ID**: ***capif_api_provider_management-4*** + +**Description**: + + This test case will check that a Non-Registered Api Provider cannot be updated + +**Pre-Conditions**: + + * Api Provider was not registered previously + +**Information of Test**: + + 1. Create public and private key at provider for provider itself and each function (apf, aef and amf) + + 2. Register of Provider at CCF: + * Send POST to *http://{CAPIF_HOSTNAME}:{CAPIF_HTTP_PORT}/register* + * body [provider register body] + + 3. Obtain Access Token: + * Send POST to *http://{CAPIF_HOSTNAME}/getauth* + * Body [provider getauth body] + + 4. Register Provider: + * Send POST *https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations* + * body [provider request body] + * Authentication Bearer with access_token + * Store each cert in a file with according name. + + 5. Update Not Registered Provider: + * Send PUT *https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations/{API_PROVIDER_NOT_REGISTERED}* + * body [provider request body] + * Use AMF Certificate. + +**Execution Steps**: + + 1. Register Provider at CCF + 3. Update Not Registered Provider + +**Expected Result**: + + 1. Update Not Registered Provider: + 1. **404 Not Found** response. + 2. body returned must accomplish **ProblemDetails** data structure, with: + * status 404 + * title with message "Not Found" + * detail with message "Not Exist Provider Enrolment Details". + * cause with message "Not found registrations to send this api provider details". + +## Test Case 5: Partially Update Registered Api Provider + +**Test ID**: ***capif_api_provider_management-5*** + +**Description**: + + This test case will check that a Registered Api Provider can be partially updated + +**Pre-Conditions**: + + * Api Provider was registered previously and there is a {registerId} for his Api Provider in the DB + +**Information of Test**: + + 1. Create public and private key at provider for provider itself and each function (apf, aef and amf) + + 2. Register of Provider at CCF: + * Send POST to *http://{CAPIF_HOSTNAME}:{CAPIF_HTTP_PORT}/register* + * body [provider register body] + + 3. Obtain Access Token: + * Send POST to *http://{CAPIF_HOSTNAME}/getauth* + * Body [provider getauth body] + + 4. Register Provider: + * Send POST *https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations* + * body [provider request body] + * Authentication Bearer with access_token + * Store each cert in a file with according name. + + 5. Partial update provider: + * Send PATCH *https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations/{registrationId}* + * body [provider request patch body] + * Use AMF Certificate. + +**Execution Steps**: + + 1. Register Provider at CCF + 2. Register Provider + 3. Partial update provider + +**Expected Result**: + + 1. Partial update provider at Provider Management: + 1. **200 OK** response. + 2. body returned must accomplish **APIProviderEnrolmentDetails** data structure, with: + * apiProvDomInfo with "ROBOT_TESTING_MOD" + +## Test Case 6: Partially Update Not Registered Api Provider + +**Test ID**: ***capif_api_provider_management-6*** + +**Description**: + + This test case will check that a Non-Registered Api Provider cannot be partially updated + +**Pre-Conditions**: + + * Api Provider was not registered previously + +**Information of Test**: + + 1. Create public and private key at provider for provider itself and each function (apf, aef and amf) + + 2. Register of Provider at CCF: + * Send POST to *http://{CAPIF_HOSTNAME}:{CAPIF_HTTP_PORT}/register* + * body [provider register body] + + 3. Obtain Access Token: + * Send POST to *http://{CAPIF_HOSTNAME}/getauth* + * Body [provider getauth body] + + 4. Register Provider: + * Send POST *https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations* + * body [provider request body] + * Authentication Bearer with access_token + * Store each cert in a file with according name. + + 5. Partial update Provider: + * Send PATCH *https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations/{API_API_PROVIDER_NOT_REGISTERED}* + * body [provider request patch body] + * Use AMF Certificate. + + +**Execution Steps**: + + 1. Register Provider at CCF + 2. Register Provider + 3. Partial update provider + +**Expected Result**: + + 1. Partial update provider: + 1. **404 Not Found** response. + 2. body returned must accomplish **ProblemDetails** data structure, with: + * status 404 + * title with message "Not Found" + * detail with message "Not Exist Provider Enrolment Details". + * cause with message "Not found registrations to send this api provider details". + +## Test Case 7: Delete Registered Api Provider + +**Test ID**: ***capif_api_provider_management-7*** + +**Description**: + + This test case will check that a Registered Api Provider can be deleted + +**Pre-Conditions**: + + * Api Provider was registered previously + +**Information of Test**: + + 1. Create public and private key at provider for provider itself and each function (apf, aef and amf) + + 2. Register of Provider at CCF: + * Send POST to *http://{CAPIF_HOSTNAME}:{CAPIF_HTTP_PORT}/register* + * body [provider register body] + + 3. Obtain Access Token: + * Send POST to *http://{CAPIF_HOSTNAME}/getauth* + * Body [provider getauth body] + + 4. Register Provider: + * Send POST *https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations* + * body [provider request body] + * Authentication Bearer with access_token + * Store each cert in a file with according name. + + 5. Delete registered provider: + * Send DELETE *https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations/{registrationId}* + * Use AMF Certificate. + +**Execution Steps**: + + 1. Register Provider at CCF + 2. Register Provider + 3. Delete Provider + +**Expected Result**: + + 1. Delete Provider: + 1. **204 No Content** response. + +## Test Case 8: Delete Not Registered Api Provider + +**Test ID**: ***capif_api_provider_management-8*** + +**Description**: + + This test case will check that a Non-Registered Api Provider cannot be deleted + +**Pre-Conditions**: + + * Api Provider was not registered previously + +**Information of Test**: + + 1. Create public and private key at provider for provider itself and each function (apf, aef and amf) + + 2. Register of Provider at CCF: + * Send POST to *http://{CAPIF_HOSTNAME}:{CAPIF_HTTP_PORT}/register* + * body [provider register body] + + 3. Obtain Access Token: + * Send POST to *http://{CAPIF_HOSTNAME}/getauth* + * Body [provider getauth body] + + 4. Register Provider: + * Send POST *https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations* + * body [provider request body] + * Authentication Bearer with access_token + * Store each cert in a file with according name. + + 5. Delete registered provider at Provider Management: + * Send DELETE *https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations/{API_PROVIDER_NOT_REGISTERED}* + * Use AMF Certificate. + +**Execution Steps**: + + 1. Register Provider at CCF + 2. Delete Provider + +**Expected Result**: + + 1. Delete Provider: + 1. **404 Not Found** response. + 2. body returned must accomplish **ProblemDetails** data structure, with: + * status 404 + * title with message "Not Found" + * detail with message "Not Exist Provider Enrolment Details". + * cause with message "Not found registrations to send this api provider details". + +[provider register body]: ./provider_details_post_example.json "API Provider Enrolment Request" + +[provider request body]: ./provider_details_post_example.json "API Provider Enrolment Request" + +[provider request patch body]: ./provider_details_enrolment_details_patch_example.json "API Provider Enrolment Patch Request" + +[provider getauth body]: ./provider_getauth_example.json "Get Auth Example" + diff --git a/doc/testing/testplan/api_provider_management/provider_details_enrolment_details_patch_example.json b/doc/testing/testplan/api_provider_management/provider_details_enrolment_details_patch_example.json new file mode 100644 index 0000000000000000000000000000000000000000..4dac4f409eccfc7201c4eaf615b55f70c38b54e4 --- /dev/null +++ b/doc/testing/testplan/api_provider_management/provider_details_enrolment_details_patch_example.json @@ -0,0 +1,29 @@ +{ + "regSec": "<public provider key>", + "apiProvFuncs": [ + { + "regInfo": { + "apiProvPubKey": "<public provider apf key>" + }, + "apiProvFuncRole": "APF", + "apiProvFuncInfo": "APF_ROBOT_TESTING_PROVIDER" + }, + { + "regInfo": { + "apiProvPubKey": "<public provider aef key>" + }, + "apiProvFuncRole": "AEF", + "apiProvFuncInfo": "AEF_ROBOT_TESTING_PROVIDER" + }, + { + "regInfo": { + "apiProvPubKey": "<public provider amf key>" + }, + "apiProvFuncRole": "AMF", + "apiProvFuncInfo": "AMF_ROBOT_TESTING_PROVIDER" + } + ], + "apiProvDomInfo": "ROBOT_TESTING", + "suppFeat": "string", + "failReason": "string" +} \ No newline at end of file diff --git a/doc/testing/testplan/api_provider_management/provider_details_post_example.json b/doc/testing/testplan/api_provider_management/provider_details_post_example.json new file mode 100644 index 0000000000000000000000000000000000000000..48e91bacf24899e55221babf610598b9d4132b61 --- /dev/null +++ b/doc/testing/testplan/api_provider_management/provider_details_post_example.json @@ -0,0 +1,17 @@ +{ + "regSec": "string", + "apiProvFuncs": [ + { + "apiProvFuncId": "string", + "regInfo": { + "apiProvPubKey": "string", + "apiProvCert": "string" + }, + "apiProvFuncRole": "AEF", + "apiProvFuncInfo": "string" + } + ], + "apiProvDomInfo": "string", + "suppFeat": "string", + "failReason": "string" +} \ No newline at end of file diff --git a/doc/testing/testplan/api_provider_management/provider_getauth_example.json b/doc/testing/testplan/api_provider_management/provider_getauth_example.json new file mode 100644 index 0000000000000000000000000000000000000000..8fc82aeebfc9531651fa746bf10be11c6aa347f3 --- /dev/null +++ b/doc/testing/testplan/api_provider_management/provider_getauth_example.json @@ -0,0 +1,4 @@ +{ + "username": "ROBOT_TESTING_PROVIDER", + "password": "password" +} diff --git a/doc/testing/testplan/api_provider_management/provider_register_body.json b/doc/testing/testplan/api_provider_management/provider_register_body.json new file mode 100644 index 0000000000000000000000000000000000000000..fc26db2141eab904b1f2f8d96e963f2ec0efcbe1 --- /dev/null +++ b/doc/testing/testplan/api_provider_management/provider_register_body.json @@ -0,0 +1,7 @@ +{ + "password": "password", + "username": "ROBOT_TESTING_PUBLISHER", + "role": "provider", + "description": "Testing", + "cn": "ROBOT_TESTING_PUBLISHER" +} diff --git a/doc/testing/testplan/api_publish_service/README.md b/doc/testing/testplan/api_publish_service/README.md new file mode 100644 index 0000000000000000000000000000000000000000..668662dfb3c8b28f229b807daa95f0ee0476b81c --- /dev/null +++ b/doc/testing/testplan/api_publish_service/README.md @@ -0,0 +1,657 @@ +# Test Plan for CAPIF Api Publish Service +At this documentation you will have all information and related files and examples of test plan for this API. + +## Test Case 1: Publish API by Authorised API Publisher + +**Test ID**: ***capif_api_publish_service-1*** + +**Description**: + + This test case will check that an API Publisher can Publish an API + +**Pre-Conditions**: + + * CAPIF subscriber is pre-authorised (has valid apfId from CAPIF Authority) + +**Information of Test**: + + 1. Perform [Provider Registration] + + 2. Publish Service API at CCF: + + * Send Post to **ccf_publish_url**: *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis* + * body [service api description] with apiName **service_1** + * Use APF Certificate + +**Execution Steps**: + + 1. Register Provider at CCF and store certificates. + + 2. Publish Service API + + 3. Retrieve {apiId} from body and Location header with new resource created from response + +**Expected Result**: + + 1. Response to Publish request must accomplish: + 1. **201 Created** + 2. Response Body must follow **ServiceAPIDescription** data structure with: + * apiId + 1. Response Header **Location** must be received with URI to new resource created, following this structure: *{apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId}* + + 3. Published Service API is stored in CAPIF Database + +## Test Case 2: Publish API by NON Authorised API Publisher + +**Test ID**: ***capif_api_publish_service-2*** + +**Description**: + + This test case will check that an API Publisher cannot Publish an API withot valid apfId + +**Pre-Conditions**: + + * CAPIF subscriber is NOT pre-authorised (has invalid apfId from CAPIF Authority) + +**Information of Test**: + + 1. Perform [Provider Registration] + + 2. Publish Service API with invalid APF ID at CCF: + * Send Post to ccf_publish_url *https://{CAPIF_HOSTNAME}/published-apis/v1/{APF_ID_NOT_VALID}/service-apis* + * body [service api description] with apiName service_1 + * Use APF Certificate + +**Execution Steps**: + + 1. Register Provider at CCF and store certificates. + 2. Publish Service API with invalid APF ID + +**Expected Result**: + + 1. Response to Publish request must accomplish: + 1. **401 Unauthorized** + 2. Error Response Body must accomplish with **ProblemDetails** data structure with: + * status **401** + * title with message "Unauthorized" + * detail with message "Publisher not existing". + * cause with message "Publisher id not found". + + 2. Service API is NOT stored in CAPIF Database + + +## Test Case 3: Retrieve all APIs Published by Authorised apfId + +**Test ID**: ***capif_api_publish_service-3*** + +**Description**: + + This test case will check that an API Publisher can Retrieve all API published + +**Pre-Conditions**: + + * CAPIF subscriber is pre-authorised (has valid apfId from CAPIF Authority) + * At least 2 service APIs are published. + +**Information of Test**: + + 1. Perform [Provider Registration] + + 2. Publish Service API at CCF: + * Send Post to *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis* + * body [service api description] with apiName service_1 + * Get apiId + * Use APF Certificate + + 3. Publish Other Service API at CCF: + * Send Post to ccf_publish_url *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis* + * body [service api description] with apiName service_2 + * Get apiId + * Use APF Certificate + + 4. Retrieve all published APIs: + * Send Get to ccf_publish_url *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis* + * Use APF Certificate + +**Execution Steps**: + + 1. Register Provider at CCF and store certificates. + 2. Publish Service API service_1 + 3. Retrieve {apiId1} from body and Location header with new resource created from response + 4. Publish Service API service_2 + 5. Retrieve {apiId2} from body and Location header with new resource created from response + 6. Retrieve All published APIs and check if both are present. + +**Expected Result**: + + 1. Response to service 1 Publish request must accomplish: + 1. **201 Created** + 2. Response Body must follow **ServiceAPIDescription** data structure with: + * apiId + 3. Response Header **Location** must be received with URI to new resource created, following this structure: *{apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId1}* + + 2. Response to service 2 Publish request must accomplish: + 1. **201 Created** + 2. Response Body must follow **ServiceAPIDescription** data structure with: + * apiId + 3. Response Header **Location** must be received with URI to new resource created, following this structure: *{apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId2}* + + 3. Published Service APIs are stored in CAPIF Database + + 4. Response to Retrieve all published APIs: + 1. **200 OK** + 2. Response body must return an array of **ServiceAPIDescription** data. + 3. Array must contain all previously published APIs. + +## Test Case 4: Retrieve all APIs Published by NON Authorised apfId + +**Test ID**: ***capif_api_publish_service-4*** + +**Description**: + + This test case will check that an API Publisher cannot Retrieve API published when apfId is not authorised + +**Pre-Conditions**: + + * CAPIF subscriber is NOT pre-authorised (has invalid apfId from CAPIF Authority) + +**Information of Test**: + + 1. Perform [Provider Registration] + + 2. Retrieve all published APIs: + * Send Get to *https://{CAPIF_HOSTNAME}/published-apis/v1/{APF_ID_NOT_VALID}/service-apis* + * Use APF Certificate + +**Execution Steps**: + + 1. Register Provider at CCF and store certificates. + 2. Retrieve All published APIs + +**Expected Result**: + + 1. Response to Publish request must accomplish: + 1. **401 Non Authorized** + 2. Error Response Body must accomplish with **ProblemDetails** data structure with: + * status **401** + * title with message "Unauthorized" + * detail with message "Provider not existing". + * cause with message "Provider id not found". + + 2. Service API is NOT stored in CAPIF Database + +## Test Case 5: Retrieve single APIs Published by Authorised apfId + +**Test ID**: ***capif_api_publish_service-5*** + +**Description**: + + This test case will check that an API Publisher can Retrieve API published one by one + +**Pre-Conditions**: + + * CAPIF subscriber is pre-authorised (has valid apfId from CAPIF Authority) + * At least 2 service APIs are published. + +**Information of Test**: + + 1. Perform [Provider Registration] + + 2. Publish Service API at CCF: + * Send Post to ccf_publish_url *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis* + * body [service api description] with apiName service_1 + * Get apiId + * Use APF Certificate + + 3. Publish Other Service API at CCF: + * Send Post to ccf_publish_url *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis* + * body [service api description] with apiName service_2 + * Get apiId + * Use APF Certificate + + 4. Retrieve service_1 published APIs detail: + * Send Get to ccf_publish_url *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis/{apiId1}* + * Use APF Certificate + + 5. Retrieve service_2 published APIs detail: + * Send Get to ccf_publish_url *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis/{apiId2}* + * Use APF Certificate + +**Execution Steps**: + + 1. Register Provider at CCF and store certificates. + 2. Publish Service API service_1. + 3. Retrieve {apiId1} from body and Location header with new resource created from response. + 4. Publish Service API service_2. + 5. Retrieve {apiId2} from body and Location header with new resource created from response. + 6. Retrieve service_1 API Detail. + 7. Retrieve service_2 API Detail. + +**Expected Result**: + + 1. Response to service 1 Publish request must accomplish: + 1. **201 Created** + 2. Response Body must follow **ServiceAPIDescription** data structure with: + * apiId + 3. Response Header **Location** must be received with URI to new resource created, following this structure: *{apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId1}* + + 2. Response to service 2 Publish request must accomplish: + 1. **201 Created** + 2. Response Body must follow **ServiceAPIDescription** data structure with: + * apiId + 3. Response Header **Location** must be received with URI to new resource created, following this structure: *{apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId2}* + + 3. Published Service APIs are stored in CAPIF Database + + 4. Response to Retrieve service_1 published API using apiId1: + 1. **200 OK** + 2. Response body must return a **ServiceAPIDescription** data. + 3. Array must contain same information than service_1 published registration response. + + 5. Response to Retrieve service_2 published API using apiId2: + 1. **200 OK** + 2. Response body must return a **ServiceAPIDescription** data. + 3. Array must contain same information than service_2 published registration response. + + +## Test Case 6: Retrieve single APIs non Published by Authorised apfId + +**Test ID**: ***capif_api_publish_service-6*** + +**Description**: + + This test case will check that an API Publisher try to get detail of not published api. + +**Pre-Conditions**: + + * CAPIF subscriber is pre-authorised (has valid apfId from CAPIF Authority) + * No published api + +**Information of Test**: + + 1. Perform [Provider Registration] + 2. Retrieve not published APIs detail: + * Send Get to ccf_publish_url *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis/{SERVICE_API_ID_NOT_VALID}* + * Use APF Certificate + +**Execution Steps**: + + 1. Register Provider at CCF and store certificates. + 2. Retrieve not published API Detail. + +**Expected Result**: + + 1. Response to Retrieve for NOT published API must accomplish: + 1. **404 Not Found** + 2. Error Response Body must accomplish with **ProblemDetails** data structure with: + * status **404** + * title with message "Not Found" + * detail with message "Service API not found". + * cause with message "No Service with specific credentials exists". + + +## Test Case 7: Retrieve single APIs Published by NON Authorised apfId + +**Test ID**: ***capif_api_publish_service-7*** + +**Description**: + + This test case will check that an API Publisher cannot Retrieve detailed API published when apfId is not authorised + +**Pre-Conditions**: + + * CAPIF subscriber is NOT pre-authorised (has invalid apfId from CAPIF Authority) + +**Information of Test**: + + 1. Perform [Provider Registration] and [Invoker Onboarding] + + 2. Publish Service API at CCF: + * Send Post to ccf_publish_url *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis* + * body [service api description] with apiName service_1 + * Get apiId + * Use APF Certificate + + 3. Retrieve detailed published APIs: + * Send Get to *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis/${apiId}* + * Use Invoker certificate + +**Execution Steps**: + + 1. Register Provider at CCF and store certificates. + 2. Publish Service API at CCF + 3. Retrieve {apiId} from body and Location header with new resource created from response. + 4. Register and onboard Invoker at CCF + 5. Store signed Invoker Certificate + 6. Retrieve detailed published API acting as Invoker + +**Expected Result**: + + 1. Response to Retrieve Detailed published API acting as Invoker must accomplish: + 1. **401 Unauthorized** + 2. Error Response Body must accomplish with **ProblemDetails** data structure with: + * status **401** + * title with message "Unauthorized" + * detail with message "User not authorized". + * cause with message "Certificate not authorized". + + 2. Service API is NOT stored in CAPIF Database + + +## Test Case 8: Update API Published by Authorised apfId with valid serviceApiId + +**Test ID**: ***capif_api_publish_service-8*** + +**Description**: + + This test case will check that an API Publisher can Update published API with a valid serviceApiId + +**Pre-Conditions**: + + * CAPIF subscriber is pre-authorised (has valid apfId from CAPIF Authority) + * A service APIs is published. + +**Information of Test**: + + 1. Perform [Provider Registration] + + 2. Publish Service API at CCF: + * Send Post to ccf_publish_url *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis* + * body [service api description] with apiName service_1 + * Get apiId + * get resource url from location Header. + * Use APF Certificate + + 3. Update published API at CCF: + * Send PUT to resource URL *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis/{serivceApiId}* + * body [service api description] with overrided apiName to service_1_modified + * Use APF Certificate + + 4. Retrieve detail of service API: + * Send Get to resource URL *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis/{serivceApiId}* + * check apiName is service_1_modified + * Use APF Certificate + +**Execution Steps**: + + 1. Register Provider at CCF and store certificates. + 2. Publish Service API + 3. Retrieve {apiId} from body and Location header with new resource url created from response + 4. Update published Service API. + 5. Retrieve detail of Service API + +**Expected Result**: + + 1. Response to Publish request must accomplish: + 1. **201 Created** + 2. Response Body must follow **ServiceAPIDescription** data structure with: + * apiId + 3. Response Header **Location** must be received with URI to new resource created, following this structure: *{apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId}* + + 2. Response to Update Published Service API: + 1. **200 OK** + 2. Response Body must follow **ServiceAPIDescription** data structure with: + * apiName service_1_modified + + 3. Response to Retrieve detail of Service API: + 1. **200 OK** + 2. Response Body must follow **ServiceAPIDescription** data structure with: + * apiName service_1_modified. + + +## Test Case 9: Update APIs Published by Authorised apfId with invalid serviceApiId + +**Test ID**: ***capif_api_publish_service-9*** + +**Description**: + + This test case will check that an API Publisher cannot Update published API with a invalid serviceApiId + +**Pre-Conditions**: + + * CAPIF subscriber is pre-authorised (has valid apfId from CAPIF Authority) + +**Information of Test**: + + 1. Perform [Provider Registration] + + 2. Publish Service API at CCF: + * Send Post to ccf_publish_url *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis* + * body [service api description] with apiName service_1 + * Get apiId + * Use APF Certificate + + 3. Update published API at CCF: + * Send PUT to resource URL *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis/{SERVICE_API_ID_NOT_VALID}* + * body [service api description] with overrided apiName to ***service_1_modified*** + * Use APF Certificate + +**Execution Steps**: + + 1. Register Provider at CCF and store certificates. + 2. Update published Service API. + +**Expected Result**: + + 1. Response to Publish request must accomplish: + 1. **201 Created** + 2. Response Body must follow **ServiceAPIDescription** data structure with: + * apiId + 3. Response Header **Location** must be received with URI to new resource created, following this structure: *{apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId}* + + 2. Response to Update Published Service API: + 1. **404 Not Found** + 2. Error Response Body must accomplish with **ProblemDetails** data structure with: + * status **404** + * title with message "Not Found" + * detail with message "Service API not found". + * cause with message "Service API id not found". + +## Test Case 10: Update APIs Published by NON Authorised apfId + +**Test ID**: ***capif_api_publish_service-10*** + +**Description**: + + This test case will check that an API Publisher cannot Update API published when apfId is not authorised + +**Pre-Conditions**: + + * CAPIF subscriber is NOT pre-authorised (has invalid apfId from CAPIF Authority) + +**Information of Test**: + + 1. Perform [Provider Registration] and [Invoker Onboarding] + + 2. Publish Service API at CCF: + * Send Post to ccf_publish_url *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis* + * body [service api description] with apiName service_1 + * Get apiId + * Use APF Certificate + + 3. Update published API at CCF: + * Send PUT to resource URL *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis/{serviceApiId}* + * body [service api description] with overrided apiName to ***service_1_modified*** + * Use invoker certificate + + 4. Retrieve detail of service API: + * Send Get to resource URL *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis/{serivceApiId}* + * check apiName is service_1 + * Use APF Certificate + +**Execution Steps**: + + 1. Register Provider at CCF and store certificates. + 2. Publish Service API at CCF + 3. Retrieve {apiId} from body and Location header with new resource created from response. + 4. Register and onboard Invoker at CCF + 5. Store signed Invoker Certificate + 6. Update published API at CCF as Invoker + 7. Retrieve detail of Service API as publisher + +**Expected Result**: + + 1. Response to Update published API acting as Invoker must accomplish: + 1. **401 Unauthorized** + 2. Error Response Body must accomplish with **ProblemDetails** data structure with: + * status **401** + * title with message "Unauthorized" + * detail with message "User not authorized". + * cause with message "Certificate not authorized". + + 2. Response to Retrieve Detail of Service API: + 1. **200 OK** + 2. Response Body must follow **ServiceAPIDescription** data structure with: + * apiName service_1. + + +## Test Case 11: Delete API Published by Authorised apfId with valid serviceApiId + +**Test ID**: ***capif_api_publish_service-11*** + +**Description**: + + This test case will check that an API Publisher can Delete published API with a valid serviceApiId + +**Pre-Conditions**: + + * CAPIF subscriber is pre-authorised (has valid apfId from CAPIF Authority). + * A service APIs is published. + +**Information of Test**: + + 1. Perform [Provider Registration] + + 2. Publish Service API at CCF: + * Send Post to ccf_publish_url *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis* + * body [service api description] with apiName service_1 + * Get apiId + * Use APF Certificate + + 3. Remove published Service API at CCF: + * Send DELETE to resource URL *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis/{serviceApiId}* + * Use APF Certificate + 4. Retrieve detail of service API: + * Send Get to resource URL *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis/{serivceApiId}* + * Use APF Certificate + +**Execution Steps**: + + 1. Register Provider at CCF and store certificates. + 2. Publish Service API + 3. Retrieve {apiId} from body and Location header with new resource created from response + 4. Remove published API at CCF + 5. Try to retreive deleted service API from CCF + +**Expected Result**: + + 1. Response to Publish request must accomplish: + 1. **201 Created** + 2. Response Body must follow **ServiceAPIDescription** data structure with: + * apiId + 3. Response Header **Location** must be received with URI to new resource created, following this structure: *{apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId}* + + 2. Published Service API is stored in CAPIF Database + + 3. Response to Remove published Service API at CCF: + 1. **204 No Content** + + 4. Response to Retrieve for DELETED published API must accomplish: + 1. **404 Not Found** + 2. Error Response Body must accomplish with **ProblemDetails** data structure with: + * status 404 + * title with message "Not Found" + * detail with message "Service API not found". + * cause with message "No Service with specific credentials exists". + + +## Test Case 12: Delete APIs Published by Authorised apfId with invalid serviceApiId + +**Test ID**: ***capif_api_publish_service-12*** + +**Description**: + + This test case will check that an API Publisher cannot Delete with invalid serviceApiId + +**Pre-Conditions**: + + * CAPIF subscriber is pre-authorised (has valid apfId from CAPIF Authority). + +**Information of Test**: + + 1. Perform [Provider Registration] + + 2. Remove published Service API at CCF with invalid serviceId: + * Send DELETE to resource URL *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis/{SERVICE_API_ID_NOT_VALID}* + * Use APF Certificate + +**Execution Steps**: + + 1. Register Provider at CCF and store certificates. + 2. Remove published API at CCF with invalid serviceId + +**Expected Result**: + + 1. Response to Remove published Service API at CCF: + 1. **404 Not Found** + 2. Error Response Body must accomplish with **ProblemDetails** data structure with: + * status 404 + * title with message "Not Found" + * detail with message "Service API not found". + * cause with message "Service API id not found". + + +## Test Case 13: Delete APIs Published by NON Authorised apfId + +**Test ID**: ***capif_api_publish_service-12*** + +**Description**: + + This test case will check that an API Publisher cannot Delete API published when apfId is not authorised + +**Pre-Conditions**: + + * CAPIF subscriber is pre-authorised (has valid apfId from CAPIF Authority). + +**Information of Test**: + + 1. Perform [Provider Registration] and [Invoker Onboarding] + + 2. Publish Service API at CCF: + * Send Post to ccf_publish_url *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis* + * body [service api description] with apiName service_1 + * Get apiId + * Use APF Certificate + + 3. Remove published Service API at CCF with invalid serviceId as Invoker: + * Send DELETE to resource URL *https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis/{SERVICE_API_ID_NOT_VALID}* + * Use invoker certificate. + +**Execution Steps**: + + 1. Register Provider at CCF and store certificates. + 2. Register Invoker and onboard Invoker at CCF + 3. Remove published API at CCF with invalid serviceId as Invoker + +**Expected Result**: + + 1. Response to Remove published Service API at CCF: + 1. **401 Unauthorized** + 2. Error Response Body must accomplish with **ProblemDetails** data structure with: + * status **401** + * title with message "Unauthorized" + * detail with message "User not authorized". + * cause with message "Certificate not authorized". + + + [service api description]: ./service_api_description_post_example.json "Service API Description Request" + [publisher register body]: ./publisher_register_body.json "Publish register Body" + [invoker onboarding body]: ../api_invoker_management/invoker_details_post_example.json "API Invoker Request" + [invoker register body]: ../api_invoker_management/invoker_register_body.json "Invoker Register Body" + [provider request body]: ../api_provider_management/provider_details_post_example.json "API Provider Enrolment Request" + [provider request patch body]: ../api_provider_management/provider_details_enrolment_details_patch_example.json "API Provider Enrolment Patch Request" + [provider getauth body]: ../api_provider_management/provider_getauth_example.json "Get Auth Example" + + [invoker onboarding]: ../common_operations/README.md#register-an-invoker "Invoker Onboarding" + [provider registration]: ../common_operations/README.md#register-a-provider "Provider Registration" + diff --git a/doc/testing/testplan/api_publish_service/publisher_register_body.json b/doc/testing/testplan/api_publish_service/publisher_register_body.json new file mode 100644 index 0000000000000000000000000000000000000000..fc26db2141eab904b1f2f8d96e963f2ec0efcbe1 --- /dev/null +++ b/doc/testing/testplan/api_publish_service/publisher_register_body.json @@ -0,0 +1,7 @@ +{ + "password": "password", + "username": "ROBOT_TESTING_PUBLISHER", + "role": "provider", + "description": "Testing", + "cn": "ROBOT_TESTING_PUBLISHER" +} diff --git a/doc/testing/testplan/api_publish_service/service_api_description_post_example.json b/doc/testing/testplan/api_publish_service/service_api_description_post_example.json new file mode 100644 index 0000000000000000000000000000000000000000..b725b428629509bf39a79c030f1bf93f4b6f18f6 --- /dev/null +++ b/doc/testing/testplan/api_publish_service/service_api_description_post_example.json @@ -0,0 +1,113 @@ +{ + "apiName": "service_1", + "aefProfiles": [ + { + "aefId": "string", + "versions": [ + { + "apiVersion": "v1", + "expiry": "2021-11-30T10:32:02.004Z", + "resources": [ + { + "resourceName": "string", + "commType": "REQUEST_RESPONSE", + "uri": "string", + "custOpName": "string", + "operations": [ + "GET" + ], + "description": "string" + } + ], + "custOperations": [ + { + "commType": "REQUEST_RESPONSE", + "custOpName": "string", + "operations": [ + "GET" + ], + "description": "string" + } + ] + } + ], + "protocol": "HTTP_1_1", + "dataFormat": "JSON", + "securityMethods": ["PSK"], + "interfaceDescriptions": [ + { + "ipv4Addr": "string", + "port": 65535, + "securityMethods": ["PSK"] + }, + { + "ipv4Addr": "string", + "port": 65535, + "securityMethods": ["PSK"] + } + ] + }, + { + "aefId": "string", + "versions": [ + { + "apiVersion": "v1", + "expiry": "2021-11-30T10:32:02.004Z", + "resources": [ + { + "resourceName": "string", + "commType": "REQUEST_RESPONSE", + "uri": "string", + "custOpName": "string", + "operations": [ + "GET" + ], + "description": "string" + } + ], + "custOperations": [ + { + "commType": "REQUEST_RESPONSE", + "custOpName": "string", + "operations": [ + "GET" + ], + "description": "string" + } + ] + } + ], + "protocol": "HTTP_1_1", + "dataFormat": "JSON", + "securityMethods": ["PSK"], + "interfaceDescriptions": [ + { + "ipv4Addr": "string", + "port": 65535, + "securityMethods": ["PSK"] + }, + { + "ipv4Addr": "string", + "port": 65535, + "securityMethods": ["PSK"] + } + ] + } + ], + "description": "string", + "supportedFeatures": "fffff", + "shareableInfo": { + "isShareable": true, + "capifProvDoms": [ + "string" + ] + }, + "serviceAPICategory": "string", + "apiSuppFeats": "fffff", + "pubApiPath": { + "ccfIds": [ + "string" + ] + }, + "ccfId": "string" +} \ No newline at end of file diff --git a/doc/testing/testplan/api_security_service/README.md b/doc/testing/testplan/api_security_service/README.md new file mode 100644 index 0000000000000000000000000000000000000000..306470adfa1b1041f00f272243975dd2f5c9c9b6 --- /dev/null +++ b/doc/testing/testplan/api_security_service/README.md @@ -0,0 +1,1287 @@ +# Test Plan for CAPIF Api Security Service +At this documentation you will have all information and related files and examples of test plan for this API. + +## Test Case 1: Create a security context for an API invoker + +**Test ID**: ***capif_security_api-1*** + +**Description**: + + This test case will check that an API Invoker can create a Security context + +**Pre-Conditions**: + + * API Invoker is pre-authorised (has valid apiInvokerID from CAPIF Authority) + +**Information of Test**: + + 1. Perform [Invoker Onboarding] + 2. Create Security Context for this Invoker + * Send PUT *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * body [service security body] + * Use Invoker Certificate + +**Execution Steps**: + + 1. Register and onboard Invoker at CCF + 2. Store signed Certificate + 3. Create Security Context + +**Expected Result**: + + 1. Create security context: + 1. **201 Created** response. + 2. body returned must accomplish **ServiceSecurity** data structure. + 3. Location Header must contain the new resource URL *{apiRoot}/capif-security/v1/trustedInvokers/{apiInvokerId}* + + +## Test Case 2: Create a security context for an API invoker with Provider role + +**Test ID**:: ***capif_security_api-2*** + +**Description**: + + This test case will check that an Provider cannot create a Security context with valid apiInvokerId. + +**Pre-Conditions**: + + * API Invoker is pre-authorised (has valid apiInvokerID), but user that create Security Context with Provider role + +**Information of Test**: + + 1. Perform [Provider Registration] and [Invoker Onboarding] + + 2. Create Security Context for this Invoker but using Provider certificate. + * Send PUT *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * body [service security body] + * Using AEF certificate + +**Execution Steps**: + + 1. Register and onboard Invoker at CCF + 2. Register Provider at CCF + 3. Create Security Context using Provider certificate + +**Expected Result**: + + 1. Create security context using Provider certificate: + 1. **401 Unauthorized** response. + 2. body returned must accomplish **ProblemDetails** data structure, with: + * status **401** + * title with message "Unauthorized" + * detail with message "Role not authorized for this API route". + * cause with message "User role must be invoker". + + 2. No context stored at DB + +## Test Case 3: Create a security context for an API invoker with Provider entity role and invalid apiInvokerId + +**Test ID**:: ***capif_security_api-3*** + +**Description**: + + This test case will check that an Provider cannot create a Security context with invalid apiInvokerID. + +**Pre-Conditions**: + + * API Invoker is pre-authorised (has valid apiInvokerID), but user that create Security Context with Provider role + +**Information of Test**: + + 1. Perform [Provider Registration] + + 2. Create Security Context for this not valid apiInvokerId and using Provider certificate. + * Send PUT *https://{CAPIF_HOSTNAME}/trustedInvokers/{API_INVOKER_NOT_VALID}* + * body [service security body] + * Using AEF certificate + +**Execution Steps**: + + 1. Register Provider at CCF + 2. Create Security Context using Provider certificate + +**Expected Result**: + + 1. Create security context using Provider certificate: + 1. **401 Unauthorized** response. + 2. body returned must accomplish **ProblemDetails** data structure, with: + * status **401** + * title with message "Unauthorized" + * detail with message "Role not authorized for this API route". + * cause with message "User role must be invoker". + 2. No context stored at DB + +## Test Case 4: Create a security context for an API invoker with Invoker entity role and invalid apiInvokerId + +**Test ID**:: ***capif_security_api-4*** + +**Description**: + + This test case will check that an Invoker cannot create a Security context with valid apiInvokerId. + +**Pre-Conditions**: + + * API Invoker is pre-authorised (has valid apiInvokerID), but user that create Security Context with invalid apiInvokerId + +**Information of Test**: + + 1. Perform [Invoker Onboarding] + + 2. Create Security Context for this Invoker: + * Send PUT *https://{CAPIF_HOSTNAME}/trustedInvokers/{API_INVOKER_NOT_VALID}* + * body [service security body] + * Use Invoker Certificate + +**Execution Steps**: + + 1. Register and onboard Invoker at CCF + 2. Create Security Context using Provider certificate + +**Expected Result**: + + 1. Create security context using Provider certificate: + 1. **404 Not Found** response. + 2. body returned must accomplish **ProblemDetails** data structure, with: + * status **404** + * title with message "Not Found" + * detail with message "Invoker not found". + * cause with message "API Invoker not exists or invalid ID". + + 2. No context stored at DB + + +## Test Case 5: Retrieve the Security Context of an API Invoker + +**Test ID**:: ***capif_security_api-5*** + +**Description**: + + This test case will check that an provider can retrieve the Security context of an API Invoker + +**Pre-Conditions**: + + * Provider is pre-authorised (has valid apfId from CAPIF Authority) and API Invoker has created a valid Security Context + +**Information of Test**: + + 1. Perform [Provider Registration] and [Invoker Onboarding] + + 2. Create Security Context for this Invoker. + * Send PUT *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * body [service security body] + * Using Invoker certificate + + 3. Retrieve Security Context of Invoker by Provider: + * Send GET *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * Using AEF Certificate + +**Execution Steps**: + + 1. Register and onboard Invoker at CCF + 2. Register Provider at CCF + 3. Create Security Context using Provider certificate + 4. Retrieve Security Context by Provider + +**Expected Result**: + + 1. Retrieve security context: + 1. **200 OK** response. + 2. body returned must accomplish **ServiceSecurity** data structure. + + +## Test Case 6: Retrieve the Security Context of an API Invoker with invalid apiInvokerID + +**Test ID**:: ***capif_security_api-6*** + +**Description**: + + This test case will check that an provider can retrieve the Security context of an API Invoker + +**Pre-Conditions**: + + * Provider is pre-authorised (has valid apfId from CAPIF Authority) and API Invoker has created a valid Security Context + +**Information of Test**: + + 1. Perform [Provider Registration] + + 2. Retrieve Security Context of invalid Invoker by Provider: + * Send GET *https://{CAPIF_HOSTNAME}/trustedInvokers/{API_INVOKER_NOT_VALID}* + * Using AEF Certificate. + +**Execution Steps**: + + 2. Register Provider at CCF + 3. Create Security Context using Provider certificate + 4. Retrieve Security Context by Provider of invalid invoker + +**Expected Result**: + + 1. Retrieve security context: + 1. **404 Not Found** response. + 2. body returned must accomplish **ProblemDetails** data structure, with: + * status **404** + * title with message "Not Found" + * detail with message "Invoker not found". + * cause with message "API Invoker not exists or invalid ID". + + +## Test Case 7: Retrieve the Security Context of an API Invoker with invalid apfId + +**Test ID**:: ***capif_security_api-7*** + +**Description**: + + This test case will check that an Provider cannot retrieve the Security context of an API Invoker without valid apfId + +**Pre-Conditions**: + + * API Exposure Function is not pre-authorised (has invalid apfId) + +**Information of Test**: + + 1. Perform [Provider Registration] and [Invoker Onboarding] + + 2. Create Security Context for this Invoker + * Send PUT *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * body [service security body] + * Using Invoker Certificate + + 3. Retrieve Security Context as Invoker role: + * Send GET *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * Using Invoker Certificate + +**Execution Steps**: + + 1. Register and onboard Invoker at CCF + 2. Store signed Certificate + 3. Create Security Context + 4. Retrieve Security Context as Provider. + +**Expected Result**: + + 1. Create security context: + 1. **401 Unauthorized** response. + 2. body returned must accomplish **ProblemDetails** data structure, with: + * status **401** + * title with message "Unauthorized" + * detail with message "Role not authorized for this API route". + * cause with message "User role must be aef". + + +## Test Case 8: Delete the Security Context of an API Invoker + +**Test ID**:: ***capif_security_api-8*** + +**Description**: + + This test case will check that an Provider can delete a Security context + +**Pre-Conditions**: + + * Provider is pre-authorised (has valid apfId from CAPIF Authority) and API Invoker has created a valid Security Context + +**Information of Test**: + + 1. Perform [Provider Registration] and [Invoker Onboarding] + + 2. Create Security Context for this Invoker but using Provider certificate. + * Send PUT *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * body [service security body] + * Using AEF certificate + + 3. Delete Security Context of Invoker by Provider: + * Send DELETE *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * Use AEF certificate + + 4. Retrieve Security Context of Invoker by Provider: + * Send GET *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * Using AEF Certificate + +**Execution Steps**: + + 1. Register and onboard Invoker at CCF + 2. Register Provider at CCF + 3. Create Security Context using Provider certificate + 4. Delete Security Context by Provider + +**Expected Result**: + + 1. Delete security context: + 1. **204 No Content** response. + + 2. Retrieve security context: + 1. **404 Not Found** response. + 2. body returned must accomplish **ProblemDetails** data structure, with: + * status **404** + * title with message "Not Found" + * detail with message "Security context not found". + * cause with message "API Invoker not exists or invalid ID". + + +## Test Case 9: Delete the Security Context of an API Invoker with Invoker entity role + +**Test ID**:: ***capif_security_api-9*** + +**Description**: + + This test case will check that an Invoker cannot delete a Security context + +**Pre-Conditions**: + + * Provider is pre-authorised (has valid apfId from CAPIF Authority) and API Invoker has created a valid Security Context + +**Information of Test**: + + 1. Perform [Provider Registration] and [Invoker Onboarding] + + 2. Create Security Context for this Invoker: + * Send PUT *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * body [service security body] + * Using Invoker certificate + + 3. Delete Security Context of Invoker: + * Send DELETE *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * Use Invoker certificate + +**Execution Steps**: + + 1. Register Provider at CCF + 2. Create Security Context using Provider certificate + 3. Delete Security Context by Invoker + +**Expected Result**: + + 1. Delete security context: + 1. **401 Unauthorized** response. + 2. body returned must accomplish **ProblemDetails** data structure, with: + * status **401** + * title with message "Unauthorized" + * detail with message "Role not authorized for this API route". + * cause with message "User role must be aef". + + +## Test Case 10: Delete the Security Context of an API Invoker with Invoker entity role and invalid apiInvokerID + +**Test ID**:: ***capif_security_api-10*** + +**Description**: + + This test case will check that an Invoker cannot delete a Security context with invalid + +**Pre-Conditions**: + + * Invoker is pre-authorised. + +**Information of Test**: + + 1. Perform [Invoker Onboarding] + + 2. Delete Security Context of Invoker: + * Send DELETE *https://{CAPIF_HOSTNAME}/trustedInvokers/{API_INVOKER_NOT_VALID}* + * Use Invoker certificate + +**Execution Steps**: + + 1. Register Provider at CCF + 2. Delete Security Context by invoker + +**Expected Result**: + + 1. Delete security context: + 1. **401 Unauthorized** response. + 2. body returned must accomplish **ProblemDetails** data structure, with: + * status **401** + * title with message "Unauthorized" + * detail with message "Role not authorized for this API route". + * cause with message "User role must be aef". + + +## Test Case 11: Delete the Security Context of an API Invoker with invalid apiInvokerID + +**Test ID**:: ***capif_security_api-11*** + +**Description**: + + This test case will check that an Provider cannot delete a Security context of invalid apiInvokerId + +**Pre-Conditions**: + + * Provider is pre-authorised (has valid apfId from CAPIF Authority). + +**Information of Test**: + + 1. Perform [Provider Registration] + + 2. Delete Security Context of Invoker by Provider: + * Send DELETE *https://{CAPIF_HOSTNAME}/trustedInvokers/{API_INVOKER_NOT_VALID}* + * Use AEF certificate + +**Execution Steps**: + + 1. Register Provider at CCF + 2. Delete Security Context by provider + +**Expected Result**: + + 1. Retrieve security context: + 1. **404 Not Found** response. + 2. body returned must accomplish **ProblemDetails** data structure, with: + * status **404** + * title with message "Not Found" + * detail with message "Invoker not found". + * cause with message "API Invoker not exists or invalid ID". + + +## Test Case 12: Update the Security Context of an API Invoker + +**Test ID**:: ***capif_security_api-12*** + +**Description**: + + This test case will check that an API Invoker can update a Security context + +**Pre-Conditions**: + + * API Invoker is pre-authorised (has valid apiInvokerID from CAPIF Authority) and Provider is also authorized + +**Information of Test**: + + 1. Perform [Provider Registration] and [Invoker Onboarding] + + 2. Create Security Context for this Invoker: + * Send PUT *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * body [service security body] + * Using Invoker Certificate. + + 3. Update Security Context of Invoker: + * Send POST *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}/update* + * body [service security body] but with notification destination modified to http://robot.testing2 + * Using Invoker Certificate. + + 4. Retrieve Security Context of Invoker by Provider: + * Send GET *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * Using AEF Certificate. + +**Execution Steps**: + + 1. Register and onboard Invoker at CCF + 2. Register Provider at CCF + 3. Create Security Context By Invoker + 4. Update Security Context By Invoker + 5. Retrieve Security Context By Provider + +**Expected Result**: + + 1. Update security context: + 1. **200 OK** response. + 2. body returned must accomplish **ServiceSecurity** data structure. + + 2. Retrieve security context: + 1. **200 OK** response. + 2. body returned must accomplish **ServiceSecurity** data structure. + 1. Check is this returned object match with modified one. + + +## Test Case 13: Update the Security Context of an API Invoker with Provider entity role + +**Test ID**:: ***capif_security_api-13*** + +**Description**: + + This test case will check that an Provider cannot update a Security context + +**Pre-Conditions**: + + * API Invoker is pre-authorised (has valid apiInvokerID from CAPIF Authority) and Provider is also authorized. + * Invoker has created the Security Context previously. + +**Information of Test**: + + 1. Perform [Provider Registration] and [Invoker Onboarding] + + 2. Create Security Context for this Invoker: + * Send PUT *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * body [service security body] + * Using Invoker Certificate. + + 3. Update Security Context of Invoker by Provider: + * Send POST *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}/update* + * body [service security body] but with notification destination modified to http://robot.testing2 + * Using AEF Certificate + +**Execution Steps**: + + 1. Register and onboard Invoker at CCF + 2. Register Provider at CCF + 3. Create Security Context + 4. Update Security Context as Provider + +**Expected Result**: + + 1. Update security context: + 1. **401 Unauthorized** response. + 2. body returned must accomplish **ProblemDetails** data structure, with: + * status **401** + * title with message "Unauthorized" + * detail with message "Role not authorized for this API route". + * cause with message "User role must be invoker". + + +## Test Case 14: Update the Security Context of an API Invoker with AEF entity role and invalid apiInvokerId + +**Test ID**:: ***capif_security_api-14*** + +**Description**: + + This test case will check that an Provider cannot update a Security context of invalid apiInvokerId + +**Pre-Conditions**: + + * API Invoker is pre-authorised (has valid apiInvokerID from CAPIF Authority) and Provider is also authorized. + * Invoker has created the Security Context previously. + +**Information of Test**: + + 1. Perform [Provider Registration] + + 2. Update Security Context of Invoker by Provider: + * Send POST *https://{CAPIF_HOSTNAME}/trustedInvokers/{API_INVOKER_NOT_VALID}/update* + * body [service security body] + * Using AEF Certificate + +**Execution Steps**: + + 1. Register Provider at CCF + 2. Update Security Context as Provider + +**Expected Result**: + + 1. Update security context: + 1. **401 Unauthorized** response. + 2. body returned must accomplish **ProblemDetails** data structure, with: + * status **401** + * title with message "Unauthorized" + * detail with message "Role not authorized for this API route". + * cause with message "User role must be invoker". + + +## Test Case 15: Update the Security Context of an API Invoker with invalid apiInvokerID + +**Test ID**:: ***capif_security_api-15*** + +**Description**: + + This test case will check that an API Invoker cannot update a Security context not valid apiInvokerId + +**Pre-Conditions**: + + * API Invoker is pre-authorised (has valid apiInvokerID from CAPIF Authority) + +**Information of Test**: + + 1. Perform [Provider Registration] and [Invoker Onboarding] + + 2. Update Security Context of Invoker: + * Send POST *https://{CAPIF_HOSTNAME}/trustedInvokers/{API_INVOKER_NOT_VALID}/update* + * body [service security body] + * Using Invoker Certificate. + +**Execution Steps**: + + 1. Register and onboard Invoker at CCF + 2. Update Security Context + +**Expected Result**: + +1. Retrieve security context: + 1. **404 Not Found** response. + 2. body returned must accomplish **ProblemDetails** data structure, with: + * status **404** + * title with message "Not Found" + * detail with message "Invoker not found". + * cause with message "API Invoker not exists or invalid ID". + + +## Test Case 16: Revoke the authorization of the API invoker for APIs. + +**Test ID**:: ***capif_security_api-16*** + +**Description**: + + This test case will check that a Provider can revoke the authorization for APIs + +**Pre-Conditions**: + + * API Invoker is pre-authorised (has valid apiInvokerID from CAPIF Authority) and Provider is also authorized + +**Information of Test**: + + 1. Perform [Provider Registration] and [Invoker Onboarding] + + 2. Create Security Context By Invoker: + * Send PUT *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * body [service security body] + * Using Invoker Certificate + + 3. Revoke Authorization by Provider: + * Send POST *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}/delete* + * body [security notification body] + * Using AEF Certificate. + + 4. Retrieve Security Context by Provider: + * Send GET *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * Using AEF Certificate. + + +**Execution Steps**: + + 1. Register and onboard Invoker at CCF + 2. Register Provider at CCF + 3. Create Security Context by Invoker + 4. Revoke Security Context by Provider + 5. Retrieve Security Context by Provider + +**Expected Result**: + + 1. Revoke Authorization: + 1. **204 No Content** response. + + 2. Retrieve security context: + 1. **404 Not Found** response. + 2. body returned must accomplish **ProblemDetails** data structure, with: + * status **404** + * title with message "Not Found" + * detail with message "Security context not found". + * cause with message "API Invoker has no security context". + + +## Test Case 17: Revoke the authorization of the API invoker for APIs without valid apfID. + +**Test ID**:: ***capif_security_api-17*** + +**Description**: + + This test case will check that an Invoker can't revoke the authorization for APIs + +**Pre-Conditions**: + + * API Invoker is pre-authorised (has valid apiInvokerID from CAPIF Authority) and Provider is also authorized + +**Information of Test**: + + 1. Perform [Provider Registration] and [Invoker Onboarding] + + 2. Create Security Context for this Invoker: + * Send PUT *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * body [service security body] + * Using Invoker Certificate. + + 3. Revoke Authorization by invoker: + * Send POST *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}/delete* + * body [security notification body] + * Using Invoker Certificate + + 4. Retrieve Security Context of Invoker by Provider: + * Send GET *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * Using Provider Certificate + +**Execution Steps**: + + 1. Register and onboard Invoker at CCF + 2. Register Provider at CCF + 3. Create Security Context + 4. Revoke Security Context by invoker + 5. Retrieve Security Context + +**Expected Result**: + + 1. Revoke Security Context by invoker: + 1. **401 Unauthorized** response. + 2. body returned must accomplish **ProblemDetails** data structure, with: + * status **401** + * title with message "Unauthorized" + * detail with message "Role not authorized for this API route". + * cause with message "User role must be provider". + + 3. Retrieve security context: + 1. **200 OK** response. + 2. body returned must accomplish **ServiceSecurity** data structure. + 1. Check is this returned object match with created one. + + +## Test Case 18: Revoke the authorization of the API invoker for APIs with invalid apiInvokerId. + +**Test ID**:: ***capif_security_api-18*** + +**Description**: + + This test case will check that an API Exposure Function cannot revoke the authorization for APIs for invalid apiInvokerId + +**Pre-Conditions**: + + * API Invoker is pre-authorised (has valid apiInvokerID from CAPIF Authority) and Provider is also authorized + +**Information of Test**: + + 1. Perform [Provider Registration] and [Invoker Onboarding] + + 2. Create Security Context for this Invoker: + * Send PUT *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * body [service security body] + * Using Invoker Certificate. + + 3. Revoke Authorization by Provider: + * Send POST *https://{CAPIF_HOSTNAME}/trustedInvokers/{API_INVOKER_NOT_VALID}/delete* + * body [security notification body] + * Using AEF Certificate. + + 4. Retrieve Security Context of Invoker by Provider: + * Send GET *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}?authenticationInfo=true&authorizationInfo=true* + * This request will ask with parameter to retrieve authenticationInfo and authorizationInfo + * Using AEF Certificate. + +**Execution Steps**: + + 1. Register and onboard Invoker at CCF + 2. Register Provider at CCF + 3. Create Security Context + 4. Revoke Security Context by Provider + 5. Retrieve Security Context + +**Expected Result**: + + 1. Revoke Security Context by invoker: + 1. **404 Not Found** response. + 2. body returned must accomplish **ProblemDetails** data structure, with: + * status **404** + * title with message "Not Found" + * detail with message "Invoker not found". + * cause with message "API Invoker not exists or invalid ID". + + 3. Retrieve security context: + 1. **200 OK** response. + 2. body returned must accomplish **ServiceSecurity** data structure. + 1. Check is this return one object that match with created one. + + +## Test Case 19: Retrieve access token + +**Test ID**:: ***capif_security_api-19*** + +**Description**: + + This test case will check that an API Invoker can retrieve a security access token OAuth 2.0. + +**Pre-Conditions**: + + * API Invoker is pre-authorised (has valid apiInvokerId) + * Service API of Provider is published + +**Information of Test**: + + 1. Perform [Provider Registration] and [Invoker Onboarding] + + 2. Publish Service API at CCF: + * Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis + * body [service api description] with apiName service_1 + * Use APF Certificate + + 3. Request Discover Published APIs not filtered: + * Send GET to ccf_discover_url *https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}* + * Param api-invoker-id is mandatory + * Using invoker certificate + + 4. Create Security Context for this Invoker + * Send PUT *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * body [service security body] + * Using Invoker Certificate. + * Create Security Information Body with one **securityInfo** for each aef present at each serviceAPIDescription present at Discover. + + 5. Request Access Token by invoker: + * Sent POST *https://{CAPIF_HOSTNAME}/securities/{securityId}/token*: + * body [access token req body] and example [example] + * ***securityId*** is apiInvokerId. + * ***grant_type=client_credentials***. + * Create Scope properly for request: ***3gpp#{aef_id}:{api_name}*** + * Using Invoker Certificate. + +**Execution Steps**: + + 1. Register Provider at CCF, store certificates and Publish Service API service_1 at CCF + 2. Register and onboard Invoker at CCF + 3. Discover Service APIs by Invoker. + 4. Create Security Context According to Service APIs discovered. + 5. Request Access Token + +**Expected Result**: + + 1. Response to Request of Access Token: + 1. **200 OK** + 2. body must follow **AccessTokenRsp** with: + 1. access_token present + 2. token_type=Bearer + +## Test Case 20: Retrieve access token by Provider + +**Test ID**:: ***capif_security_api-20*** + +**Description**: + + This test case will check that an API Exposure Function cannot revoke the authorization for APIs for invalid apiInvokerId + +**Pre-Conditions**: + + * API Invoker is pre-authorised (has valid apiInvokerID from CAPIF Authority) and Provider is also authorized + +**Information of Test**: + + 1. Perform [Provider Registration] and [Invoker Onboarding] + + 2. Publish Service API at CCF: + * Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis + * body [service api description] with apiName service_1 + * Use APF Certificate + + 3. Request Discover Published APIs not filtered: + * Send GET to ccf_discover_url *https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}* + * Param api-invoker-id is mandatory + * Using invoker certificate + + 4. Create Security Context for this Invoker + * Send PUT *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * body [service security body] + * Using Invoker Certificate. + * Create Security Information Body with one **securityInfo** for each aef present at each serviceAPIDescription present at Discover. + + 5. Request Access Token by provider: + * Sent POST *https://{CAPIF_HOSTNAME}/securities/{securityId}/token*: + * body [access token req body] + * ***securityId*** is apiInvokerId + * ***grant_type=client_credentials*** + * Using AEF certificate + +**Execution Steps**: + + 1. Register Provider at CCF, store certificates and Publish Service API service_1 at CCF + 2. Register and onboard Invoker at CCF + 3. Discover Service APIs by Invoker. + 4. Create Security Context According to Service APIs discovered. + 5. Request Access Token by Provider + +**Expected Result**: + + 1. Response to Request of Access Token: + 1. **401 Unauthorized** response. + 2. body returned must accomplish **AccessTokenErr** data structure, with: + * error unauthorized_client + * error_description=Role not authorized for this API route + +## Test Case 21: Retrieve access token by Provider with invalid apiInvokerId + +**Test ID**:: ***capif_security_api-21*** + +**Description**: + + This test case will check that an API Exposure Function cannot retrieve a security access token without valid apiInvokerId + +**Pre-Conditions**: + + * API Invoker is pre-authorised and Provider is also authorized + +**Information of Test**: + + 1. Perform [Provider Registration] and [Invoker Onboarding] + + 2. Publish Service API at CCF: + * Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis + * body [service api description] with apiName service_1 + * Use APF Certificate + + 3. Request Discover Published APIs not filtered: + * Send GET to ccf_discover_url *https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}* + * Param api-invoker-id is mandatory + * Using invoker certificate + + 4. Create Security Context for this Invoker + * Send PUT *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * body [service security body] + * Using Invoker Certificate. + * Create Security Information Body with one **securityInfo** for each aef present at each serviceAPIDescription present at Discover. + + 5. Request Access Token by provider: + * Sent POST *https://{CAPIF_HOSTNAME}/securities/{API_INVOKER_NOT_VALID}/token*. + * body [access token req body] + * ***securityId*** is apiInvokerId + * ***grant_type=client_credentials*** + * Using AEF certificate + +**Execution Steps**: + + 1. Register Provider at CCF, store certificates and Publish Service API service_1 at CCF + 2. Register and onboard Invoker at CCF + 3. Discover Service APIs by Invoker. + 4. Create Security Context According to Service APIs discovered. + 5. Request Access Token by Provider + +**Expected Result**: + + 1. Response to Request of Access Token: + 1. **401 Unauthorized** response. + 2. body returned must accomplish **AccessTokenErr** data structure, with: + * error unauthorized_client + * error_description=Role not authorized for this API route + + +## Test Case 22: Retrieve access token with invalid apiInvokerId + +**Test ID**:: ***capif_security_api-22*** + +**Description**: + + This test case will check that an API Invoker can't retrieve a security access token without valid apiInvokerId + +**Pre-Conditions**: + + * API Invoker is pre-authorised (has valid apiInvokerId) + +**Information of Test**: + + 1. Perform [Provider Registration] and [Invoker Onboarding] + 2. Publish Service API at CCF: + * Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis + * body [service api description] with apiName service_1 + * Use APF Certificate + 3. Request Discover Published APIs not filtered: + * Send GET to ccf_discover_url *https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}* + * Param api-invoker-id is mandatory + * Using invoker certificate + 4. Create Security Context for this Invoker + * Send PUT *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * body [service security body] + * Using Invoker Certificate. + * Create Security Information Body with one **securityInfo** for each aef present at each serviceAPIDescription present at Discover. + 5. Request Access Token by invoker: + * Sent POST *https://{CAPIF_HOSTNAME}/securities/{API_INVOKER_NOT_VALID}/token*. + * body [access token req body] + * ***securityId*** is apiInvokerId + * ***grant_type=client_credentials*** + * Using Invoker certificate + +**Execution Steps**: + + 1. Register Provider at CCF, store certificates and Publish Service API service_1 at CCF + 2. Register and onboard Invoker at CCF + 3. Discover Service APIs by Invoker. + 4. Create Security Context According to Service APIs discovered. + 5. Request Access Token by Invoker + +**Expected Result**: + + 1. Response to Request of Access Token: + 1. **404 Not Found** response. + 2. body returned must accomplish **ProblemDetails29571** data structure, with: + * status 404 + * title Not Found + * detail Security context not found + * cause API Invoker has no security context + + +**NOTE: ProblemDetails29571 is the definition present for this request at swagger of ProblemDetails, and this is different from definition of ProblemDetails across other CAPIF Services** + +## Test Case 23: Retrieve access token with invalid client_id + +**Test ID**:: ***capif_security_api-23*** + +**Description**: + + This test case will check that an API Exposure Function cannot retrieve a security access token without valid client_id at body + +**Pre-Conditions**: + + * API Invoker is pre-authorised and Provider is also authorized + +**Information of Test**: + + 1. Perform [Provider Registration] and [Invoker Onboarding] + + 2. Publish Service API at CCF: + * Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis + * body [service api description] with apiName service_1 + * Use APF Certificate + + 3. Request Discover Published APIs not filtered: + * Send GET to ccf_discover_url *https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}* + * Param api-invoker-id is mandatory + * Using invoker certificate + + 4. Create Security Context for this Invoker + * Send PUT *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * body [service security body] + * Using Invoker Certificate. + * Create Security Information Body with one **securityInfo** for each aef present at each serviceAPIDescription present at Discover. + + 5. Request Access Token by invoker: + * Sent POST *https://{CAPIF_HOSTNAME}/securities/{securityId}/token*. + * body [access token req body] + * ***securityId*** is apiInvokerId + * ***grant_type=client_credentials*** + * **client_id is not-valid** + * Using Invoker certificate + +**Execution Steps**: + + 1. Register Provider at CCF, store certificates and Publish Service API service_1 at CCF + 2. Register and onboard Invoker at CCF + 3. Discover Service APIs by Invoker. + 4. Create Security Context According to Service APIs discovered. + 5. Request Access Token by Invoker + +**Expected Result**: + + 1. Response to Request of Access Token: + 1. **400 Bad Request** response. + 2. body returned must accomplish **AccessTokenErr** data structure, with: + * error invalid_client + * error_description=Client Id not found + + +## Test Case 24: Retrieve access token with unsupported grant_type + +**Test ID**:: ***capif_security_api-24*** + +**Description**: + + This test case will check that an API Exposure Function cannot retrieve a security access token with unsupported grant_type + +**Pre-Conditions**: + + * API Invoker is pre-authorised and Provider is also authorized + +**Information of Test**: + + 1. Perform [Provider Registration] and [Invoker Onboarding] + + 2. Publish Service API at CCF: + * Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis + * body [service api description] with apiName service_1 + * Use APF Certificate + + 3. Request Discover Published APIs not filtered: + * Send GET to ccf_discover_url *https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}* + * Param api-invoker-id is mandatory + * Using invoker certificate + + 4. Create Security Context for this Invoker + * Send PUT *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * body [service security body] + * Using Invoker Certificate. + * Create Security Information Body with one **securityInfo** for each aef present at each serviceAPIDescription present at Discover. + + 5. Request Access Token by invoker: + * Sent POST *https://{CAPIF_HOSTNAME}/securities/{securityId}/token*. + * body [access token req body] + * ***securityId*** is apiInvokerId + * ***grant_type=not_valid*** + * Using Invoker certificate + +**Execution Steps**: + + 1. Register Provider at CCF, store certificates and Publish Service API service_1 at CCF + 2. Register and onboard Invoker at CCF + 3. Discover Service APIs by Invoker. + 4. Create Security Context According to Service APIs discovered. + 5. Request Access Token by Invoker + +**Expected Result**: + + 1. Response to Request of Access Token: + 1. **400 Bad Request** response. + 2. body returned must accomplish **AccessTokenErr** data structure, with: + * error unsupported_grant_type + * error_description=Invalid value for `grant_type` \\(${grant_type}\\), must be one of \\['client_credentials'\\] - 'grant_type' + +## Test Case 25: Retrieve access token with invalid scope + +**Test ID**:: ***capif_security_api-25*** + +**Description**: + + This test case will check that an API Exposure Function cannot retrieve a security access token with complete invalid scope + +**Pre-Conditions**: + + * API Invoker is pre-authorised and Provider is also authorized + +**Information of Test**: + + 1. Perform [Provider Registration] and [Invoker Onboarding] + + 2. Publish Service API at CCF: + * Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis + * body [service api description] with apiName service_1 + * Use APF Certificate + + 3. Request Discover Published APIs not filtered: + * Send GET to ccf_discover_url *https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}* + * Param api-invoker-id is mandatory + * Using invoker certificate + + 4. Create Security Context for this Invoker + * Send PUT *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * body [service security body] + * Using Invoker Certificate. + * Create Security Information Body with one **securityInfo** for each aef present at each serviceAPIDescription present at Discover. + + 5. Request Access Token by invoker: + * Sent POST *https://{CAPIF_HOSTNAME}/securities/{securityId}/token*. + * body [access token req body] + * ***securityId*** is apiInvokerId + * ***grant_type=client_credentials*** + * ***scope=not-valid-scope*** + * Using Invoker certificate + +**Execution Steps**: + + 1. Register Provider at CCF, store certificates and Publish Service API service_1 at CCF + 2. Register and onboard Invoker at CCF + 3. Discover Service APIs by Invoker. + 4. Create Security Context According to Service APIs discovered. + 5. Request Access Token by Invoker + +**Expected Result**: + + 1. Response to Request of Access Token: + 1. **400 Bad Request** response. + 2. body returned must accomplish **AccessTokenErr** data structure, with: + * error invalid_scope + * error_description=The first characters must be '3gpp' + + +## Test Case 26: Retrieve access token with invalid aefid at scope + +**Test ID**:: ***capif_security_api-26*** + +**Description**: + + This test case will check that an API Exposure Function cannot retrieve a security access token with invalid aefId at scope + +**Pre-Conditions**: + + * API Invoker is pre-authorised and Provider is also authorized + +**Information of Test**: + + 1. Perform [Provider Registration] and [Invoker Onboarding] + + 2. Publish Service API at CCF: + * Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis + * body [service api description] with apiName service_1 + * Use APF Certificate + + 3. Request Discover Published APIs not filtered: + * Send GET to ccf_discover_url *https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}* + * Param api-invoker-id is mandatory + * Using invoker certificate + + 4. Create Security Context for this Invoker + * Send PUT *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * body [service security body] + * Using Invoker Certificate. + * Create Security Information Body with one **securityInfo** for each aef present at each serviceAPIDescription present at Discover. + + 5. Request Access Token by invoker: + * Sent POST *https://{CAPIF_HOSTNAME}/securities/{securityId}/token*. + * body [access token req body] + * ***securityId*** is apiInvokerId + * ***grant_type=client_credentials*** + * ***scope=3gpp#1234:service_1*** + * Using Invoker certificate + +**Execution Steps**: + + 1. Register Provider at CCF, store certificates and Publish Service API service_1 at CCF + 2. Register and onboard Invoker at CCF + 3. Discover Service APIs by Invoker. + 4. Create Security Context According to Service APIs discovered. + 5. Request Access Token by Invoker + +**Expected Result**: + + 1. Response to Request of Access Token: + 1. **400 Bad Request** response. + 2. body returned must accomplish **AccessTokenErr** data structure, with: + * error invalid_scope + * error_description=One of aef_id not belongs of your security context + + +## Test Case 27: Retrieve access token with invalid apiName at scope + +**Test ID**:: ***capif_security_api-27*** + +**Description**: + + This test case will check that an API Exposure Function cannot retrieve a security access token with invalid apiName at scope + +**Pre-Conditions**: + + * API Invoker is pre-authorised and Provider is also authorized + +**Information of Test**: + + 1. Perform [Provider Registration] and [Invoker Onboarding] + + 2. Publish Service API at CCF: + * Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis + * body [service api description] with apiName service_1 + * Use APF Certificate + + 3. Request Discover Published APIs not filtered: + * Send GET to ccf_discover_url *https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}* + * Param api-invoker-id is mandatory + * Using invoker certificate + + 4. Create Security Context for this Invoker + * Send PUT *https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}* + * body [service security body] + * Using Invoker Certificate. + * Create Security Information Body with one **securityInfo** for each aef present at each serviceAPIDescription present at Discover. + + 5. Request Access Token by invoker: + * Sent POST *https://{CAPIF_HOSTNAME}/securities/{securityId}/token*. + * body [access token req body] + * ***securityId*** is apiInvokerId + * ***grant_type=client_credentials*** + * ***scope=3gpp#{aef_id}:not-valid*** + * Using Invoker certificate + +**Execution Steps**: + + 1. Register Provider at CCF, store certificates and Publish Service API service_1 at CCF + 2. Register and onboard Invoker at CCF + 3. Discover Service APIs by Invoker. + 4. Create Security Context According to Service APIs discovered. + 5. Request Access Token by Invoker + +**Expected Result**: + + 1. Response to Request of Access Token: + 1. **400 Bad Request** response. + 2. body returned must accomplish **AccessTokenErr** data structure, with: + * error invalid_scope + * error_description=One of the api names does not exist or is not associated with the aef id provided + + + [Return To All Test Plans]: ../README.md + + + + [service security body]: ./service_security.json "Service Security Request" + [security notification body]: ./security_notification.json "Security Notification Request" + [access token req body]: ./access_token_req.json "Access Token Request" + [example]: ./access_token_req.json "Access Token Request Example" + + [invoker onboarding]: ../common_operations/README.md#register-an-invoker "Invoker Onboarding" + [provider registration]: ../common_operations/README.md#register-a-provider "Provider Registration" + + diff --git a/doc/testing/testplan/api_security_service/access_token_req.json b/doc/testing/testplan/api_security_service/access_token_req.json new file mode 100644 index 0000000000000000000000000000000000000000..8504736e1fb40d49c3bcb4c6a8bca4dbb6d9f855 --- /dev/null +++ b/doc/testing/testplan/api_security_service/access_token_req.json @@ -0,0 +1,6 @@ +{ + "client_id": "client_id", + "client_secret": "client_secret", + "grant_type": "client_credentials", + "scope": "scope" +} \ No newline at end of file diff --git a/doc/testing/testplan/api_security_service/access_token_req_example.json b/doc/testing/testplan/api_security_service/access_token_req_example.json new file mode 100644 index 0000000000000000000000000000000000000000..070a717db975b76a80792117b50957ce4267cf6b --- /dev/null +++ b/doc/testing/testplan/api_security_service/access_token_req_example.json @@ -0,0 +1,5 @@ +{ + "client_id": "bb260b4d0b3a0f954fa23f42d979ca", + "grant_type": "client_credentials", + "scope": "3gpp#af7e4cf70063814770e7b00b87273e:service_1" +} diff --git a/doc/testing/testplan/api_security_service/security_notification.json b/doc/testing/testplan/api_security_service/security_notification.json new file mode 100644 index 0000000000000000000000000000000000000000..6b94eb5497ed8b6bde547dda6a4abc71783bc998 --- /dev/null +++ b/doc/testing/testplan/api_security_service/security_notification.json @@ -0,0 +1,9 @@ +{ + "aefId": "aefId", + "apiIds": [ + "apiIds", + "apiIds" + ], + "apiInvokerId": "api_invoker_id", + "cause": "OVERLIMIT_USAGE" +} \ No newline at end of file diff --git a/doc/testing/testplan/api_security_service/service_security.json b/doc/testing/testplan/api_security_service/service_security.json new file mode 100644 index 0000000000000000000000000000000000000000..ad7bc1ad5c64f6dc979a294044b5b44f5f43c68a --- /dev/null +++ b/doc/testing/testplan/api_security_service/service_security.json @@ -0,0 +1,25 @@ +{ + "notificationDestination": "http://robot.testing", + "supportedFeatures": "fffffff", + "securityInfo": [{ + "authenticationInfo": "authenticationInfo", + "authorizationInfo": "authorizationInfo", + "interfaceDetails": { + "ipv4Addr": "127.0.0.1", + "securityMethods": ["PSK"], + "port": 5248 + }, + "prefSecurityMethods": ["PSK", "PKI", "OAUTH"], + }, + { + "authenticationInfo": "authenticationInfo", + "authorizationInfo": "authorizationInfo", + "prefSecurityMethods": ["PSK", "PKI", "OAUTH"], + "aefId": "aefId" + }], + "websockNotifConfig": { + "requestWebsocketUri": true, + "websocketUri": "websocketUri" + }, + "requestTestNotification": true +} diff --git a/doc/testing/testplan/common_operations/README.md b/doc/testing/testplan/common_operations/README.md new file mode 100644 index 0000000000000000000000000000000000000000..e75570791e791a22caca495c280d9f5f539d4743 --- /dev/null +++ b/doc/testing/testplan/common_operations/README.md @@ -0,0 +1,87 @@ +# Common Operations + +## Register an Invoker + +### Steps to perform operation + 1. Create public and private key at invoker + 2. Register of Invoker at CCF: + * Send POST to http://{CAPIF_HOSTNAME}:{CAPIF_HTTP_PORT}/register + * Body [invoker register body] + + 3. Obtain Access Token: + * Send POST to *http://{CAPIF_HOSTNAME}/getauth* + * Body [invoker getauth body] + + 4. Onboard Invoker: + * Send POST to https://{CAPIF_HOSTNAME}/api-invoker-management/v1/onboardedInvokers + * Reference Request Body: [invoker onboarding body] + * "onboardingInformation"->"apiInvokerPublicKey": must contain public key generated by Invoker. + * Send at Authorization Header the Bearer access_token obtained previously (Authorization:Bearer ${access_token}) + +### Checks to ensure onboarding + 1. Response to Register: + 1. **201 Created** + + 2. Response to Get Auth: + 1. **200 OK** + 2. ***access_token*** returned. + + 3. Response to Onboard request must accomplish: + 1. **201 Created** + 2. Response Body must follow **APIInvokerEnrolmentDetails** data structure with: + * apiInvokerId + * onboardingInformation->apiInvokerCertificate must contain the public key signed. + 3. Response Header **Location** must be received with URI to new resource created, following this structure: *{apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}* + + +## Register a Provider + +### Steps to Perform operation + 1. Create public and private key at provider for provider itself and each function (apf, aef and amf) + 2. Register of Provider at CCF: + * Send POST to *http://{CAPIF_HOSTNAME}:{CAPIF_HTTP_PORT}/register* + * body [provider register body] + + 3. Obtain Access Token: + * Send POST to *http://{CAPIF_HOSTNAME}/getauth* + * Body [provider getauth body] + + 4. Register Provider: + * Send POST *https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations* + * body [provider request body] + * Send at Authorization Header the Bearer access_token obtained previously (Authorization:Bearer ${access_token}) + * Store each cert in a file with according name. + +### Checks to ensure provider registration + 1. Response to Register: + 1. **201 Created** + + 2. Response to Get Auth: + 1. **200 OK** + 2. ***access_token*** returned. + + 3. Register Provider at Provider Management: + 1. **201 Created** response. + 2. body returned must accomplish **APIProviderEnrolmentDetails** data structure. + 3. For each **apiProvFuncs**, we must check: + 1. **apiProvFuncId** is set + 2. **apiProvCert** under **regInfo** is set properly + 4. Location Header must contain the new resource URL *{apiRoot}/api-provider-management/v1/registrations/{registrationId}* + + + + + +[invoker register body]: ../api_invoker_management/invoker_register_body.json "Invoker Register Body" +[invoker onboarding body]: ../api_invoker_management/invoker_details_post_example.json "API Invoker Request" +[invoker getauth body]: ../api_invoker_management/invoker_getauth_example.json "Get Auth Example" + +[provider register body]: ../api_provider_management/provider_register_body.json "Provider Register Body" +[provider request body]: ../api_provider_management/provider_details_post_example.json "API Provider Enrolment Request" +[provider getauth body]: ../api_provider_management/provider_getauth_example.json "Get Auth Example" + + + + + +[Return To All Test Plans]: ../README.md diff --git a/mkdocs.yml b/mkdocs.yml index 5e12033d727fcf1306352164333280a983e21d8a..b92927659f5578f2f9235b0f7ff0bcdb44b84224 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -71,15 +71,11 @@ extra: nav: - Overview: - Introduction: index.md - - Design & Architecture: - - Architecture: ./architecture/architecture.md - Getting Started: - - How to Run Locally: ./gettingstarted/howto.md + - How to Run: ./gettingstarted/howtorun.md - Deployment/Installation: ./gettingstarted/deployment.md - Testing: - - Testing: ./gettingstarted/testing.md - - Test Plan: ./gettingstarted/testplan.md - - Robot Framwork: ./gettingstarted/robotframwork.md - - Postman: ./gettingstarted/postman.md - - Contributing: - - Developing: ./contributing/developing.md + - Test Plan: ./testing/testplan/README.md + - Robot Framework: ./testing/robotframework/README.md + - Postman: ./testing/postman/README.md + - FAQ: ./FAQ.md