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

cziegeler pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/felix-dev.git


The following commit(s) were added to refs/heads/master by this push:
     new 8715ca5e4f FELIX-6796 : Potential NPE when logging into webconsole
8715ca5e4f is described below

commit 8715ca5e4f5c8876cd04f063ee4f9ba145bd67b1
Author: Carsten Ziegeler <[email protected]>
AuthorDate: Tue Aug 12 15:12:41 2025 +0200

    FELIX-6796 : Potential NPE when logging into webconsole
---
 .../webconsole/internal/servlet/OsgiManager.java   | 26 +++++++++++++---------
 .../internal/servlet/OsgiManagerHttpContext.java   | 11 +++++----
 .../servlet/OsgiManagerHttpContextTest.java        |  4 +++-
 .../internal/servlet/OsgiManagerTest.java          |  9 ++++----
 4 files changed, 29 insertions(+), 21 deletions(-)

diff --git 
a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java
 
b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java
index 1e3516def5..349025fd30 100644
--- 
a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java
+++ 
b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java
@@ -38,6 +38,7 @@ import java.util.ResourceBundle;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentSkipListSet;
+import java.util.concurrent.atomic.AtomicReference;
 
 import org.apache.felix.webconsole.servlet.User;
 import org.apache.felix.webconsole.internal.OsgiManagerPlugin;
