Commit 5133b13d authored by Alex Kakiris's avatar Alex Kakiris
Browse files

onboard invoker

parent 7c3ba7d9
Loading
Loading
Loading
Loading
+1 −1
Changes for README.md: 1 added line, 1 removed line.
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@ Notes:
- If you use the default local OpenCAPIF deployment, no value changes are usually needed.
- If any of those service names are changed in your OpenCAPIF deployment, you must update docker-compose.yml accordingly (for example CAPIF_HOSTNAME, REGISTER_HOSTNAME, VAULT_HOSTNAME, and extra_hosts). This will be improved in future versions.
- CCF_ONBOARDING_URL, CCF_API_ONBOARDING_URL, CCF_PUBLISH_URL, CCF_DISCOVER_URL, and CCF_SECURITY_URL are static per deployment and must match the ccf_* paths returned by CAPIF's /getauth response; a mismatch is logged as a WARNING on login.
- The certificate subject fields can be overridden via `CERT_ORGANIZATION` (default `Telefonica I+D`), `CERT_ORGANIZATIONAL_UNIT` (`Innovation`), `CERT_LOCALITY` (`Madrid`), `CERT_STATE` (`Madrid`), `CERT_COUNTRY` (`ES`, must be a 2-letter code) and `CERT_EMAIL` (`inno@tid.es`). These have defaults, so unlike the `CCF_*` vars they don't need to be set in `docker-compose.yml`.
- The CSR subject fields can be set via `CERT_ORGANIZATION` (default `Telefonica I+D`), `CERT_ORGANIZATIONAL_UNIT` (`Innovation`), `CERT_LOCALITY` (`Madrid`), `CERT_STATE` (`Madrid`), `CERT_COUNTRY` (`ES`, must be a 2-letter code) and `CERT_EMAIL` (`inno@tid.es`). They have defaults, so they don't need to be set in `docker-compose.yml`.

Example /etc/hosts entries for a default local setup:

+20 −3
Changes for capif_backend/backoffice_service/controllers/me_controller.py: 20 added lines, 3 removed lines.
Original line number Diff line number Diff line
from flask import Blueprint, jsonify
from flask import Blueprint, jsonify, request
from flask_jwt_extended import jwt_required

from ..core.operations import Operations
from ..utils.utils import get_capif_token, get_capif_urls

me_routes = Blueprint("me_routes", __name__)

operations = Operations()   # create operations object -> operations.py

@me_routes.route("/invoker", methods=["POST"])
@jwt_required()
@@ -13,5 +14,21 @@ def onboard_invoker():
    if not capif_token:
        return jsonify({"error": "This account has no CAPIF credentials."}), 403

    payload = request.get_json(silent=True) or {}
    invoker_info = payload.get("apiInvokerInformation")
    notification_destination = payload.get("notificationDestination")
    if not invoker_info or not notification_destination:
        return jsonify({"error": "apiInvokerInformation and notificationDestination are required."}), 400

    ccf_onboarding_url = get_capif_urls()["ccf_onboarding_url"]
    return jsonify({"invoker_onboarding_url": ccf_onboarding_url}), 200
 No newline at end of file
    data, status = operations.onboard_invoker(
        capif_token, ccf_onboarding_url, invoker_info, notification_destination
    )

    if status != 201:
        return jsonify({"error": "CCF onboarding failed.", "ccf_status": status, "ccf_response": data}), 502

    return jsonify({
        "apiInvokerId": data["apiInvokerId"],
        "apiInvokerCertificate": data["onboardingInformation"]["apiInvokerCertificate"],
    }), 201
 No newline at end of file
+32 −2
Changes for capif_backend/backoffice_service/core/operations.py: 32 added lines, 2 removed lines.
Original line number Diff line number Diff line
from flask import jsonify, make_response
import requests
# from ..configs.config import Config
from ..config import Config
import os
import json
import copy
@@ -10,6 +8,10 @@ import sys
from requests.auth import HTTPBasicAuth
from urllib.parse import urlencode

# from ..configs.config import Config
from ..config import Config
from ..utils.certs import generate_keypair_and_csr


class Operations:

@@ -487,9 +489,37 @@ class Operations:
            print(f"Error: {str(e)}")  # Log de error
            return {"error": str(e)}

    def onboard_invoker(self, capif_token, onboarding_url, invoker_info, notification_destination):
        """Onboard an API invoker in CCF on behalf of the logged-in user."""
        csr_request, _private_key = generate_keypair_and_csr()
        body = {
            "apiInvokerInformation": invoker_info,
            "notificationDestination": notification_destination,
            "requestTestNotification": False,
            "onboardingInformation": {"apiInvokerPublicKey": csr_request.decode("utf-8")},
            "supportedFeatures": "fffffff",
            "websockNotifConfig": {"requestWebsocketUri": True, "websocketUri": "websocketUri"},
        }

        url = "https://{}/{}".format(os.getenv('CAPIF_HOSTNAME'), onboarding_url)

        try:
            response = requests.post(
                url,
                json=body,
                headers={"Authorization": f"Bearer {capif_token}"},
                verify="newcerts/ca_root.crt",
                timeout=30,
            )
        except requests.exceptions.RequestException as e:
            return {"error": f"Could not reach CCF: {e}"}, 502

        try:
            data = response.json()
        except ValueError:
            data = {"error": response.text}

        return data, response.status_code


    def get_invokers_of_a_user(self, uuid):