This is an automated email from the ASF dual-hosted git repository.
heliang666s pushed a commit to branch 3.3
in repository https://gitbox.apache.org/repos/asf/dubbo.git
The following commit(s) were added to refs/heads/3.3 by this push:
new bcc220ad4b Fix #15988: Clear SecurityContext in finally block to
prevent thread pollution (#15997)
bcc220ad4b is described below
commit bcc220ad4b9b071bde405ffccef30f6907a8677c
Author: Shivvani Ramadugu <[email protected]>
AuthorDate: Wed Jan 14 13:15:29 2026 +0530
Fix #15988: Clear SecurityContext in finally block to prevent thread
pollution (#15997)
---
.../ContextHolderAuthenticationResolverFilter.java | 8 ++-
...textHolderAuthenticationResolverFilterTest.java | 68 ++++++++++++++++++++++
2 files changed, 75 insertions(+), 1 deletion(-)
diff --git
a/dubbo-plugin/dubbo-spring-security/src/main/java/org/apache/dubbo/spring/security/filter/ContextHolderAuthenticationResolverFilter.java
b/dubbo-plugin/dubbo-spring-security/src/main/java/org/apache/dubbo/spring/security/filter/ContextHolderAuthenticationResolverFilter.java
index 0183938b54..6a74864340 100644
---
a/dubbo-plugin/dubbo-spring-security/src/main/java/org/apache/dubbo/spring/security/filter/ContextHolderAuthenticationResolverFilter.java
+++
b/dubbo-plugin/dubbo-spring-security/src/main/java/org/apache/dubbo/spring/security/filter/ContextHolderAuthenticationResolverFilter.java
@@ -61,7 +61,13 @@ public class ContextHolderAuthenticationResolverFilter
implements Filter {
getSecurityContext(invocation);
}
- return invoker.invoke(invocation);
+ try {
+ return invoker.invoke(invocation);
+ } finally {
+ if (this.mapper != null) {
+ SecurityContextHolder.clearContext();
+ }
+ }
}
private void getSecurityContext(Invocation invocation) {
diff --git
a/dubbo-plugin/dubbo-spring-security/src/test/java/org/apache/dubbo/spring/security/filter/ContextHolderAuthenticationResolverFilterTest.java
b/dubbo-plugin/dubbo-spring-security/src/test/java/org/apache/dubbo/spring/security/filter/ContextHolderAuthenticationResolverFilterTest.java
new file mode 100644
index 0000000000..a2109416f0
--- /dev/null
+++
b/dubbo-plugin/dubbo-spring-security/src/test/java/org/apache/dubbo/spring/security/filter/ContextHolderAuthenticationResolverFilterTest.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.spring.security.filter;
+
+import org.apache.dubbo.common.beans.factory.ScopeBeanFactory;
+import org.apache.dubbo.rpc.AppResponse;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.model.ApplicationModel;
+import org.apache.dubbo.spring.security.jackson.ObjectMapperCodec;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+import
org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+class ContextHolderAuthenticationResolverFilterTest {
+
+ @AfterEach
+ public void cleanup() {
+ SecurityContextHolder.clearContext();
+ }
+
+ @Test
+ void testSecurityContextIsClearedAfterInvoke() {
+ ApplicationModel applicationModel = mock(ApplicationModel.class);
+ ScopeBeanFactory beanFactory = mock(ScopeBeanFactory.class);
+ ObjectMapperCodec codec = mock(ObjectMapperCodec.class);
+
+ when(applicationModel.getBeanFactory()).thenReturn(beanFactory);
+ when(beanFactory.getBean(ObjectMapperCodec.class)).thenReturn(codec);
+
+ ContextHolderAuthenticationResolverFilter filter =
+ new
ContextHolderAuthenticationResolverFilter(applicationModel);
+
+ Invocation invocation = mock(Invocation.class);
+ Invoker<?> invoker = mock(Invoker.class);
+
+ when(invoker.invoke(any(Invocation.class))).thenReturn(new
AppResponse());
+ SecurityContextHolder.getContext()
+ .setAuthentication(new
UsernamePasswordAuthenticationToken("user", "password"));
+ filter.invoke(invoker, invocation);
+ Authentication auth =
SecurityContextHolder.getContext().getAuthentication();
+
+ assertNull(
+ auth, "SecurityContext must be cleared after the filter chain
completes to prevent thread pollution.");
+ }
+}