Skip to content

[feature] Added CIDR and subnet support to FREERADIUS_ALLOWED_HOSTS #229#694

Open
UltraBot05 wants to merge 1 commit intoopenwisp:masterfrom
UltraBot05:fix-allowed-hosts-cidr
Open

[feature] Added CIDR and subnet support to FREERADIUS_ALLOWED_HOSTS #229#694
UltraBot05 wants to merge 1 commit intoopenwisp:masterfrom
UltraBot05:fix-allowed-hosts-cidr

Conversation

@UltraBot05
Copy link

Added strict=False to ipaddress.ip_network parsing and strip() to string inputs to allow networks with host bits and spaces to be correctly parsed and authenticated.

Checklist

  • I have read the OpenWISP Contributing Guidelines.
  • I have manually tested the changes proposed in this pull request.
  • I have written new test cases for new code and/or updated existing tests for changes to existing code.
  • I have updated the documentation.

Reference to Existing Issue

Closes #229.

Description of Changes

This PR enables CIDR and subnet support for FREERADIUS_ALLOWED_HOSTS by adding strict=False to ipaddress.ip_network() parsing in base/models.py and api/freeradius_views.py.

This change prevents ValueError crashes when host bits are set and allows authentication for any client IP within a defined network range. Additionally, .strip() was added to handle accidental whitespace in input strings. New test cases in test_freeradius_api.py verify correct range-based authentication and resilient string parsing.

@coderabbitai
Copy link

coderabbitai bot commented Mar 16, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: c6b04f6b-2253-4c43-b701-11e91e0a7d65

📥 Commits

Reviewing files that changed from the base of the PR and between e2ee205 and f31bb3a.

📒 Files selected for processing (3)
  • openwisp_radius/api/freeradius_views.py
  • openwisp_radius/base/models.py
  • openwisp_radius/tests/test_api/test_freeradius_api.py
📜 Recent review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
  • GitHub Check: Python==3.10 | django~=5.2.0
  • GitHub Check: Python==3.13 | django~=5.1.0
  • GitHub Check: Python==3.11 | django~=5.1.0
  • GitHub Check: Python==3.11 | django~=5.2.0
  • GitHub Check: Python==3.12 | django~=5.1.0
  • GitHub Check: Python==3.12 | django~=5.2.0
  • GitHub Check: Python==3.12 | django~=4.2.0
  • GitHub Check: Python==3.11 | django~=4.2.0
  • GitHub Check: Python==3.10 | django~=4.2.0
  • GitHub Check: Python==3.10 | django~=5.1.0
  • GitHub Check: Python==3.13 | django~=5.2.0
🔇 Additional comments (4)
openwisp_radius/base/models.py (2)

1341-1345: Good normalization for allowed-host entries.

Trimming each token and filtering empties here makes downstream validation and caching behavior consistent.


1389-1391: Validation logic correctly enables CIDR/subnet compatibility.

Using strict=False with guarded parsing is aligned with the new range-support requirement and avoids false rejections for host-bit notation.

openwisp_radius/api/freeradius_views.py (1)

108-110: IP membership check update is correct and consistent with model parsing.

This change properly supports CIDR ranges and whitespace-tolerant entries during runtime authorization.

openwisp_radius/tests/test_api/test_freeradius_api.py (1)

2388-2447: Solid regression coverage for CIDR and boundary behavior.

These tests validate the key scenarios introduced by the feature: in-range auth, whitespace/host-bit tolerance, and explicit out-of-range rejection.


📝 Walkthrough

Walkthrough

The changes add CIDR/range support and whitespace-tolerant parsing for FreeRADIUS allowed hosts. Model properties and validators now split comma-separated entries, trim each entry, ignore empties, and validate networks using ip_network(..., strict=False). The API view constructs ip_network from the stripped client IP when checking membership against allowed networks. Three tests were added to cover CIDR ranges, entries with spaces/host bits, and rejection of IPs outside allowed ranges.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant API_View as Freeradius API View
    participant Settings as RadiusSettings Parser
    participant Validator as IP Network Validator
    participant Cache as Cache/DB

    Client->>API_View: request from client IP
    API_View->>Settings: freeradius_allowed_hosts_list (split & trim)
    Settings->>Cache: read/write cached hosts list
    API_View->>Validator: construct ip_network(stripped_client_ip, strict=False)
    Validator->>Settings: check if client IP in any allowed network
    alt IP allowed
        API_View-->>Client: 200 OK (allowed)
    else IP not allowed
        API_View-->>Client: 403 Forbidden (detail: IP not allowed)
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Bug Fixes ❓ Inconclusive PR title states '[fix]' but referenced issue #229 is labeled '[feature]' for adding CIDR support to FREERADIUS_ALLOWED_HOSTS. Unclear whether this implements new functionality or fixes an undocumented broken feature. Confirm if this is a feature implementation (check not applicable) or bug fix (check applies). If bug fix, verify regression tests exercise CIDR validation and fail when strict=False is removed.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change (adding CIDR and subnet support) and references the linked issue number.
Description check ✅ Passed The description follows the template with all required sections completed, including checklist, reference to issue #229, and clear explanation of changes.
Linked Issues check ✅ Passed The changes fully implement the objective from issue #229 by enabling CIDR/subnet support in FREERADIUS_ALLOWED_HOSTS through strict=False parameter and strip() handling.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing CIDR/subnet support for FREERADIUS_ALLOWED_HOSTS as specified in issue #229, with no unrelated modifications.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

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.

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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@openwisp_radius/base/models.py`:
- Around line 1388-1390: The loop over allowed_hosts_set redundantly calls
str(...).strip() before validating with ipaddress.ip_network; since
allowed_hosts_set is built from freeradius_allowed_hosts_list which already
strips and yields strings, replace ipaddress.ip_network(str(ip_address).strip(),
strict=False) with ipaddress.ip_network(ip_address, strict=False) in the
validation loop (keep strict=False).

In `@openwisp_radius/tests/test_api/test_freeradius_api.py`:
- Around line 2388-2447: Add parallel CIDR-related tests to the TestClientIpApi
class mirroring the new tests in TestTransactionClientIpApi: create tests named
like test_ip_from_radsetting_cidr_range_valid,
test_ip_from_radsetting_spaces_and_host_bits_valid, and
test_ip_outside_cidr_range_rejected that manipulate
OrganizationRadiusSettings.freeradius_allowed_hosts, patch
openwisp_radius.api.freeradius_views.get_client_ip, and assert the same
responses as in the Transaction tests; also add edge-case tests in
TestClientIpApi for IPv6 CIDR ranges (e.g., ::1/128 and 2001:db8::/32) and a
regression test for a single IP without CIDR to ensure existing behavior from
test_ip_from_radsetting_invalid is preserved.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 3ea97a6c-6e92-4dc2-8af3-995aba4b7baa

📥 Commits

Reviewing files that changed from the base of the PR and between eef0edf and e2ee205.

📒 Files selected for processing (3)
  • openwisp_radius/api/freeradius_views.py
  • openwisp_radius/base/models.py
  • openwisp_radius/tests/test_api/test_freeradius_api.py
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
  • GitHub Check: Python==3.13 | django~=5.2.0
  • GitHub Check: Python==3.10 | django~=5.2.0
  • GitHub Check: Python==3.12 | django~=5.1.0
  • GitHub Check: Python==3.11 | django~=4.2.0
  • GitHub Check: Python==3.12 | django~=4.2.0
  • GitHub Check: Python==3.10 | django~=4.2.0
  • GitHub Check: Python==3.13 | django~=5.1.0
  • GitHub Check: Python==3.12 | django~=5.2.0
  • GitHub Check: Python==3.11 | django~=5.2.0
  • GitHub Check: Python==3.10 | django~=5.1.0
  • GitHub Check: Python==3.11 | django~=5.1.0
🔇 Additional comments (5)
openwisp_radius/base/models.py (1)

1342-1346: LGTM!

The list comprehension correctly strips whitespace from each entry and filters out empty strings, ensuring robust parsing of comma-separated IP addresses with accidental spaces.

openwisp_radius/api/freeradius_views.py (1)

106-118: LGTM! Correct implementation of CIDR range matching.

The logic correctly:

  1. Uses ip_network(str(ip).strip(), strict=False) to parse allowed hosts as networks, supporting both single IPs and CIDR ranges.
  2. Checks if the client IP falls within any allowed network using the in operator with ip_address() and ip_network().
  3. Preserves the existing error handling for invalid IP configurations.

The str(ip).strip() is slightly redundant (values should already be stripped strings), but serves as defensive coding and doesn't impact functionality.

openwisp_radius/tests/test_api/test_freeradius_api.py (3)

2388-2403: LGTM! Good test coverage for CIDR range matching.

This test correctly validates that an IP address within a CIDR range (172.18.0.10 in 172.18.0.0/16) is accepted for authorization.


2405-2425: LGTM! Comprehensive test for whitespace and host bits handling.

This test effectively validates:

  1. Whitespace trimming in allowed hosts parsing (space after comma).
  2. Host bits in CIDR notation (172.18.0.5/16 instead of canonical 172.18.0.0/16) working with strict=False.
  3. Cache correctness after save.
  4. Client IP within the range is accepted.

2427-2447: LGTM! Good negative test case for CIDR rejection.

This test correctly validates that an IP address outside the allowed CIDR range (10.0.0.5 not in 172.18.0.0/16) is rejected with the appropriate 403 status and error message.

@coveralls
Copy link

coveralls commented Mar 16, 2026

Coverage Status

coverage: 97.461% (+0.001%) from 97.46%
when pulling f31bb3a on UltraBot05:fix-allowed-hosts-cidr
into eef0edf on openwisp:master.

…isp#229

Closes openwisp#229

Added strict=False to ipaddress.ip_network parsing and strip() to string
inputs to allow networks with host bits and spaces to be correctly
parsed and authenticated.
@UltraBot05 UltraBot05 force-pushed the fix-allowed-hosts-cidr branch from e2ee205 to f31bb3a Compare March 16, 2026 09:37
@UltraBot05 UltraBot05 changed the title [fix] Added CIDR and subnet support to FREERADIUS_ALLOWED_HOSTS #229 [feature] Added CIDR and subnet support to FREERADIUS_ALLOWED_HOSTS #229 Mar 16, 2026
@UltraBot05
Copy link
Author

UltraBot05 commented Mar 16, 2026

Hi, some information on this:

On CodeRabbitAI's input:
I used the (value or "").strip() pattern to sanitize the host strings, which prevents the server from crashing on null values or messy whitespace. I've added new test cases in test_freeradius_api.py to cover these scenarios.

CIs have passed, please check.

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.

[feature] Allow IP range to for allowed freeradius hosts

2 participants