@@ -187,7 +188,7 @@ public class OsgiManager extends HttpServlet {
 
     private ServiceTracker<BrandingPlugin, BrandingPlugin> brandingTracker;
 
-    private ServiceTracker<SecurityProvider, SecurityProvider> 
securityProviderTracker;
+    private final AtomicReference<ServiceTracker<SecurityProvider, 
SecurityProvider>> securityProviderTracker = new AtomicReference<>();
 
     @SuppressWarnings("rawtypes")
     private ServiceRegistration configurationListener;
@@ -267,14 +268,14 @@ public class OsgiManager extends HttpServlet {
         this.defaultConfiguration.put( PROP_RELOAD_TIMEOUT,
             ConfigurationUtil.getProperty( bundleContext, 
FRAMEWORK_RELOAD_TIMEOUT, DEFAULT_RELOAD_TIMEOUT ) );
 
+        this.requiredSecurityProviders = 
splitCommaSeparatedString(bundleContext.getProperty(FRAMEWORK_PROP_SECURITY_PROVIDERS));
+
         // configure and start listening for configuration
         updateConfiguration(null);
 
-        this.requiredSecurityProviders = 
splitCommaSeparatedString(bundleContext.getProperty(FRAMEWORK_PROP_SECURITY_PROVIDERS));
-
         // add support for pluggable security
-        securityProviderTracker = new ServiceTracker<>(bundleContext, 
SecurityProvider.class, new UpdateDependenciesStateCustomizer());
-        securityProviderTracker.open();
+        securityProviderTracker.set(new ServiceTracker<>(bundleContext, 
SecurityProvider.class, new UpdateDependenciesStateCustomizer()));
+        securityProviderTracker.get().open();
 
         // register managed service as a service factory
         this.configurationListener = bundleContext.registerService( 
"org.osgi.service.cm.ManagedService",
@@ -389,10 +390,11 @@ public class OsgiManager extends HttpServlet {
         }
 
         // stop tracking security provider
-        if (securityProviderTracker != null) {
-            securityProviderTracker.close();
-            securityProviderTracker = null;
+        final ServiceTracker<SecurityProvider, SecurityProvider> tracker = 
securityProviderTracker.get();
+        if (tracker != null) {
+            tracker.close();
         }
+        securityProviderTracker.set(null);
 
         this.bundleContext = null;
     }
@@ -539,8 +541,10 @@ public class OsgiManager extends HttpServlet {
 
     @SuppressWarnings("deprecation")
     private final void logout(final HttpServletRequest request, final 
HttpServletResponse response) throws IOException {
-        final SecurityProvider securityProvider = 
securityProviderTracker.getService();
-        securityProvider.logout(request, response);
+        final SecurityProvider securityProvider = 
securityProviderTracker.get().getService();
+        if (securityProvider != null) {
+            securityProvider.logout(request, response);
+        }
         if (!response.isCommitted()) {
             // check if special logout cookie is set, this is used to prevent
             // from an endless loop with basic auth
@@ -915,7 +919,7 @@ public class OsgiManager extends HttpServlet {
         this.unregisterHttpWhiteboardServices();
         // switch location
         this.webManagerRoot = newWebManagerRoot;
-        this.registerHttpWhiteboardServices();
+        this.updateRegistrationState();
     }
 
     static Set<String> splitCommaSeparatedString(final String str) {
diff --git 
a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerHttpContext.java
 
b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerHttpContext.java
index 608ebd7004..c1f3307617 100644
--- 
a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerHttpContext.java
+++ 
b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerHttpContext.java
@@ -17,6 +17,7 @@
 package org.apache.felix.webconsole.internal.servlet;
 
 import java.net.URL;
+import java.util.concurrent.atomic.AtomicReference;
 
 import org.apache.felix.webconsole.servlet.User;
 import org.apache.felix.webconsole.spi.SecurityProvider;
@@ -31,16 +32,17 @@ import jakarta.servlet.http.HttpServletResponse;
 
 final class OsgiManagerHttpContext extends ServletContextHelper {
 
-    private final ServiceTracker<SecurityProvider, SecurityProvider> tracker;
+    private final AtomicReference<ServiceTracker<SecurityProvider, 
SecurityProvider>> holder;
 
     private final Bundle bundle;
 
     private final String webManagerRoot;
 
     OsgiManagerHttpContext(final Bundle webConsoleBundle,
-            final ServiceTracker<SecurityProvider, SecurityProvider> tracker, 
final String webManagerRoot) {
+            final AtomicReference<ServiceTracker<SecurityProvider, 
SecurityProvider>> holder,
+            final String webManagerRoot) {
         super(webConsoleBundle);
-        this.tracker = tracker;
+        this.holder = holder;
         this.bundle = webConsoleBundle;
         this.webManagerRoot = webManagerRoot;
     }
@@ -62,7 +64,8 @@ final class OsgiManagerHttpContext extends 
ServletContextHelper {
     @Override
     @SuppressWarnings("deprecation")
     public boolean handleSecurity( final HttpServletRequest r, final 
HttpServletResponse response ) {
-        final SecurityProvider provider = tracker.getService();
+        final ServiceTracker<SecurityProvider, SecurityProvider> tracker = 
holder.get();
+        final SecurityProvider provider = tracker != null ? 
tracker.getService() : null;
 
         // for compatibility we have to adjust a few methods on the request
         final HttpServletRequest request = new HttpServletRequestWrapper(r) {
diff --git 
a/webconsole/src/test/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerHttpContextTest.java
 
b/webconsole/src/test/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerHttpContextTest.java
index cb40c490bf..efc928e5bd 100644
--- 
a/webconsole/src/test/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerHttpContextTest.java
+++ 
b/webconsole/src/test/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerHttpContextTest.java
@@ -29,6 +29,8 @@ import org.osgi.util.tracker.ServiceTracker;
 
 import static org.junit.Assert.assertEquals;
 
+import java.util.concurrent.atomic.AtomicReference;
+
 public class OsgiManagerHttpContextTest {
 
     @Test
@@ -39,7 +41,7 @@ public class OsgiManagerHttpContextTest {
         ServiceTracker<SecurityProvider, SecurityProvider> tracker = 
Mockito.mock(ServiceTracker.class);
         Mockito.when(tracker.getService()).thenReturn(provider);
 
-        OsgiManagerHttpContext ctx = new OsgiManagerHttpContext(bundle, 
tracker, "/system/console");
+        OsgiManagerHttpContext ctx = new OsgiManagerHttpContext(bundle, new 
AtomicReference<>(tracker), "/system/console");
 
         HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
         HttpServletResponse response = Mockito.mock(HttpServletResponse.class);
diff --git 
a/webconsole/src/test/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerTest.java
 
b/webconsole/src/test/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerTest.java
index 76551650dd..ee13d839d7 100644
--- 
a/webconsole/src/test/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerTest.java
+++ 
b/webconsole/src/test/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerTest.java
@@ -87,7 +87,7 @@ public class OsgiManagerTest {
 
         ServiceReference sref = Mockito.mock(ServiceReference.class);
         stc.addingService(sref);
-        assertEquals(0, updateCalled.size());
+        assertEquals(1, updateCalled.size());
 
         ServiceReference sref2 = Mockito.mock(ServiceReference.class);
         
Mockito.when(sref2.getProperty(SecurityProvider.PROPERTY_ID)).thenReturn("xyz");
@@ -95,7 +95,7 @@ public class OsgiManagerTest {
         
Mockito.when(bc.getService(sref2)).thenReturn(Mockito.mock(SecurityProvider.class));
         stc.addingService(sref2);
         assertEquals(Collections.singleton("xyz"), 
mgr.registeredSecurityProviders);
-        assertEquals(1, updateCalled.size());
+        assertEquals(2, updateCalled.size());
     }
 
     @SuppressWarnings({ "unchecked", "rawtypes" })
@@ -128,15 +128,14 @@ public class OsgiManagerTest {
         Mockito.when(sref.getProperty(Constants.SERVICE_ID)).thenReturn(3L);
         stc.removedService(sref, null);
 
-        assertEquals(2, updateCalled.size());
+        assertEquals(3, updateCalled.size());
         assertEquals(2, mgr.registeredSecurityProviders.size());
         assertTrue(mgr.registeredSecurityProviders.contains("abc"));
         assertTrue(mgr.registeredSecurityProviders.contains("xyz"));
 
-
         stc.removedService(sref2, null);
         assertEquals(Collections.singleton("abc"), 
mgr.registeredSecurityProviders);
-        assertEquals(3, updateCalled.size());
+        assertEquals(4, updateCalled.size());
     }
 
     @SuppressWarnings({ "unchecked", "rawtypes" })

Reply via email to