Add OIDC admin config page with auto-signup toggle
Backend: add autoSignup field to OidcConfig, ClickHouse schema, repository, and admin controller. Gate OIDC login when auto-signup is disabled and user is not pre-created (returns 403). Frontend: add OIDC admin page with full CRUD (save/test/delete), role-gated Admin nav link parsed from JWT, and matching design system styles. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -80,7 +80,8 @@ public class OidcConfigAdminController {
|
||||
request.clientId() != null ? request.clientId() : "",
|
||||
clientSecret,
|
||||
request.rolesClaim() != null ? request.rolesClaim() : "realm_access.roles",
|
||||
request.defaultRoles() != null ? request.defaultRoles() : List.of("VIEWER")
|
||||
request.defaultRoles() != null ? request.defaultRoles() : List.of("VIEWER"),
|
||||
request.autoSignup()
|
||||
);
|
||||
|
||||
configRepository.save(config);
|
||||
@@ -134,6 +135,7 @@ public class OidcConfigAdminController {
|
||||
map.put("clientSecretSet", !config.clientSecret().isBlank());
|
||||
map.put("rolesClaim", config.rolesClaim());
|
||||
map.put("defaultRoles", config.defaultRoles());
|
||||
map.put("autoSignup", config.autoSignup());
|
||||
return map;
|
||||
}
|
||||
|
||||
@@ -143,6 +145,7 @@ public class OidcConfigAdminController {
|
||||
String clientId,
|
||||
String clientSecret,
|
||||
String rolesClaim,
|
||||
List<String> defaultRoles
|
||||
List<String> defaultRoles,
|
||||
boolean autoSignup
|
||||
) {}
|
||||
}
|
||||
|
||||
@@ -90,8 +90,15 @@ public class OidcAuthController {
|
||||
String issuerHost = URI.create(config.get().issuerUri()).getHost();
|
||||
String provider = "oidc:" + issuerHost;
|
||||
|
||||
// Check auto-signup gate: if disabled, user must already exist
|
||||
Optional<UserInfo> existingUser = userRepository.findById(userId);
|
||||
if (!config.get().autoSignup() && existingUser.isEmpty()) {
|
||||
return ResponseEntity.status(403)
|
||||
.body(Map.of("message", "Account not provisioned. Contact your administrator."));
|
||||
}
|
||||
|
||||
// Resolve roles: DB override > OIDC claim > default
|
||||
List<String> roles = resolveRoles(userId, oidcUser.roles(), config.get());
|
||||
List<String> roles = resolveRoles(existingUser, oidcUser.roles(), config.get());
|
||||
|
||||
userRepository.upsert(new UserInfo(
|
||||
userId, provider, oidcUser.email(), oidcUser.name(), roles, Instant.now()));
|
||||
@@ -110,8 +117,7 @@ public class OidcAuthController {
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> resolveRoles(String userId, List<String> oidcRoles, OidcConfig config) {
|
||||
Optional<UserInfo> existing = userRepository.findById(userId);
|
||||
private List<String> resolveRoles(Optional<UserInfo> existing, List<String> oidcRoles, OidcConfig config) {
|
||||
if (existing.isPresent() && !existing.get().roles().isEmpty()) {
|
||||
return existing.get().roles();
|
||||
}
|
||||
|
||||
@@ -73,7 +73,8 @@ public class SecurityBeanConfig {
|
||||
envOidc.getClientId(),
|
||||
envOidc.getClientSecret() != null ? envOidc.getClientSecret() : "",
|
||||
envOidc.getRolesClaim(),
|
||||
envOidc.getDefaultRoles()
|
||||
envOidc.getDefaultRoles(),
|
||||
true
|
||||
);
|
||||
configRepository.save(config);
|
||||
log.info("OIDC config seeded from environment variables: issuer={}", envOidc.getIssuerUri());
|
||||
|
||||
@@ -27,7 +27,7 @@ public class ClickHouseOidcConfigRepository implements OidcConfigRepository {
|
||||
@Override
|
||||
public Optional<OidcConfig> find() {
|
||||
List<OidcConfig> results = jdbc.query(
|
||||
"SELECT enabled, issuer_uri, client_id, client_secret, roles_claim, default_roles "
|
||||
"SELECT enabled, issuer_uri, client_id, client_secret, roles_claim, default_roles, auto_signup "
|
||||
+ "FROM oidc_config FINAL WHERE config_id = 'default'",
|
||||
this::mapRow
|
||||
);
|
||||
@@ -37,14 +37,15 @@ public class ClickHouseOidcConfigRepository implements OidcConfigRepository {
|
||||
@Override
|
||||
public void save(OidcConfig config) {
|
||||
jdbc.update(
|
||||
"INSERT INTO oidc_config (config_id, enabled, issuer_uri, client_id, client_secret, roles_claim, default_roles, updated_at) "
|
||||
+ "VALUES ('default', ?, ?, ?, ?, ?, ?, now64(3, 'UTC'))",
|
||||
"INSERT INTO oidc_config (config_id, enabled, issuer_uri, client_id, client_secret, roles_claim, default_roles, auto_signup, updated_at) "
|
||||
+ "VALUES ('default', ?, ?, ?, ?, ?, ?, ?, now64(3, 'UTC'))",
|
||||
config.enabled(),
|
||||
config.issuerUri(),
|
||||
config.clientId(),
|
||||
config.clientSecret(),
|
||||
config.rolesClaim(),
|
||||
config.defaultRoles().toArray(new String[0])
|
||||
config.defaultRoles().toArray(new String[0]),
|
||||
config.autoSignup()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -61,7 +62,8 @@ public class ClickHouseOidcConfigRepository implements OidcConfigRepository {
|
||||
rs.getString("client_id"),
|
||||
rs.getString("client_secret"),
|
||||
rs.getString("roles_claim"),
|
||||
Arrays.asList(rolesArray)
|
||||
Arrays.asList(rolesArray),
|
||||
rs.getBoolean("auto_signup")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user