Skip to content

98 extend ipfilter functionality with subnets#152

Merged
jesperlarsson1910 merged 9 commits intomainfrom
98-extend-ipfilter-functionality-with-subnets
Feb 28, 2026
Merged

98 extend ipfilter functionality with subnets#152
jesperlarsson1910 merged 9 commits intomainfrom
98-extend-ipfilter-functionality-with-subnets

Conversation

@jesperlarsson1910
Copy link

@jesperlarsson1910 jesperlarsson1910 commented Feb 27, 2026

Missing last commit from #140

Summary by CodeRabbit

  • New Features
    • Added support for CIDR subnet ranges in IP whitelists and blacklists
    • Dynamic IP and subnet list management (add/remove at runtime)
    • Proxy header trust configuration option
    • Enhanced IP evaluation with prioritized whitelist and blacklist logic
    • Improved logging for blocked requests and proper HTTP 403 response formatting

Signed-off-by: Jesper Larsson <jesper.larsson@iths.se>
Signed-off-by: Jesper Larsson <jesper.larsson@iths.se>
Signed-off-by: Jesper Larsson <jesper.larsson@iths.se>
Signed-off-by: Jesper Larsson <jesper.larsson@iths.se>
Signed-off-by: Jesper Larsson <jesper.larsson@iths.se>
@jesperlarsson1910 jesperlarsson1910 marked this pull request as draft February 27, 2026 23:01
@coderabbitai
Copy link

coderabbitai bot commented Feb 27, 2026

Warning

Rate limit exceeded

@jesperlarsson1910 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 16 minutes and 7 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 6567ff3 and f6f040a.

📒 Files selected for processing (3)
  • src/main/java/org/juv25d/config/IpFilterConfig.java
  • src/main/java/org/juv25d/filter/IpFilter.java
  • src/test/java/org/juv25d/filter/IpFilterTest.java
📝 Walkthrough

Walkthrough

The IP filter class is enhanced with CIDR subnet support, thread-safe collections for whitelist/blacklist management, proxy header trust configuration, dynamic list management methods, and state getter methods. Tests are updated to align with new constructor signatures.

Changes

Cohort / File(s) Summary
IP Filter Enhancement
src/main/java/org/juv25d/filter/IpFilter.java
Major refactor introducing CIDR subnet support via SubnetUtils, thread-safe ConcurrentHashSet collections, three new constructors (including default), dynamic add/remove methods, state getters, proxy header trust flag, enhanced IP evaluation logic prioritizing whitelist/subnets, and improved logging for blocked attempts.
Test Updates
src/test/java/org/juv25d/filter/IpFilterTest.java
Constructor invocations updated from four-argument to three-argument format across all test cases to match new IpFilter API signature.

Sequence Diagram

sequenceDiagram
    participant Client as Client
    participant IpFilter as IpFilter
    participant SubnetUtils as SubnetUtils
    participant Logger as Logger

    Client->>IpFilter: doFilter(request)
    IpFilter->>IpFilter: getClientIp(request)
    Note over IpFilter: Extract IP from request or proxy headers
    
    IpFilter->>IpFilter: isAllowed(clientIp)
    
    alt IP in whitelist IPs
        IpFilter->>Logger: Log approved (whitelist)
        IpFilter-->>Client: Allow request
    else IP in whitelist subnets
        IpFilter->>SubnetUtils: Check CIDR containment
        SubnetUtils-->>IpFilter: Containment result
        IpFilter->>Logger: Log approved (subnet)
        IpFilter-->>Client: Allow request
    else IP in blacklist IPs
        IpFilter->>Logger: Log blocked (blacklist)
        IpFilter-->>Client: forbidden() - 403 response
    else IP in blacklist subnets
        IpFilter->>SubnetUtils: Check CIDR containment
        SubnetUtils-->>IpFilter: Containment result
        IpFilter->>Logger: Log blocked (subnet)
        IpFilter-->>Client: forbidden() - 403 response
    else allowByDefault flag
        alt True
            IpFilter-->>Client: Allow request
        else False
            IpFilter->>Logger: Log blocked (default deny)
            IpFilter-->>Client: forbidden() - 403 response
        end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • PR #140: Adds CIDR subnet support, proxy-header client-IP handling, thread-safe collections, and runtime add/remove/get APIs to IpFilter—directly overlaps with this PR's core features.
  • PR #99: Modifies IpFilter.isAllowed logic and introduces constructor overloads including the three-argument variant now tested in this PR.
  • PR #59: Replaces a previous IpFilter implementation with a more feature-rich version, providing context for this enhancement's evolutionary path.

Suggested reviewers

  • SandraNelj
  • bamsemats
  • johanbriger

Poem

🐰 Hops with glee through CIDR ranges,
Subnets sorted, whitelists arranged,
Thread-safe collections, proxy headers true,
IP filtering fresh and new!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 55.88% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title accurately describes the main change—extending IP filter functionality with subnet support. It is concise and clearly summarizes the primary modification.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 98-extend-ipfilter-functionality-with-subnets

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.

