Skip to content

fix(security): harden BFF auth endpoints and federated CSS - #25

Merged
danreed-rh merged 1 commit into
Gkrumbach07:mainfrom
gmenher:fix/security-hardening
Aug 11, 2026
Merged

fix(security): harden BFF auth endpoints and federated CSS#25
danreed-rh merged 1 commit into
Gkrumbach07:mainfrom
gmenher:fix/security-hardening

Conversation

@gmenher

@gmenher gmenher commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Jira: RHOAIENG-83129

Summary

Security hardening for the openshell-dashboard BFF, addressing findings from an initial security review. Also removes local CSS files that broke PatternFly theming in Module Federation consumption.

Changes

Security (backend)

  1. Rate-limit auth endpoints — Token exchange and refresh are now throttled at 10 req/min/IP to prevent brute-force refresh token abuse and IdP amplification. Only trusts X-Forwarded-For from loopback connections; direct clients are identified by RemoteAddr. Returns 429 with Retry-After: 60.

  2. OIDC issuer + token_endpoint HTTPS enforcement — Rejects non-HTTPS issuer URLs and token endpoints to prevent MITM on token exchange. Plaintext HTTP is only permitted for exact localhost/127.0.0.1 development addresses (with port separator to block localhost.evil.com variants).

  3. Stop forwarding stale tokens in dev mode — When AUTH_DISABLED=true, the auth middleware no longer reads or forwards tokens from request headers. Prevents "invalid token" errors when the gateway is configured with allowUnauthenticatedUsers=true.

  4. Workspace URL param validation — Adds validateURLParam("workspace") middleware that rejects paths not matching DNS-1123 before they reach the gateway.

  5. WebSocket origin relaxed in dev modecheckWebSocketOrigin accepts all origins when auth is disabled, simplifying local development with proxied frontends.

Frontend

  1. Terminal WebSocket URL — Uses getApiBasePath() so the terminal connects to the correct path in federated mode (/openshell/api/v1/.../terminal).

  2. CSS removal — Deletes SandboxCard.css and SandboxEgressSummary.css that broke PatternFly theming in federated consumption. Replaced with inline styles using PF design tokens.

Testing

  • go build ./... — pass
  • go vet ./... — pass
  • go test ./... — 4 packages, all pass (includes new tests for rate-limiter, input validation, OIDC enforcement, clientIP trust logic)
  • Manual: rate-limit returns 429 on 11th request, invalid workspace returns 400, valid workspace returns 200

Known limitations

  • Rate-limiter is in-memory/per-process (defense-in-depth; production ingress is primary control)
  • {name}, {provider} params not yet validated (follow-up)
  • Token in sessionStorage remains a security gap — feat/cookie-session-auth branch addresses this separately

Depends on

PR #18 should merge first (shared base commit 516da0c).

@Gkrumbach07

Copy link
Copy Markdown
Owner

Thanks — four of these I want to keep: CSS deletion, dev mode token fix, terminal basePath, and the writeGrpcError wrapped-error fix (all gateway methods use fmt.Errorf wrapping so every error was returning 500).

Drop the rate limiter, HTTPS enforcement, workspace validation, and CORS credentials header. Our BFF is relay-only (ADR 0002) — no OIDC endpoints. The genai BFF doesn't have rate limiting or HTTPS enforcement either; that belongs at the ingress layer.

One thing on the CSS: replace the inline style={{}} props with PF component props (<FlexItem flex={{ default: 'flex_1' }}>, <Content component="p">, etc.) or PF utility classes as fallback. No inline styles.

gmenher added a commit to gmenher/openshell-dashboard that referenced this pull request Aug 10, 2026
Address Gage's feedback on PR Gkrumbach07#25:

1. writeGrpcError: Replace status.FromError with errors.As + GRPCStatus()
   interface. Extracts the original clean gateway message directly,
   fixing all 64 handler call sites that returned 500 due to grpc-go
   v1.82+ wrapping the fmt.Errorf chain into the message.

2. CSS: Delete SandboxCard.css and SandboxEgressSummary.css (broke PF
   theming in Module Federation). Replace with PF component props
   (flex, grow) and utility classes (pf-v6-u-flex-shrink-0,
   pf-v6-u-text-color-subtle, pf-v6-u-py-sm, etc.). Remaining
   style={{}} only for minWidth:0 (no PF equivalent) and dynamic
   icon color.

3. Terminal: Use getApiBasePath() for WebSocket URL so federated mode
   connects to /openshell/api/v1/.../terminal correctly.

4. Tests: TestWriteGrpcErrorWrapped covers 6 real-world wrapped error
   scenarios (short messages, double-wrapped, Unavailable).
@gmenher
gmenher force-pushed the fix/security-hardening branch from 9f78b81 to 775db53 Compare August 10, 2026 09:56
@gmenher
gmenher requested a review from Gkrumbach07 as a code owner August 10, 2026 09:57
gmenher added a commit to gmenher/openshell-dashboard that referenced this pull request Aug 10, 2026
Address Gage's feedback on PR Gkrumbach07#25:

1. writeGrpcError: Replace status.FromError with errors.As + GRPCStatus()
   interface. Extracts the original clean gateway message directly,
   fixing all 64 handler call sites that returned 500 due to grpc-go
   v1.82+ wrapping the fmt.Errorf chain into the message.

2. CSS: Delete SandboxCard.css and SandboxEgressSummary.css (broke PF
   theming in Module Federation). Replace with PF component props
   (flex, grow) and utility classes (pf-v6-u-flex-shrink-0,
   pf-v6-u-text-color-subtle, pf-v6-u-py-sm, etc.). Remaining
   style={{}} only for minWidth:0 (no PF equivalent) and dynamic
   icon color.

3. Terminal: Use getApiBasePath() for WebSocket URL so federated mode
   connects to /openshell/api/v1/.../terminal correctly.

4. Tests: TestWriteGrpcErrorWrapped covers 6 real-world wrapped error
   scenarios (short messages, double-wrapped, Unavailable).
@gmenher
gmenher force-pushed the fix/security-hardening branch from 775db53 to b5397fd Compare August 10, 2026 15:30
@danreed-rh danreed-rh self-assigned this Aug 10, 2026
Address Gage's feedback on PR Gkrumbach07#25:

1. writeGrpcError: Replace status.FromError with errors.As + GRPCStatus()
   interface. Extracts the original clean gateway message directly,
   fixing all 64 handler call sites that returned 500 due to grpc-go
   v1.82+ wrapping the fmt.Errorf chain into the message.

2. CSS: Delete SandboxCard.css and SandboxEgressSummary.css (broke PF
   theming in Module Federation). Replace with PF component props
   (flex, grow) and utility classes (pf-v6-u-flex-shrink-0,
   pf-v6-u-text-color-subtle, pf-v6-u-py-sm, etc.). Remaining
   style={{}} only for minWidth:0 (no PF equivalent) and dynamic
   icon color.

3. Terminal: Use getApiBasePath() for WebSocket URL so federated mode
   connects to /openshell/api/v1/.../terminal correctly.

4. Tests: TestWriteGrpcErrorWrapped covers 6 real-world wrapped error
   scenarios (short messages, double-wrapped, Unavailable).
@gmenher
gmenher force-pushed the fix/security-hardening branch from b5397fd to 8e7af2b Compare August 11, 2026 16:09
@danreed-rh
danreed-rh merged commit 8bf7a76 into Gkrumbach07:main Aug 11, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants