This is an automated email from the ASF dual-hosted git repository.

sergehuber pushed a commit to branch UNOMI-1031-authorizedips-fail-closed
in repository https://gitbox.apache.org/repos/asf/unomi.git


The following commit(s) were added to 
refs/heads/UNOMI-1031-authorizedips-fail-closed by this push:
     new 58de523a8 UNOMI-1031: Re-arm the missing authorizedIPs warning and 
document GraphQL
58de523a8 is described below

commit 58de523a8c9bf3c1b769572910cf47620f2c0887
Author: Serge Huber <[email protected]>
AuthorDate: Mon Nov 2 11:31:18 2026 +0100

    UNOMI-1031: Re-arm the missing authorizedIPs warning and document GraphQL
    
    - Warn again when a tenant that had authorized IPs empties its list.
    - Public GraphQL callers pass no IP, so they can never send protected 
events.
    - Unit-test that a null authorizedIPs is refused like an empty one.
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
 manual/src/main/asciidoc/multitenancy.adoc                         | 5 +++--
 .../org/apache/unomi/services/impl/events/EventServiceImpl.java    | 2 ++
 .../apache/unomi/services/impl/events/EventServiceImplTest.java    | 7 +++++++
 3 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/manual/src/main/asciidoc/multitenancy.adoc 
b/manual/src/main/asciidoc/multitenancy.adoc
index edc664744..44dbf840d 100644
--- a/manual/src/main/asciidoc/multitenancy.adoc
+++ b/manual/src/main/asciidoc/multitenancy.adoc
@@ -76,8 +76,9 @@ curl -X POST http://localhost:8181/cxs/tenants \
 Protected event types (`sessionCreated`, `sessionReassigned`, 
`profileUpdated`, `ruleFired`, `updateProperties`, plus
 any extra types listed in the tenant's `restrictedEventTypes`) are accepted 
from a public API key caller only when the
 caller IP is in the tenant's `authorizedIPs` (addresses or CIDR ranges). An 
empty `authorizedIPs` list, the default,
-refuses them from every public caller; update the tenant to set it. Callers 
using the tenant private key or
-administrator credentials are not IP-checked.
+refuses them from every public caller; update the tenant to set it. The 
GraphQL API passes no caller IP, so public
+GraphQL callers can never send protected events. Callers using the tenant 
private key or administrator credentials are
+not IP-checked.
 
 The create response includes the tenant with **masked** API key metadata only 
(plaintext secrets are not returned and cannot be recovered from storage):
 
diff --git 
a/services/src/main/java/org/apache/unomi/services/impl/events/EventServiceImpl.java
 
b/services/src/main/java/org/apache/unomi/services/impl/events/EventServiceImpl.java
index b87ab700e..e3e59faaf 100644
--- 
a/services/src/main/java/org/apache/unomi/services/impl/events/EventServiceImpl.java
+++ 
b/services/src/main/java/org/apache/unomi/services/impl/events/EventServiceImpl.java
@@ -196,6 +196,8 @@ public class EventServiceImpl implements EventService {
             }
             return false;
         }
+        // Warn again if the tenant later empties its list.
+        tenantsWarnedWithoutAuthorizedIPs.remove(tenant.getItemId());
         return IPValidationUtils.isIpAuthorized(sourceIP, authorizedIPs);
     }
 
diff --git 
a/services/src/test/java/org/apache/unomi/services/impl/events/EventServiceImplTest.java
 
b/services/src/test/java/org/apache/unomi/services/impl/events/EventServiceImplTest.java
index 54c944e41..944bdf347 100644
--- 
a/services/src/test/java/org/apache/unomi/services/impl/events/EventServiceImplTest.java
+++ 
b/services/src/test/java/org/apache/unomi/services/impl/events/EventServiceImplTest.java
@@ -587,6 +587,13 @@ public class EventServiceImplTest {
         unrestricted.setEventType("unrestricted");
         assertTrue(eventService.isEventAllowedForTenant(unrestricted, 
TENANT_1, "127.0.0.1"),
                 "Unrestricted event should still be allowed");
+
+        tenant.setAuthorizedIPs(null);
+        tenantService.saveTenant(tenant);
+        Event globalRestricted = createTestEvent();
+        globalRestricted.setEventType("globalRestricted");
+        assertFalse(eventService.isEventAllowedForTenant(globalRestricted, 
TENANT_1, "127.0.0.1"),
+                "A null authorizedIPs must be refused like an empty one");
     }
 
     @Test

Reply via email to