@jesperlarsson1910 jesperlarsson1910 marked this pull request as ready for review February 27, 2026 23:03
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
src/main/java/org/juv25d/config/IpFilterConfig.java (1)

22-23: Consider consistent formatting for getter.

The trustProxyHeaders() getter uses single-line formatting while allowByDefault() uses multi-line. Minor inconsistency.

♻️ Consistent formatting
-    public boolean trustProxyHeaders() {return trustProxyHeaders;}
+    public boolean trustProxyHeaders() {
+        return trustProxyHeaders;
+    }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/org/juv25d/config/IpFilterConfig.java` around lines 22 - 23,
The getter formatting is inconsistent: change the single-line method public
boolean trustProxyHeaders() {return trustProxyHeaders;} to match the multi-line
style used by allowByDefault() by expanding it into a conventional multiline
getter (use the same brace/indent style and spacing as allowByDefault()); locate
the trustProxyHeaders() method in IpFilterConfig and update its formatting only
(no logic changes).
src/test/java/org/juv25d/filter/IpFilterTest.java (1)

94-107: Minor naming convention inconsistency.

Method name Ip_inNeitherList_followsDefault starts with a capital I, which is inconsistent with other test methods that use lowercase_camelCase pattern (e.g., whitelist_allowsIp, blacklist_blocksIp).

♻️ Consistent naming
-    void Ip_inNeitherList_followsDefault(boolean allowByDefault) throws IOException {
+    void ip_inNeitherList_followsDefault(boolean allowByDefault) throws IOException {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/test/java/org/juv25d/filter/IpFilterTest.java` around lines 94 - 107,
Rename the test method Ip_inNeitherList_followsDefault in class IpFilterTest to
follow lowercase_camelCase (e.g., ip_inNeitherList_followsDefault or
ipInNeitherList_followsDefault) to match other tests like whitelist_allowsIp and
blacklist_blocksIp; update any references to this method (test runner or
annotations if present) so the test continues to execute under the new name.
src/main/java/org/juv25d/filter/IpFilter.java (1)

69-82: Consider constructor delegation to reduce duplication.

The 4-argument constructor duplicates initialization logic from the 3-argument constructor. Using this(...) delegation improves maintainability.

♻️ Refactor using constructor delegation
-    public IpFilter(`@Nullable` Set<String> whitelist, `@Nullable` Set<String> blacklist, boolean allowByDefault, boolean trustProxyHeaders) {
-        if (whitelist != null) {
-            for (String entry : whitelist) {
-                addToWhitelist(entry);
-            }
-        }
-        if (blacklist != null) {
-            for (String entry : blacklist) {
-                addToBlacklist(entry);
-            }
-        }
-        this.allowByDefault = allowByDefault;
-        this.trustProxyHeaders = trustProxyHeaders;
-    }
+    public IpFilter(`@Nullable` Set<String> whitelist, `@Nullable` Set<String> blacklist, boolean allowByDefault, boolean trustProxyHeaders) {
+        this.allowByDefault = allowByDefault;
+        this.trustProxyHeaders = trustProxyHeaders;
+        if (whitelist != null) {
+            whitelist.forEach(this::addToWhitelist);
+        }
+        if (blacklist != null) {
+            blacklist.forEach(this::addToBlacklist);
+        }
+    }

