From b393d262cb92d511f1452831ec635faba9f34d7a Mon Sep 17 00:00:00 2001 From: hsiegeln <37154749+hsiegeln@users.noreply.github.com> Date: Tue, 17 Mar 2026 13:20:35 +0100 Subject: [PATCH] refactor: remove OIDC env var config and seeder OIDC configuration is already fully database-backed (oidc_config table, admin API, OidcConfigRepository). Remove the redundant env var binding (SecurityProperties.Oidc), the env-to-DB seeder (oidcConfigSeeder), and the OIDC section from application.yml. Co-Authored-By: Claude Opus 4.6 (1M context) --- CLAUDE.md | 11 ++--- .../app/security/SecurityBeanConfig.java | 41 ------------------- .../app/security/SecurityProperties.java | 27 ------------ .../src/main/resources/application.yml | 8 +--- 4 files changed, 7 insertions(+), 80 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index e3a8fddd..fc67c3f0 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -40,18 +40,19 @@ java -jar cameleer3-server-app/target/cameleer3-server-app-1.0-SNAPSHOT.jar - Maintains agent instance registry with states: LIVE → STALE → DEAD - Storage: PostgreSQL (TimescaleDB) for structured data, OpenSearch for full-text search - Security: JWT auth with RBAC (AGENT/VIEWER/OPERATOR/ADMIN roles), Ed25519 config signing, bootstrap token for registration -- OIDC: Optional external identity provider support (token exchange pattern). Configured via `CAMELEER_OIDC_*` env vars +- OIDC: Optional external identity provider support (token exchange pattern). Configured via admin API, stored in database (`oidc_config` table) - User persistence: PostgreSQL `users` table, admin CRUD at `/api/v1/admin/users` ## CI/CD & Deployment -- CI workflow: `.gitea/workflows/ci.yml` — build → docker → deploy on push to main +- CI workflow: `.gitea/workflows/ci.yml` — build → docker → deploy on push to main or feature branches - Build step skips integration tests (`-DskipITs`) — Testcontainers needs Docker daemon - Docker: multi-stage build (`Dockerfile`), `$BUILDPLATFORM` for native Maven on ARM64 runner, amd64 runtime - `REGISTRY_TOKEN` build arg required for `cameleer3-common` dependency resolution - Registry: `gitea.siegeln.net/cameleer/cameleer3-server` (container images) -- K8s manifests in `deploy/` — PostgreSQL + OpenSearch StatefulSets, server Deployment + NodePort Service (30081) -- Deployment target: k3s at 192.168.50.86, namespace `cameleer` -- Secrets managed in CI deploy step (idempotent `--dry-run=client | kubectl apply`): `cameleer-auth`, `postgres-credentials`, `opensearch-credentials`, `CAMELEER_JWT_SECRET` +- K8s manifests in `deploy/` — Kustomize base + overlays (main/feature), shared infra (PostgreSQL, OpenSearch, Authentik) as top-level manifests +- Deployment target: k3s at 192.168.50.86, namespace `cameleer` (main), `cam-` (feature branches) +- Feature branches: isolated namespace, PG schema, OpenSearch index prefix; Traefik Ingress at `-api.cameleer.siegeln.net` +- Secrets managed in CI deploy step (idempotent `--dry-run=client | kubectl apply`): `cameleer-auth`, `postgres-credentials`, `opensearch-credentials` - K8s probes: server uses `/api/v1/health`, PostgreSQL uses `pg_isready`, OpenSearch uses `/_cluster/health` - Docker build uses buildx registry cache + `--provenance=false` for Gitea compatibility diff --git a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/SecurityBeanConfig.java b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/SecurityBeanConfig.java index 5c0bdff5..d8e70958 100644 --- a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/SecurityBeanConfig.java +++ b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/SecurityBeanConfig.java @@ -1,29 +1,20 @@ package com.cameleer3.server.app.security; -import com.cameleer3.server.core.security.OidcConfig; -import com.cameleer3.server.core.security.OidcConfigRepository; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import java.util.List; - /** * Configuration class that creates security service beans and validates * that required security properties are set. *

