diff --git a/CITATION.cff b/CITATION.cff index 4b5d6ed9..ef7f8ff7 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -1,9 +1,9 @@ -cff-version: 2.0.0 +cff-version: 2.1.0 message: "If you use this software, please cite it as below." authors: - family-names: "EVOLVED-5g" given-names: "EVOLVED-5g" title: "CAPIF_API_Services" -version: 2.0 -date-released: 2022-09-23 +version: 2.1 +date-released: 2022-01-30 url: "https://github.com/EVOLVED-5G/CAPIF_API_Services" diff --git a/README.md b/README.md index 6f2082c5..d4f29563 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,7 @@ - [Mongo DB Dashboard](#mongo-db-dashboard) - [CAPIF Tool Release 1.0](#capif-tool-release-10) - [CAPIF Tool Release 2.0](#capif-tool-release-20) +- [CAPIF Tool Release 2.1](#capif-tool-release-21) # Repository structure @@ -552,4 +553,30 @@ Additional information about this version: - JWT Authentication Server - Easy RSA Server - TLS Enabled -hola + + +# CAPIF Tool Release 2.1 + +This CAPIF services have many stability improvements: +- API Provider Management Service adds TLS connection using certificates. +- Added logs on Services. +- Easy RSA: + - Fix: recreate always when we try to sign a public key. Previously if there are a signed key with same filename causes a MISMATCH error. + - Code refactor. + - Scripts added for manual remove of signed certificates. +- JWT Auth Service: + - code refactor + - New register operation added, distinguish between invoker and exposer logic. +- NGINX service: + - Adjusted rounting information. + - TLS over API Provider Management Service. + - removed not used endpoints + - TLS over some endpoint at JWT Auth Service. + - Added retry to obtain ca root certificate over Easy RSA service. + - Added check of ca.crt obtained. + - nginx_prepare.sh is refactored and parametrized. +- Robot Framework Test: + - Adjusted the register flow for exposer and invoker. + - End points used in that flow are changed. + - API Provider Management tests adapted to use TLS. + diff --git a/pac/Jenkins-dummy.groovy b/pac/Jenkins-dummy.groovy new file mode 100644 index 00000000..04a868c9 --- /dev/null +++ b/pac/Jenkins-dummy.groovy @@ -0,0 +1,15 @@ +pipeline { + agent any + + parameters { + string(name: 'GIT_CICD_BRANCH', defaultValue: 'develop', description: 'Deployment git branch name') + } + + stages { + stage('Say Hello and Goobye!') { + steps { + echo "Hello and Goodbye" + } + } + } +} diff --git a/pac/Jenkinsfile-capif-tests.groovy b/pac/Jenkinsfile-capif-tests.groovy index 7c6174be..09cec730 100644 --- a/pac/Jenkinsfile-capif-tests.groovy +++ b/pac/Jenkinsfile-capif-tests.groovy @@ -38,6 +38,8 @@ pipeline { disableConcurrentBuilds() buildDiscarder(logRotator(daysToKeepStr: '14', numToKeepStr: '30', artifactDaysToKeepStr: '14', artifactNumToKeepStr: '30')) ansiColor('xterm') + timeout(time: 15, unit: 'MINUTES') + retry(2) } parameters { string(name: 'BRANCH_NAME', defaultValue: 'develop', description: 'Deployment git branch name') diff --git a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/controllers/default_controller.py b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/controllers/default_controller.py index 3398b1be..3cb42e95 100644 --- a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/controllers/default_controller.py +++ b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/controllers/default_controller.py @@ -1,13 +1,20 @@ import connexion import six +import json +from flask import Response, request from ..core.provider_enrolment_details_api import ProviderManagementOperations +from ..core.check_user import CapifUsersOperations +from ..encoder import JSONEncoder from api_provider_management.models.api_provider_enrolment_details import APIProviderEnrolmentDetails # noqa: E501 from api_provider_management.models.problem_details import ProblemDetails # noqa: E501 from api_provider_management import util +from cryptography.hazmat.backends import default_backend +from cryptography import x509 provider_management_ops = ProviderManagementOperations() +check_user = CapifUsersOperations() def registrations_post(body): # noqa: E501 """registrations_post @@ -20,6 +27,20 @@ def registrations_post(body): # noqa: E501 :rtype: APIProviderEnrolmentDetails """ + cert_tmp = request.headers['X-Ssl-Client-Cert'] + cert_raw = cert_tmp.replace('\t', '') + + + cert = x509.load_pem_x509_certificate(str.encode(cert_raw), default_backend()) + cn = cert.subject.get_attributes_for_oid(x509.OID_COMMON_NAME)[0].value.strip() + + capif_user = check_user.check_capif_user(cn, "exposer") + + if not capif_user: + prob = ProblemDetails(title="Unauthorized", status=401, detail="User not authorized", + cause="Certificate not authorized") + return Response(json.dumps(prob, cls=JSONEncoder), status=401, mimetype='application/json') + if connexion.request.is_json: body = APIProviderEnrolmentDetails.from_dict(connexion.request.get_json()) # noqa: E501 @@ -40,6 +61,20 @@ def registrations_registration_id_delete(registration_id): # noqa: E501 :rtype: None """ + cert_tmp = request.headers['X-Ssl-Client-Cert'] + cert_raw = cert_tmp.replace('\t', '') + + + cert = x509.load_pem_x509_certificate(str.encode(cert_raw), default_backend()) + cn = cert.subject.get_attributes_for_oid(x509.OID_COMMON_NAME)[0].value.strip() + + capif_user = check_user.check_capif_user(cn, "exposer") + + if not capif_user: + prob = ProblemDetails(title="Unauthorized", status=401, detail="User not authorized", + cause="Certificate not authorized") + return Response(json.dumps(prob, cls=JSONEncoder), status=401, mimetype='application/json') + res = provider_management_ops.delete_api_provider_enrolment_details(registration_id) return res @@ -57,9 +92,23 @@ def registrations_registration_id_put(registration_id, body): # noqa: E501 :rtype: APIProviderEnrolmentDetails """ + cert_tmp = request.headers['X-Ssl-Client-Cert'] + cert_raw = cert_tmp.replace('\t', '') + + + cert = x509.load_pem_x509_certificate(str.encode(cert_raw), default_backend()) + cn = cert.subject.get_attributes_for_oid(x509.OID_COMMON_NAME)[0].value.strip() + + capif_user = check_user.check_capif_user(cn, "exposer") + + if not capif_user: + prob = ProblemDetails(title="Unauthorized", status=401, detail="User not authorized", + cause="Certificate not authorized") + return Response(json.dumps(prob, cls=JSONEncoder), status=401, mimetype='application/json') + if connexion.request.is_json: body = APIProviderEnrolmentDetails.from_dict(connexion.request.get_json()) # noqa: E501 - + res = provider_management_ops.update_api_provider_enrolment_details(registration_id,body) return res diff --git a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/controllers/individual_api_provider_enrolment_details_controller.py b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/controllers/individual_api_provider_enrolment_details_controller.py index 11dccff9..040b208b 100644 --- a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/controllers/individual_api_provider_enrolment_details_controller.py +++ b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/controllers/individual_api_provider_enrolment_details_controller.py @@ -1,13 +1,20 @@ from email.quoprimime import body_decode import connexion import six +import json +from flask import Response, request from ..core.provider_enrolment_details_api import ProviderManagementOperations +from ..core.check_user import CapifUsersOperations +from ..encoder import JSONEncoder from api_provider_management.models.api_provider_enrolment_details import APIProviderEnrolmentDetails # noqa: E501 from api_provider_management.models.api_provider_enrolment_details_patch import APIProviderEnrolmentDetailsPatch # noqa: E501 from api_provider_management.models.problem_details import ProblemDetails # noqa: E501 from api_provider_management import util +from cryptography.hazmat.backends import default_backend +from cryptography import x509 +check_user = CapifUsersOperations() provider_management_ops = ProviderManagementOperations() @@ -23,6 +30,20 @@ def modify_ind_api_provider_enrolment(registration_id, body): # noqa: E501 :rtype: APIProviderEnrolmentDetails """ + cert_tmp = request.headers['X-Ssl-Client-Cert'] + cert_raw = cert_tmp.replace('\t', '') + + + cert = x509.load_pem_x509_certificate(str.encode(cert_raw), default_backend()) + cn = cert.subject.get_attributes_for_oid(x509.OID_COMMON_NAME)[0].value.strip() + + capif_user = check_user.check_capif_user(cn, "exposer") + + if not capif_user: + prob = ProblemDetails(title="Unauthorized", status=401, detail="User not authorized", + cause="Certificate not authorized") + return Response(json.dumps(prob, cls=JSONEncoder), status=401, mimetype='application/json') + if connexion.request.is_json: body = APIProviderEnrolmentDetailsPatch.from_dict(connexion.request.get_json()) # noqa: E501 diff --git a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/check_user.py b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/check_user.py new file mode 100644 index 00000000..e5a8beaa --- /dev/null +++ b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/check_user.py @@ -0,0 +1,21 @@ +import sys +from ..db.db import MongoDatabse + +class CapifUsersOperations: + + def __init__(self): + self.db = MongoDatabse() + + def check_capif_user(self, common_name, role): + try: + mycol = self.db.get_col_by_name(self.db.capif_users) + + capif_user = mycol.find_one({"$and": [{"cn": common_name}, {"role": role}]}) + + if capif_user is None: + return False + + return True + except Exception as e: + print("An exception occurred ::", e, file=sys.stderr) + return False \ No newline at end of file diff --git a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/db/db.py b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/db/db.py index f6b13da2..d0ef3b83 100644 --- a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/db/db.py +++ b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/db/db.py @@ -8,6 +8,7 @@ def __init__(self): self.config = Config().getConfig() self.db = self.__connect() self.provider_enrolment_details = self.config['mongo']['col'] + self.capif_users = self.config['mongo']['capif_users'] def get_col_by_name(self, name): return self.db[name] diff --git a/services/TS29222_CAPIF_API_Provider_Management_API/config.yaml b/services/TS29222_CAPIF_API_Provider_Management_API/config.yaml index c9da51ed..5e81a3df 100644 --- a/services/TS29222_CAPIF_API_Provider_Management_API/config.yaml +++ b/services/TS29222_CAPIF_API_Provider_Management_API/config.yaml @@ -3,7 +3,7 @@ mongo: { 'password': 'example', 'db': 'capif', 'col': 'providerenrolmentdetails', - 'jwt': 'user', + 'capif_users': 'user', 'host': 'mongo', 'port': "27017" } diff --git a/services/TS29222_CAPIF_API_Provider_Management_API/requirements.txt b/services/TS29222_CAPIF_API_Provider_Management_API/requirements.txt index 867a0317..06a8795e 100644 --- a/services/TS29222_CAPIF_API_Provider_Management_API/requirements.txt +++ b/services/TS29222_CAPIF_API_Provider_Management_API/requirements.txt @@ -3,4 +3,5 @@ swagger-ui-bundle >= 0.0.2 python_dateutil >= 2.6.0 setuptools >= 21.0.0 Flask == 2.0.3 +cryptography pymongo == 4.0.1 diff --git a/services/TS29222_CAPIF_Events_API/capif_events/controllers/default_controller.py b/services/TS29222_CAPIF_Events_API/capif_events/controllers/default_controller.py index b23c6c16..66ebb321 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/controllers/default_controller.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/controllers/default_controller.py @@ -32,7 +32,7 @@ def subscriber_id_subscriptions_post(subscriber_id, body): # noqa: E501 cert = x509.load_pem_x509_certificate(str.encode(cert_raw), default_backend()) cn = cert.subject.get_attributes_for_oid(x509.OID_COMMON_NAME)[0].value.strip() - capif_user = check_user.check_capif_user(cn, "invoker", "apf") + capif_user = check_user.check_capif_user(cn, "invoker", "exposer") if not capif_user: prob = ProblemDetails(title="Unauthorized", status=401, detail="User not authorized", diff --git a/services/easy_rsa/Dockerfile b/services/easy_rsa/Dockerfile index 560648d0..31900246 100644 --- a/services/easy_rsa/Dockerfile +++ b/services/easy_rsa/Dockerfile @@ -28,6 +28,7 @@ COPY requirements.txt requirements.txt RUN pip3 install --no-cache-dir -r requirements.txt COPY . . +RUN chmod a+x *.sh EXPOSE 8080 diff --git a/services/easy_rsa/app.py b/services/easy_rsa/app.py index 003a0b3e..7eb4be20 100644 --- a/services/easy_rsa/app.py +++ b/services/easy_rsa/app.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 -from flask import Flask, jsonify, request, Response +from typing import List +from flask import Flask, jsonify, request, Response, current_app import json import subprocess import sys @@ -31,6 +32,12 @@ def sign_csr(): mode = request.json["mode"] filename = request.json["filename"] + app.logger.info("sign-csr for user "+ filename) + names = get_files(filename) + + if len(names) != 0: + revoke_list(names) + csr_file = open(filename + '.csr', 'wb') csr_file.write(bytes(csr, 'utf-8')) csr_file.close() @@ -56,11 +63,15 @@ def sign_csr(): @app.route("/certdata", methods=["DELETE"]) def data_test(): + names = get_files('ROBOT_TESTING') + + return revoke_list(names) +def get_files(prefix): files = [] dir_list = os.listdir() for file in dir_list: - if file.startswith('ROBOT_TESTING'): + if file.startswith(prefix): files.append(file) print(files) @@ -72,13 +83,20 @@ def data_test(): convert_list_to_set = set(names) names = list(convert_list_to_set) print("Entities to remove", names) + return names + +def revoke_cert(name): + p = subprocess.call("/root/EasyRSA-3.0.4/easyrsa --batch revoke {}".format(name), + stdout=subprocess.PIPE, shell=True) + delete_file('/root/{}.csr'.format(name)) + delete_file('/root/pki/issued/{}.crt'.format(name)) + delete_file('/root/pki/reqs/{}.req'.format(name)) + current_app.logger.info("cert %s removed", name) + +def revoke_list(names=list): for name in names: - p = subprocess.call("/root/EasyRSA-3.0.4/easyrsa --batch revoke {}".format(name), - stdout=subprocess.PIPE, shell=True) - delete_file('/root/{}.csr'.format(name)) - delete_file('/root/pki/issued/{}.crt'.format(name)) - delete_file('/root/pki/reqs/{}.req'.format(name)) + revoke_cert(name) res = Response(json.dumps({'certificate_removed': names}), status=200, mimetype='application/json') diff --git a/services/easy_rsa/revoke_demo_users.sh b/services/easy_rsa/revoke_demo_users.sh new file mode 100755 index 00000000..c7affaf3 --- /dev/null +++ b/services/easy_rsa/revoke_demo_users.sh @@ -0,0 +1,5 @@ +#!/bin/bash +DUMMY=dummy +CUSTOMER_EXPOSER=customexposer +./revoke_user.sh $DUMMY +./revoke_user.sh $CUSTOMER_EXPOSER \ No newline at end of file diff --git a/services/easy_rsa/revoke_user.sh b/services/easy_rsa/revoke_user.sh new file mode 100755 index 00000000..67c05f96 --- /dev/null +++ b/services/easy_rsa/revoke_user.sh @@ -0,0 +1,10 @@ +#!/bin/bash +USER=dummy +if [ "$#" -eq 1 ]; then + USER=$1 +fi + +/root/EasyRSA-3.0.4/easyrsa --batch revoke $USER +rm -rf /root/$USER.csr +rm -rf /root/pki/issued/$USER.crt +rm -rf /root/pki/reqs/$USER.req diff --git a/services/jwt_auth/Dockerfile b/services/jwt_auth/Dockerfile index e049afd4..f4925742 100644 --- a/services/jwt_auth/Dockerfile +++ b/services/jwt_auth/Dockerfile @@ -5,6 +5,7 @@ WORKDIR /usr/src/app COPY requirements.txt /usr/src/app/requirements.txt +RUN apk add -U --no-cache gcc build-base linux-headers ca-certificates libffi-dev libressl-dev libxslt-dev RUN pip3 install --no-cache-dir -r requirements.txt COPY . /usr/src/app @@ -13,4 +14,4 @@ EXPOSE 8080 ENTRYPOINT ["python3"] -CMD ["-m", "app"] +CMD ["-m", "register_service"] diff --git a/services/jwt_auth/app.py b/services/jwt_auth/app.py deleted file mode 100644 index 9b455627..00000000 --- a/services/jwt_auth/app.py +++ /dev/null @@ -1,150 +0,0 @@ -#!/usr/bin/env python3 - -from flask import Flask, jsonify, request -from flask_jwt_extended import JWTManager, jwt_required, create_access_token -from pymongo import MongoClient -import secrets - - -app = Flask(__name__) -app.config['MONGODB_SETTINGS'] = { - 'user': 'root', - 'password': 'example', - 'db': 'capif', - 'col': 'invokerdetails', - 'jwt': 'user', - 'host': 'mongo', - 'port': 27017, -} -app.config['CAPIF_HOST'] = { - 'ip': 'localhost', - 'port': 8080, -} - -app.config["JWT_SECRET_KEY"] = "this-is-secret-key" - -jwt = JWTManager(app) - -user = app.config['MONGODB_SETTINGS']['user'] -passwd = app.config['MONGODB_SETTINGS']['password'] -db = app.config['MONGODB_SETTINGS']['db'] -col = app.config['MONGODB_SETTINGS']['jwt'] -host = app.config['MONGODB_SETTINGS']['host'] -port = app.config['MONGODB_SETTINGS']['port'] - -capif_ip = app.config['CAPIF_HOST']['ip'] -capif_port = app.config['CAPIF_HOST']['port'] - -uri = "mongodb://" + user + ":" + passwd + "@" + host + ":" + str(port) - -myclient = MongoClient(uri) -mydb = myclient[db] -user = mydb[col] -invokerdetails = mydb['invokerdetails'] -serviceapidescriptions = mydb['serviceapidescriptions'] -eventsdetails = mydb['eventsdetails'] -servicesecurity = mydb['servicesecurity'] -providerenrolmentdetails = mydb['providerenrolmentdetails'] - - -@app.route("/register", methods=["POST"]) -def register(): - username = request.json["username"] - role = request.json["role"] - test = user.find_one({"username": username}) - if test: - return jsonify("User already exists"), 409 - elif role != "invoker" and role != "exposer": - return jsonify(message="Role must be invoker or exposer"), 409 - else: - username = request.json["username"] - password = request.json["password"] - role = request.json["role"] - description = request.json["description"] - cn = request.json["cn"] - user_info = dict(_id=secrets.token_hex(7), username=username, password=password, role=role, description=description, cn=cn) - obj = user.insert_one(user_info) - - if role == "invoker": - return jsonify(message=role + " registered successfully", - id=obj.inserted_id, - ccf_onboarding_url="api-invoker-management/v1/onboardedInvokers", - ccf_discover_url="service-apis/v1/allServiceAPIs?api-invoker-id="), 201 - elif role == "exposer": - return jsonify(message=role + " registered successfully", - id=obj.inserted_id, - ccf_publish_url="published-apis/v1/{}/service-apis".format(obj.inserted_id)), 201 - - -@app.route("/gettoken", methods=["POST"]) -def gettoken(): - username = request.json["username"] - password = request.json["password"] - role = request.json["role"] - - test = user.find_one({"username": username, "password": password, "role": role}) - if test: - access_token = create_access_token(identity=(username + " " + role)) - return jsonify(message="Token returned successfully", access_token=access_token), 201 - else: - return jsonify(message="Bad credentials. User not found"), 401 - - -@app.route("/testdata", methods=["DELETE"]) -def testusers(): - splitter_string = '//' - message_returned = '' - - myquery = {"username": {"$regex": "^ROBOT_TESTING.*"}} - result = user.delete_many(myquery) - if result.deleted_count == 0: - message_returned += "No test users present" - else: - message_returned += "Deleted " + str(result.deleted_count) + " Test Users" - message_returned += splitter_string - - myquery = {"description": {"$regex": "^ROBOT_TESTING.*"}} - result = serviceapidescriptions.delete_many(myquery) - if result.deleted_count == 0: - message_returned += "No test services present" - else: - message_returned += "Deleted " + str(result.deleted_count) + " Test Services" - message_returned += splitter_string - - myquery = {"api_invoker_information": {"$regex": "^ROBOT_TESTING.*"}} - result = invokerdetails.delete_many(myquery) - if result.deleted_count == 0: - message_returned += "No test Invokers present" - else: - message_returned += "Deleted " + str(result.deleted_count) + " Test Invokers" - message_returned += splitter_string - - myquery = {"notification_destination": {"$regex": "^ROBOT_TESTING.*"}} - result = eventsdetails.delete_many(myquery) - if result.deleted_count == 0: - message_returned += "No event subscription present" - else: - message_returned += "Deleted " + str(result.deleted_count) + " Event Subscriptions" - message_returned += splitter_string - - myquery = {"notification_destination": {"$regex": "^ROBOT_TESTING.*"}} - result = servicesecurity.delete_many(myquery) - if result.deleted_count == 0: - message_returned += "No service security subscription present" - else: - message_returned += "Deleted " + str(result.deleted_count) + " service security Subscriptions" - message_returned += splitter_string - - myquery = {"api_prov_dom_info": {"$regex": "^ROBOT_TESTING.*"}} - result = providerenrolmentdetails.delete_many(myquery) - if result.deleted_count == 0: - message_returned += "No Provider Enrolment Details present" - else: - message_returned += "Deleted " + str(result.deleted_count) + " provider enrolment details" - message_returned += splitter_string - - return jsonify(message=message_returned), 200 - - -if __name__ == '__main__': - app.run(debug=True, host='0.0.0.0', port=8080) diff --git a/services/jwt_auth/config.yaml b/services/jwt_auth/config.yaml new file mode 100644 index 00000000..e7e5e54c --- /dev/null +++ b/services/jwt_auth/config.yaml @@ -0,0 +1,8 @@ +mongo: { + 'user': 'root', + 'password': 'example', + 'db': 'capif', + 'col': 'user', + 'host': 'mongo', + 'port': '27017' +} diff --git a/services/jwt_auth/register_service/__init__.py b/services/jwt_auth/register_service/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/services/jwt_auth/register_service/__main__.py b/services/jwt_auth/register_service/__main__.py new file mode 100644 index 00000000..bd4d3d1c --- /dev/null +++ b/services/jwt_auth/register_service/__main__.py @@ -0,0 +1,20 @@ + +import os +from flask import Flask +from .controllers.register_controller import register_routes +from flask_jwt_extended import JWTManager + +app = Flask(__name__) + +jwt = JWTManager(app) + +app.config["JWT_SECRET_KEY"] = "this-is-secret-key" +app.register_blueprint(register_routes) + + +#---------------------------------------- +# launch +#---------------------------------------- + +if __name__ == "__main__": + app.run(debug=True, host = '0.0.0.0', port=8080) diff --git a/services/jwt_auth/register_service/controllers/register_controller.py b/services/jwt_auth/register_service/controllers/register_controller.py new file mode 100644 index 00000000..26da7317 --- /dev/null +++ b/services/jwt_auth/register_service/controllers/register_controller.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python3 + +from flask import Flask, jsonify, request, Blueprint +from flask_jwt_extended import JWTManager, jwt_required, create_access_token +from pymongo import MongoClient +from ..core.register_operations import RegisterOperations +import secrets + + +register_routes = Blueprint("register_routes", __name__) +register_operation = RegisterOperations() + +@register_routes.route("/register", methods=["POST"]) +def register(): + username = request.json["username"] + password = request.json["password"] + description = request.json["description"] + role = request.json["role"] + cn = request.json["cn"] + if role != "invoker" and role != "exposer": + return jsonify(message="Role must be invoker or exposer"), 400 + + if role == "invoker": + return register_operation.register_invoker(username, password, description, cn, role) + + elif role == "exposer": + return register_operation.register_aef(username, password, description, cn, role) + +@register_routes.route("/getauth", methods=["POST"]) +def getauth(): + username = request.json["username"] + password = request.json["password"] + role = request.json["role"] + + return register_operation.get_auth(username, password, role) + +#Pending to remove +@register_routes.route("/testdata", methods=["DELETE"]) +def testusers(): + uri = "mongodb://" + "root" + ":" + "example" + "@" + "mongo" + ":" + str(27017) + + myclient = MongoClient(uri) + mydb = myclient["capif"] + user = mydb["user"] + invokerdetails = mydb['invokerdetails'] + serviceapidescriptions = mydb['serviceapidescriptions'] + eventsdetails = mydb['eventsdetails'] + servicesecurity = mydb['servicesecurity'] + providerenrolmentdetails = mydb['providerenrolmentdetails'] + + splitter_string = '//' + message_returned = '' + + myquery = {"username": {"$regex": "^ROBOT_TESTING.*"}} + result = user.delete_many(myquery) + if result.deleted_count == 0: + message_returned += "No test users present" + else: + message_returned += "Deleted " + str(result.deleted_count) + " Test Users" + message_returned += splitter_string + + myquery = {"description": {"$regex": "^ROBOT_TESTING.*"}} + result = serviceapidescriptions.delete_many(myquery) + if result.deleted_count == 0: + message_returned += "No test services present" + else: + message_returned += "Deleted " + str(result.deleted_count) + " Test Services" + message_returned += splitter_string + + myquery = {"api_invoker_information": {"$regex": "^ROBOT_TESTING.*"}} + result = invokerdetails.delete_many(myquery) + if result.deleted_count == 0: + message_returned += "No test Invokers present" + else: + message_returned += "Deleted " + str(result.deleted_count) + " Test Invokers" + message_returned += splitter_string + + myquery = {"notification_destination": {"$regex": "^ROBOT_TESTING.*"}} + result = eventsdetails.delete_many(myquery) + if result.deleted_count == 0: + message_returned += "No event subscription present" + else: + message_returned += "Deleted " + str(result.deleted_count) + " Event Subscriptions" + message_returned += splitter_string + + myquery = {"notification_destination": {"$regex": "^ROBOT_TESTING.*"}} + result = servicesecurity.delete_many(myquery) + if result.deleted_count == 0: + message_returned += "No service security subscription present" + else: + message_returned += "Deleted " + str(result.deleted_count) + " service security Subscriptions" + message_returned += splitter_string + + myquery = {"api_prov_dom_info": {"$regex": "^ROBOT_TESTING.*"}} + result = providerenrolmentdetails.delete_many(myquery) + if result.deleted_count == 0: + message_returned += "No Provider Enrolment Details present" + else: + message_returned += "Deleted " + str(result.deleted_count) + " provider enrolment details" + message_returned += splitter_string + + return jsonify(message=message_returned), 200 + diff --git a/services/jwt_auth/register_service/core/register_operations.py b/services/jwt_auth/register_service/core/register_operations.py new file mode 100644 index 00000000..38ce4dc7 --- /dev/null +++ b/services/jwt_auth/register_service/core/register_operations.py @@ -0,0 +1,117 @@ +from flask import Flask, jsonify, request +from flask_jwt_extended import create_access_token +from ..db.db import MongoDatabse +import secrets +import requests +import json + +from OpenSSL.SSL import FILETYPE_PEM +from OpenSSL.crypto import (dump_certificate_request, dump_privatekey, load_publickey, PKey, TYPE_RSA, X509Req, dump_publickey) + + + +class RegisterOperations: + + def __init__(self): + self.db = MongoDatabse() + self.mimetype = 'application/json' + + def register_invoker(self, username, password, description, cn, role): + + mycol = self.db.get_col_by_name(self.db.capif_users) + exist_user = mycol.find_one({"username": username}) + if exist_user: + return jsonify("Invoker already exists"), 409 + + user_info = dict(_id=secrets.token_hex(7), username=username, password=password, role=role, description=description, cn=cn) + obj = mycol.insert_one(user_info) + + return jsonify(message="invoker registered successfully", + id=obj.inserted_id, + ccf_onboarding_url="api-invoker-management/v1/onboardedInvokers", + ccf_discover_url="service-apis/v1/allServiceAPIs?api-invoker-id="), 201 + + + def register_aef(self, username, password, description, cn, role): + mycol = self.db.get_col_by_name(self.db.capif_users) + exist_user = mycol.find_one({"username": username}) + if exist_user: + return jsonify("Exposer already exists"), 409 + + user_info = dict(_id=secrets.token_hex(7), username=username, password=password, role=role, description=description, cn=cn) + obj = mycol.insert_one(user_info) + + return jsonify(message="exposer" + " registered successfully", + id=obj.inserted_id, + ccf_api_onboarding_url="api-provider-management/v1/registrations", + ccf_publish_url="published-apis/v1/{}/service-apis".format(obj.inserted_id)), 201 + + def get_auth(self, username, password, role): + + if role == "invoker": + mycol = self.db.get_col_by_name(self.db.capif_users) + exist_user = mycol.find_one({"username": username, "password": password, "role": role}) + if exist_user: + access_token = create_access_token(identity=(username + " " + role)) + url = "http://easy-rsa:8080/ca-root" + headers = { + + 'Content-Type': self.mimetype + } + response = requests.request("GET", url, headers=headers) + response_payload = json.loads(response.text) + return jsonify(message="Token and CA root returned successfully", access_token=access_token, ca_root=response_payload["certificate"]), 201 + else: + return jsonify(message="Bad credentials. User not found"), 401 + elif role == "exposer": + mycol = self.db.get_col_by_name(self.db.capif_users) + exist_user = mycol.find_one({"username": username, "password": password, "role": role}) + + if exist_user: + try: + csr_request, private_key = self.create_csr(cn=username) + publick_key = csr_request.decode("utf-8") + url = "http://easy-rsa:8080/sign-csr" + + payload = dict() + payload['csr'] = publick_key + payload['mode'] = 'client' + payload['filename'] = username + + headers = { + + 'Content-Type': self.mimetype + + } + + response = requests.request("POST", url, headers=headers, data=json.dumps(payload)) + response_payload = json.loads(response.text) + + return jsonify(message="Certificate created successfuly", cert=response_payload["certificate"], private_key=private_key.decode("utf-8")), 201 + + except Exception as e: + return jsonify(message="Error while create certificate: "+ str(e)), 500 + else: + return jsonify(message="Bad credentials. User not found"), 401 + + + def create_csr(self,cn): + + # create public/private key + key = PKey() + key.generate_key(TYPE_RSA, 2048) + + # Generate CSR + req = X509Req() + req.get_subject().CN = cn + req.get_subject().O = 'Telefonica I+D' + req.get_subject().C = 'ES' + req.set_pubkey(key) + req.sign(key, 'sha256') + + + csr_request = dump_certificate_request(FILETYPE_PEM, req) + + private_key = dump_privatekey(FILETYPE_PEM, key) + + return csr_request, private_key \ No newline at end of file diff --git a/services/jwt_auth/register_service/db/config.py b/services/jwt_auth/register_service/db/config.py new file mode 100644 index 00000000..afd64b06 --- /dev/null +++ b/services/jwt_auth/register_service/db/config.py @@ -0,0 +1,20 @@ +import yaml +import os + +#Config class to get config +class Config: + def __init__(self): + self.cached = 0 + self.file="./config.yaml" + self.my_config = {} + + stamp = os.stat(self.file).st_mtime + if stamp != self.cached: + self.cached = stamp + f = open(self.file) + self.my_config = yaml.safe_load(f) + f.close() + + def getConfig(self): + return self.my_config + diff --git a/services/jwt_auth/register_service/db/db.py b/services/jwt_auth/register_service/db/db.py new file mode 100644 index 00000000..ccbd0d0d --- /dev/null +++ b/services/jwt_auth/register_service/db/db.py @@ -0,0 +1,26 @@ +from pymongo import MongoClient +from .config import Config + + +class MongoDatabse(): + + def __init__(self): + self.config = Config().getConfig() + self.db = self.__connect() + self.capif_users = self.config['mongo']['col'] + + + def get_col_by_name(self, name): + return self.db[name] + + def __connect(self): + uri = "mongodb://" + self.config['mongo']['user'] + ":" + self.config['mongo']['password'] + "@" + self.config['mongo']['host'] + ":" + self.config['mongo']['port'] + client = MongoClient(uri) + + try: + client.admin.command("ping") + mydb = client[self.config['mongo']['db']] + return mydb + except Exception as e: + print("An exception occurred ::", e) + return None diff --git a/services/jwt_auth/requirements.txt b/services/jwt_auth/requirements.txt index 4e32f5d9..d83737c8 100644 --- a/services/jwt_auth/requirements.txt +++ b/services/jwt_auth/requirements.txt @@ -3,4 +3,6 @@ setuptools >= 21.0.0 Flask == 2.0.3 pymongo == 4.0.1 flask_jwt_extended +pyopenssl +pyyaml requests diff --git a/services/nginx/Dockerfile b/services/nginx/Dockerfile index 8cab0b6b..d2c6aa27 100644 --- a/services/nginx/Dockerfile +++ b/services/nginx/Dockerfile @@ -1,6 +1,7 @@ -FROM nginx:latest +FROM nginx:1.23.1 RUN apt-get update && apt-get install -y jq && apt-get clean RUN apt-get install -y openssl +RUN apt-get install -y curl=7.74.0-1.3+deb11u3 RUN mkdir -p /etc/nginx/certs diff --git a/services/nginx/nginx.conf b/services/nginx/nginx.conf index a2e79ac3..08da5d1d 100644 --- a/services/nginx/nginx.conf +++ b/services/nginx/nginx.conf @@ -26,12 +26,10 @@ http { location /testdata { proxy_pass http://jwtauth:8080/testdata; } - location /gettoken { - proxy_pass http://jwtauth:8080/gettoken; - } - location /api-provider-management { - proxy_pass http://api-provider-management:8080; + location /getauth { + proxy_pass http://jwtauth:8080/getauth; } + } server { @@ -84,6 +82,14 @@ http { proxy_set_header X-SSL-Client-Cert $ssl_client_cert; proxy_pass http://capif-events:8080; } + + location /api-provider-management { + if ($ssl_client_verify != SUCCESS) { + return 403; + } + proxy_set_header X-SSL-Client-Cert $ssl_client_cert; + proxy_pass http://api-provider-management:8080; + } } } diff --git a/services/nginx/nginx_prepare.sh b/services/nginx/nginx_prepare.sh index 7d218933..fa99aa60 100644 --- a/services/nginx/nginx_prepare.sh +++ b/services/nginx/nginx_prepare.sh @@ -1,9 +1,28 @@ -curl --request GET 'http://easy-rsa:8080/ca-root' 2>/dev/null | jq -r '.certificate' -j > /etc/nginx/certs/ca.crt +#!/bin/bash +EASY_RSA_HOSTNAME="easy-rsa" +EASY_RSA_PORT="8080" +CERTS_FOLDER="/etc/nginx/certs" +cd $CERTS_FOLDER -folder="/etc/nginx/certs" -cd $folder +curl --retry 30 \ + --retry-all-errors \ + --connect-timeout 5 \ + --max-time 10 \ + --retry-delay 10 \ + --retry-max-time 300 \ + --request GET "http://$EASY_RSA_HOSTNAME:$EASY_RSA_PORT/ca-root" 2>/dev/null | jq -r '.certificate' -j > $CERTS_FOLDER/ca.crt -openssl genrsa -out server.key 2048 +openssl verify -CAfile $CERTS_FOLDER/ca.crt $CERTS_FOLDER/ca.crt +rc=$? +if [ $rc -eq 0 ] +then + echo "CA root Certificate downloaded successfull" +else + echo "Failure: CA root certificate is not valid" + exit $rc +fi + +openssl genrsa -out $CERTS_FOLDER/server.key 2048 echo "NGINX Hostname is $CAPIF_HOSTNAME" @@ -22,7 +41,7 @@ COMPANY="" # company name # create the certificate request #cat <<__EOF__ | openssl req -new $DAYS -nodes -keyout client.key -out client.csr -cat <<__EOF__ | openssl req -new $DAYS -key server.key -out server.csr +cat <<__EOF__ | openssl req -new $DAYS -key $CERTS_FOLDER/server.key -out $CERTS_FOLDER/server.csr $COUNTRY $STATE $LOCALITY @@ -34,7 +53,13 @@ $CHALLENGE $COMPANY __EOF__ -awk -v cert="$(cat server.csr)" 'BEGIN{gsub(/\n/, "\\n", cert)} {sub(/"CERT"/, "\"" cert "\"")} 1' sign_req_body_tmp.json > sign_req_body.json -curl --location --request POST 'http://easy-rsa:8080/sign-csr' --header 'Content-Type: application/json' -d @./sign_req_body.json | jq -r '.certificate' -j > /etc/nginx/certs/server.crt +awk -v cert="$(cat $CERTS_FOLDER/server.csr)" 'BEGIN{gsub(/\n/, "\\n", cert)} {sub(/"CERT"/, "\"" cert "\"")} 1' $CERTS_FOLDER/sign_req_body_tmp.json > $CERTS_FOLDER/sign_req_body.json +curl --retry 30 \ + --retry-all-errors \ + --connect-timeout 5 \ + --max-time 10 \ + --retry-delay 10 \ + --retry-max-time 300 \ + --location --request POST "http://$EASY_RSA_HOSTNAME:$EASY_RSA_PORT/sign-csr" --header 'Content-Type: application/json' -d @./sign_req_body.json | jq -r '.certificate' -j > $CERTS_FOLDER/server.crt nginx \ No newline at end of file diff --git a/tests/features/CAPIF Api Provider Management/capif_api_provider_managenet.robot b/tests/features/CAPIF Api Provider Management/capif_api_provider_managenet.robot index da8ef4f0..7c8477ff 100644 --- a/tests/features/CAPIF Api Provider Management/capif_api_provider_managenet.robot +++ b/tests/features/CAPIF Api Provider Management/capif_api_provider_managenet.robot @@ -14,12 +14,16 @@ ${API_PROVIDER_NOT_REGISTERED} notValid *** Test Cases *** Register Api Provider [Tags] capif_api_provider_management-1 + ${register_user_info}= Publisher Default Registration + ${request_body}= Create Api Provider Enrolment Details Body ${resp}= Post Request Capif ... /api-provider-management/v1/registrations ... json=${request_body} - ... server=http://${CAPIF_HOSTNAME}:${CAPIF_HTTP_PORT}/ + ... server=https://${CAPIF_HOSTNAME}/ + ... verify=ca.crt + ... username=${PUBLISHER_USERNAME} Status Should Be 201 ${resp} @@ -30,12 +34,16 @@ Register Api Provider Register Api Provider Already registered [Tags] capif_api_provider_management-2 + ${register_user_info}= Publisher Default Registration + ${request_body}= Create Api Provider Enrolment Details Body ${resp}= Post Request Capif ... /api-provider-management/v1/registrations ... json=${request_body} - ... server=http://${CAPIF_HOSTNAME}:${CAPIF_HTTP_PORT}/ + ... server=https://${CAPIF_HOSTNAME}/ + ... verify=ca.crt + ... username=${PUBLISHER_USERNAME} Status Should Be 201 ${resp} @@ -47,18 +55,24 @@ Register Api Provider Already registered ${resp}= Post Request Capif ... /api-provider-management/v1/registrations ... json=${request_body} - ... server=http://${CAPIF_HOSTNAME}:${CAPIF_HTTP_PORT}/ + ... server=https://${CAPIF_HOSTNAME}/ + ... verify=ca.crt + ... username=${PUBLISHER_USERNAME} Status Should Be 403 ${resp} Update Registered Api Provider [Tags] capif_api_provider_management-3 + ${register_user_info}= Publisher Default Registration + ${request_body}= Create Api Provider Enrolment Details Body ${resp}= Post Request Capif ... /api-provider-management/v1/registrations ... json=${request_body} - ... server=http://${CAPIF_HOSTNAME}:${CAPIF_HTTP_PORT}/ + ... server=https://${CAPIF_HOSTNAME}/ + ... verify=ca.crt + ... username=${PUBLISHER_USERNAME} Status Should Be 201 ${resp} @@ -72,29 +86,39 @@ Update Registered Api Provider ${resp}= Put Request Capif ... ${location_url.path} ... json=${request_body} - ... server=http://${CAPIF_HOSTNAME}:${CAPIF_HTTP_PORT}/ + ... server=https://${CAPIF_HOSTNAME}/ + ... verify=ca.crt + ... username=${PUBLISHER_USERNAME} Status Should Be 200 ${resp} Update Not Registered Api Provider [Tags] capif_api_provider_management-4 + ${register_user_info}= Publisher Default Registration + ${request_body}= Create Api Provider Enrolment Details Body ${resp}= Put Request Capif ... /api-provider-management/v1/registrations/${API_PROVIDER_NOT_REGISTERED} ... json=${request_body} - ... server=http://${CAPIF_HOSTNAME}:${CAPIF_HTTP_PORT}/ + ... server=https://${CAPIF_HOSTNAME}/ + ... verify=ca.crt + ... username=${PUBLISHER_USERNAME} Status Should Be 404 ${resp} Partially Update Registered Api Provider [Tags] capif_api_provider_management-5 + ${register_user_info}= Publisher Default Registration + ${request_body}= Create Api Provider Enrolment Details Body ${resp}= Post Request Capif ... /api-provider-management/v1/registrations ... json=${request_body} - ... server=http://${CAPIF_HOSTNAME}:${CAPIF_HTTP_PORT}/ + ... server=https://${CAPIF_HOSTNAME}/ + ... verify=ca.crt + ... username=${PUBLISHER_USERNAME} Status Should Be 201 ${resp} # Store dummy signede certificate @@ -108,29 +132,39 @@ Partially Update Registered Api Provider ${resp}= Patch Request Capif ... ${location_url.path} ... json=${request_body} - ... server=http://${CAPIF_HOSTNAME}:${CAPIF_HTTP_PORT}/ + ... server=https://${CAPIF_HOSTNAME}/ + ... verify=ca.crt + ... username=${PUBLISHER_USERNAME} Status Should Be 200 ${resp} Partially Update Not Registered Api Provider [Tags] capif_api_provider_management-6 + ${register_user_info}= Publisher Default Registration + ${request_body}= Create Api Provider Enrolment Details Patch Body ${resp}= Patch Request Capif ... /api-provider-management/v1/registrations/${API_PROVIDER_NOT_REGISTERED} ... json=${request_body} - ... server=http://${CAPIF_HOSTNAME}:${CAPIF_HTTP_PORT}/ + ... server=https://${CAPIF_HOSTNAME}/ + ... verify=ca.crt + ... username=${PUBLISHER_USERNAME} Status Should Be 404 ${resp} Delete Registered Api Provider [Tags] capif_api_provider_management-7 + ${register_user_info}= Publisher Default Registration + ${request_body}= Create Api Provider Enrolment Details Body ${resp}= Post Request Capif ... /api-provider-management/v1/registrations ... json=${request_body} - ... server=http://${CAPIF_HOSTNAME}:${CAPIF_HTTP_PORT}/ + ... server=https://${CAPIF_HOSTNAME}/ + ... verify=ca.crt + ... username=${PUBLISHER_USERNAME} Status Should Be 201 ${resp} @@ -138,15 +172,20 @@ Delete Registered Api Provider ${resp}= Delete Request Capif ... ${location_url.path} - ... server=http://${CAPIF_HOSTNAME}:${CAPIF_HTTP_PORT}/ + ... server=https://${CAPIF_HOSTNAME}/ + ... verify=ca.crt + ... username=${PUBLISHER_USERNAME} Status Should Be 204 ${resp} Delete Not Registered Api Provider [Tags] capif_api_provider_management-8 + ${register_user_info}= Publisher Default Registration ${resp}= Delete Request Capif ... /api-provider-management/v1/registrations/${API_PROVIDER_NOT_REGISTERED} - ... server=http://${CAPIF_HOSTNAME}:${CAPIF_HTTP_PORT}/ + ... server=https://${CAPIF_HOSTNAME}/ + ... verify=ca.crt + ... username=${PUBLISHER_USERNAME} Status Should Be 404 ${resp} diff --git a/tests/features/CAPIF Api Publish Service/capif_api_publish_service.robot b/tests/features/CAPIF Api Publish Service/capif_api_publish_service.robot index 3d0f6d7b..ef10733c 100644 --- a/tests/features/CAPIF Api Publish Service/capif_api_publish_service.robot +++ b/tests/features/CAPIF Api Publish Service/capif_api_publish_service.robot @@ -18,19 +18,6 @@ Publish API by Authorised API Publisher ${register_user_info}= Register User At Jwt Auth ... username=${PUBLISHER_USERNAME} role=${PUBLISHER_ROLE} - # Sign certificate - ${request_body}= Sign Csr Body ${PUBLISHER_USERNAME} ${register_user_info['csr_request']} - ${resp}= Post Request Capif - ... sign-csr - ... json=${request_body} - ... server=${CAPIF_HTTP_URL} - ... verify=ca.crt - # ... access_token=${register_user_info['access_token']} - Status Should Be 201 ${resp} - - # Store dummy signede certificate - Store In File ${PUBLISHER_USERNAME}.crt ${resp.json()['certificate']} - # Test ${request_body}= Create Service Api Description ${resp}= Post Request Capif diff --git a/tests/resources/common/basicRequests.robot b/tests/resources/common/basicRequests.robot index 84965854..98083b69 100644 --- a/tests/resources/common/basicRequests.robot +++ b/tests/resources/common/basicRequests.robot @@ -3,10 +3,10 @@ Documentation This resource file contains the basic requests used by Capif Library RequestsLibrary Library Collections +Library OperatingSystem *** Variables *** -# ${NGINX_HOSTNAME} http://localhost:8080 ${CAPIF_AUTH} ${CAPIF_BEARER} @@ -15,12 +15,10 @@ ${CAPIF_BEARER} Create CAPIF Session [Documentation] Create needed session and headers. ... If server input data is set to NONE, it will try to use NGINX_HOSTNAME variable. - [Arguments] ${server}=${NONE} ${access_token}=${NONE} ${verify}=${NONE} + [Arguments] ${server}=${NONE} ${access_token}=${NONE} ${verify}=${NONE} IF "${server}" != "${NONE}" Create Session apisession ${server} verify=${verify} - # ELSE - # Create Session apisession ${NGINX_HOSTNAME} verify=True END ${headers}= Create Dictionary @@ -34,7 +32,7 @@ Post Request Capif [Timeout] 60s [Arguments] ${endpoint} ${json}=${NONE} ${server}=${NONE} ${access_token}=${NONE} ${auth}=${NONE} ${verify}=${FALSE} ${cert}=${NONE} ${username}=${NONE} ${data}=${NONE} - ${headers}= Create CAPIF Session ${server} ${access_token} ${verify} + ${headers}= Create CAPIF Session ${server} ${access_token} ${verify} IF '${username}' != '${NONE}' ${cert}= Set variable ${{ ('${username}.crt','${username}.key') }} @@ -138,7 +136,11 @@ Register User At Jwt Auth [Arguments] ${username} ${role} ${password}=password ${description}=Testing # Create certificate and private_key for this machine. - ${csr_request}= Create Csr ${username}.csr ${username}.key ${username} + IF "${role}" == "${INVOKER_ROLE}" + ${csr_request}= Create Csr ${username}.csr ${username}.key ${username} + ELSE + ${csr_request}= Set Variable ${None} + END &{body}= Create Dictionary ... password=${password} @@ -153,38 +155,44 @@ Register User At Jwt Auth Should Be Equal As Strings ${resp.status_code} 201 - ${access_token}= Get Token For User ${username} ${password} ${role} + ${get_auth_response}= Get Auth For User ${username} ${password} ${role} ${register_user_info}= Create Dictionary - ... access_token=${access_token} ... netappID=${resp.json()['id']} ... csr_request=${csr_request} ... &{resp.json()} + ... &{get_auth_response} Log Dictionary ${register_user_info} + IF "cert" in @{register_user_info.keys()} + Store In File ${username}.crt ${register_user_info['cert']} + END + IF "private_key" in @{register_user_info.keys()} + Store In File ${username}.key ${register_user_info['private_key']} + END + RETURN ${register_user_info} -Get Token For User +Get Auth For User [Arguments] ${username} ${password} ${role} &{body}= Create Dictionary username=${username} password=${password} role=${role} - ${resp}= POST On Session jwtsession /gettoken json=${body} + ${resp}= POST On Session jwtsession /getauth json=${body} Should Be Equal As Strings ${resp.status_code} 201 - RETURN ${resp.json()["access_token"]} + # Should Be Equal As Strings ${resp.json()['message']} Certificate created successfuly + + RETURN ${resp.json()} Clean Test Information By HTTP Requests - Create Session jwtsession ${CAPIF_HTTP_URL} verify=True + Create Session jwtsession ${CAPIF_HTTP_URL} verify=True ${resp}= DELETE On Session jwtsession /testdata Should Be Equal As Strings ${resp.status_code} 200 - ${resp}= DELETE On Session jwtsession /certdata - Should Be Equal As Strings ${resp.status_code} 200 - Invoker Default Onboarding ${register_user_info}= Register User At Jwt Auth ... username=${INVOKER_USERNAME} role=${INVOKER_ROLE} @@ -217,17 +225,4 @@ Publisher Default Registration ${register_user_info}= Register User At Jwt Auth ... username=${PUBLISHER_USERNAME} role=${PUBLISHER_ROLE} - # Sign certificate - ${request_body}= Sign Csr Body ${PUBLISHER_USERNAME} ${register_user_info['csr_request']} - ${resp}= Post Request Capif - ... sign-csr - ... json=${request_body} - ... server=${CAPIF_HTTP_URL} - ... verify=ca.crt - # ... access_token=${register_user_info['access_token']} - Status Should Be 201 ${resp} - - # Store dummy signede certificate - Store In File ${PUBLISHER_USERNAME}.crt ${resp.json()['certificate']} - RETURN ${register_user_info}