This is an automated email from the ASF dual-hosted git repository.
cziegeler pushed a commit to branch SLING-9622
in repository
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-auth-core.git
The following commit(s) were added to refs/heads/SLING-9622 by this push:
new 45fff72 SLING-9622 : Handle mapping within auth.core bundle and
update auth requirements when mapping changes
45fff72 is described below
commit 45fff72707a83ec252c24ad550acd2d06cd0cfec
Author: Carsten Ziegeler <[email protected]>
AuthorDate: Wed Aug 5 08:58:35 2020 +0200
SLING-9622 : Handle mapping within auth.core bundle and update auth
requirements when mapping changes
---
pom.xml | 12 +-
.../core/impl/AuthenticationHandlerHolder.java | 6 +-
.../sling/auth/core/impl/PathBasedHolder.java | 10 +-
.../sling/auth/core/impl/PathBasedHolderCache.java | 143 +++++++++------------
.../sling/auth/core/impl/SlingAuthenticator.java | 4 +-
.../impl/SlingAuthenticatorServiceListener.java | 66 +++++++---
.../SlingAuthenticatorServiceListenerTest.java | 69 +++++++++-
7 files changed, 193 insertions(+), 117 deletions(-)
diff --git a/pom.xml b/pom.xml
index f7d1a1a..97d5350 100644
--- a/pom.xml
+++ b/pom.xml
@@ -75,9 +75,15 @@
<scope>provided</scope>
</dependency>
<dependency>
- <groupId>org.apache.sling</groupId>
- <artifactId>org.apache.sling.commons.osgi</artifactId>
- <version>2.2.0</version>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.util.function</artifactId>
+ <version>1.0.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.util.converter</artifactId>
+ <version>1.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
diff --git
a/src/main/java/org/apache/sling/auth/core/impl/AuthenticationHandlerHolder.java
b/src/main/java/org/apache/sling/auth/core/impl/AuthenticationHandlerHolder.java
index 066362b..e7ea528 100644
---
a/src/main/java/org/apache/sling/auth/core/impl/AuthenticationHandlerHolder.java
+++
b/src/main/java/org/apache/sling/auth/core/impl/AuthenticationHandlerHolder.java
@@ -28,8 +28,8 @@ import org.apache.sling.auth.core.AuthUtil;
import org.apache.sling.auth.core.spi.AuthenticationFeedbackHandler;
import org.apache.sling.auth.core.spi.AuthenticationHandler;
import org.apache.sling.auth.core.spi.AuthenticationInfo;
-import org.apache.sling.commons.osgi.PropertiesUtil;
import org.osgi.framework.ServiceReference;
+import org.osgi.util.converter.Converters;
/**
* The <code>AuthenticationHandlerHolder</code> class represents an
@@ -53,11 +53,11 @@ final class AuthenticationHandlerHolder extends
final ServiceReference serviceReference) {
super(fullPath, serviceReference);
- final String browserOnly =
PropertiesUtil.toString(serviceReference.getProperty(AuthConstants.AUTH_HANDLER_BROWSER_ONLY),
null);
+ final String browserOnly =
Converters.standardConverter().convert(serviceReference.getProperty(AuthConstants.AUTH_HANDLER_BROWSER_ONLY)).to(String.class);
// assign the fields
this.handler = handler;
- this.authType =
PropertiesUtil.toString(serviceReference.getProperty(TYPE_PROPERTY), null);
+ this.authType =
Converters.standardConverter().convert(serviceReference.getProperty(TYPE_PROPERTY)).to(String.class);
this.browserOnlyRequestCredentials =
"true".equalsIgnoreCase(browserOnly)
|| "yes".equalsIgnoreCase(browserOnly);
}
diff --git a/src/main/java/org/apache/sling/auth/core/impl/PathBasedHolder.java
b/src/main/java/org/apache/sling/auth/core/impl/PathBasedHolder.java
index 2fc09eb..8d605b1 100644
--- a/src/main/java/org/apache/sling/auth/core/impl/PathBasedHolder.java
+++ b/src/main/java/org/apache/sling/auth/core/impl/PathBasedHolder.java
@@ -18,9 +18,9 @@
*/
package org.apache.sling.auth.core.impl;
-import org.apache.sling.commons.osgi.PropertiesUtil;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
+import org.osgi.util.converter.Converters;
/**
* The <code>PathBasedHolder</code> provides the basic abstraction for managing
@@ -135,15 +135,13 @@ public abstract class PathBasedHolder implements
Comparable<PathBasedHolder> {
return "Apache Sling Request Authenticator";
}
- final String descr = PropertiesUtil.toString(
- serviceReference.getProperty(Constants.SERVICE_DESCRIPTION), null);
+ final String descr =
Converters.standardConverter().convert(serviceReference.getProperty(Constants.SERVICE_DESCRIPTION)).to(String.class);
if (descr != null) {
return descr;
}
- return "Service "
- + PropertiesUtil.toString(
- serviceReference.getProperty(Constants.SERVICE_ID), "unknown");
+ final String id =
Converters.standardConverter().convert(serviceReference.getProperty(Constants.SERVICE_ID)).defaultValue("unknown").to(String.class);
+ return "Service ".concat(id);
}
/**
diff --git
a/src/main/java/org/apache/sling/auth/core/impl/PathBasedHolderCache.java
b/src/main/java/org/apache/sling/auth/core/impl/PathBasedHolderCache.java
index ab0982d..e8def27 100644
--- a/src/main/java/org/apache/sling/auth/core/impl/PathBasedHolderCache.java
+++ b/src/main/java/org/apache/sling/auth/core/impl/PathBasedHolderCache.java
@@ -20,120 +20,95 @@ package org.apache.sling.auth.core.impl;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.http.HttpServletRequest;
public class PathBasedHolderCache<Type extends PathBasedHolder> {
- private final Map<String, Map<String, SortedSet<Type>>> cache = new
HashMap<String, Map<String, SortedSet<Type>>>();
-
- /** Read/write lock to synchronize the cache access. */
- private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
+ /**
+ * The cache is a concurrent map of concurrent maps.
+ * As the final value, the sorted set is replaced on each change, reading
of the
+ * cache does not need to be synchronized. Updating of the cache is
synchronized.
+ */
+ private final Map<String, Map<String, SortedSet<Type>>> cache = new
ConcurrentHashMap<>();
public void clear() {
- this.rwLock.writeLock().lock();
- try {
- cache.clear();
- } finally {
- this.rwLock.writeLock().unlock();
- }
+ cache.clear();
}
- public void addHolder(final Type holder) {
- this.rwLock.writeLock().lock();
- try {
-
- final Map<String, SortedSet<Type>> byHostMap =
cache.computeIfAbsent(holder.protocol, protocol -> new HashMap<>());
+ public synchronized void addHolder(final Type holder) {
+ final Map<String, SortedSet<Type>> byHostMap =
cache.computeIfAbsent(holder.protocol, protocol -> new ConcurrentHashMap<>());
- final SortedSet<Type> byPathSet = new TreeSet<Type>();
+ final SortedSet<Type> byPathSet = new TreeSet<Type>();
- // preset with current list
- final SortedSet<Type> currentPathSet = byHostMap.get(holder.host);
- if (currentPathSet != null) {
- byPathSet.addAll(currentPathSet);
- }
+ // preset with current list
+ final SortedSet<Type> currentPathSet = byHostMap.get(holder.host);
+ if (currentPathSet != null) {
+ byPathSet.addAll(currentPathSet);
+ }
- // add the new holder
- byPathSet.add(holder);
+ // add the new holder
+ byPathSet.add(holder);
- // replace old set with new set
- byHostMap.put(holder.host, byPathSet);
- } finally {
- this.rwLock.writeLock().unlock();
- }
+ // replace old set with new set
+ byHostMap.put(holder.host, byPathSet);
}
- public void removeHolder(final Type holder) {
- this.rwLock.writeLock().lock();
- try {
- final Map<String, SortedSet<Type>> byHostMap =
cache.get(holder.protocol);
- if (byHostMap != null) {
- final SortedSet<Type> byPathSet = byHostMap.get(holder.host);
- if (byPathSet != null) {
-
- // create a new set without the removed holder
- final SortedSet<Type> set = new TreeSet<Type>();
- set.addAll(byPathSet);
- set.remove(holder);
-
- // replace the old set with the new one (or remove if
empty)
- if (set.isEmpty()) {
- byHostMap.remove(holder.host);
- } else {
- byHostMap.put(holder.host, set);
- }
+ public synchronized void removeHolder(final Type holder) {
+ final Map<String, SortedSet<Type>> byHostMap =
cache.get(holder.protocol);
+ if (byHostMap != null) {
+ final SortedSet<Type> byPathSet = byHostMap.get(holder.host);
+ if (byPathSet != null) {
+
+ // create a new set without the removed holder
+ final SortedSet<Type> set = new TreeSet<Type>();
+ set.addAll(byPathSet);
+ set.remove(holder);
+
+ // replace the old set with the new one (or remove if empty)
+ if (set.isEmpty()) {
+ byHostMap.remove(holder.host);
+ } else {
+ byHostMap.put(holder.host, set);
}
}
- } finally {
- this.rwLock.writeLock().unlock();
}
}
public Collection<Type>[] findApplicableHolders(final HttpServletRequest
request) {
- this.rwLock.readLock().lock();
- try {
- final String hostname = request.getServerName()
- + (request.getServerPort() != 80 && request.getServerPort()
!= 443
- ? ":" + request.getServerPort()
- : "");
-
- @SuppressWarnings("unchecked")
- final SortedSet<Type>[] result = new SortedSet[4];
-
- final Map<String, SortedSet<Type>> byHostMap =
cache.get(request.getScheme());
- if ( byHostMap != null ) {
- result[0] = byHostMap.get(hostname);
- result[1] = byHostMap.get("");
- }
- final Map<String, SortedSet<Type>> defaultByHostMap =
cache.get("");
- if ( defaultByHostMap != null ) {
- result[2] = defaultByHostMap.get(hostname);
- result[3] = defaultByHostMap.get("");
- }
- return result;
- } finally {
- this.rwLock.readLock().unlock();
+ final String hostname = request.getServerName()
+ + (request.getServerPort() != 80 && request.getServerPort() !=
443
+ ? ":" + request.getServerPort()
+ : "");
+
+ @SuppressWarnings("unchecked")
+ final SortedSet<Type>[] result = new SortedSet[4];
+
+ final Map<String, SortedSet<Type>> byHostMap =
cache.get(request.getScheme());
+ if ( byHostMap != null ) {
+ result[0] = byHostMap.get(hostname);
+ result[1] = byHostMap.get("");
}
+ final Map<String, SortedSet<Type>> defaultByHostMap = cache.get("");
+ if ( defaultByHostMap != null ) {
+ result[2] = defaultByHostMap.get(hostname);
+ result[3] = defaultByHostMap.get("");
+ }
+ return result;
}
public List<Type> getHolders() {
- this.rwLock.readLock().lock();
- try {
- final List<Type> result = new ArrayList<Type>();
- for (Map<String, SortedSet<Type>> byHostEntry : cache.values()) {
- for (SortedSet<Type> holderSet : byHostEntry.values()) {
- result.addAll(holderSet);
- }
+ final List<Type> result = new ArrayList<Type>();
+ for (Map<String, SortedSet<Type>> byHostEntry : cache.values()) {
+ for (SortedSet<Type> holderSet : byHostEntry.values()) {
+ result.addAll(holderSet);
}
- return result;
- } finally {
- this.rwLock.readLock().unlock();
}
+ return result;
}
}
diff --git
a/src/main/java/org/apache/sling/auth/core/impl/SlingAuthenticator.java
b/src/main/java/org/apache/sling/auth/core/impl/SlingAuthenticator.java
index 914099c..6ad51bd 100644
--- a/src/main/java/org/apache/sling/auth/core/impl/SlingAuthenticator.java
+++ b/src/main/java/org/apache/sling/auth/core/impl/SlingAuthenticator.java
@@ -60,7 +60,6 @@ import org.apache.sling.auth.core.spi.AuthenticationHandler;
import org.apache.sling.auth.core.spi.AuthenticationInfo;
import org.apache.sling.auth.core.spi.AuthenticationInfoPostProcessor;
import org.apache.sling.auth.core.spi.DefaultAuthenticationFeedbackHandler;
-import org.apache.sling.commons.osgi.PropertiesUtil;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
@@ -85,6 +84,7 @@ import org.osgi.service.metatype.annotations.AttributeType;
import org.osgi.service.metatype.annotations.Designate;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;
import org.osgi.service.metatype.annotations.Option;
+import org.osgi.util.converter.Converters;
import org.osgi.util.tracker.ServiceTracker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -1720,7 +1720,7 @@ public class SlingAuthenticator implements Authenticator,
}
private void bindAuthHandler(final Object handler, final
ServiceReference ref) {
- final String paths[] =
PropertiesUtil.toStringArray(ref.getProperty(AuthenticationHandler.PATH_PROPERTY));
+ final String paths[] =
Converters.standardConverter().convert(ref.getProperty(AuthenticationHandler.PATH_PROPERTY)).to(String[].class);
if (paths != null && paths.length > 0) {
// generate the holders
diff --git
a/src/main/java/org/apache/sling/auth/core/impl/SlingAuthenticatorServiceListener.java
b/src/main/java/org/apache/sling/auth/core/impl/SlingAuthenticatorServiceListener.java
index ca967f6..46e0958 100644
---
a/src/main/java/org/apache/sling/auth/core/impl/SlingAuthenticatorServiceListener.java
+++
b/src/main/java/org/apache/sling/auth/core/impl/SlingAuthenticatorServiceListener.java
@@ -36,7 +36,6 @@ import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.api.resource.mapping.ResourceMapper;
import org.apache.sling.auth.core.AuthConstants;
-import org.apache.sling.commons.osgi.PropertiesUtil;
import org.osgi.framework.AllServiceListener;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
@@ -47,6 +46,7 @@ import org.osgi.framework.ServiceRegistration;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventConstants;
import org.osgi.service.event.EventHandler;
+import org.osgi.util.converter.Converters;
/**
* Service listener keeping track of all auth requirements registered in
@@ -107,6 +107,12 @@ public class SlingAuthenticatorServiceListener implements
AllServiceListener, Ev
return null;
}
+ /**
+ * Create a new listener
+ * @param authRequiredCache The cache
+ * @param executor For updating
+ * @param factory The resource resolver factory
+ */
private SlingAuthenticatorServiceListener(final
PathBasedHolderCache<AuthenticationRequirementHolder> authRequiredCache,
final Executor executor,
final ResourceResolverFactory factory) {
@@ -135,6 +141,9 @@ public class SlingAuthenticatorServiceListener implements
AllServiceListener, Ev
}
}
+ /**
+ * Handle service registration updates (add, modified, remove)
+ */
@Override
public void serviceChanged(final ServiceEvent event) {
// modification of service properties, unregistration of the
@@ -158,6 +167,9 @@ public class SlingAuthenticatorServiceListener implements
AllServiceListener, Ev
schedule();
}
+ /**
+ * Handle a mapping event
+ */
@Override
public void handleEvent(final Event event) {
queue(UPDATE, null);
@@ -184,6 +196,10 @@ public class SlingAuthenticatorServiceListener implements
AllServiceListener, Ev
}
}
+ /**
+ * Process the queue, one by one
+ * Lazy creation of resource resolver / resource mapper
+ */
private void processQueue() {
ResourceResolver resolver = null;
ResourceMapper mapper = null;
@@ -223,11 +239,20 @@ public class SlingAuthenticatorServiceListener implements
AllServiceListener, Ev
}
}
+ /**
+ * Process a single action
+ * @param mapper
+ * @param id
+ * @param action
+ */
private void process(final ResourceMapper mapper, final Long id, final
Action action) {
switch ( action.type ) {
- case ADDED : this.addService(mapper, action.reference); break;
- case REMOVED :
this.removeService((Long)action.reference.getProperty(Constants.SERVICE_ID));
break;
- case MODIFIED : this.modifiedService(mapper, action.reference);
break;
+ case ADDED : this.addService(mapper, action.reference);
+ break;
+ case REMOVED :
this.removeService((Long)action.reference.getProperty(Constants.SERVICE_ID));
+ break;
+ case MODIFIED : this.modifiedService(mapper, action.reference);
+ break;
case UPDATE: final List<AuthenticationRequirementHolder> list =
props.get(id);
if (!list.isEmpty() ) {
this.modifiedService(mapper,
list.get(0).serviceReference);
@@ -261,17 +286,20 @@ public class SlingAuthenticatorServiceListener implements
AllServiceListener, Ev
authReq = authReq.trim();
if ( authReq.length() > 0 ) {
final String prefix;
- if ( authReq.startsWith("+") || authReq.startsWith("-") ) {
- prefix = authReq.substring(0, 1);
+ if ( authReq.startsWith("+") ) {
+ prefix = null;
+ authReq = authReq.substring(1);
+ } else if ( authReq.startsWith("-") ) {
+ prefix = "-";
+ authReq = authReq.substring(1);
} else {
- prefix = "+";
- authReq = prefix.concat(authReq);
+ prefix = null;
}
- paths.add(authReq);
+ paths.add(prefix == null ? authReq :
prefix.concat(authReq));
if ( mapper != null ) {
- for(final String mappedPath :
mapper.getAllMappings(authReq.substring(1))) {
- paths.add(prefix.concat(mappedPath));
+ for(final String mappedPath :
mapper.getAllMappings(authReq)) {
+ paths.add(prefix == null ? mappedPath :
prefix.concat(mappedPath));
}
}
}
@@ -285,8 +313,8 @@ public class SlingAuthenticatorServiceListener implements
AllServiceListener, Ev
* @param ref The service reference
*/
private void addService(final ResourceMapper mapper, final
ServiceReference<?> ref) {
- final String[] authReqPaths =
PropertiesUtil.toStringArray(ref.getProperty(AuthConstants.AUTH_REQUIREMENTS));
- if ( authReqPaths != null ) {
+ final String[] authReqPaths =
Converters.standardConverter().convert(ref.getProperty(AuthConstants.AUTH_REQUIREMENTS)).to(String[].class);
+ if ( authReqPaths.length > 0 ) {
final Long id = (Long)ref.getProperty(Constants.SERVICE_ID);
final Set<String> paths = buildPathsSet(mapper, authReqPaths);
@@ -309,9 +337,9 @@ public class SlingAuthenticatorServiceListener implements
AllServiceListener, Ev
* @param ref The service reference
*/
private void modifiedService(final ResourceMapper mapper, final
ServiceReference<?> ref) {
- final String[] authReqPaths =
PropertiesUtil.toStringArray(ref.getProperty(AuthConstants.AUTH_REQUIREMENTS));
+ final String[] authReqPaths =
Converters.standardConverter().convert(ref.getProperty(AuthConstants.AUTH_REQUIREMENTS)).to(String[].class);
final Long id = (Long)ref.getProperty(Constants.SERVICE_ID);
- if ( authReqPaths != null ) {
+ if ( authReqPaths.length > 0 ) {
final Set<String> oldPaths = regProps.get(id);
if ( oldPaths == null ) {
addService(mapper, ref);
@@ -360,10 +388,18 @@ public class SlingAuthenticatorServiceListener implements
AllServiceListener, Ev
regProps.remove(id);
}
+ /**
+ * Action type for the queued execution
+ *
+ */
public enum ActionType {
ADDED, MODIFIED, REMOVED, UPDATE
}
+ /**
+ * Action for the queued execution
+ *
+ */
public static final class Action {
public final ActionType type;
diff --git
a/src/test/java/org/apache/sling/auth/core/impl/SlingAuthenticatorServiceListenerTest.java
b/src/test/java/org/apache/sling/auth/core/impl/SlingAuthenticatorServiceListenerTest.java
index feffc93..c87a1bc 100644
---
a/src/test/java/org/apache/sling/auth/core/impl/SlingAuthenticatorServiceListenerTest.java
+++
b/src/test/java/org/apache/sling/auth/core/impl/SlingAuthenticatorServiceListenerTest.java
@@ -51,9 +51,9 @@ public class SlingAuthenticatorServiceListenerTest {
final String[] paths,
final ServiceReference<?>[] refs,
final boolean[] requireAuth) {
- assertEquals(paths.length, refs.length);
+ assertEquals("Wrong input to assert paths", paths.length, refs.length);
if ( requireAuth != null ) {
- assertEquals(paths.length, requireAuth.length);
+ assertEquals("Wrong input to assert paths", paths.length,
requireAuth.length);
}
assertEquals(paths.length, cache.getHolders().size());
@@ -119,16 +119,46 @@ public class SlingAuthenticatorServiceListenerTest {
final ServiceReference<?> ref = createServiceReference(new String[]
{"/path1"});
listener.serviceChanged(new ServiceEvent(ServiceEvent.REGISTERED,
ref));
- assertEquals(1, cache.getHolders().size());
assertPaths(cache, new String[] {"/path1"},
new ServiceReference<?>[] {ref});
- assertEquals(ref, cache.getHolders().get(0).serviceReference);
listener.serviceChanged(new ServiceEvent(ServiceEvent.UNREGISTERING,
ref));
assertTrue(cache.getHolders().isEmpty());
}
+ @Test public void testAddUpdateRemoveRegistration() throws LoginException {
+ final PathBasedHolderCache<AuthenticationRequirementHolder> cache =
new PathBasedHolderCache<AuthenticationRequirementHolder>();
+ final BundleContext context = mock(BundleContext.class);
+ final ResourceMapper mapper = mock(ResourceMapper.class);
+
when(mapper.getAllMappings("/path1")).thenReturn(Arrays.asList("/path1",
"/path1a"));
+
when(mapper.getAllMappings("/path2")).thenReturn(Arrays.asList("/path2",
"/path2a"));
+
when(mapper.getAllMappings("/path3")).thenReturn(Arrays.asList("/path3",
"/path3a"));
+
+ final SlingAuthenticatorServiceListener listener =
SlingAuthenticatorServiceListener.createListener(context, callable ->
callable.run(), createFactoryForMapper(mapper), cache);
+
+ // add
+ final ServiceReference<?> ref = createServiceReference(new String[]
{"/path1", "/path2"});
+ listener.serviceChanged(new ServiceEvent(ServiceEvent.REGISTERED,
ref));
+
+ assertPaths(cache, new String[] {"/path1", "/path1a", "/path2",
"/path2a"},
+ new ServiceReference<?>[] {ref, ref, ref, ref},
+ new boolean[] {true, true, true, true});
+
+ // update
+ when(ref.getProperty(AuthConstants.AUTH_REQUIREMENTS)).thenReturn(new
String[] {"/path2", "/path3"});
+ listener.serviceChanged(new ServiceEvent(ServiceEvent.MODIFIED, ref));
+
+ assertPaths(cache, new String[] {"/path2", "/path2a", "/path3",
"/path3a"},
+ new ServiceReference<?>[] {ref, ref, ref, ref},
+ new boolean[] {true, true, true, true});
+
+ // remmove
+ listener.serviceChanged(new ServiceEvent(ServiceEvent.UNREGISTERING,
ref));
+
+ assertTrue(cache.getHolders().isEmpty());
+ }
+
@Test public void testDuplicateRegistration() throws LoginException {
final PathBasedHolderCache<AuthenticationRequirementHolder> cache =
new PathBasedHolderCache<AuthenticationRequirementHolder>();
final BundleContext context = mock(BundleContext.class);
@@ -304,4 +334,35 @@ public class SlingAuthenticatorServiceListenerTest {
new ServiceReference<?>[] {ref, ref, ref, ref, ref, ref},
new boolean[] {false, true, true, false, true, true});
}
+
+ @Test public void testSwitchAllowDeny() throws LoginException {
+ final PathBasedHolderCache<AuthenticationRequirementHolder> cache =
new PathBasedHolderCache<AuthenticationRequirementHolder>();
+ final BundleContext context = mock(BundleContext.class);
+ final ResourceMapper mapper = mock(ResourceMapper.class);
+
when(mapper.getAllMappings("/path1")).thenReturn(Arrays.asList("/path1",
"/path1a"));
+
when(mapper.getAllMappings("/path2")).thenReturn(Arrays.asList("/path2",
"/path2a"));
+
+ final SlingAuthenticatorServiceListener listener =
SlingAuthenticatorServiceListener.createListener(context, callable ->
callable.run(), createFactoryForMapper(mapper), cache);
+
+ // add
+ final ServiceReference<?> ref = createServiceReference(new String[]
{"+/path1", "-/path2"});
+ listener.serviceChanged(new ServiceEvent(ServiceEvent.REGISTERED,
ref));
+
+ assertPaths(cache, new String[] {"/path1", "/path1a", "/path2",
"/path2a"},
+ new ServiceReference<?>[] {ref, ref, ref, ref},
+ new boolean[] {true, true, false, false});
+
+ // update
+ when(ref.getProperty(AuthConstants.AUTH_REQUIREMENTS)).thenReturn(new
String[] {"-/path1", "/path2"});
+ listener.serviceChanged(new ServiceEvent(ServiceEvent.MODIFIED, ref));
+
+ assertPaths(cache, new String[] {"/path1", "/path1a", "/path2",
"/path2a"},
+ new ServiceReference<?>[] {ref, ref, ref, ref},
+ new boolean[] {false, false, true, true});
+
+ // remmove
+ listener.serviceChanged(new ServiceEvent(ServiceEvent.UNREGISTERING,
ref));
+
+ assertTrue(cache.getHolders().isEmpty());
+ }
}