From 534e936cd4c1248f1dd1f42756399d7ec2957ef7 Mon Sep 17 00:00:00 2001 From: hsiegeln <37154749+hsiegeln@users.noreply.github.com> Date: Sat, 11 Apr 2026 21:30:33 +0200 Subject: [PATCH] Group OIDC settings under cameleer.server.security.oidc.* MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move OIDC properties into a nested Oidc class within SecurityProperties for clearer grouping. Env vars gain an extra separator: cameleer.server.security.oidc.issueruri → CAMELEER_SERVER_SECURITY_OIDC_ISSUERURI cameleer.server.security.oidc.jwkseturi → CAMELEER_SERVER_SECURITY_OIDC_JWKSETURI cameleer.server.security.oidc.audience → CAMELEER_SERVER_SECURITY_OIDC_AUDIENCE cameleer.server.security.oidc.tlsskipverify → CAMELEER_SERVER_SECURITY_OIDC_TLSSKIPVERIFY Co-Authored-By: Claude Opus 4.6 (1M context) --- .../app/controller/UserAdminController.java | 2 +- .../app/security/OidcTokenExchanger.java | 8 ++--- .../server/app/security/SecurityConfig.java | 12 +++---- .../app/security/SecurityProperties.java | 31 ++++++++++++------- .../src/main/resources/application.yml | 9 +++--- 5 files changed, 35 insertions(+), 27 deletions(-) diff --git a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/UserAdminController.java b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/UserAdminController.java index 387cfd64..4fa57c40 100644 --- a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/UserAdminController.java +++ b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/UserAdminController.java @@ -59,7 +59,7 @@ public class UserAdminController { this.rbacService = rbacService; this.userRepository = userRepository; this.auditService = auditService; - String issuer = securityProperties.getOidcIssuerUri(); + String issuer = securityProperties.getOidc().getIssuerUri(); this.oidcEnabled = issuer != null && !issuer.isBlank(); } diff --git a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/OidcTokenExchanger.java b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/OidcTokenExchanger.java index 0646da42..7eeabbd6 100644 --- a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/OidcTokenExchanger.java +++ b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/OidcTokenExchanger.java @@ -88,7 +88,7 @@ public class OidcTokenExchanger { body += "&resource=" + java.net.URLEncoder.encode(configAudience, java.nio.charset.StandardCharsets.UTF_8); httpRequest.setBody(body); } - if (securityProperties.isOidcTlsSkipVerify()) { + if (securityProperties.getOidc().isTlsSkipVerify()) { httpRequest.setSSLSocketFactory(InsecureTlsHelper.socketFactory()); httpRequest.setHostnameVerifier(InsecureTlsHelper.hostnameVerifier()); } @@ -267,7 +267,7 @@ public class OidcTokenExchanger { OIDCProviderMetadata metadata = getProviderMetadata(issuerUri); URL jwksUrl = metadata.getJWKSetURI().toURL(); JWKSource jwkSource = OidcProviderHelper.buildJwkSource( - jwksUrl, securityProperties.isOidcTlsSkipVerify()); + jwksUrl, securityProperties.getOidc().isTlsSkipVerify()); var keySelector = new JWSVerificationKeySelector( OidcProviderHelper.SUPPORTED_ALGORITHMS, jwkSource); ConfigurableJWTProcessor processor = new DefaultJWTProcessor<>(); @@ -286,7 +286,7 @@ public class OidcTokenExchanger { synchronized (this) { if (providerMetadata == null || !issuerUri.equals(cachedIssuerUri)) { providerMetadata = OidcProviderHelper.fetchMetadata( - issuerUri, securityProperties.isOidcTlsSkipVerify()); + issuerUri, securityProperties.getOidc().isTlsSkipVerify()); cachedIssuerUri = issuerUri; jwtProcessor = null; // Reset processor when issuer changes log.info("OIDC provider metadata loaded from {}", issuerUri); @@ -303,7 +303,7 @@ public class OidcTokenExchanger { OIDCProviderMetadata metadata = getProviderMetadata(issuerUri); URL jwksUrl = metadata.getJWKSetURI().toURL(); JWKSource jwkSource = OidcProviderHelper.buildJwkSource( - jwksUrl, securityProperties.isOidcTlsSkipVerify()); + jwksUrl, securityProperties.getOidc().isTlsSkipVerify()); var keySelector = new JWSVerificationKeySelector( OidcProviderHelper.SUPPORTED_ALGORITHMS, jwkSource); diff --git a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/SecurityConfig.java b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/SecurityConfig.java index d7a7a83d..ec98db49 100644 --- a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/SecurityConfig.java +++ b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/SecurityConfig.java @@ -63,7 +63,7 @@ public class SecurityConfig { CorsConfigurationSource corsConfigurationSource, UserRepository userRepository) throws Exception { JwtDecoder oidcDecoder = null; - String issuer = securityProperties.getOidcIssuerUri(); + String issuer = securityProperties.getOidc().getIssuerUri(); if (issuer != null && !issuer.isBlank()) { try { oidcDecoder = buildOidcDecoder(securityProperties); @@ -155,22 +155,22 @@ public class SecurityConfig { * {@code at+jwt} token type (RFC 9068) by accepting any JWT type. */ private JwtDecoder buildOidcDecoder(SecurityProperties properties) throws Exception { - String issuerUri = properties.getOidcIssuerUri(); + String issuerUri = properties.getOidc().getIssuerUri(); // Resolve JWKS URI: use explicit config if set, otherwise discover from OIDC metadata. URL jwksUri; - String jwkSetUri = properties.getOidcJwkSetUri(); + String jwkSetUri = properties.getOidc().getJwkSetUri(); if (jwkSetUri != null && !jwkSetUri.isBlank()) { jwksUri = new URI(jwkSetUri).toURL(); log.info("Using explicit JWKS URI: {}", jwksUri); } else { OIDCProviderMetadata metadata = OidcProviderHelper.fetchMetadata( - issuerUri, properties.isOidcTlsSkipVerify()); + issuerUri, properties.getOidc().isTlsSkipVerify()); jwksUri = metadata.getJWKSetURI().toURL(); } JWKSource jwkSource = OidcProviderHelper.buildJwkSource( - jwksUri, properties.isOidcTlsSkipVerify()); + jwksUri, properties.getOidc().isTlsSkipVerify()); var keySelector = new JWSVerificationKeySelector( OidcProviderHelper.SUPPORTED_ALGORITHMS, jwkSource); var processor = new DefaultJWTProcessor(); @@ -181,7 +181,7 @@ public class SecurityConfig { // Validate issuer + optionally audience OAuth2TokenValidator validators; - String audience = properties.getOidcAudience(); + String audience = properties.getOidc().getAudience(); if (audience != null && !audience.isBlank()) { validators = new DelegatingOAuth2TokenValidator<>( JwtValidators.createDefaultWithIssuer(issuerUri), 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 4eead62f..381883ca 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 @@ -17,11 +17,24 @@ public class SecurityProperties { private String uiPassword; private String uiOrigin; private String jwtSecret; - private String oidcIssuerUri; - private String oidcJwkSetUri; - private String oidcAudience; - private boolean oidcTlsSkipVerify; private String corsAllowedOrigins; + private Oidc oidc = new Oidc(); + + public static class Oidc { + private String issuerUri; + private String jwkSetUri; + private String audience; + private boolean tlsSkipVerify; + + public String getIssuerUri() { return issuerUri; } + public void setIssuerUri(String issuerUri) { this.issuerUri = issuerUri; } + public String getJwkSetUri() { return jwkSetUri; } + public void setJwkSetUri(String jwkSetUri) { this.jwkSetUri = jwkSetUri; } + public String getAudience() { return audience; } + public void setAudience(String audience) { this.audience = audience; } + public boolean isTlsSkipVerify() { return tlsSkipVerify; } + public void setTlsSkipVerify(boolean tlsSkipVerify) { this.tlsSkipVerify = tlsSkipVerify; } + } public long getAccessTokenExpiryMs() { return accessTokenExpiryMs; } public void setAccessTokenExpiryMs(long accessTokenExpiryMs) { this.accessTokenExpiryMs = accessTokenExpiryMs; } @@ -39,14 +52,8 @@ 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 String getOidcIssuerUri() { return oidcIssuerUri; } - public void setOidcIssuerUri(String oidcIssuerUri) { this.oidcIssuerUri = oidcIssuerUri; } - public String getOidcJwkSetUri() { return oidcJwkSetUri; } - public void setOidcJwkSetUri(String oidcJwkSetUri) { this.oidcJwkSetUri = oidcJwkSetUri; } - public String getOidcAudience() { return oidcAudience; } - public void setOidcAudience(String oidcAudience) { this.oidcAudience = oidcAudience; } - public boolean isOidcTlsSkipVerify() { return oidcTlsSkipVerify; } - public void setOidcTlsSkipVerify(boolean oidcTlsSkipVerify) { this.oidcTlsSkipVerify = oidcTlsSkipVerify; } public String getCorsAllowedOrigins() { return corsAllowedOrigins; } public void setCorsAllowedOrigins(String corsAllowedOrigins) { this.corsAllowedOrigins = corsAllowedOrigins; } + 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 c5459c8b..8d10f7b0 100644 --- a/cameleer3-server-app/src/main/resources/application.yml +++ b/cameleer3-server-app/src/main/resources/application.yml @@ -69,11 +69,12 @@ cameleer: uipassword: ${CAMELEER_SERVER_SECURITY_UIPASSWORD:admin} uiorigin: ${CAMELEER_SERVER_SECURITY_UIORIGIN:http://localhost:5173} jwtsecret: ${CAMELEER_SERVER_SECURITY_JWTSECRET:} - oidcissueruri: ${CAMELEER_SERVER_SECURITY_OIDCISSUERURI:} - oidcjwkseturi: ${CAMELEER_SERVER_SECURITY_OIDCJWKSETURI:} - oidcaudience: ${CAMELEER_SERVER_SECURITY_OIDCAUDIENCE:} - oidctlsskipverify: ${CAMELEER_SERVER_SECURITY_OIDCTLSSKIPVERIFY:false} corsallowedorigins: ${CAMELEER_SERVER_SECURITY_CORSALLOWEDORIGINS:} + oidc: + issueruri: ${CAMELEER_SERVER_SECURITY_OIDC_ISSUERURI:} + jwkseturi: ${CAMELEER_SERVER_SECURITY_OIDC_JWKSETURI:} + audience: ${CAMELEER_SERVER_SECURITY_OIDC_AUDIENCE:} + tlsskipverify: ${CAMELEER_SERVER_SECURITY_OIDC_TLSSKIPVERIFY:false} clickhouse: url: ${CAMELEER_SERVER_CLICKHOUSE_URL:jdbc:clickhouse://localhost:8123/cameleer} username: ${CAMELEER_SERVER_CLICKHOUSE_USERNAME:default}