Add RBAC with role-based endpoint authorization and OIDC support
Implement three-phase security upgrade: Phase 1 - RBAC: Extend JWT with roles claim, populate Spring GrantedAuthority in filter, enforce role-based access (AGENT for data/heartbeat/SSE, VIEWER+ for search/diagrams, OPERATOR+ for commands, ADMIN for user management). Configurable JWT secret via CAMELEER_JWT_SECRET env var for token persistence across restarts. Phase 2 - User persistence: ClickHouse users table with ReplacingMergeTree, UserRepository interface + ClickHouse impl, UserAdminController for CRUD at /api/v1/admin/users. Local login upserts user on each authentication. Phase 3 - OIDC: Token exchange flow where SPA sends auth code, server exchanges it server-side (keeping client_secret secure), validates id_token via JWKS, resolves roles (DB override > OIDC claim > default), issues internal JWT. Conditional on CAMELEER_OIDC_ENABLED=true. Uses oauth2-oidc-sdk for standards compliance. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -40,6 +40,14 @@ security:
|
||||
ui-user: ${CAMELEER_UI_USER:admin}
|
||||
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:
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
user_id String,
|
||||
provider LowCardinality(String),
|
||||
email String DEFAULT '',
|
||||
display_name String DEFAULT '',
|
||||
roles Array(LowCardinality(String)),
|
||||
created_at DateTime64(3, 'UTC') DEFAULT now64(3, 'UTC'),
|
||||
updated_at DateTime64(3, 'UTC') DEFAULT now64(3, 'UTC')
|
||||
) ENGINE = ReplacingMergeTree(updated_at)
|
||||
ORDER BY (user_id);
|
||||
Reference in New Issue
Block a user