This is an automated email from the ASF dual-hosted git repository. bdelacretaz pushed a commit to branch resolver-2.x in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-servlets-resolver.git
commit 26edac2f39ca2f61fc9aeeada61426b78ec8252c Author: Bertrand Delacretaz <[email protected]> AuthorDate: Thu Jul 10 17:57:42 2025 +0200 SLING-12739 - selectively hide scripts and servlets --- .../resolver/internal/SlingServletResolver.java | 23 +++- .../internal/AbsoluteResourceTypeTest.java | 140 +++++++++++++++++++++ .../internal/resourcehiding/ServletHidingTest.java | 125 ++++++++++++++++++ .../sling/servlets/resolver/it/TestServlet.java | 4 +- .../it/resourcehiding/BadPredicateNameIT.java | 59 +++++++++ .../it/resourcehiding/BasicResourceHidingIT.java | 49 ++++++++ .../it/resourcehiding/HiddenServletFallbackIT.java | 47 +++++++ .../resolver/it/resourcehiding/NoHidingIT.java | 53 ++++++++ .../it/resourcehiding/ResourceHidingITBase.java | 89 +++++++++++++ 9 files changed, 586 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/apache/sling/servlets/resolver/internal/SlingServletResolver.java b/src/main/java/org/apache/sling/servlets/resolver/internal/SlingServletResolver.java index 2eecb28..a54d8bd 100644 --- a/src/main/java/org/apache/sling/servlets/resolver/internal/SlingServletResolver.java +++ b/src/main/java/org/apache/sling/servlets/resolver/internal/SlingServletResolver.java @@ -28,6 +28,7 @@ import java.io.IOException; import java.util.Collection; import java.util.Collections; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Predicate; import javax.servlet.Servlet; import javax.servlet.ServletContext; @@ -63,6 +64,7 @@ import org.apache.sling.servlets.resolver.internal.helper.ResourceCollector; import org.apache.sling.servlets.resolver.internal.resolution.ResolutionCache; import org.apache.sling.servlets.resolver.internal.resource.MergingServletResourceProvider; import org.apache.sling.servlets.resolver.internal.resource.SlingServletConfig; +import org.jetbrains.annotations.NotNull; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.service.component.annotations.Activate; @@ -70,6 +72,8 @@ import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Deactivate; import org.osgi.service.component.annotations.Modified; import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; import org.osgi.service.metatype.annotations.Designate; import org.osgi.util.tracker.ServiceTracker; import org.slf4j.Logger; @@ -129,6 +133,13 @@ public class SlingServletResolver private final ThreadLocal<ResourceResolver> perThreadScriptResolver = new ThreadLocal<>(); + @Reference( + target = "(name=sling.servlet.resolver.resource.hiding)", + policy = ReferencePolicy.DYNAMIC, + cardinality = ReferenceCardinality.OPTIONAL + ) + private volatile Predicate<String> resourceHidingPredicate; + /** * The allowed execution paths. */ @@ -442,6 +453,15 @@ public class SlingServletResolver return res; } + /** @return true if the given Resource is hidden by our resourceHidingPredicate */ + private boolean isHidden(@NotNull Resource r) { + final boolean result = r != null && resourceHidingPredicate != null && resourceHidingPredicate.test(r.getPath()); + if(result && LOGGER.isDebugEnabled()) { + LOGGER.debug("Resource hidden by resource hiding predicate: {}", r.getPath()); + } + return result; + } + /** * Resolve an appropriate servlet for a given request and resource type * using the provided ResourceResolver @@ -468,7 +488,7 @@ public class SlingServletResolver final String scriptPath = ResourceUtil.normalize(scriptNameOrResourceType); if (scriptPath != null && isPathAllowed(scriptPath, this.executionPaths.get()) ) { final Resource res = AbstractResourceCollector.getResourceOrNull(resolver,scriptPath,useResourceCaching); - servlet = this.getServlet(res); + servlet = isHidden(res) ? null : this.getServlet(res); if (servlet != null && !pathBasedServletAcceptor.accept(request, servlet)) { if(LOGGER.isDebugEnabled()) { LOGGER.debug("Servlet {} rejected by {} returning FORBIDDEN status", RequestUtil.getServletName(servlet), @@ -536,6 +556,7 @@ public class SlingServletResolver } final Collection<Resource> candidates = locationUtil.getServlets(resolver, localCache.getScriptEngineExtensions()); + candidates.removeIf(r -> isHidden(r)); if (LOGGER.isDebugEnabled()) { if (candidates.isEmpty()) { diff --git a/src/test/java/org/apache/sling/servlets/resolver/internal/AbsoluteResourceTypeTest.java b/src/test/java/org/apache/sling/servlets/resolver/internal/AbsoluteResourceTypeTest.java new file mode 100644 index 0000000..2c22511 --- /dev/null +++ b/src/test/java/org/apache/sling/servlets/resolver/internal/AbsoluteResourceTypeTest.java @@ -0,0 +1,140 @@ +/* + * 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.servlets.resolver.internal; + +import org.apache.sling.api.SlingHttpServletRequest; +import org.apache.sling.api.request.RequestPathInfo; +import org.apache.sling.api.request.RequestProgressTracker; +import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ResourceResolver; +import org.junit.Test; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.junit.Assert.*; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Predicate; + +import javax.servlet.Servlet; + +import org.apache.sling.api.resource.PersistenceException; +import org.osgi.framework.Bundle; +import org.apache.sling.servlets.resolver.internal.resource.MockServletResource; + +public class AbsoluteResourceTypeTest extends SlingServletResolverTestBase { + + private static final String absolutePath = "/absolute/resource/type.servlet"; + + @Override + protected void defineTestServlets(Bundle bundle) { + // Create a mock servlet for testing + final Servlet testServlet = mock(Servlet.class); + final Map<String, Object> properties = new HashMap<>(); + properties.put(MockServletResource.PROP_SERVLET, testServlet); + + // Register the servlet at an absolute path with .servlet suffix + try { + Resource root = mockResourceResolver.getResource("/"); + // Create intermediate directories + Resource absolute = mockResourceResolver.create(root, "absolute", null); + Resource resource = mockResourceResolver.create(absolute, "resource", null); + // Create the resource with .servlet suffix so it becomes a MockServletResource + mockResourceResolver.create(resource, "type.servlet", properties); + } catch (PersistenceException e) { + fail("Failed to create test servlet resource: " + e.getMessage()); + } + } + + private Servlet resolveFromPath(String path) throws Exception { + // Setup test data + final SlingHttpServletRequest request = mock(SlingHttpServletRequest.class); + final Resource resource = mock(Resource.class); + final RequestProgressTracker tracker = mock(RequestProgressTracker.class); + final RequestPathInfo pathInfo = mock(RequestPathInfo.class); + + // Mock the request + when(request.getRequestProgressTracker()).thenReturn(tracker); + when(request.getResource()).thenReturn(resource); + when(request.getRequestPathInfo()).thenReturn(pathInfo); + when(pathInfo.getExtension()).thenReturn("html"); + when(pathInfo.getSelectors()).thenReturn(new String[0]); + when(resource.getResourceType()).thenReturn(absolutePath); + + // Set up the shared script resolver to use our mock resource resolver + Field sharedScriptResolverField = servletResolver.getClass().getDeclaredField("sharedScriptResolver"); + sharedScriptResolverField.setAccessible(true); + @SuppressWarnings("unchecked") + AtomicReference<ResourceResolver> sharedScriptResolver = (AtomicReference<ResourceResolver>) sharedScriptResolverField + .get(servletResolver); + sharedScriptResolver.set(mockResourceResolver); + + // Use reflection to call the private resolveServletInternal method + Method resolveServletInternalMethod = servletResolver.getClass().getDeclaredMethod( + "resolveServletInternal", + SlingHttpServletRequest.class, + Resource.class, + String.class, + ResourceResolver.class); + resolveServletInternalMethod.setAccessible(true); + + return (Servlet)resolveServletInternalMethod.invoke( + servletResolver, + request, + resource, + path, + mockResourceResolver); + } + + @Test + public void testAbsolutePath() throws Exception { + final Servlet s = resolveFromPath(absolutePath); + assertNotNull("Expecting a Servlet for valid absolute path", s); + } + + @Test + public void testAbsolutePathHiddenByPredicate() throws Exception { + final Predicate<String> hideAbsolutePath = path -> absolutePath.equals(path); + final Field f = servletResolver.getClass().getDeclaredField("resourceHidingPredicate"); + f.setAccessible(true); + f.set(servletResolver, hideAbsolutePath); + try { + final Servlet s = resolveFromPath(absolutePath); + assertNull("Expecting null when hidden by our Predicate", s); + } finally { + f.set(servletResolver, null); + } + } + + @Test + public void testNonExistingPath() throws Exception { + final Servlet s = resolveFromPath("/does/not/exist"); + assertNull("Expecting null for non-existent absolute path", s); + } + + @Test + public void testRelativePath() throws Exception { + final Servlet s = resolveFromPath("relative/path"); + assertNull("Expecting null for relative path", s); + } +} diff --git a/src/test/java/org/apache/sling/servlets/resolver/internal/resourcehiding/ServletHidingTest.java b/src/test/java/org/apache/sling/servlets/resolver/internal/resourcehiding/ServletHidingTest.java new file mode 100644 index 0000000..55577da --- /dev/null +++ b/src/test/java/org/apache/sling/servlets/resolver/internal/resourcehiding/ServletHidingTest.java @@ -0,0 +1,125 @@ +/* + * 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.servlets.resolver.internal.resourcehiding; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Predicate; + +import javax.servlet.Servlet; + +import org.apache.sling.api.resource.PersistenceException; +import org.apache.sling.api.resource.ResourceUtil; +import org.apache.sling.api.servlets.SlingSafeMethodsServlet; +import org.apache.sling.commons.testing.sling.MockSlingHttpServletRequest; +import org.apache.sling.servlets.resolver.internal.SlingServletResolverTestBase; +import org.apache.sling.servlets.resolver.internal.helper.HelperTestBase; +import org.apache.sling.servlets.resolver.internal.resource.MockServletResource; +import org.junit.Test; +import org.osgi.framework.Bundle; + +public class ServletHidingTest extends SlingServletResolverTestBase { + + private static final String TEST_ID = UUID.randomUUID().toString(); + + protected static class TestServlet extends SlingSafeMethodsServlet { + private final String id; + + public TestServlet(String id) { + this.id = id; + } + + public String toString() { + return id; + } + } + + private void setServletHidingFilter(Predicate<String> predicate) throws Exception { + final Field predicateField = servletResolver.getClass().getDeclaredField("resourceHidingPredicate"); + predicateField.setAccessible(true); + predicateField.set(servletResolver, predicate); + } + + private void registerServlet(String id, String resourceType) { + final String path = "/" + resourceType + "/" + ResourceUtil.getName(resourceType) + ".servlet"; + Map<String, Object> props = new HashMap<>(); + props.put(MockServletResource.PROP_SERVLET, new TestServlet(id)); + HelperTestBase.addOrReplaceResource(mockResourceResolver, path, props); + try { + mockResourceResolver.commit(); + } catch (PersistenceException e) { + fail(e.toString()); + } + } + + private Servlet resolveServlet() { + MockSlingHttpServletRequest req = new MockSlingHttpServletRequest( + MockSlingHttpServletRequest.RESOURCE_TYPE, null, "html", null, null); + req.setResourceResolver(mockResourceResolver); + return servletResolver.resolveServlet(req); + } + + @Override + protected void defineTestServlets(Bundle bundle) { + registerServlet(TEST_ID, MockSlingHttpServletRequest.RESOURCE_TYPE); + } + + private void assertResolvesToTestServletId(String info, boolean expectMatch) { + final Servlet s = resolveServlet(); + assertNotNull("Expecting non-null Servlet", s); + if(expectMatch) { + assertEquals("Expecting our test servlet (" + info + ")", TEST_ID, s.toString()); + } else { + assertNotEquals("NOT expecting our test servlet (" + info + ")", TEST_ID, s.toString()); + } + } + + @Test + public void testHideAndSeek() throws Exception { + final AtomicBoolean hide = new AtomicBoolean(); + final Predicate<String> pred = (ignoredPath) -> hide.get(); + + // No filtering + setServletHidingFilter(null); + assertResolvesToTestServletId("before hiding", true); + + // Filter with our predicate + setServletHidingFilter(pred); + hide.set(true); + assertResolvesToTestServletId("hidden by our Predicate", false); + hide.set(false); + assertResolvesToTestServletId("Predicate active but returns false", true); + + // Back to no filtering, (paranoid) check that it's really gone + setServletHidingFilter(null); + hide.set(false); + assertResolvesToTestServletId("No Predicate set, hide=false", true); + hide.set(true); + assertResolvesToTestServletId("No Predicate set, hide=true", true); + } + +} diff --git a/src/test/java/org/apache/sling/servlets/resolver/it/TestServlet.java b/src/test/java/org/apache/sling/servlets/resolver/it/TestServlet.java index 39e1d08..181307f 100644 --- a/src/test/java/org/apache/sling/servlets/resolver/it/TestServlet.java +++ b/src/test/java/org/apache/sling/servlets/resolver/it/TestServlet.java @@ -56,12 +56,12 @@ public class TestServlet extends HttpServlet { doGet(req, resp); } - TestServlet with(String key, Object value) { + public TestServlet with(String key, Object value) { properties.put(key, value); return this; } - void register(BundleContext context) { + public void register(BundleContext context) { context.registerService(Servlet.class.getName(), this, properties); } } \ No newline at end of file diff --git a/src/test/java/org/apache/sling/servlets/resolver/it/resourcehiding/BadPredicateNameIT.java b/src/test/java/org/apache/sling/servlets/resolver/it/resourcehiding/BadPredicateNameIT.java new file mode 100644 index 0000000..d8e8f7b --- /dev/null +++ b/src/test/java/org/apache/sling/servlets/resolver/it/resourcehiding/BadPredicateNameIT.java @@ -0,0 +1,59 @@ +/* + * 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.servlets.resolver.it.resourcehiding; + +import static org.junit.Assert.assertEquals; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.ops4j.pax.exam.junit.PaxExam; +import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy; +import org.ops4j.pax.exam.spi.reactors.PerClass; + +@RunWith(PaxExam.class) +@ExamReactorStrategy(PerClass.class) +public class BadPredicateNameIT extends ResourceHidingITBase { + + @Before + public void setupPredicate() { + registerPredicate(path -> true, "invalid.name.that.causes.the.predicate.to.be.ignored"); + } + + @After + public void checkNothingHidden() { + assertEquals(0, hiddenResourcesCount); + } + + @Test + public void testExtApresent() throws Exception { + assertTestServlet("/." + EXT_A, EXT_A); + } + + @Test + public void testExtBpresent() throws Exception { + assertTestServlet("/." + EXT_B, EXT_B); + } + + @Test + public void testSelApresent() throws Exception { + assertTestServlet("/." + SEL_A + "." + EXT_A, SEL_A); + } +} diff --git a/src/test/java/org/apache/sling/servlets/resolver/it/resourcehiding/BasicResourceHidingIT.java b/src/test/java/org/apache/sling/servlets/resolver/it/resourcehiding/BasicResourceHidingIT.java new file mode 100644 index 0000000..10afb48 --- /dev/null +++ b/src/test/java/org/apache/sling/servlets/resolver/it/resourcehiding/BasicResourceHidingIT.java @@ -0,0 +1,49 @@ +/* + * 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.servlets.resolver.it.resourcehiding; + +import static org.junit.Assert.assertEquals; + +import javax.servlet.http.HttpServletResponse; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.ops4j.pax.exam.junit.PaxExam; +import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy; +import org.ops4j.pax.exam.spi.reactors.PerClass; + +@RunWith(PaxExam.class) +@ExamReactorStrategy(PerClass.class) +public class BasicResourceHidingIT extends ResourceHidingITBase { + + @Before + public void setupPredicate() { + registerPredicate((path) -> path.contains(EXT_B)); + } + + @Test + public void testOnlyApresent() throws Exception { + assertEquals(0, hiddenResourcesCount); + assertTestServlet("/." + EXT_A, EXT_A); + assertEquals(0, hiddenResourcesCount); + assertTestServlet("/." + EXT_B, HttpServletResponse.SC_NOT_FOUND); + assertEquals(1, hiddenResourcesCount); + } +} \ No newline at end of file diff --git a/src/test/java/org/apache/sling/servlets/resolver/it/resourcehiding/HiddenServletFallbackIT.java b/src/test/java/org/apache/sling/servlets/resolver/it/resourcehiding/HiddenServletFallbackIT.java new file mode 100644 index 0000000..c891e7c --- /dev/null +++ b/src/test/java/org/apache/sling/servlets/resolver/it/resourcehiding/HiddenServletFallbackIT.java @@ -0,0 +1,47 @@ +/* + * 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.servlets.resolver.it.resourcehiding; + +import static org.junit.Assert.assertEquals; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.ops4j.pax.exam.junit.PaxExam; +import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy; +import org.ops4j.pax.exam.spi.reactors.PerClass; + +@RunWith(PaxExam.class) +@ExamReactorStrategy(PerClass.class) +public class HiddenServletFallbackIT extends ResourceHidingITBase { + + @Before + public void setupPredicate() { + registerPredicate((path) -> path.contains(SEL_A)); + } + + @Test + public void testFallbackToExtA() throws Exception { + assertEquals(0, hiddenResourcesCount); + assertTestServlet("/." + SEL_A + "." + EXT_A, EXT_A); + assertEquals(1, hiddenResourcesCount); + assertTestServlet("/." + EXT_A, EXT_A); + assertEquals(1, hiddenResourcesCount); + } +} \ No newline at end of file diff --git a/src/test/java/org/apache/sling/servlets/resolver/it/resourcehiding/NoHidingIT.java b/src/test/java/org/apache/sling/servlets/resolver/it/resourcehiding/NoHidingIT.java new file mode 100644 index 0000000..4fae143 --- /dev/null +++ b/src/test/java/org/apache/sling/servlets/resolver/it/resourcehiding/NoHidingIT.java @@ -0,0 +1,53 @@ +/* + * 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.servlets.resolver.it.resourcehiding; + +import static org.junit.Assert.assertEquals; + +import org.junit.After; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.ops4j.pax.exam.junit.PaxExam; +import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy; +import org.ops4j.pax.exam.spi.reactors.PerClass; + +@RunWith(PaxExam.class) +@ExamReactorStrategy(PerClass.class) +public class NoHidingIT extends ResourceHidingITBase { + + @After + public void checkNothingHidden() { + assertEquals(0, hiddenResourcesCount); + } + + @Test + public void testExtApresent() throws Exception { + assertTestServlet("/." + EXT_A, EXT_A); + } + + @Test + public void testExtBpresent() throws Exception { + assertTestServlet("/." + EXT_B, EXT_B); + } + + @Test + public void testSelApresent() throws Exception { + assertTestServlet("/." + SEL_A + "." + EXT_A, SEL_A); + } +} diff --git a/src/test/java/org/apache/sling/servlets/resolver/it/resourcehiding/ResourceHidingITBase.java b/src/test/java/org/apache/sling/servlets/resolver/it/resourcehiding/ResourceHidingITBase.java new file mode 100644 index 0000000..5d8631c --- /dev/null +++ b/src/test/java/org/apache/sling/servlets/resolver/it/resourcehiding/ResourceHidingITBase.java @@ -0,0 +1,89 @@ +/* + * 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.servlets.resolver.it.resourcehiding; + +import java.util.Hashtable; +import java.util.UUID; +import java.util.function.Predicate; + +import org.apache.sling.servlets.resolver.it.ServletResolverTestSupport; +import org.apache.sling.servlets.resolver.it.TestServlet; +import org.jetbrains.annotations.Nullable; +import org.junit.Before; + +/** Base for all our hiding tests, so that they all use the same set of servlets */ +public class ResourceHidingITBase extends ServletResolverTestSupport { + + protected final static String EXT_A = "EXT_A" + UUID.randomUUID(); + protected final static String EXT_B = "EXT_B" + UUID.randomUUID(); + protected final static String SEL_A = "SEL_A" + UUID.randomUUID(); + protected int hiddenResourcesCount = 0; + + public final static String PREDICATE_NAME = "sling.servlet.resolver.resource.hiding"; + + @Before + public void reset() { + hiddenResourcesCount = 0; + } + + @Before + public void setupTestServletsAndResourceHiding() throws Exception { + // Register two servlets differing only in extensions + new TestServlet(EXT_A) + .with(P_RESOURCE_TYPES, RT_DEFAULT) + .with(P_METHODS, M_GET) + .with(P_EXTENSIONS, EXT_A) + .register(bundleContext); + + new TestServlet(EXT_B) + .with(P_RESOURCE_TYPES, RT_DEFAULT) + .with(P_METHODS, M_GET) + .with(P_EXTENSIONS, EXT_B) + .register(bundleContext); + + // And one more specific servlet, that will fall back + // to EXT_A when hidden + new TestServlet(SEL_A) + .with(P_RESOURCE_TYPES, RT_DEFAULT) + .with(P_METHODS, M_GET) + .with(P_EXTENSIONS, EXT_A) + .with(P_SELECTORS, SEL_A) + .register(bundleContext); + } + + protected void registerPredicate(Predicate<String> p) { + registerPredicate(p, null); + } + + protected void registerPredicate(Predicate<String> p, @Nullable String name) { + final Predicate<String> wrappedPredicate = new Predicate<String>() { + @Override + public boolean test(String path) { + final boolean result = p.test(path); + if(result) { + hiddenResourcesCount++; + } + return result; + } + }; + final Hashtable<String,String> props = new Hashtable<>(); + props.put("name", name != null ? name : PREDICATE_NAME); + bundleContext.registerService(Predicate.class.getName(), wrappedPredicate, props); + } +} \ No newline at end of file
