From 51c73d64a45698aa1469f2015d1c52d216e1dc7c Mon Sep 17 00:00:00 2001 From: hsiegeln <37154749+hsiegeln@users.noreply.github.com> Date: Sun, 5 Apr 2026 10:23:02 +0200 Subject: [PATCH] fix: read M2M credentials from bootstrap JSON when env vars empty The bootstrap dynamically creates the M2M app and writes credentials to the JSON file. LogtoConfig now falls back to the bootstrap file when LOGTO_M2M_CLIENT_ID/SECRET env vars are not set. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../cameleer/saas/identity/LogtoConfig.java | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/siegeln/cameleer/saas/identity/LogtoConfig.java b/src/main/java/net/siegeln/cameleer/saas/identity/LogtoConfig.java index 095683d..f323422 100644 --- a/src/main/java/net/siegeln/cameleer/saas/identity/LogtoConfig.java +++ b/src/main/java/net/siegeln/cameleer/saas/identity/LogtoConfig.java @@ -1,11 +1,21 @@ package net.siegeln.cameleer.saas.identity; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.annotation.PostConstruct; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; +import java.io.File; + @Configuration public class LogtoConfig { + private static final Logger log = LoggerFactory.getLogger(LogtoConfig.class); + private static final String BOOTSTRAP_FILE = "/data/bootstrap/logto-bootstrap.json"; + @Value("${cameleer.identity.logto-endpoint:}") private String logtoEndpoint; @@ -15,11 +25,35 @@ public class LogtoConfig { @Value("${cameleer.identity.m2m-client-secret:}") private String m2mClientSecret; + @PostConstruct + public void init() { + if (isConfigured()) return; + + // Fall back to bootstrap file for M2M credentials + try { + File file = new File(BOOTSTRAP_FILE); + if (file.exists()) { + JsonNode node = new ObjectMapper().readTree(file); + if ((m2mClientId == null || m2mClientId.isEmpty()) && node.has("m2mClientId")) { + m2mClientId = node.get("m2mClientId").asText(); + } + if ((m2mClientSecret == null || m2mClientSecret.isEmpty()) && node.has("m2mClientSecret")) { + m2mClientSecret = node.get("m2mClientSecret").asText(); + } + log.info("Loaded M2M credentials from bootstrap file"); + } + } catch (Exception e) { + log.warn("Failed to read bootstrap config for M2M credentials: {}", e.getMessage()); + } + } + public String getLogtoEndpoint() { return logtoEndpoint; } public String getM2mClientId() { return m2mClientId; } public String getM2mClientSecret() { return m2mClientSecret; } public boolean isConfigured() { - return !logtoEndpoint.isEmpty() && !m2mClientId.isEmpty() && !m2mClientSecret.isEmpty(); + return logtoEndpoint != null && !logtoEndpoint.isEmpty() + && m2mClientId != null && !m2mClientId.isEmpty() + && m2mClientSecret != null && !m2mClientSecret.isEmpty(); } }