SLING-9336 - Hide servlet services from the outside
* filter servlet services with a hook
diff --git a/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/BundledHooks.java b/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/BundledHooks.java
new file mode 100644
index 0000000..371df4b
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/BundledHooks.java
@@ -0,0 +1,57 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ 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.sling.scripting.bundle.tracker.internal;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.hooks.service.EventListenerHook;
+import org.osgi.framework.hooks.service.FindHook;
+import org.osgi.framework.hooks.service.ListenerHook;
+import org.osgi.service.component.annotations.Component;
+
+@Component
+public class BundledHooks implements FindHook, EventListenerHook {
+ @Override
+ public void find(BundleContext context, String name, String filter, boolean allServices, Collection<ServiceReference<?>> references) {
+ if (!context.getBundle().getSymbolicName().equals("org.apache.sling.servlets.resolver")) {
+ for (Iterator<ServiceReference<?>> iter = references.iterator(); iter.hasNext();) {
+ if (iter.next().getProperty(BundledHooks.class.getName()) != null) {
+ iter.remove();
+ }
+ }
+ }
+ }
+
+
+ @Override
+ public void event(ServiceEvent event, Map<BundleContext, Collection<ListenerHook.ListenerInfo>> listeners) {
+ if (event.getServiceReference().getProperty(BundledHooks.class.getName()) != null) {
+ for (Iterator<Map.Entry<BundleContext, Collection<ListenerHook.ListenerInfo>>> entries = listeners.entrySet().iterator(); entries.hasNext();) {
+ if (!entries.next().getKey().getBundle().getSymbolicName().equals("org.apache.sling.servlets.resolver")) {
+ entries.remove();
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/BundledScriptTracker.java b/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/BundledScriptTracker.java
index 5d51820..df959d0 100644
--- a/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/BundledScriptTracker.java
+++ b/src/main/java/org/apache/sling/scripting/bundle/tracker/internal/BundledScriptTracker.java
@@ -182,6 +182,7 @@
if (executable.getPath().equals(servletCapability.getPath())) {
properties.put(ServletResolverConstants.SLING_SERVLET_PATHS, executable.getPath());
}
+ properties.put(BundledHooks.class.getName(), "true");
regs.add(
bundle.getBundleContext().registerService(
Servlet.class,
@@ -238,6 +239,7 @@
"=" + rt + "; " +
ServletResolverConstants.SLING_SERVLET_EXTENSIONS + "=" + extensions + "; " +
ServletResolverConstants.SLING_SERVLET_METHODS + "=" + methods + "}");
+ properties.put(BundledHooks.class.getName(), "true");
reg = registeringBundle.orElse(m_context).registerService(Servlet.class, new DispatcherServlet(rt), properties);
} else {
if (!new HashSet<>(Arrays.asList(PropertiesUtil
diff --git a/src/test/java/org/apache/sling/scripting/bundle/tracker/internal/BundledHooksTest.java b/src/test/java/org/apache/sling/scripting/bundle/tracker/internal/BundledHooksTest.java
new file mode 100644
index 0000000..1b974fb
--- /dev/null
+++ b/src/test/java/org/apache/sling/scripting/bundle/tracker/internal/BundledHooksTest.java
@@ -0,0 +1,130 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ 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.sling.scripting.bundle.tracker.internal;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.hooks.service.ListenerHook;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class BundledHooksTest {
+ @Test
+ public void testFindHookFiltersOther() {
+ BundledHooks hooks = new BundledHooks();
+
+ BundleContext context = mock(BundleContext.class);
+ Bundle bundle = mock(Bundle.class);
+ ServiceReference<?> ref = mock(ServiceReference.class);
+
+ when(context.getBundle()).thenReturn(bundle);
+ when(bundle.getSymbolicName()).thenReturn("org.apache.sling.foo.bar");
+ when(ref.getProperty(BundledHooks.class.getName())).thenReturn("true");
+ List<ServiceReference<?>> services = new ArrayList<>();
+
+ services.add(ref);
+ hooks.find(context, null, null, true, services);
+
+ Assert.assertTrue(services.isEmpty());
+ }
+
+ @Test
+ public void testFindHookDoesNotFilterResolver() {
+ BundledHooks hooks = new BundledHooks();
+
+ BundleContext context = mock(BundleContext.class);
+ Bundle bundle = mock(Bundle.class);
+ ServiceReference<?> ref = mock(ServiceReference.class);
+
+ when(context.getBundle()).thenReturn(bundle);
+ when(bundle.getSymbolicName()).thenReturn("org.apache.sling.servlets.resolver");
+ when(ref.getProperty(BundledHooks.class.getName())).thenReturn("true");
+ List<ServiceReference<?>> services = new ArrayList<>();
+
+ services.add(ref);
+ hooks.find(context, null, null, true, services);
+
+ Assert.assertEquals(1, services.size());
+ }
+
+ @Test
+ public void testEventHookFiltersOther() {
+ BundledHooks hooks = new BundledHooks();
+
+ ServiceEvent event = mock(ServiceEvent.class);
+
+ BundleContext context = mock(BundleContext.class);
+ Bundle bundle = mock(Bundle.class);
+ ServiceReference ref = mock(ServiceReference.class);
+
+ when(event.getServiceReference()).thenReturn(ref);
+
+ when(context.getBundle()).thenReturn(bundle);
+ when(bundle.getSymbolicName()).thenReturn("org.apache.sling.foo.bar");
+ when(ref.getProperty(BundledHooks.class.getName())).thenReturn("true");
+
+ ListenerHook.ListenerInfo info = mock(ListenerHook.ListenerInfo.class);
+ when(info.getBundleContext()).thenReturn(context);
+ Map<BundleContext, Collection<ListenerHook.ListenerInfo>> listeners = new HashMap<>();
+ listeners.put(context, new ArrayList<>(Arrays.asList(info)));
+
+ hooks.event(event, listeners);
+
+ Assert.assertTrue(listeners.isEmpty());
+ }
+
+ @Test
+ public void testEventHookDoesNotFilterResolver() {
+ BundledHooks hooks = new BundledHooks();
+
+ ServiceEvent event = mock(ServiceEvent.class);
+
+ BundleContext context = mock(BundleContext.class);
+ Bundle bundle = mock(Bundle.class);
+ ServiceReference ref = mock(ServiceReference.class);
+
+ when(event.getServiceReference()).thenReturn(ref);
+
+ when(context.getBundle()).thenReturn(bundle);
+ when(bundle.getSymbolicName()).thenReturn("org.apache.sling.servlets.resolver");
+ when(ref.getProperty(BundledHooks.class.getName())).thenReturn("true");
+
+ ListenerHook.ListenerInfo info = mock(ListenerHook.ListenerInfo.class);
+ when(info.getBundleContext()).thenReturn(context);
+ Map<BundleContext, Collection<ListenerHook.ListenerInfo>> listeners = new HashMap<>();
+ listeners.put(context, new ArrayList<>(Arrays.asList(info)));
+
+ hooks.event(event, listeners);
+
+ Assert.assertEquals(1, listeners.size());
+
+ Assert.assertEquals(1, listeners.get(context).size());
+ }
+}