Persist user CAPIF session from /getauth

Keeps the CAPIF access_token returned by register's /getauth in the backoffice JWT, so onboarding can authenticate as the user. Static ccf_* endpoint paths move to env config, with a warning logged on login if they drift from what CAPIF returns.

Merge request reports

Loading
+12 −5
Changes for capif_backend/backoffice_service/controllers/login.py: 12 added lines, 5 removed lines.
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ from flask_cors import cross_origin
from datetime import timedelta

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

# create blueprint backoffice_routes
access_routes = Blueprint("access_routes", __name__)
@@ -22,14 +23,19 @@ def login():
    print("username: ", username)

    role = "admin"
    capif_token = None
    # Check if the username and password are correct
    # TODO: Implement proper authentication mechanism (e.g., check against a database)
    if username != "superadmin" or password != "admin":
        _, status_code = operations.user_login(username, password)
        capif_auth, status_code = operations.user_login(username, password)
        if status_code != 200:
            print("Bad username or password")
            return jsonify({"msg": "Bad username or password"}), 401
        role = "user"
        capif_token = capif_auth.get("access_token")
        for key, configured in get_capif_urls().items():
            if configured != capif_auth.get(key):
                print(f"WARNING: {key} from /getauth ({capif_auth.get(key)}) differs from config ({configured})")

    # Configure token expiration to 24 hours
    # expires = timedelta(hours=8)
@@ -42,9 +48,9 @@ def login():

    # identity is a data that can be serialized in json -> username = superadmin
    access_token = create_access_token(identity=username, expires_delta=expires,
                                       additional_claims={"role": role})
                                    additional_claims={"role": role, "capif_token": capif_token})  # Include role and capif_token in the access token claims
    refresh_token = create_refresh_token(identity=username, expires_delta=expires_refresh,
                                         additional_claims={"role": role})
                                        additional_claims={"role": role, "capif_token": capif_token})  # Include role and capif_token in the refresh token claims

    return jsonify(access_token=access_token, refresh_token=refresh_token, role=role)

@@ -56,12 +62,13 @@ def refresh():
        return jsonify(message="CORS options OK"), 200

    current_user = get_jwt_identity()
    role = get_jwt().get("role", "user") # Get the role from the refresh token claims
    role = get_jwt().get("role", "user")
    capif_token = get_jwt().get("capif_token")

    # Configure new access token expiration to 8 hours
    expires = timedelta(hours=8)
    new_access_token = create_access_token(identity=current_user, expires_delta=expires,
                                           additional_claims={"role": role}) # New access token with the same role as the refresh token
                                           additional_claims={"role": role, "capif_token": capif_token})

    return jsonify(access_token=new_access_token, user=current_user, role=role)

+3 −5
Changes for capif_backend/backoffice_service/core/operations.py: 3 added lines, 5 removed lines.
Original line number Diff line number Diff line
@@ -202,13 +202,11 @@ class Operations:
                verify=False
            )
            if response.status_code == 200:
                json_response = response.json()
                access_token = json_response.get("access_token")
                return jsonify({"access_token": access_token}), 200
                return response.json(), 200
            else:
                return jsonify({"error": "Invalid credentials"}), 401
                return {"error": "Invalid credentials"}, 401
        except requests.exceptions.RequestException as e:
            return jsonify({"error": f"Error during user login: {str(e)}"}), 500
            return {"error": f"Error during user login: {str(e)}"}, 500

    def create_user(self, user_data):
        def login3():
+16 −0
Changes for capif_backend/backoffice_service/utils/utils.py: 16 added lines, 0 removed lines.
Original line number Diff line number Diff line
import re
import os
from flask import request, jsonify
from flask_jwt_extended import verify_jwt_in_request, get_jwt

@@ -34,3 +35,18 @@ def admin_only():

    return None

def get_capif_token():
    """Return the CAPIF register token from the current JWT, or None for superadmin."""
    return get_jwt().get("capif_token")

def get_capif_urls():
    """CCF endpoints URLs. Static per deployment, so they are stored in environment variables."""
    return {
        "ccf_onboarding_url": os.getenv("CCF_ONBOARDING_URL"),
        "ccf_api_onboarding_url": os.getenv("CCF_API_ONBOARDING_URL"),
        "ccf_publish_url": os.getenv("CCF_PUBLISH_URL"),
        "ccf_discover_url": os.getenv("CCF_DISCOVER_URL"),
        "ccf_security_url": os.getenv("CCF_SECURITY_URL"),   
    }

+1 −0
Changes for README.md: 1 added line, 0 removed lines.
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@ Notes:
- Even when deploying OpenCAPIF, you should ensure local name resolution for capifcore, register, and vault in /etc/hosts based on your OpenCAPIF deployment configuration. This is required both to reach the services and to avoid certificate validation issues.
- 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.

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

+6 −0
Changes for docker-compose.yml: 6 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -16,6 +16,12 @@ services:
      - vault:host-gateway
    environment:
      - CAPIF_HOSTNAME=capifcore
      - PYTHONUNBUFFERED=1
      - CCF_ONBOARDING_URL=api-invoker-management/v1/onboardedInvokers
      - CCF_API_ONBOARDING_URL=api-provider-management/v1/registrations
      - CCF_PUBLISH_URL=published-apis/v1/<apfId>/service-apis
      - CCF_DISCOVER_URL=service-apis/v1/allServiceAPIs?api-invoker-id=
      - CCF_SECURITY_URL=capif-security/v1/trustedInvokers/<apiInvokerId>
      # - VAULT_HOSTNAME=vault.ocf-vault.svc.cluster.local # direccion VAULT despliegue
      - VAULT_HOSTNAME=host.docker.internal # direccion VAULT local
      - REGISTER_HOSTNAME=register:8084
Loading