* Fails fast on startup if {@code CAMELEER_AUTH_TOKEN} is not set. - * Seeds OIDC config from env vars into the database if DB is empty. */ @Configuration @EnableConfigurationProperties(SecurityProperties.class) public class SecurityBeanConfig { - private static final Logger log = LoggerFactory.getLogger(SecurityBeanConfig.class); - @Bean public JwtServiceImpl jwtService(SecurityProperties properties) { return new JwtServiceImpl(properties); @@ -50,36 +41,4 @@ public class SecurityBeanConfig { }; } - /** - * Seeds OIDC config from env vars into the database if the DB has no config yet. - * This allows initial provisioning via env vars, after which the admin UI takes over. - */ - @Bean - public InitializingBean oidcConfigSeeder(SecurityProperties properties, - OidcConfigRepository configRepository) { - return () -> { - if (configRepository.find().isPresent()) { - log.debug("OIDC config already present in database, skipping env var seed"); - return; - } - - SecurityProperties.Oidc envOidc = properties.getOidc(); - if (envOidc.isEnabled() - && envOidc.getIssuerUri() != null && !envOidc.getIssuerUri().isBlank() - && envOidc.getClientId() != null && !envOidc.getClientId().isBlank()) { - OidcConfig config = new OidcConfig( - true, - envOidc.getIssuerUri(), - envOidc.getClientId(), - envOidc.getClientSecret() != null ? envOidc.getClientSecret() : "", - envOidc.getRolesClaim(), - envOidc.getDefaultRoles(), - true, - "name" - ); - configRepository.save(config); - log.info("OIDC config seeded from environment variables: issuer={}", envOidc.getIssuerUri()); - } - }; - } } diff --git a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/SecurityProperties.java b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/SecurityProperties.java index e867098b..15ceddbc 100644 --- a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/SecurityProperties.java +++ b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/SecurityProperties.java @@ -2,8 +2,6 @@ package com.cameleer3.server.app.security; import org.springframework.boot.context.properties.ConfigurationProperties; -import java.util.List; - /** * Configuration properties for security settings. * Bound from the {@code security.*} namespace in application.yml. @@ -19,29 +17,6 @@ public class SecurityProperties { private String uiPassword; private String uiOrigin; private String jwtSecret; - private Oidc oidc = new Oidc(); - - public static class Oidc { - private boolean enabled = false; - private String issuerUri; - private String clientId; - private String clientSecret; - private String rolesClaim = "realm_access.roles"; - private List defaultRoles = List.of("VIEWER"); - - public boolean isEnabled() { return enabled; } - public void setEnabled(boolean enabled) { this.enabled = enabled; } - public String getIssuerUri() { return issuerUri; } - public void setIssuerUri(String issuerUri) { this.issuerUri = issuerUri; } - public String getClientId() { return clientId; } - public void setClientId(String clientId) { this.clientId = clientId; } - public String getClientSecret() { return clientSecret; } - public void setClientSecret(String clientSecret) { this.clientSecret = clientSecret; } - public String getRolesClaim() { return rolesClaim; } - public void setRolesClaim(String rolesClaim) { this.rolesClaim = rolesClaim; } - public List getDefaultRoles() { return defaultRoles; } - public void setDefaultRoles(List defaultRoles) { this.defaultRoles = defaultRoles; } - } public long getAccessTokenExpiryMs() { return accessTokenExpiryMs; } public void setAccessTokenExpiryMs(long accessTokenExpiryMs) { this.accessTokenExpiryMs = accessTokenExpiryMs; } @@ -59,6 +34,4 @@ public class SecurityProperties { public void setUiOrigin(String uiOrigin) { this.uiOrigin = uiOrigin; } public String getJwtSecret() { return jwtSecret; } public void setJwtSecret(String jwtSecret) { this.jwtSecret = jwtSecret; } - public Oidc getOidc() { return oidc; } - public void setOidc(Oidc oidc) { this.oidc = oidc; } } diff --git a/cameleer3-server-app/src/main/resources/application.yml b/cameleer3-server-app/src/main/resources/application.yml index 2662faf8..b976f4d8 100644 --- a/cameleer3-server-app/src/main/resources/application.yml +++ b/cameleer3-server-app/src/main/resources/application.yml @@ -53,13 +53,7 @@ security: ui-password: ${CAMELEER_UI_PASSWORD:admin} ui-origin: ${CAMELEER_UI_ORIGIN:http://localhost:5173} jwt-secret: ${CAMELEER_JWT_SECRET:} - oidc: - enabled: ${CAMELEER_OIDC_ENABLED:false} - issuer-uri: ${CAMELEER_OIDC_ISSUER:} - client-id: ${CAMELEER_OIDC_CLIENT_ID:} - client-secret: ${CAMELEER_OIDC_CLIENT_SECRET:} - roles-claim: ${CAMELEER_OIDC_ROLES_CLAIM:realm_access.roles} - default-roles: ${CAMELEER_OIDC_DEFAULT_ROLES:VIEWER} + springdoc: api-docs: