From 332a771fac9f65975d5b30d7a487b89a3911eeb5 Mon Sep 17 00:00:00 2001
From: Jorge <jorge.moratinossalcines@telefonica.com>
Date: Tue, 26 Mar 2024 08:30:00 +0000
Subject: [PATCH] Deployed f7ecca3 to 0.0 in public with MkDocs 1.5.3 and mike
 2.0.0

---
 public/0.0/404.html                           |   8 +--
 public/0.0/FAQ/index.html                     |   8 +--
 public/0.0/gettingstarted/howtorun/index.html |  26 +++++-----
 .../0.0/gettingstarted/repository/index.html  |   8 +--
 .../Open CAPIF Logo Screen_B_W Slogan NEG.png | Bin 0 -> 22786 bytes
 ...CAPIF Logo Screen_Colour Slogan NEG@3x.png | Bin 0 -> 93037 bytes
 public/0.0/index.html                         |  48 ++++++++----------
 public/0.0/search/search_index.json           |   2 +-
 public/0.0/sitemap.xml                        |  34 ++++++-------
 public/0.0/sitemap.xml.gz                     | Bin 376 -> 376 bytes
 public/0.0/stylesheets/extra.css              |  24 +++++++++
 public/0.0/testing/postman/index.html         |   8 +--
 public/0.0/testing/robotframework/index.html  |   8 +--
 .../api_access_control_policy/index.html      |   8 +--
 .../testplan/api_auditing_service/index.html  |   8 +--
 .../testplan/api_discover_service/index.html  |   8 +--
 .../testplan/api_events_service/index.html    |   8 +--
 .../api_invoker_management/index.html         |   8 +--
 .../testplan/api_logging_service/index.html   |   8 +--
 .../api_provider_management/index.html        |   8 +--
 .../testplan/api_publish_service/index.html   |   8 +--
 .../testplan/api_security_service/index.html  |   8 +--
 .../testplan/common_operations/index.html     |   8 +--
 public/0.0/testing/testplan/index.html        |   8 +--
 24 files changed, 157 insertions(+), 105 deletions(-)
 create mode 100644 public/0.0/images/logos/Open CAPIF Logo Screen_B_W Slogan NEG.png
 create mode 100644 public/0.0/images/logos/Open CAPIF Logo Screen_Colour Slogan NEG@3x.png
 create mode 100644 public/0.0/stylesheets/extra.css

diff --git a/public/0.0/404.html b/public/0.0/404.html
index 2bf8118b..d350c3f3 100644
--- a/public/0.0/404.html
+++ b/public/0.0/404.html
@@ -46,6 +46,8 @@
       
     
     
+      <link rel="stylesheet" href="/0.0/stylesheets/extra.css">
+    
     <script>__md_scope=new URL("/0.0",location),__md_hash=e=>[...e].reduce((e,_)=>(e<<5)-e+_.charCodeAt(0),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
     
       
@@ -61,7 +63,7 @@
     
     
     
-    <body dir="ltr" data-md-color-scheme="default" data-md-color-primary="cyan" data-md-color-accent="blue">
+    <body dir="ltr" data-md-color-scheme="default" data-md-color-primary="custom" data-md-color-accent="custom">
   
     
     <input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
@@ -87,7 +89,7 @@
   <nav class="md-header__inner md-grid" aria-label="Header">
     <a href="/0.0/." title="ETSI SDG OCF Documentation" class="md-header__button md-logo" aria-label="ETSI SDG OCF Documentation" data-md-component="logo">
       
-  <img src="/0.0/images/logos/OpenCAPIF.png" alt="logo">
+  <img src="/0.0/images/logos/Open CAPIF Logo Screen_B_W Slogan NEG.png" alt="logo">
 
     </a>
     <label class="md-header__button md-icon" for="__drawer">
@@ -193,7 +195,7 @@
   <label class="md-nav__title" for="__drawer">
     <a href="/0.0/." title="ETSI SDG OCF Documentation" class="md-nav__button md-logo" aria-label="ETSI SDG OCF Documentation" data-md-component="logo">
       
-  <img src="/0.0/images/logos/OpenCAPIF.png" alt="logo">
+  <img src="/0.0/images/logos/Open CAPIF Logo Screen_B_W Slogan NEG.png" alt="logo">
 
     </a>
     ETSI SDG OCF Documentation
diff --git a/public/0.0/FAQ/index.html b/public/0.0/FAQ/index.html
index f9d3d29c..d2dff4f1 100644
--- a/public/0.0/FAQ/index.html
+++ b/public/0.0/FAQ/index.html
@@ -50,6 +50,8 @@
       
     
     
+      <link rel="stylesheet" href="../stylesheets/extra.css">
+    
     <script>__md_scope=new URL("..",location),__md_hash=e=>[...e].reduce((e,_)=>(e<<5)-e+_.charCodeAt(0),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
     
       
@@ -65,7 +67,7 @@
     
     
     
-    <body dir="ltr" data-md-color-scheme="default" data-md-color-primary="cyan" data-md-color-accent="blue">
+    <body dir="ltr" data-md-color-scheme="default" data-md-color-primary="custom" data-md-color-accent="custom">
   
     
     <input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
@@ -96,7 +98,7 @@
   <nav class="md-header__inner md-grid" aria-label="Header">
     <a href=".." title="ETSI SDG OCF Documentation" class="md-header__button md-logo" aria-label="ETSI SDG OCF Documentation" data-md-component="logo">
       
-  <img src="../images/logos/OpenCAPIF.png" alt="logo">
+  <img src="../images/logos/Open CAPIF Logo Screen_B_W Slogan NEG.png" alt="logo">
 
     </a>
     <label class="md-header__button md-icon" for="__drawer">
@@ -202,7 +204,7 @@
   <label class="md-nav__title" for="__drawer">
     <a href=".." title="ETSI SDG OCF Documentation" class="md-nav__button md-logo" aria-label="ETSI SDG OCF Documentation" data-md-component="logo">
       
-  <img src="../images/logos/OpenCAPIF.png" alt="logo">
+  <img src="../images/logos/Open CAPIF Logo Screen_B_W Slogan NEG.png" alt="logo">
 
     </a>
     ETSI SDG OCF Documentation
diff --git a/public/0.0/gettingstarted/howtorun/index.html b/public/0.0/gettingstarted/howtorun/index.html
index 6d19d32a..f5c7ad02 100644
--- a/public/0.0/gettingstarted/howtorun/index.html
+++ b/public/0.0/gettingstarted/howtorun/index.html
@@ -52,6 +52,8 @@
       
     
     
+      <link rel="stylesheet" href="../../stylesheets/extra.css">
+    
     <script>__md_scope=new URL("../..",location),__md_hash=e=>[...e].reduce((e,_)=>(e<<5)-e+_.charCodeAt(0),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
     
       
@@ -67,7 +69,7 @@
     
     
     
-    <body dir="ltr" data-md-color-scheme="default" data-md-color-primary="cyan" data-md-color-accent="blue">
+    <body dir="ltr" data-md-color-scheme="default" data-md-color-primary="custom" data-md-color-accent="custom">
   
     
     <input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
@@ -98,7 +100,7 @@
   <nav class="md-header__inner md-grid" aria-label="Header">
     <a href="../.." title="ETSI SDG OCF Documentation" class="md-header__button md-logo" aria-label="ETSI SDG OCF Documentation" data-md-component="logo">
       
-  <img src="../../images/logos/OpenCAPIF.png" alt="logo">
+  <img src="../../images/logos/Open CAPIF Logo Screen_B_W Slogan NEG.png" alt="logo">
 
     </a>
     <label class="md-header__button md-icon" for="__drawer">
@@ -204,7 +206,7 @@
   <label class="md-nav__title" for="__drawer">
     <a href="../.." title="ETSI SDG OCF Documentation" class="md-nav__button md-logo" aria-label="ETSI SDG OCF Documentation" data-md-component="logo">
       
-  <img src="../../images/logos/OpenCAPIF.png" alt="logo">
+  <img src="../../images/logos/Open CAPIF Logo Screen_B_W Slogan NEG.png" alt="logo">
 
     </a>
     ETSI SDG OCF Documentation
@@ -634,8 +636,8 @@
 </ul>
 <p>Capif services are developed under <a href="https://labs.etsi.org/rep/ocf/capif/-/tree/main/services">services folder</a>.</p>
 <h3 id="run-all-capif-services-locally-with-docker-images">Run All CAPIF Services locally with Docker images</h3>
-<p>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.</p>
-<p>All script are present under <strong><em>services</em></strong> directory.</p>
+<p>To run using docker and docker compose, version 2.10 or higher, you must ensure you have those tools installed in your machine. Also to simplify the process, we have 3 scripts allowing docker images to deploy, check and cleanup.</p>
+<p>All these scripts are available under <strong><em>services</em></strong> directory.</p>
 <p>To run CAPIF APIs locally using docker and docker-compose you can use run.sh script:</p>
 <pre><code>./run.sh -h
 
@@ -644,7 +646,7 @@ Usage: ./run.sh &lt;options&gt;
        -m : Clean monitoring service
        -h : show this help
 </code></pre>
-<p>This script build and run all services using docker images, including mongodb and nginx locally and in background, and import ca.crt to nginx. By default monitoring is not activated and Nginx deployed use <strong>capifcore</strong> as a hostname. </p>
+<p>This script builds and runs all services using docker images, including mongodb and nginx locally and in the background, and imports ca.crt to nginx. By default monitoring is not activated and Nginx is deployed use <strong>capifcore</strong> as a hostname. </p>
 <p>Some examples of use:</p>
 <pre><code># Default values, No monitoring and capifcore as CAPIF_HOSTNAME
 ./run.sh
@@ -656,14 +658,14 @@ Usage: ./run.sh &lt;options&gt;
 ./run.sh -c opencapif.etsi.org -m true 
 
 </code></pre>
-<p>If you want to check if all CAPIF services are running properly in local machine after execute run.sh, we can use:</p>
+<p>If you want to check if all CAPIF services are running properly in a local machine after executing run.sh, you can use:</p>
 <pre><code>./check_services_are_running.sh
 </code></pre>
 <p>This shell script will return 0 if all services are running properly.</p>
 <p>When we need to stop all CAPIF services, we can use next bash script:</p>
 <pre><code>./clean_capif_docker_services.sh -a
 </code></pre>
-<p>NOTE: You can use different flags if you only want to stop some of them, please check help using</p>
+<p>NOTE: You can use different flags if you only want to stop some of them, please check the help using</p>
 <pre><code>./clean_capif_docker_services.sh -h
 
 Usage: clean_capif_docker_services.sh &lt;options&gt;
@@ -677,7 +679,7 @@ Usage: clean_capif_docker_services.sh &lt;options&gt;
 <p>This shell script will remove and clean all CAPIF services started previously with run.sh</p>
 <p>On the other hand you can check logs using show_logs.sh script, please check options:</p>
 <pre><code>./show_logs.sh
-You must specify an option before run script.
+You must specify an option when running the script.
 Usage: ./show_logs.sh &lt;options&gt;
        -c : Show capif services
        -v : Show vault service
@@ -687,7 +689,7 @@ Usage: ./show_logs.sh &lt;options&gt;
        -f : Follow log output
        -h : Show this help
 </code></pre>
-<p>You can also use option -f in order to live follow log output</p>
+<p>You can also use option -f in order to follow log output in real time</p>
 <h3 id="run-all-capif-services-locally-with-docker-images-and-deploy-monitoring-stack">Run All CAPIF Services locally with Docker images and deploy monitoring stack</h3>
 <p>It is now possible to deploy a monitoring stack for CAPIF with Grafana, Prometheus, FluentBit, Loki, Cadvisor, Tempo and Opentelemetry.</p>
 <p>To deploy CAPIF together with the monitoring stack, it is only necessary to execute the following.</p>
@@ -696,9 +698,9 @@ Usage: ./show_logs.sh &lt;options&gt;
 <p>After they have been built, the different panels can be consulted in Grafana at the url</p>
 <pre><code>http://localhost:3000
 </code></pre>
-<p>By default, the monitoring option is set to false. Once up, all data sources and dashboards are automatically provisioned</p>
+<p>By default, the monitoring option is set to false. Once up, all data sources and dashboards are automatically provisioned.</p>
 <h3 id="run-each-service-using-docker">Run each service using Docker</h3>
-<p>Also you can run service by service using docker:</p>
+<p>Also you can run OpenCAPIF service by service using docker:</p>
 <pre><code>cd &lt;Service&gt;
 docker build -t capif_security .
 docker run -p 8080:8080 capif_security
diff --git a/public/0.0/gettingstarted/repository/index.html b/public/0.0/gettingstarted/repository/index.html
index 63d2888f..fcc95d99 100644
--- a/public/0.0/gettingstarted/repository/index.html
+++ b/public/0.0/gettingstarted/repository/index.html
@@ -48,6 +48,8 @@
       
     
     
+      <link rel="stylesheet" href="../../stylesheets/extra.css">
+    
     <script>__md_scope=new URL("../..",location),__md_hash=e=>[...e].reduce((e,_)=>(e<<5)-e+_.charCodeAt(0),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
     
       
@@ -63,7 +65,7 @@
     
     
     
-    <body dir="ltr" data-md-color-scheme="default" data-md-color-primary="cyan" data-md-color-accent="blue">
+    <body dir="ltr" data-md-color-scheme="default" data-md-color-primary="custom" data-md-color-accent="custom">
   
     
     <input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
@@ -89,7 +91,7 @@
   <nav class="md-header__inner md-grid" aria-label="Header">
     <a href="../.." title="ETSI SDG OCF Documentation" class="md-header__button md-logo" aria-label="ETSI SDG OCF Documentation" data-md-component="logo">
       
-  <img src="../../images/logos/OpenCAPIF.png" alt="logo">
+  <img src="../../images/logos/Open CAPIF Logo Screen_B_W Slogan NEG.png" alt="logo">
 
     </a>
     <label class="md-header__button md-icon" for="__drawer">
@@ -195,7 +197,7 @@
   <label class="md-nav__title" for="__drawer">
     <a href="../.." title="ETSI SDG OCF Documentation" class="md-nav__button md-logo" aria-label="ETSI SDG OCF Documentation" data-md-component="logo">
       
-  <img src="../../images/logos/OpenCAPIF.png" alt="logo">
+  <img src="../../images/logos/Open CAPIF Logo Screen_B_W Slogan NEG.png" alt="logo">
 
     </a>
     ETSI SDG OCF Documentation
diff --git a/public/0.0/images/logos/Open CAPIF Logo Screen_B_W Slogan NEG.png b/public/0.0/images/logos/Open CAPIF Logo Screen_B_W Slogan NEG.png
new file mode 100644
index 0000000000000000000000000000000000000000..d0061b6f859094be2b4c4d9e73047ebbe2524e98
GIT binary patch
literal 22786
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

literal 0
HcmV?d00001

diff --git a/public/0.0/images/logos/Open CAPIF Logo Screen_Colour Slogan NEG@3x.png b/public/0.0/images/logos/Open CAPIF Logo Screen_Colour Slogan NEG@3x.png
new file mode 100644
index 0000000000000000000000000000000000000000..06f34e564036a3bff31f3e85311ca144d2346d2b
GIT binary patch
literal 93037
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
LD2Nw}8u<MmF~4t6

literal 0
HcmV?d00001

diff --git a/public/0.0/index.html b/public/0.0/index.html
index 4505c802..537c3a1c 100644
--- a/public/0.0/index.html
+++ b/public/0.0/index.html
@@ -50,6 +50,8 @@
       
     
     
+      <link rel="stylesheet" href="stylesheets/extra.css">
+    
     <script>__md_scope=new URL(".",location),__md_hash=e=>[...e].reduce((e,_)=>(e<<5)-e+_.charCodeAt(0),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
     
       
@@ -65,7 +67,7 @@
     
     
     
-    <body dir="ltr" data-md-color-scheme="default" data-md-color-primary="cyan" data-md-color-accent="blue">
+    <body dir="ltr" data-md-color-scheme="default" data-md-color-primary="custom" data-md-color-accent="custom">
   
     
     <input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
@@ -96,7 +98,7 @@
   <nav class="md-header__inner md-grid" aria-label="Header">
     <a href="." title="ETSI SDG OCF Documentation" class="md-header__button md-logo" aria-label="ETSI SDG OCF Documentation" data-md-component="logo">
       
-  <img src="images/logos/OpenCAPIF.png" alt="logo">
+  <img src="images/logos/Open CAPIF Logo Screen_B_W Slogan NEG.png" alt="logo">
 
     </a>
     <label class="md-header__button md-icon" for="__drawer">
@@ -202,7 +204,7 @@
   <label class="md-nav__title" for="__drawer">
     <a href="." title="ETSI SDG OCF Documentation" class="md-nav__button md-logo" aria-label="ETSI SDG OCF Documentation" data-md-component="logo">
       
-  <img src="images/logos/OpenCAPIF.png" alt="logo">
+  <img src="images/logos/Open CAPIF Logo Screen_B_W Slogan NEG.png" alt="logo">
 
     </a>
     ETSI SDG OCF Documentation
@@ -756,7 +758,7 @@
 
 <p><img src="images/logos/OpenCAPIF.png" alt="drawing" width="200"/></p>
 <h1 id="release-00">Release 0.0</h1>
-<p>The APIs included in release 0.0 are:</p>
+<p>The APIs included in Release 0.0 are:</p>
 <ul>
 <li>JWT Authentication APIs</li>
 <li>CAPIF Invoker Management API</li>
@@ -766,15 +768,14 @@
 <li>CAPIF Events API</li>
 <li>CAPIF Provider Management API</li>
 </ul>
-<p>Testing Suite of all services with robot.
-Also Postman suite to a simple test.</p>
+<p>This Release also includes a Robot Test Suite for all those services and a Postman Test Suite for simple testing.</p>
 <h2 id="what-is-opencapif">What is OpenCAPIF?</h2>
 <p>CAPIF is the “Common API Framework” defined by 3GPP to manage the APIs exposed by 3GPP networks in their northbound interfaces.</p>
 <p>CAPIF defines three types of entities:</p>
 <ul>
 <li>API Providers, which are the entities exposing APIs (e.g., NEF)</li>
 <li>API Invokers, which are the entities that consume APIs (e.g., Applications), and</li>
-<li>the CAPIF Core Function, that manages the relationships between the other two.</li>
+<li>the CAPIF Core Function, which manages the relationships between the other two.</li>
 </ul>
 <p><img alt="CAPIF Core Function" src="images/architecture/CAPIF_Core_Function.png" title="CAPIF Core Function" /></p>
 <p>The CAPIF Core Function is the cornerstone of the Common API Framework and provides the following capabilities:</p>
@@ -789,8 +790,8 @@ Also Postman suite to a simple test.</p>
 <li>Monitoring the service API invocations;</li>
 <li>Onboarding a new API Invoker and offboarding an API Invoker;</li>
 <li>Storing policy configurations related to CAPIF and service APIs;</li>
-<li>Support accessing the logs for auditing (e.g., detecting abuse); and</li>
-<li>Support publishing and discovery of service APIs information among CAPIF Core Function (CAPIF interconnection).</li>
+<li>Support for accessing the logs for auditing (e.g., detecting abuse); and</li>
+<li>Support for publishing and discovery of service APIs information among CAPIF Core Function (CAPIF interconnection).</li>
 </ul>
 <p>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.</p>
 <p><img alt="Flow" src="images/architecture/msg_flow.png" title="Flow" /></p>
@@ -798,9 +799,8 @@ Also Postman suite to a simple test.</p>
 <h2 id="repository-structure">Repository structure</h2>
 <p>You can check the code at <a href="https://labs.etsi.org/rep/ocf/capif" title="OpenCAPIF Repository">OpenCAPIF Repository</a></p>
 <pre><code>CAPIF_API_Services
-└───docs
-│    └───test_plan
-│    └───testing_with_postman
+└───helm
+└───monitoring
 └───services
 └───tests
 └───tools
@@ -808,31 +808,25 @@ Also Postman suite to a simple test.</p>
     └───open_api_script
 </code></pre>
 <ul>
+<li><strong>helm</strong>: This folder contains helm files to deploy capif under k8s environment.</li>
+<li><strong>monitoring</strong>: This folder contains grafana helm files to deploy capif under k8s environment.</li>
 <li><strong>services</strong>: Services developed following CAPIF API specifications. Also, other complementary services (e.g., NGINX and JWTauth services for the authentication of API consuming entities).</li>
 <li><strong>tools</strong>: Auxiliary tools. Robot Framework related code and OpenAPI scripts.</li>
-<li>
-<p><strong>test</strong>: Tests developed using Robot Framework.</p>
-</li>
-<li>
-<p><strong>docs</strong>: Documents related to the code in the repository.</p>
-</li>
-<li>images: images used in the repository</li>
-<li>test_plan: test plan descriptions for each API service referring to the test that are executed with the Robot Framework.</li>
-<li>testing_with_postman: auxiliary JSON file needed for the Postman-based examples.</li>
+<li><strong>test</strong>: Tests developed using Robot Framework.</li>
 </ul>
 <h2 id="capif_api_services">CAPIF_API_Services</h2>
 <p>This repository has the python-flask Mockup servers created with openapi-generator related with CAPIF APIS defined here:
 <a href="https://forge.3gpp.org/rep/all/5G_APIs" title="Open API Descriptions of 3GPP 5G APIs">Open API Descriptions of 3GPP 5G APIs</a></p>
 <h2 id="how-to-test-capif-apis">How to test CAPIF APIs</h2>
-<p>The above APIs can be tested either with POSTMAN tool or running developed tests with Robot Framework.</p>
+<p>The above APIs can be tested either with POSTMAN tool or running the developed tests with Robot Framework.</p>
 <h2 id="test-plan-documentation">Test Plan Documentation</h2>
-<p>Complete documentation of tests is here: <a href="testing/testplan/" title="Test Plan Directory">Test Plan Directory</a></p>
+<p>Complete documentation of tests is available here: <a href="testing/testplan/" title="Test Plan Directory">Test Plan Directory</a></p>
 <h2 id="robot-framework">Robot Framework</h2>
-<p>In order to ensure modifications over CAPIF services still accomplish the required functionality, Robot Framework test suite must be success.</p>
-<p>Test suite implemented accomplish requirements described under test plan at <a href="testing/testplan/" title="Test Plan Directory">Test Plan Directory</a> folder.</p>
-<p>Please go to <a href="testing/robotframework/" title="Testing with Robot Framework">Testing with Robot Framework</a> Section</p>
+<p>In order to ensure that modifications over CAPIF services still fulfills the required functionality, the Robot Framework Test Suite must be successfully run.</p>
+<p>The Robot Test Suite covers the requirements described in the test plan at <a href="testing/testplan/" title="Test Plan Directory">Test Plan Directory</a> folder.</p>
+<p>Please check the <a href="testing/robotframework/" title="Testing with Robot Framework">Testing with Robot Framework</a> Section</p>
 <h2 id="using-postman">Using PostMan</h2>
-<p>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.</p>
+<p>You can also 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.</p>
 <p>For more information on how to test the APIs with POSTMAN, go to this <a href="testing/postman/" title="POSTMAN Section">POSTMAN Section</a>.</p>
 <h2 id="important-urls">Important urls:</h2>
 <h2 id="mongo-capifs-db-dashboard">Mongo CAPIF's DB Dashboard</h2>
diff --git a/public/0.0/search/search_index.json b/public/0.0/search/search_index.json
index 1f2aff5c..c7e7b7b8 100644
--- a/public/0.0/search/search_index.json
+++ b/public/0.0/search/search_index.json
@@ -1 +1 @@
-{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Introduction","text":""},{"location":"#release-00","title":"Release 0.0","text":"<p>The APIs included in release 0.0 are:</p> <ul> <li>JWT Authentication APIs</li> <li>CAPIF Invoker Management API</li> <li>CAPIF Publish API</li> <li>CAPIF Discover API</li> <li>CAPIF Security API</li> <li>CAPIF Events API</li> <li>CAPIF Provider Management API</li> </ul> <p>Testing Suite of all services with robot. Also Postman suite to a simple test.</p>"},{"location":"#what-is-opencapif","title":"What is OpenCAPIF?","text":"<p>CAPIF is the \u201cCommon API Framework\u201d defined by 3GPP to manage the APIs exposed by 3GPP networks in their northbound interfaces.</p> <p>CAPIF defines three types of entities:</p> <ul> <li>API Providers, which are the entities exposing APIs (e.g., NEF)</li> <li>API Invokers, which are the entities that consume APIs (e.g., Applications), and</li> <li>the CAPIF Core Function, that manages the relationships between the other two.</li> </ul> <p></p> <p>The CAPIF Core Function is the cornerstone of the Common API Framework and provides the following capabilities:</p> <ul> <li>Authenticating the API Invoker based on its identity and other information;</li> <li>Supporting mutual authentication with the API Invoker;</li> <li>Providing authorization for the API Invoker prior to accessing the exposed APIs;</li> <li>Publishing, storing, and supporting the discovery of service APIs information;</li> <li>Controlling the service API access based on PLMN operator configured policies;</li> <li>Storing the logs for the service API invocations and providing the service API invocation logs to authorized entities;</li> <li>Charging based on the logs of the service API invocations;</li> <li>Monitoring the service API invocations;</li> <li>Onboarding a new API Invoker and offboarding an API Invoker;</li> <li>Storing policy configurations related to CAPIF and service APIs;</li> <li>Support accessing the logs for auditing (e.g., detecting abuse); and</li> <li>Support publishing and discovery of service APIs information among CAPIF Core Function (CAPIF interconnection).</li> </ul> <p>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.</p> <p></p> <p>If you want to know more about OpenCAPIF check The story behind openCAPIF</p>"},{"location":"#repository-structure","title":"Repository structure","text":"<p>You can check the code at OpenCAPIF Repository</p> <pre><code>CAPIF_API_Services\n\u2514\u2500\u2500\u2500docs\n\u2502    \u2514\u2500\u2500\u2500test_plan\n\u2502    \u2514\u2500\u2500\u2500testing_with_postman\n\u2514\u2500\u2500\u2500services\n\u2514\u2500\u2500\u2500tests\n\u2514\u2500\u2500\u2500tools\n    \u2514\u2500\u2500\u2500robot\n    \u2514\u2500\u2500\u2500open_api_script\n</code></pre> <ul> <li>services: Services developed following CAPIF API specifications. Also, other complementary services (e.g., NGINX and JWTauth services for the authentication of API consuming entities).</li> <li>tools: Auxiliary tools. Robot Framework related code and OpenAPI scripts.</li> <li> <p>test: Tests developed using Robot Framework.</p> </li> <li> <p>docs: Documents related to the code in the repository.</p> </li> <li>images: images used in the repository</li> <li>test_plan: test plan descriptions for each API service referring to the test that are executed with the Robot Framework.</li> <li>testing_with_postman: auxiliary JSON file needed for the Postman-based examples.</li> </ul>"},{"location":"#capif_api_services","title":"CAPIF_API_Services","text":"<p>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</p>"},{"location":"#how-to-test-capif-apis","title":"How to test CAPIF APIs","text":"<p>The above APIs can be tested either with POSTMAN tool or running developed tests with Robot Framework.</p>"},{"location":"#test-plan-documentation","title":"Test Plan Documentation","text":"<p>Complete documentation of tests is here: Test Plan Directory</p>"},{"location":"#robot-framework","title":"Robot Framework","text":"<p>In order to ensure modifications over CAPIF services still accomplish the required functionality, Robot Framework test suite must be success.</p> <p>Test suite implemented accomplish requirements described under test plan at Test Plan Directory folder.</p> <p>Please go to Testing with Robot Framework Section</p>"},{"location":"#using-postman","title":"Using PostMan","text":"<p>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.</p> <p>For more information on how to test the APIs with POSTMAN, go to this POSTMAN Section.</p>"},{"location":"#important-urls","title":"Important urls:","text":""},{"location":"#mongo-capifs-db-dashboard","title":"Mongo CAPIF's DB Dashboard","text":"<pre><code>http://localhost:8082/ (if accessed from localhost) \n\nor\n\nhttp://&lt;Mongo CAPIF Express Host IP&gt;:8082/ (if accessed from another host)\n</code></pre>"},{"location":"#mongo-registers-db-dashboard","title":"Mongo Register's DB Dashboard","text":"<pre><code>http://localhost:8083/ (if accessed from localhost) \n\nor\n\nhttp://&lt;Mongo Register Express Host IP&gt;:8083/ (if accessed from another host)\n</code></pre>"},{"location":"#faq-documentation","title":"FAQ Documentation","text":"<p>Frequently asked questions can be found here: FAQ Section</p>"},{"location":"FAQ/","title":"Frequently Asked Questions (FAQ)","text":""},{"location":"FAQ/#does-the-user-have-to-develop-the-3-elements-of-the-provider-aef-amf-and-apf","title":"Does the user have to develop the 3 elements of the provider (AEF, AMF and APF)?","text":"<p>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.</p>"},{"location":"FAQ/#there-is-one-party-that-publishes-the-api-and-another-that-exposes-it-what-is-the-difference","title":"There is one party that publishes the API and another that exposes it, what is the difference?","text":"<p>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.</p>"},{"location":"FAQ/#before-publishing-an-api-do-you-have-to-be-registered-in-capif","title":"Before publishing an API, do you have to be registered in CAPIF?","text":"<p>Yes, before publishing an API you must register using the POST /register endpoint.</p>"},{"location":"FAQ/#where-is-the-registration-done","title":"Where is the registration done?","text":"<p>Registration is done in a REST API outside of the CAPIF specification taht we have implemented.</p>"},{"location":"FAQ/#is-the-username-and-password-chosen-by-the-user-when-registering-or-is-it-assigned-when-requesting-registration-to-capif-public-instance","title":"Is the username and password chosen by the user when registering or is it assigned when requesting registration to CAPIF public instance?","text":"<p>When you make the request to the \"/endpoint\" of register, you will be returned a username and a password determined by CAPIF.</p>"},{"location":"FAQ/#what-is-a-csr","title":"What is a CSR?","text":"<p>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.</p>"},{"location":"FAQ/#when-doing-the-register_provider-where-can-i-find-the-csrs-that-are-generated","title":"When doing the register_provider where can I find the CSRs that are generated?","text":"<p>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.</p>"},{"location":"FAQ/#how-to-use-the-example-client-capif_invoker_gui","title":"How to use the example client (CAPIF_INVOKER_GUI)?","text":"<p>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.</p>"},{"location":"FAQ/#where-is-the-capif-public-instance-located","title":"Where is the CAPIF public instance located?","text":"<p>The CAPIF public instance can be found at the following URLs: - capif.mobilesandbox.cloud:37211 (HTTPS) - capif.mobilesandbox.cloud:37212 (HTTP)</p>"},{"location":"FAQ/#do-you-have-to-publish-3-apis-one-for-each-instance","title":"Do you have to publish 3 APIs? one for each instance?","text":"<p>No, you only have to publish a single API but each component is responsible for a specific service, whether publishing or exposing.</p>"},{"location":"FAQ/#once-the-api-is-published-is-it-always-active-or-do-you-have-to-republish-it-every-time-you-want-to-use-it","title":"Once the API is published, is it always active? Or do you have to republish it every time you want to use it?","text":"<p>It is better to unsubscribe the API every time you exit the application since otherwise it could be republished and it would be double.</p>"},{"location":"FAQ/#would-the-same-username-and-password-be-valid-for-different-invokers","title":"Would the same username and password be valid for different invokers?","text":"<p>Yes, a user can have multiple invokers at the same time, and as such, the username and password would be the same.</p>"},{"location":"FAQ/#what-is-the-notfication-destination-field-in-the-register_invoker-request","title":"What is the notfication destination field in the register_invoker request?","text":"<p>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...</p>"},{"location":"FAQ/#is-the-notification_destination-a-required-field-in-the-register_invoker","title":"Is the notification_destination a required field in the register_invoker","text":"<p>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.</p>"},{"location":"FAQ/#what-is-the-purpose-of-the-discover_service-function-in-the-invoker-client","title":"What is the purpose of the \"discover_service\" function in the invoker client?","text":"<p>The discover_service returns a json with all the services that exist exposed in CAPIF at that moment.</p>"},{"location":"FAQ/#what-is-the-purpose-of-the-get_security_auth-function-in-the-invoker-client","title":"What is the purpose of the \"get_security_auth\" function in the invoker client?","text":"<p>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.</p>"},{"location":"FAQ/#what-is-the-purpose-of-the-register_security_context-function-in-the-invoker-client","title":"What is the purpose of the \"register_security_context\" function in the invoker client?","text":"<p>To consume the API it is necessary to have a Security Context registered with the data and the authentication method.</p>"},{"location":"FAQ/#is-a-user-the-same-as-an-exposer","title":"Is a user the same as an exposer?","text":"<p>No, a user registers in CAPIF and once done can have the role of invoker, provider or both.</p>"},{"location":"FAQ/#where-can-i-put-my-endpoint","title":"Where can I put my endpoint?","text":"<p>You have to set your endpoint when doing the \"publish_service\" functionality: <code>publish_service capif_ops/config_files/service_api_description_hello.json</code></p> <p>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.</p>"},{"location":"gettingstarted/howtorun/","title":"How to Run","text":"<ul> <li>Run All CAPIF Services locally with Docker images</li> <li>Run All CAPIF Services locally with Docker images and deploy monitoring stack</li> <li>Run each service using Docker</li> <li>Run each service using Python</li> </ul> <p>Capif services are developed under services folder.</p>"},{"location":"gettingstarted/howtorun/#run-all-capif-services-locally-with-docker-images","title":"Run All CAPIF Services locally with Docker images","text":"<p>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.</p> <p>All script are present under services directory.</p> <p>To run CAPIF APIs locally using docker and docker-compose you can use run.sh script:</p> <pre><code>./run.sh -h\n\nUsage: ./run.sh &lt;options&gt;\n       -c : Setup different hostname for capif\n       -m : Clean monitoring service\n       -h : show this help\n</code></pre> <p>This script build and run all services using docker images, including mongodb and nginx locally and in background, and import ca.crt to nginx. By default monitoring is not activated and Nginx deployed use capifcore as a hostname. </p> <p>Some examples of use:</p> <pre><code># Default values, No monitoring and capifcore as CAPIF_HOSTNAME\n./run.sh\n\n# opencapif.etsi.org as CAPIF_HOSTNAME\n./run.sh -c opencapif.etsi.org\n\n# opencapif.etsi.org as CAPIF_HOSTNAME and monitoring activated\n./run.sh -c opencapif.etsi.org -m true \n\n</code></pre> <p>If you want to check if all CAPIF services are running properly in local machine after execute run.sh, we can use:</p> <pre><code>./check_services_are_running.sh\n</code></pre> <p>This shell script will return 0 if all services are running properly.</p> <p>When we need to stop all CAPIF services, we can use next bash script:</p> <pre><code>./clean_capif_docker_services.sh -a\n</code></pre> <p>NOTE: You can use different flags if you only want to stop some of them, please check help using</p> <pre><code>./clean_capif_docker_services.sh -h\n\nUsage: clean_capif_docker_services.sh &lt;options&gt;\n       -c : clean capif services\n       -v : clean vault service\n       -r : clean register service\n       -m : clean monitoring service\n       -a : clean all services\n       -h : show this help\n</code></pre> <p>This shell script will remove and clean all CAPIF services started previously with run.sh</p> <p>On the other hand you can check logs using show_logs.sh script, please check options:</p> <pre><code>./show_logs.sh\nYou must specify an option before run script.\nUsage: ./show_logs.sh &lt;options&gt;\n       -c : Show capif services\n       -v : Show vault service\n       -r : Show register service\n       -m : Show monitoring service\n       -a : Show all services\n       -f : Follow log output\n       -h : Show this help\n</code></pre> <p>You can also use option -f in order to live follow log output</p>"},{"location":"gettingstarted/howtorun/#run-all-capif-services-locally-with-docker-images-and-deploy-monitoring-stack","title":"Run All CAPIF Services locally with Docker images and deploy monitoring stack","text":"<p>It is now possible to deploy a monitoring stack for CAPIF with Grafana, Prometheus, FluentBit, Loki, Cadvisor, Tempo and Opentelemetry.</p> <p>To deploy CAPIF together with the monitoring stack, it is only necessary to execute the following.</p> <pre><code>./run.sh -m true\n</code></pre> <p>After they have been built, the different panels can be consulted in Grafana at the url</p> <pre><code>http://localhost:3000\n</code></pre> <p>By default, the monitoring option is set to false. Once up, all data sources and dashboards are automatically provisioned</p>"},{"location":"gettingstarted/howtorun/#run-each-service-using-docker","title":"Run each service using Docker","text":"<p>Also you can run service by service using docker:</p> <pre><code>cd &lt;Service&gt;\ndocker build -t capif_security .\ndocker run -p 8080:8080 capif_security\n</code></pre>"},{"location":"gettingstarted/howtorun/#run-each-service-using-python","title":"Run each service using Python","text":"<p>Run using python</p> <pre><code>cd &lt;Service&gt;\npip3 install -r requirements.txt\npython3 -m &lt;service&gt;\n</code></pre>"},{"location":"testing/postman/","title":"Postman","text":"<p>In this section we can use Postman to publish an API as a provider and use it as an invoker.</p>"},{"location":"testing/postman/#requisites","title":"Requisites","text":"<ul> <li>We will need to have Node.js installed since we will use a small script to create the CSRs of the certificates.</li> <li>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).</li> </ul>"},{"location":"testing/postman/#first-steps","title":"First steps","text":"<ol> <li>Install the Node dependencies package.json to run the script with:</li> </ol> <pre><code>npm i\n</code></pre> <ol> <li>Run the script.js with the following command:</li> </ol> <pre><code>node script.js\n</code></pre> <ol> <li>Import Postman collection and environment variables (CAPIF.postman_collection.json and CAPIF.postman_environment.json)</li> <li>Select CAPIF Environment before start testing.</li> </ol>"},{"location":"testing/postman/#remote-capif","title":"Remote CAPIF","text":"<p>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.</p> <p>Enviroments in Postman</p> <pre><code>CAPIF_HOSTNAME     capifcore\nCAPIF_PORT         8080\nREGISTER_HOSTNAME  register\nREGISTER_PORT      8084\n</code></pre> <p>Const in script.js</p> <pre><code>CAPIF_HOSTNAME    capifcore\n</code></pre>"},{"location":"testing/postman/#capif-flows","title":"CAPIF Flows","text":"<p>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.</p>"},{"location":"testing/postman/#publication-of-an-api","title":"Publication of an API","text":""},{"location":"testing/postman/#01-register_user_provider","title":"01-register_user_provider","text":""},{"location":"testing/postman/#02-getauth_provider","title":"02-getauth_provider","text":""},{"location":"testing/postman/#03-onboard_provider","title":"03-onboard_provider","text":"<p>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.</p> <p>To configure go to settings in Postman and open the certificates section. </p> <ul> <li>Here, activate the CA certificates option and add the ca_cert.pem file found in the Responses folder.</li> <li>Adds a client certificate specifying the CAPIF host being used and the files client_cert.crt and client_key.key in the Responses folder.</li> </ul> <p>Once this is done, the node script will be in charge of changing the certificate that is necessary in each request.</p>"},{"location":"testing/postman/#04-publish_api","title":"04-publish_api","text":"<p>Once the api is published, we can start it. In this case we have a test one created in python called hello_api.py that can be executed with the following command:</p> <pre><code>python3 hello_api.py\n</code></pre> <p>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.</p> <p>With this the provider part would be finished.</p>"},{"location":"testing/postman/#calling-the-api","title":"Calling the API","text":""},{"location":"testing/postman/#05-register_user_invoker","title":"05-register_user_invoker","text":""},{"location":"testing/postman/#06-getauth_invoker","title":"06-getauth_invoker","text":""},{"location":"testing/postman/#07-onboard_invoker","title":"07-onboard_invoker","text":"<p>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.</p>"},{"location":"testing/postman/#08-discover","title":"08-discover","text":""},{"location":"testing/postman/#09-security_context","title":"09-security_context","text":""},{"location":"testing/postman/#10-get_token","title":"10-get_token","text":""},{"location":"testing/postman/#11-call_service","title":"11-call_service","text":"<p>With this, we would have made the API call and finished the flow.</p>"},{"location":"testing/postman/#other-requests","title":"Other requests","text":"<p>Other requests that we have added are the following:</p> <ul> <li>offboard_provider      Performs offboarding of the provider, thereby eliminating the published APIs.</li> <li>offboard_invoker       Offboards the invoker, also eliminating access to the APIs of that invoker.</li> <li>remove_user_invoker    Delete the user created for the invoker.</li> <li>remove_user_provider   Delete the user created for the provider.</li> </ul>"},{"location":"testing/postman/#notes","title":"Notes","text":"<ul> <li>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.</li> <li>It is possible that if external CAPIFs are used (Public CAPIF) the test data may already be used or the API already registered.</li> <li>It is necessary to have the Node service running to make the certificate change for the requests, otherwise it will not work.</li> <li>We are working on adding more requests to the Postman collection.</li> <li>This collection is a testing guide and is recommended for testing purposes only.</li> </ul>"},{"location":"testing/robotframework/","title":"Robot Framework","text":""},{"location":"testing/robotframework/#steps-to-test","title":"Steps to Test","text":"<p>To run any test locally you will need docker and docker-compose installed in order run services and execute test plan. Steps will be:</p> <ul> <li> <p>Run All Services: See section Run All CAPIF Services</p> </li> <li> <p>Run desired tests: At this point we have 2 options:</p> </li> <li> <p>Using helper script: Script Test Execution</p> </li> <li>Build robot docker image and execute manually robot docker: Manual Build And Test Execution</li> </ul>"},{"location":"testing/robotframework/#script-test-execution","title":"Script Test Execution","text":"<p>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.</p> <pre><code>./runCapifTests.sh --include &lt;TAG&gt;\n</code></pre> <p>Results will be stored at /results <p>Please check parameters (include) under Test Execution at Manual Build And Test Execution.</p>"},{"location":"testing/robotframework/#manual-build-and-test-execution","title":"Manual Build And Test Execution","text":"<ul> <li>Build Robot docker image:</li> </ul> <pre><code>cd tools/robot\ndocker build . -t 5gnow-robot-test:latest\n</code></pre> <ul> <li>Tests Execution:</li> </ul> <p>Execute all tests locally:</p> <pre><code>&lt;PATH_TO_REPOSITORY&gt;=path in local machine to repository cloned.\n&lt;PATH_RESULT_FOLDER&gt;=path to a folder on local machine to store results of Robot Framework execution.\n&lt;CAPIF_HOSTNAME&gt;=Is the hostname set when run.sh is executed, by default it will be capifcore.\n&lt;CAPIF_HTTP_PORT&gt;=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.\n\nTo execute all tests run :\ndocker run -ti --rm --network=\"host\" -v &lt;PATH_TO_REPOSITORY&gt;/tests:/opt/robot-tests/tests -v &lt;PATH_RESULT_FOLDER&gt;:/opt/robot-tests/results 5gnow-robot-test:latest --variable CAPIF_HOSTNAME:capifcore --variable CAPIF_HTTP_PORT:8080 --include all\n</code></pre> <p>Execute specific tests locally:</p> <pre><code>To run more specific tests, for example, only one functionality:\n&lt;TAG&gt;=Select one from list:\n  \"capif_api_acl\",\n  \"capif_api_auditing_service\",\n  \"capif_api_discover_service\",\n  \"capif_api_events\",\n  \"capif_api_invoker_management\",\n  \"capif_api_logging_service\",\n  \"capif_api_provider_management\",\n  \"capif_api_publish_service\",\n  \"capif_security_api\n\nAnd Run:\ndocker run -ti --rm --network=\"host\" -v &lt;PATH_TO_REPOSITORY&gt;/tests:/opt/robot-tests/tests -v &lt;PATH_RESULT_FOLDER&gt;:/opt/robot-tests/results 5gnow-robot-test:latest --variable CAPIF_HOSTNAME:capifcore --variable CAPIF_HTTP_PORT:8080 --include &lt;TAG&gt;\n</code></pre>"},{"location":"testing/robotframework/#test-result-review","title":"Test result review","text":"<p>In order to Review results after tests, you can check general report at /report.html or if you need more detailed information /log.html, example: <ul> <li> <p>Report: </p> </li> <li> <p>Detailed information: </p> </li> </ul> <p>NOTE: If you need more detail at Robot Framework Logs you can set log level option just adding to command --loglevel DEBUG</p>"},{"location":"testing/testplan/","title":"Test Plan Index","text":"<p>List of Common API Services implemented:</p> <ul> <li>Api Invoker Management</li> <li>Api Provider Management</li> <li>Api Publish Service</li> <li>Api Discover Service</li> <li>Api Events Service</li> <li>Api Security Service</li> <li>Api Logging Service</li> <li>Api Auditing Service</li> <li>Api Access Control Policy</li> </ul>"},{"location":"testing/testplan/api_access_control_policy/","title":"Test Plan for CAPIF Api Access Control Policy","text":"<p>At this documentation you will have all information and related files and examples of test plan for this API.</p>"},{"location":"testing/testplan/api_access_control_policy/#test-case-1-retrieve-acl","title":"Test Case 1: Retrieve ACL","text":"<p>Test ID: capif_api_acl-1</p> <p>Description:</p> <p>This test case will check that an API Provider can retrieve ACL from CAPIF</p> <p>Pre-Conditions:</p> <ul> <li>API Provider had a Service API Published on CAPIF</li> <li>API Invoker had a Security Context for Service API published.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Store serviceApiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Perform Invoker Onboarding store apiInvokerId</p> </li> <li>Discover published APIs</li> <li> <p>Create Security Context for this Invoker</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Use Invoker Certificate</li> </ul> </li> <li> <p>Provider Retrieve ACL</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId}?aef-id=${aef_id}</li> <li>Use serviceApiId and aefId</li> <li>Use AEF Provider Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Provider at CCF.</li> <li>Publish a provider API with name service_1</li> <li>Register and onboard Invoker at CCF</li> <li>Store signed Certificate</li> <li>Create Security Context</li> <li>Provider Get ACL information.</li> </ol> <p>Expected Result:</p> <ol> <li>ACL Response:<ol> <li>200 OK Response.</li> <li>body returned must accomplish AccessControlPolicyList data structure.</li> <li>apiInvokerPolicies must:<ol> <li>contain only one object.</li> <li>apiInvokerId must match apiInvokerId registered previously.</li> </ol> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_access_control_policy/#test-case-2-retrieve-acl-with-2-service-apis-published","title":"Test Case 2: Retrieve ACL with 2 Service APIs published","text":"<p>Test ID: capif_api_acl-2</p> <p>Description:</p> <p>This test case will check that an API Provider can retrieve ACL from CAPIF for 2 different serviceApis published.</p> <p>Pre-Conditions:</p> <ul> <li>API Provider had two Service API Published on CAPIF</li> <li>API Invoker had a Security Context for both Service APIs published.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Store serviceApiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_2</li> <li>Store serviceApiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Perform Invoker Onboarding store apiInvokerId</p> </li> <li>Discover published APIs</li> <li> <p>Create Security Context for this Invoker for both published APIs</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Use Invoker Certificate</li> </ul> </li> <li> <p>Provider Retrieve ACL for serviceApiId1</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId1}?aef-id=${aef_id}</li> <li>Use serviceApiId and aefId</li> <li>Use AEF Provider Certificate</li> </ul> </li> <li> <p>Provider Retrieve ACL for serviceApiId2</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId2}?aef-id=${aef_id}</li> <li>Use serviceApiId and aefId</li> <li>Use AEF Provider Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Provider at CCF.</li> <li>Publish a provider API with name service_1 and service_2</li> <li>Register and onboard Invoker at CCF</li> <li>Store signed Certificate</li> <li>Create Security Context</li> <li>Provider Get ACL information for service_1.</li> <li>Provider Get ACL information for service_2.</li> </ol> <p>Expected Result:</p> <ol> <li>ACL Response:<ol> <li>200 OK Response.</li> <li>body returned must accomplish AccessControlPolicyList data structure.</li> <li>apiInvokerPolicies must:<ol> <li>contain one object.</li> <li>apiInvokerId must match apiInvokerId registered previously.</li> </ol> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_access_control_policy/#test-case-3-retrieve-acl-with-security-context-created-by-two-different-invokers","title":"Test Case 3: Retrieve ACL with security context created by two different Invokers","text":"<p>Test ID: capif_api_acl-3</p> <p>Description:</p> <p>This test case will check that an API Provider can retrieve ACL from CAPIF containing 2 objects.</p> <p>Pre-Conditions:</p> <ul> <li>API Provider had a Service API Published on CAPIF</li> <li>Two API Invokers had a Security Context for same Service API published by provider.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Store serviceApiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Perform Invoker Onboarding store apiInvokerId</p> </li> <li>Discover published APIs</li> <li> <p>Create Security Context for this Invoker for both published APIs</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Use Invoker Certificate</li> </ul> </li> <li> <p>Repeat previous 3 steps in order to have a new Invoker.</p> </li> <li> <p>Provider Retrieve ACL for serviceApiId</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId1}?aef-id=${aef_id}</li> <li>Use serviceApiId and aefId</li> <li>Use AEF Provider Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Provider at CCF.</li> <li>Publish a provider API with name service_1 and service_2</li> <li>Register and onboard Invoker at CCF</li> <li>Store signed Certificate</li> <li>Create Security Context</li> <li>Provider Get ACL information.</li> </ol> <p>Expected Result:</p> <ol> <li>ACL Response:<ol> <li>200 OK Response.</li> <li>body returned must accomplish AccessControlPolicyList data structure.</li> <li>apiInvokerPolicies must:<ol> <li>Contain two objects.</li> <li>One object must match with apiInvokerId1 and the other one with apiInvokerId2 an registered previously.</li> </ol> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_access_control_policy/#test-case-4-retrieve-acl-filtered-by-api-invoker-id","title":"Test Case 4: Retrieve ACL filtered by api-invoker-id","text":"<p>Test ID: capif_api_acl-4</p> <p>Description:</p> <p>This test case will check that an API Provider can retrieve ACL filtering by apiInvokerId from CAPIF containing 1 objects.</p> <p>Pre-Conditions:</p> <ul> <li>API Provider had a Service API Published on CAPIF</li> <li>Two API Invokers had a Security Context for same Service API published by provider.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Store serviceApiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Perform Invoker Onboarding store apiInvokerId</p> </li> <li>Discover published APIs</li> <li> <p>Create Security Context for this Invoker for both published APIs</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Use Invoker Certificate</li> </ul> </li> <li> <p>Repeat previous 3 steps in order to have a new Invoker.</p> </li> <li> <p>Provider Retrieve ACL for serviceApiId</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId1}?aef-id=${aef_id}&amp;api-invoker-id={apiInvokerId1}</li> <li>Use serviceApiId, aefId and apiInvokerId1</li> <li>Use AEF Provider Certificate</li> </ul> </li> <li> <p>Provider Retrieve ACL for serviceApiId</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId1}?aef-id=${aef_id}&amp;api-invoker-id={apiInvokerId2}</li> <li>Use serviceApiId, aefId and apiInvokerId2</li> <li>Use AEF Provider Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Provider at CCF.</li> <li>Publish a provider API with name service_1 and service_2</li> <li>Register and onboard Invoker at CCF</li> <li>Store signed Certificate</li> <li>Create Security Context</li> <li>Provider Get ACL information with query parameter indicating first api-invoker-id.</li> <li>Provider Get ACL information with query parameter indicating second api-invoker-id.</li> </ol> <p>Expected Result:</p> <ol> <li> <p>ACL Response:</p> <ol> <li>200 OK Response.</li> <li>body returned must accomplish AccessControlPolicyList data structure.</li> <li>apiInvokerPolicies must:<ol> <li>Contain one objects.</li> <li>Object must match with apiInvokerId1.</li> </ol> </li> </ol> </li> <li> <p>ACL Response:</p> <ol> <li>200 OK Response.</li> <li>body returned must accomplish AccessControlPolicyList data structure.</li> <li>apiInvokerPolicies must:<ol> <li>Contain one objects.</li> <li>Object must match with apiInvokerId2.</li> </ol> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_access_control_policy/#test-case-5-retrieve-acl-filtered-by-supported-features","title":"Test Case 5: Retrieve ACL filtered by supported-features","text":"<p>Test ID: capif_api_acl-5</p> <p>Description:</p> <p>CURRENTLY NOT SUPPORTED FEATURE</p> <p>This test case will check that an API Provider can retrieve ACL filtering by supportedFeatures from CAPIF containing 1 objects.</p> <p>Pre-Conditions:</p> <ul> <li>API Provider had a Service API Published on CAPIF</li> <li>Two API Invokers had a Security Context for same Service API published by provider.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Store serviceApiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Perform Invoker Onboarding store apiInvokerId</p> </li> <li>Discover published APIs</li> <li> <p>Create Security Context for this Invoker for both published APIs</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Use Invoker Certificate</li> </ul> </li> <li> <p>Repeat previous 3 steps in order to have a new Invoker.</p> </li> <li> <p>Provider Retrieve ACL for serviceApiId</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId1}?aef-id=${aef_id}&amp;supported-features={apiInvokerId1}</li> <li>Use serviceApiId, aefId and apiInvokerId1</li> <li>Use AEF Provider Certificate</li> </ul> </li> <li> <p>Provider Retrieve ACL for serviceApiId</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId1}?aef-id=${aef_id}&amp;supported-features={apiInvokerId2}</li> <li>Use serviceApiId, aefId and apiInvokerId2</li> <li>Use AEF Provider Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Provider at CCF.</li> <li>Publish a provider API with name service_1 and service_2</li> <li>Register and onboard Invoker at CCF</li> <li>Store signed Certificate</li> <li>Create Security Context</li> <li>Provider Get ACL information with query parameter indicating first supported-features.</li> <li>Provider Get ACL information with query parameter indicating second supported-features.</li> </ol> <p>Expected Result:</p> <ol> <li> <p>ACL Response:</p> <ol> <li>200 OK Response.</li> <li>body returned must accomplish AccessControlPolicyList data structure.</li> <li>apiInvokerPolicies must:<ol> <li>Contain one objects.</li> <li>Object must match with supportedFeatures1.</li> </ol> </li> </ol> </li> <li> <p>ACL Response:</p> <ol> <li>200 OK Response.</li> <li>body returned must accomplish AccessControlPolicyList data structure.</li> <li>apiInvokerPolicies must:<ol> <li>Contain one objects.</li> <li>Object must match with supportedFeatures1.</li> </ol> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_access_control_policy/#test-case-6-retrieve-acl-with-aef-id-not-valid","title":"Test Case 6: Retrieve ACL with aef-id not valid","text":"<p>Test ID: capif_api_acl-6</p> <p>Description:</p> <p>This test case will check that an API Provider can't retrieve ACL from CAPIF if aef-id is not valid</p> <p>Pre-Conditions:</p> <ul> <li>API Provider had a Service API Published on CAPIF</li> <li>API Invoker had a Security Context for Service API published.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Store serviceApiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Perform Invoker Onboarding store apiInvokerId</p> </li> <li>Discover published APIs</li> <li> <p>Create Security Context for this Invoker</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Use Invoker Certificate</li> </ul> </li> <li> <p>Provider Retrieve ACL</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId}?aef-id=${AEF_ID_NOT_VALID}</li> <li>Use serviceApiId and AEF_ID_NOT_VALID</li> <li>Use AEF Provider Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Provider at CCF.</li> <li>Publish a provider API with name service_1</li> <li>Register and onboard Invoker at CCF</li> <li>Store signed Certificate</li> <li>Create Security Context</li> <li>Provider Get ACL information.</li> </ol> <p>Expected Result:</p> <ol> <li>ACL Response:<ol> <li>404 Not Found Response.</li> <li>body returned must accomplish Problem Details data structure.</li> <li>apiInvokerPolicies must:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>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}\".</li> <li>cause with message \"Wrong id\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_access_control_policy/#test-case-7-retrieve-acl-with-service-id-not-valid","title":"Test Case 7: Retrieve ACL with service-id not valid","text":"<p>Test ID: capif_api_acl-7</p> <p>Description:</p> <p>This test case will check that an API Provider can't retrieve ACL from CAPIF if service-api-id is not valid</p> <p>Pre-Conditions:</p> <ul> <li>API Provider had a Service API Published on CAPIF</li> <li>API Invoker had a Security Context for Service API published.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Store serviceApiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Perform Invoker Onboarding store apiInvokerId</p> </li> <li>Discover published APIs</li> <li> <p>Create Security Context for this Invoker</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Use Invoker Certificate</li> </ul> </li> <li> <p>Provider Retrieve ACL</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${NOT_VALID_SERVICE_API_ID}?aef-id=${aef_id}</li> <li>Use NOT_VALID_SERVICE_API_ID and aef_id</li> <li>Use AEF Provider Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Provider at CCF.</li> <li>Publish a provider API with name service_1</li> <li>Register and onboard Invoker at CCF</li> <li>Store signed Certificate</li> <li>Create Security Context</li> <li>Provider Get ACL information.</li> </ol> <p>Expected Result:</p> <ol> <li>ACL Response:<ol> <li>404 Not Found Response.</li> <li>body returned must accomplish Problem Details data structure.</li> <li>apiInvokerPolicies must:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>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}\".</li> <li>cause with message \"Wrong id\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_access_control_policy/#test-case-8-retrieve-acl-with-service-api-id-and-aef-id-not-valid","title":"Test Case 8: Retrieve ACL with service-api-id and aef-id not valid","text":"<p>Test ID: capif_api_acl-8</p> <p>Description:</p> <p>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</p> <p>Pre-Conditions:</p> <ul> <li>API Provider had a Service API Published on CAPIF</li> <li>API Invoker had a Security Context for Service API published.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Store serviceApiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Perform Invoker Onboarding store apiInvokerId</p> </li> <li>Discover published APIs</li> <li> <p>Create Security Context for this Invoker</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Use Invoker Certificate</li> </ul> </li> <li> <p>Provider Retrieve ACL</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${NOT_VALID_SERVICE_API_ID}?aef-id=${AEF_ID_NOT_VALID}</li> <li>Use NOT_VALID_SERVICE_API_ID and aef_id</li> <li>Use AEF Provider Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Provider at CCF.</li> <li>Publish a provider API with name service_1</li> <li>Register and onboard Invoker at CCF</li> <li>Store signed Certificate</li> <li>Create Security Context</li> <li>Provider Get ACL information.</li> </ol> <p>Expected Result:</p> <ol> <li>ACL Response:<ol> <li>404 Not Found Response.</li> <li>body returned must accomplish Problem Details data structure.</li> <li>apiInvokerPolicies must:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>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}\".</li> <li>cause with message \"Wrong id\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_access_control_policy/#test-case-9-retrieve-acl-without-securitycontext-created-previously-by-invoker","title":"Test Case 9: Retrieve ACL without SecurityContext created previously by Invoker","text":"<p>Test ID: capif_api_acl-9</p> <p>Description:</p> <p>This test case will check that an API Provider can't retrieve ACL if no invoker had requested Security Context to CAPIF</p> <p>Pre-Conditions:</p> <ul> <li>API Provider had a Service API Published on CAPIF</li> <li>API Invoker created but no Security Context for Service API published had been requested.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Store serviceApiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Perform Invoker Onboarding store apiInvokerId</p> </li> <li> <p>Discover published APIs</p> </li> <li> <p>Provider Retrieve ACL</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId}?aef-id=${aef_id}</li> <li>Use serviceApiId and aefId</li> <li>Use AEF Provider Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Provider at CCF.</li> <li>Publish a provider API with name service_1</li> <li>Register and onboard Invoker at CCF</li> <li>Store signed Certificate</li> <li>Create Security Context</li> <li>Provider Get ACL information.</li> </ol> <p>Expected Result:</p> <ol> <li>ACL Response:<ol> <li>404 Not Found Response.</li> <li>body returned must accomplish Problem Details data structure.</li> <li>apiInvokerPolicies must:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>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}\".</li> <li>cause with message \"Wrong id\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_access_control_policy/#test-case-10-retrieve-acl-filtered-by-api-invoker-id-not-present","title":"Test Case 10: Retrieve ACL filtered by api-invoker-id not present","text":"<p>Test ID: capif_api_acl-10</p> <p>Description:</p> <p>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.</p> <p>Pre-Conditions:</p> <ul> <li>API Provider had a Service API Published on CAPIF</li> <li>API Invoker had a Security Context for Service API published.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Store serviceApiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Perform Invoker Onboarding store apiInvokerId</p> </li> <li>Discover published APIs</li> <li> <p>Create Security Context for this Invoker</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Use Invoker Certificate</li> </ul> </li> <li> <p>Provider Retrieve ACL</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId}?aef-id=${aef_id}&amp;api-invoker-id={NOT_VALID_API_INVOKER_ID}</li> <li>Use serviceApiId, aefId and NOT_VALID_API_INVOKER_ID</li> <li>Use AEF Provider Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Provider at CCF.</li> <li>Publish a provider API with name service_1</li> <li>Register and onboard Invoker at CCF</li> <li>Store signed Certificate</li> <li>Create Security Context</li> <li>Provider Get ACL information.</li> </ol> <p>Expected Result:</p> <ol> <li>ACL Response:<ol> <li>404 Not Found Response.</li> <li>body returned must accomplish Problem Details data structure.</li> <li>apiInvokerPolicies must:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>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}\".</li> <li>cause with message \"Wrong id\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_access_control_policy/#test-case-11-retrieve-acl-with-apf-certificate","title":"Test Case 11: Retrieve ACL with APF Certificate","text":"<p>Test ID: capif_api_acl-11</p> <p>Description:</p> <p>This test case will check that an API Provider can't retrieve ACL from CAPIF using APF Certificate</p> <p>Pre-Conditions:</p> <ul> <li>API Provider had a Service API Published on CAPIF</li> <li>API Invoker had a Security Context for Service API published.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Store serviceApiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Perform Invoker Onboarding store apiInvokerId</p> </li> <li>Discover published APIs</li> <li> <p>Create Security Context for this Invoker</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Use Invoker Certificate</li> </ul> </li> <li> <p>Provider Retrieve ACL</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId}?aef-id=${aef_id}</li> <li>Use serviceApiId and aefId</li> <li>Use APF Provider Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Provider at CCF.</li> <li>Publish a provider API with name service_1</li> <li>Register and onboard Invoker at CCF</li> <li>Store signed Certificate</li> <li>Create Security Context</li> <li>Provider Get ACL information.</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Logging Service must accomplish:<ol> <li>401 Unauthorized</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 401</li> <li>title with message \"Unauthorized\"</li> <li>detail with message \"Role not authorized for this API route\".</li> <li>cause with message \"Certificate not authorized\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_access_control_policy/#test-case-12-retrieve-acl-with-amf-certificate","title":"Test Case 12: Retrieve ACL with AMF Certificate","text":"<p>Test ID: capif_api_acl-12</p> <p>Description:</p> <p>This test case will check that an API Provider can't retrieve ACL from CAPIF using AMF Certificate</p> <p>Pre-Conditions:</p> <ul> <li>API Provider had a Service API Published on CAPIF</li> <li>API Invoker had a Security Context for Service API published.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Store serviceApiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Perform Invoker Onboarding store apiInvokerId</p> </li> <li>Discover published APIs</li> <li> <p>Create Security Context for this Invoker</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Use Invoker Certificate</li> </ul> </li> <li> <p>Provider Retrieve ACL</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId}?aef-id=${aef_id}</li> <li>Use serviceApiId and aefId</li> <li>Use AMF Provider Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Provider at CCF.</li> <li>Publish a provider API with name service_1</li> <li>Register and onboard Invoker at CCF</li> <li>Store signed Certificate</li> <li>Create Security Context</li> <li>Provider Get ACL information.</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Logging Service must accomplish:<ol> <li>401 Unauthorized</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 401</li> <li>title with message \"Unauthorized\"</li> <li>detail with message \"Role not authorized for this API route\".</li> <li>cause with message \"Certificate not authorized\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_access_control_policy/#test-case-13-retrieve-acl-with-invoker-certificate","title":"Test Case 13: Retrieve ACL with Invoker Certificate","text":"<p>Test ID: capif_api_acl-13</p> <p>Description:</p> <p>This test case will check that an API Provider can't retrieve ACL from CAPIF using Invoker Certificate</p> <p>Pre-Conditions:</p> <ul> <li>API Provider had a Service API Published on CAPIF</li> <li>API Invoker had a Security Context for Service API published.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Store serviceApiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Perform Invoker Onboarding store apiInvokerId</p> </li> <li>Discover published APIs</li> <li> <p>Create Security Context for this Invoker</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Use Invoker Certificate</li> </ul> </li> <li> <p>Provider Retrieve ACL</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId}?aef-id=${aef_id}</li> <li>Use serviceApiId and aefId</li> <li>Use Invoker Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Provider at CCF.</li> <li>Publish a provider API with name service_1</li> <li>Register and onboard Invoker at CCF</li> <li>Store signed Certificate</li> <li>Create Security Context</li> <li>Provider Get ACL information.</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Logging Service must accomplish:<ol> <li>401 Unauthorized</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 401</li> <li>title with message \"Unauthorized\"</li> <li>detail with message \"Role not authorized for this API route\".</li> <li>cause with message \"Certificate not authorized\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_access_control_policy/#test-case-14-no-acl-for-invoker-after-be-removed","title":"Test Case 14: No ACL for invoker after be removed","text":"<p>Test ID: capif_api_acl-14</p> <p>Description:</p> <p>This test case will check that ACLs are removed after invoker is removed.</p> <p>Pre-Conditions:</p> <ul> <li>API Provider had a Service API Published on CAPIF</li> <li>API Invoker had a Security Context for Service API published and ACL is present</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Store serviceApiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Perform Invoker Onboarding store apiInvokerId</p> </li> <li>Discover published APIs</li> <li> <p>Create Security Context for this Invoker</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Use Invoker Certificate</li> </ul> </li> <li> <p>Provider Retrieve ACL</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId}?aef-id=${aef_id}&amp;api-invoker-id={api-invoker-id}</li> <li>Use serviceApiId, aefId and api-invoker-id</li> <li>Use AEF Provider Certificate</li> </ul> </li> <li>Remove Invoker from CAPIF</li> <li>Provider Retrieve ACL<ul> <li>Send GET https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId}?aef-id=${aef_id}&amp;api-invoker-id={api-invoker-id}</li> <li>Use serviceApiId, aefId and api-invoker-id</li> <li>Use AEF Provider Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Provider at CCF.</li> <li>Publish a provider API with name service_1</li> <li>Register and onboard Invoker at CCF</li> <li>Store signed Certificate</li> <li>Create Security Context</li> <li>Provider Get ACL information of invoker.</li> <li>Remove Invoker from CAPIF.</li> <li>Provider Get ACL information of invoker.</li> </ol> <p>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.</p> <ol> <li>ACL Response:<ol> <li>404 Not Found Response.</li> <li>body returned must accomplish Problem Details data structure.</li> <li>apiInvokerPolicies must:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>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\".</li> <li>cause with message \"Wrong id\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_auditing_service/","title":"Test Plan for CAPIF Api Auditing Service","text":"<p>At this documentation you will have all information and related files and examples of test plan for this API.</p>"},{"location":"testing/testplan/api_auditing_service/#test-case-1-get-capif-log-entry","title":"Test Case 1: Get CAPIF Log Entry.","text":"<p>Test ID: capif_api_auditing-1</p> <p>Description:</p> <p>This test case will check that a CAPIF AMF can get log entry to Logging Service</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF provider is pre-authorised (has valid AMF cert from CAPIF Authority)</li> <li>Service exist in CAPIF</li> <li>Invoker exist in CAPIF</li> <li>Log Entry exist in CAPIF</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform provider onboarding, invoker onboarding </p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body [service api description] with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Create Log Entry:</p> <ul> <li>Send POST to https://{CAPIF_HOSTNAME}/api-invocation-logs/v1/{aefId}/logs</li> <li>body log entry request body</li> <li>Use AEF Certificate</li> </ul> </li> <li> <p>Get Log:</p> <ol> <li>Send GET to https://{CAPIF_HOSTNAME}/logs/v1/apiInvocationLogs?aef-id={aefId}&amp;api-invoker-id={api-invoker-id}</li> <li>Use AMF Certificate</li> </ol> </li> </ol> <p>Execution Steps:   1. Register Provider and Invoker CCF   2. Publish Service   3. Create Log Entry   4. Get Log Entry</p> <p>Expected Result:</p> <ol> <li>Response to Logging Service must accomplish:<ol> <li>200 OK</li> <li>Response Body must follow InvocationLog data structure with:<ul> <li>aefId</li> <li>apiInvokerId</li> <li>logs</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_auditing_service/#test-case-2-get-capif-log-entry-with-no-log-entry-in-capif","title":"Test Case 2: Get CAPIF Log Entry With no Log entry in CAPIF.","text":"<p>Test ID: capif_api_auditing-2</p> <p>Description:</p> <p>This test case will check that a CAPIF AEF can create log entry to Logging Service</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF provider is pre-authorised (has valid AMF cert from CAPIF Authority)</li> <li>Service exist in CAPIF</li> <li>Invoker exist in CAPIF</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform provider onboarding, invoker onboarding </p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body [service api description] with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Get Log:</p> <ol> <li>Send GET to https://{CAPIF_HOSTNAME}/logs/v1/apiInvocationLogs?aef-id={aefId}&amp;api-invoker-id={api-invoker-id}</li> <li>Use AMF Certificate</li> </ol> </li> </ol> <p>Execution Steps:   1. Register Provider and Invoker CCF   2. Publish Service   3. Get Log Entry</p> <p>Expected Result:</p> <ol> <li>Response to Logging Service must accomplish:<ol> <li>404 Not Found</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 404</li> <li>title with message \"Not Found Log Entry in CAPIF\".</li> <li>cause with message \"Not Exist Logs with the filters applied\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_auditing_service/#test-case-3-get-capif-log-entry-without-aef-id-and-api-invoker-id","title":"Test Case 3: Get CAPIF Log Entry without aef-id and api-invoker-id.","text":"<p>Test ID: capif_api_auditing-3</p> <p>Description:</p> <p>This test case will check that a CAPIF AEF can create log entry to Logging Service</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF provider is no pre-authorised (has no valid AMF cert from CAPIF Authority)</li> <li>Service exist in CAPIF</li> <li>Invoker exist in CAPIF</li> <li>Log Entry exist in CAPIF</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform provider onboarding, invoker onboarding </p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body [service api description] with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Create Log Entry:</p> <ul> <li>Send POST to https://{CAPIF_HOSTNAME}/api-invocation-logs/v1/{aefId}/logs</li> <li>body log entry request body</li> <li>Use AEF Certificate</li> </ul> </li> <li> <p>Get Log:</p> <ol> <li>Send GET to *https://{CAPIF_HOSTNAME}/logs/v1/apiInvocationLogs</li> <li>Use AMF Certificate</li> </ol> </li> </ol> <p>Execution Steps:   1. Register Provider and Invoker CCF   2. Publish Service   3. Create Log Entry   4. Get Log Entry</p> <p>Expected Result:</p> <ol> <li>Response to Logging Service must accomplish:<ol> <li>400 Bad Request</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 400</li> <li>title with message \"Bad Request\"</li> <li>detail with message \"aef_id and api_invoker_id parameters are mandatory\".</li> <li>cause with message \"Mandatory parameters missing\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_auditing_service/#test-case-4-get-capif-log-entry-with-filtter-api-version","title":"Test Case 4: Get CAPIF Log Entry with filtter api-version.","text":"<p>Test ID: capif_api_auditing-4</p> <p>Description:</p> <p>This test case will check that a CAPIF AMF can get log entry to Logging Service</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF provider is pre-authorised (has valid AMF cert from CAPIF Authority)</li> <li>Service exist in CAPIF</li> <li>Invoker exist in CAPIF</li> <li>Log Entry exist in CAPIF</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform provider onboarding, invoker onboarding </p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body [service api description] with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Create Log Entry:</p> <ul> <li>Send POST to https://{CAPIF_HOSTNAME}/api-invocation-logs/v1/{aefId}/logs</li> <li>body log entry request body</li> <li>Use AEF Certificate</li> </ul> </li> <li> <p>Get Log:</p> <ol> <li>Send GET to https://{CAPIF_HOSTNAME}/logs/v1/apiInvocationLogs?aef-id={aefId}&amp;api-invoker-id={api-invoker-id}&amp;api-version={v1}</li> <li>Use AMF Certificate</li> </ol> </li> </ol> <p>Execution Steps:   1. Register Provider and Invoker CCF   2. Publish Service   3. Create Log Entry   4. Get Log Entry</p> <p>Expected Result:</p> <ol> <li>Response to Logging Service must accomplish:<ol> <li>200 OK</li> <li>Response Body must follow InvocationLog data structure with:<ul> <li>aefId</li> <li>apiInvokerId</li> <li>logs</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_auditing_service/#test-case-5-get-capif-log-entry-with-filter-api-version-but-not-exist-in-log-entry","title":"Test Case 5: Get CAPIF Log Entry with filter api-version but not exist in log entry.","text":"<p>Test ID: capif_api_auditing-4</p> <p>Description:</p> <p>This test case will check that a CAPIF AMF can get log entry to Logging Service</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF provider is pre-authorised (has valid AMF cert from CAPIF Authority)</li> <li>Service exist in CAPIF</li> <li>Invoker exist in CAPIF</li> <li>Log Entry exist in CAPIF</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform provider onboarding, invoker onboarding </p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body [service api description] with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Create Log Entry:</p> <ul> <li>Send POST to https://{CAPIF_HOSTNAME}/api-invocation-logs/v1/{aefId}/logs</li> <li>body log entry request body</li> <li>Use AEF Certificate</li> </ul> </li> <li> <p>Get Log:</p> <ol> <li>Send GET to https://{CAPIF_HOSTNAME}/logs/v1/apiInvocationLogs?aef-id={aefId}&amp;api-invoker-id={api-invoker-id}&amp;api-version={v58}</li> <li>Use AMF Certificate</li> </ol> </li> </ol> <p>Execution Steps:   1. Register Provider and Invoker CCF   2. Publish Service   3. Create Log Entry   4. Get Log Entry</p> <p>Expected Result:</p> <ol> <li>Response to Logging Service must accomplish:<ol> <li>404 Not Found</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 404</li> <li>detail with message \"Parameters do not match any log entry\"</li> <li>cause with message \"No logs found\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_discover_service/","title":"Test Plan for CAPIF Discover Service","text":"<p>At this documentation you will have all information and related files and examples of test plan for this API.</p>"},{"location":"testing/testplan/api_discover_service/#test-case-1-discover-published-service-apis-by-authorised-api-invoker","title":"Test Case 1: Discover Published service APIs by Authorised API Invoker","text":"<p>Test ID: capif_api_discover_service-1</p> <p>Description:</p> <p>This test case will check if NetApp (Invoker) can discover published service APIs.</p> <p>Pre-Conditions:</p> <ul> <li>Service APIs are published.</li> <li>NetApp was registered previously</li> <li>NetApp was onboarded previously with {onboardingId}</li> </ul> <p>Information of Test:</p> <ol> <li>Perform Provider Registration and Invoker Onboarding</li> <li>Publish Service API at CCF:<ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li>Request Discover Published APIs:<ul> <li>Send GET to https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}</li> <li>Param api-invoker-id is mandatory</li> <li>Use Invoker Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF, store certificates and Publish Service API at CCF</li> <li>Register Invoker and Onboard Invoker at CCF</li> <li>Discover Service APIs by Invoker</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Response to Publish request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow ServiceAPIDescription data structure with:<ul> <li>apiId</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId}</li> </ol> </li> <li> <p>Response to Onboard request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow APIInvokerEnrolmentDetails data structure with:<ul> <li>apiInvokerId</li> <li>onboardingInformation-&gt;apiInvokerCertificate must contain the public key signed.</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}</li> </ol> </li> <li>Response to Discover Request By Invoker:<ol> <li>200 OK response.</li> <li>Response body must follow DiscoveredAPIs data structure:<ul> <li>Check if DiscoveredAPIs contains the API Published previously</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_discover_service/#test-case-2-discover-published-service-apis-by-non-authorised-api-invoker","title":"Test Case 2: Discover Published service APIs by Non Authorised API Invoker","text":"<p>Test ID: capif_api_discover_service-2</p> <p>Description:</p> <p>This test case will check that an API Publisher can't discover published APIs because is not authorized.</p> <p>Pre-Conditions:</p> <ul> <li>Service APIs are published.</li> </ul> <p>Information of Test:</p> <ol> <li>Perform Provider Registration and Invoker Onboarding</li> <li>Publish Service API at CCF:<ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li>Request Discover Published APIs by no invoker entity:<ul> <li>Send GET to https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}</li> <li>Param api-invoker-id is mandatory</li> <li>Use not Invoker Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF, store certificates and Publish Service API at CCF</li> <li>Register Invoker and Onboard Invoker at CCF</li> <li>Discover Service APIs by no invoker entity</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Response to Publish request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow ServiceAPIDescription data structure with:<ul> <li>apiId</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId}</li> </ol> </li> <li> <p>Response to Onboard request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow APIInvokerEnrolmentDetails data structure with:<ul> <li>apiInvokerId</li> <li>onboardingInformation-&gt;apiInvokerCertificate must contain the public key signed.</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}</li> </ol> </li> <li> <p>Response to Discover Request By no invoker entity:</p> <ol> <li>401 Unauthorized</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 401</li> <li>title with message \"Unauthorized\"</li> <li>detail with message \"User not authorized\".</li> <li>cause with message \"Certificate not authorized\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_discover_service/#test-case-3-discover-published-service-apis-by-not-registered-api-invoker","title":"Test Case 3: Discover Published service APIs by not registered API Invoker","text":"<p>Test ID: capif_api_discover_service-3</p> <p>Description:</p> <p>This test case will check that a not registered invoker is forbidden to discover published APIs.</p> <p>Pre-Conditions:</p> <ul> <li>Service APIs are published.</li> </ul> <p>Information of Test:</p> <ol> <li>Perform Provider Registration and Invoker Onboarding</li> <li>Publish Service API at CCF:<ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li>Request Discover Published APIs with not valid apiInvoker:<ul> <li>Send GET to https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={INVOKER_NOT_REGISTERED}</li> <li>Param api-invoker-id is mandatory</li> <li>Using invoker certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF, store certificates and Publish Service API at CCF</li> <li>Register Invoker and Onboard Invoker at CCF</li> <li>Discover Service APIs by Publisher</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Response to Publish request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow ServiceAPIDescription data structure with:<ul> <li>apiId</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId}</li> </ol> </li> <li> <p>Response to Onboard request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow APIInvokerEnrolmentDetails data structure with:<ul> <li>apiInvokerId</li> <li>onboardingInformation-&gt;apiInvokerCertificate must contain the public key signed.</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}</li> </ol> </li> <li> <p>Response to Discover Request By Invoker:</p> <ol> <li>404 Not Found</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"API Invoker does not exist\".</li> <li>cause with message \"API Invoker id not found\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_discover_service/#test-case-4-discover-published-service-apis-by-registered-api-invoker-with-1-result-filtered","title":"Test Case 4: Discover Published service APIs by registered API Invoker with 1 result filtered","text":"<p>Test ID: capif_api_discover_service-4</p> <p>Description:</p> <p>This test case will check if NetApp (Invoker) can discover published service APIs.</p> <p>Pre-Conditions:</p> <ul> <li>At least 2 Service APIs are published.</li> <li>NetApp was registered previously</li> <li>NetApp was onboarded previously with {onboardingId}</li> </ul> <p>Information of Test:</p> <ol> <li>Perform Provider Registration and Invoker Onboarding</li> <li>Publish Service API at CCF:<ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li>Publish Service API at CCF:<ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_2</li> <li>Use APF Certificate</li> </ul> </li> <li>Request Discover Published APIs filtering by api-name:<ul> <li>Send GET to ccf_discover_url https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}&amp;api-name=service_1</li> <li>Param api-invoker-id is mandatory</li> <li>Using invoker certificate</li> <li>filter by api-name service_1</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF, store certificates and Publish Service API service_1 and service_2 at CCF</li> <li>Register Invoker and Onboard Invoker at CCF</li> <li>Discover Service APIs by Invoker.</li> <li>Discover filtered by api-name service_1 Service APIs by Invoker</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Publish request must accomplish:<ol> <li>201 Created</li> <li>Response Body must follow ServiceAPIDescription data structure with:<ul> <li>apiId</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId}</li> </ol> </li> <li>Response to Onboard request must accomplish:<ol> <li>201 Created</li> <li>Response Body must follow APIInvokerEnrolmentDetails data structure with:<ul> <li>apiInvokerId</li> <li>onboardingInformation-&gt;apiInvokerCertificate must contain the public key signed.</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}</li> </ol> </li> <li>Response to Discover Request By Invoker:<ol> <li>200 OK response.</li> <li>Response body must follow DiscoveredAPIs data structure:<ul> <li>Check if DiscoveredAPIs contains previously registered Service APIs published.</li> </ul> </li> </ol> </li> <li>Response to Discover Request By Invoker:<ol> <li>200 OK response.</li> <li>Response body must follow DiscoveredAPIs data structure:<ul> <li>Check if DiscoveredAPIs contains only Service API published with api-name service_1</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_discover_service/#test-case-5-discover-published-service-apis-by-registered-api-invoker-filtered-with-no-match","title":"Test Case 5: Discover Published service APIs by registered API Invoker filtered with no match","text":"<p>Test ID: capif_api_discover_service-5</p> <p>Description:</p> <p>This test case will check if NetApp (Invoker) can discover published service APIs.</p> <p>Pre-Conditions:</p> <ul> <li>At least 2 Service APIs are published.</li> <li>NetApp was registered previously</li> <li>NetApp was onboarded previously with {onboardingId}</li> </ul> <p>Information of Test:</p> <ol> <li>Perform Provider Registration and Invoker Onboarding</li> <li>Publish Service API at CCF:<ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li>Publish Service API at CCF:<ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_2</li> <li>Use APF Certificate</li> </ul> </li> <li>Request Discover Published APIs filtering by api-name not published:<ul> <li>Send GET to ccf_discover_url https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}&amp;api-name=NOT_VALID_NAME</li> <li>Param api-invoker-id is mandatory</li> <li>Using invoker certificate</li> <li>filter by api-name NOT_VALID_NAME</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF, store certificates and Publish Service API service_1 and service_2 at CCF</li> <li>Register Invoker and Onboard Invoker at CCF</li> <li>Discover Service APIs by Invoker.</li> <li>Discover filtered by api-name not published Service APIs by Invoker</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Publish request must accomplish:<ol> <li>201 Created</li> <li>Response Body must follow ServiceAPIDescription data structure with:<ul> <li>apiId</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId}</li> </ol> </li> <li>Response to Onboard request must accomplish:<ol> <li>201 Created</li> <li>Response Body must follow APIInvokerEnrolmentDetails data structure with:<ul> <li>apiInvokerId</li> <li>onboardingInformation-&gt;apiInvokerCertificate must contain the public key signed.</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}</li> </ol> </li> <li>Response to Discover Request By Invoker:<ol> <li>200 OK response.</li> <li>Response body must follow DiscoveredAPIs data structure:<ul> <li>Check if DiscoveredAPIs contains previously registered Service APIs published.</li> </ul> </li> </ol> </li> <li>Response to Discover Request By Invoker:<ol> <li>404 Not Found response.</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"API Invoker {api_invoker_id} has no API Published that accomplish filter conditions\".</li> <li>cause with message \"No API Published accomplish filter conditions\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_discover_service/#test-case-6-discover-published-service-apis-by-registered-api-invoker-not-filtered","title":"Test Case 6: Discover Published service APIs by registered API Invoker not filtered","text":"<p>Test ID: capif_api_discover_service-6</p> <p>Description:</p> <p>This test case will check if NetApp (Invoker) can discover published service APIs.</p> <p>Pre-Conditions:</p> <ul> <li>2 Service APIs are published.</li> <li>NetApp was registered previously</li> <li>NetApp was onboarded previously with {onboardingId}</li> </ul> <p>Information of Test:</p> <ol> <li>Perform Provider Registration and Invoker Onboarding</li> <li>Publish Service API at CCF:<ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li>Publish Service API at CCF:<ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_2</li> <li>Use APF Certificate</li> </ul> </li> <li>Request Discover Published APIs not filtered:<ul> <li>Send GET to ccf_discover_url https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}</li> <li>Param api-invoker-id is mandatory</li> <li>Using invoker certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF, store certificates and Publish Service API service_1 and service_2 at CCF</li> <li>Register Invoker and Onboard Invoker at CCF</li> <li>Discover Service APIs by Invoker.</li> <li>Discover without filter by Invoker</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Response to Publish request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow ServiceAPIDescription data structure with:<ul> <li>apiId</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId}</li> </ol> </li> <li> <p>Response to Onboard request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow APIInvokerEnrolmentDetails data structure with:<ul> <li>apiInvokerId</li> <li>onboardingInformation-&gt;apiInvokerCertificate must contain the public key signed.</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}</li> </ol> </li> <li> <p>Response to Discover Request By Invoker:</p> <ol> <li>200 OK response.</li> <li>Response body must follow DiscoveredAPIs data structure:<ul> <li>Check if DiscoveredAPIs contains the 2 previously registered Service APIs published.</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_events_service/","title":"Test Plan for CAPIF Api Events Service","text":"<p>At this documentation you will have all information and related files and examples of test plan for this API.</p>"},{"location":"testing/testplan/api_events_service/#tests","title":"Tests","text":""},{"location":"testing/testplan/api_events_service/#test-case-1-creates-a-new-individual-capif-event-subscription","title":"Test Case 1: Creates a new individual CAPIF Event Subscription.","text":"<p>Test ID: capif_api_events-1</p> <p>Description:</p> <p>This test case will check that a CAPIF subscriber (Invoker or Publisher) can Subscribe to Events Pre-Conditions:</p> <ul> <li>CAPIF subscriber is pre-authorised (has valid InvokerId or apfId from CAPIF Authority)</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Invoker Onboarding</p> </li> <li> <p>Event Subscription:</p> <ol> <li>Send POST to https://{CAPIF_HOSTNAME}/capif-events/v1/{subscriberId}/subscriptions</li> <li>body event subscription request body</li> <li>Use Invoker Certificate</li> </ol> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Invoker and Onboard Invoker at CCF</li> <li>Subscribe to Events</li> <li>Retrieve {subscriberId} and {subscriptionId} from Location Header</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Response to Onboard request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow APIInvokerEnrolmentDetails data structure with:<ul> <li>apiInvokerId</li> <li>onboardingInformation-&gt;apiInvokerCertificate must contain the public key signed.</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}</li> </ol> </li> <li> <p>Response to Event Subscription must accomplish:</p> <ol> <li>201 Created</li> <li>The URI of the created resource shall be returned in the \"Location\" HTTP header, following this structure: *{apiRoot}/capif-events/{apiVersion}/{subscriberId}/subscriptions/{subscriptionId}</li> <li>Response Body must follow EventSubscription data structure.</li> </ol> </li> <li> <p>Event Subscriptions are stored in CAPIF Database</p> </li> </ol>"},{"location":"testing/testplan/api_events_service/#test-case-2-creates-a-new-individual-capif-event-subscription-with-invalid-subscriberid","title":"Test Case 2: Creates a new individual CAPIF Event Subscription with Invalid SubscriberId","text":"<p>Test ID: capif_api_events-2</p> <p>Description:</p> <p>This test case will check that a CAPIF subscriber (Invoker or Publisher) cannot Subscribe to Events without valid SubcriberId</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF subscriber is not pre-authorised (has invalid InvokerId or apfId)</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Invoker Onboarding</p> </li> <li> <p>Event Subscription:</p> <ol> <li>Send POST to https://{CAPIF_HOSTNAME}/capif-events/v1/{SUBSCRIBER_NOT_REGISTERED}/subscriptions</li> <li>body event subscription request body</li> <li>Use Invoker Certificate</li> </ol> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Invoker and Onboard Invoker at CCF</li> <li>Subscribe to Events</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Response to Onboard request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow APIInvokerEnrolmentDetails data structure with:<ul> <li>apiInvokerId</li> <li>onboardingInformation-&gt;apiInvokerCertificate must contain the public key signed.</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}</li> </ol> </li> <li> <p>Response to Event Subscription must accomplish:</p> <ol> <li>404 Not Found</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Invoker or APF or AEF or AMF Not found\".</li> <li>cause with message \"Subscriber Not Found\".</li> </ul> </li> </ol> </li> <li> <p>Event Subscriptions are not stored in CAPIF Database</p> </li> </ol>"},{"location":"testing/testplan/api_events_service/#test-case-3-deletes-an-individual-capif-event-subscription","title":"Test Case 3: Deletes an individual CAPIF Event Subscription","text":"<p>Test ID: capif_api_events-3</p> <p>Description:</p> <p>This test case will check that a CAPIF subscriber (Invoker or Publisher) can Delete an Event Subscription</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF subscriber is pre-authorised (has valid InvokerId or apfId from CAPIF Authority)</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Invoker Onboarding</p> </li> <li> <p>Event Subscription:</p> <ol> <li>Send POST to https://{CAPIF_HOSTNAME}/capif-events/v1/{subscriberId}/subscriptions</li> <li>body event subscription request body</li> <li>Use Invoker Certificate</li> </ol> </li> <li> <p>Remove Event Subscription:</p> <ol> <li>Send DELETE to https://{CAPIF_HOSTNAME}/capif-events/v1/{subscriberId}/subscriptions</li> <li>Use Invoker Certificate</li> </ol> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Invoker and Onboard Invoker at CCF</li> <li>Subscribe to Events</li> <li>Retrieve {subscriberId} and {subscriptionId} from Location Header</li> <li>Remove Event Subscription</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Response to Onboard request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow APIInvokerEnrolmentDetails data structure with:<ul> <li>apiInvokerId</li> <li>onboardingInformation-&gt;apiInvokerCertificate must contain the public key signed.</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}</li> </ol> </li> <li> <p>Response to Event Subscription must accomplish:</p> <ol> <li>201 Created</li> <li>The URI of the created resource shall be returned in the \"Location\" HTTP header, following this structure: *{apiRoot}/capif-events/{apiVersion}/{subscriberId}/subscriptions/{subscriptionId}</li> <li>Response Body must follow EventSubscription data structure.</li> </ol> </li> <li> <p>Event Subscriptions are stored in CAPIF Database</p> </li> <li> <p>Remove Event Subscription:</p> <ol> <li>204 No Content</li> </ol> </li> <li> <p>Event Subscription is not present at CAPIF Database.</p> </li> </ol>"},{"location":"testing/testplan/api_events_service/#test-case-4-deletes-an-individual-capif-event-subscription-with-invalid-subscriberid","title":"Test Case 4: Deletes an individual CAPIF Event Subscription with invalid SubscriberId","text":"<p>Test ID: capif_api_events-4</p> <p>Description:</p> <p>This test case will check that a CAPIF subscriber (Invoker or Publisher) cannot Delete to Events without valid SubcriberId</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF subscriber is pre-authorised (has valid InvokerId or apfId).</li> <li>CAPIF subscriber is subscribed to Events.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Invoker Onboarding</p> </li> <li> <p>Event Subscription:</p> <ol> <li>Send POST to https://{CAPIF_HOSTNAME}/capif-events/v1/{subscriberId}/subscriptions</li> <li>body event subscription request body</li> <li>Use Invoker Certificate</li> </ol> </li> <li> <p>Remove Event Subcription with not valid subscriber:</p> <ol> <li>Send DELETE to to https://{CAPIF_HOSTNAME}/capif-events/v1/{SUBSCRIBER_ID_NOT_VALID}/subscriptions/{subcriptionId}</li> <li>Use Invoker Certificate</li> </ol> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Invoker and Onboard Invoker at CCF</li> <li>Subscribe to Events</li> <li>Retrieve Location Header with subscriptionId.</li> <li>Remove Event Subscribed with not valid Subscriber.</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Response to Onboard request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow APIInvokerEnrolmentDetails data structure with:<ul> <li>apiInvokerId</li> <li>onboardingInformation-&gt;apiInvokerCertificate must contain the public key signed.</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}</li> </ol> </li> <li> <p>Response to Event Subscription must accomplish:</p> <ol> <li>201 Created</li> <li>The URI of the created resource shall be returned in the \"Location\" HTTP header, following this structure: *{apiRoot}/capif-events/{apiVersion}/{subscriberId}/subscriptions/{subscriptionId}</li> <li>Response Body must follow EventSubscription data structure.</li> </ol> </li> <li> <p>Event Subscriptions are stored in CAPIF Database</p> </li> <li>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\".</li> </ol>"},{"location":"testing/testplan/api_events_service/#test-case-5-deletes-an-individual-capif-event-subscription-with-invalid-subscriptionid","title":"Test Case 5: Deletes an individual CAPIF Event Subscription with invalid SubscriptionId","text":"<p>Test ID: capif_api_events-5</p> <p>Description:</p> <p>This test case will check that a CAPIF subscriber (Invoker or Publisher) cannot Delete an Event Subscription without valid SubscriptionId</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF subscriber is pre-authorised (has invalid InvokerId or apfId).</li> <li>CAPIF subscriber is subscribed to Events.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Invoker Onboarding</p> </li> <li> <p>Event Subscription:</p> <ol> <li>Send POST to https://{CAPIF_HOSTNAME}/capif-events/v1/{subscriberId}/subscriptions</li> <li>body event subscription request body</li> <li>Use Invoker Certificate</li> </ol> </li> <li> <p>Remove Event Subcription with not valid subscriber:</p> <ol> <li>Send DELETE to to https://{CAPIF_HOSTNAME}/capif-events/v1/{subcriberId}/subscriptions/{SUBSCRIPTION_ID_NOT_VALID}</li> <li>Use Invoker Certificate</li> </ol> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Invoker and Onboard Invoker at CCF</li> <li>Subscribe to Events</li> <li>Retrieve Location Header with subscriptionId.</li> <li>Remove Event Subscribed with not valid Subscriber.</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Response to Onboard request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow APIInvokerEnrolmentDetails data structure with:<ul> <li>apiInvokerId</li> <li>onboardingInformation-&gt;apiInvokerCertificate must contain the public key signed.</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}</li> </ol> </li> <li> <p>Response to Event Subscription must accomplish:</p> <ol> <li>201 Created</li> <li>The URI of the created resource shall be returned in the \"Location\" HTTP header, following this structure: *{apiRoot}/capif-events/{apiVersion}/{subscriberId}/subscriptions/{subscriptionId}</li> <li>Response Body must follow EventSubscription data structure.</li> </ol> </li> <li> <p>Event Subscriptions are stored in CAPIF Database</p> </li> <li>Remove Event Subscription with not valid subscriber:<ol> <li>404 Not Found</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 404</li> <li>detail with message \"Service API not existing\".</li> <li>cause with message \"Event API subscription id not found\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_invoker_management/","title":"Test Plan for CAPIF Api Invoker Management","text":"<p>At this documentation you will have all information and related files and examples of test plan for this API.</p>"},{"location":"testing/testplan/api_invoker_management/#test-case-1-onboard-netapp","title":"Test Case 1: Onboard NetApp","text":"<p>Test ID: capif_api_invoker_management-1</p> <p>Description:</p> <p>This test will try to register new NetApp at CAPIF Core.</p> <p>Pre-Conditions:</p> <ul> <li>NetApp was not registered previously</li> <li>NetApp was not onboarded previously</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Create public and private key at invoker</p> </li> <li> <p>Register of Invoker at CCF:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}:{CAPIF_HTTP_PORT}/register </li> <li>body invoker register body</li> </ul> </li> <li> <p>Obtain Access Token:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}/getauth</li> <li>Body invoker getauth body</li> </ul> </li> <li> <p>Onboard Invoker:</p> <ul> <li>Send POST to https://{CAPIF_HOSTNAME}/api-invoker-management/v1/onboardedInvokers</li> <li>Reference Request Body: invoker onboarding body</li> <li>\"onboardingInformation\"-&gt;\"apiInvokerPublicKey\": must contain public key generated by Invoker.</li> <li>Send at Authorization Header the Bearer access_token obtained previously (Authorization:Bearer ${access_token})</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Invoker at CCF</li> <li>Onboard Invoker at CCF</li> <li>Store signed Certificate</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Onboard request must accomplish:<ol> <li>201 Created</li> <li>Response Body must follow APIInvokerEnrolmentDetails data structure with:<ul> <li>apiInvokerId</li> <li>onboardingInformation-&gt;apiInvokerCertificate must contain the public key signed.</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}</li> </ol> </li> </ol>"},{"location":"testing/testplan/api_invoker_management/#test-case-2-onboard-netapp-already-onboarded","title":"Test Case 2: Onboard NetApp Already onboarded","text":"<p>Test ID: capif_api_invoker_management-2</p> <p>Description:</p> <p>This test will check second onboard of same NetApp is not allowed.</p> <p>Pre-Conditions:</p> <ul> <li>NetApp was registered previously</li> <li>NetApp was onboarded previously</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Invoker Onboarding</p> </li> <li> <p>Repeat Onboard Invoker:</p> <ul> <li>Send POST to https://{CAPIF_HOSTNAME}/api-invoker-management/v1/onboardedInvokers</li> <li>Reference Request Body: invoker onboarding body</li> <li>\"onboardingInformation\"-&gt;\"apiInvokerPublicKey\": must contain public key generated by Invoker.</li> <li>Send at Authorization Header the Bearer access_token obtained previously (Authorization:Bearer ${access_token})</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register NetApp at CCF</li> <li>Onboard NetApp at CCF</li> <li>Store signed Certificate at NetApp</li> <li>Onboard Again the NetApp at CCF</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Onboard request must accomplish:<ol> <li>201 Created</li> <li>Response Body must follow APIInvokerEnrolmentDetails data structure with:<ul> <li>apiInvokerId</li> <li>onboardingInformation-&gt;apiInvokerCertificate must contain the public key signed.</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}</li> </ol> </li> <li>Response to Second Onboard of NetApp must accomplish:<ol> <li>403 Forbidden</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 403</li> <li>title with message \"Forbidden\"</li> <li>detail with message \"Invoker Already registered\".</li> <li>cause with message \"Identical invoker public key\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_invoker_management/#test-case-3-update-onboarded-netapp","title":"Test Case 3: Update Onboarded NetApp","text":"<p>Test ID: capif_api_invoker_management-3</p> <p>Description:</p> <p>This test will try to update information of previous onboard NetApp at CAPIF Core.</p> <p>Pre-Conditions:</p> <ul> <li>NetApp was registered previously</li> <li>NetApp was onboarded previously with {onboardingId}</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Invoker Onboarding</p> </li> <li> <p>Update information of previously onboarded Invoker:</p> <ul> <li>Send PUT to https://{CAPIF_HOSTNAME}/api-invoker-management/v1/onboardedInvokers/{onboardingId}</li> <li>Reference Request Body is: [put invoker onboarding body]</li> <li>\"notificationDestination\": \"http://host.docker.internal:8086/netapp_new_callback\",</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Invoker at CCF</li> <li>Onboard Invoker at CCF</li> <li>Store signed Certificate</li> <li>Update Onboarding Information at CCF with a minor change on \"notificationDestination\"</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Onboard request must accomplish:<ol> <li>201 Created</li> <li>Response Body must follow APIInvokerEnrolmentDetails data structure with:<ul> <li>apiInvokerId</li> <li>onboardingInformation-&gt;apiInvokerCertificate must contain the public key signed.</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}</li> </ol> </li> <li>Response to Update Request (PUT) with minor change must contain:<ol> <li>200 OK response.</li> <li>notificationDestination on response must contain the new value</li> </ol> </li> </ol>"},{"location":"testing/testplan/api_invoker_management/#test-case-4-update-not-onboarded-netapp","title":"Test Case 4: Update Not Onboarded NetApp","text":"<p>Test ID: capif_api_invoker_management-4</p> <p>Description:</p> <p>This test will try to update information of not onboarded NetApp at CAPIF Core.</p> <p>Pre-Conditions:</p> <ul> <li>NetApp was registered previously</li> <li>NetApp was not onboarded previously</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Invoker Onboarding</p> </li> <li> <p>Update information of not onboarded Invoker:</p> <ul> <li>Send PUT to https://{CAPIF_HOSTNAME}/api-invoker-management/v1/onboardedInvokers/{INVOKER_NOT_REGISTERED}</li> <li>Reference Request Body is: [put invoker onboarding body]</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Invoker at CCF</li> <li>Onboard Invoker at CCF</li> <li>Update Onboarding Information at CCF of not onboarded</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Onboard request must accomplish:<ol> <li>201 Created</li> </ol> </li> <li>Response to Update Request (PUT) must contain:<ol> <li>404 Not Found</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Please provide an existing Netapp ID\".</li> <li>cause with message \"Not exist NetappID\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_invoker_management/#test-case-5-offboard-netapp","title":"Test Case 5: Offboard NetApp","text":"<p>Test ID: capif_api_invoker_management-5</p> <p>Description:</p> <p>This test case will check that a Registered NetApp can be deleted.</p> <p>Pre-Conditions:</p> <ul> <li>NetApp was registered previously</li> <li>NetApp was onboarded previously</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Invoker Onboarding</p> </li> <li> <p>Offboard:</p> <ul> <li>Send Delete to https://{CAPIF_HOSTNAME}/api-invoker-management/v1/onboardedInvokers/{onboardingId}</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Invoker at CCF</li> <li>Onboard Invoker at CCF</li> <li>Offboard Invoker at CCF</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Onboard request must accomplish:<ol> <li>201 Created</li> </ol> </li> <li>Response to Offboard Request (DELETE) must contain:<ol> <li>204 No Content</li> </ol> </li> </ol>"},{"location":"testing/testplan/api_invoker_management/#test-case-6-offboard-not-previsouly-onboarded-netapp","title":"Test Case 6: Offboard Not previsouly Onboarded NetApp","text":"<p>Test ID: capif_api_invoker_management-6</p> <p>Description:</p> <p>This test case will check that a Non-Registered NetApp cannot be deleted</p> <p>Pre-Conditions:</p> <ul> <li>NetApp was registered previously</li> <li>NetApp was not onboarded previously</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Invoker Onboarding</p> </li> <li> <p>Offboard:</p> <ul> <li>Send Delete to https://{CAPIF_HOSTNAME}/api-invoker-management/v1/onboardedInvokers/{INVOKER_NOT_REGISTERED}</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Invoker at CCF</li> <li>Offboard Invoker at CCF</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Offboard Request (DELETE) must contain:<ol> <li>404 Not Found</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Please provide an existing Netapp ID\".</li> <li>cause with message \"Not exist NetappID\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_invoker_management/#test-case-7-update-onboarded-netapp-certificate","title":"Test Case 7: Update Onboarded NetApp Certificate","text":"<p>Test ID: capif_api_invoker_management-7</p> <p>Description:</p> <p>This test will try to update public key and get a new signed certificate by CAPIF Core.</p> <p>Pre-Conditions:</p> <ul> <li>NetApp was registered previously</li> <li>NetApp was onboarded previously with {onboardingId} and {public_key_1}</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Invoker Onboarding with public_key_1.</p> </li> <li> <p>Create {public_key_2}</p> </li> <li> <p>Update information of previously onboarded Invoker:</p> <ul> <li>Send PUT to https://{CAPIF_HOSTNAME}/api-invoker-management/v1/onboardedInvokers/{onboardingId}</li> <li>Reference Request Body is: [put invoker onboarding body]</li> <li>[\"onboardingInformation\"][\"apiInvokerPublicKey\"]: {public_key_2},</li> <li>Store new certificate.</li> </ul> </li> <li> <p>Update information of previously onboarded Invoker Using new certificate:</p> <ul> <li>Send PUT to https://{CAPIF_HOSTNAME}/api-invoker-management/v1/onboardedInvokers/{onboardingId}</li> <li>Reference Request Body is: [put invoker onboarding body]</li> <li>\"notificationDestination\": \"http://host.docker.internal:8086/netapp_new_callback\",</li> <li>Use new invoker certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Invoker at CCF</li> <li>Onboard Invoker at CCF</li> <li>Store signed Certificate</li> <li>Update Onboarding Information at CCF with new public key</li> <li>Update Onboarding Information at CCF with minor change</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Onboard request must accomplish:<ol> <li>201 Created</li> <li>Response Body must follow APIInvokerEnrolmentDetails data structure with:<ul> <li>apiInvokerId</li> <li>onboardingInformation-&gt;apiInvokerCertificate must contain the public key signed.</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}</li> </ol> </li> <li>Response to Update Request (PUT) with new public key:<ol> <li>200 OK response.</li> <li>apiInvokerCertificate with new certificate on response -&gt; store to use.</li> </ol> </li> <li>Response to Update Request (PUT) with minor change must contain:<ol> <li>200 OK response.</li> <li>notificationDestination on response must contain the new value</li> </ol> </li> </ol>"},{"location":"testing/testplan/api_logging_service/","title":"Test Plan for CAPIF Api Logging Service","text":"<p>At this documentation you will have all information and related files and examples of test plan for this API.</p>"},{"location":"testing/testplan/api_logging_service/#test-case-1-creates-a-new-individual-capif-log-entry","title":"Test Case 1: Creates a new individual CAPIF Log Entry.","text":"<p>Test ID: capif_api_logging-1</p> <p>Description:</p> <p>This test case will check that a CAPIF AEF can create log entry to Logging Service</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF provider is pre-authorised (has valid aefId from CAPIF Authority)</li> <li>Service exist in CAPIF</li> <li>Invoker exist in CAPIF</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform provider onboarding and invoker onboarding</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body [service api description] with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Log Entry:</p> <ol> <li>Send POST to https://{CAPIF_HOSTNAME}/api-invocation-logs/v1/{aefId}/logs</li> <li>body log entry request body</li> <li>Use AEF Certificate</li> </ol> </li> </ol> <p>Execution Steps:   1. Register Provider and Invoker CCF   2. Publish Service   3. Create Log Entry</p> <p>Expected Result:</p> <ol> <li>Response to Logging Service must accomplish:<ol> <li>201 Created</li> <li>Response Body must follow InvocationLog data structure with:<ul> <li>aefId</li> <li>apiInvokerId</li> <li>logs</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/api-invocation-logs/v1/{aefId}/logs/{logId}</li> </ol> </li> </ol>"},{"location":"testing/testplan/api_logging_service/#test-case-2-creates-a-new-individual-capif-log-entry-with-invalid-aefid","title":"Test Case 2:  Creates a new individual CAPIF Log Entry with Invalid aefId","text":"<p>Test ID: capif_api_logging-2</p> <p>Description:</p> <p>This test case will check that a CAPIF subscriber (AEF) cannot create Log Entry without valid aefId</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF provider is not pre-authorised (has not valid aefId from CAPIF Authority)</li> <li>Service exist in CAPIF</li> <li>Invoker exist in CAPIF</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform provider onboarding and invoker onboarding</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body [service api description] with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Log Entry:</p> <ol> <li>Send POST to https://{CAPIF_HOSTNAME}/api-invocation-logs/v1/{not-valid-aefId}/logs</li> <li>body log entry request body</li> <li>Use AEF Certificate</li> </ol> </li> </ol> <p>Execution Steps:   1. Register Provider and Invoker CCF   2. Publish Service   3. Create Log Entry</p> <p>Expected Result:</p> <ol> <li>Response to Logging Service must accomplish:<ol> <li>404 Not Found</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Exposer not exist\".</li> <li>cause with message \"Exposer id not found\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_logging_service/#test-case-3-creates-a-new-individual-capif-log-entry-with-invalid-serviceapi","title":"Test Case 3:  Creates a new individual CAPIF Log Entry with Invalid serviceAPI","text":"<p>Test ID: capif_api_logging-3</p> <p>Description:</p> <p>This test case will check that a CAPIF subscriber (AEF) cannot create Log Entry without valid aefId</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF subscriber is pre-authorised (has valid aefId from CAPIF Authority)</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform provider onboarding and invoker onboarding</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body [service api description] with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Log Entry:</p> <ol> <li>Send POST to https://{CAPIF_HOSTNAME}/api-invocation-logs/v1/{aefId}/logs</li> <li>body [log entry request body with serviceAPI apiName apiId not valid]</li> <li>Use AEF Certificate</li> </ol> </li> </ol> <p>Execution Steps:   1. Register Provider and Invoker CCF   2. Publish Service   3. Create Log Entry</p> <p>Expected Result:</p> <ol> <li>Response to Logging Service must accomplish:<ol> <li>404 Not Found</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Invoker not exist\".</li> <li>cause with message \"Invoker id not found\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_logging_service/#test-case-4-creates-a-new-individual-capif-log-entry-with-invalid-apiinvokerid","title":"Test Case 4:  Creates a new individual CAPIF Log Entry with Invalid apiInvokerId","text":"<p>Test ID: capif_api_logging-4</p> <p>Description:</p> <p>This test case will check that a CAPIF subscriber (AEF) cannot create Log Entry without valid aefId</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF subscriber is pre-authorised (has valid aefId from CAPIF Authority)</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform provider onboarding and invoker onboarding</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body [service api description] with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Log Entry:</p> <ol> <li>Send POST to https://{CAPIF_HOSTNAME}/api-invocation-logs/v1/{aefId}/logs</li> <li>body [log entry request body with invokerId not valid]</li> <li>Use AEF Certificate</li> </ol> </li> </ol> <p>Execution Steps:   1. Register Provider and Invoker CCF   2. Publish Service   3. Create Log Entry</p> <p>Expected Result:</p> <ol> <li> <p>Response to Onboard request must accomplish:</p> <ol> <li>201 Created response.</li> <li>body returned must accomplish APIProviderEnrolmentDetails data structure.</li> <li>For each apiProvFuncs, we must check:<ol> <li>apiProvFuncId is set</li> <li>apiProvCert under regInfo is set properly</li> </ol> </li> <li>Location Header must contain the new resource URL {apiRoot}/api-provider-management/v1/registrations/{registrationId}</li> </ol> </li> <li> <p>Response to Logging Service must accomplish:</p> <ol> <li>404 Not Found</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Invoker not exist\".</li> <li>cause with message \"Invoker id not found\".</li> </ul> </li> </ol> </li> <li> <p>Log Entry are not stored in CAPIF Database</p> </li> </ol>"},{"location":"testing/testplan/api_logging_service/#test-case-5-creates-a-new-individual-capif-log-entry-with-invalid-aefid-in-body","title":"Test Case 5:  Creates a new individual CAPIF Log Entry with Invalid aefId in body","text":"<p>Test ID: capif_api_logging-5</p> <p>Description:</p> <p>This test case will check that a CAPIF subscriber (AEF) cannot create Log Entry without valid aefId in body</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF provider is pre-authorised (has valid apfId from CAPIF Authority)</li> <li>Service exist in CAPIF</li> <li>Invoker exist in CAPIF</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform provider onboarding and invoker onboarding</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body [service api description] with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Log Entry:</p> <ol> <li>Send POST to https://{CAPIF_HOSTNAME}/api-invocation-logs/v1/{aefId}/logs</li> <li>body [log entry request body with bad aefId] </li> <li>Use AEF Certificate</li> </ol> </li> </ol> <p>Execution Steps:   1. Register Provider and Invoker CCF   2. Publish Service   3. Create Log Entry</p> <p>Expected Result:</p> <ol> <li>Response to Logging Service must accomplish:<ol> <li>401 Unauthorized</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 401</li> <li>title with message \"Unauthorized\"</li> <li>detail with message \"AEF id not matching in request and body\".</li> <li>cause with message \"Not identical AEF id\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_provider_management/","title":"Test Plan for CAPIF Api Provider Management","text":"<p>At this documentation you will have all information and related files and examples of test plan for this API.</p>"},{"location":"testing/testplan/api_provider_management/#test-case-1-register-api-provider","title":"Test Case 1: Register Api Provider","text":"<p>Test ID: capif_api_provider_management-1</p> <p>Description:</p> <p>This test case will check that Api Provider can be registered con CCF</p> <p>Pre-Conditions:</p> <ul> <li>Provider is pre-authorised (has valid certificate from CAPIF Authority)</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Create public and private key at provider for provider itself and each function (apf, aef and amf)</p> </li> <li> <p>Register of Provider at CCF:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}:{CAPIF_HTTP_PORT}/register</li> <li>body provider register body</li> </ul> </li> <li> <p>Obtain Access Token:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}/getauth</li> <li>Body provider getauth body</li> </ul> </li> <li> <p>Register Provider:</p> <ul> <li>Send POST https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations</li> <li>body provider request body</li> <li>Authentication Bearer with access_token</li> <li>Store each cert in a file with according name.</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Create private and public key for provider and each function to register.</li> <li>Register Provider.</li> </ol> <p>Expected Result:</p> <ol> <li>Register Provider at Provider Management:<ol> <li>201 Created response.</li> <li>body returned must accomplish APIProviderEnrolmentDetails data structure.</li> <li>For each apiProvFuncs, we must check:<ol> <li>apiProvFuncId is set</li> <li>apiProvCert under regInfo is set properly</li> </ol> </li> <li>Location Header must contain the new resource URL {apiRoot}/api-provider-management/v1/registrations/{registrationId}</li> </ol> </li> </ol>"},{"location":"testing/testplan/api_provider_management/#test-case-2-register-api-provider-already-registered","title":"Test Case 2: Register Api Provider Already registered","text":"<p>Test ID: capif_api_provider_management-2</p> <p>Description:</p> <p>This test case will check that a Api Provider previously registered cannot be re-registered</p> <p>Pre-Conditions:</p> <ul> <li>Api Provider was registered previously and there is a {registerId} for his Api Provider in the DB</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Create public and private key at provider for provider itself and each function (apf, aef and amf)</p> </li> <li> <p>Register of Provider at CCF:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}:{CAPIF_HTTP_PORT}/register</li> <li>body provider register body</li> </ul> </li> <li> <p>Obtain Access Token:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}/getauth</li> <li>Body provider getauth body</li> </ul> </li> <li> <p>Register Provider:</p> <ul> <li>Send POST https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations</li> <li>body provider request body</li> <li>Authentication Bearer with access_token</li> <li>Store each cert in a file with according name.</li> </ul> </li> <li> <p>Re-Register Provider:</p> <ul> <li>Same regSec than Previous registration</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Create private and public key for provider and each function to register.</li> <li>Register Provider.</li> <li>Re-Register Provider.</li> </ol> <p>Expected Result:</p> <ol> <li>Re-Register Provider:<ol> <li>403 Forbidden response.</li> <li>body returned must accomplish ProblemDetails data structure, with:<ul> <li>status 403</li> <li>title with message \"Forbidden\"</li> <li>detail with message \"Provider already registered\".</li> <li>cause with message \"Identical provider reg sec\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_provider_management/#test-case-3-update-registered-api-provider","title":"Test Case 3: Update Registered Api Provider","text":"<p>Test ID: capif_api_provider_management-3</p> <p>Description:</p> <p>This test case will check that a Registered Api Provider can be updated</p> <p>Pre-Conditions:</p> <ul> <li>Api Provider was registered previously and there is a {registerId} for his Api Provider in the DB</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Create public and private key at provider for provider itself and each function (apf, aef and amf)</p> </li> <li> <p>Register of Provider at CCF:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}:{CAPIF_HTTP_PORT}/register</li> <li>body provider register body</li> </ul> </li> <li> <p>Obtain Access Token:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}/getauth</li> <li>Body provider getauth body</li> </ul> </li> <li> <p>Register Provider:</p> <ul> <li>Send POST https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations</li> <li>body provider request body</li> <li>Authentication Bearer with access_token</li> <li>Get Resource URL from Location</li> </ul> </li> <li> <p>Update Provider:</p> <ul> <li>Send PUT to Resource URL returned at registration https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations/{registrationId}</li> <li>body provider request body with apiProvDomInfo set to ROBOT_TESTING_MOD</li> <li>Use AMF Certificate.</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Create private and public key for provider and each function to register.</li> <li>Register Provider</li> <li>Update Provider</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Register Provider:</p> <ol> <li>201 Created response.</li> <li>body returned must accomplish APIProviderEnrolmentDetails data structure.</li> <li>Location Header must contain the new resource URL {apiRoot}/api-provider-management/v1/registrations/{registrationId}</li> </ol> </li> <li> <p>Update Provider:</p> <ol> <li>200 OK response.</li> <li>body returned must accomplish APIProviderEnrolmentDetails data structure, with:<ul> <li>apiProvDomInfo set to ROBOT_TESTING_MOD</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_provider_management/#test-case-4-update-not-registered-api-provider","title":"Test Case 4: Update Not Registered Api Provider","text":"<p>Test ID: capif_api_provider_management-4</p> <p>Description:</p> <p>This test case will check that a Non-Registered Api Provider cannot be updated</p> <p>Pre-Conditions:</p> <ul> <li>Api Provider was not registered previously</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Create public and private key at provider for provider itself and each function (apf, aef and amf)</p> </li> <li> <p>Register of Provider at CCF:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}:{CAPIF_HTTP_PORT}/register</li> <li>body provider register body</li> </ul> </li> <li> <p>Obtain Access Token:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}/getauth</li> <li>Body provider getauth body</li> </ul> </li> <li> <p>Register Provider:</p> <ul> <li>Send POST https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations</li> <li>body provider request body</li> <li>Authentication Bearer with access_token</li> <li>Store each cert in a file with according name.</li> </ul> </li> <li> <p>Update Not Registered Provider:</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations/{API_PROVIDER_NOT_REGISTERED}</li> <li>body provider request body</li> <li>Use AMF Certificate.</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF</li> <li>Update Not Registered Provider</li> </ol> <p>Expected Result:</p> <ol> <li>Update Not Registered Provider:<ol> <li>404 Not Found response.</li> <li>body returned must accomplish ProblemDetails data structure, with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Not Exist Provider Enrolment Details\".</li> <li>cause with message \"Not found registrations to send this api provider details\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_provider_management/#test-case-5-partially-update-registered-api-provider","title":"Test Case 5: Partially Update Registered Api Provider","text":"<p>Test ID: capif_api_provider_management-5</p> <p>Description:</p> <p>This test case will check that a Registered Api Provider can be partially updated</p> <p>Pre-Conditions:</p> <ul> <li>Api Provider was registered previously and there is a {registerId} for his Api Provider in the DB</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Create public and private key at provider for provider itself and each function (apf, aef and amf)</p> </li> <li> <p>Register of Provider at CCF:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}:{CAPIF_HTTP_PORT}/register</li> <li>body provider register body</li> </ul> </li> <li> <p>Obtain Access Token:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}/getauth</li> <li>Body provider getauth body</li> </ul> </li> <li> <p>Register Provider:</p> <ul> <li>Send POST https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations</li> <li>body provider request body</li> <li>Authentication Bearer with access_token</li> <li>Store each cert in a file with according name.</li> </ul> </li> <li> <p>Partial update provider:</p> <ul> <li>Send PATCH https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations/{registrationId}</li> <li>body provider request patch body</li> <li>Use AMF Certificate.</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF</li> <li>Register Provider</li> <li>Partial update provider</li> </ol> <p>Expected Result:</p> <ol> <li>Partial update provider at Provider Management:<ol> <li>200 OK response.</li> <li>body returned must accomplish APIProviderEnrolmentDetails data structure, with:<ul> <li>apiProvDomInfo with \"ROBOT_TESTING_MOD\"</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_provider_management/#test-case-6-partially-update-not-registered-api-provider","title":"Test Case 6: Partially Update Not Registered Api Provider","text":"<p>Test ID: capif_api_provider_management-6</p> <p>Description:</p> <p>This test case will check that a Non-Registered Api Provider cannot be partially updated  </p> <p>Pre-Conditions:</p> <ul> <li>Api Provider was not registered previously</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Create public and private key at provider for provider itself and each function (apf, aef and amf)</p> </li> <li> <p>Register of Provider at CCF:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}:{CAPIF_HTTP_PORT}/register</li> <li>body provider register body</li> </ul> </li> <li> <p>Obtain Access Token:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}/getauth</li> <li>Body provider getauth body</li> </ul> </li> <li> <p>Register Provider:</p> <ul> <li>Send POST https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations</li> <li>body provider request body</li> <li>Authentication Bearer with access_token</li> <li>Store each cert in a file with according name.</li> </ul> </li> <li> <p>Partial update Provider:</p> <ul> <li>Send PATCH https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations/{API_API_PROVIDER_NOT_REGISTERED}</li> <li>body provider request patch body</li> <li>Use AMF Certificate.</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF</li> <li>Register Provider</li> <li>Partial update provider</li> </ol> <p>Expected Result:</p> <ol> <li>Partial update provider:<ol> <li>404 Not Found response.</li> <li>body returned must accomplish ProblemDetails data structure, with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Not Exist Provider Enrolment Details\".</li> <li>cause with message \"Not found registrations to send this api provider details\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_provider_management/#test-case-7-delete-registered-api-provider","title":"Test Case 7: Delete Registered Api Provider","text":"<p>Test ID: capif_api_provider_management-7</p> <p>Description:</p> <p>This test case will check that a Registered Api Provider can be deleted</p> <p>Pre-Conditions:</p> <ul> <li>Api Provider was registered previously</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Create public and private key at provider for provider itself and each function (apf, aef and amf)</p> </li> <li> <p>Register of Provider at CCF:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}:{CAPIF_HTTP_PORT}/register</li> <li>body provider register body</li> </ul> </li> <li> <p>Obtain Access Token:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}/getauth</li> <li>Body provider getauth body</li> </ul> </li> <li> <p>Register Provider:</p> <ul> <li>Send POST https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations</li> <li>body provider request body</li> <li>Authentication Bearer with access_token</li> <li>Store each cert in a file with according name.</li> </ul> </li> <li> <p>Delete registered provider:</p> <ul> <li>Send DELETE https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations/{registrationId}</li> <li>Use AMF Certificate.</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF</li> <li>Register Provider</li> <li>Delete Provider</li> </ol> <p>Expected Result:</p> <ol> <li>Delete Provider:<ol> <li>204 No Content response.</li> </ol> </li> </ol>"},{"location":"testing/testplan/api_provider_management/#test-case-8-delete-not-registered-api-provider","title":"Test Case 8: Delete Not Registered Api Provider","text":"<p>Test ID: capif_api_provider_management-8</p> <p>Description:</p> <p>This test case will check that a Non-Registered Api Provider cannot be deleted</p> <p>Pre-Conditions:</p> <ul> <li>Api Provider was not registered previously</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Create public and private key at provider for provider itself and each function (apf, aef and amf)</p> </li> <li> <p>Register of Provider at CCF:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}:{CAPIF_HTTP_PORT}/register</li> <li>body provider register body</li> </ul> </li> <li> <p>Obtain Access Token:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}/getauth</li> <li>Body provider getauth body</li> </ul> </li> <li> <p>Register Provider:</p> <ul> <li>Send POST https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations</li> <li>body provider request body</li> <li>Authentication Bearer with access_token</li> <li>Store each cert in a file with according name.</li> </ul> </li> <li> <p>Delete registered provider at Provider Management:</p> <ul> <li>Send DELETE https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations/{API_PROVIDER_NOT_REGISTERED}</li> <li>Use AMF Certificate.</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF</li> <li>Delete Provider</li> </ol> <p>Expected Result:</p> <ol> <li>Delete Provider:<ol> <li>404 Not Found response.</li> <li>body returned must accomplish ProblemDetails data structure, with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Not Exist Provider Enrolment Details\".</li> <li>cause with message \"Not found registrations to send this api provider details\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_publish_service/","title":"Test Plan for CAPIF Api Publish Service","text":"<p>At this documentation you will have all information and related files and examples of test plan for this API.</p>"},{"location":"testing/testplan/api_publish_service/#test-case-1-publish-api-by-authorised-api-publisher","title":"Test Case 1: Publish API by Authorised API Publisher","text":"<p>Test ID: capif_api_publish_service-1</p> <p>Description:</p> <p>This test case will check that an API Publisher can Publish an API</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF subscriber is pre-authorised (has valid apfId from CAPIF Authority)</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> </li> <li> <p>Send Post to ccf_publish_url: https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</p> </li> <li>body service api description with apiName service_1</li> <li>Use APF Certificate</li> </ol> <p>Execution Steps:</p> <ol> <li> <p>Register Provider at CCF and store certificates.</p> </li> <li> <p>Publish Service API</p> </li> <li> <p>Retrieve {apiId} from body and Location header with new resource created from response</p> </li> </ol> <p>Expected Result:</p> <ol> <li> <p>Response to Publish request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow ServiceAPIDescription data structure with:<ul> <li>apiId</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId}</li> </ol> </li> <li> <p>Published Service API is stored in CAPIF Database</p> </li> </ol>"},{"location":"testing/testplan/api_publish_service/#test-case-2-publish-api-by-non-authorised-api-publisher","title":"Test Case 2: Publish API by NON Authorised API Publisher","text":"<p>Test ID: capif_api_publish_service-2</p> <p>Description:</p> <p>This test case will check that an API Publisher cannot Publish an API withot valid apfId </p> <p>Pre-Conditions:</p> <ul> <li>CAPIF subscriber is NOT pre-authorised (has invalid apfId from CAPIF Authority)</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API with invalid APF ID at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{APF_ID_NOT_VALID}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF and store certificates.</li> <li>Publish Service API with invalid APF ID</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Response to Publish request must accomplish:</p> <ol> <li>401 Unauthorized</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 401</li> <li>title with message \"Unauthorized\"</li> <li>detail with message \"Publisher not existing\".</li> <li>cause with message \"Publisher id not found\".</li> </ul> </li> </ol> </li> <li> <p>Service API is NOT stored in CAPIF Database</p> </li> </ol>"},{"location":"testing/testplan/api_publish_service/#test-case-3-retrieve-all-apis-published-by-authorised-apfid","title":"Test Case 3: Retrieve all APIs Published by Authorised apfId","text":"<p>Test ID: capif_api_publish_service-3</p> <p>Description:</p> <p>This test case will check that an API Publisher can Retrieve all API published</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF subscriber is pre-authorised (has valid apfId from CAPIF Authority)</li> <li>At least 2 service APIs are published.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Get apiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Publish Other Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_2</li> <li>Get apiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Retrieve all published APIs:</p> <ul> <li>Send Get to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>Use APF Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF and store certificates.</li> <li>Publish Service API service_1</li> <li>Retrieve {apiId1} from body and Location header with new resource created from response</li> <li>Publish Service API service_2</li> <li>Retrieve {apiId2} from body and Location header with new resource created from response</li> <li>Retrieve All published APIs and check if both are present.</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Response to service 1 Publish request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow ServiceAPIDescription data structure with:<ul> <li>apiId</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId1}</li> </ol> </li> <li> <p>Response to service 2 Publish request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow ServiceAPIDescription data structure with:<ul> <li>apiId</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId2}</li> </ol> </li> <li> <p>Published Service APIs are stored in CAPIF Database</p> </li> <li> <p>Response to Retrieve all published APIs:</p> <ol> <li>200 OK</li> <li>Response body must return an array of ServiceAPIDescription data.</li> <li>Array must contain all previously published APIs.</li> </ol> </li> </ol>"},{"location":"testing/testplan/api_publish_service/#test-case-4-retrieve-all-apis-published-by-non-authorised-apfid","title":"Test Case 4: Retrieve all APIs Published by NON Authorised apfId","text":"<p>Test ID: capif_api_publish_service-4</p> <p>Description:</p> <p>This test case will check that an API Publisher cannot Retrieve API published when apfId is not authorised </p> <p>Pre-Conditions:</p> <ul> <li>CAPIF subscriber is NOT pre-authorised (has invalid apfId from CAPIF Authority)</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Retrieve all published APIs:</p> <ul> <li>Send Get to https://{CAPIF_HOSTNAME}/published-apis/v1/{APF_ID_NOT_VALID}/service-apis</li> <li>Use APF Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF and store certificates.</li> <li>Retrieve All published APIs</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Response to Publish request must accomplish:</p> <ol> <li>401 Non Authorized</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 401</li> <li>title with message \"Unauthorized\"</li> <li>detail with message \"Provider not existing\".</li> <li>cause with message \"Provider id not found\".</li> </ul> </li> </ol> </li> <li> <p>Service API is NOT stored in CAPIF Database</p> </li> </ol>"},{"location":"testing/testplan/api_publish_service/#test-case-5-retrieve-single-apis-published-by-authorised-apfid","title":"Test Case 5: Retrieve single APIs Published by Authorised apfId","text":"<p>Test ID: capif_api_publish_service-5</p> <p>Description:</p> <p>This test case will check that an API Publisher can Retrieve API published one by one</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF subscriber is pre-authorised (has valid apfId from CAPIF Authority)</li> <li>At least 2 service APIs are published.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Get apiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Publish Other Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_2</li> <li>Get apiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Retrieve service_1 published APIs detail:</p> <ul> <li>Send Get to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis/{apiId1}</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Retrieve service_2 published APIs detail:</p> <ul> <li>Send Get to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis/{apiId2}</li> <li>Use APF Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF and store certificates.</li> <li>Publish Service API service_1.</li> <li>Retrieve {apiId1} from body and Location header with new resource created from response.</li> <li>Publish Service API service_2.</li> <li>Retrieve {apiId2} from body and Location header with new resource created from response.</li> <li>Retrieve service_1 API Detail.</li> <li>Retrieve service_2 API Detail.</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Response to service 1 Publish request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow ServiceAPIDescription data structure with:<ul> <li>apiId</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId1}</li> </ol> </li> <li> <p>Response to service 2 Publish request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow ServiceAPIDescription data structure with:<ul> <li>apiId</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId2}</li> </ol> </li> <li> <p>Published Service APIs are stored in CAPIF Database</p> </li> <li> <p>Response to Retrieve service_1 published API using apiId1:</p> <ol> <li>200 OK</li> <li>Response body must return a ServiceAPIDescription data.</li> <li>Array must contain same information than service_1 published registration response.</li> </ol> </li> <li> <p>Response to Retrieve service_2 published API using apiId2:</p> <ol> <li>200 OK</li> <li>Response body must return a ServiceAPIDescription data.</li> <li>Array must contain same information than service_2 published registration response.</li> </ol> </li> </ol>"},{"location":"testing/testplan/api_publish_service/#test-case-6-retrieve-single-apis-non-published-by-authorised-apfid","title":"Test Case 6: Retrieve single APIs non Published by Authorised apfId","text":"<p>Test ID: capif_api_publish_service-6</p> <p>Description:</p> <p>This test case will check that an API Publisher try to get detail of not published api.</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF subscriber is pre-authorised (has valid apfId from CAPIF Authority)</li> <li>No published api</li> </ul> <p>Information of Test:</p> <ol> <li>Perform Provider Registration</li> <li>Retrieve not published APIs detail:<ul> <li>Send Get to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis/{SERVICE_API_ID_NOT_VALID}</li> <li>Use APF Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF and store certificates.</li> <li>Retrieve not published API Detail.</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Retrieve for NOT published API must accomplish:<ol> <li>404 Not Found</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Service API not found\".</li> <li>cause with message \"No Service with specific credentials exists\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_publish_service/#test-case-7-retrieve-single-apis-published-by-non-authorised-apfid","title":"Test Case 7: Retrieve single APIs Published by NON Authorised apfId","text":"<p>Test ID: capif_api_publish_service-7</p> <p>Description:</p> <p>This test case will check that an API Publisher cannot Retrieve detailed API published when apfId is not authorised </p> <p>Pre-Conditions:</p> <ul> <li>CAPIF subscriber is NOT pre-authorised (has invalid apfId from CAPIF Authority)</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Get apiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Retrieve detailed published APIs:</p> <ul> <li>Send Get to https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis/${apiId}</li> <li>Use Invoker certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF and store certificates.</li> <li>Publish Service API at CCF</li> <li>Retrieve {apiId} from body and Location header with new resource created from response.</li> <li>Register and onboard Invoker at CCF</li> <li>Store signed Invoker Certificate</li> <li>Retrieve detailed published API acting as Invoker</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Response to Retrieve Detailed published API acting as Invoker must accomplish:</p> <ol> <li>401 Unauthorized</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 401</li> <li>title with message \"Unauthorized\"</li> <li>detail with message \"User not authorized\".</li> <li>cause with message \"Certificate not authorized\".</li> </ul> </li> </ol> </li> <li> <p>Service API is NOT stored in CAPIF Database</p> </li> </ol>"},{"location":"testing/testplan/api_publish_service/#test-case-8-update-api-published-by-authorised-apfid-with-valid-serviceapiid","title":"Test Case 8: Update API Published by Authorised apfId with valid serviceApiId","text":"<p>Test ID: capif_api_publish_service-8</p> <p>Description:</p> <p>This test case will check that an API Publisher can Update published API with a valid serviceApiId </p> <p>Pre-Conditions:</p> <ul> <li>CAPIF subscriber is pre-authorised (has valid apfId from CAPIF Authority)</li> <li>A service APIs is published.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Get apiId</li> <li>get resource url from location Header.</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Update published API at CCF:</p> <ul> <li>Send PUT to resource URL https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis/{serivceApiId}</li> <li>body service api description with overrided apiName to service_1_modified</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Retrieve detail of service API:</p> <ul> <li>Send Get to resource URL https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis/{serivceApiId}</li> <li>check apiName is service_1_modified</li> <li>Use APF Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF and store certificates.</li> <li>Publish Service API</li> <li>Retrieve {apiId} from body and Location header with new resource url created from response</li> <li>Update published Service API.</li> <li>Retrieve detail of Service API</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Response to Publish request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow ServiceAPIDescription data structure with:<ul> <li>apiId</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId}</li> </ol> </li> <li> <p>Response to Update Published Service API:</p> <ol> <li>200 OK</li> <li>Response Body must follow ServiceAPIDescription data structure with:<ul> <li>apiName service_1_modified</li> </ul> </li> </ol> </li> <li> <p>Response to Retrieve detail of Service API:</p> <ol> <li>200 OK</li> <li>Response Body must follow ServiceAPIDescription data structure with:<ul> <li>apiName service_1_modified.</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_publish_service/#test-case-9-update-apis-published-by-authorised-apfid-with-invalid-serviceapiid","title":"Test Case 9: Update APIs Published by Authorised apfId with invalid serviceApiId","text":"<p>Test ID: capif_api_publish_service-9</p> <p>Description:</p> <p>This test case will check that an API Publisher cannot Update published API with a invalid serviceApiId</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF subscriber is pre-authorised (has valid apfId from CAPIF Authority)</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Get apiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Update published API at CCF:</p> <ul> <li>Send PUT to resource URL https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis/{SERVICE_API_ID_NOT_VALID}</li> <li>body service api description with overrided apiName to service_1_modified</li> <li>Use APF Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF and store certificates.</li> <li>Update published Service API.</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Response to Publish request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow ServiceAPIDescription data structure with:<ul> <li>apiId</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId}</li> </ol> </li> <li> <p>Response to Update Published Service API:</p> <ol> <li>404 Not Found</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Service API not found\".</li> <li>cause with message \"Service API id not found\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_publish_service/#test-case-10-update-apis-published-by-non-authorised-apfid","title":"Test Case 10: Update APIs Published by NON Authorised apfId","text":"<p>Test ID: capif_api_publish_service-10</p> <p>Description:</p> <p>This test case will check that an API Publisher cannot Update API published when apfId is not authorised</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF subscriber is NOT pre-authorised (has invalid apfId from CAPIF Authority)</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Get apiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Update published API at CCF:</p> <ul> <li>Send PUT to resource URL https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis/{serviceApiId}</li> <li>body service api description with overrided apiName to service_1_modified</li> <li>Use invoker certificate</li> </ul> </li> <li> <p>Retrieve detail of service API:</p> <ul> <li>Send Get to resource URL https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis/{serivceApiId}</li> <li>check apiName is service_1</li> <li>Use APF Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF and store certificates.</li> <li>Publish Service API at CCF</li> <li>Retrieve {apiId} from body and Location header with new resource created from response.</li> <li>Register and onboard Invoker at CCF</li> <li>Store signed Invoker Certificate</li> <li>Update published API at CCF as Invoker</li> <li>Retrieve detail of Service API as publisher</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Response to Update published API acting as Invoker must accomplish:</p> <ol> <li>401 Unauthorized</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 401</li> <li>title with message \"Unauthorized\"</li> <li>detail with message \"User not authorized\".</li> <li>cause with message \"Certificate not authorized\".</li> </ul> </li> </ol> </li> <li> <p>Response to Retrieve Detail of Service API:</p> <ol> <li>200 OK</li> <li>Response Body must follow ServiceAPIDescription data structure with:<ul> <li>apiName service_1.</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_publish_service/#test-case-11-delete-api-published-by-authorised-apfid-with-valid-serviceapiid","title":"Test Case 11: Delete API Published by Authorised apfId with valid serviceApiId","text":"<p>Test ID: capif_api_publish_service-11</p> <p>Description:</p> <p>This test case will check that an API Publisher can Delete published API with a valid serviceApiId</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF subscriber is pre-authorised (has valid apfId from CAPIF Authority).</li> <li>A service APIs is published.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Get apiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Remove published Service API at CCF:</p> <ul> <li>Send DELETE to resource URL https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis/{serviceApiId}</li> <li>Use APF Certificate</li> </ul> </li> <li>Retrieve detail of service API:<ul> <li>Send Get to resource URL https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis/{serivceApiId}</li> <li>Use APF Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF and store certificates.</li> <li>Publish Service API</li> <li>Retrieve {apiId} from body and Location header with new resource created from response</li> <li>Remove published API at CCF</li> <li>Try to retreive deleted service API from CCF</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Response to Publish request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow ServiceAPIDescription data structure with:<ul> <li>apiId</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId}</li> </ol> </li> <li> <p>Published Service API is stored in CAPIF Database</p> </li> <li> <p>Response to Remove published Service API at CCF:</p> <ol> <li>204 No Content</li> </ol> </li> <li> <p>Response to Retrieve for DELETED published API must accomplish:</p> <ol> <li>404 Not Found</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Service API not found\".</li> <li>cause with message \"No Service with specific credentials exists\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_publish_service/#test-case-12-delete-apis-published-by-authorised-apfid-with-invalid-serviceapiid","title":"Test Case 12: Delete APIs Published by Authorised apfId with invalid serviceApiId","text":"<p>Test ID: capif_api_publish_service-12</p> <p>Description:</p> <p>This test case will check that an API Publisher cannot Delete with invalid serviceApiId</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF subscriber is pre-authorised (has valid apfId from CAPIF Authority).</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Remove published Service API at CCF with invalid serviceId:</p> <ul> <li>Send DELETE to resource URL https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis/{SERVICE_API_ID_NOT_VALID}</li> <li>Use APF Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF and store certificates.</li> <li>Remove published API at CCF with invalid serviceId</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Remove published Service API at CCF:<ol> <li>404 Not Found</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Service API not found\".</li> <li>cause with message \"Service API id not found\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_publish_service/#test-case-13-delete-apis-published-by-non-authorised-apfid","title":"Test Case 13: Delete APIs Published by NON Authorised apfId","text":"<p>Test ID: capif_api_publish_service-12</p> <p>Description:</p> <p>This test case will check that an API Publisher cannot Delete API published when apfId is not authorised</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF subscriber is pre-authorised (has valid apfId from CAPIF Authority).</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Get apiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Remove published Service API at CCF with invalid serviceId as Invoker:</p> <ul> <li>Send DELETE to resource URL https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis/{SERVICE_API_ID_NOT_VALID}</li> <li>Use invoker certificate.</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF and store certificates.</li> <li>Register Invoker and onboard Invoker at CCF</li> <li>Remove published API at CCF with invalid serviceId as Invoker</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Remove published Service API at CCF:<ol> <li>401 Unauthorized</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 401</li> <li>title with message \"Unauthorized\"</li> <li>detail with message \"User not authorized\".</li> <li>cause with message \"Certificate not authorized\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/","title":"Test Plan for CAPIF Api Security Service","text":"<p>At this documentation you will have all information and related files and examples of test plan for this API.</p>"},{"location":"testing/testplan/api_security_service/#test-case-1-create-a-security-context-for-an-api-invoker","title":"Test Case 1: Create a security context for an API invoker","text":"<p>Test ID: capif_security_api-1</p> <p>Description:</p> <p>This test case will check that an API Invoker can create a Security context</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised (has valid apiInvokerID from CAPIF Authority)</li> </ul> <p>Information of Test:</p> <ol> <li>Perform Invoker Onboarding</li> <li>Create Security Context for this Invoker<ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Use Invoker Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Invoker at CCF</li> <li>Store signed Certificate</li> <li>Create Security Context</li> </ol> <p>Expected Result:</p> <ol> <li>Create security context:<ol> <li>201 Created response.</li> <li>body returned must accomplish ServiceSecurity data structure.</li> <li>Location Header must contain the new resource URL {apiRoot}/capif-security/v1/trustedInvokers/{apiInvokerId}</li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-2-create-a-security-context-for-an-api-invoker-with-provider-role","title":"Test Case 2: Create a security context for an API invoker with Provider role","text":"<p>Test ID:: capif_security_api-2</p> <p>Description:</p> <p>This test case will check that an Provider cannot create a Security context with valid apiInvokerId.</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised (has valid apiInvokerID), but user that create Security Context with Provider role</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Create Security Context for this Invoker but using Provider certificate.</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Using AEF certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Invoker at CCF</li> <li>Register Provider at CCF</li> <li>Create Security Context using Provider certificate</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Create security context using Provider certificate:</p> <ol> <li>401 Unauthorized response.</li> <li>body returned must accomplish ProblemDetails data structure, with:<ul> <li>status 401</li> <li>title with message \"Unauthorized\"</li> <li>detail with message \"Role not authorized for this API route\".</li> <li>cause with message \"User role must be invoker\".</li> </ul> </li> </ol> </li> <li> <p>No context stored at DB</p> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-3-create-a-security-context-for-an-api-invoker-with-provider-entity-role-and-invalid-apiinvokerid","title":"Test Case 3: Create a security context for an API invoker with Provider entity role and invalid apiInvokerId","text":"<p>Test ID:: capif_security_api-3</p> <p>Description:</p> <p>This test case will check that an Provider cannot create a Security context with invalid apiInvokerID.</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised (has valid apiInvokerID), but user that create Security Context with Provider role</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Create Security Context for this not valid apiInvokerId and using Provider certificate.</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{API_INVOKER_NOT_VALID}</li> <li>body service security body</li> <li>Using AEF certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF</li> <li>Create Security Context using Provider certificate</li> </ol> <p>Expected Result:</p> <ol> <li>Create security context using Provider certificate:<ol> <li>401 Unauthorized response.</li> <li>body returned must accomplish ProblemDetails data structure, with:<ul> <li>status 401</li> <li>title with message \"Unauthorized\"</li> <li>detail with message \"Role not authorized for this API route\".</li> <li>cause with message \"User role must be invoker\".</li> </ul> </li> </ol> </li> <li>No context stored at DB</li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-4-create-a-security-context-for-an-api-invoker-with-invoker-entity-role-and-invalid-apiinvokerid","title":"Test Case 4: Create a security context for an API invoker with Invoker entity role and invalid apiInvokerId","text":"<p>Test ID:: capif_security_api-4</p> <p>Description:</p> <p>This test case will check that an Invoker cannot create a Security context with valid apiInvokerId.</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised (has valid apiInvokerID), but user that create Security Context with invalid apiInvokerId</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Invoker Onboarding</p> </li> <li> <p>Create Security Context for this Invoker:</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{API_INVOKER_NOT_VALID}</li> <li>body service security body</li> <li>Use Invoker Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Invoker at CCF</li> <li>Create Security Context using Provider certificate</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Create security context using Provider certificate:</p> <ol> <li>404 Not Found response.</li> <li>body returned must accomplish ProblemDetails data structure, with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Invoker not found\".</li> <li>cause with message \"API Invoker not exists or invalid ID\".</li> </ul> </li> </ol> </li> <li> <p>No context stored at DB</p> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-5-retrieve-the-security-context-of-an-api-invoker","title":"Test Case 5: Retrieve the Security Context of an API Invoker","text":"<p>Test ID:: capif_security_api-5</p> <p>Description:</p> <p>This test case will check that an provider can retrieve the Security context of an API Invoker</p> <p>Pre-Conditions:</p> <ul> <li>Provider is pre-authorised (has valid apfId from CAPIF Authority) and API Invoker has created a valid Security Context</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Create Security Context for this Invoker.</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Using Invoker certificate</li> </ul> </li> <li> <p>Retrieve Security Context of Invoker by Provider:</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>Using AEF Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Invoker at CCF</li> <li>Register Provider at CCF</li> <li>Create Security Context using Provider certificate</li> <li>Retrieve Security Context by Provider</li> </ol> <p>Expected Result:</p> <ol> <li>Retrieve security context:<ol> <li>200 OK response.</li> <li>body returned must accomplish ServiceSecurity data structure.</li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-6-retrieve-the-security-context-of-an-api-invoker-with-invalid-apiinvokerid","title":"Test Case 6: Retrieve the Security Context of an API Invoker with invalid apiInvokerID","text":"<p>Test ID:: capif_security_api-6</p> <p>Description:</p> <p>This test case will check that an provider can retrieve the Security context of an API Invoker</p> <p>Pre-Conditions:</p> <ul> <li>Provider is pre-authorised (has valid apfId from CAPIF Authority) and API Invoker has created a valid Security Context</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Retrieve Security Context of invalid Invoker by Provider:</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/trustedInvokers/{API_INVOKER_NOT_VALID}</li> <li>Using AEF Certificate.</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF</li> <li>Create Security Context using Provider certificate</li> <li>Retrieve Security Context by Provider of invalid invoker</li> </ol> <p>Expected Result:</p> <ol> <li>Retrieve security context:<ol> <li>404 Not Found response.</li> <li>body returned must accomplish ProblemDetails data structure, with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Invoker not found\".</li> <li>cause with message \"API Invoker not exists or invalid ID\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-7-retrieve-the-security-context-of-an-api-invoker-with-invalid-apfid","title":"Test Case 7: Retrieve the Security Context of an API Invoker with invalid apfId","text":"<p>Test ID:: capif_security_api-7</p> <p>Description:</p> <p>This test case will check that an Provider cannot retrieve the Security context of an API Invoker without valid apfId</p> <p>Pre-Conditions:</p> <ul> <li>API Exposure Function is not pre-authorised (has invalid apfId)</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Create Security Context for this Invoker</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Using Invoker Certificate</li> </ul> </li> <li> <p>Retrieve Security Context as Invoker role:</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>Using Invoker Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Invoker at CCF</li> <li>Store signed Certificate</li> <li>Create Security Context</li> <li>Retrieve Security Context as Provider.</li> </ol> <p>Expected Result:</p> <ol> <li>Create security context:<ol> <li>401 Unauthorized response.</li> <li>body returned must accomplish ProblemDetails data structure, with:<ul> <li>status 401</li> <li>title with message \"Unauthorized\"</li> <li>detail with message \"Role not authorized for this API route\".</li> <li>cause with message \"User role must be aef\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-8-delete-the-security-context-of-an-api-invoker","title":"Test Case 8: Delete the Security Context of an API Invoker","text":"<p>Test ID:: capif_security_api-8</p> <p>Description:</p> <p>This test case will check that an Provider can delete a Security context</p> <p>Pre-Conditions:</p> <ul> <li>Provider is pre-authorised (has valid apfId from CAPIF Authority) and API Invoker has created a valid Security Context</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Create Security Context for this Invoker but using Provider certificate.</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Using AEF certificate</li> </ul> </li> <li> <p>Delete Security Context of Invoker by Provider:</p> <ul> <li>Send DELETE https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>Use AEF certificate</li> </ul> </li> <li> <p>Retrieve Security Context of Invoker by Provider:</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>Using AEF Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Invoker at CCF</li> <li>Register Provider at CCF</li> <li>Create Security Context using Provider certificate</li> <li>Delete Security Context by Provider</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Delete security context:</p> <ol> <li>204 No Content response.</li> </ol> </li> <li> <p>Retrieve security context:</p> <ol> <li>404 Not Found response.</li> <li>body returned must accomplish ProblemDetails data structure, with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Security context not found\".</li> <li>cause with message \"API Invoker not exists or invalid ID\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-9-delete-the-security-context-of-an-api-invoker-with-invoker-entity-role","title":"Test Case 9: Delete the Security Context of an API Invoker with Invoker entity role","text":"<p>Test ID:: capif_security_api-9</p> <p>Description:</p> <p>This test case will check that an Invoker cannot delete a Security context</p> <p>Pre-Conditions:</p> <ul> <li>Provider is pre-authorised (has valid apfId from CAPIF Authority) and API Invoker has created a valid Security Context</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Create Security Context for this Invoker:</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Using Invoker certificate</li> </ul> </li> <li> <p>Delete Security Context of Invoker:</p> <ul> <li>Send DELETE https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>Use Invoker certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF</li> <li>Create Security Context using Provider certificate</li> <li>Delete Security Context by Invoker</li> </ol> <p>Expected Result:</p> <ol> <li>Delete security context:<ol> <li>401 Unauthorized response.</li> <li>body returned must accomplish ProblemDetails data structure, with:<ul> <li>status 401</li> <li>title with message \"Unauthorized\"</li> <li>detail with message \"Role not authorized for this API route\".</li> <li>cause with message \"User role must be aef\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-10-delete-the-security-context-of-an-api-invoker-with-invoker-entity-role-and-invalid-apiinvokerid","title":"Test Case 10: Delete the Security Context of an API Invoker with Invoker entity role and invalid apiInvokerID","text":"<p>Test ID:: capif_security_api-10</p> <p>Description:</p> <p>This test case will check that an Invoker cannot delete a Security context with invalid </p> <p>Pre-Conditions:</p> <ul> <li>Invoker is pre-authorised.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Invoker Onboarding</p> </li> <li> <p>Delete Security Context of Invoker:</p> <ul> <li>Send DELETE https://{CAPIF_HOSTNAME}/trustedInvokers/{API_INVOKER_NOT_VALID}</li> <li>Use Invoker certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF</li> <li>Delete Security Context by invoker</li> </ol> <p>Expected Result:</p> <ol> <li>Delete security context:<ol> <li>401 Unauthorized response.</li> <li>body returned must accomplish ProblemDetails data structure, with:<ul> <li>status 401</li> <li>title with message \"Unauthorized\"</li> <li>detail with message \"Role not authorized for this API route\".</li> <li>cause with message \"User role must be aef\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-11-delete-the-security-context-of-an-api-invoker-with-invalid-apiinvokerid","title":"Test Case 11: Delete the Security Context of an API Invoker with invalid apiInvokerID","text":"<p>Test ID:: capif_security_api-11</p> <p>Description:</p> <p>This test case will check that an Provider cannot delete a Security context of invalid apiInvokerId</p> <p>Pre-Conditions:</p> <ul> <li>Provider is pre-authorised (has valid apfId from CAPIF Authority).</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Delete Security Context of Invoker by Provider:</p> <ul> <li>Send DELETE https://{CAPIF_HOSTNAME}/trustedInvokers/{API_INVOKER_NOT_VALID}</li> <li>Use AEF certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF</li> <li>Delete Security Context by provider</li> </ol> <p>Expected Result:</p> <ol> <li>Retrieve security context:<ol> <li>404 Not Found response.</li> <li>body returned must accomplish ProblemDetails data structure, with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Invoker not found\".</li> <li>cause with message \"API Invoker not exists or invalid ID\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-12-update-the-security-context-of-an-api-invoker","title":"Test Case 12: Update the Security Context of an API Invoker","text":"<p>Test ID:: capif_security_api-12</p> <p>Description:</p> <p>This test case will check that an API Invoker can update a Security context</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised (has valid apiInvokerID from CAPIF Authority) and Provider is also authorized</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Create Security Context for this Invoker:</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Using Invoker Certificate.</li> </ul> </li> <li> <p>Update Security Context of Invoker:</p> <ul> <li>Send POST https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}/update</li> <li>body service security body but with notification destination modified to http://robot.testing2</li> <li>Using Invoker Certificate.</li> </ul> </li> <li> <p>Retrieve Security Context of Invoker by Provider:</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>Using AEF Certificate.</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Invoker at CCF</li> <li>Register Provider at CCF</li> <li>Create Security Context By Invoker</li> <li>Update Security Context By Invoker</li> <li>Retrieve Security Context By Provider</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Update security context:</p> <ol> <li>200 OK response.</li> <li>body returned must accomplish ServiceSecurity data structure.</li> </ol> </li> <li> <p>Retrieve security context:</p> <ol> <li>200 OK response.</li> <li>body returned must accomplish ServiceSecurity data structure.<ol> <li>Check is this returned object match with modified one.</li> </ol> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-13-update-the-security-context-of-an-api-invoker-with-provider-entity-role","title":"Test Case 13: Update the Security Context of an API Invoker with Provider entity role","text":"<p>Test ID:: capif_security_api-13</p> <p>Description:</p> <p>This test case will check that an Provider cannot update a Security context</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised (has valid apiInvokerID from CAPIF Authority) and Provider is also authorized.</li> <li>Invoker has created the Security Context previously.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Create Security Context for this Invoker:</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Using Invoker Certificate.</li> </ul> </li> <li> <p>Update Security Context of Invoker by Provider:</p> <ul> <li>Send POST https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}/update</li> <li>body service security body but with notification destination modified to http://robot.testing2</li> <li>Using AEF Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Invoker at CCF</li> <li>Register Provider at CCF</li> <li>Create Security Context</li> <li>Update Security Context as Provider</li> </ol> <p>Expected Result:</p> <ol> <li>Update security context:<ol> <li>401 Unauthorized response.</li> <li>body returned must accomplish ProblemDetails data structure, with:<ul> <li>status 401</li> <li>title with message \"Unauthorized\"</li> <li>detail with message \"Role not authorized for this API route\".</li> <li>cause with message \"User role must be invoker\". </li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-14-update-the-security-context-of-an-api-invoker-with-aef-entity-role-and-invalid-apiinvokerid","title":"Test Case 14: Update the Security Context of an API Invoker with AEF entity role and invalid apiInvokerId","text":"<p>Test ID:: capif_security_api-14</p> <p>Description:</p> <p>This test case will check that an Provider cannot update a Security context of invalid apiInvokerId</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised (has valid apiInvokerID from CAPIF Authority) and Provider is also authorized.</li> <li>Invoker has created the Security Context previously.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Update Security Context of Invoker by Provider:</p> <ul> <li>Send POST https://{CAPIF_HOSTNAME}/trustedInvokers/{API_INVOKER_NOT_VALID}/update</li> <li>body service security body</li> <li>Using AEF Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF</li> <li>Update Security Context as Provider</li> </ol> <p>Expected Result:</p> <ol> <li>Update security context:<ol> <li>401 Unauthorized response.</li> <li>body returned must accomplish ProblemDetails data structure, with:<ul> <li>status 401</li> <li>title with message \"Unauthorized\"</li> <li>detail with message \"Role not authorized for this API route\".</li> <li>cause with message \"User role must be invoker\". </li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-15-update-the-security-context-of-an-api-invoker-with-invalid-apiinvokerid","title":"Test Case 15: Update the Security Context of an API Invoker with invalid apiInvokerID","text":"<p>Test ID:: capif_security_api-15</p> <p>Description:</p> <p>This test case will check that an API Invoker cannot update a Security context not valid apiInvokerId</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised (has valid apiInvokerID from CAPIF Authority)</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Update Security Context of Invoker:</p> <ul> <li>Send POST https://{CAPIF_HOSTNAME}/trustedInvokers/{API_INVOKER_NOT_VALID}/update</li> <li>body service security body</li> <li>Using Invoker Certificate.</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Invoker at CCF</li> <li>Update Security Context</li> </ol> <p>Expected Result:</p> <ol> <li>Retrieve security context:<ol> <li>404 Not Found response.</li> <li>body returned must accomplish ProblemDetails data structure, with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Invoker not found\".</li> <li>cause with message \"API Invoker not exists or invalid ID\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-16-revoke-the-authorization-of-the-api-invoker-for-apis","title":"Test Case 16: Revoke the authorization of the API invoker for APIs.","text":"<p>Test ID:: capif_security_api-16</p> <p>Description:</p> <p>This test case will check that a Provider can revoke the authorization for APIs</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised (has valid apiInvokerID from CAPIF Authority) and Provider is also authorized</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Create Security Context By Invoker:</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Using Invoker Certificate</li> </ul> </li> <li> <p>Revoke Authorization by Provider:</p> <ul> <li>Send POST https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}/delete</li> <li>body security notification body</li> <li>Using AEF Certificate.</li> </ul> </li> <li> <p>Retrieve Security Context by Provider:</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>Using AEF Certificate.</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Invoker at CCF</li> <li>Register Provider at CCF</li> <li>Create Security Context by Invoker</li> <li>Revoke Security Context by Provider</li> <li>Retrieve Security Context by Provider</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Revoke Authorization:</p> <ol> <li>204 No Content response.</li> </ol> </li> <li> <p>Retrieve security context:</p> <ol> <li>404 Not Found response.</li> <li>body returned must accomplish ProblemDetails data structure, with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Security context not found\".</li> <li>cause with message \"API Invoker has no security context\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-17-revoke-the-authorization-of-the-api-invoker-for-apis-without-valid-apfid","title":"Test Case 17: Revoke the authorization of the API invoker for APIs without valid apfID.","text":"<p>Test ID:: capif_security_api-17</p> <p>Description:</p> <p>This test case will check that an Invoker can't revoke the authorization for APIs</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised (has valid apiInvokerID from CAPIF Authority) and Provider is also authorized</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Create Security Context for this Invoker:</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Using Invoker Certificate.</li> </ul> </li> <li> <p>Revoke Authorization by invoker:</p> <ul> <li>Send POST https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}/delete</li> <li>body security notification body</li> <li>Using Invoker Certificate</li> </ul> </li> <li> <p>Retrieve Security Context of Invoker by Provider:</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>Using Provider Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Invoker at CCF</li> <li>Register Provider at CCF</li> <li>Create Security Context</li> <li>Revoke Security Context by invoker</li> <li>Retrieve Security Context</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Revoke Security Context by invoker:</p> <ol> <li>401 Unauthorized response.</li> <li>body returned must accomplish ProblemDetails data structure, with:<ul> <li>status 401</li> <li>title with message \"Unauthorized\"</li> <li>detail with message \"Role not authorized for this API route\".</li> <li>cause with message \"User role must be provider\". </li> </ul> </li> </ol> </li> <li> <p>Retrieve security context:</p> <ol> <li>200 OK response.</li> <li>body returned must accomplish ServiceSecurity data structure.<ol> <li>Check is this returned object match with created one.</li> </ol> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-18-revoke-the-authorization-of-the-api-invoker-for-apis-with-invalid-apiinvokerid","title":"Test Case 18: Revoke the authorization of the API invoker for APIs with invalid apiInvokerId.","text":"<p>Test ID:: capif_security_api-18</p> <p>Description:</p> <p>This test case will check that an API Exposure Function cannot revoke the authorization for APIs for invalid apiInvokerId</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised (has valid apiInvokerID from CAPIF Authority) and Provider is also authorized</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Create Security Context for this Invoker:</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Using Invoker Certificate.</li> </ul> </li> <li> <p>Revoke Authorization by Provider:</p> <ul> <li>Send POST https://{CAPIF_HOSTNAME}/trustedInvokers/{API_INVOKER_NOT_VALID}/delete</li> <li>body security notification body</li> <li>Using AEF Certificate.</li> </ul> </li> <li> <p>Retrieve Security Context of Invoker by Provider:</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}?authenticationInfo=true&amp;authorizationInfo=true</li> <li>This request will ask with parameter to retrieve authenticationInfo and authorizationInfo</li> <li>Using AEF Certificate.</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Invoker at CCF</li> <li>Register Provider at CCF</li> <li>Create Security Context</li> <li>Revoke Security Context by Provider</li> <li>Retrieve Security Context</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Revoke Security Context by invoker:</p> <ol> <li>404 Not Found response.</li> <li>body returned must accomplish ProblemDetails data structure, with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Invoker not found\".</li> <li>cause with message \"API Invoker not exists or invalid ID\".</li> </ul> </li> </ol> </li> <li> <p>Retrieve security context:</p> <ol> <li>200 OK response.</li> <li>body returned must accomplish ServiceSecurity data structure.<ol> <li>Check is this return one object that match with created one.</li> </ol> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-19-retrieve-access-token","title":"Test Case 19: Retrieve access token","text":"<p>Test ID:: capif_security_api-19</p> <p>Description:</p> <p>This test case will check that an API Invoker can retrieve a security access token OAuth 2.0.</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised (has valid apiInvokerId)</li> <li>Service API of Provider is published</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body [service api description] with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Request Discover Published APIs not filtered:</p> <ul> <li>Send GET to ccf_discover_url https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}</li> <li>Param api-invoker-id is mandatory</li> <li>Using invoker certificate</li> </ul> </li> <li> <p>Create Security Context for this Invoker</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Using Invoker Certificate.</li> <li>Create Security Information Body with one securityInfo for each aef present at each serviceAPIDescription present at Discover.</li> </ul> </li> <li> <p>Request Access Token by invoker:</p> <ul> <li>Sent POST https://{CAPIF_HOSTNAME}/securities/{securityId}/token:</li> <li>body access token req body and example example</li> <li>securityId is apiInvokerId.</li> <li>grant_type=client_credentials.</li> <li>Create Scope properly for request: 3gpp#{aef_id}:{api_name}</li> <li>Using Invoker Certificate.</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF, store certificates and Publish Service API service_1 at CCF</li> <li>Register and onboard Invoker at CCF</li> <li>Discover Service APIs by Invoker.</li> <li>Create Security Context According to Service APIs discovered.</li> <li>Request Access Token</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Request of Access Token:<ol> <li>200 OK</li> <li>body must follow AccessTokenRsp with:<ol> <li>access_token present</li> <li>token_type=Bearer</li> </ol> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-20-retrieve-access-token-by-provider","title":"Test Case 20: Retrieve access token by Provider","text":"<p>Test ID:: capif_security_api-20</p> <p>Description:</p> <p>This test case will check that an API Exposure Function cannot revoke the authorization for APIs for invalid apiInvokerId</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised (has valid apiInvokerID from CAPIF Authority) and Provider is also authorized</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body [service api description] with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Request Discover Published APIs not filtered:</p> <ul> <li>Send GET to ccf_discover_url https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}</li> <li>Param api-invoker-id is mandatory</li> <li>Using invoker certificate</li> </ul> </li> <li> <p>Create Security Context for this Invoker</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Using Invoker Certificate.</li> <li>Create Security Information Body with one securityInfo for each aef present at each serviceAPIDescription present at Discover.</li> </ul> </li> <li> <p>Request Access Token by provider:</p> <ul> <li>Sent POST https://{CAPIF_HOSTNAME}/securities/{securityId}/token:</li> <li>body access token req body</li> <li>securityId is apiInvokerId</li> <li>grant_type=client_credentials</li> <li>Using AEF certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF, store certificates and Publish Service API service_1 at CCF</li> <li>Register and onboard Invoker at CCF</li> <li>Discover Service APIs by Invoker.</li> <li>Create Security Context According to Service APIs discovered.</li> <li>Request Access Token by Provider</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Request of Access Token:<ol> <li>401 Unauthorized response.</li> <li>body returned must accomplish AccessTokenErr data structure, with:<ul> <li>error unauthorized_client</li> <li>error_description=Role not authorized for this API route</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-21-retrieve-access-token-by-provider-with-invalid-apiinvokerid","title":"Test Case 21: Retrieve access token by Provider with invalid apiInvokerId","text":"<p>Test ID:: capif_security_api-21</p> <p>Description:</p> <p>This test case will check that an API Exposure Function cannot retrieve a security access token without valid apiInvokerId</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised and Provider is also authorized</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body [service api description] with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Request Discover Published APIs not filtered:</p> <ul> <li>Send GET to ccf_discover_url https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}</li> <li>Param api-invoker-id is mandatory</li> <li>Using invoker certificate</li> </ul> </li> <li> <p>Create Security Context for this Invoker</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Using Invoker Certificate.</li> <li>Create Security Information Body with one securityInfo for each aef present at each serviceAPIDescription present at Discover.</li> </ul> </li> <li> <p>Request Access Token by provider:</p> <ul> <li>Sent POST https://{CAPIF_HOSTNAME}/securities/{API_INVOKER_NOT_VALID}/token.</li> <li>body access token req body</li> <li>securityId is apiInvokerId</li> <li>grant_type=client_credentials</li> <li>Using AEF certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF, store certificates and Publish Service API service_1 at CCF</li> <li>Register and onboard Invoker at CCF</li> <li>Discover Service APIs by Invoker.</li> <li>Create Security Context According to Service APIs discovered.</li> <li>Request Access Token by Provider</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Request of Access Token:<ol> <li>401 Unauthorized response.</li> <li>body returned must accomplish AccessTokenErr data structure, with:<ul> <li>error unauthorized_client</li> <li>error_description=Role not authorized for this API route</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-22-retrieve-access-token-with-invalid-apiinvokerid","title":"Test Case 22: Retrieve access token with invalid apiInvokerId","text":"<p>Test ID:: capif_security_api-22</p> <p>Description:</p> <p>This test case will check that an API Invoker can't retrieve a security access token without valid apiInvokerId</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised (has valid apiInvokerId)</li> </ul> <p>Information of Test:</p> <ol> <li>Perform Provider Registration and Invoker Onboarding</li> <li>Publish Service API at CCF:<ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body [service api description] with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li>Request Discover Published APIs not filtered:<ul> <li>Send GET to ccf_discover_url https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}</li> <li>Param api-invoker-id is mandatory</li> <li>Using invoker certificate</li> </ul> </li> <li>Create Security Context for this Invoker<ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Using Invoker Certificate.</li> <li>Create Security Information Body with one securityInfo for each aef present at each serviceAPIDescription present at Discover.</li> </ul> </li> <li>Request Access Token by invoker:<ul> <li>Sent POST https://{CAPIF_HOSTNAME}/securities/{API_INVOKER_NOT_VALID}/token.</li> <li>body access token req body</li> <li>securityId is apiInvokerId</li> <li>grant_type=client_credentials</li> <li>Using Invoker certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF, store certificates and Publish Service API service_1 at CCF</li> <li>Register and onboard Invoker at CCF</li> <li>Discover Service APIs by Invoker.</li> <li>Create Security Context According to Service APIs discovered.</li> <li>Request Access Token by Invoker</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Request of Access Token:<ol> <li>404 Not Found response.</li> <li>body returned must accomplish ProblemDetails29571 data structure, with:<ul> <li>status 404</li> <li>title Not Found</li> <li>detail Security context not found</li> <li>cause API Invoker has no security context</li> </ul> </li> </ol> </li> </ol> <p>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</p>"},{"location":"testing/testplan/api_security_service/#test-case-23-retrieve-access-token-with-invalid-client_id","title":"Test Case 23: Retrieve access token with invalid client_id","text":"<p>Test ID:: capif_security_api-23</p> <p>Description:</p> <p>This test case will check that an API Exposure Function cannot retrieve a security access token without valid client_id at body</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised and Provider is also authorized</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body [service api description] with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Request Discover Published APIs not filtered:</p> <ul> <li>Send GET to ccf_discover_url https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}</li> <li>Param api-invoker-id is mandatory</li> <li>Using invoker certificate</li> </ul> </li> <li> <p>Create Security Context for this Invoker</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Using Invoker Certificate.</li> <li>Create Security Information Body with one securityInfo for each aef present at each serviceAPIDescription present at Discover.</li> </ul> </li> <li> <p>Request Access Token by invoker:</p> <ul> <li>Sent POST https://{CAPIF_HOSTNAME}/securities/{securityId}/token.</li> <li>body access token req body</li> <li>securityId is apiInvokerId</li> <li>grant_type=client_credentials</li> <li>client_id is not-valid </li> <li>Using Invoker certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF, store certificates and Publish Service API service_1 at CCF</li> <li>Register and onboard Invoker at CCF</li> <li>Discover Service APIs by Invoker.</li> <li>Create Security Context According to Service APIs discovered.</li> <li>Request Access Token by Invoker</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Request of Access Token:<ol> <li>400 Bad Request response.</li> <li>body returned must accomplish AccessTokenErr data structure, with:<ul> <li>error invalid_client</li> <li>error_description=Client Id not found</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-24-retrieve-access-token-with-unsupported-grant_type","title":"Test Case 24: Retrieve access token with unsupported grant_type","text":"<p>Test ID:: capif_security_api-24</p> <p>Description:</p> <p>This test case will check that an API Exposure Function cannot retrieve a security access token with unsupported grant_type</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised and Provider is also authorized</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body [service api description] with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Request Discover Published APIs not filtered:</p> <ul> <li>Send GET to ccf_discover_url https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}</li> <li>Param api-invoker-id is mandatory</li> <li>Using invoker certificate</li> </ul> </li> <li> <p>Create Security Context for this Invoker</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Using Invoker Certificate.</li> <li>Create Security Information Body with one securityInfo for each aef present at each serviceAPIDescription present at Discover.</li> </ul> </li> <li> <p>Request Access Token by invoker:</p> <ul> <li>Sent POST https://{CAPIF_HOSTNAME}/securities/{securityId}/token.</li> <li>body access token req body</li> <li>securityId is apiInvokerId</li> <li>grant_type=not_valid</li> <li>Using Invoker certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF, store certificates and Publish Service API service_1 at CCF</li> <li>Register and onboard Invoker at CCF</li> <li>Discover Service APIs by Invoker.</li> <li>Create Security Context According to Service APIs discovered.</li> <li>Request Access Token by Invoker</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Request of Access Token:<ol> <li>400 Bad Request response.</li> <li>body returned must accomplish AccessTokenErr data structure, with:<ul> <li>error unsupported_grant_type</li> <li>error_description=Invalid value for <code>grant_type</code> \\(${grant_type}\\), must be one of \\['client_credentials'\\] - 'grant_type'</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-25-retrieve-access-token-with-invalid-scope","title":"Test Case 25: Retrieve access token with invalid scope","text":"<p>Test ID:: capif_security_api-25</p> <p>Description:</p> <p>This test case will check that an API Exposure Function cannot retrieve a security access token with complete invalid scope</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised and Provider is also authorized</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body [service api description] with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Request Discover Published APIs not filtered:</p> <ul> <li>Send GET to ccf_discover_url https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}</li> <li>Param api-invoker-id is mandatory</li> <li>Using invoker certificate</li> </ul> </li> <li> <p>Create Security Context for this Invoker</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Using Invoker Certificate.</li> <li>Create Security Information Body with one securityInfo for each aef present at each serviceAPIDescription present at Discover.</li> </ul> </li> <li> <p>Request Access Token by invoker:</p> <ul> <li>Sent POST https://{CAPIF_HOSTNAME}/securities/{securityId}/token.</li> <li>body access token req body</li> <li>securityId is apiInvokerId</li> <li>grant_type=client_credentials</li> <li>scope=not-valid-scope</li> <li>Using Invoker certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF, store certificates and Publish Service API service_1 at CCF</li> <li>Register and onboard Invoker at CCF</li> <li>Discover Service APIs by Invoker.</li> <li>Create Security Context According to Service APIs discovered.</li> <li>Request Access Token by Invoker</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Request of Access Token:<ol> <li>400 Bad Request response.</li> <li>body returned must accomplish AccessTokenErr data structure, with:<ul> <li>error invalid_scope</li> <li>error_description=The first characters must be '3gpp'</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-26-retrieve-access-token-with-invalid-aefid-at-scope","title":"Test Case 26: Retrieve access token with invalid aefid at scope","text":"<p>Test ID:: capif_security_api-26</p> <p>Description:</p> <p>This test case will check that an API Exposure Function cannot retrieve a security access token with invalid aefId at scope</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised and Provider is also authorized</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body [service api description] with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Request Discover Published APIs not filtered:</p> <ul> <li>Send GET to ccf_discover_url https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}</li> <li>Param api-invoker-id is mandatory</li> <li>Using invoker certificate</li> </ul> </li> <li> <p>Create Security Context for this Invoker</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Using Invoker Certificate.</li> <li>Create Security Information Body with one securityInfo for each aef present at each serviceAPIDescription present at Discover.</li> </ul> </li> <li> <p>Request Access Token by invoker:</p> <ul> <li>Sent POST https://{CAPIF_HOSTNAME}/securities/{securityId}/token.</li> <li>body access token req body</li> <li>securityId is apiInvokerId</li> <li>grant_type=client_credentials</li> <li>scope=3gpp#1234:service_1</li> <li>Using Invoker certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF, store certificates and Publish Service API service_1 at CCF</li> <li>Register and onboard Invoker at CCF</li> <li>Discover Service APIs by Invoker.</li> <li>Create Security Context According to Service APIs discovered.</li> <li>Request Access Token by Invoker</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Request of Access Token:<ol> <li>400 Bad Request response.</li> <li>body returned must accomplish AccessTokenErr data structure, with:<ul> <li>error invalid_scope</li> <li>error_description=One of aef_id not belongs of your security context</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-27-retrieve-access-token-with-invalid-apiname-at-scope","title":"Test Case 27: Retrieve access token with invalid apiName at scope","text":"<p>Test ID:: capif_security_api-27</p> <p>Description:</p> <p>This test case will check that an API Exposure Function cannot retrieve a security access token with invalid apiName at scope</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised and Provider is also authorized</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body [service api description] with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Request Discover Published APIs not filtered:</p> <ul> <li>Send GET to ccf_discover_url https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}</li> <li>Param api-invoker-id is mandatory</li> <li>Using invoker certificate</li> </ul> </li> <li> <p>Create Security Context for this Invoker</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Using Invoker Certificate.</li> <li>Create Security Information Body with one securityInfo for each aef present at each serviceAPIDescription present at Discover.</li> </ul> </li> <li> <p>Request Access Token by invoker:</p> <ul> <li>Sent POST https://{CAPIF_HOSTNAME}/securities/{securityId}/token.</li> <li>body access token req body</li> <li>securityId is apiInvokerId</li> <li>grant_type=client_credentials</li> <li>scope=3gpp#{aef_id}:not-valid</li> <li>Using Invoker certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF, store certificates and Publish Service API service_1 at CCF</li> <li>Register and onboard Invoker at CCF</li> <li>Discover Service APIs by Invoker.</li> <li>Create Security Context According to Service APIs discovered.</li> <li>Request Access Token by Invoker</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Request of Access Token:<ol> <li>400 Bad Request response.</li> <li>body returned must accomplish AccessTokenErr data structure, with:<ul> <li>error invalid_scope</li> <li>error_description=One of the api names does not exist or is not associated with the aef id provided</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/common_operations/","title":"Common Operations","text":""},{"location":"testing/testplan/common_operations/#register-an-invoker","title":"Register an Invoker","text":""},{"location":"testing/testplan/common_operations/#steps-to-perform-operation","title":"Steps to perform operation","text":"<ol> <li>Create public and private key at invoker</li> <li> <p>Register of Invoker at CCF:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}:{CAPIF_HTTP_PORT}/register</li> <li>Body invoker register body</li> </ul> </li> <li> <p>Obtain Access Token:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}/getauth</li> <li>Body invoker getauth body</li> </ul> </li> <li> <p>Onboard Invoker:             * Send POST to https://{CAPIF_HOSTNAME}/api-invoker-management/v1/onboardedInvokers          * Reference Request Body: invoker onboarding body          * \"onboardingInformation\"-&gt;\"apiInvokerPublicKey\": must contain public key generated by Invoker.          * Send at Authorization Header the Bearer access_token obtained previously (Authorization:Bearer ${access_token})</p> </li> </ol>"},{"location":"testing/testplan/common_operations/#checks-to-ensure-onboarding","title":"Checks to ensure onboarding","text":"<ol> <li> <p>Response to Register:</p> <ol> <li>201 Created</li> </ol> </li> <li> <p>Response to Get Auth:</p> <ol> <li>200 OK</li> <li>access_token returned.</li> </ol> </li> <li> <p>Response to Onboard request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow APIInvokerEnrolmentDetails data structure with:<ul> <li>apiInvokerId</li> <li>onboardingInformation-&gt;apiInvokerCertificate must contain the public key signed.</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}</li> </ol> </li> </ol>"},{"location":"testing/testplan/common_operations/#register-a-provider","title":"Register a Provider","text":""},{"location":"testing/testplan/common_operations/#steps-to-perform-operation_1","title":"Steps to Perform operation","text":"<ol> <li>Create public and private key at provider for provider itself and each function (apf, aef and amf)</li> <li> <p>Register of Provider at CCF:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}:{CAPIF_HTTP_PORT}/register</li> <li>body provider register body</li> </ul> </li> <li> <p>Obtain Access Token:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}/getauth</li> <li>Body provider getauth body</li> </ul> </li> <li> <p>Register Provider:</p> <ul> <li>Send POST https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations</li> <li>body provider request body</li> <li>Send at Authorization Header the Bearer access_token obtained previously (Authorization:Bearer ${access_token})</li> <li>Store each cert in a file with according name.</li> </ul> </li> </ol>"},{"location":"testing/testplan/common_operations/#checks-to-ensure-provider-registration","title":"Checks to ensure provider registration","text":"<ol> <li> <p>Response to Register:</p> <ol> <li>201 Created</li> </ol> </li> <li> <p>Response to Get Auth:</p> <ol> <li>200 OK</li> <li>access_token returned.</li> </ol> </li> <li> <p>Register Provider at Provider Management:</p> <ol> <li>201 Created response.</li> <li>body returned must accomplish APIProviderEnrolmentDetails data structure.</li> <li>For each apiProvFuncs, we must check:<ol> <li>apiProvFuncId is set</li> <li>apiProvCert under regInfo is set properly</li> </ol> </li> <li>Location Header must contain the new resource URL {apiRoot}/api-provider-management/v1/registrations/{registrationId}</li> </ol> </li> </ol>"}]}
\ No newline at end of file
+{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Introduction","text":""},{"location":"#release-00","title":"Release 0.0","text":"<p>The APIs included in Release 0.0 are:</p> <ul> <li>JWT Authentication APIs</li> <li>CAPIF Invoker Management API</li> <li>CAPIF Publish API</li> <li>CAPIF Discover API</li> <li>CAPIF Security API</li> <li>CAPIF Events API</li> <li>CAPIF Provider Management API</li> </ul> <p>This Release also includes a Robot Test Suite for all those services and a Postman Test Suite for simple testing.</p>"},{"location":"#what-is-opencapif","title":"What is OpenCAPIF?","text":"<p>CAPIF is the \u201cCommon API Framework\u201d defined by 3GPP to manage the APIs exposed by 3GPP networks in their northbound interfaces.</p> <p>CAPIF defines three types of entities:</p> <ul> <li>API Providers, which are the entities exposing APIs (e.g., NEF)</li> <li>API Invokers, which are the entities that consume APIs (e.g., Applications), and</li> <li>the CAPIF Core Function, which manages the relationships between the other two.</li> </ul> <p></p> <p>The CAPIF Core Function is the cornerstone of the Common API Framework and provides the following capabilities:</p> <ul> <li>Authenticating the API Invoker based on its identity and other information;</li> <li>Supporting mutual authentication with the API Invoker;</li> <li>Providing authorization for the API Invoker prior to accessing the exposed APIs;</li> <li>Publishing, storing, and supporting the discovery of service APIs information;</li> <li>Controlling the service API access based on PLMN operator configured policies;</li> <li>Storing the logs for the service API invocations and providing the service API invocation logs to authorized entities;</li> <li>Charging based on the logs of the service API invocations;</li> <li>Monitoring the service API invocations;</li> <li>Onboarding a new API Invoker and offboarding an API Invoker;</li> <li>Storing policy configurations related to CAPIF and service APIs;</li> <li>Support for accessing the logs for auditing (e.g., detecting abuse); and</li> <li>Support for publishing and discovery of service APIs information among CAPIF Core Function (CAPIF interconnection).</li> </ul> <p>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.</p> <p></p> <p>If you want to know more about OpenCAPIF check The story behind openCAPIF</p>"},{"location":"#repository-structure","title":"Repository structure","text":"<p>You can check the code at OpenCAPIF Repository</p> <pre><code>CAPIF_API_Services\n\u2514\u2500\u2500\u2500helm\n\u2514\u2500\u2500\u2500monitoring\n\u2514\u2500\u2500\u2500services\n\u2514\u2500\u2500\u2500tests\n\u2514\u2500\u2500\u2500tools\n    \u2514\u2500\u2500\u2500robot\n    \u2514\u2500\u2500\u2500open_api_script\n</code></pre> <ul> <li>helm: This folder contains helm files to deploy capif under k8s environment.</li> <li>monitoring: This folder contains grafana helm files to deploy capif under k8s environment.</li> <li>services: Services developed following CAPIF API specifications. Also, other complementary services (e.g., NGINX and JWTauth services for the authentication of API consuming entities).</li> <li>tools: Auxiliary tools. Robot Framework related code and OpenAPI scripts.</li> <li>test: Tests developed using Robot Framework.</li> </ul>"},{"location":"#capif_api_services","title":"CAPIF_API_Services","text":"<p>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</p>"},{"location":"#how-to-test-capif-apis","title":"How to test CAPIF APIs","text":"<p>The above APIs can be tested either with POSTMAN tool or running the developed tests with Robot Framework.</p>"},{"location":"#test-plan-documentation","title":"Test Plan Documentation","text":"<p>Complete documentation of tests is available here: Test Plan Directory</p>"},{"location":"#robot-framework","title":"Robot Framework","text":"<p>In order to ensure that modifications over CAPIF services still fulfills the required functionality, the Robot Framework Test Suite must be successfully run.</p> <p>The Robot Test Suite covers the requirements described in the test plan at Test Plan Directory folder.</p> <p>Please check the Testing with Robot Framework Section</p>"},{"location":"#using-postman","title":"Using PostMan","text":"<p>You can also 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.</p> <p>For more information on how to test the APIs with POSTMAN, go to this POSTMAN Section.</p>"},{"location":"#important-urls","title":"Important urls:","text":""},{"location":"#mongo-capifs-db-dashboard","title":"Mongo CAPIF's DB Dashboard","text":"<pre><code>http://localhost:8082/ (if accessed from localhost) \n\nor\n\nhttp://&lt;Mongo CAPIF Express Host IP&gt;:8082/ (if accessed from another host)\n</code></pre>"},{"location":"#mongo-registers-db-dashboard","title":"Mongo Register's DB Dashboard","text":"<pre><code>http://localhost:8083/ (if accessed from localhost) \n\nor\n\nhttp://&lt;Mongo Register Express Host IP&gt;:8083/ (if accessed from another host)\n</code></pre>"},{"location":"#faq-documentation","title":"FAQ Documentation","text":"<p>Frequently asked questions can be found here: FAQ Section</p>"},{"location":"FAQ/","title":"Frequently Asked Questions (FAQ)","text":""},{"location":"FAQ/#does-the-user-have-to-develop-the-3-elements-of-the-provider-aef-amf-and-apf","title":"Does the user have to develop the 3 elements of the provider (AEF, AMF and APF)?","text":"<p>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.</p>"},{"location":"FAQ/#there-is-one-party-that-publishes-the-api-and-another-that-exposes-it-what-is-the-difference","title":"There is one party that publishes the API and another that exposes it, what is the difference?","text":"<p>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.</p>"},{"location":"FAQ/#before-publishing-an-api-do-you-have-to-be-registered-in-capif","title":"Before publishing an API, do you have to be registered in CAPIF?","text":"<p>Yes, before publishing an API you must register using the POST /register endpoint.</p>"},{"location":"FAQ/#where-is-the-registration-done","title":"Where is the registration done?","text":"<p>Registration is done in a REST API outside of the CAPIF specification taht we have implemented.</p>"},{"location":"FAQ/#is-the-username-and-password-chosen-by-the-user-when-registering-or-is-it-assigned-when-requesting-registration-to-capif-public-instance","title":"Is the username and password chosen by the user when registering or is it assigned when requesting registration to CAPIF public instance?","text":"<p>When you make the request to the \"/endpoint\" of register, you will be returned a username and a password determined by CAPIF.</p>"},{"location":"FAQ/#what-is-a-csr","title":"What is a CSR?","text":"<p>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.</p>"},{"location":"FAQ/#when-doing-the-register_provider-where-can-i-find-the-csrs-that-are-generated","title":"When doing the register_provider where can I find the CSRs that are generated?","text":"<p>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.</p>"},{"location":"FAQ/#how-to-use-the-example-client-capif_invoker_gui","title":"How to use the example client (CAPIF_INVOKER_GUI)?","text":"<p>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.</p>"},{"location":"FAQ/#where-is-the-capif-public-instance-located","title":"Where is the CAPIF public instance located?","text":"<p>The CAPIF public instance can be found at the following URLs: - capif.mobilesandbox.cloud:37211 (HTTPS) - capif.mobilesandbox.cloud:37212 (HTTP)</p>"},{"location":"FAQ/#do-you-have-to-publish-3-apis-one-for-each-instance","title":"Do you have to publish 3 APIs? one for each instance?","text":"<p>No, you only have to publish a single API but each component is responsible for a specific service, whether publishing or exposing.</p>"},{"location":"FAQ/#once-the-api-is-published-is-it-always-active-or-do-you-have-to-republish-it-every-time-you-want-to-use-it","title":"Once the API is published, is it always active? Or do you have to republish it every time you want to use it?","text":"<p>It is better to unsubscribe the API every time you exit the application since otherwise it could be republished and it would be double.</p>"},{"location":"FAQ/#would-the-same-username-and-password-be-valid-for-different-invokers","title":"Would the same username and password be valid for different invokers?","text":"<p>Yes, a user can have multiple invokers at the same time, and as such, the username and password would be the same.</p>"},{"location":"FAQ/#what-is-the-notfication-destination-field-in-the-register_invoker-request","title":"What is the notfication destination field in the register_invoker request?","text":"<p>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...</p>"},{"location":"FAQ/#is-the-notification_destination-a-required-field-in-the-register_invoker","title":"Is the notification_destination a required field in the register_invoker","text":"<p>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.</p>"},{"location":"FAQ/#what-is-the-purpose-of-the-discover_service-function-in-the-invoker-client","title":"What is the purpose of the \"discover_service\" function in the invoker client?","text":"<p>The discover_service returns a json with all the services that exist exposed in CAPIF at that moment.</p>"},{"location":"FAQ/#what-is-the-purpose-of-the-get_security_auth-function-in-the-invoker-client","title":"What is the purpose of the \"get_security_auth\" function in the invoker client?","text":"<p>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.</p>"},{"location":"FAQ/#what-is-the-purpose-of-the-register_security_context-function-in-the-invoker-client","title":"What is the purpose of the \"register_security_context\" function in the invoker client?","text":"<p>To consume the API it is necessary to have a Security Context registered with the data and the authentication method.</p>"},{"location":"FAQ/#is-a-user-the-same-as-an-exposer","title":"Is a user the same as an exposer?","text":"<p>No, a user registers in CAPIF and once done can have the role of invoker, provider or both.</p>"},{"location":"FAQ/#where-can-i-put-my-endpoint","title":"Where can I put my endpoint?","text":"<p>You have to set your endpoint when doing the \"publish_service\" functionality: <code>publish_service capif_ops/config_files/service_api_description_hello.json</code></p> <p>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.</p>"},{"location":"gettingstarted/howtorun/","title":"How to Run","text":"<ul> <li>Run All CAPIF Services locally with Docker images</li> <li>Run All CAPIF Services locally with Docker images and deploy monitoring stack</li> <li>Run each service using Docker</li> <li>Run each service using Python</li> </ul> <p>Capif services are developed under services folder.</p>"},{"location":"gettingstarted/howtorun/#run-all-capif-services-locally-with-docker-images","title":"Run All CAPIF Services locally with Docker images","text":"<p>To run using docker and docker compose, version 2.10 or higher, you must ensure you have those tools installed in your machine. Also to simplify the process, we have 3 scripts allowing docker images to deploy, check and cleanup.</p> <p>All these scripts are available under services directory.</p> <p>To run CAPIF APIs locally using docker and docker-compose you can use run.sh script:</p> <pre><code>./run.sh -h\n\nUsage: ./run.sh &lt;options&gt;\n       -c : Setup different hostname for capif\n       -m : Clean monitoring service\n       -h : show this help\n</code></pre> <p>This script builds and runs all services using docker images, including mongodb and nginx locally and in the background, and imports ca.crt to nginx. By default monitoring is not activated and Nginx is deployed use capifcore as a hostname. </p> <p>Some examples of use:</p> <pre><code># Default values, No monitoring and capifcore as CAPIF_HOSTNAME\n./run.sh\n\n# opencapif.etsi.org as CAPIF_HOSTNAME\n./run.sh -c opencapif.etsi.org\n\n# opencapif.etsi.org as CAPIF_HOSTNAME and monitoring activated\n./run.sh -c opencapif.etsi.org -m true \n\n</code></pre> <p>If you want to check if all CAPIF services are running properly in a local machine after executing run.sh, you can use:</p> <pre><code>./check_services_are_running.sh\n</code></pre> <p>This shell script will return 0 if all services are running properly.</p> <p>When we need to stop all CAPIF services, we can use next bash script:</p> <pre><code>./clean_capif_docker_services.sh -a\n</code></pre> <p>NOTE: You can use different flags if you only want to stop some of them, please check the help using</p> <pre><code>./clean_capif_docker_services.sh -h\n\nUsage: clean_capif_docker_services.sh &lt;options&gt;\n       -c : clean capif services\n       -v : clean vault service\n       -r : clean register service\n       -m : clean monitoring service\n       -a : clean all services\n       -h : show this help\n</code></pre> <p>This shell script will remove and clean all CAPIF services started previously with run.sh</p> <p>On the other hand you can check logs using show_logs.sh script, please check options:</p> <pre><code>./show_logs.sh\nYou must specify an option when running the script.\nUsage: ./show_logs.sh &lt;options&gt;\n       -c : Show capif services\n       -v : Show vault service\n       -r : Show register service\n       -m : Show monitoring service\n       -a : Show all services\n       -f : Follow log output\n       -h : Show this help\n</code></pre> <p>You can also use option -f in order to follow log output in real time</p>"},{"location":"gettingstarted/howtorun/#run-all-capif-services-locally-with-docker-images-and-deploy-monitoring-stack","title":"Run All CAPIF Services locally with Docker images and deploy monitoring stack","text":"<p>It is now possible to deploy a monitoring stack for CAPIF with Grafana, Prometheus, FluentBit, Loki, Cadvisor, Tempo and Opentelemetry.</p> <p>To deploy CAPIF together with the monitoring stack, it is only necessary to execute the following.</p> <pre><code>./run.sh -m true\n</code></pre> <p>After they have been built, the different panels can be consulted in Grafana at the url</p> <pre><code>http://localhost:3000\n</code></pre> <p>By default, the monitoring option is set to false. Once up, all data sources and dashboards are automatically provisioned.</p>"},{"location":"gettingstarted/howtorun/#run-each-service-using-docker","title":"Run each service using Docker","text":"<p>Also you can run OpenCAPIF service by service using docker:</p> <pre><code>cd &lt;Service&gt;\ndocker build -t capif_security .\ndocker run -p 8080:8080 capif_security\n</code></pre>"},{"location":"gettingstarted/howtorun/#run-each-service-using-python","title":"Run each service using Python","text":"<p>Run using python</p> <pre><code>cd &lt;Service&gt;\npip3 install -r requirements.txt\npython3 -m &lt;service&gt;\n</code></pre>"},{"location":"testing/postman/","title":"Postman","text":"<p>In this section we can use Postman to publish an API as a provider and use it as an invoker.</p>"},{"location":"testing/postman/#requisites","title":"Requisites","text":"<ul> <li>We will need to have Node.js installed since we will use a small script to create the CSRs of the certificates.</li> <li>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).</li> </ul>"},{"location":"testing/postman/#first-steps","title":"First steps","text":"<ol> <li>Install the Node dependencies package.json to run the script with:</li> </ol> <pre><code>npm i\n</code></pre> <ol> <li>Run the script.js with the following command:</li> </ol> <pre><code>node script.js\n</code></pre> <ol> <li>Import Postman collection and environment variables (CAPIF.postman_collection.json and CAPIF.postman_environment.json)</li> <li>Select CAPIF Environment before start testing.</li> </ol>"},{"location":"testing/postman/#remote-capif","title":"Remote CAPIF","text":"<p>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.</p> <p>Enviroments in Postman</p> <pre><code>CAPIF_HOSTNAME     capifcore\nCAPIF_PORT         8080\nREGISTER_HOSTNAME  register\nREGISTER_PORT      8084\n</code></pre> <p>Const in script.js</p> <pre><code>CAPIF_HOSTNAME    capifcore\n</code></pre>"},{"location":"testing/postman/#capif-flows","title":"CAPIF Flows","text":"<p>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.</p>"},{"location":"testing/postman/#publication-of-an-api","title":"Publication of an API","text":""},{"location":"testing/postman/#01-register_user_provider","title":"01-register_user_provider","text":""},{"location":"testing/postman/#02-getauth_provider","title":"02-getauth_provider","text":""},{"location":"testing/postman/#03-onboard_provider","title":"03-onboard_provider","text":"<p>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.</p> <p>To configure go to settings in Postman and open the certificates section. </p> <ul> <li>Here, activate the CA certificates option and add the ca_cert.pem file found in the Responses folder.</li> <li>Adds a client certificate specifying the CAPIF host being used and the files client_cert.crt and client_key.key in the Responses folder.</li> </ul> <p>Once this is done, the node script will be in charge of changing the certificate that is necessary in each request.</p>"},{"location":"testing/postman/#04-publish_api","title":"04-publish_api","text":"<p>Once the api is published, we can start it. In this case we have a test one created in python called hello_api.py that can be executed with the following command:</p> <pre><code>python3 hello_api.py\n</code></pre> <p>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.</p> <p>With this the provider part would be finished.</p>"},{"location":"testing/postman/#calling-the-api","title":"Calling the API","text":""},{"location":"testing/postman/#05-register_user_invoker","title":"05-register_user_invoker","text":""},{"location":"testing/postman/#06-getauth_invoker","title":"06-getauth_invoker","text":""},{"location":"testing/postman/#07-onboard_invoker","title":"07-onboard_invoker","text":"<p>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.</p>"},{"location":"testing/postman/#08-discover","title":"08-discover","text":""},{"location":"testing/postman/#09-security_context","title":"09-security_context","text":""},{"location":"testing/postman/#10-get_token","title":"10-get_token","text":""},{"location":"testing/postman/#11-call_service","title":"11-call_service","text":"<p>With this, we would have made the API call and finished the flow.</p>"},{"location":"testing/postman/#other-requests","title":"Other requests","text":"<p>Other requests that we have added are the following:</p> <ul> <li>offboard_provider      Performs offboarding of the provider, thereby eliminating the published APIs.</li> <li>offboard_invoker       Offboards the invoker, also eliminating access to the APIs of that invoker.</li> <li>remove_user_invoker    Delete the user created for the invoker.</li> <li>remove_user_provider   Delete the user created for the provider.</li> </ul>"},{"location":"testing/postman/#notes","title":"Notes","text":"<ul> <li>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.</li> <li>It is possible that if external CAPIFs are used (Public CAPIF) the test data may already be used or the API already registered.</li> <li>It is necessary to have the Node service running to make the certificate change for the requests, otherwise it will not work.</li> <li>We are working on adding more requests to the Postman collection.</li> <li>This collection is a testing guide and is recommended for testing purposes only.</li> </ul>"},{"location":"testing/robotframework/","title":"Robot Framework","text":""},{"location":"testing/robotframework/#steps-to-test","title":"Steps to Test","text":"<p>To run any test locally you will need docker and docker-compose installed in order run services and execute test plan. Steps will be:</p> <ul> <li> <p>Run All Services: See section Run All CAPIF Services</p> </li> <li> <p>Run desired tests: At this point we have 2 options:</p> </li> <li> <p>Using helper script: Script Test Execution</p> </li> <li>Build robot docker image and execute manually robot docker: Manual Build And Test Execution</li> </ul>"},{"location":"testing/robotframework/#script-test-execution","title":"Script Test Execution","text":"<p>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.</p> <pre><code>./runCapifTests.sh --include &lt;TAG&gt;\n</code></pre> <p>Results will be stored at /results <p>Please check parameters (include) under Test Execution at Manual Build And Test Execution.</p>"},{"location":"testing/robotframework/#manual-build-and-test-execution","title":"Manual Build And Test Execution","text":"<ul> <li>Build Robot docker image:</li> </ul> <pre><code>cd tools/robot\ndocker build . -t 5gnow-robot-test:latest\n</code></pre> <ul> <li>Tests Execution:</li> </ul> <p>Execute all tests locally:</p> <pre><code>&lt;PATH_TO_REPOSITORY&gt;=path in local machine to repository cloned.\n&lt;PATH_RESULT_FOLDER&gt;=path to a folder on local machine to store results of Robot Framework execution.\n&lt;CAPIF_HOSTNAME&gt;=Is the hostname set when run.sh is executed, by default it will be capifcore.\n&lt;CAPIF_HTTP_PORT&gt;=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.\n\nTo execute all tests run :\ndocker run -ti --rm --network=\"host\" -v &lt;PATH_TO_REPOSITORY&gt;/tests:/opt/robot-tests/tests -v &lt;PATH_RESULT_FOLDER&gt;:/opt/robot-tests/results 5gnow-robot-test:latest --variable CAPIF_HOSTNAME:capifcore --variable CAPIF_HTTP_PORT:8080 --include all\n</code></pre> <p>Execute specific tests locally:</p> <pre><code>To run more specific tests, for example, only one functionality:\n&lt;TAG&gt;=Select one from list:\n  \"capif_api_acl\",\n  \"capif_api_auditing_service\",\n  \"capif_api_discover_service\",\n  \"capif_api_events\",\n  \"capif_api_invoker_management\",\n  \"capif_api_logging_service\",\n  \"capif_api_provider_management\",\n  \"capif_api_publish_service\",\n  \"capif_security_api\n\nAnd Run:\ndocker run -ti --rm --network=\"host\" -v &lt;PATH_TO_REPOSITORY&gt;/tests:/opt/robot-tests/tests -v &lt;PATH_RESULT_FOLDER&gt;:/opt/robot-tests/results 5gnow-robot-test:latest --variable CAPIF_HOSTNAME:capifcore --variable CAPIF_HTTP_PORT:8080 --include &lt;TAG&gt;\n</code></pre>"},{"location":"testing/robotframework/#test-result-review","title":"Test result review","text":"<p>In order to Review results after tests, you can check general report at /report.html or if you need more detailed information /log.html, example: <ul> <li> <p>Report: </p> </li> <li> <p>Detailed information: </p> </li> </ul> <p>NOTE: If you need more detail at Robot Framework Logs you can set log level option just adding to command --loglevel DEBUG</p>"},{"location":"testing/testplan/","title":"Test Plan Index","text":"<p>List of Common API Services implemented:</p> <ul> <li>Api Invoker Management</li> <li>Api Provider Management</li> <li>Api Publish Service</li> <li>Api Discover Service</li> <li>Api Events Service</li> <li>Api Security Service</li> <li>Api Logging Service</li> <li>Api Auditing Service</li> <li>Api Access Control Policy</li> </ul>"},{"location":"testing/testplan/api_access_control_policy/","title":"Test Plan for CAPIF Api Access Control Policy","text":"<p>At this documentation you will have all information and related files and examples of test plan for this API.</p>"},{"location":"testing/testplan/api_access_control_policy/#test-case-1-retrieve-acl","title":"Test Case 1: Retrieve ACL","text":"<p>Test ID: capif_api_acl-1</p> <p>Description:</p> <p>This test case will check that an API Provider can retrieve ACL from CAPIF</p> <p>Pre-Conditions:</p> <ul> <li>API Provider had a Service API Published on CAPIF</li> <li>API Invoker had a Security Context for Service API published.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Store serviceApiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Perform Invoker Onboarding store apiInvokerId</p> </li> <li>Discover published APIs</li> <li> <p>Create Security Context for this Invoker</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Use Invoker Certificate</li> </ul> </li> <li> <p>Provider Retrieve ACL</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId}?aef-id=${aef_id}</li> <li>Use serviceApiId and aefId</li> <li>Use AEF Provider Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Provider at CCF.</li> <li>Publish a provider API with name service_1</li> <li>Register and onboard Invoker at CCF</li> <li>Store signed Certificate</li> <li>Create Security Context</li> <li>Provider Get ACL information.</li> </ol> <p>Expected Result:</p> <ol> <li>ACL Response:<ol> <li>200 OK Response.</li> <li>body returned must accomplish AccessControlPolicyList data structure.</li> <li>apiInvokerPolicies must:<ol> <li>contain only one object.</li> <li>apiInvokerId must match apiInvokerId registered previously.</li> </ol> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_access_control_policy/#test-case-2-retrieve-acl-with-2-service-apis-published","title":"Test Case 2: Retrieve ACL with 2 Service APIs published","text":"<p>Test ID: capif_api_acl-2</p> <p>Description:</p> <p>This test case will check that an API Provider can retrieve ACL from CAPIF for 2 different serviceApis published.</p> <p>Pre-Conditions:</p> <ul> <li>API Provider had two Service API Published on CAPIF</li> <li>API Invoker had a Security Context for both Service APIs published.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Store serviceApiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_2</li> <li>Store serviceApiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Perform Invoker Onboarding store apiInvokerId</p> </li> <li>Discover published APIs</li> <li> <p>Create Security Context for this Invoker for both published APIs</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Use Invoker Certificate</li> </ul> </li> <li> <p>Provider Retrieve ACL for serviceApiId1</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId1}?aef-id=${aef_id}</li> <li>Use serviceApiId and aefId</li> <li>Use AEF Provider Certificate</li> </ul> </li> <li> <p>Provider Retrieve ACL for serviceApiId2</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId2}?aef-id=${aef_id}</li> <li>Use serviceApiId and aefId</li> <li>Use AEF Provider Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Provider at CCF.</li> <li>Publish a provider API with name service_1 and service_2</li> <li>Register and onboard Invoker at CCF</li> <li>Store signed Certificate</li> <li>Create Security Context</li> <li>Provider Get ACL information for service_1.</li> <li>Provider Get ACL information for service_2.</li> </ol> <p>Expected Result:</p> <ol> <li>ACL Response:<ol> <li>200 OK Response.</li> <li>body returned must accomplish AccessControlPolicyList data structure.</li> <li>apiInvokerPolicies must:<ol> <li>contain one object.</li> <li>apiInvokerId must match apiInvokerId registered previously.</li> </ol> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_access_control_policy/#test-case-3-retrieve-acl-with-security-context-created-by-two-different-invokers","title":"Test Case 3: Retrieve ACL with security context created by two different Invokers","text":"<p>Test ID: capif_api_acl-3</p> <p>Description:</p> <p>This test case will check that an API Provider can retrieve ACL from CAPIF containing 2 objects.</p> <p>Pre-Conditions:</p> <ul> <li>API Provider had a Service API Published on CAPIF</li> <li>Two API Invokers had a Security Context for same Service API published by provider.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Store serviceApiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Perform Invoker Onboarding store apiInvokerId</p> </li> <li>Discover published APIs</li> <li> <p>Create Security Context for this Invoker for both published APIs</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Use Invoker Certificate</li> </ul> </li> <li> <p>Repeat previous 3 steps in order to have a new Invoker.</p> </li> <li> <p>Provider Retrieve ACL for serviceApiId</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId1}?aef-id=${aef_id}</li> <li>Use serviceApiId and aefId</li> <li>Use AEF Provider Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Provider at CCF.</li> <li>Publish a provider API with name service_1 and service_2</li> <li>Register and onboard Invoker at CCF</li> <li>Store signed Certificate</li> <li>Create Security Context</li> <li>Provider Get ACL information.</li> </ol> <p>Expected Result:</p> <ol> <li>ACL Response:<ol> <li>200 OK Response.</li> <li>body returned must accomplish AccessControlPolicyList data structure.</li> <li>apiInvokerPolicies must:<ol> <li>Contain two objects.</li> <li>One object must match with apiInvokerId1 and the other one with apiInvokerId2 an registered previously.</li> </ol> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_access_control_policy/#test-case-4-retrieve-acl-filtered-by-api-invoker-id","title":"Test Case 4: Retrieve ACL filtered by api-invoker-id","text":"<p>Test ID: capif_api_acl-4</p> <p>Description:</p> <p>This test case will check that an API Provider can retrieve ACL filtering by apiInvokerId from CAPIF containing 1 objects.</p> <p>Pre-Conditions:</p> <ul> <li>API Provider had a Service API Published on CAPIF</li> <li>Two API Invokers had a Security Context for same Service API published by provider.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Store serviceApiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Perform Invoker Onboarding store apiInvokerId</p> </li> <li>Discover published APIs</li> <li> <p>Create Security Context for this Invoker for both published APIs</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Use Invoker Certificate</li> </ul> </li> <li> <p>Repeat previous 3 steps in order to have a new Invoker.</p> </li> <li> <p>Provider Retrieve ACL for serviceApiId</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId1}?aef-id=${aef_id}&amp;api-invoker-id={apiInvokerId1}</li> <li>Use serviceApiId, aefId and apiInvokerId1</li> <li>Use AEF Provider Certificate</li> </ul> </li> <li> <p>Provider Retrieve ACL for serviceApiId</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId1}?aef-id=${aef_id}&amp;api-invoker-id={apiInvokerId2}</li> <li>Use serviceApiId, aefId and apiInvokerId2</li> <li>Use AEF Provider Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Provider at CCF.</li> <li>Publish a provider API with name service_1 and service_2</li> <li>Register and onboard Invoker at CCF</li> <li>Store signed Certificate</li> <li>Create Security Context</li> <li>Provider Get ACL information with query parameter indicating first api-invoker-id.</li> <li>Provider Get ACL information with query parameter indicating second api-invoker-id.</li> </ol> <p>Expected Result:</p> <ol> <li> <p>ACL Response:</p> <ol> <li>200 OK Response.</li> <li>body returned must accomplish AccessControlPolicyList data structure.</li> <li>apiInvokerPolicies must:<ol> <li>Contain one objects.</li> <li>Object must match with apiInvokerId1.</li> </ol> </li> </ol> </li> <li> <p>ACL Response:</p> <ol> <li>200 OK Response.</li> <li>body returned must accomplish AccessControlPolicyList data structure.</li> <li>apiInvokerPolicies must:<ol> <li>Contain one objects.</li> <li>Object must match with apiInvokerId2.</li> </ol> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_access_control_policy/#test-case-5-retrieve-acl-filtered-by-supported-features","title":"Test Case 5: Retrieve ACL filtered by supported-features","text":"<p>Test ID: capif_api_acl-5</p> <p>Description:</p> <p>CURRENTLY NOT SUPPORTED FEATURE</p> <p>This test case will check that an API Provider can retrieve ACL filtering by supportedFeatures from CAPIF containing 1 objects.</p> <p>Pre-Conditions:</p> <ul> <li>API Provider had a Service API Published on CAPIF</li> <li>Two API Invokers had a Security Context for same Service API published by provider.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Store serviceApiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Perform Invoker Onboarding store apiInvokerId</p> </li> <li>Discover published APIs</li> <li> <p>Create Security Context for this Invoker for both published APIs</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Use Invoker Certificate</li> </ul> </li> <li> <p>Repeat previous 3 steps in order to have a new Invoker.</p> </li> <li> <p>Provider Retrieve ACL for serviceApiId</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId1}?aef-id=${aef_id}&amp;supported-features={apiInvokerId1}</li> <li>Use serviceApiId, aefId and apiInvokerId1</li> <li>Use AEF Provider Certificate</li> </ul> </li> <li> <p>Provider Retrieve ACL for serviceApiId</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId1}?aef-id=${aef_id}&amp;supported-features={apiInvokerId2}</li> <li>Use serviceApiId, aefId and apiInvokerId2</li> <li>Use AEF Provider Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Provider at CCF.</li> <li>Publish a provider API with name service_1 and service_2</li> <li>Register and onboard Invoker at CCF</li> <li>Store signed Certificate</li> <li>Create Security Context</li> <li>Provider Get ACL information with query parameter indicating first supported-features.</li> <li>Provider Get ACL information with query parameter indicating second supported-features.</li> </ol> <p>Expected Result:</p> <ol> <li> <p>ACL Response:</p> <ol> <li>200 OK Response.</li> <li>body returned must accomplish AccessControlPolicyList data structure.</li> <li>apiInvokerPolicies must:<ol> <li>Contain one objects.</li> <li>Object must match with supportedFeatures1.</li> </ol> </li> </ol> </li> <li> <p>ACL Response:</p> <ol> <li>200 OK Response.</li> <li>body returned must accomplish AccessControlPolicyList data structure.</li> <li>apiInvokerPolicies must:<ol> <li>Contain one objects.</li> <li>Object must match with supportedFeatures1.</li> </ol> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_access_control_policy/#test-case-6-retrieve-acl-with-aef-id-not-valid","title":"Test Case 6: Retrieve ACL with aef-id not valid","text":"<p>Test ID: capif_api_acl-6</p> <p>Description:</p> <p>This test case will check that an API Provider can't retrieve ACL from CAPIF if aef-id is not valid</p> <p>Pre-Conditions:</p> <ul> <li>API Provider had a Service API Published on CAPIF</li> <li>API Invoker had a Security Context for Service API published.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Store serviceApiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Perform Invoker Onboarding store apiInvokerId</p> </li> <li>Discover published APIs</li> <li> <p>Create Security Context for this Invoker</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Use Invoker Certificate</li> </ul> </li> <li> <p>Provider Retrieve ACL</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId}?aef-id=${AEF_ID_NOT_VALID}</li> <li>Use serviceApiId and AEF_ID_NOT_VALID</li> <li>Use AEF Provider Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Provider at CCF.</li> <li>Publish a provider API with name service_1</li> <li>Register and onboard Invoker at CCF</li> <li>Store signed Certificate</li> <li>Create Security Context</li> <li>Provider Get ACL information.</li> </ol> <p>Expected Result:</p> <ol> <li>ACL Response:<ol> <li>404 Not Found Response.</li> <li>body returned must accomplish Problem Details data structure.</li> <li>apiInvokerPolicies must:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>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}\".</li> <li>cause with message \"Wrong id\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_access_control_policy/#test-case-7-retrieve-acl-with-service-id-not-valid","title":"Test Case 7: Retrieve ACL with service-id not valid","text":"<p>Test ID: capif_api_acl-7</p> <p>Description:</p> <p>This test case will check that an API Provider can't retrieve ACL from CAPIF if service-api-id is not valid</p> <p>Pre-Conditions:</p> <ul> <li>API Provider had a Service API Published on CAPIF</li> <li>API Invoker had a Security Context for Service API published.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Store serviceApiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Perform Invoker Onboarding store apiInvokerId</p> </li> <li>Discover published APIs</li> <li> <p>Create Security Context for this Invoker</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Use Invoker Certificate</li> </ul> </li> <li> <p>Provider Retrieve ACL</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${NOT_VALID_SERVICE_API_ID}?aef-id=${aef_id}</li> <li>Use NOT_VALID_SERVICE_API_ID and aef_id</li> <li>Use AEF Provider Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Provider at CCF.</li> <li>Publish a provider API with name service_1</li> <li>Register and onboard Invoker at CCF</li> <li>Store signed Certificate</li> <li>Create Security Context</li> <li>Provider Get ACL information.</li> </ol> <p>Expected Result:</p> <ol> <li>ACL Response:<ol> <li>404 Not Found Response.</li> <li>body returned must accomplish Problem Details data structure.</li> <li>apiInvokerPolicies must:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>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}\".</li> <li>cause with message \"Wrong id\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_access_control_policy/#test-case-8-retrieve-acl-with-service-api-id-and-aef-id-not-valid","title":"Test Case 8: Retrieve ACL with service-api-id and aef-id not valid","text":"<p>Test ID: capif_api_acl-8</p> <p>Description:</p> <p>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</p> <p>Pre-Conditions:</p> <ul> <li>API Provider had a Service API Published on CAPIF</li> <li>API Invoker had a Security Context for Service API published.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Store serviceApiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Perform Invoker Onboarding store apiInvokerId</p> </li> <li>Discover published APIs</li> <li> <p>Create Security Context for this Invoker</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Use Invoker Certificate</li> </ul> </li> <li> <p>Provider Retrieve ACL</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${NOT_VALID_SERVICE_API_ID}?aef-id=${AEF_ID_NOT_VALID}</li> <li>Use NOT_VALID_SERVICE_API_ID and aef_id</li> <li>Use AEF Provider Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Provider at CCF.</li> <li>Publish a provider API with name service_1</li> <li>Register and onboard Invoker at CCF</li> <li>Store signed Certificate</li> <li>Create Security Context</li> <li>Provider Get ACL information.</li> </ol> <p>Expected Result:</p> <ol> <li>ACL Response:<ol> <li>404 Not Found Response.</li> <li>body returned must accomplish Problem Details data structure.</li> <li>apiInvokerPolicies must:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>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}\".</li> <li>cause with message \"Wrong id\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_access_control_policy/#test-case-9-retrieve-acl-without-securitycontext-created-previously-by-invoker","title":"Test Case 9: Retrieve ACL without SecurityContext created previously by Invoker","text":"<p>Test ID: capif_api_acl-9</p> <p>Description:</p> <p>This test case will check that an API Provider can't retrieve ACL if no invoker had requested Security Context to CAPIF</p> <p>Pre-Conditions:</p> <ul> <li>API Provider had a Service API Published on CAPIF</li> <li>API Invoker created but no Security Context for Service API published had been requested.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Store serviceApiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Perform Invoker Onboarding store apiInvokerId</p> </li> <li> <p>Discover published APIs</p> </li> <li> <p>Provider Retrieve ACL</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId}?aef-id=${aef_id}</li> <li>Use serviceApiId and aefId</li> <li>Use AEF Provider Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Provider at CCF.</li> <li>Publish a provider API with name service_1</li> <li>Register and onboard Invoker at CCF</li> <li>Store signed Certificate</li> <li>Create Security Context</li> <li>Provider Get ACL information.</li> </ol> <p>Expected Result:</p> <ol> <li>ACL Response:<ol> <li>404 Not Found Response.</li> <li>body returned must accomplish Problem Details data structure.</li> <li>apiInvokerPolicies must:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>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}\".</li> <li>cause with message \"Wrong id\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_access_control_policy/#test-case-10-retrieve-acl-filtered-by-api-invoker-id-not-present","title":"Test Case 10: Retrieve ACL filtered by api-invoker-id not present","text":"<p>Test ID: capif_api_acl-10</p> <p>Description:</p> <p>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.</p> <p>Pre-Conditions:</p> <ul> <li>API Provider had a Service API Published on CAPIF</li> <li>API Invoker had a Security Context for Service API published.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Store serviceApiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Perform Invoker Onboarding store apiInvokerId</p> </li> <li>Discover published APIs</li> <li> <p>Create Security Context for this Invoker</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Use Invoker Certificate</li> </ul> </li> <li> <p>Provider Retrieve ACL</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId}?aef-id=${aef_id}&amp;api-invoker-id={NOT_VALID_API_INVOKER_ID}</li> <li>Use serviceApiId, aefId and NOT_VALID_API_INVOKER_ID</li> <li>Use AEF Provider Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Provider at CCF.</li> <li>Publish a provider API with name service_1</li> <li>Register and onboard Invoker at CCF</li> <li>Store signed Certificate</li> <li>Create Security Context</li> <li>Provider Get ACL information.</li> </ol> <p>Expected Result:</p> <ol> <li>ACL Response:<ol> <li>404 Not Found Response.</li> <li>body returned must accomplish Problem Details data structure.</li> <li>apiInvokerPolicies must:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>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}\".</li> <li>cause with message \"Wrong id\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_access_control_policy/#test-case-11-retrieve-acl-with-apf-certificate","title":"Test Case 11: Retrieve ACL with APF Certificate","text":"<p>Test ID: capif_api_acl-11</p> <p>Description:</p> <p>This test case will check that an API Provider can't retrieve ACL from CAPIF using APF Certificate</p> <p>Pre-Conditions:</p> <ul> <li>API Provider had a Service API Published on CAPIF</li> <li>API Invoker had a Security Context for Service API published.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Store serviceApiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Perform Invoker Onboarding store apiInvokerId</p> </li> <li>Discover published APIs</li> <li> <p>Create Security Context for this Invoker</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Use Invoker Certificate</li> </ul> </li> <li> <p>Provider Retrieve ACL</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId}?aef-id=${aef_id}</li> <li>Use serviceApiId and aefId</li> <li>Use APF Provider Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Provider at CCF.</li> <li>Publish a provider API with name service_1</li> <li>Register and onboard Invoker at CCF</li> <li>Store signed Certificate</li> <li>Create Security Context</li> <li>Provider Get ACL information.</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Logging Service must accomplish:<ol> <li>401 Unauthorized</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 401</li> <li>title with message \"Unauthorized\"</li> <li>detail with message \"Role not authorized for this API route\".</li> <li>cause with message \"Certificate not authorized\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_access_control_policy/#test-case-12-retrieve-acl-with-amf-certificate","title":"Test Case 12: Retrieve ACL with AMF Certificate","text":"<p>Test ID: capif_api_acl-12</p> <p>Description:</p> <p>This test case will check that an API Provider can't retrieve ACL from CAPIF using AMF Certificate</p> <p>Pre-Conditions:</p> <ul> <li>API Provider had a Service API Published on CAPIF</li> <li>API Invoker had a Security Context for Service API published.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Store serviceApiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Perform Invoker Onboarding store apiInvokerId</p> </li> <li>Discover published APIs</li> <li> <p>Create Security Context for this Invoker</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Use Invoker Certificate</li> </ul> </li> <li> <p>Provider Retrieve ACL</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId}?aef-id=${aef_id}</li> <li>Use serviceApiId and aefId</li> <li>Use AMF Provider Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Provider at CCF.</li> <li>Publish a provider API with name service_1</li> <li>Register and onboard Invoker at CCF</li> <li>Store signed Certificate</li> <li>Create Security Context</li> <li>Provider Get ACL information.</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Logging Service must accomplish:<ol> <li>401 Unauthorized</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 401</li> <li>title with message \"Unauthorized\"</li> <li>detail with message \"Role not authorized for this API route\".</li> <li>cause with message \"Certificate not authorized\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_access_control_policy/#test-case-13-retrieve-acl-with-invoker-certificate","title":"Test Case 13: Retrieve ACL with Invoker Certificate","text":"<p>Test ID: capif_api_acl-13</p> <p>Description:</p> <p>This test case will check that an API Provider can't retrieve ACL from CAPIF using Invoker Certificate</p> <p>Pre-Conditions:</p> <ul> <li>API Provider had a Service API Published on CAPIF</li> <li>API Invoker had a Security Context for Service API published.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Store serviceApiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Perform Invoker Onboarding store apiInvokerId</p> </li> <li>Discover published APIs</li> <li> <p>Create Security Context for this Invoker</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Use Invoker Certificate</li> </ul> </li> <li> <p>Provider Retrieve ACL</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId}?aef-id=${aef_id}</li> <li>Use serviceApiId and aefId</li> <li>Use Invoker Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Provider at CCF.</li> <li>Publish a provider API with name service_1</li> <li>Register and onboard Invoker at CCF</li> <li>Store signed Certificate</li> <li>Create Security Context</li> <li>Provider Get ACL information.</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Logging Service must accomplish:<ol> <li>401 Unauthorized</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 401</li> <li>title with message \"Unauthorized\"</li> <li>detail with message \"Role not authorized for this API route\".</li> <li>cause with message \"Certificate not authorized\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_access_control_policy/#test-case-14-no-acl-for-invoker-after-be-removed","title":"Test Case 14: No ACL for invoker after be removed","text":"<p>Test ID: capif_api_acl-14</p> <p>Description:</p> <p>This test case will check that ACLs are removed after invoker is removed.</p> <p>Pre-Conditions:</p> <ul> <li>API Provider had a Service API Published on CAPIF</li> <li>API Invoker had a Security Context for Service API published and ACL is present</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Store serviceApiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Perform Invoker Onboarding store apiInvokerId</p> </li> <li>Discover published APIs</li> <li> <p>Create Security Context for this Invoker</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Use Invoker Certificate</li> </ul> </li> <li> <p>Provider Retrieve ACL</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId}?aef-id=${aef_id}&amp;api-invoker-id={api-invoker-id}</li> <li>Use serviceApiId, aefId and api-invoker-id</li> <li>Use AEF Provider Certificate</li> </ul> </li> <li>Remove Invoker from CAPIF</li> <li>Provider Retrieve ACL<ul> <li>Send GET https://{CAPIF_HOSTNAME}/access-control-policy/v1/accessControlPolicyList/${serviceApiId}?aef-id=${aef_id}&amp;api-invoker-id={api-invoker-id}</li> <li>Use serviceApiId, aefId and api-invoker-id</li> <li>Use AEF Provider Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Provider at CCF.</li> <li>Publish a provider API with name service_1</li> <li>Register and onboard Invoker at CCF</li> <li>Store signed Certificate</li> <li>Create Security Context</li> <li>Provider Get ACL information of invoker.</li> <li>Remove Invoker from CAPIF.</li> <li>Provider Get ACL information of invoker.</li> </ol> <p>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.</p> <ol> <li>ACL Response:<ol> <li>404 Not Found Response.</li> <li>body returned must accomplish Problem Details data structure.</li> <li>apiInvokerPolicies must:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>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\".</li> <li>cause with message \"Wrong id\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_auditing_service/","title":"Test Plan for CAPIF Api Auditing Service","text":"<p>At this documentation you will have all information and related files and examples of test plan for this API.</p>"},{"location":"testing/testplan/api_auditing_service/#test-case-1-get-capif-log-entry","title":"Test Case 1: Get CAPIF Log Entry.","text":"<p>Test ID: capif_api_auditing-1</p> <p>Description:</p> <p>This test case will check that a CAPIF AMF can get log entry to Logging Service</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF provider is pre-authorised (has valid AMF cert from CAPIF Authority)</li> <li>Service exist in CAPIF</li> <li>Invoker exist in CAPIF</li> <li>Log Entry exist in CAPIF</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform provider onboarding, invoker onboarding </p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body [service api description] with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Create Log Entry:</p> <ul> <li>Send POST to https://{CAPIF_HOSTNAME}/api-invocation-logs/v1/{aefId}/logs</li> <li>body log entry request body</li> <li>Use AEF Certificate</li> </ul> </li> <li> <p>Get Log:</p> <ol> <li>Send GET to https://{CAPIF_HOSTNAME}/logs/v1/apiInvocationLogs?aef-id={aefId}&amp;api-invoker-id={api-invoker-id}</li> <li>Use AMF Certificate</li> </ol> </li> </ol> <p>Execution Steps:   1. Register Provider and Invoker CCF   2. Publish Service   3. Create Log Entry   4. Get Log Entry</p> <p>Expected Result:</p> <ol> <li>Response to Logging Service must accomplish:<ol> <li>200 OK</li> <li>Response Body must follow InvocationLog data structure with:<ul> <li>aefId</li> <li>apiInvokerId</li> <li>logs</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_auditing_service/#test-case-2-get-capif-log-entry-with-no-log-entry-in-capif","title":"Test Case 2: Get CAPIF Log Entry With no Log entry in CAPIF.","text":"<p>Test ID: capif_api_auditing-2</p> <p>Description:</p> <p>This test case will check that a CAPIF AEF can create log entry to Logging Service</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF provider is pre-authorised (has valid AMF cert from CAPIF Authority)</li> <li>Service exist in CAPIF</li> <li>Invoker exist in CAPIF</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform provider onboarding, invoker onboarding </p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body [service api description] with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Get Log:</p> <ol> <li>Send GET to https://{CAPIF_HOSTNAME}/logs/v1/apiInvocationLogs?aef-id={aefId}&amp;api-invoker-id={api-invoker-id}</li> <li>Use AMF Certificate</li> </ol> </li> </ol> <p>Execution Steps:   1. Register Provider and Invoker CCF   2. Publish Service   3. Get Log Entry</p> <p>Expected Result:</p> <ol> <li>Response to Logging Service must accomplish:<ol> <li>404 Not Found</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 404</li> <li>title with message \"Not Found Log Entry in CAPIF\".</li> <li>cause with message \"Not Exist Logs with the filters applied\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_auditing_service/#test-case-3-get-capif-log-entry-without-aef-id-and-api-invoker-id","title":"Test Case 3: Get CAPIF Log Entry without aef-id and api-invoker-id.","text":"<p>Test ID: capif_api_auditing-3</p> <p>Description:</p> <p>This test case will check that a CAPIF AEF can create log entry to Logging Service</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF provider is no pre-authorised (has no valid AMF cert from CAPIF Authority)</li> <li>Service exist in CAPIF</li> <li>Invoker exist in CAPIF</li> <li>Log Entry exist in CAPIF</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform provider onboarding, invoker onboarding </p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body [service api description] with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Create Log Entry:</p> <ul> <li>Send POST to https://{CAPIF_HOSTNAME}/api-invocation-logs/v1/{aefId}/logs</li> <li>body log entry request body</li> <li>Use AEF Certificate</li> </ul> </li> <li> <p>Get Log:</p> <ol> <li>Send GET to *https://{CAPIF_HOSTNAME}/logs/v1/apiInvocationLogs</li> <li>Use AMF Certificate</li> </ol> </li> </ol> <p>Execution Steps:   1. Register Provider and Invoker CCF   2. Publish Service   3. Create Log Entry   4. Get Log Entry</p> <p>Expected Result:</p> <ol> <li>Response to Logging Service must accomplish:<ol> <li>400 Bad Request</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 400</li> <li>title with message \"Bad Request\"</li> <li>detail with message \"aef_id and api_invoker_id parameters are mandatory\".</li> <li>cause with message \"Mandatory parameters missing\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_auditing_service/#test-case-4-get-capif-log-entry-with-filtter-api-version","title":"Test Case 4: Get CAPIF Log Entry with filtter api-version.","text":"<p>Test ID: capif_api_auditing-4</p> <p>Description:</p> <p>This test case will check that a CAPIF AMF can get log entry to Logging Service</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF provider is pre-authorised (has valid AMF cert from CAPIF Authority)</li> <li>Service exist in CAPIF</li> <li>Invoker exist in CAPIF</li> <li>Log Entry exist in CAPIF</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform provider onboarding, invoker onboarding </p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body [service api description] with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Create Log Entry:</p> <ul> <li>Send POST to https://{CAPIF_HOSTNAME}/api-invocation-logs/v1/{aefId}/logs</li> <li>body log entry request body</li> <li>Use AEF Certificate</li> </ul> </li> <li> <p>Get Log:</p> <ol> <li>Send GET to https://{CAPIF_HOSTNAME}/logs/v1/apiInvocationLogs?aef-id={aefId}&amp;api-invoker-id={api-invoker-id}&amp;api-version={v1}</li> <li>Use AMF Certificate</li> </ol> </li> </ol> <p>Execution Steps:   1. Register Provider and Invoker CCF   2. Publish Service   3. Create Log Entry   4. Get Log Entry</p> <p>Expected Result:</p> <ol> <li>Response to Logging Service must accomplish:<ol> <li>200 OK</li> <li>Response Body must follow InvocationLog data structure with:<ul> <li>aefId</li> <li>apiInvokerId</li> <li>logs</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_auditing_service/#test-case-5-get-capif-log-entry-with-filter-api-version-but-not-exist-in-log-entry","title":"Test Case 5: Get CAPIF Log Entry with filter api-version but not exist in log entry.","text":"<p>Test ID: capif_api_auditing-4</p> <p>Description:</p> <p>This test case will check that a CAPIF AMF can get log entry to Logging Service</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF provider is pre-authorised (has valid AMF cert from CAPIF Authority)</li> <li>Service exist in CAPIF</li> <li>Invoker exist in CAPIF</li> <li>Log Entry exist in CAPIF</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform provider onboarding, invoker onboarding </p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body [service api description] with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Create Log Entry:</p> <ul> <li>Send POST to https://{CAPIF_HOSTNAME}/api-invocation-logs/v1/{aefId}/logs</li> <li>body log entry request body</li> <li>Use AEF Certificate</li> </ul> </li> <li> <p>Get Log:</p> <ol> <li>Send GET to https://{CAPIF_HOSTNAME}/logs/v1/apiInvocationLogs?aef-id={aefId}&amp;api-invoker-id={api-invoker-id}&amp;api-version={v58}</li> <li>Use AMF Certificate</li> </ol> </li> </ol> <p>Execution Steps:   1. Register Provider and Invoker CCF   2. Publish Service   3. Create Log Entry   4. Get Log Entry</p> <p>Expected Result:</p> <ol> <li>Response to Logging Service must accomplish:<ol> <li>404 Not Found</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 404</li> <li>detail with message \"Parameters do not match any log entry\"</li> <li>cause with message \"No logs found\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_discover_service/","title":"Test Plan for CAPIF Discover Service","text":"<p>At this documentation you will have all information and related files and examples of test plan for this API.</p>"},{"location":"testing/testplan/api_discover_service/#test-case-1-discover-published-service-apis-by-authorised-api-invoker","title":"Test Case 1: Discover Published service APIs by Authorised API Invoker","text":"<p>Test ID: capif_api_discover_service-1</p> <p>Description:</p> <p>This test case will check if NetApp (Invoker) can discover published service APIs.</p> <p>Pre-Conditions:</p> <ul> <li>Service APIs are published.</li> <li>NetApp was registered previously</li> <li>NetApp was onboarded previously with {onboardingId}</li> </ul> <p>Information of Test:</p> <ol> <li>Perform Provider Registration and Invoker Onboarding</li> <li>Publish Service API at CCF:<ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li>Request Discover Published APIs:<ul> <li>Send GET to https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}</li> <li>Param api-invoker-id is mandatory</li> <li>Use Invoker Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF, store certificates and Publish Service API at CCF</li> <li>Register Invoker and Onboard Invoker at CCF</li> <li>Discover Service APIs by Invoker</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Response to Publish request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow ServiceAPIDescription data structure with:<ul> <li>apiId</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId}</li> </ol> </li> <li> <p>Response to Onboard request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow APIInvokerEnrolmentDetails data structure with:<ul> <li>apiInvokerId</li> <li>onboardingInformation-&gt;apiInvokerCertificate must contain the public key signed.</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}</li> </ol> </li> <li>Response to Discover Request By Invoker:<ol> <li>200 OK response.</li> <li>Response body must follow DiscoveredAPIs data structure:<ul> <li>Check if DiscoveredAPIs contains the API Published previously</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_discover_service/#test-case-2-discover-published-service-apis-by-non-authorised-api-invoker","title":"Test Case 2: Discover Published service APIs by Non Authorised API Invoker","text":"<p>Test ID: capif_api_discover_service-2</p> <p>Description:</p> <p>This test case will check that an API Publisher can't discover published APIs because is not authorized.</p> <p>Pre-Conditions:</p> <ul> <li>Service APIs are published.</li> </ul> <p>Information of Test:</p> <ol> <li>Perform Provider Registration and Invoker Onboarding</li> <li>Publish Service API at CCF:<ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li>Request Discover Published APIs by no invoker entity:<ul> <li>Send GET to https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}</li> <li>Param api-invoker-id is mandatory</li> <li>Use not Invoker Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF, store certificates and Publish Service API at CCF</li> <li>Register Invoker and Onboard Invoker at CCF</li> <li>Discover Service APIs by no invoker entity</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Response to Publish request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow ServiceAPIDescription data structure with:<ul> <li>apiId</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId}</li> </ol> </li> <li> <p>Response to Onboard request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow APIInvokerEnrolmentDetails data structure with:<ul> <li>apiInvokerId</li> <li>onboardingInformation-&gt;apiInvokerCertificate must contain the public key signed.</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}</li> </ol> </li> <li> <p>Response to Discover Request By no invoker entity:</p> <ol> <li>401 Unauthorized</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 401</li> <li>title with message \"Unauthorized\"</li> <li>detail with message \"User not authorized\".</li> <li>cause with message \"Certificate not authorized\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_discover_service/#test-case-3-discover-published-service-apis-by-not-registered-api-invoker","title":"Test Case 3: Discover Published service APIs by not registered API Invoker","text":"<p>Test ID: capif_api_discover_service-3</p> <p>Description:</p> <p>This test case will check that a not registered invoker is forbidden to discover published APIs.</p> <p>Pre-Conditions:</p> <ul> <li>Service APIs are published.</li> </ul> <p>Information of Test:</p> <ol> <li>Perform Provider Registration and Invoker Onboarding</li> <li>Publish Service API at CCF:<ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li>Request Discover Published APIs with not valid apiInvoker:<ul> <li>Send GET to https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={INVOKER_NOT_REGISTERED}</li> <li>Param api-invoker-id is mandatory</li> <li>Using invoker certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF, store certificates and Publish Service API at CCF</li> <li>Register Invoker and Onboard Invoker at CCF</li> <li>Discover Service APIs by Publisher</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Response to Publish request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow ServiceAPIDescription data structure with:<ul> <li>apiId</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId}</li> </ol> </li> <li> <p>Response to Onboard request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow APIInvokerEnrolmentDetails data structure with:<ul> <li>apiInvokerId</li> <li>onboardingInformation-&gt;apiInvokerCertificate must contain the public key signed.</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}</li> </ol> </li> <li> <p>Response to Discover Request By Invoker:</p> <ol> <li>404 Not Found</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"API Invoker does not exist\".</li> <li>cause with message \"API Invoker id not found\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_discover_service/#test-case-4-discover-published-service-apis-by-registered-api-invoker-with-1-result-filtered","title":"Test Case 4: Discover Published service APIs by registered API Invoker with 1 result filtered","text":"<p>Test ID: capif_api_discover_service-4</p> <p>Description:</p> <p>This test case will check if NetApp (Invoker) can discover published service APIs.</p> <p>Pre-Conditions:</p> <ul> <li>At least 2 Service APIs are published.</li> <li>NetApp was registered previously</li> <li>NetApp was onboarded previously with {onboardingId}</li> </ul> <p>Information of Test:</p> <ol> <li>Perform Provider Registration and Invoker Onboarding</li> <li>Publish Service API at CCF:<ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li>Publish Service API at CCF:<ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_2</li> <li>Use APF Certificate</li> </ul> </li> <li>Request Discover Published APIs filtering by api-name:<ul> <li>Send GET to ccf_discover_url https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}&amp;api-name=service_1</li> <li>Param api-invoker-id is mandatory</li> <li>Using invoker certificate</li> <li>filter by api-name service_1</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF, store certificates and Publish Service API service_1 and service_2 at CCF</li> <li>Register Invoker and Onboard Invoker at CCF</li> <li>Discover Service APIs by Invoker.</li> <li>Discover filtered by api-name service_1 Service APIs by Invoker</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Publish request must accomplish:<ol> <li>201 Created</li> <li>Response Body must follow ServiceAPIDescription data structure with:<ul> <li>apiId</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId}</li> </ol> </li> <li>Response to Onboard request must accomplish:<ol> <li>201 Created</li> <li>Response Body must follow APIInvokerEnrolmentDetails data structure with:<ul> <li>apiInvokerId</li> <li>onboardingInformation-&gt;apiInvokerCertificate must contain the public key signed.</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}</li> </ol> </li> <li>Response to Discover Request By Invoker:<ol> <li>200 OK response.</li> <li>Response body must follow DiscoveredAPIs data structure:<ul> <li>Check if DiscoveredAPIs contains previously registered Service APIs published.</li> </ul> </li> </ol> </li> <li>Response to Discover Request By Invoker:<ol> <li>200 OK response.</li> <li>Response body must follow DiscoveredAPIs data structure:<ul> <li>Check if DiscoveredAPIs contains only Service API published with api-name service_1</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_discover_service/#test-case-5-discover-published-service-apis-by-registered-api-invoker-filtered-with-no-match","title":"Test Case 5: Discover Published service APIs by registered API Invoker filtered with no match","text":"<p>Test ID: capif_api_discover_service-5</p> <p>Description:</p> <p>This test case will check if NetApp (Invoker) can discover published service APIs.</p> <p>Pre-Conditions:</p> <ul> <li>At least 2 Service APIs are published.</li> <li>NetApp was registered previously</li> <li>NetApp was onboarded previously with {onboardingId}</li> </ul> <p>Information of Test:</p> <ol> <li>Perform Provider Registration and Invoker Onboarding</li> <li>Publish Service API at CCF:<ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li>Publish Service API at CCF:<ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_2</li> <li>Use APF Certificate</li> </ul> </li> <li>Request Discover Published APIs filtering by api-name not published:<ul> <li>Send GET to ccf_discover_url https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}&amp;api-name=NOT_VALID_NAME</li> <li>Param api-invoker-id is mandatory</li> <li>Using invoker certificate</li> <li>filter by api-name NOT_VALID_NAME</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF, store certificates and Publish Service API service_1 and service_2 at CCF</li> <li>Register Invoker and Onboard Invoker at CCF</li> <li>Discover Service APIs by Invoker.</li> <li>Discover filtered by api-name not published Service APIs by Invoker</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Publish request must accomplish:<ol> <li>201 Created</li> <li>Response Body must follow ServiceAPIDescription data structure with:<ul> <li>apiId</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId}</li> </ol> </li> <li>Response to Onboard request must accomplish:<ol> <li>201 Created</li> <li>Response Body must follow APIInvokerEnrolmentDetails data structure with:<ul> <li>apiInvokerId</li> <li>onboardingInformation-&gt;apiInvokerCertificate must contain the public key signed.</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}</li> </ol> </li> <li>Response to Discover Request By Invoker:<ol> <li>200 OK response.</li> <li>Response body must follow DiscoveredAPIs data structure:<ul> <li>Check if DiscoveredAPIs contains previously registered Service APIs published.</li> </ul> </li> </ol> </li> <li>Response to Discover Request By Invoker:<ol> <li>404 Not Found response.</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"API Invoker {api_invoker_id} has no API Published that accomplish filter conditions\".</li> <li>cause with message \"No API Published accomplish filter conditions\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_discover_service/#test-case-6-discover-published-service-apis-by-registered-api-invoker-not-filtered","title":"Test Case 6: Discover Published service APIs by registered API Invoker not filtered","text":"<p>Test ID: capif_api_discover_service-6</p> <p>Description:</p> <p>This test case will check if NetApp (Invoker) can discover published service APIs.</p> <p>Pre-Conditions:</p> <ul> <li>2 Service APIs are published.</li> <li>NetApp was registered previously</li> <li>NetApp was onboarded previously with {onboardingId}</li> </ul> <p>Information of Test:</p> <ol> <li>Perform Provider Registration and Invoker Onboarding</li> <li>Publish Service API at CCF:<ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li>Publish Service API at CCF:<ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_2</li> <li>Use APF Certificate</li> </ul> </li> <li>Request Discover Published APIs not filtered:<ul> <li>Send GET to ccf_discover_url https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}</li> <li>Param api-invoker-id is mandatory</li> <li>Using invoker certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF, store certificates and Publish Service API service_1 and service_2 at CCF</li> <li>Register Invoker and Onboard Invoker at CCF</li> <li>Discover Service APIs by Invoker.</li> <li>Discover without filter by Invoker</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Response to Publish request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow ServiceAPIDescription data structure with:<ul> <li>apiId</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId}</li> </ol> </li> <li> <p>Response to Onboard request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow APIInvokerEnrolmentDetails data structure with:<ul> <li>apiInvokerId</li> <li>onboardingInformation-&gt;apiInvokerCertificate must contain the public key signed.</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}</li> </ol> </li> <li> <p>Response to Discover Request By Invoker:</p> <ol> <li>200 OK response.</li> <li>Response body must follow DiscoveredAPIs data structure:<ul> <li>Check if DiscoveredAPIs contains the 2 previously registered Service APIs published.</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_events_service/","title":"Test Plan for CAPIF Api Events Service","text":"<p>At this documentation you will have all information and related files and examples of test plan for this API.</p>"},{"location":"testing/testplan/api_events_service/#tests","title":"Tests","text":""},{"location":"testing/testplan/api_events_service/#test-case-1-creates-a-new-individual-capif-event-subscription","title":"Test Case 1: Creates a new individual CAPIF Event Subscription.","text":"<p>Test ID: capif_api_events-1</p> <p>Description:</p> <p>This test case will check that a CAPIF subscriber (Invoker or Publisher) can Subscribe to Events Pre-Conditions:</p> <ul> <li>CAPIF subscriber is pre-authorised (has valid InvokerId or apfId from CAPIF Authority)</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Invoker Onboarding</p> </li> <li> <p>Event Subscription:</p> <ol> <li>Send POST to https://{CAPIF_HOSTNAME}/capif-events/v1/{subscriberId}/subscriptions</li> <li>body event subscription request body</li> <li>Use Invoker Certificate</li> </ol> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Invoker and Onboard Invoker at CCF</li> <li>Subscribe to Events</li> <li>Retrieve {subscriberId} and {subscriptionId} from Location Header</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Response to Onboard request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow APIInvokerEnrolmentDetails data structure with:<ul> <li>apiInvokerId</li> <li>onboardingInformation-&gt;apiInvokerCertificate must contain the public key signed.</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}</li> </ol> </li> <li> <p>Response to Event Subscription must accomplish:</p> <ol> <li>201 Created</li> <li>The URI of the created resource shall be returned in the \"Location\" HTTP header, following this structure: *{apiRoot}/capif-events/{apiVersion}/{subscriberId}/subscriptions/{subscriptionId}</li> <li>Response Body must follow EventSubscription data structure.</li> </ol> </li> <li> <p>Event Subscriptions are stored in CAPIF Database</p> </li> </ol>"},{"location":"testing/testplan/api_events_service/#test-case-2-creates-a-new-individual-capif-event-subscription-with-invalid-subscriberid","title":"Test Case 2: Creates a new individual CAPIF Event Subscription with Invalid SubscriberId","text":"<p>Test ID: capif_api_events-2</p> <p>Description:</p> <p>This test case will check that a CAPIF subscriber (Invoker or Publisher) cannot Subscribe to Events without valid SubcriberId</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF subscriber is not pre-authorised (has invalid InvokerId or apfId)</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Invoker Onboarding</p> </li> <li> <p>Event Subscription:</p> <ol> <li>Send POST to https://{CAPIF_HOSTNAME}/capif-events/v1/{SUBSCRIBER_NOT_REGISTERED}/subscriptions</li> <li>body event subscription request body</li> <li>Use Invoker Certificate</li> </ol> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Invoker and Onboard Invoker at CCF</li> <li>Subscribe to Events</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Response to Onboard request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow APIInvokerEnrolmentDetails data structure with:<ul> <li>apiInvokerId</li> <li>onboardingInformation-&gt;apiInvokerCertificate must contain the public key signed.</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}</li> </ol> </li> <li> <p>Response to Event Subscription must accomplish:</p> <ol> <li>404 Not Found</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Invoker or APF or AEF or AMF Not found\".</li> <li>cause with message \"Subscriber Not Found\".</li> </ul> </li> </ol> </li> <li> <p>Event Subscriptions are not stored in CAPIF Database</p> </li> </ol>"},{"location":"testing/testplan/api_events_service/#test-case-3-deletes-an-individual-capif-event-subscription","title":"Test Case 3: Deletes an individual CAPIF Event Subscription","text":"<p>Test ID: capif_api_events-3</p> <p>Description:</p> <p>This test case will check that a CAPIF subscriber (Invoker or Publisher) can Delete an Event Subscription</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF subscriber is pre-authorised (has valid InvokerId or apfId from CAPIF Authority)</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Invoker Onboarding</p> </li> <li> <p>Event Subscription:</p> <ol> <li>Send POST to https://{CAPIF_HOSTNAME}/capif-events/v1/{subscriberId}/subscriptions</li> <li>body event subscription request body</li> <li>Use Invoker Certificate</li> </ol> </li> <li> <p>Remove Event Subscription:</p> <ol> <li>Send DELETE to https://{CAPIF_HOSTNAME}/capif-events/v1/{subscriberId}/subscriptions</li> <li>Use Invoker Certificate</li> </ol> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Invoker and Onboard Invoker at CCF</li> <li>Subscribe to Events</li> <li>Retrieve {subscriberId} and {subscriptionId} from Location Header</li> <li>Remove Event Subscription</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Response to Onboard request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow APIInvokerEnrolmentDetails data structure with:<ul> <li>apiInvokerId</li> <li>onboardingInformation-&gt;apiInvokerCertificate must contain the public key signed.</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}</li> </ol> </li> <li> <p>Response to Event Subscription must accomplish:</p> <ol> <li>201 Created</li> <li>The URI of the created resource shall be returned in the \"Location\" HTTP header, following this structure: *{apiRoot}/capif-events/{apiVersion}/{subscriberId}/subscriptions/{subscriptionId}</li> <li>Response Body must follow EventSubscription data structure.</li> </ol> </li> <li> <p>Event Subscriptions are stored in CAPIF Database</p> </li> <li> <p>Remove Event Subscription:</p> <ol> <li>204 No Content</li> </ol> </li> <li> <p>Event Subscription is not present at CAPIF Database.</p> </li> </ol>"},{"location":"testing/testplan/api_events_service/#test-case-4-deletes-an-individual-capif-event-subscription-with-invalid-subscriberid","title":"Test Case 4: Deletes an individual CAPIF Event Subscription with invalid SubscriberId","text":"<p>Test ID: capif_api_events-4</p> <p>Description:</p> <p>This test case will check that a CAPIF subscriber (Invoker or Publisher) cannot Delete to Events without valid SubcriberId</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF subscriber is pre-authorised (has valid InvokerId or apfId).</li> <li>CAPIF subscriber is subscribed to Events.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Invoker Onboarding</p> </li> <li> <p>Event Subscription:</p> <ol> <li>Send POST to https://{CAPIF_HOSTNAME}/capif-events/v1/{subscriberId}/subscriptions</li> <li>body event subscription request body</li> <li>Use Invoker Certificate</li> </ol> </li> <li> <p>Remove Event Subcription with not valid subscriber:</p> <ol> <li>Send DELETE to to https://{CAPIF_HOSTNAME}/capif-events/v1/{SUBSCRIBER_ID_NOT_VALID}/subscriptions/{subcriptionId}</li> <li>Use Invoker Certificate</li> </ol> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Invoker and Onboard Invoker at CCF</li> <li>Subscribe to Events</li> <li>Retrieve Location Header with subscriptionId.</li> <li>Remove Event Subscribed with not valid Subscriber.</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Response to Onboard request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow APIInvokerEnrolmentDetails data structure with:<ul> <li>apiInvokerId</li> <li>onboardingInformation-&gt;apiInvokerCertificate must contain the public key signed.</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}</li> </ol> </li> <li> <p>Response to Event Subscription must accomplish:</p> <ol> <li>201 Created</li> <li>The URI of the created resource shall be returned in the \"Location\" HTTP header, following this structure: *{apiRoot}/capif-events/{apiVersion}/{subscriberId}/subscriptions/{subscriptionId}</li> <li>Response Body must follow EventSubscription data structure.</li> </ol> </li> <li> <p>Event Subscriptions are stored in CAPIF Database</p> </li> <li>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\".</li> </ol>"},{"location":"testing/testplan/api_events_service/#test-case-5-deletes-an-individual-capif-event-subscription-with-invalid-subscriptionid","title":"Test Case 5: Deletes an individual CAPIF Event Subscription with invalid SubscriptionId","text":"<p>Test ID: capif_api_events-5</p> <p>Description:</p> <p>This test case will check that a CAPIF subscriber (Invoker or Publisher) cannot Delete an Event Subscription without valid SubscriptionId</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF subscriber is pre-authorised (has invalid InvokerId or apfId).</li> <li>CAPIF subscriber is subscribed to Events.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Invoker Onboarding</p> </li> <li> <p>Event Subscription:</p> <ol> <li>Send POST to https://{CAPIF_HOSTNAME}/capif-events/v1/{subscriberId}/subscriptions</li> <li>body event subscription request body</li> <li>Use Invoker Certificate</li> </ol> </li> <li> <p>Remove Event Subcription with not valid subscriber:</p> <ol> <li>Send DELETE to to https://{CAPIF_HOSTNAME}/capif-events/v1/{subcriberId}/subscriptions/{SUBSCRIPTION_ID_NOT_VALID}</li> <li>Use Invoker Certificate</li> </ol> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Invoker and Onboard Invoker at CCF</li> <li>Subscribe to Events</li> <li>Retrieve Location Header with subscriptionId.</li> <li>Remove Event Subscribed with not valid Subscriber.</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Response to Onboard request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow APIInvokerEnrolmentDetails data structure with:<ul> <li>apiInvokerId</li> <li>onboardingInformation-&gt;apiInvokerCertificate must contain the public key signed.</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}</li> </ol> </li> <li> <p>Response to Event Subscription must accomplish:</p> <ol> <li>201 Created</li> <li>The URI of the created resource shall be returned in the \"Location\" HTTP header, following this structure: *{apiRoot}/capif-events/{apiVersion}/{subscriberId}/subscriptions/{subscriptionId}</li> <li>Response Body must follow EventSubscription data structure.</li> </ol> </li> <li> <p>Event Subscriptions are stored in CAPIF Database</p> </li> <li>Remove Event Subscription with not valid subscriber:<ol> <li>404 Not Found</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 404</li> <li>detail with message \"Service API not existing\".</li> <li>cause with message \"Event API subscription id not found\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_invoker_management/","title":"Test Plan for CAPIF Api Invoker Management","text":"<p>At this documentation you will have all information and related files and examples of test plan for this API.</p>"},{"location":"testing/testplan/api_invoker_management/#test-case-1-onboard-netapp","title":"Test Case 1: Onboard NetApp","text":"<p>Test ID: capif_api_invoker_management-1</p> <p>Description:</p> <p>This test will try to register new NetApp at CAPIF Core.</p> <p>Pre-Conditions:</p> <ul> <li>NetApp was not registered previously</li> <li>NetApp was not onboarded previously</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Create public and private key at invoker</p> </li> <li> <p>Register of Invoker at CCF:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}:{CAPIF_HTTP_PORT}/register </li> <li>body invoker register body</li> </ul> </li> <li> <p>Obtain Access Token:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}/getauth</li> <li>Body invoker getauth body</li> </ul> </li> <li> <p>Onboard Invoker:</p> <ul> <li>Send POST to https://{CAPIF_HOSTNAME}/api-invoker-management/v1/onboardedInvokers</li> <li>Reference Request Body: invoker onboarding body</li> <li>\"onboardingInformation\"-&gt;\"apiInvokerPublicKey\": must contain public key generated by Invoker.</li> <li>Send at Authorization Header the Bearer access_token obtained previously (Authorization:Bearer ${access_token})</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Invoker at CCF</li> <li>Onboard Invoker at CCF</li> <li>Store signed Certificate</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Onboard request must accomplish:<ol> <li>201 Created</li> <li>Response Body must follow APIInvokerEnrolmentDetails data structure with:<ul> <li>apiInvokerId</li> <li>onboardingInformation-&gt;apiInvokerCertificate must contain the public key signed.</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}</li> </ol> </li> </ol>"},{"location":"testing/testplan/api_invoker_management/#test-case-2-onboard-netapp-already-onboarded","title":"Test Case 2: Onboard NetApp Already onboarded","text":"<p>Test ID: capif_api_invoker_management-2</p> <p>Description:</p> <p>This test will check second onboard of same NetApp is not allowed.</p> <p>Pre-Conditions:</p> <ul> <li>NetApp was registered previously</li> <li>NetApp was onboarded previously</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Invoker Onboarding</p> </li> <li> <p>Repeat Onboard Invoker:</p> <ul> <li>Send POST to https://{CAPIF_HOSTNAME}/api-invoker-management/v1/onboardedInvokers</li> <li>Reference Request Body: invoker onboarding body</li> <li>\"onboardingInformation\"-&gt;\"apiInvokerPublicKey\": must contain public key generated by Invoker.</li> <li>Send at Authorization Header the Bearer access_token obtained previously (Authorization:Bearer ${access_token})</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register NetApp at CCF</li> <li>Onboard NetApp at CCF</li> <li>Store signed Certificate at NetApp</li> <li>Onboard Again the NetApp at CCF</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Onboard request must accomplish:<ol> <li>201 Created</li> <li>Response Body must follow APIInvokerEnrolmentDetails data structure with:<ul> <li>apiInvokerId</li> <li>onboardingInformation-&gt;apiInvokerCertificate must contain the public key signed.</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}</li> </ol> </li> <li>Response to Second Onboard of NetApp must accomplish:<ol> <li>403 Forbidden</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 403</li> <li>title with message \"Forbidden\"</li> <li>detail with message \"Invoker Already registered\".</li> <li>cause with message \"Identical invoker public key\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_invoker_management/#test-case-3-update-onboarded-netapp","title":"Test Case 3: Update Onboarded NetApp","text":"<p>Test ID: capif_api_invoker_management-3</p> <p>Description:</p> <p>This test will try to update information of previous onboard NetApp at CAPIF Core.</p> <p>Pre-Conditions:</p> <ul> <li>NetApp was registered previously</li> <li>NetApp was onboarded previously with {onboardingId}</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Invoker Onboarding</p> </li> <li> <p>Update information of previously onboarded Invoker:</p> <ul> <li>Send PUT to https://{CAPIF_HOSTNAME}/api-invoker-management/v1/onboardedInvokers/{onboardingId}</li> <li>Reference Request Body is: [put invoker onboarding body]</li> <li>\"notificationDestination\": \"http://host.docker.internal:8086/netapp_new_callback\",</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Invoker at CCF</li> <li>Onboard Invoker at CCF</li> <li>Store signed Certificate</li> <li>Update Onboarding Information at CCF with a minor change on \"notificationDestination\"</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Onboard request must accomplish:<ol> <li>201 Created</li> <li>Response Body must follow APIInvokerEnrolmentDetails data structure with:<ul> <li>apiInvokerId</li> <li>onboardingInformation-&gt;apiInvokerCertificate must contain the public key signed.</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}</li> </ol> </li> <li>Response to Update Request (PUT) with minor change must contain:<ol> <li>200 OK response.</li> <li>notificationDestination on response must contain the new value</li> </ol> </li> </ol>"},{"location":"testing/testplan/api_invoker_management/#test-case-4-update-not-onboarded-netapp","title":"Test Case 4: Update Not Onboarded NetApp","text":"<p>Test ID: capif_api_invoker_management-4</p> <p>Description:</p> <p>This test will try to update information of not onboarded NetApp at CAPIF Core.</p> <p>Pre-Conditions:</p> <ul> <li>NetApp was registered previously</li> <li>NetApp was not onboarded previously</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Invoker Onboarding</p> </li> <li> <p>Update information of not onboarded Invoker:</p> <ul> <li>Send PUT to https://{CAPIF_HOSTNAME}/api-invoker-management/v1/onboardedInvokers/{INVOKER_NOT_REGISTERED}</li> <li>Reference Request Body is: [put invoker onboarding body]</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Invoker at CCF</li> <li>Onboard Invoker at CCF</li> <li>Update Onboarding Information at CCF of not onboarded</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Onboard request must accomplish:<ol> <li>201 Created</li> </ol> </li> <li>Response to Update Request (PUT) must contain:<ol> <li>404 Not Found</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Please provide an existing Netapp ID\".</li> <li>cause with message \"Not exist NetappID\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_invoker_management/#test-case-5-offboard-netapp","title":"Test Case 5: Offboard NetApp","text":"<p>Test ID: capif_api_invoker_management-5</p> <p>Description:</p> <p>This test case will check that a Registered NetApp can be deleted.</p> <p>Pre-Conditions:</p> <ul> <li>NetApp was registered previously</li> <li>NetApp was onboarded previously</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Invoker Onboarding</p> </li> <li> <p>Offboard:</p> <ul> <li>Send Delete to https://{CAPIF_HOSTNAME}/api-invoker-management/v1/onboardedInvokers/{onboardingId}</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Invoker at CCF</li> <li>Onboard Invoker at CCF</li> <li>Offboard Invoker at CCF</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Onboard request must accomplish:<ol> <li>201 Created</li> </ol> </li> <li>Response to Offboard Request (DELETE) must contain:<ol> <li>204 No Content</li> </ol> </li> </ol>"},{"location":"testing/testplan/api_invoker_management/#test-case-6-offboard-not-previsouly-onboarded-netapp","title":"Test Case 6: Offboard Not previsouly Onboarded NetApp","text":"<p>Test ID: capif_api_invoker_management-6</p> <p>Description:</p> <p>This test case will check that a Non-Registered NetApp cannot be deleted</p> <p>Pre-Conditions:</p> <ul> <li>NetApp was registered previously</li> <li>NetApp was not onboarded previously</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Invoker Onboarding</p> </li> <li> <p>Offboard:</p> <ul> <li>Send Delete to https://{CAPIF_HOSTNAME}/api-invoker-management/v1/onboardedInvokers/{INVOKER_NOT_REGISTERED}</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Invoker at CCF</li> <li>Offboard Invoker at CCF</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Offboard Request (DELETE) must contain:<ol> <li>404 Not Found</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Please provide an existing Netapp ID\".</li> <li>cause with message \"Not exist NetappID\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_invoker_management/#test-case-7-update-onboarded-netapp-certificate","title":"Test Case 7: Update Onboarded NetApp Certificate","text":"<p>Test ID: capif_api_invoker_management-7</p> <p>Description:</p> <p>This test will try to update public key and get a new signed certificate by CAPIF Core.</p> <p>Pre-Conditions:</p> <ul> <li>NetApp was registered previously</li> <li>NetApp was onboarded previously with {onboardingId} and {public_key_1}</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Invoker Onboarding with public_key_1.</p> </li> <li> <p>Create {public_key_2}</p> </li> <li> <p>Update information of previously onboarded Invoker:</p> <ul> <li>Send PUT to https://{CAPIF_HOSTNAME}/api-invoker-management/v1/onboardedInvokers/{onboardingId}</li> <li>Reference Request Body is: [put invoker onboarding body]</li> <li>[\"onboardingInformation\"][\"apiInvokerPublicKey\"]: {public_key_2},</li> <li>Store new certificate.</li> </ul> </li> <li> <p>Update information of previously onboarded Invoker Using new certificate:</p> <ul> <li>Send PUT to https://{CAPIF_HOSTNAME}/api-invoker-management/v1/onboardedInvokers/{onboardingId}</li> <li>Reference Request Body is: [put invoker onboarding body]</li> <li>\"notificationDestination\": \"http://host.docker.internal:8086/netapp_new_callback\",</li> <li>Use new invoker certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Invoker at CCF</li> <li>Onboard Invoker at CCF</li> <li>Store signed Certificate</li> <li>Update Onboarding Information at CCF with new public key</li> <li>Update Onboarding Information at CCF with minor change</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Onboard request must accomplish:<ol> <li>201 Created</li> <li>Response Body must follow APIInvokerEnrolmentDetails data structure with:<ul> <li>apiInvokerId</li> <li>onboardingInformation-&gt;apiInvokerCertificate must contain the public key signed.</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}</li> </ol> </li> <li>Response to Update Request (PUT) with new public key:<ol> <li>200 OK response.</li> <li>apiInvokerCertificate with new certificate on response -&gt; store to use.</li> </ol> </li> <li>Response to Update Request (PUT) with minor change must contain:<ol> <li>200 OK response.</li> <li>notificationDestination on response must contain the new value</li> </ol> </li> </ol>"},{"location":"testing/testplan/api_logging_service/","title":"Test Plan for CAPIF Api Logging Service","text":"<p>At this documentation you will have all information and related files and examples of test plan for this API.</p>"},{"location":"testing/testplan/api_logging_service/#test-case-1-creates-a-new-individual-capif-log-entry","title":"Test Case 1: Creates a new individual CAPIF Log Entry.","text":"<p>Test ID: capif_api_logging-1</p> <p>Description:</p> <p>This test case will check that a CAPIF AEF can create log entry to Logging Service</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF provider is pre-authorised (has valid aefId from CAPIF Authority)</li> <li>Service exist in CAPIF</li> <li>Invoker exist in CAPIF</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform provider onboarding and invoker onboarding</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body [service api description] with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Log Entry:</p> <ol> <li>Send POST to https://{CAPIF_HOSTNAME}/api-invocation-logs/v1/{aefId}/logs</li> <li>body log entry request body</li> <li>Use AEF Certificate</li> </ol> </li> </ol> <p>Execution Steps:   1. Register Provider and Invoker CCF   2. Publish Service   3. Create Log Entry</p> <p>Expected Result:</p> <ol> <li>Response to Logging Service must accomplish:<ol> <li>201 Created</li> <li>Response Body must follow InvocationLog data structure with:<ul> <li>aefId</li> <li>apiInvokerId</li> <li>logs</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/api-invocation-logs/v1/{aefId}/logs/{logId}</li> </ol> </li> </ol>"},{"location":"testing/testplan/api_logging_service/#test-case-2-creates-a-new-individual-capif-log-entry-with-invalid-aefid","title":"Test Case 2:  Creates a new individual CAPIF Log Entry with Invalid aefId","text":"<p>Test ID: capif_api_logging-2</p> <p>Description:</p> <p>This test case will check that a CAPIF subscriber (AEF) cannot create Log Entry without valid aefId</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF provider is not pre-authorised (has not valid aefId from CAPIF Authority)</li> <li>Service exist in CAPIF</li> <li>Invoker exist in CAPIF</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform provider onboarding and invoker onboarding</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body [service api description] with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Log Entry:</p> <ol> <li>Send POST to https://{CAPIF_HOSTNAME}/api-invocation-logs/v1/{not-valid-aefId}/logs</li> <li>body log entry request body</li> <li>Use AEF Certificate</li> </ol> </li> </ol> <p>Execution Steps:   1. Register Provider and Invoker CCF   2. Publish Service   3. Create Log Entry</p> <p>Expected Result:</p> <ol> <li>Response to Logging Service must accomplish:<ol> <li>404 Not Found</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Exposer not exist\".</li> <li>cause with message \"Exposer id not found\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_logging_service/#test-case-3-creates-a-new-individual-capif-log-entry-with-invalid-serviceapi","title":"Test Case 3:  Creates a new individual CAPIF Log Entry with Invalid serviceAPI","text":"<p>Test ID: capif_api_logging-3</p> <p>Description:</p> <p>This test case will check that a CAPIF subscriber (AEF) cannot create Log Entry without valid aefId</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF subscriber is pre-authorised (has valid aefId from CAPIF Authority)</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform provider onboarding and invoker onboarding</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body [service api description] with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Log Entry:</p> <ol> <li>Send POST to https://{CAPIF_HOSTNAME}/api-invocation-logs/v1/{aefId}/logs</li> <li>body [log entry request body with serviceAPI apiName apiId not valid]</li> <li>Use AEF Certificate</li> </ol> </li> </ol> <p>Execution Steps:   1. Register Provider and Invoker CCF   2. Publish Service   3. Create Log Entry</p> <p>Expected Result:</p> <ol> <li>Response to Logging Service must accomplish:<ol> <li>404 Not Found</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Invoker not exist\".</li> <li>cause with message \"Invoker id not found\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_logging_service/#test-case-4-creates-a-new-individual-capif-log-entry-with-invalid-apiinvokerid","title":"Test Case 4:  Creates a new individual CAPIF Log Entry with Invalid apiInvokerId","text":"<p>Test ID: capif_api_logging-4</p> <p>Description:</p> <p>This test case will check that a CAPIF subscriber (AEF) cannot create Log Entry without valid aefId</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF subscriber is pre-authorised (has valid aefId from CAPIF Authority)</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform provider onboarding and invoker onboarding</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body [service api description] with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Log Entry:</p> <ol> <li>Send POST to https://{CAPIF_HOSTNAME}/api-invocation-logs/v1/{aefId}/logs</li> <li>body [log entry request body with invokerId not valid]</li> <li>Use AEF Certificate</li> </ol> </li> </ol> <p>Execution Steps:   1. Register Provider and Invoker CCF   2. Publish Service   3. Create Log Entry</p> <p>Expected Result:</p> <ol> <li> <p>Response to Onboard request must accomplish:</p> <ol> <li>201 Created response.</li> <li>body returned must accomplish APIProviderEnrolmentDetails data structure.</li> <li>For each apiProvFuncs, we must check:<ol> <li>apiProvFuncId is set</li> <li>apiProvCert under regInfo is set properly</li> </ol> </li> <li>Location Header must contain the new resource URL {apiRoot}/api-provider-management/v1/registrations/{registrationId}</li> </ol> </li> <li> <p>Response to Logging Service must accomplish:</p> <ol> <li>404 Not Found</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Invoker not exist\".</li> <li>cause with message \"Invoker id not found\".</li> </ul> </li> </ol> </li> <li> <p>Log Entry are not stored in CAPIF Database</p> </li> </ol>"},{"location":"testing/testplan/api_logging_service/#test-case-5-creates-a-new-individual-capif-log-entry-with-invalid-aefid-in-body","title":"Test Case 5:  Creates a new individual CAPIF Log Entry with Invalid aefId in body","text":"<p>Test ID: capif_api_logging-5</p> <p>Description:</p> <p>This test case will check that a CAPIF subscriber (AEF) cannot create Log Entry without valid aefId in body</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF provider is pre-authorised (has valid apfId from CAPIF Authority)</li> <li>Service exist in CAPIF</li> <li>Invoker exist in CAPIF</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform provider onboarding and invoker onboarding</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body [service api description] with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Log Entry:</p> <ol> <li>Send POST to https://{CAPIF_HOSTNAME}/api-invocation-logs/v1/{aefId}/logs</li> <li>body [log entry request body with bad aefId] </li> <li>Use AEF Certificate</li> </ol> </li> </ol> <p>Execution Steps:   1. Register Provider and Invoker CCF   2. Publish Service   3. Create Log Entry</p> <p>Expected Result:</p> <ol> <li>Response to Logging Service must accomplish:<ol> <li>401 Unauthorized</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 401</li> <li>title with message \"Unauthorized\"</li> <li>detail with message \"AEF id not matching in request and body\".</li> <li>cause with message \"Not identical AEF id\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_provider_management/","title":"Test Plan for CAPIF Api Provider Management","text":"<p>At this documentation you will have all information and related files and examples of test plan for this API.</p>"},{"location":"testing/testplan/api_provider_management/#test-case-1-register-api-provider","title":"Test Case 1: Register Api Provider","text":"<p>Test ID: capif_api_provider_management-1</p> <p>Description:</p> <p>This test case will check that Api Provider can be registered con CCF</p> <p>Pre-Conditions:</p> <ul> <li>Provider is pre-authorised (has valid certificate from CAPIF Authority)</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Create public and private key at provider for provider itself and each function (apf, aef and amf)</p> </li> <li> <p>Register of Provider at CCF:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}:{CAPIF_HTTP_PORT}/register</li> <li>body provider register body</li> </ul> </li> <li> <p>Obtain Access Token:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}/getauth</li> <li>Body provider getauth body</li> </ul> </li> <li> <p>Register Provider:</p> <ul> <li>Send POST https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations</li> <li>body provider request body</li> <li>Authentication Bearer with access_token</li> <li>Store each cert in a file with according name.</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Create private and public key for provider and each function to register.</li> <li>Register Provider.</li> </ol> <p>Expected Result:</p> <ol> <li>Register Provider at Provider Management:<ol> <li>201 Created response.</li> <li>body returned must accomplish APIProviderEnrolmentDetails data structure.</li> <li>For each apiProvFuncs, we must check:<ol> <li>apiProvFuncId is set</li> <li>apiProvCert under regInfo is set properly</li> </ol> </li> <li>Location Header must contain the new resource URL {apiRoot}/api-provider-management/v1/registrations/{registrationId}</li> </ol> </li> </ol>"},{"location":"testing/testplan/api_provider_management/#test-case-2-register-api-provider-already-registered","title":"Test Case 2: Register Api Provider Already registered","text":"<p>Test ID: capif_api_provider_management-2</p> <p>Description:</p> <p>This test case will check that a Api Provider previously registered cannot be re-registered</p> <p>Pre-Conditions:</p> <ul> <li>Api Provider was registered previously and there is a {registerId} for his Api Provider in the DB</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Create public and private key at provider for provider itself and each function (apf, aef and amf)</p> </li> <li> <p>Register of Provider at CCF:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}:{CAPIF_HTTP_PORT}/register</li> <li>body provider register body</li> </ul> </li> <li> <p>Obtain Access Token:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}/getauth</li> <li>Body provider getauth body</li> </ul> </li> <li> <p>Register Provider:</p> <ul> <li>Send POST https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations</li> <li>body provider request body</li> <li>Authentication Bearer with access_token</li> <li>Store each cert in a file with according name.</li> </ul> </li> <li> <p>Re-Register Provider:</p> <ul> <li>Same regSec than Previous registration</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Create private and public key for provider and each function to register.</li> <li>Register Provider.</li> <li>Re-Register Provider.</li> </ol> <p>Expected Result:</p> <ol> <li>Re-Register Provider:<ol> <li>403 Forbidden response.</li> <li>body returned must accomplish ProblemDetails data structure, with:<ul> <li>status 403</li> <li>title with message \"Forbidden\"</li> <li>detail with message \"Provider already registered\".</li> <li>cause with message \"Identical provider reg sec\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_provider_management/#test-case-3-update-registered-api-provider","title":"Test Case 3: Update Registered Api Provider","text":"<p>Test ID: capif_api_provider_management-3</p> <p>Description:</p> <p>This test case will check that a Registered Api Provider can be updated</p> <p>Pre-Conditions:</p> <ul> <li>Api Provider was registered previously and there is a {registerId} for his Api Provider in the DB</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Create public and private key at provider for provider itself and each function (apf, aef and amf)</p> </li> <li> <p>Register of Provider at CCF:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}:{CAPIF_HTTP_PORT}/register</li> <li>body provider register body</li> </ul> </li> <li> <p>Obtain Access Token:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}/getauth</li> <li>Body provider getauth body</li> </ul> </li> <li> <p>Register Provider:</p> <ul> <li>Send POST https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations</li> <li>body provider request body</li> <li>Authentication Bearer with access_token</li> <li>Get Resource URL from Location</li> </ul> </li> <li> <p>Update Provider:</p> <ul> <li>Send PUT to Resource URL returned at registration https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations/{registrationId}</li> <li>body provider request body with apiProvDomInfo set to ROBOT_TESTING_MOD</li> <li>Use AMF Certificate.</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Create private and public key for provider and each function to register.</li> <li>Register Provider</li> <li>Update Provider</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Register Provider:</p> <ol> <li>201 Created response.</li> <li>body returned must accomplish APIProviderEnrolmentDetails data structure.</li> <li>Location Header must contain the new resource URL {apiRoot}/api-provider-management/v1/registrations/{registrationId}</li> </ol> </li> <li> <p>Update Provider:</p> <ol> <li>200 OK response.</li> <li>body returned must accomplish APIProviderEnrolmentDetails data structure, with:<ul> <li>apiProvDomInfo set to ROBOT_TESTING_MOD</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_provider_management/#test-case-4-update-not-registered-api-provider","title":"Test Case 4: Update Not Registered Api Provider","text":"<p>Test ID: capif_api_provider_management-4</p> <p>Description:</p> <p>This test case will check that a Non-Registered Api Provider cannot be updated</p> <p>Pre-Conditions:</p> <ul> <li>Api Provider was not registered previously</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Create public and private key at provider for provider itself and each function (apf, aef and amf)</p> </li> <li> <p>Register of Provider at CCF:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}:{CAPIF_HTTP_PORT}/register</li> <li>body provider register body</li> </ul> </li> <li> <p>Obtain Access Token:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}/getauth</li> <li>Body provider getauth body</li> </ul> </li> <li> <p>Register Provider:</p> <ul> <li>Send POST https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations</li> <li>body provider request body</li> <li>Authentication Bearer with access_token</li> <li>Store each cert in a file with according name.</li> </ul> </li> <li> <p>Update Not Registered Provider:</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations/{API_PROVIDER_NOT_REGISTERED}</li> <li>body provider request body</li> <li>Use AMF Certificate.</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF</li> <li>Update Not Registered Provider</li> </ol> <p>Expected Result:</p> <ol> <li>Update Not Registered Provider:<ol> <li>404 Not Found response.</li> <li>body returned must accomplish ProblemDetails data structure, with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Not Exist Provider Enrolment Details\".</li> <li>cause with message \"Not found registrations to send this api provider details\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_provider_management/#test-case-5-partially-update-registered-api-provider","title":"Test Case 5: Partially Update Registered Api Provider","text":"<p>Test ID: capif_api_provider_management-5</p> <p>Description:</p> <p>This test case will check that a Registered Api Provider can be partially updated</p> <p>Pre-Conditions:</p> <ul> <li>Api Provider was registered previously and there is a {registerId} for his Api Provider in the DB</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Create public and private key at provider for provider itself and each function (apf, aef and amf)</p> </li> <li> <p>Register of Provider at CCF:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}:{CAPIF_HTTP_PORT}/register</li> <li>body provider register body</li> </ul> </li> <li> <p>Obtain Access Token:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}/getauth</li> <li>Body provider getauth body</li> </ul> </li> <li> <p>Register Provider:</p> <ul> <li>Send POST https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations</li> <li>body provider request body</li> <li>Authentication Bearer with access_token</li> <li>Store each cert in a file with according name.</li> </ul> </li> <li> <p>Partial update provider:</p> <ul> <li>Send PATCH https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations/{registrationId}</li> <li>body provider request patch body</li> <li>Use AMF Certificate.</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF</li> <li>Register Provider</li> <li>Partial update provider</li> </ol> <p>Expected Result:</p> <ol> <li>Partial update provider at Provider Management:<ol> <li>200 OK response.</li> <li>body returned must accomplish APIProviderEnrolmentDetails data structure, with:<ul> <li>apiProvDomInfo with \"ROBOT_TESTING_MOD\"</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_provider_management/#test-case-6-partially-update-not-registered-api-provider","title":"Test Case 6: Partially Update Not Registered Api Provider","text":"<p>Test ID: capif_api_provider_management-6</p> <p>Description:</p> <p>This test case will check that a Non-Registered Api Provider cannot be partially updated  </p> <p>Pre-Conditions:</p> <ul> <li>Api Provider was not registered previously</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Create public and private key at provider for provider itself and each function (apf, aef and amf)</p> </li> <li> <p>Register of Provider at CCF:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}:{CAPIF_HTTP_PORT}/register</li> <li>body provider register body</li> </ul> </li> <li> <p>Obtain Access Token:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}/getauth</li> <li>Body provider getauth body</li> </ul> </li> <li> <p>Register Provider:</p> <ul> <li>Send POST https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations</li> <li>body provider request body</li> <li>Authentication Bearer with access_token</li> <li>Store each cert in a file with according name.</li> </ul> </li> <li> <p>Partial update Provider:</p> <ul> <li>Send PATCH https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations/{API_API_PROVIDER_NOT_REGISTERED}</li> <li>body provider request patch body</li> <li>Use AMF Certificate.</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF</li> <li>Register Provider</li> <li>Partial update provider</li> </ol> <p>Expected Result:</p> <ol> <li>Partial update provider:<ol> <li>404 Not Found response.</li> <li>body returned must accomplish ProblemDetails data structure, with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Not Exist Provider Enrolment Details\".</li> <li>cause with message \"Not found registrations to send this api provider details\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_provider_management/#test-case-7-delete-registered-api-provider","title":"Test Case 7: Delete Registered Api Provider","text":"<p>Test ID: capif_api_provider_management-7</p> <p>Description:</p> <p>This test case will check that a Registered Api Provider can be deleted</p> <p>Pre-Conditions:</p> <ul> <li>Api Provider was registered previously</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Create public and private key at provider for provider itself and each function (apf, aef and amf)</p> </li> <li> <p>Register of Provider at CCF:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}:{CAPIF_HTTP_PORT}/register</li> <li>body provider register body</li> </ul> </li> <li> <p>Obtain Access Token:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}/getauth</li> <li>Body provider getauth body</li> </ul> </li> <li> <p>Register Provider:</p> <ul> <li>Send POST https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations</li> <li>body provider request body</li> <li>Authentication Bearer with access_token</li> <li>Store each cert in a file with according name.</li> </ul> </li> <li> <p>Delete registered provider:</p> <ul> <li>Send DELETE https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations/{registrationId}</li> <li>Use AMF Certificate.</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF</li> <li>Register Provider</li> <li>Delete Provider</li> </ol> <p>Expected Result:</p> <ol> <li>Delete Provider:<ol> <li>204 No Content response.</li> </ol> </li> </ol>"},{"location":"testing/testplan/api_provider_management/#test-case-8-delete-not-registered-api-provider","title":"Test Case 8: Delete Not Registered Api Provider","text":"<p>Test ID: capif_api_provider_management-8</p> <p>Description:</p> <p>This test case will check that a Non-Registered Api Provider cannot be deleted</p> <p>Pre-Conditions:</p> <ul> <li>Api Provider was not registered previously</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Create public and private key at provider for provider itself and each function (apf, aef and amf)</p> </li> <li> <p>Register of Provider at CCF:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}:{CAPIF_HTTP_PORT}/register</li> <li>body provider register body</li> </ul> </li> <li> <p>Obtain Access Token:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}/getauth</li> <li>Body provider getauth body</li> </ul> </li> <li> <p>Register Provider:</p> <ul> <li>Send POST https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations</li> <li>body provider request body</li> <li>Authentication Bearer with access_token</li> <li>Store each cert in a file with according name.</li> </ul> </li> <li> <p>Delete registered provider at Provider Management:</p> <ul> <li>Send DELETE https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations/{API_PROVIDER_NOT_REGISTERED}</li> <li>Use AMF Certificate.</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF</li> <li>Delete Provider</li> </ol> <p>Expected Result:</p> <ol> <li>Delete Provider:<ol> <li>404 Not Found response.</li> <li>body returned must accomplish ProblemDetails data structure, with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Not Exist Provider Enrolment Details\".</li> <li>cause with message \"Not found registrations to send this api provider details\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_publish_service/","title":"Test Plan for CAPIF Api Publish Service","text":"<p>At this documentation you will have all information and related files and examples of test plan for this API.</p>"},{"location":"testing/testplan/api_publish_service/#test-case-1-publish-api-by-authorised-api-publisher","title":"Test Case 1: Publish API by Authorised API Publisher","text":"<p>Test ID: capif_api_publish_service-1</p> <p>Description:</p> <p>This test case will check that an API Publisher can Publish an API</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF subscriber is pre-authorised (has valid apfId from CAPIF Authority)</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> </li> <li> <p>Send Post to ccf_publish_url: https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</p> </li> <li>body service api description with apiName service_1</li> <li>Use APF Certificate</li> </ol> <p>Execution Steps:</p> <ol> <li> <p>Register Provider at CCF and store certificates.</p> </li> <li> <p>Publish Service API</p> </li> <li> <p>Retrieve {apiId} from body and Location header with new resource created from response</p> </li> </ol> <p>Expected Result:</p> <ol> <li> <p>Response to Publish request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow ServiceAPIDescription data structure with:<ul> <li>apiId</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId}</li> </ol> </li> <li> <p>Published Service API is stored in CAPIF Database</p> </li> </ol>"},{"location":"testing/testplan/api_publish_service/#test-case-2-publish-api-by-non-authorised-api-publisher","title":"Test Case 2: Publish API by NON Authorised API Publisher","text":"<p>Test ID: capif_api_publish_service-2</p> <p>Description:</p> <p>This test case will check that an API Publisher cannot Publish an API withot valid apfId </p> <p>Pre-Conditions:</p> <ul> <li>CAPIF subscriber is NOT pre-authorised (has invalid apfId from CAPIF Authority)</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API with invalid APF ID at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{APF_ID_NOT_VALID}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF and store certificates.</li> <li>Publish Service API with invalid APF ID</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Response to Publish request must accomplish:</p> <ol> <li>401 Unauthorized</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 401</li> <li>title with message \"Unauthorized\"</li> <li>detail with message \"Publisher not existing\".</li> <li>cause with message \"Publisher id not found\".</li> </ul> </li> </ol> </li> <li> <p>Service API is NOT stored in CAPIF Database</p> </li> </ol>"},{"location":"testing/testplan/api_publish_service/#test-case-3-retrieve-all-apis-published-by-authorised-apfid","title":"Test Case 3: Retrieve all APIs Published by Authorised apfId","text":"<p>Test ID: capif_api_publish_service-3</p> <p>Description:</p> <p>This test case will check that an API Publisher can Retrieve all API published</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF subscriber is pre-authorised (has valid apfId from CAPIF Authority)</li> <li>At least 2 service APIs are published.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Get apiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Publish Other Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_2</li> <li>Get apiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Retrieve all published APIs:</p> <ul> <li>Send Get to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>Use APF Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF and store certificates.</li> <li>Publish Service API service_1</li> <li>Retrieve {apiId1} from body and Location header with new resource created from response</li> <li>Publish Service API service_2</li> <li>Retrieve {apiId2} from body and Location header with new resource created from response</li> <li>Retrieve All published APIs and check if both are present.</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Response to service 1 Publish request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow ServiceAPIDescription data structure with:<ul> <li>apiId</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId1}</li> </ol> </li> <li> <p>Response to service 2 Publish request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow ServiceAPIDescription data structure with:<ul> <li>apiId</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId2}</li> </ol> </li> <li> <p>Published Service APIs are stored in CAPIF Database</p> </li> <li> <p>Response to Retrieve all published APIs:</p> <ol> <li>200 OK</li> <li>Response body must return an array of ServiceAPIDescription data.</li> <li>Array must contain all previously published APIs.</li> </ol> </li> </ol>"},{"location":"testing/testplan/api_publish_service/#test-case-4-retrieve-all-apis-published-by-non-authorised-apfid","title":"Test Case 4: Retrieve all APIs Published by NON Authorised apfId","text":"<p>Test ID: capif_api_publish_service-4</p> <p>Description:</p> <p>This test case will check that an API Publisher cannot Retrieve API published when apfId is not authorised </p> <p>Pre-Conditions:</p> <ul> <li>CAPIF subscriber is NOT pre-authorised (has invalid apfId from CAPIF Authority)</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Retrieve all published APIs:</p> <ul> <li>Send Get to https://{CAPIF_HOSTNAME}/published-apis/v1/{APF_ID_NOT_VALID}/service-apis</li> <li>Use APF Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF and store certificates.</li> <li>Retrieve All published APIs</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Response to Publish request must accomplish:</p> <ol> <li>401 Non Authorized</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 401</li> <li>title with message \"Unauthorized\"</li> <li>detail with message \"Provider not existing\".</li> <li>cause with message \"Provider id not found\".</li> </ul> </li> </ol> </li> <li> <p>Service API is NOT stored in CAPIF Database</p> </li> </ol>"},{"location":"testing/testplan/api_publish_service/#test-case-5-retrieve-single-apis-published-by-authorised-apfid","title":"Test Case 5: Retrieve single APIs Published by Authorised apfId","text":"<p>Test ID: capif_api_publish_service-5</p> <p>Description:</p> <p>This test case will check that an API Publisher can Retrieve API published one by one</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF subscriber is pre-authorised (has valid apfId from CAPIF Authority)</li> <li>At least 2 service APIs are published.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Get apiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Publish Other Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_2</li> <li>Get apiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Retrieve service_1 published APIs detail:</p> <ul> <li>Send Get to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis/{apiId1}</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Retrieve service_2 published APIs detail:</p> <ul> <li>Send Get to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis/{apiId2}</li> <li>Use APF Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF and store certificates.</li> <li>Publish Service API service_1.</li> <li>Retrieve {apiId1} from body and Location header with new resource created from response.</li> <li>Publish Service API service_2.</li> <li>Retrieve {apiId2} from body and Location header with new resource created from response.</li> <li>Retrieve service_1 API Detail.</li> <li>Retrieve service_2 API Detail.</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Response to service 1 Publish request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow ServiceAPIDescription data structure with:<ul> <li>apiId</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId1}</li> </ol> </li> <li> <p>Response to service 2 Publish request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow ServiceAPIDescription data structure with:<ul> <li>apiId</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId2}</li> </ol> </li> <li> <p>Published Service APIs are stored in CAPIF Database</p> </li> <li> <p>Response to Retrieve service_1 published API using apiId1:</p> <ol> <li>200 OK</li> <li>Response body must return a ServiceAPIDescription data.</li> <li>Array must contain same information than service_1 published registration response.</li> </ol> </li> <li> <p>Response to Retrieve service_2 published API using apiId2:</p> <ol> <li>200 OK</li> <li>Response body must return a ServiceAPIDescription data.</li> <li>Array must contain same information than service_2 published registration response.</li> </ol> </li> </ol>"},{"location":"testing/testplan/api_publish_service/#test-case-6-retrieve-single-apis-non-published-by-authorised-apfid","title":"Test Case 6: Retrieve single APIs non Published by Authorised apfId","text":"<p>Test ID: capif_api_publish_service-6</p> <p>Description:</p> <p>This test case will check that an API Publisher try to get detail of not published api.</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF subscriber is pre-authorised (has valid apfId from CAPIF Authority)</li> <li>No published api</li> </ul> <p>Information of Test:</p> <ol> <li>Perform Provider Registration</li> <li>Retrieve not published APIs detail:<ul> <li>Send Get to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis/{SERVICE_API_ID_NOT_VALID}</li> <li>Use APF Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF and store certificates.</li> <li>Retrieve not published API Detail.</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Retrieve for NOT published API must accomplish:<ol> <li>404 Not Found</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Service API not found\".</li> <li>cause with message \"No Service with specific credentials exists\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_publish_service/#test-case-7-retrieve-single-apis-published-by-non-authorised-apfid","title":"Test Case 7: Retrieve single APIs Published by NON Authorised apfId","text":"<p>Test ID: capif_api_publish_service-7</p> <p>Description:</p> <p>This test case will check that an API Publisher cannot Retrieve detailed API published when apfId is not authorised </p> <p>Pre-Conditions:</p> <ul> <li>CAPIF subscriber is NOT pre-authorised (has invalid apfId from CAPIF Authority)</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Get apiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Retrieve detailed published APIs:</p> <ul> <li>Send Get to https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis/${apiId}</li> <li>Use Invoker certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF and store certificates.</li> <li>Publish Service API at CCF</li> <li>Retrieve {apiId} from body and Location header with new resource created from response.</li> <li>Register and onboard Invoker at CCF</li> <li>Store signed Invoker Certificate</li> <li>Retrieve detailed published API acting as Invoker</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Response to Retrieve Detailed published API acting as Invoker must accomplish:</p> <ol> <li>401 Unauthorized</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 401</li> <li>title with message \"Unauthorized\"</li> <li>detail with message \"User not authorized\".</li> <li>cause with message \"Certificate not authorized\".</li> </ul> </li> </ol> </li> <li> <p>Service API is NOT stored in CAPIF Database</p> </li> </ol>"},{"location":"testing/testplan/api_publish_service/#test-case-8-update-api-published-by-authorised-apfid-with-valid-serviceapiid","title":"Test Case 8: Update API Published by Authorised apfId with valid serviceApiId","text":"<p>Test ID: capif_api_publish_service-8</p> <p>Description:</p> <p>This test case will check that an API Publisher can Update published API with a valid serviceApiId </p> <p>Pre-Conditions:</p> <ul> <li>CAPIF subscriber is pre-authorised (has valid apfId from CAPIF Authority)</li> <li>A service APIs is published.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Get apiId</li> <li>get resource url from location Header.</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Update published API at CCF:</p> <ul> <li>Send PUT to resource URL https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis/{serivceApiId}</li> <li>body service api description with overrided apiName to service_1_modified</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Retrieve detail of service API:</p> <ul> <li>Send Get to resource URL https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis/{serivceApiId}</li> <li>check apiName is service_1_modified</li> <li>Use APF Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF and store certificates.</li> <li>Publish Service API</li> <li>Retrieve {apiId} from body and Location header with new resource url created from response</li> <li>Update published Service API.</li> <li>Retrieve detail of Service API</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Response to Publish request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow ServiceAPIDescription data structure with:<ul> <li>apiId</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId}</li> </ol> </li> <li> <p>Response to Update Published Service API:</p> <ol> <li>200 OK</li> <li>Response Body must follow ServiceAPIDescription data structure with:<ul> <li>apiName service_1_modified</li> </ul> </li> </ol> </li> <li> <p>Response to Retrieve detail of Service API:</p> <ol> <li>200 OK</li> <li>Response Body must follow ServiceAPIDescription data structure with:<ul> <li>apiName service_1_modified.</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_publish_service/#test-case-9-update-apis-published-by-authorised-apfid-with-invalid-serviceapiid","title":"Test Case 9: Update APIs Published by Authorised apfId with invalid serviceApiId","text":"<p>Test ID: capif_api_publish_service-9</p> <p>Description:</p> <p>This test case will check that an API Publisher cannot Update published API with a invalid serviceApiId</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF subscriber is pre-authorised (has valid apfId from CAPIF Authority)</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Get apiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Update published API at CCF:</p> <ul> <li>Send PUT to resource URL https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis/{SERVICE_API_ID_NOT_VALID}</li> <li>body service api description with overrided apiName to service_1_modified</li> <li>Use APF Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF and store certificates.</li> <li>Update published Service API.</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Response to Publish request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow ServiceAPIDescription data structure with:<ul> <li>apiId</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId}</li> </ol> </li> <li> <p>Response to Update Published Service API:</p> <ol> <li>404 Not Found</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Service API not found\".</li> <li>cause with message \"Service API id not found\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_publish_service/#test-case-10-update-apis-published-by-non-authorised-apfid","title":"Test Case 10: Update APIs Published by NON Authorised apfId","text":"<p>Test ID: capif_api_publish_service-10</p> <p>Description:</p> <p>This test case will check that an API Publisher cannot Update API published when apfId is not authorised</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF subscriber is NOT pre-authorised (has invalid apfId from CAPIF Authority)</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Get apiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Update published API at CCF:</p> <ul> <li>Send PUT to resource URL https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis/{serviceApiId}</li> <li>body service api description with overrided apiName to service_1_modified</li> <li>Use invoker certificate</li> </ul> </li> <li> <p>Retrieve detail of service API:</p> <ul> <li>Send Get to resource URL https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis/{serivceApiId}</li> <li>check apiName is service_1</li> <li>Use APF Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF and store certificates.</li> <li>Publish Service API at CCF</li> <li>Retrieve {apiId} from body and Location header with new resource created from response.</li> <li>Register and onboard Invoker at CCF</li> <li>Store signed Invoker Certificate</li> <li>Update published API at CCF as Invoker</li> <li>Retrieve detail of Service API as publisher</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Response to Update published API acting as Invoker must accomplish:</p> <ol> <li>401 Unauthorized</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 401</li> <li>title with message \"Unauthorized\"</li> <li>detail with message \"User not authorized\".</li> <li>cause with message \"Certificate not authorized\".</li> </ul> </li> </ol> </li> <li> <p>Response to Retrieve Detail of Service API:</p> <ol> <li>200 OK</li> <li>Response Body must follow ServiceAPIDescription data structure with:<ul> <li>apiName service_1.</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_publish_service/#test-case-11-delete-api-published-by-authorised-apfid-with-valid-serviceapiid","title":"Test Case 11: Delete API Published by Authorised apfId with valid serviceApiId","text":"<p>Test ID: capif_api_publish_service-11</p> <p>Description:</p> <p>This test case will check that an API Publisher can Delete published API with a valid serviceApiId</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF subscriber is pre-authorised (has valid apfId from CAPIF Authority).</li> <li>A service APIs is published.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Get apiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Remove published Service API at CCF:</p> <ul> <li>Send DELETE to resource URL https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis/{serviceApiId}</li> <li>Use APF Certificate</li> </ul> </li> <li>Retrieve detail of service API:<ul> <li>Send Get to resource URL https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis/{serivceApiId}</li> <li>Use APF Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF and store certificates.</li> <li>Publish Service API</li> <li>Retrieve {apiId} from body and Location header with new resource created from response</li> <li>Remove published API at CCF</li> <li>Try to retreive deleted service API from CCF</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Response to Publish request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow ServiceAPIDescription data structure with:<ul> <li>apiId</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/published-apis/v1/{apfId}/service-apis/{serviceApiId}</li> </ol> </li> <li> <p>Published Service API is stored in CAPIF Database</p> </li> <li> <p>Response to Remove published Service API at CCF:</p> <ol> <li>204 No Content</li> </ol> </li> <li> <p>Response to Retrieve for DELETED published API must accomplish:</p> <ol> <li>404 Not Found</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Service API not found\".</li> <li>cause with message \"No Service with specific credentials exists\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_publish_service/#test-case-12-delete-apis-published-by-authorised-apfid-with-invalid-serviceapiid","title":"Test Case 12: Delete APIs Published by Authorised apfId with invalid serviceApiId","text":"<p>Test ID: capif_api_publish_service-12</p> <p>Description:</p> <p>This test case will check that an API Publisher cannot Delete with invalid serviceApiId</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF subscriber is pre-authorised (has valid apfId from CAPIF Authority).</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Remove published Service API at CCF with invalid serviceId:</p> <ul> <li>Send DELETE to resource URL https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis/{SERVICE_API_ID_NOT_VALID}</li> <li>Use APF Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF and store certificates.</li> <li>Remove published API at CCF with invalid serviceId</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Remove published Service API at CCF:<ol> <li>404 Not Found</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Service API not found\".</li> <li>cause with message \"Service API id not found\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_publish_service/#test-case-13-delete-apis-published-by-non-authorised-apfid","title":"Test Case 13: Delete APIs Published by NON Authorised apfId","text":"<p>Test ID: capif_api_publish_service-12</p> <p>Description:</p> <p>This test case will check that an API Publisher cannot Delete API published when apfId is not authorised</p> <p>Pre-Conditions:</p> <ul> <li>CAPIF subscriber is pre-authorised (has valid apfId from CAPIF Authority).</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body service api description with apiName service_1</li> <li>Get apiId</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Remove published Service API at CCF with invalid serviceId as Invoker:</p> <ul> <li>Send DELETE to resource URL https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis/{SERVICE_API_ID_NOT_VALID}</li> <li>Use invoker certificate.</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF and store certificates.</li> <li>Register Invoker and onboard Invoker at CCF</li> <li>Remove published API at CCF with invalid serviceId as Invoker</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Remove published Service API at CCF:<ol> <li>401 Unauthorized</li> <li>Error Response Body must accomplish with ProblemDetails data structure with:<ul> <li>status 401</li> <li>title with message \"Unauthorized\"</li> <li>detail with message \"User not authorized\".</li> <li>cause with message \"Certificate not authorized\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/","title":"Test Plan for CAPIF Api Security Service","text":"<p>At this documentation you will have all information and related files and examples of test plan for this API.</p>"},{"location":"testing/testplan/api_security_service/#test-case-1-create-a-security-context-for-an-api-invoker","title":"Test Case 1: Create a security context for an API invoker","text":"<p>Test ID: capif_security_api-1</p> <p>Description:</p> <p>This test case will check that an API Invoker can create a Security context</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised (has valid apiInvokerID from CAPIF Authority)</li> </ul> <p>Information of Test:</p> <ol> <li>Perform Invoker Onboarding</li> <li>Create Security Context for this Invoker<ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Use Invoker Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Invoker at CCF</li> <li>Store signed Certificate</li> <li>Create Security Context</li> </ol> <p>Expected Result:</p> <ol> <li>Create security context:<ol> <li>201 Created response.</li> <li>body returned must accomplish ServiceSecurity data structure.</li> <li>Location Header must contain the new resource URL {apiRoot}/capif-security/v1/trustedInvokers/{apiInvokerId}</li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-2-create-a-security-context-for-an-api-invoker-with-provider-role","title":"Test Case 2: Create a security context for an API invoker with Provider role","text":"<p>Test ID:: capif_security_api-2</p> <p>Description:</p> <p>This test case will check that an Provider cannot create a Security context with valid apiInvokerId.</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised (has valid apiInvokerID), but user that create Security Context with Provider role</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Create Security Context for this Invoker but using Provider certificate.</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Using AEF certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Invoker at CCF</li> <li>Register Provider at CCF</li> <li>Create Security Context using Provider certificate</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Create security context using Provider certificate:</p> <ol> <li>401 Unauthorized response.</li> <li>body returned must accomplish ProblemDetails data structure, with:<ul> <li>status 401</li> <li>title with message \"Unauthorized\"</li> <li>detail with message \"Role not authorized for this API route\".</li> <li>cause with message \"User role must be invoker\".</li> </ul> </li> </ol> </li> <li> <p>No context stored at DB</p> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-3-create-a-security-context-for-an-api-invoker-with-provider-entity-role-and-invalid-apiinvokerid","title":"Test Case 3: Create a security context for an API invoker with Provider entity role and invalid apiInvokerId","text":"<p>Test ID:: capif_security_api-3</p> <p>Description:</p> <p>This test case will check that an Provider cannot create a Security context with invalid apiInvokerID.</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised (has valid apiInvokerID), but user that create Security Context with Provider role</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Create Security Context for this not valid apiInvokerId and using Provider certificate.</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{API_INVOKER_NOT_VALID}</li> <li>body service security body</li> <li>Using AEF certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF</li> <li>Create Security Context using Provider certificate</li> </ol> <p>Expected Result:</p> <ol> <li>Create security context using Provider certificate:<ol> <li>401 Unauthorized response.</li> <li>body returned must accomplish ProblemDetails data structure, with:<ul> <li>status 401</li> <li>title with message \"Unauthorized\"</li> <li>detail with message \"Role not authorized for this API route\".</li> <li>cause with message \"User role must be invoker\".</li> </ul> </li> </ol> </li> <li>No context stored at DB</li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-4-create-a-security-context-for-an-api-invoker-with-invoker-entity-role-and-invalid-apiinvokerid","title":"Test Case 4: Create a security context for an API invoker with Invoker entity role and invalid apiInvokerId","text":"<p>Test ID:: capif_security_api-4</p> <p>Description:</p> <p>This test case will check that an Invoker cannot create a Security context with valid apiInvokerId.</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised (has valid apiInvokerID), but user that create Security Context with invalid apiInvokerId</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Invoker Onboarding</p> </li> <li> <p>Create Security Context for this Invoker:</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{API_INVOKER_NOT_VALID}</li> <li>body service security body</li> <li>Use Invoker Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Invoker at CCF</li> <li>Create Security Context using Provider certificate</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Create security context using Provider certificate:</p> <ol> <li>404 Not Found response.</li> <li>body returned must accomplish ProblemDetails data structure, with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Invoker not found\".</li> <li>cause with message \"API Invoker not exists or invalid ID\".</li> </ul> </li> </ol> </li> <li> <p>No context stored at DB</p> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-5-retrieve-the-security-context-of-an-api-invoker","title":"Test Case 5: Retrieve the Security Context of an API Invoker","text":"<p>Test ID:: capif_security_api-5</p> <p>Description:</p> <p>This test case will check that an provider can retrieve the Security context of an API Invoker</p> <p>Pre-Conditions:</p> <ul> <li>Provider is pre-authorised (has valid apfId from CAPIF Authority) and API Invoker has created a valid Security Context</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Create Security Context for this Invoker.</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Using Invoker certificate</li> </ul> </li> <li> <p>Retrieve Security Context of Invoker by Provider:</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>Using AEF Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Invoker at CCF</li> <li>Register Provider at CCF</li> <li>Create Security Context using Provider certificate</li> <li>Retrieve Security Context by Provider</li> </ol> <p>Expected Result:</p> <ol> <li>Retrieve security context:<ol> <li>200 OK response.</li> <li>body returned must accomplish ServiceSecurity data structure.</li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-6-retrieve-the-security-context-of-an-api-invoker-with-invalid-apiinvokerid","title":"Test Case 6: Retrieve the Security Context of an API Invoker with invalid apiInvokerID","text":"<p>Test ID:: capif_security_api-6</p> <p>Description:</p> <p>This test case will check that an provider can retrieve the Security context of an API Invoker</p> <p>Pre-Conditions:</p> <ul> <li>Provider is pre-authorised (has valid apfId from CAPIF Authority) and API Invoker has created a valid Security Context</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Retrieve Security Context of invalid Invoker by Provider:</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/trustedInvokers/{API_INVOKER_NOT_VALID}</li> <li>Using AEF Certificate.</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF</li> <li>Create Security Context using Provider certificate</li> <li>Retrieve Security Context by Provider of invalid invoker</li> </ol> <p>Expected Result:</p> <ol> <li>Retrieve security context:<ol> <li>404 Not Found response.</li> <li>body returned must accomplish ProblemDetails data structure, with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Invoker not found\".</li> <li>cause with message \"API Invoker not exists or invalid ID\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-7-retrieve-the-security-context-of-an-api-invoker-with-invalid-apfid","title":"Test Case 7: Retrieve the Security Context of an API Invoker with invalid apfId","text":"<p>Test ID:: capif_security_api-7</p> <p>Description:</p> <p>This test case will check that an Provider cannot retrieve the Security context of an API Invoker without valid apfId</p> <p>Pre-Conditions:</p> <ul> <li>API Exposure Function is not pre-authorised (has invalid apfId)</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Create Security Context for this Invoker</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Using Invoker Certificate</li> </ul> </li> <li> <p>Retrieve Security Context as Invoker role:</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>Using Invoker Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Invoker at CCF</li> <li>Store signed Certificate</li> <li>Create Security Context</li> <li>Retrieve Security Context as Provider.</li> </ol> <p>Expected Result:</p> <ol> <li>Create security context:<ol> <li>401 Unauthorized response.</li> <li>body returned must accomplish ProblemDetails data structure, with:<ul> <li>status 401</li> <li>title with message \"Unauthorized\"</li> <li>detail with message \"Role not authorized for this API route\".</li> <li>cause with message \"User role must be aef\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-8-delete-the-security-context-of-an-api-invoker","title":"Test Case 8: Delete the Security Context of an API Invoker","text":"<p>Test ID:: capif_security_api-8</p> <p>Description:</p> <p>This test case will check that an Provider can delete a Security context</p> <p>Pre-Conditions:</p> <ul> <li>Provider is pre-authorised (has valid apfId from CAPIF Authority) and API Invoker has created a valid Security Context</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Create Security Context for this Invoker but using Provider certificate.</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Using AEF certificate</li> </ul> </li> <li> <p>Delete Security Context of Invoker by Provider:</p> <ul> <li>Send DELETE https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>Use AEF certificate</li> </ul> </li> <li> <p>Retrieve Security Context of Invoker by Provider:</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>Using AEF Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Invoker at CCF</li> <li>Register Provider at CCF</li> <li>Create Security Context using Provider certificate</li> <li>Delete Security Context by Provider</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Delete security context:</p> <ol> <li>204 No Content response.</li> </ol> </li> <li> <p>Retrieve security context:</p> <ol> <li>404 Not Found response.</li> <li>body returned must accomplish ProblemDetails data structure, with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Security context not found\".</li> <li>cause with message \"API Invoker not exists or invalid ID\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-9-delete-the-security-context-of-an-api-invoker-with-invoker-entity-role","title":"Test Case 9: Delete the Security Context of an API Invoker with Invoker entity role","text":"<p>Test ID:: capif_security_api-9</p> <p>Description:</p> <p>This test case will check that an Invoker cannot delete a Security context</p> <p>Pre-Conditions:</p> <ul> <li>Provider is pre-authorised (has valid apfId from CAPIF Authority) and API Invoker has created a valid Security Context</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Create Security Context for this Invoker:</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Using Invoker certificate</li> </ul> </li> <li> <p>Delete Security Context of Invoker:</p> <ul> <li>Send DELETE https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>Use Invoker certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF</li> <li>Create Security Context using Provider certificate</li> <li>Delete Security Context by Invoker</li> </ol> <p>Expected Result:</p> <ol> <li>Delete security context:<ol> <li>401 Unauthorized response.</li> <li>body returned must accomplish ProblemDetails data structure, with:<ul> <li>status 401</li> <li>title with message \"Unauthorized\"</li> <li>detail with message \"Role not authorized for this API route\".</li> <li>cause with message \"User role must be aef\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-10-delete-the-security-context-of-an-api-invoker-with-invoker-entity-role-and-invalid-apiinvokerid","title":"Test Case 10: Delete the Security Context of an API Invoker with Invoker entity role and invalid apiInvokerID","text":"<p>Test ID:: capif_security_api-10</p> <p>Description:</p> <p>This test case will check that an Invoker cannot delete a Security context with invalid </p> <p>Pre-Conditions:</p> <ul> <li>Invoker is pre-authorised.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Invoker Onboarding</p> </li> <li> <p>Delete Security Context of Invoker:</p> <ul> <li>Send DELETE https://{CAPIF_HOSTNAME}/trustedInvokers/{API_INVOKER_NOT_VALID}</li> <li>Use Invoker certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF</li> <li>Delete Security Context by invoker</li> </ol> <p>Expected Result:</p> <ol> <li>Delete security context:<ol> <li>401 Unauthorized response.</li> <li>body returned must accomplish ProblemDetails data structure, with:<ul> <li>status 401</li> <li>title with message \"Unauthorized\"</li> <li>detail with message \"Role not authorized for this API route\".</li> <li>cause with message \"User role must be aef\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-11-delete-the-security-context-of-an-api-invoker-with-invalid-apiinvokerid","title":"Test Case 11: Delete the Security Context of an API Invoker with invalid apiInvokerID","text":"<p>Test ID:: capif_security_api-11</p> <p>Description:</p> <p>This test case will check that an Provider cannot delete a Security context of invalid apiInvokerId</p> <p>Pre-Conditions:</p> <ul> <li>Provider is pre-authorised (has valid apfId from CAPIF Authority).</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Delete Security Context of Invoker by Provider:</p> <ul> <li>Send DELETE https://{CAPIF_HOSTNAME}/trustedInvokers/{API_INVOKER_NOT_VALID}</li> <li>Use AEF certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF</li> <li>Delete Security Context by provider</li> </ol> <p>Expected Result:</p> <ol> <li>Retrieve security context:<ol> <li>404 Not Found response.</li> <li>body returned must accomplish ProblemDetails data structure, with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Invoker not found\".</li> <li>cause with message \"API Invoker not exists or invalid ID\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-12-update-the-security-context-of-an-api-invoker","title":"Test Case 12: Update the Security Context of an API Invoker","text":"<p>Test ID:: capif_security_api-12</p> <p>Description:</p> <p>This test case will check that an API Invoker can update a Security context</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised (has valid apiInvokerID from CAPIF Authority) and Provider is also authorized</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Create Security Context for this Invoker:</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Using Invoker Certificate.</li> </ul> </li> <li> <p>Update Security Context of Invoker:</p> <ul> <li>Send POST https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}/update</li> <li>body service security body but with notification destination modified to http://robot.testing2</li> <li>Using Invoker Certificate.</li> </ul> </li> <li> <p>Retrieve Security Context of Invoker by Provider:</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>Using AEF Certificate.</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Invoker at CCF</li> <li>Register Provider at CCF</li> <li>Create Security Context By Invoker</li> <li>Update Security Context By Invoker</li> <li>Retrieve Security Context By Provider</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Update security context:</p> <ol> <li>200 OK response.</li> <li>body returned must accomplish ServiceSecurity data structure.</li> </ol> </li> <li> <p>Retrieve security context:</p> <ol> <li>200 OK response.</li> <li>body returned must accomplish ServiceSecurity data structure.<ol> <li>Check is this returned object match with modified one.</li> </ol> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-13-update-the-security-context-of-an-api-invoker-with-provider-entity-role","title":"Test Case 13: Update the Security Context of an API Invoker with Provider entity role","text":"<p>Test ID:: capif_security_api-13</p> <p>Description:</p> <p>This test case will check that an Provider cannot update a Security context</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised (has valid apiInvokerID from CAPIF Authority) and Provider is also authorized.</li> <li>Invoker has created the Security Context previously.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Create Security Context for this Invoker:</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Using Invoker Certificate.</li> </ul> </li> <li> <p>Update Security Context of Invoker by Provider:</p> <ul> <li>Send POST https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}/update</li> <li>body service security body but with notification destination modified to http://robot.testing2</li> <li>Using AEF Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Invoker at CCF</li> <li>Register Provider at CCF</li> <li>Create Security Context</li> <li>Update Security Context as Provider</li> </ol> <p>Expected Result:</p> <ol> <li>Update security context:<ol> <li>401 Unauthorized response.</li> <li>body returned must accomplish ProblemDetails data structure, with:<ul> <li>status 401</li> <li>title with message \"Unauthorized\"</li> <li>detail with message \"Role not authorized for this API route\".</li> <li>cause with message \"User role must be invoker\". </li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-14-update-the-security-context-of-an-api-invoker-with-aef-entity-role-and-invalid-apiinvokerid","title":"Test Case 14: Update the Security Context of an API Invoker with AEF entity role and invalid apiInvokerId","text":"<p>Test ID:: capif_security_api-14</p> <p>Description:</p> <p>This test case will check that an Provider cannot update a Security context of invalid apiInvokerId</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised (has valid apiInvokerID from CAPIF Authority) and Provider is also authorized.</li> <li>Invoker has created the Security Context previously.</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration</p> </li> <li> <p>Update Security Context of Invoker by Provider:</p> <ul> <li>Send POST https://{CAPIF_HOSTNAME}/trustedInvokers/{API_INVOKER_NOT_VALID}/update</li> <li>body service security body</li> <li>Using AEF Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF</li> <li>Update Security Context as Provider</li> </ol> <p>Expected Result:</p> <ol> <li>Update security context:<ol> <li>401 Unauthorized response.</li> <li>body returned must accomplish ProblemDetails data structure, with:<ul> <li>status 401</li> <li>title with message \"Unauthorized\"</li> <li>detail with message \"Role not authorized for this API route\".</li> <li>cause with message \"User role must be invoker\". </li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-15-update-the-security-context-of-an-api-invoker-with-invalid-apiinvokerid","title":"Test Case 15: Update the Security Context of an API Invoker with invalid apiInvokerID","text":"<p>Test ID:: capif_security_api-15</p> <p>Description:</p> <p>This test case will check that an API Invoker cannot update a Security context not valid apiInvokerId</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised (has valid apiInvokerID from CAPIF Authority)</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Update Security Context of Invoker:</p> <ul> <li>Send POST https://{CAPIF_HOSTNAME}/trustedInvokers/{API_INVOKER_NOT_VALID}/update</li> <li>body service security body</li> <li>Using Invoker Certificate.</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Invoker at CCF</li> <li>Update Security Context</li> </ol> <p>Expected Result:</p> <ol> <li>Retrieve security context:<ol> <li>404 Not Found response.</li> <li>body returned must accomplish ProblemDetails data structure, with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Invoker not found\".</li> <li>cause with message \"API Invoker not exists or invalid ID\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-16-revoke-the-authorization-of-the-api-invoker-for-apis","title":"Test Case 16: Revoke the authorization of the API invoker for APIs.","text":"<p>Test ID:: capif_security_api-16</p> <p>Description:</p> <p>This test case will check that a Provider can revoke the authorization for APIs</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised (has valid apiInvokerID from CAPIF Authority) and Provider is also authorized</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Create Security Context By Invoker:</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Using Invoker Certificate</li> </ul> </li> <li> <p>Revoke Authorization by Provider:</p> <ul> <li>Send POST https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}/delete</li> <li>body security notification body</li> <li>Using AEF Certificate.</li> </ul> </li> <li> <p>Retrieve Security Context by Provider:</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>Using AEF Certificate.</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Invoker at CCF</li> <li>Register Provider at CCF</li> <li>Create Security Context by Invoker</li> <li>Revoke Security Context by Provider</li> <li>Retrieve Security Context by Provider</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Revoke Authorization:</p> <ol> <li>204 No Content response.</li> </ol> </li> <li> <p>Retrieve security context:</p> <ol> <li>404 Not Found response.</li> <li>body returned must accomplish ProblemDetails data structure, with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Security context not found\".</li> <li>cause with message \"API Invoker has no security context\".</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-17-revoke-the-authorization-of-the-api-invoker-for-apis-without-valid-apfid","title":"Test Case 17: Revoke the authorization of the API invoker for APIs without valid apfID.","text":"<p>Test ID:: capif_security_api-17</p> <p>Description:</p> <p>This test case will check that an Invoker can't revoke the authorization for APIs</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised (has valid apiInvokerID from CAPIF Authority) and Provider is also authorized</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Create Security Context for this Invoker:</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Using Invoker Certificate.</li> </ul> </li> <li> <p>Revoke Authorization by invoker:</p> <ul> <li>Send POST https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}/delete</li> <li>body security notification body</li> <li>Using Invoker Certificate</li> </ul> </li> <li> <p>Retrieve Security Context of Invoker by Provider:</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>Using Provider Certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Invoker at CCF</li> <li>Register Provider at CCF</li> <li>Create Security Context</li> <li>Revoke Security Context by invoker</li> <li>Retrieve Security Context</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Revoke Security Context by invoker:</p> <ol> <li>401 Unauthorized response.</li> <li>body returned must accomplish ProblemDetails data structure, with:<ul> <li>status 401</li> <li>title with message \"Unauthorized\"</li> <li>detail with message \"Role not authorized for this API route\".</li> <li>cause with message \"User role must be provider\". </li> </ul> </li> </ol> </li> <li> <p>Retrieve security context:</p> <ol> <li>200 OK response.</li> <li>body returned must accomplish ServiceSecurity data structure.<ol> <li>Check is this returned object match with created one.</li> </ol> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-18-revoke-the-authorization-of-the-api-invoker-for-apis-with-invalid-apiinvokerid","title":"Test Case 18: Revoke the authorization of the API invoker for APIs with invalid apiInvokerId.","text":"<p>Test ID:: capif_security_api-18</p> <p>Description:</p> <p>This test case will check that an API Exposure Function cannot revoke the authorization for APIs for invalid apiInvokerId</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised (has valid apiInvokerID from CAPIF Authority) and Provider is also authorized</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Create Security Context for this Invoker:</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Using Invoker Certificate.</li> </ul> </li> <li> <p>Revoke Authorization by Provider:</p> <ul> <li>Send POST https://{CAPIF_HOSTNAME}/trustedInvokers/{API_INVOKER_NOT_VALID}/delete</li> <li>body security notification body</li> <li>Using AEF Certificate.</li> </ul> </li> <li> <p>Retrieve Security Context of Invoker by Provider:</p> <ul> <li>Send GET https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}?authenticationInfo=true&amp;authorizationInfo=true</li> <li>This request will ask with parameter to retrieve authenticationInfo and authorizationInfo</li> <li>Using AEF Certificate.</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register and onboard Invoker at CCF</li> <li>Register Provider at CCF</li> <li>Create Security Context</li> <li>Revoke Security Context by Provider</li> <li>Retrieve Security Context</li> </ol> <p>Expected Result:</p> <ol> <li> <p>Revoke Security Context by invoker:</p> <ol> <li>404 Not Found response.</li> <li>body returned must accomplish ProblemDetails data structure, with:<ul> <li>status 404</li> <li>title with message \"Not Found\"</li> <li>detail with message \"Invoker not found\".</li> <li>cause with message \"API Invoker not exists or invalid ID\".</li> </ul> </li> </ol> </li> <li> <p>Retrieve security context:</p> <ol> <li>200 OK response.</li> <li>body returned must accomplish ServiceSecurity data structure.<ol> <li>Check is this return one object that match with created one.</li> </ol> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-19-retrieve-access-token","title":"Test Case 19: Retrieve access token","text":"<p>Test ID:: capif_security_api-19</p> <p>Description:</p> <p>This test case will check that an API Invoker can retrieve a security access token OAuth 2.0.</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised (has valid apiInvokerId)</li> <li>Service API of Provider is published</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body [service api description] with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Request Discover Published APIs not filtered:</p> <ul> <li>Send GET to ccf_discover_url https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}</li> <li>Param api-invoker-id is mandatory</li> <li>Using invoker certificate</li> </ul> </li> <li> <p>Create Security Context for this Invoker</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Using Invoker Certificate.</li> <li>Create Security Information Body with one securityInfo for each aef present at each serviceAPIDescription present at Discover.</li> </ul> </li> <li> <p>Request Access Token by invoker:</p> <ul> <li>Sent POST https://{CAPIF_HOSTNAME}/securities/{securityId}/token:</li> <li>body access token req body and example example</li> <li>securityId is apiInvokerId.</li> <li>grant_type=client_credentials.</li> <li>Create Scope properly for request: 3gpp#{aef_id}:{api_name}</li> <li>Using Invoker Certificate.</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF, store certificates and Publish Service API service_1 at CCF</li> <li>Register and onboard Invoker at CCF</li> <li>Discover Service APIs by Invoker.</li> <li>Create Security Context According to Service APIs discovered.</li> <li>Request Access Token</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Request of Access Token:<ol> <li>200 OK</li> <li>body must follow AccessTokenRsp with:<ol> <li>access_token present</li> <li>token_type=Bearer</li> </ol> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-20-retrieve-access-token-by-provider","title":"Test Case 20: Retrieve access token by Provider","text":"<p>Test ID:: capif_security_api-20</p> <p>Description:</p> <p>This test case will check that an API Exposure Function cannot revoke the authorization for APIs for invalid apiInvokerId</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised (has valid apiInvokerID from CAPIF Authority) and Provider is also authorized</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body [service api description] with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Request Discover Published APIs not filtered:</p> <ul> <li>Send GET to ccf_discover_url https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}</li> <li>Param api-invoker-id is mandatory</li> <li>Using invoker certificate</li> </ul> </li> <li> <p>Create Security Context for this Invoker</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Using Invoker Certificate.</li> <li>Create Security Information Body with one securityInfo for each aef present at each serviceAPIDescription present at Discover.</li> </ul> </li> <li> <p>Request Access Token by provider:</p> <ul> <li>Sent POST https://{CAPIF_HOSTNAME}/securities/{securityId}/token:</li> <li>body access token req body</li> <li>securityId is apiInvokerId</li> <li>grant_type=client_credentials</li> <li>Using AEF certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF, store certificates and Publish Service API service_1 at CCF</li> <li>Register and onboard Invoker at CCF</li> <li>Discover Service APIs by Invoker.</li> <li>Create Security Context According to Service APIs discovered.</li> <li>Request Access Token by Provider</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Request of Access Token:<ol> <li>401 Unauthorized response.</li> <li>body returned must accomplish AccessTokenErr data structure, with:<ul> <li>error unauthorized_client</li> <li>error_description=Role not authorized for this API route</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-21-retrieve-access-token-by-provider-with-invalid-apiinvokerid","title":"Test Case 21: Retrieve access token by Provider with invalid apiInvokerId","text":"<p>Test ID:: capif_security_api-21</p> <p>Description:</p> <p>This test case will check that an API Exposure Function cannot retrieve a security access token without valid apiInvokerId</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised and Provider is also authorized</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body [service api description] with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Request Discover Published APIs not filtered:</p> <ul> <li>Send GET to ccf_discover_url https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}</li> <li>Param api-invoker-id is mandatory</li> <li>Using invoker certificate</li> </ul> </li> <li> <p>Create Security Context for this Invoker</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Using Invoker Certificate.</li> <li>Create Security Information Body with one securityInfo for each aef present at each serviceAPIDescription present at Discover.</li> </ul> </li> <li> <p>Request Access Token by provider:</p> <ul> <li>Sent POST https://{CAPIF_HOSTNAME}/securities/{API_INVOKER_NOT_VALID}/token.</li> <li>body access token req body</li> <li>securityId is apiInvokerId</li> <li>grant_type=client_credentials</li> <li>Using AEF certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF, store certificates and Publish Service API service_1 at CCF</li> <li>Register and onboard Invoker at CCF</li> <li>Discover Service APIs by Invoker.</li> <li>Create Security Context According to Service APIs discovered.</li> <li>Request Access Token by Provider</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Request of Access Token:<ol> <li>401 Unauthorized response.</li> <li>body returned must accomplish AccessTokenErr data structure, with:<ul> <li>error unauthorized_client</li> <li>error_description=Role not authorized for this API route</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-22-retrieve-access-token-with-invalid-apiinvokerid","title":"Test Case 22: Retrieve access token with invalid apiInvokerId","text":"<p>Test ID:: capif_security_api-22</p> <p>Description:</p> <p>This test case will check that an API Invoker can't retrieve a security access token without valid apiInvokerId</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised (has valid apiInvokerId)</li> </ul> <p>Information of Test:</p> <ol> <li>Perform Provider Registration and Invoker Onboarding</li> <li>Publish Service API at CCF:<ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body [service api description] with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li>Request Discover Published APIs not filtered:<ul> <li>Send GET to ccf_discover_url https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}</li> <li>Param api-invoker-id is mandatory</li> <li>Using invoker certificate</li> </ul> </li> <li>Create Security Context for this Invoker<ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Using Invoker Certificate.</li> <li>Create Security Information Body with one securityInfo for each aef present at each serviceAPIDescription present at Discover.</li> </ul> </li> <li>Request Access Token by invoker:<ul> <li>Sent POST https://{CAPIF_HOSTNAME}/securities/{API_INVOKER_NOT_VALID}/token.</li> <li>body access token req body</li> <li>securityId is apiInvokerId</li> <li>grant_type=client_credentials</li> <li>Using Invoker certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF, store certificates and Publish Service API service_1 at CCF</li> <li>Register and onboard Invoker at CCF</li> <li>Discover Service APIs by Invoker.</li> <li>Create Security Context According to Service APIs discovered.</li> <li>Request Access Token by Invoker</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Request of Access Token:<ol> <li>404 Not Found response.</li> <li>body returned must accomplish ProblemDetails29571 data structure, with:<ul> <li>status 404</li> <li>title Not Found</li> <li>detail Security context not found</li> <li>cause API Invoker has no security context</li> </ul> </li> </ol> </li> </ol> <p>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</p>"},{"location":"testing/testplan/api_security_service/#test-case-23-retrieve-access-token-with-invalid-client_id","title":"Test Case 23: Retrieve access token with invalid client_id","text":"<p>Test ID:: capif_security_api-23</p> <p>Description:</p> <p>This test case will check that an API Exposure Function cannot retrieve a security access token without valid client_id at body</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised and Provider is also authorized</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body [service api description] with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Request Discover Published APIs not filtered:</p> <ul> <li>Send GET to ccf_discover_url https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}</li> <li>Param api-invoker-id is mandatory</li> <li>Using invoker certificate</li> </ul> </li> <li> <p>Create Security Context for this Invoker</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Using Invoker Certificate.</li> <li>Create Security Information Body with one securityInfo for each aef present at each serviceAPIDescription present at Discover.</li> </ul> </li> <li> <p>Request Access Token by invoker:</p> <ul> <li>Sent POST https://{CAPIF_HOSTNAME}/securities/{securityId}/token.</li> <li>body access token req body</li> <li>securityId is apiInvokerId</li> <li>grant_type=client_credentials</li> <li>client_id is not-valid </li> <li>Using Invoker certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF, store certificates and Publish Service API service_1 at CCF</li> <li>Register and onboard Invoker at CCF</li> <li>Discover Service APIs by Invoker.</li> <li>Create Security Context According to Service APIs discovered.</li> <li>Request Access Token by Invoker</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Request of Access Token:<ol> <li>400 Bad Request response.</li> <li>body returned must accomplish AccessTokenErr data structure, with:<ul> <li>error invalid_client</li> <li>error_description=Client Id not found</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-24-retrieve-access-token-with-unsupported-grant_type","title":"Test Case 24: Retrieve access token with unsupported grant_type","text":"<p>Test ID:: capif_security_api-24</p> <p>Description:</p> <p>This test case will check that an API Exposure Function cannot retrieve a security access token with unsupported grant_type</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised and Provider is also authorized</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body [service api description] with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Request Discover Published APIs not filtered:</p> <ul> <li>Send GET to ccf_discover_url https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}</li> <li>Param api-invoker-id is mandatory</li> <li>Using invoker certificate</li> </ul> </li> <li> <p>Create Security Context for this Invoker</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Using Invoker Certificate.</li> <li>Create Security Information Body with one securityInfo for each aef present at each serviceAPIDescription present at Discover.</li> </ul> </li> <li> <p>Request Access Token by invoker:</p> <ul> <li>Sent POST https://{CAPIF_HOSTNAME}/securities/{securityId}/token.</li> <li>body access token req body</li> <li>securityId is apiInvokerId</li> <li>grant_type=not_valid</li> <li>Using Invoker certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF, store certificates and Publish Service API service_1 at CCF</li> <li>Register and onboard Invoker at CCF</li> <li>Discover Service APIs by Invoker.</li> <li>Create Security Context According to Service APIs discovered.</li> <li>Request Access Token by Invoker</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Request of Access Token:<ol> <li>400 Bad Request response.</li> <li>body returned must accomplish AccessTokenErr data structure, with:<ul> <li>error unsupported_grant_type</li> <li>error_description=Invalid value for <code>grant_type</code> \\(${grant_type}\\), must be one of \\['client_credentials'\\] - 'grant_type'</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-25-retrieve-access-token-with-invalid-scope","title":"Test Case 25: Retrieve access token with invalid scope","text":"<p>Test ID:: capif_security_api-25</p> <p>Description:</p> <p>This test case will check that an API Exposure Function cannot retrieve a security access token with complete invalid scope</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised and Provider is also authorized</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body [service api description] with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Request Discover Published APIs not filtered:</p> <ul> <li>Send GET to ccf_discover_url https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}</li> <li>Param api-invoker-id is mandatory</li> <li>Using invoker certificate</li> </ul> </li> <li> <p>Create Security Context for this Invoker</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Using Invoker Certificate.</li> <li>Create Security Information Body with one securityInfo for each aef present at each serviceAPIDescription present at Discover.</li> </ul> </li> <li> <p>Request Access Token by invoker:</p> <ul> <li>Sent POST https://{CAPIF_HOSTNAME}/securities/{securityId}/token.</li> <li>body access token req body</li> <li>securityId is apiInvokerId</li> <li>grant_type=client_credentials</li> <li>scope=not-valid-scope</li> <li>Using Invoker certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF, store certificates and Publish Service API service_1 at CCF</li> <li>Register and onboard Invoker at CCF</li> <li>Discover Service APIs by Invoker.</li> <li>Create Security Context According to Service APIs discovered.</li> <li>Request Access Token by Invoker</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Request of Access Token:<ol> <li>400 Bad Request response.</li> <li>body returned must accomplish AccessTokenErr data structure, with:<ul> <li>error invalid_scope</li> <li>error_description=The first characters must be '3gpp'</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-26-retrieve-access-token-with-invalid-aefid-at-scope","title":"Test Case 26: Retrieve access token with invalid aefid at scope","text":"<p>Test ID:: capif_security_api-26</p> <p>Description:</p> <p>This test case will check that an API Exposure Function cannot retrieve a security access token with invalid aefId at scope</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised and Provider is also authorized</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body [service api description] with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Request Discover Published APIs not filtered:</p> <ul> <li>Send GET to ccf_discover_url https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}</li> <li>Param api-invoker-id is mandatory</li> <li>Using invoker certificate</li> </ul> </li> <li> <p>Create Security Context for this Invoker</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Using Invoker Certificate.</li> <li>Create Security Information Body with one securityInfo for each aef present at each serviceAPIDescription present at Discover.</li> </ul> </li> <li> <p>Request Access Token by invoker:</p> <ul> <li>Sent POST https://{CAPIF_HOSTNAME}/securities/{securityId}/token.</li> <li>body access token req body</li> <li>securityId is apiInvokerId</li> <li>grant_type=client_credentials</li> <li>scope=3gpp#1234:service_1</li> <li>Using Invoker certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF, store certificates and Publish Service API service_1 at CCF</li> <li>Register and onboard Invoker at CCF</li> <li>Discover Service APIs by Invoker.</li> <li>Create Security Context According to Service APIs discovered.</li> <li>Request Access Token by Invoker</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Request of Access Token:<ol> <li>400 Bad Request response.</li> <li>body returned must accomplish AccessTokenErr data structure, with:<ul> <li>error invalid_scope</li> <li>error_description=One of aef_id not belongs of your security context</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/api_security_service/#test-case-27-retrieve-access-token-with-invalid-apiname-at-scope","title":"Test Case 27: Retrieve access token with invalid apiName at scope","text":"<p>Test ID:: capif_security_api-27</p> <p>Description:</p> <p>This test case will check that an API Exposure Function cannot retrieve a security access token with invalid apiName at scope</p> <p>Pre-Conditions:</p> <ul> <li>API Invoker is pre-authorised and Provider is also authorized</li> </ul> <p>Information of Test:</p> <ol> <li> <p>Perform Provider Registration and Invoker Onboarding</p> </li> <li> <p>Publish Service API at CCF:</p> <ul> <li>Send Post to ccf_publish_url https://{CAPIF_HOSTNAME}/published-apis/v1/{apfId}/service-apis</li> <li>body [service api description] with apiName service_1</li> <li>Use APF Certificate</li> </ul> </li> <li> <p>Request Discover Published APIs not filtered:</p> <ul> <li>Send GET to ccf_discover_url https://{CAPIF_HOSTNAME}/service-apis/v1/allServiceAPIs?api-invoker-id={apiInvokerId}</li> <li>Param api-invoker-id is mandatory</li> <li>Using invoker certificate</li> </ul> </li> <li> <p>Create Security Context for this Invoker</p> <ul> <li>Send PUT https://{CAPIF_HOSTNAME}/trustedInvokers/{apiInvokerId}</li> <li>body service security body</li> <li>Using Invoker Certificate.</li> <li>Create Security Information Body with one securityInfo for each aef present at each serviceAPIDescription present at Discover.</li> </ul> </li> <li> <p>Request Access Token by invoker:</p> <ul> <li>Sent POST https://{CAPIF_HOSTNAME}/securities/{securityId}/token.</li> <li>body access token req body</li> <li>securityId is apiInvokerId</li> <li>grant_type=client_credentials</li> <li>scope=3gpp#{aef_id}:not-valid</li> <li>Using Invoker certificate</li> </ul> </li> </ol> <p>Execution Steps:</p> <ol> <li>Register Provider at CCF, store certificates and Publish Service API service_1 at CCF</li> <li>Register and onboard Invoker at CCF</li> <li>Discover Service APIs by Invoker.</li> <li>Create Security Context According to Service APIs discovered.</li> <li>Request Access Token by Invoker</li> </ol> <p>Expected Result:</p> <ol> <li>Response to Request of Access Token:<ol> <li>400 Bad Request response.</li> <li>body returned must accomplish AccessTokenErr data structure, with:<ul> <li>error invalid_scope</li> <li>error_description=One of the api names does not exist or is not associated with the aef id provided</li> </ul> </li> </ol> </li> </ol>"},{"location":"testing/testplan/common_operations/","title":"Common Operations","text":""},{"location":"testing/testplan/common_operations/#register-an-invoker","title":"Register an Invoker","text":""},{"location":"testing/testplan/common_operations/#steps-to-perform-operation","title":"Steps to perform operation","text":"<ol> <li>Create public and private key at invoker</li> <li> <p>Register of Invoker at CCF:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}:{CAPIF_HTTP_PORT}/register</li> <li>Body invoker register body</li> </ul> </li> <li> <p>Obtain Access Token:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}/getauth</li> <li>Body invoker getauth body</li> </ul> </li> <li> <p>Onboard Invoker:             * Send POST to https://{CAPIF_HOSTNAME}/api-invoker-management/v1/onboardedInvokers          * Reference Request Body: invoker onboarding body          * \"onboardingInformation\"-&gt;\"apiInvokerPublicKey\": must contain public key generated by Invoker.          * Send at Authorization Header the Bearer access_token obtained previously (Authorization:Bearer ${access_token})</p> </li> </ol>"},{"location":"testing/testplan/common_operations/#checks-to-ensure-onboarding","title":"Checks to ensure onboarding","text":"<ol> <li> <p>Response to Register:</p> <ol> <li>201 Created</li> </ol> </li> <li> <p>Response to Get Auth:</p> <ol> <li>200 OK</li> <li>access_token returned.</li> </ol> </li> <li> <p>Response to Onboard request must accomplish:</p> <ol> <li>201 Created</li> <li>Response Body must follow APIInvokerEnrolmentDetails data structure with:<ul> <li>apiInvokerId</li> <li>onboardingInformation-&gt;apiInvokerCertificate must contain the public key signed.</li> </ul> </li> <li>Response Header Location must be received with URI to new resource created, following this structure: {apiRoot}/api-invoker-management/{apiVersion}/onboardedInvokers/{onboardingId}</li> </ol> </li> </ol>"},{"location":"testing/testplan/common_operations/#register-a-provider","title":"Register a Provider","text":""},{"location":"testing/testplan/common_operations/#steps-to-perform-operation_1","title":"Steps to Perform operation","text":"<ol> <li>Create public and private key at provider for provider itself and each function (apf, aef and amf)</li> <li> <p>Register of Provider at CCF:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}:{CAPIF_HTTP_PORT}/register</li> <li>body provider register body</li> </ul> </li> <li> <p>Obtain Access Token:</p> <ul> <li>Send POST to http://{CAPIF_HOSTNAME}/getauth</li> <li>Body provider getauth body</li> </ul> </li> <li> <p>Register Provider:</p> <ul> <li>Send POST https://{CAPIF_HOSTNAME}/api-provider-management/v1/registrations</li> <li>body provider request body</li> <li>Send at Authorization Header the Bearer access_token obtained previously (Authorization:Bearer ${access_token})</li> <li>Store each cert in a file with according name.</li> </ul> </li> </ol>"},{"location":"testing/testplan/common_operations/#checks-to-ensure-provider-registration","title":"Checks to ensure provider registration","text":"<ol> <li> <p>Response to Register:</p> <ol> <li>201 Created</li> </ol> </li> <li> <p>Response to Get Auth:</p> <ol> <li>200 OK</li> <li>access_token returned.</li> </ol> </li> <li> <p>Register Provider at Provider Management:</p> <ol> <li>201 Created response.</li> <li>body returned must accomplish APIProviderEnrolmentDetails data structure.</li> <li>For each apiProvFuncs, we must check:<ol> <li>apiProvFuncId is set</li> <li>apiProvCert under regInfo is set properly</li> </ol> </li> <li>Location Header must contain the new resource URL {apiRoot}/api-provider-management/v1/registrations/{registrationId}</li> </ol> </li> </ol>"}]}
\ No newline at end of file
diff --git a/public/0.0/sitemap.xml b/public/0.0/sitemap.xml
index 8e878274..0080ab06 100644
--- a/public/0.0/sitemap.xml
+++ b/public/0.0/sitemap.xml
@@ -2,87 +2,87 @@
 <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
     <url>
          <loc>https://ocf.etsi.org/0.0/</loc>
-         <lastmod>2024-03-25</lastmod>
+         <lastmod>2024-03-26</lastmod>
          <changefreq>daily</changefreq>
     </url>
     <url>
          <loc>https://ocf.etsi.org/0.0/FAQ/</loc>
-         <lastmod>2024-03-25</lastmod>
+         <lastmod>2024-03-26</lastmod>
          <changefreq>daily</changefreq>
     </url>
     <url>
          <loc>https://ocf.etsi.org/0.0/gettingstarted/howtorun/</loc>
-         <lastmod>2024-03-25</lastmod>
+         <lastmod>2024-03-26</lastmod>
          <changefreq>daily</changefreq>
     </url>
     <url>
          <loc>https://ocf.etsi.org/0.0/gettingstarted/repository/</loc>
-         <lastmod>2024-03-25</lastmod>
+         <lastmod>2024-03-26</lastmod>
          <changefreq>daily</changefreq>
     </url>
     <url>
          <loc>https://ocf.etsi.org/0.0/testing/postman/</loc>
-         <lastmod>2024-03-25</lastmod>
+         <lastmod>2024-03-26</lastmod>
          <changefreq>daily</changefreq>
     </url>
     <url>
          <loc>https://ocf.etsi.org/0.0/testing/robotframework/</loc>
-         <lastmod>2024-03-25</lastmod>
+         <lastmod>2024-03-26</lastmod>
          <changefreq>daily</changefreq>
     </url>
     <url>
          <loc>https://ocf.etsi.org/0.0/testing/testplan/</loc>
-         <lastmod>2024-03-25</lastmod>
+         <lastmod>2024-03-26</lastmod>
          <changefreq>daily</changefreq>
     </url>
     <url>
          <loc>https://ocf.etsi.org/0.0/testing/testplan/api_access_control_policy/</loc>
-         <lastmod>2024-03-25</lastmod>
+         <lastmod>2024-03-26</lastmod>
          <changefreq>daily</changefreq>
     </url>
     <url>
          <loc>https://ocf.etsi.org/0.0/testing/testplan/api_auditing_service/</loc>
-         <lastmod>2024-03-25</lastmod>
+         <lastmod>2024-03-26</lastmod>
          <changefreq>daily</changefreq>
     </url>
     <url>
          <loc>https://ocf.etsi.org/0.0/testing/testplan/api_discover_service/</loc>
-         <lastmod>2024-03-25</lastmod>
+         <lastmod>2024-03-26</lastmod>
          <changefreq>daily</changefreq>
     </url>
     <url>
          <loc>https://ocf.etsi.org/0.0/testing/testplan/api_events_service/</loc>
-         <lastmod>2024-03-25</lastmod>
+         <lastmod>2024-03-26</lastmod>
          <changefreq>daily</changefreq>
     </url>
     <url>
          <loc>https://ocf.etsi.org/0.0/testing/testplan/api_invoker_management/</loc>
-         <lastmod>2024-03-25</lastmod>
+         <lastmod>2024-03-26</lastmod>
          <changefreq>daily</changefreq>
     </url>
     <url>
          <loc>https://ocf.etsi.org/0.0/testing/testplan/api_logging_service/</loc>
-         <lastmod>2024-03-25</lastmod>
+         <lastmod>2024-03-26</lastmod>
          <changefreq>daily</changefreq>
     </url>
     <url>
          <loc>https://ocf.etsi.org/0.0/testing/testplan/api_provider_management/</loc>
-         <lastmod>2024-03-25</lastmod>
+         <lastmod>2024-03-26</lastmod>
          <changefreq>daily</changefreq>
     </url>
     <url>
          <loc>https://ocf.etsi.org/0.0/testing/testplan/api_publish_service/</loc>
-         <lastmod>2024-03-25</lastmod>
+         <lastmod>2024-03-26</lastmod>
          <changefreq>daily</changefreq>
     </url>
     <url>
          <loc>https://ocf.etsi.org/0.0/testing/testplan/api_security_service/</loc>
-         <lastmod>2024-03-25</lastmod>
+         <lastmod>2024-03-26</lastmod>
          <changefreq>daily</changefreq>
     </url>
     <url>
          <loc>https://ocf.etsi.org/0.0/testing/testplan/common_operations/</loc>
-         <lastmod>2024-03-25</lastmod>
+         <lastmod>2024-03-26</lastmod>
          <changefreq>daily</changefreq>
     </url>
 </urlset>
\ No newline at end of file
diff --git a/public/0.0/sitemap.xml.gz b/public/0.0/sitemap.xml.gz
index 0be8637cb997f4143233fcba7fa4c4707f00a155..8a811d9f2b5b7b30686e9aca990c7037865e95d6 100644
GIT binary patch
delta 31
mcmeyt^n;0AzMF%iy`5<yyBt$g=tgx<Mvhlm%vC%*3=9C51qeU@

delta 31
mcmeyt^n;0AzMF%i-JNkFyByOkuZ`-Sj2wbhNt=0i7#IMRmIy-t

diff --git a/public/0.0/stylesheets/extra.css b/public/0.0/stylesheets/extra.css
new file mode 100644
index 00000000..22975038
--- /dev/null
+++ b/public/0.0/stylesheets/extra.css
@@ -0,0 +1,24 @@
+:root {
+
+    --color1: #EF4136;
+    --color2: #F7941D;
+    --color3: #FFDE17;
+    --color4: #BFD730;
+    --color5: #2BB673;
+    --color6: #C800D4;
+    --color7: #397EC1;
+    --color8: #004A8D;
+    --color9: #000000;
+
+
+    --md-primary-fg-color: var(--color7);
+    --md-primary-fg-color--light: var(--color8);
+    --md-primary-fg-color--dark: var(--color2);
+    /* --md-primary-bg-color:               hsla(0, 0%, 100%, 1);
+  --md-primary-bg-color--light:        hsla(0, 0%, 100%, 0.7); */
+
+    --md-accent-fg-color: var(--color1);
+    /* --md-accent-fg-color--transparent:   hsla(#{hex2hsl($clr-indigo-a200)}, 0.1);
+  --md-accent-bg-color:                hsla(0, 0%, 100%, 1);
+  --md-accent-bg-color--light:         hsla(0, 0%, 100%, 0.7); */
+}
\ No newline at end of file
diff --git a/public/0.0/testing/postman/index.html b/public/0.0/testing/postman/index.html
index 8e29401e..d003e918 100644
--- a/public/0.0/testing/postman/index.html
+++ b/public/0.0/testing/postman/index.html
@@ -52,6 +52,8 @@
       
     
     
+      <link rel="stylesheet" href="../../stylesheets/extra.css">
+    
     <script>__md_scope=new URL("../..",location),__md_hash=e=>[...e].reduce((e,_)=>(e<<5)-e+_.charCodeAt(0),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
     
       
@@ -67,7 +69,7 @@
     
     
     
-    <body dir="ltr" data-md-color-scheme="default" data-md-color-primary="cyan" data-md-color-accent="blue">
+    <body dir="ltr" data-md-color-scheme="default" data-md-color-primary="custom" data-md-color-accent="custom">
   
     
     <input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
@@ -98,7 +100,7 @@
   <nav class="md-header__inner md-grid" aria-label="Header">
     <a href="../.." title="ETSI SDG OCF Documentation" class="md-header__button md-logo" aria-label="ETSI SDG OCF Documentation" data-md-component="logo">
       
-  <img src="../../images/logos/OpenCAPIF.png" alt="logo">
+  <img src="../../images/logos/Open CAPIF Logo Screen_B_W Slogan NEG.png" alt="logo">
 
     </a>
     <label class="md-header__button md-icon" for="__drawer">
@@ -204,7 +206,7 @@
   <label class="md-nav__title" for="__drawer">
     <a href="../.." title="ETSI SDG OCF Documentation" class="md-nav__button md-logo" aria-label="ETSI SDG OCF Documentation" data-md-component="logo">
       
-  <img src="../../images/logos/OpenCAPIF.png" alt="logo">
+  <img src="../../images/logos/Open CAPIF Logo Screen_B_W Slogan NEG.png" alt="logo">
 
     </a>
     ETSI SDG OCF Documentation
diff --git a/public/0.0/testing/robotframework/index.html b/public/0.0/testing/robotframework/index.html
index 41acf487..11214f4c 100644
--- a/public/0.0/testing/robotframework/index.html
+++ b/public/0.0/testing/robotframework/index.html
@@ -52,6 +52,8 @@
       
     
     
+      <link rel="stylesheet" href="../../stylesheets/extra.css">
+    
     <script>__md_scope=new URL("../..",location),__md_hash=e=>[...e].reduce((e,_)=>(e<<5)-e+_.charCodeAt(0),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
     
       
@@ -67,7 +69,7 @@
     
     
     
-    <body dir="ltr" data-md-color-scheme="default" data-md-color-primary="cyan" data-md-color-accent="blue">
+    <body dir="ltr" data-md-color-scheme="default" data-md-color-primary="custom" data-md-color-accent="custom">
   
     
     <input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
@@ -98,7 +100,7 @@
   <nav class="md-header__inner md-grid" aria-label="Header">
     <a href="../.." title="ETSI SDG OCF Documentation" class="md-header__button md-logo" aria-label="ETSI SDG OCF Documentation" data-md-component="logo">
       
-  <img src="../../images/logos/OpenCAPIF.png" alt="logo">
+  <img src="../../images/logos/Open CAPIF Logo Screen_B_W Slogan NEG.png" alt="logo">
 
     </a>
     <label class="md-header__button md-icon" for="__drawer">
@@ -204,7 +206,7 @@
   <label class="md-nav__title" for="__drawer">
     <a href="../.." title="ETSI SDG OCF Documentation" class="md-nav__button md-logo" aria-label="ETSI SDG OCF Documentation" data-md-component="logo">
       
-  <img src="../../images/logos/OpenCAPIF.png" alt="logo">
+  <img src="../../images/logos/Open CAPIF Logo Screen_B_W Slogan NEG.png" alt="logo">
 
     </a>
     ETSI SDG OCF Documentation
diff --git a/public/0.0/testing/testplan/api_access_control_policy/index.html b/public/0.0/testing/testplan/api_access_control_policy/index.html
index 1a28899a..f0807522 100644
--- a/public/0.0/testing/testplan/api_access_control_policy/index.html
+++ b/public/0.0/testing/testplan/api_access_control_policy/index.html
@@ -48,6 +48,8 @@
       
     
     
+      <link rel="stylesheet" href="../../../stylesheets/extra.css">
+    
     <script>__md_scope=new URL("../../..",location),__md_hash=e=>[...e].reduce((e,_)=>(e<<5)-e+_.charCodeAt(0),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
     
       
@@ -63,7 +65,7 @@
     
     
     
-    <body dir="ltr" data-md-color-scheme="default" data-md-color-primary="cyan" data-md-color-accent="blue">
+    <body dir="ltr" data-md-color-scheme="default" data-md-color-primary="custom" data-md-color-accent="custom">
   
     
     <input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
@@ -94,7 +96,7 @@
   <nav class="md-header__inner md-grid" aria-label="Header">
     <a href="../../.." title="ETSI SDG OCF Documentation" class="md-header__button md-logo" aria-label="ETSI SDG OCF Documentation" data-md-component="logo">
       
-  <img src="../../../images/logos/OpenCAPIF.png" alt="logo">
+  <img src="../../../images/logos/Open CAPIF Logo Screen_B_W Slogan NEG.png" alt="logo">
 
     </a>
     <label class="md-header__button md-icon" for="__drawer">
@@ -200,7 +202,7 @@
   <label class="md-nav__title" for="__drawer">
     <a href="../../.." title="ETSI SDG OCF Documentation" class="md-nav__button md-logo" aria-label="ETSI SDG OCF Documentation" data-md-component="logo">
       
-  <img src="../../../images/logos/OpenCAPIF.png" alt="logo">
+  <img src="../../../images/logos/Open CAPIF Logo Screen_B_W Slogan NEG.png" alt="logo">
 
     </a>
     ETSI SDG OCF Documentation
diff --git a/public/0.0/testing/testplan/api_auditing_service/index.html b/public/0.0/testing/testplan/api_auditing_service/index.html
index 18650813..752bb541 100644
--- a/public/0.0/testing/testplan/api_auditing_service/index.html
+++ b/public/0.0/testing/testplan/api_auditing_service/index.html
@@ -48,6 +48,8 @@
       
     
     
+      <link rel="stylesheet" href="../../../stylesheets/extra.css">
+    
     <script>__md_scope=new URL("../../..",location),__md_hash=e=>[...e].reduce((e,_)=>(e<<5)-e+_.charCodeAt(0),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
     
       
@@ -63,7 +65,7 @@
     
     
     
-    <body dir="ltr" data-md-color-scheme="default" data-md-color-primary="cyan" data-md-color-accent="blue">
+    <body dir="ltr" data-md-color-scheme="default" data-md-color-primary="custom" data-md-color-accent="custom">
   
     
     <input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
@@ -94,7 +96,7 @@
   <nav class="md-header__inner md-grid" aria-label="Header">
     <a href="../../.." title="ETSI SDG OCF Documentation" class="md-header__button md-logo" aria-label="ETSI SDG OCF Documentation" data-md-component="logo">
       
-  <img src="../../../images/logos/OpenCAPIF.png" alt="logo">
+  <img src="../../../images/logos/Open CAPIF Logo Screen_B_W Slogan NEG.png" alt="logo">
 
     </a>
     <label class="md-header__button md-icon" for="__drawer">
@@ -200,7 +202,7 @@
   <label class="md-nav__title" for="__drawer">
     <a href="../../.." title="ETSI SDG OCF Documentation" class="md-nav__button md-logo" aria-label="ETSI SDG OCF Documentation" data-md-component="logo">
       
-  <img src="../../../images/logos/OpenCAPIF.png" alt="logo">
+  <img src="../../../images/logos/Open CAPIF Logo Screen_B_W Slogan NEG.png" alt="logo">
 
     </a>
     ETSI SDG OCF Documentation
diff --git a/public/0.0/testing/testplan/api_discover_service/index.html b/public/0.0/testing/testplan/api_discover_service/index.html
index 67481069..238b784a 100644
--- a/public/0.0/testing/testplan/api_discover_service/index.html
+++ b/public/0.0/testing/testplan/api_discover_service/index.html
@@ -48,6 +48,8 @@
       
     
     
+      <link rel="stylesheet" href="../../../stylesheets/extra.css">
+    
     <script>__md_scope=new URL("../../..",location),__md_hash=e=>[...e].reduce((e,_)=>(e<<5)-e+_.charCodeAt(0),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
     
       
@@ -63,7 +65,7 @@
     
     
     
-    <body dir="ltr" data-md-color-scheme="default" data-md-color-primary="cyan" data-md-color-accent="blue">
+    <body dir="ltr" data-md-color-scheme="default" data-md-color-primary="custom" data-md-color-accent="custom">
   
     
     <input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
@@ -94,7 +96,7 @@
   <nav class="md-header__inner md-grid" aria-label="Header">
     <a href="../../.." title="ETSI SDG OCF Documentation" class="md-header__button md-logo" aria-label="ETSI SDG OCF Documentation" data-md-component="logo">
       
-  <img src="../../../images/logos/OpenCAPIF.png" alt="logo">
+  <img src="../../../images/logos/Open CAPIF Logo Screen_B_W Slogan NEG.png" alt="logo">
 
     </a>
     <label class="md-header__button md-icon" for="__drawer">
@@ -200,7 +202,7 @@
   <label class="md-nav__title" for="__drawer">
     <a href="../../.." title="ETSI SDG OCF Documentation" class="md-nav__button md-logo" aria-label="ETSI SDG OCF Documentation" data-md-component="logo">
       
-  <img src="../../../images/logos/OpenCAPIF.png" alt="logo">
+  <img src="../../../images/logos/Open CAPIF Logo Screen_B_W Slogan NEG.png" alt="logo">
 
     </a>
     ETSI SDG OCF Documentation
diff --git a/public/0.0/testing/testplan/api_events_service/index.html b/public/0.0/testing/testplan/api_events_service/index.html
index c3c85c59..2f4be45f 100644
--- a/public/0.0/testing/testplan/api_events_service/index.html
+++ b/public/0.0/testing/testplan/api_events_service/index.html
@@ -48,6 +48,8 @@
       
     
     
+      <link rel="stylesheet" href="../../../stylesheets/extra.css">
+    
     <script>__md_scope=new URL("../../..",location),__md_hash=e=>[...e].reduce((e,_)=>(e<<5)-e+_.charCodeAt(0),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
     
       
@@ -63,7 +65,7 @@
     
     
     
-    <body dir="ltr" data-md-color-scheme="default" data-md-color-primary="cyan" data-md-color-accent="blue">
+    <body dir="ltr" data-md-color-scheme="default" data-md-color-primary="custom" data-md-color-accent="custom">
   
     
     <input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
@@ -94,7 +96,7 @@
   <nav class="md-header__inner md-grid" aria-label="Header">
     <a href="../../.." title="ETSI SDG OCF Documentation" class="md-header__button md-logo" aria-label="ETSI SDG OCF Documentation" data-md-component="logo">
       
-  <img src="../../../images/logos/OpenCAPIF.png" alt="logo">
+  <img src="../../../images/logos/Open CAPIF Logo Screen_B_W Slogan NEG.png" alt="logo">
 
     </a>
     <label class="md-header__button md-icon" for="__drawer">
@@ -200,7 +202,7 @@
   <label class="md-nav__title" for="__drawer">
     <a href="../../.." title="ETSI SDG OCF Documentation" class="md-nav__button md-logo" aria-label="ETSI SDG OCF Documentation" data-md-component="logo">
       
-  <img src="../../../images/logos/OpenCAPIF.png" alt="logo">
+  <img src="../../../images/logos/Open CAPIF Logo Screen_B_W Slogan NEG.png" alt="logo">
 
     </a>
     ETSI SDG OCF Documentation
diff --git a/public/0.0/testing/testplan/api_invoker_management/index.html b/public/0.0/testing/testplan/api_invoker_management/index.html
index c483a29d..09846a7a 100644
--- a/public/0.0/testing/testplan/api_invoker_management/index.html
+++ b/public/0.0/testing/testplan/api_invoker_management/index.html
@@ -48,6 +48,8 @@
       
     
     
+      <link rel="stylesheet" href="../../../stylesheets/extra.css">
+    
     <script>__md_scope=new URL("../../..",location),__md_hash=e=>[...e].reduce((e,_)=>(e<<5)-e+_.charCodeAt(0),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
     
       
@@ -63,7 +65,7 @@
     
     
     
-    <body dir="ltr" data-md-color-scheme="default" data-md-color-primary="cyan" data-md-color-accent="blue">
+    <body dir="ltr" data-md-color-scheme="default" data-md-color-primary="custom" data-md-color-accent="custom">
   
     
     <input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
@@ -94,7 +96,7 @@
   <nav class="md-header__inner md-grid" aria-label="Header">
     <a href="../../.." title="ETSI SDG OCF Documentation" class="md-header__button md-logo" aria-label="ETSI SDG OCF Documentation" data-md-component="logo">
       
-  <img src="../../../images/logos/OpenCAPIF.png" alt="logo">
+  <img src="../../../images/logos/Open CAPIF Logo Screen_B_W Slogan NEG.png" alt="logo">
 
     </a>
     <label class="md-header__button md-icon" for="__drawer">
@@ -200,7 +202,7 @@
   <label class="md-nav__title" for="__drawer">
     <a href="../../.." title="ETSI SDG OCF Documentation" class="md-nav__button md-logo" aria-label="ETSI SDG OCF Documentation" data-md-component="logo">
       
-  <img src="../../../images/logos/OpenCAPIF.png" alt="logo">
+  <img src="../../../images/logos/Open CAPIF Logo Screen_B_W Slogan NEG.png" alt="logo">
 
     </a>
     ETSI SDG OCF Documentation
diff --git a/public/0.0/testing/testplan/api_logging_service/index.html b/public/0.0/testing/testplan/api_logging_service/index.html
index a43151ab..59540438 100644
--- a/public/0.0/testing/testplan/api_logging_service/index.html
+++ b/public/0.0/testing/testplan/api_logging_service/index.html
@@ -48,6 +48,8 @@
       
     
     
+      <link rel="stylesheet" href="../../../stylesheets/extra.css">
+    
     <script>__md_scope=new URL("../../..",location),__md_hash=e=>[...e].reduce((e,_)=>(e<<5)-e+_.charCodeAt(0),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
     
       
@@ -63,7 +65,7 @@
     
     
     
-    <body dir="ltr" data-md-color-scheme="default" data-md-color-primary="cyan" data-md-color-accent="blue">
+    <body dir="ltr" data-md-color-scheme="default" data-md-color-primary="custom" data-md-color-accent="custom">
   
     
     <input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
@@ -94,7 +96,7 @@
   <nav class="md-header__inner md-grid" aria-label="Header">
     <a href="../../.." title="ETSI SDG OCF Documentation" class="md-header__button md-logo" aria-label="ETSI SDG OCF Documentation" data-md-component="logo">
       
-  <img src="../../../images/logos/OpenCAPIF.png" alt="logo">
+  <img src="../../../images/logos/Open CAPIF Logo Screen_B_W Slogan NEG.png" alt="logo">
 
     </a>
     <label class="md-header__button md-icon" for="__drawer">
@@ -200,7 +202,7 @@
   <label class="md-nav__title" for="__drawer">
     <a href="../../.." title="ETSI SDG OCF Documentation" class="md-nav__button md-logo" aria-label="ETSI SDG OCF Documentation" data-md-component="logo">
       
-  <img src="../../../images/logos/OpenCAPIF.png" alt="logo">
+  <img src="../../../images/logos/Open CAPIF Logo Screen_B_W Slogan NEG.png" alt="logo">
 
     </a>
     ETSI SDG OCF Documentation
diff --git a/public/0.0/testing/testplan/api_provider_management/index.html b/public/0.0/testing/testplan/api_provider_management/index.html
index c163ed5c..4b6e2d45 100644
--- a/public/0.0/testing/testplan/api_provider_management/index.html
+++ b/public/0.0/testing/testplan/api_provider_management/index.html
@@ -48,6 +48,8 @@
       
     
     
+      <link rel="stylesheet" href="../../../stylesheets/extra.css">
+    
     <script>__md_scope=new URL("../../..",location),__md_hash=e=>[...e].reduce((e,_)=>(e<<5)-e+_.charCodeAt(0),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
     
       
@@ -63,7 +65,7 @@
     
     
     
-    <body dir="ltr" data-md-color-scheme="default" data-md-color-primary="cyan" data-md-color-accent="blue">
+    <body dir="ltr" data-md-color-scheme="default" data-md-color-primary="custom" data-md-color-accent="custom">
   
     
     <input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
@@ -94,7 +96,7 @@
   <nav class="md-header__inner md-grid" aria-label="Header">
     <a href="../../.." title="ETSI SDG OCF Documentation" class="md-header__button md-logo" aria-label="ETSI SDG OCF Documentation" data-md-component="logo">
       
-  <img src="../../../images/logos/OpenCAPIF.png" alt="logo">
+  <img src="../../../images/logos/Open CAPIF Logo Screen_B_W Slogan NEG.png" alt="logo">
 
     </a>
     <label class="md-header__button md-icon" for="__drawer">
@@ -200,7 +202,7 @@
   <label class="md-nav__title" for="__drawer">
     <a href="../../.." title="ETSI SDG OCF Documentation" class="md-nav__button md-logo" aria-label="ETSI SDG OCF Documentation" data-md-component="logo">
       
-  <img src="../../../images/logos/OpenCAPIF.png" alt="logo">
+  <img src="../../../images/logos/Open CAPIF Logo Screen_B_W Slogan NEG.png" alt="logo">
 
     </a>
     ETSI SDG OCF Documentation
diff --git a/public/0.0/testing/testplan/api_publish_service/index.html b/public/0.0/testing/testplan/api_publish_service/index.html
index f1e2414a..c84ee66f 100644
--- a/public/0.0/testing/testplan/api_publish_service/index.html
+++ b/public/0.0/testing/testplan/api_publish_service/index.html
@@ -48,6 +48,8 @@
       
     
     
+      <link rel="stylesheet" href="../../../stylesheets/extra.css">
+    
     <script>__md_scope=new URL("../../..",location),__md_hash=e=>[...e].reduce((e,_)=>(e<<5)-e+_.charCodeAt(0),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
     
       
@@ -63,7 +65,7 @@
     
     
     
-    <body dir="ltr" data-md-color-scheme="default" data-md-color-primary="cyan" data-md-color-accent="blue">
+    <body dir="ltr" data-md-color-scheme="default" data-md-color-primary="custom" data-md-color-accent="custom">
   
     
     <input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
@@ -94,7 +96,7 @@
   <nav class="md-header__inner md-grid" aria-label="Header">
     <a href="../../.." title="ETSI SDG OCF Documentation" class="md-header__button md-logo" aria-label="ETSI SDG OCF Documentation" data-md-component="logo">
       
-  <img src="../../../images/logos/OpenCAPIF.png" alt="logo">
+  <img src="../../../images/logos/Open CAPIF Logo Screen_B_W Slogan NEG.png" alt="logo">
 
     </a>
     <label class="md-header__button md-icon" for="__drawer">
@@ -200,7 +202,7 @@
   <label class="md-nav__title" for="__drawer">
     <a href="../../.." title="ETSI SDG OCF Documentation" class="md-nav__button md-logo" aria-label="ETSI SDG OCF Documentation" data-md-component="logo">
       
-  <img src="../../../images/logos/OpenCAPIF.png" alt="logo">
+  <img src="../../../images/logos/Open CAPIF Logo Screen_B_W Slogan NEG.png" alt="logo">
 
     </a>
     ETSI SDG OCF Documentation
diff --git a/public/0.0/testing/testplan/api_security_service/index.html b/public/0.0/testing/testplan/api_security_service/index.html
index fa46f897..8685c87d 100644
--- a/public/0.0/testing/testplan/api_security_service/index.html
+++ b/public/0.0/testing/testplan/api_security_service/index.html
@@ -48,6 +48,8 @@
       
     
     
+      <link rel="stylesheet" href="../../../stylesheets/extra.css">
+    
     <script>__md_scope=new URL("../../..",location),__md_hash=e=>[...e].reduce((e,_)=>(e<<5)-e+_.charCodeAt(0),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
     
       
@@ -63,7 +65,7 @@
     
     
     
-    <body dir="ltr" data-md-color-scheme="default" data-md-color-primary="cyan" data-md-color-accent="blue">
+    <body dir="ltr" data-md-color-scheme="default" data-md-color-primary="custom" data-md-color-accent="custom">
   
     
     <input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
@@ -94,7 +96,7 @@
   <nav class="md-header__inner md-grid" aria-label="Header">
     <a href="../../.." title="ETSI SDG OCF Documentation" class="md-header__button md-logo" aria-label="ETSI SDG OCF Documentation" data-md-component="logo">
       
-  <img src="../../../images/logos/OpenCAPIF.png" alt="logo">
+  <img src="../../../images/logos/Open CAPIF Logo Screen_B_W Slogan NEG.png" alt="logo">
 
     </a>
     <label class="md-header__button md-icon" for="__drawer">
@@ -200,7 +202,7 @@
   <label class="md-nav__title" for="__drawer">
     <a href="../../.." title="ETSI SDG OCF Documentation" class="md-nav__button md-logo" aria-label="ETSI SDG OCF Documentation" data-md-component="logo">
       
-  <img src="../../../images/logos/OpenCAPIF.png" alt="logo">
+  <img src="../../../images/logos/Open CAPIF Logo Screen_B_W Slogan NEG.png" alt="logo">
 
     </a>
     ETSI SDG OCF Documentation
diff --git a/public/0.0/testing/testplan/common_operations/index.html b/public/0.0/testing/testplan/common_operations/index.html
index a14c726a..1cc0139a 100644
--- a/public/0.0/testing/testplan/common_operations/index.html
+++ b/public/0.0/testing/testplan/common_operations/index.html
@@ -48,6 +48,8 @@
       
     
     
+      <link rel="stylesheet" href="../../../stylesheets/extra.css">
+    
     <script>__md_scope=new URL("../../..",location),__md_hash=e=>[...e].reduce((e,_)=>(e<<5)-e+_.charCodeAt(0),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
     
       
@@ -63,7 +65,7 @@
     
     
     
-    <body dir="ltr" data-md-color-scheme="default" data-md-color-primary="cyan" data-md-color-accent="blue">
+    <body dir="ltr" data-md-color-scheme="default" data-md-color-primary="custom" data-md-color-accent="custom">
   
     
     <input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
@@ -94,7 +96,7 @@
   <nav class="md-header__inner md-grid" aria-label="Header">
     <a href="../../.." title="ETSI SDG OCF Documentation" class="md-header__button md-logo" aria-label="ETSI SDG OCF Documentation" data-md-component="logo">
       
-  <img src="../../../images/logos/OpenCAPIF.png" alt="logo">
+  <img src="../../../images/logos/Open CAPIF Logo Screen_B_W Slogan NEG.png" alt="logo">
 
     </a>
     <label class="md-header__button md-icon" for="__drawer">
@@ -200,7 +202,7 @@
   <label class="md-nav__title" for="__drawer">
     <a href="../../.." title="ETSI SDG OCF Documentation" class="md-nav__button md-logo" aria-label="ETSI SDG OCF Documentation" data-md-component="logo">
       
-  <img src="../../../images/logos/OpenCAPIF.png" alt="logo">
+  <img src="../../../images/logos/Open CAPIF Logo Screen_B_W Slogan NEG.png" alt="logo">
 
     </a>
     ETSI SDG OCF Documentation
diff --git a/public/0.0/testing/testplan/index.html b/public/0.0/testing/testplan/index.html
index a7856b84..46ea7476 100644
--- a/public/0.0/testing/testplan/index.html
+++ b/public/0.0/testing/testplan/index.html
@@ -52,6 +52,8 @@
       
     
     
+      <link rel="stylesheet" href="../../stylesheets/extra.css">
+    
     <script>__md_scope=new URL("../..",location),__md_hash=e=>[...e].reduce((e,_)=>(e<<5)-e+_.charCodeAt(0),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
     
       
@@ -67,7 +69,7 @@
     
     
     
-    <body dir="ltr" data-md-color-scheme="default" data-md-color-primary="cyan" data-md-color-accent="blue">
+    <body dir="ltr" data-md-color-scheme="default" data-md-color-primary="custom" data-md-color-accent="custom">
   
     
     <input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
@@ -98,7 +100,7 @@
   <nav class="md-header__inner md-grid" aria-label="Header">
     <a href="../.." title="ETSI SDG OCF Documentation" class="md-header__button md-logo" aria-label="ETSI SDG OCF Documentation" data-md-component="logo">
       
-  <img src="../../images/logos/OpenCAPIF.png" alt="logo">
+  <img src="../../images/logos/Open CAPIF Logo Screen_B_W Slogan NEG.png" alt="logo">
 
     </a>
     <label class="md-header__button md-icon" for="__drawer">
@@ -204,7 +206,7 @@
   <label class="md-nav__title" for="__drawer">
     <a href="../.." title="ETSI SDG OCF Documentation" class="md-nav__button md-logo" aria-label="ETSI SDG OCF Documentation" data-md-component="logo">
       
-  <img src="../../images/logos/OpenCAPIF.png" alt="logo">
+  <img src="../../images/logos/Open CAPIF Logo Screen_B_W Slogan NEG.png" alt="logo">
 
     </a>
     ETSI SDG OCF Documentation
-- 
GitLab