Skip to content

Allow exposing data to anonymous users as config option#1137

Merged
Brutus5000 merged 1 commit into
developfrom
security-fixes
Jun 14, 2026
Merged

Allow exposing data to anonymous users as config option#1137
Brutus5000 merged 1 commit into
developfrom
security-fixes

Conversation

@Sheikah45

@Sheikah45 Sheikah45 commented Jun 14, 2026

Copy link
Copy Markdown
Member

Also add other security config changes to support development with gitops-stack tilt

Summary by CodeRabbit

Release Notes

  • New Features

    • Added faf-api.allow-anonymous configuration to control anonymous access.
    • When enabled, /data/** can be accessed without authentication.
  • Bug Fixes

    • Improved role checking to safely handle unauthenticated/anonymous requests without errors.
  • Chores

    • Updated local development configuration to enable anonymous access and use local Hydra endpoints for OAuth2 JWT (issuer/JWKS) settings.

@Sheikah45 Sheikah45 requested a review from Brutus5000 June 14, 2026 01:18
@coderabbitai

coderabbitai Bot commented Jun 14, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds an allowAnonymous boolean flag to FafApiProperties (removing the unused Anope nested class), gates MethodSecurityConfig registration on allow-anonymous=false, extends WebSecurityConfig to conditionally permit /data/**, null-guards ElideUser.isInRole, and updates local dev config with anonymous access and local Hydra JWT endpoints.

Changes

Anonymous Access Feature Flag

Layer / File(s) Summary
allowAnonymous property contract
src/main/java/com/faforever/api/config/FafApiProperties.java
Adds private boolean allowAnonymous field to the root config class and removes the no-longer-used Anope nested class.
Security config conditional wiring and authorization rules
src/main/java/com/faforever/api/config/security/MethodSecurityConfig.java, src/main/java/com/faforever/api/config/security/WebSecurityConfig.java, src/main/java/com/faforever/api/security/ElideUser.java
MethodSecurityConfig is gated with @ConditionalOnProperty(name="faf-api.allow-anonymous", havingValue="false", matchIfMissing=true). WebSecurityConfig injects FafApiProperties via @RequiredArgsConstructor, and permits /data/** when isAllowAnonymous() is true. ElideUser.isInRole is updated to return false instead of throwing when fafAuthentication is null.
Local dev configuration
src/main/resources/config/application-local.yml
Sets allow-anonymous: true under faf-api and replaces JWT jwk-set-uri / issuer-uri with local HTTP Hydra endpoints.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant WebSecurityConfig
    participant FafApiProperties
    participant MethodSecurityConfig
    participant ElideUser

    Client->>WebSecurityConfig: request to /data/**
    WebSecurityConfig->>FafApiProperties: isAllowAnonymous()
    alt allowAnonymous = true
        FafApiProperties-->>WebSecurityConfig: true
        WebSecurityConfig-->>Client: permitAll (no auth required)
    else allowAnonymous = false
        FafApiProperties-->>WebSecurityConfig: false
        WebSecurityConfig->>MethodSecurityConfig: enforce method security
        MethodSecurityConfig->>ElideUser: isInRole(role)
        ElideUser->>ElideUser: fafAuthentication != null?
        alt fafAuthentication exists
            ElideUser-->>MethodSecurityConfig: hasRole(role) result
        else fafAuthentication is null
            ElideUser-->>MethodSecurityConfig: false
        end
        MethodSecurityConfig-->>WebSecurityConfig: authorization decision
        WebSecurityConfig-->>Client: authorized or forbidden
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • FAForever/faf-java-api#1138: Both PRs modify WebSecurityConfig.securityFilterChain to permit unauthenticated access to specific endpoints—this PR gates /data/** using fafApiProperties.allowAnonymous, while the related PR permits unauthenticated access to specific actuator endpoints.

Poem

🐇 Hop, hop, through the security gate,
Anonymous friends can now navigate!
The Anope class? Gone without a trace,
allowAnonymous takes its place.
No null exceptions shall startle the hare —
Local dev blooms with fresh Hydra air! 🌿

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title accurately describes the main change: adding a configuration option to allow anonymous access to data, which is the core purpose of the PR across all modified files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch security-fixes

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/main/java/com/faforever/api/config/security/WebSecurityConfig.java (1)

46-52: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

/actuator/** anonymous access is broader than health/readiness.

This permits any exposed actuator endpoint anonymously. Limit anonymous access to health probes (typically "/actuator/health" and "/actuator/health/**"), ideally GET-only.

Suggested tightening
       authorizeConfig.requestMatchers(
         "/swagger-ui/**",
         "/swagger-resources/**",
         "/v3/api-docs/**",
-        "/",
-        "/actuator/**"
+        "/"
       ).permitAll();
+      authorizeConfig.requestMatchers(
+        HttpMethod.GET,
+        "/actuator/health",
+        "/actuator/health/**"
+      ).permitAll();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/faforever/api/config/security/WebSecurityConfig.java`
around lines 46 - 52, The current security configuration permits anonymous
access to all actuator endpoints using the `/actuator/**` pattern, which is
overly permissive. Replace this broad pattern with specific patterns for health
probes only, such as `/actuator/health` and `/actuator/health/**`. Additionally,
restrict anonymous access to these health endpoints to GET requests only by
using `requestMatchers` with the `.permitAll()` method being applied only to GET
requests on health endpoints, while other actuator endpoints remain protected.
src/main/java/com/faforever/api/security/ElideUser.java (1)

21-27: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Null-safe role check is incomplete; getName() can still NPE.

isInRole now handles null auth, but Line 22 still dereferences fafAuthentication directly. With anonymous/non-FAF principals, this remains a crash path.

Suggested fix
   `@Override`
   public String getName() {
-    return fafAuthentication.getName();
+    return fafAuthentication != null ? fafAuthentication.getName() : super.getName();
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/faforever/api/security/ElideUser.java` around lines 21 -
27, The getName() method in the ElideUser class dereferences fafAuthentication
directly without a null check, creating a crash path for anonymous or non-FAF
principals, while the isInRole() method has been updated with proper
null-safety. Apply the same null-safe pattern to the getName() method by
checking if fafAuthentication is not null before calling getName() on it, and
return an appropriate default value (such as null or an empty string) if
fafAuthentication is null, matching the defensive approach used in isInRole().
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main/java/com/faforever/api/config/security/MethodSecurityConfig.java`:
- Around line 11-16: The MethodSecurityConfig class uses `@ConditionalOnProperty`
to disable method security globally when faf-api.allow-anonymous is true, which
is overly broad and removes all `@PreAuthorize/`@Secured enforcement. Remove the
`@ConditionalOnProperty` annotation from `@EnableMethodSecurity`(securedEnabled =
true) to ensure method security is always enabled. Instead, configure anonymous
access at the request matcher or controller level through your security
configuration (such as in SecurityFilterChain or by using `@PermitAll` on specific
controller methods) so that only specific endpoints allow anonymous access while
protected endpoints remain enforced.

---

Outside diff comments:
In `@src/main/java/com/faforever/api/config/security/WebSecurityConfig.java`:
- Around line 46-52: The current security configuration permits anonymous access
to all actuator endpoints using the `/actuator/**` pattern, which is overly
permissive. Replace this broad pattern with specific patterns for health probes
only, such as `/actuator/health` and `/actuator/health/**`. Additionally,
restrict anonymous access to these health endpoints to GET requests only by
using `requestMatchers` with the `.permitAll()` method being applied only to GET
requests on health endpoints, while other actuator endpoints remain protected.

In `@src/main/java/com/faforever/api/security/ElideUser.java`:
- Around line 21-27: The getName() method in the ElideUser class dereferences
fafAuthentication directly without a null check, creating a crash path for
anonymous or non-FAF principals, while the isInRole() method has been updated
with proper null-safety. Apply the same null-safe pattern to the getName()
method by checking if fafAuthentication is not null before calling getName() on
it, and return an appropriate default value (such as null or an empty string) if
fafAuthentication is null, matching the defensive approach used in isInRole().
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1025f318-8ffd-47f6-8fa3-6ff6dbb727e7

📥 Commits

Reviewing files that changed from the base of the PR and between ea4e7b1 and d596efc.

📒 Files selected for processing (5)
  • src/main/java/com/faforever/api/config/FafApiProperties.java
  • src/main/java/com/faforever/api/config/security/MethodSecurityConfig.java
  • src/main/java/com/faforever/api/config/security/WebSecurityConfig.java
  • src/main/java/com/faforever/api/security/ElideUser.java
  • src/main/resources/config/application-local.yml

Comment on lines +11 to 16
@ConditionalOnProperty(
value = "faf-api.allow-anonymous",
havingValue = "false",
matchIfMissing = true
)
@EnableMethodSecurity(securedEnabled = true)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Global method-security disablement is too broad.

When faf-api.allow-anonymous=true, this removes all @PreAuthorize/@Secured enforcement, not just for health/readiness or /data/**. Keep method security enabled and scope anonymous access at request matcher/controller level instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/faforever/api/config/security/MethodSecurityConfig.java`
around lines 11 - 16, The MethodSecurityConfig class uses `@ConditionalOnProperty`
to disable method security globally when faf-api.allow-anonymous is true, which
is overly broad and removes all `@PreAuthorize/`@Secured enforcement. Remove the
`@ConditionalOnProperty` annotation from `@EnableMethodSecurity`(securedEnabled =
true) to ensure method security is always enabled. Instead, configure anonymous
access at the request matcher or controller level through your security
configuration (such as in SecurityFilterChain or by using `@PermitAll` on specific
controller methods) so that only specific endpoints allow anonymous access while
protected endpoints remain enforced.

@Brutus5000

Copy link
Copy Markdown
Member

Your changes overlap with #1138

But they do more, because the expose too much. Do you need anything more than in #1138 for Tilt?

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main/java/com/faforever/api/config/security/WebSecurityConfig.java (1)

70-72: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Exposing /data/** contradicts the stated PR objective of exposing actuator endpoints.

The PR objectives specify exposing "actuator endpoints to anonymous users to enable health and readiness checks," but this implementation exposes /data/**, which in Elide-based applications typically represents the entire JSON:API data access layer (CRUD operations on entities), not actuator endpoints.

Combined with MethodSecurityConfig being disabled when allow-anonymous=true (see context snippet from MethodSecurityConfig.java), this creates a wide-open API surface with no authentication or authorization when the flag is enabled.

Expected behavior for health/readiness checks:

if (fafApiProperties.isAllowAnonymous()) {
  authorizeConfig.requestMatchers(
    "/actuator/health",
    "/actuator/readiness"
  ).permitAll();
}

If the broader /data/** exposure is intentional for the Tilt local development workflow, please:

  1. Add a clear comment explaining why the entire data API needs anonymous access (not just actuator endpoints)
  2. Update the PR description to reflect the actual scope
  3. Consider whether this aligns with the concern raised by Brutus5000 about unnecessary exposure beyond PR #1138
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/faforever/api/config/security/WebSecurityConfig.java`
around lines 70 - 72, The permitAll() configuration for `/data/**` in the
anonymous access block exposes the entire JSON:API data layer instead of just
the actuator endpoints specified in the PR objectives. Replace the `/data/**`
matcher with the specific actuator endpoints `/actuator/health` and
`/actuator/readiness` to align with the stated goal of enabling health and
readiness checks. If the broader `/data/**` exposure is intentional for local
development, add a clear code comment explaining why the entire data API
requires anonymous access and verify this aligns with the security concerns
raised in the PR description.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/main/java/com/faforever/api/config/security/WebSecurityConfig.java`:
- Around line 70-72: The permitAll() configuration for `/data/**` in the
anonymous access block exposes the entire JSON:API data layer instead of just
the actuator endpoints specified in the PR objectives. Replace the `/data/**`
matcher with the specific actuator endpoints `/actuator/health` and
`/actuator/readiness` to align with the stated goal of enabling health and
readiness checks. If the broader `/data/**` exposure is intentional for local
development, add a clear code comment explaining why the entire data API
requires anonymous access and verify this aligns with the security concerns
raised in the PR description.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 78d21b6e-300c-444a-ac94-def7370bfe37

📥 Commits

Reviewing files that changed from the base of the PR and between d596efc and 7a92474.

📒 Files selected for processing (1)
  • src/main/java/com/faforever/api/config/security/WebSecurityConfig.java

@Sheikah45 Sheikah45 changed the title Expose actuator to anonymous for health and readiness checks Allow exposing data to anonymous users as config option Jun 14, 2026
@Brutus5000 Brutus5000 merged commit 96f3ed3 into develop Jun 14, 2026
4 checks passed
@Brutus5000 Brutus5000 deleted the security-fixes branch June 14, 2026 11:47
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.

2 participants