Then update the 3-argument constructor to delegate:

     public IpFilter(`@Nullable` Set<String> whitelist, `@Nullable` Set<String> blacklist, boolean allowByDefault) {
-        if (whitelist != null) {
-            for (String entry : whitelist) {
-                addToWhitelist(entry);
-            }
-        }
-        if (blacklist != null) {
-            for (String entry : blacklist) {
-                addToBlacklist(entry);
-            }
-        }
-        this.allowByDefault = allowByDefault;
-        this.trustProxyHeaders = false;
+        this(whitelist, blacklist, allowByDefault, false);
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/org/juv25d/filter/IpFilter.java` around lines 69 - 82, Refactor
the IpFilter constructors to delegate: replace the current 4-arg constructor
body with a call to the existing 3-arg constructor using this(whitelist,
blacklist, allowByDefault) as the first statement, then set
this.trustProxyHeaders = trustProxyHeaders; this removes the duplicated
whitelist/blacklist initialization while keeping the existing
addToWhitelist/addToBlacklist logic in the 3-arg constructor (refer to the
IpFilter( Set<String>, Set<String>, boolean ) and IpFilter( Set<String>,
Set<String>, boolean, boolean ) constructors).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/main/java/org/juv25d/filter/IpFilter.java`:
- Around line 36-59: The Javadoc for the IpFilter(Set<String>, Set<String>,
boolean) constructor wrongly states it sets trustProxyHeaders = true while the
constructor actually assigns this.trustProxyHeaders = false; update the Javadoc
to reflect the actual behavior (change the sentence "This constructor sets
{`@code` trustProxyHeaders = true}" to indicate it sets trustProxyHeaders to
false) or alternatively change the constructor assignment if the intended
behavior was to trust proxy headers; locate the IpFilter constructor and the
trustProxyHeaders field to make the correction so docs and implementation match.

---

Nitpick comments:
In `@src/main/java/org/juv25d/config/IpFilterConfig.java`:
- Around line 22-23: The getter formatting is inconsistent: change the
single-line method public boolean trustProxyHeaders() {return
trustProxyHeaders;} to match the multi-line style used by allowByDefault() by
expanding it into a conventional multiline getter (use the same brace/indent
style and spacing as allowByDefault()); locate the trustProxyHeaders() method in
IpFilterConfig and update its formatting only (no logic changes).

In `@src/main/java/org/juv25d/filter/IpFilter.java`:
- Around line 69-82: Refactor the IpFilter constructors to delegate: replace the
current 4-arg constructor body with a call to the existing 3-arg constructor
using this(whitelist, blacklist, allowByDefault) as the first statement, then
set this.trustProxyHeaders = trustProxyHeaders; this removes the duplicated
whitelist/blacklist initialization while keeping the existing
addToWhitelist/addToBlacklist logic in the 3-arg constructor (refer to the
IpFilter( Set<String>, Set<String>, boolean ) and IpFilter( Set<String>,
Set<String>, boolean, boolean ) constructors).

In `@src/test/java/org/juv25d/filter/IpFilterTest.java`:
- Around line 94-107: Rename the test method Ip_inNeitherList_followsDefault in
class IpFilterTest to follow lowercase_camelCase (e.g.,
ip_inNeitherList_followsDefault or ipInNeitherList_followsDefault) to match
other tests like whitelist_allowsIp and blacklist_blocksIp; update any
references to this method (test runner or annotations if present) so the test
continues to execute under the new name.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bfa50a9 and d73617a.

📒 Files selected for processing (4)
  • pom.xml
  • src/main/java/org/juv25d/config/IpFilterConfig.java
  • src/main/java/org/juv25d/filter/IpFilter.java
  • src/test/java/org/juv25d/filter/IpFilterTest.java

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/test/java/org/juv25d/filter/IpFilterTest.java (1)

34-43: Inconsistent constructor usage compared to updated tests.

This test uses the 4-arg constructor new IpFilter(Set.of("127.0.0.1"), null, false, false), but the test doesn't exercise proxy header functionality. The parallel test whitelist_allowsIpInRange at line 48 was updated to use the 3-arg constructor.

For consistency across the test suite, consider updating this line as well.

♻️ Suggested change for consistency
     `@Test`
     `@DisplayName`("Allow ip only in whitelist")
     void whitelist_allowsIp() throws IOException {
-        IpFilter filter = new IpFilter(Set.of("127.0.0.1"), null, false, false);
+        IpFilter filter = new IpFilter(Set.of("127.0.0.1"), null, false);
 
         filter.doFilter(req, res, chain);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/test/java/org/juv25d/filter/IpFilterTest.java` around lines 34 - 43, The
test whitelist_allowsIp uses the 4-arg IpFilter constructor but should match the
updated tests (like whitelist_allowsIpInRange) that use the 3-arg constructor;
update the instantiation in method whitelist_allowsIp to call new
IpFilter(Set.of("127.0.0.1"), null, false) (i.e., remove the extra boolean
argument) so constructor usage is consistent across tests and proxy-header
behavior isn't accidentally enabled.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/test/java/org/juv25d/filter/IpFilterTest.java`:
- Around line 34-43: The test whitelist_allowsIp uses the 4-arg IpFilter
constructor but should match the updated tests (like whitelist_allowsIpInRange)
that use the 3-arg constructor; update the instantiation in method
whitelist_allowsIp to call new IpFilter(Set.of("127.0.0.1"), null, false) (i.e.,
remove the extra boolean argument) so constructor usage is consistent across
tests and proxy-header behavior isn't accidentally enabled.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d73617a and 6567ff3.

📒 Files selected for processing (1)
  • src/test/java/org/juv25d/filter/IpFilterTest.java

Signed-off-by: Jesper Larsson <jesper.larsson@iths.se>
Signed-off-by: Jesper Larsson <jesper.larsson@iths.se>
Copy link

@OskarLundqvist33 OskarLundqvist33 left a comment

Choose a reason for hiding this comment

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

This significantly enhances the IP filtering functionality with CIDR range support, proxy header handling, and dynamic list updates — all of which are valuable upgrades and well implemented. The tests align well with the expected behaviour. It looks great, nice work!

@jesperlarsson1910 jesperlarsson1910 merged commit e609337 into main Feb 28, 2026
2 checks passed
@jesperlarsson1910 jesperlarsson1910 deleted the 98-extend-ipfilter-functionality-with-subnets branch February 28, 2026 10: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.

3 participants