Ocf145 review check cert on discover events and provider services

Proposers

  • Pelayo Torres (TID)

Description

Cert verification isn't used in some operations of the Discover, Events, and Provider Management services. Check why and determine whether or not it needs to be added.

Demo or definition of done

Certification.validation is a useful process that needs to be present on all APIs to perform authorization and control access functionalities.

The CAPIF APIs that did not have cert_validation on all their functions were:

  • Provider Management
  • Discover
  • Events
  • Logging
  • Audit

The Provider Management API did not need any change as the only API without certification validation was the onboarding of a Provider (POST method) which is using access token for authorization (and the functionality is already implemented)

For the Discover, Logging and Audit APIs the certification validation process was implemented from scratch, based on the implementation of other APIs. 

Only on Audit API, the validation only checks if the not using the API has AMF rights (because no AMF id is included on the request)

On the Events API, certification validation process was not enabled on all APIs. It was added. 

Also, the robots tests needed some fixes, as there were some misalignments on the certifications imported and the API arguments concerning 

Acknowledgements

This work is funded by the European Commission through the project with Grant Agreement number . example HORIZON-JU-SNS-2022 FLEX-SCALE project with Grant Agreement number 101096909.

Merge request reports

Loading
+32 −0
Changes for services/TS29222_CAPIF_Auditing_API/logs/controllers/default_controller.py: 32 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -3,13 +3,45 @@ from logs import util
from logs.models.interface_description import InterfaceDescription  # noqa: E501
from logs.models.operation import Operation  # noqa: E501
from logs.models.protocol import Protocol  # noqa: E501
from functools import wraps
from cryptography import x509
from cryptography.hazmat.backends import default_backend

from ..core.auditoperations import AuditOperations
from ..core.responses import bad_request_error
from ..core.validate_user import ControlAccess

audit_operations = AuditOperations()
valid_user = ControlAccess()


def cert_validation():
    def _cert_validation(f):
        @wraps(f)
        def __cert_validation(*args, **kwargs):

            args = request.view_args
            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()

            if cn != "superadmin":
                cert_signature = cert.signature.hex()
                result = valid_user.validate_user_cert(cert_signature)

                if result is not None:
                    return result

            result = f(**kwargs)
            return result
        return __cert_validation
    return _cert_validation


@cert_validation()
def api_invocation_logs_get(aef_id=None, api_invoker_id=None, time_range_start=None, time_range_end=None, api_id=None, api_name=None, api_version=None, protocol=None, operation=None, result=None, resource_name=None, src_interface=None, dest_interface=None, supported_features=None):  # noqa: E501
    """api_invocation_logs_get

+31 −0
Changes for services/TS29222_CAPIF_Auditing_API/logs/core/validate_user.py: 31 added lines, 0 removed lines.
Original line number Diff line number Diff line
import json

from flask import Response, current_app

from ..encoder import CustomJSONEncoder
from ..models.problem_details import ProblemDetails
from ..util import serialize_clean_camel_case
from .resources import Resource
from .responses import internal_server_error


class ControlAccess(Resource):

    def validate_user_cert(self, cert_signature):

        cert_col = self.db.get_col_by_name(self.db.certs_col)

        try:
            my_query = {'cert_signature': cert_signature}
            cert_entry = cert_col.find_one(my_query)

            if cert_entry is not None:
                if cert_entry["role"] != "AMF":
                    prob = ProblemDetails(title="Unauthorized", detail="User not authorized", cause="You are not the owner of this resource")
                    prob = serialize_clean_camel_case(prob)
                    return Response(json.dumps(prob, cls=CustomJSONEncoder), status=401, mimetype="application/json")

        except Exception as e:
            exception = "An exception occurred in validate invoker"
            current_app.logger.error(exception + "::" + str(e))
            return internal_server_error(detail=exception, cause=str(e))
 No newline at end of file
+1 −0
Changes for services/TS29222_CAPIF_Auditing_API/logs/db/db.py: 1 added line, 0 removed lines.
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ class MongoDatabse():
        self.db = self.__connect()
        self.invocation_logs = self.config['mongo']['logs_col']
        self.capif_users = self.config['mongo']['capif_users_col']
        self.certs_col = self.config['mongo']['certs_col']

    def get_col_by_name(self, name):
        return self.db[name]
+1 −0
Changes for services/TS29222_CAPIF_Auditing_API/config.yaml: 1 added line, 0 removed lines.
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@ mongo: {
  'db': 'capif',
  'logs_col': 'invocationlogs',
  'capif_users_col': "user",
  'certs_col': "certs",
  'host': 'mongo',
  'port': "27017"
}
+32 −1
Changes for services/TS29222_CAPIF_Discover_Service_API/service_apis/controllers/default_controller.py: 32 added lines, 1 removed line.
Original line number Diff line number Diff line
import json

from functools import wraps
from cryptography import x509
from cryptography.hazmat.backends import default_backend
from flask import current_app, request
from service_apis.models.discovered_apis import DiscoveredAPIs  # noqa: E501

from ..core.discoveredapis import DiscoverApisOperations, return_negotiated_supp_feat_dict
from ..core.validate_user import ControlAccess

discover_apis = DiscoverApisOperations()
valid_user = ControlAccess()

def cert_validation():
    def _cert_validation(f):
        @wraps(f)
        def __cert_validation(*args, **kwargs):

            args = request.view_args
            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()

            if cn != "superadmin":
                cert_signature = cert.signature.hex()
                current_app.logger.debug(request.args)
                result = valid_user.validate_user_cert(request.args["api-invoker-id"], cert_signature)

                if result is not None:
                    return result

            result = f(**kwargs)
            return result
        return __cert_validation
    return _cert_validation


@cert_validation()
def all_service_apis_get(api_invoker_id, api_name=None, api_version=None, comm_type=None, protocol=None, aef_id=None, data_format=None, api_cat=None, preferred_aef_loc=None, req_api_prov_name=None, supported_features=None, api_supported_features=None, ue_ip_addr=None, service_kpis=None, grant_types=None):  # noqa: E501
    """all_service_apis_get

Loading
Loading