Add IP filter to request pipeline - #59
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds IP-based access control and propagates client IP through requests: new Changes
Sequence Diagram(s)sequenceDiagram
participant Client as Client
participant Conn as ConnectionHandler
participant Parser as HttpParser
participant IpF as IpFilter
participant Chain as FilterChain
participant Res as HttpResponse
Client->>Conn: send TCP request
Conn->>Conn: extract remoteIp from socket
Conn->>Parser: parse raw request bytes
Parser-->>Conn: HttpRequest(..., "UNKNOWN") (if parser has no IP)
Conn->>IpF: pass HttpRequest(with remoteIp)
alt IP allowed
IpF->>Chain: doFilter -> continue pipeline
Chain->>Res: handlers produce response
else IP blocked
IpF->>Res: set 403 Forbidden response
end
Res->>Client: send response
Estimated Code Review Effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly Related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
No actionable comments were generated in the recent review. 🎉 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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@src/main/java/org/juv25d/ConnectionHandler.java`:
- Around line 32-43: Guard against socket.getInetAddress() returning null and
stop manually copying fields; implement a copy method on the HttpRequest record
(e.g., withRemoteIp(String remoteIp)) that returns a new HttpRequest with the
same fields but different remoteIp, then in ConnectionHandler use InetAddress
addr = socket.getInetAddress(); String remoteIp = addr != null ?
addr.getHostAddress() : socket.getRemoteSocketAddress() != null ?
socket.getRemoteSocketAddress().toString() : "unknown"; and create the request
via parsed.withRemoteIp(remoteIp) instead of reconstructing all fields.
In `@src/main/java/org/juv25d/filter/IpFilter.java`:
- Around line 44-53: The forbidden(HttpResponse res, String ip) method in
IpFilter currently echoes the client IP in the 403 response body, which risks
disclosing internal/proxy IPs; change it to return a generic 403 message (e.g.,
"403 Forbidden") or make verbosity configurable so the body does not include the
ip variable. Update the forbidden(...) implementation to remove concatenation of
ip from the response body (or gate that behavior behind a configuration flag in
IpFilter) and ensure Content-Length and body bytes reflect the new generic
message.
🧹 Nitpick comments (4)
src/main/java/org/juv25d/App.java (1)
18-21: Hardcoded empty sets — consider loading from configuration.Both sets are empty, making the filter a no-op. Per issue
#43, whitelist/blacklist should be configurable via the main config file or a separate configuration. This is fine as a development default, but consider loading these from configuration so the feature can be enabled without code changes.Also, placing
IpFilterbeforeLoggingFiltermeans blocked requests won't be logged. If security auditing of denied requests is desired, consider swapping the order or adding a log statement insideIpFilter.forbidden().src/main/java/org/juv25d/http/HttpParser.java (1)
60-60:"UNKNOWN"placeholder is fragile — consider a factory method or builder.The parser shouldn't need to supply a transport-layer value. Since
HttpRequestis a record, every construction site must pass all fields, so adding a field requires updating every call site. A static factory method onHttpRequest(e.g.,HttpRequest.fromParsed(...)that defaultsremoteIptonull) or awithRemoteIp(String)copy method would decouple parsing from transport concerns and reduce the maintenance burden.src/main/java/org/juv25d/filter/IpFilter.java (2)
15-18: Consider defensive copies of the sets.The constructor stores direct references to the passed sets. If a caller passes a mutable
HashSet, it could be modified after construction, silently changing filter behavior at runtime. While the current call site usesSet.of()(immutable), the class API should be safe regardless.Proposed fix
public IpFilter(Set<String> whitelist, Set<String> blacklist) { - this.whitelist = whitelist; - this.blacklist = blacklist; + this.whitelist = whitelist != null ? Set.copyOf(whitelist) : Set.of(); + this.blacklist = blacklist != null ? Set.copyOf(blacklist) : Set.of(); }This also eliminates the null checks in
doFiltersince the sets would always be non-null.
40-42:getClientIponly checks socket IP — won't work behind a reverse proxy.If the server sits behind a load balancer or reverse proxy,
remoteIpwill always be the proxy's address. Standard practice is to also check headers likeX-Forwarded-FororX-Real-IP(with caution, as these can be spoofed by clients when there's no trusted proxy). This is likely out of scope for this PR, but worth keeping in mind for production use.
annikaholmqvist94
left a comment
There was a problem hiding this comment.
Great addition, IP filtering is a valuable security feature.
Highlights
- Clean whitelist/blacklist implementation
- Smart default-open for development, easy to lock down later
- Good integration with existing pipeline-architecture
- Clear 403 responses for blocked clients
Suggestion
Consider adding a comment in App.java explaining the Set.of() configuration is intentionally open for development.
Solid implementation that's flexible and production-ready.
Approved
3880bb4
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@src/main/java/org/juv25d/App.java`:
- Around line 23-28: The pipeline currently adds LoggingFilter twice (once via
pipeline.addFilter(new LoggingFilter()) and again via
pipeline.addGlobalFilter(new LoggingFilter(), 0)), causing duplicate logs;
remove the duplicate by deleting the pipeline.addFilter(new LoggingFilter())
call (leaving the global filter) or vice versa—ensure only one LoggingFilter is
registered (either via addFilter or addGlobalFilter) and keep the IpFilter(...)
line intact.
🧹 Nitpick comments (1)
src/main/java/org/juv25d/App.java (1)
21-26: IP filter lists are hardcoded — issue#43requires config-driven whitelist/blacklist.The linked issue specifies that whitelist/blacklist should be configurable via the main config file (or a referenced file). Currently the sets are hardcoded as empty.
ConfigLoaderis already available on line 15 — consider loading the IP lists from it. The current no-op setup is fine as a stepping stone, but this should be tracked as a follow-up.Would you like me to open an issue to track loading IP filter configuration from
ConfigLoader?
Closes #43
This PR adds an IP filter to the request pipeline.
(whitelist/blacklist can be enabled when needed)
The implementation was tested by blocking localhost and verifying HTTP 403 responses.
Summary by CodeRabbit
New Features
Behavior
Tests