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" })