feat: push OIDC config to provisioned server for SSO login
After provisioning a server, pushes Logto Traditional Web App credentials (client ID + secret) via the server's OIDC admin API. This enables SSO: users authenticated via Logto can access the server dashboard without a separate login. Reads tradAppSecret from bootstrap JSON via LogtoConfig. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -29,12 +29,13 @@ public class LogtoConfig {
|
||||
private String serverEndpoint;
|
||||
|
||||
private String tradAppId;
|
||||
private String tradAppSecret;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
if (isConfigured()) return;
|
||||
|
||||
// Fall back to bootstrap file for M2M credentials + trad app ID
|
||||
// Fall back to bootstrap file for M2M credentials + trad app
|
||||
try {
|
||||
File file = new File(BOOTSTRAP_FILE);
|
||||
if (file.exists()) {
|
||||
@@ -48,6 +49,9 @@ public class LogtoConfig {
|
||||
if (node.has("tradAppId")) {
|
||||
tradAppId = node.get("tradAppId").asText();
|
||||
}
|
||||
if (node.has("tradAppSecret")) {
|
||||
tradAppSecret = node.get("tradAppSecret").asText();
|
||||
}
|
||||
log.info("Loaded M2M credentials from bootstrap file");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
@@ -60,6 +64,7 @@ public class LogtoConfig {
|
||||
public String getM2mClientSecret() { return m2mClientSecret; }
|
||||
public String getServerEndpoint() { return serverEndpoint; }
|
||||
public String getTradAppId() { return tradAppId; }
|
||||
public String getTradAppSecret() { return tradAppSecret; }
|
||||
|
||||
public boolean isConfigured() {
|
||||
return logtoEndpoint != null && !logtoEndpoint.isEmpty()
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
@@ -127,6 +128,28 @@ public class VendorTenantService {
|
||||
} catch (Exception e) {
|
||||
log.warn("License push failed for tenant {}: {}", tenant.getSlug(), e.getMessage());
|
||||
}
|
||||
|
||||
// Configure OIDC on the provisioned server (SSO via Logto)
|
||||
if (logtoConfig.getTradAppId() != null && logtoConfig.getTradAppSecret() != null) {
|
||||
try {
|
||||
String publicBase = provisioningProps.publicProtocol() + "://" + provisioningProps.publicHost();
|
||||
serverApiClient.pushOidcConfig(result.serverEndpoint(), Map.of(
|
||||
"enabled", true,
|
||||
"issuerUri", publicBase + "/oidc",
|
||||
"clientId", logtoConfig.getTradAppId(),
|
||||
"clientSecret", logtoConfig.getTradAppSecret(),
|
||||
"autoSignup", true,
|
||||
"defaultRoles", List.of("VIEWER"),
|
||||
"displayNameClaim", "name",
|
||||
"rolesClaim", "roles",
|
||||
"audience", "https://api.cameleer.local",
|
||||
"additionalScopes", List.of()
|
||||
));
|
||||
log.info("Pushed OIDC config to server for tenant {}", tenant.getSlug());
|
||||
} catch (Exception e) {
|
||||
log.warn("OIDC config push failed for tenant {}: {}", tenant.getSlug(), e.getMessage());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tenant.setProvisionError(result.error());
|
||||
tenant.setStatus(TenantStatus.PROVISIONING);
|
||||
|
||||
Reference in New Issue
Block a user