Serge Huber created UNOMI-941:
---------------------------------

             Summary: Security service thread-safety and authentication 
hardening
                 Key: UNOMI-941
                 URL: https://issues.apache.org/jira/browse/UNOMI-941
             Project: Apache Unomi
          Issue Type: Sub-task
          Components: unomi(-core)
    Affects Versions: unomi-3.1.0
            Reporter: Serge Huber
            Assignee: Serge Huber
             Fix For: unomi-3.1.0


Three security/thread-safety issues found in {{{}KarafSecurityService{}}}, 
{{{}ExecutionContextManagerImpl{}}}, and {{{}SecurityFilter{}}}:

*1. {{@RequiresTenant}} authorization reads tenant from caller-supplied header 
({{{}SecurityFilter:76{}}})* {{SecurityFilter}} reads the tenant to authorize 
from the {{X-Unomi-Tenant}} request header, not from the authenticated subject. 
An authenticated tenant-A admin can send {{X-Unomi-Tenant: B}} to attempt to 
access tenant B. The header name also differs from {{X-Unomi-Tenant-Id}} set by 
{{{}AuthenticationFilter{}}}, so the check silently reads {{null}} under normal 
authentication flow. _Fix:_ Derive the tenant from 
{{securityService.getCurrentSubjectTenantId()}} — not from a request header.

*2. {{SYSTEM_SUBJECT}} mutated concurrently during {{init()}} 
({{{}KarafSecurityService:72{}}})* {{updateSystemSubject()}} calls {{.clear()}} 
then re-adds principals on the shared {{Subject}} instance. Concurrent 
{{getSystemSubject()}} calls during container startup see a transiently empty 
subject, causing system permission checks to fail momentarily. The subject is 
also never set read-only, so callers can corrupt it. _Fix:_ Build a new 
{{{}Subject{}}}, call {{{}setReadOnly(){}}}, then atomically assign via 
{{{}AtomicReference{}}}.

*3. {{executeAsSystem}} restores previous subject via {{set(null)}} instead of 
{{remove()}} ({{{}ExecutionContextManagerImpl:104{}}})* When there is no 
previous subject, the finally block calls 
{{{}securityService.setCurrentSubject(null){}}}, which calls 
{{currentSubject.set(null)}} — this leaves a dead slot in the thread-local map 
rather than removing it. In a thread-pool environment, these slots accumulate 
and are never reclaimed. _Fix:_ Call {{securityService.clearCurrentSubject()}} 
(which calls {{{}remove(){}}}) when {{previousSubject}} is null.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to