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)