Skip to content

Security

theGreenGuy edited this page Jun 4, 2026 · 2 revisions

Security

Edge authentication + per-endpoint authorization, toggleable so the stack runs locally without a realm (build.md §4.8, §12).

Authentication — gateway JWT

With openwcs.security.enabled=true, the gateway is an OAuth2 resource server: it validates the JWT against the Keycloak realm, requires auth on /api/**, and forwards the identity downstream as X-Auth-User / X-Auth-Roles. It always strips client-supplied versions of those headers (anti-spoofing) — the gateway is the trust boundary. Off by default, all traffic is permitted so the stack runs without tokens.

This path is exercised end-to-end in CI (GatewayAuthEndToEndTest) against a live Keycloak Testcontainer that imports the openwcs realm: no token → 401, a realm JWT → 200 with the identity propagated, and a client-supplied X-Auth-* header is stripped.

Authorization — per-endpoint RBAC

  • libs/common carries a code-defined Permission catalog and a RoleCatalog (ADMIN/SUPERVISOR/OPERATOR/VIEWER) mirroring the IAM seed.
  • Each service enforces a coded Permission against the forwarded X-Auth-Roles, gated by openwcs.security.enabled (no-op when off; 403 problem+json on a missing permission when on). order-management uses an AccessGuard; other services use an RbacFilter.
  • Inter-service identity propagation: services forward X-Auth-* on outbound calls (e.g. allocation → inventory), so downstream RBAC authorizes against the original user.

IAM service

iam (port 8087) owns the authorization model: users → roles → coded permissions, with effective-permission resolution (union across roles). Keycloak does authentication; IAM layers RBAC on top.

Warehouse access (per-user scope)

Each user is mapped to the warehouses they may work in and one default (iam.user_warehouse; a partial-unique index enforces at-most-one default per user). Endpoints under /api/iam/warehouse-access:

  • GET /me — the signed-in user's allowed warehouses + default (the UI's top-bar switcher auto-selects the default on login and scopes every warehouse-related screen; users never type a UUID).
  • GET / PUT /{username} — list/replace a user's mapping. ADMIN-only, enforced server-side on X-Auth-Roles (not just in the UI). The default must be one of the allowed warehouses.

A network-only /internal/warehouse-access/{username} (mapped off /api/**, so unreachable through nginx or the gateway's public routes) lets the gateway resolve a user's warehouses.

Gateway enforcement. For non-admins the gateway resolves the allowed set from IAM (short-TTL cache; fails open if IAM is unavailable), forwards it downstream as X-Auth-Warehouses, and rejects with 403 any request that names a warehouseId (query parameter, or the /warehouses/{id} path) outside that set. Admins are never warehouse-scoped. Writes that carry the warehouse only in a JSON body are guarded per-endpoint downstream via the forwarded header (follow-up).

Keycloak realm

Docker Compose imports platform/keycloak/openwcs-realm.json — realm openwcs with roles ADMIN/SUPERVISOR/OPERATOR/VIEWER, the public openwcs-web client (direct-access grants on for dev), and demo users (dev-only passwords). Reached at http://localhost:8180.

Enabling it

Set OPENWCS_SECURITY_ENABLED=true and point the gateway at the realm, e.g. SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URI=http://localhost:8180/realms/openwcs.

Not yet: mTLS between services (internal trust currently rides on forwarded headers behind the edge); custom (non-seed) IAM roles would need a runtime IAM lookup.

Clone this wiki locally