Merge pull request #1 from apache/issues/SLING-7930
Initial attempt on providing default ServiceUserMapped and only mappiā¦
diff --git a/src/main/java/org/apache/sling/serviceusermapping/impl/ServiceUserMappedBundleFilter.java b/src/main/java/org/apache/sling/serviceusermapping/impl/ServiceUserMappedBundleFilter.java
index bdf794c..ae95071 100644
--- a/src/main/java/org/apache/sling/serviceusermapping/impl/ServiceUserMappedBundleFilter.java
+++ b/src/main/java/org/apache/sling/serviceusermapping/impl/ServiceUserMappedBundleFilter.java
@@ -24,14 +24,19 @@
import java.util.Map;
import org.apache.sling.serviceusermapping.Mapping;
+import org.apache.sling.serviceusermapping.ServiceUserMapped;
+import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
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.Activate;
import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
/**
* The <code>ServiceUserMappingBundleFilter</code> only allows the bundle for which the service mapping is available to see it.
@@ -40,20 +45,40 @@
service = {EventListenerHook.class, FindHook.class} )
public class ServiceUserMappedBundleFilter implements EventListenerHook, FindHook {
+ @Reference
+ volatile ServiceUserMapperImpl mapper;
+
+ volatile BundleContext context;
+
+ @Activate
+ void start(BundleContext context) {
+ this.context = context;
+ }
+
@Override
public void event(ServiceEvent serviceEvent, Map map) {
ServiceReference serviceReference = serviceEvent.getServiceReference();
- if (isServiceMappingReference(serviceReference)) {
+ if (isServiceMappingReference(serviceReference) && serviceEvent.getType() == ServiceEvent.REGISTERED) {
Object serviceName = serviceReference.getProperty(Mapping.SERVICENAME);
+ String subserviceName = getSubServiceName(serviceReference);
+ Iterator<Map.Entry<BundleContext, Collection<ListenerHook.ListenerInfo>>> it = map.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry<BundleContext, Collection<ListenerHook.ListenerInfo>> entry = it.next();
+ BundleContext ctx = entry.getKey();
- if (serviceName != null && serviceName instanceof String) {
- Iterator<Map.Entry<BundleContext, Collection<ListenerHook.ListenerInfo>>> it = map.entrySet().iterator();
- while (it.hasNext()) {
- BundleContext ctx = it.next().getKey();
-
- String bundleServiceName = ServiceUserMapperImpl.getServiceName(ctx.getBundle());
- if (!serviceName.equals(bundleServiceName)) {
+ if (!ctx.getBundle().equals(context.getBundle()) && !isValid(ctx.getBundle(), serviceName, subserviceName)) {
+ boolean keep = false;
+ Iterator<ListenerHook.ListenerInfo> iter = entry.getValue().iterator();
+ while (iter.hasNext()) {
+ if (!matchDefault(ctx.getBundle(), serviceName, subserviceName, iter.next().getFilter(), serviceReference)) {
+ iter.remove();
+ }
+ else {
+ keep = true;
+ }
+ }
+ if (!keep) {
it.remove();
}
}
@@ -64,21 +89,64 @@
@Override
public void find(BundleContext bundleContext, String name, String filter, boolean allServices,
Collection references) {
- String bundleServiceName = ServiceUserMapperImpl.getServiceName(bundleContext.getBundle());
Iterator<ServiceReference> it = references.iterator();
while (it.hasNext()) {
ServiceReference serviceReference = it.next();
if (isServiceMappingReference(serviceReference)) {
Object serviceName = serviceReference.getProperty(Mapping.SERVICENAME);
-
- if (serviceName != null && !serviceName.equals(bundleServiceName)) {
- it.remove();
+ String subserviceName = getSubServiceName(serviceReference);
+ if (!isValid(bundleContext.getBundle(), serviceName, subserviceName)) {
+ if (!matchDefault(bundleContext.getBundle(), serviceName, subserviceName, filter, serviceReference)) {
+ it.remove();
+ }
}
}
}
}
+ private boolean isValid(Bundle bundle, Object serviceName, String subserviceName) {
+ String bundleServiceName = mapper.getServiceName(bundle);
+ if (bundleServiceName.equals(serviceName)) {
+ Iterable<String> principals = mapper.getServicePrincipalNames(bundle, subserviceName);
+ if (principals != null && principals.iterator().hasNext()) {
+ return true;
+ }
+ String user = mapper.getServiceUserID(bundle, subserviceName);
+ if (user != null && !user.isEmpty()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private boolean matchDefault(Bundle bundle, Object serviceName, String subserviceName, String filter, ServiceReference ref) {
+ if ( mapper.getServiceName(context.getBundle()).equals(serviceName) ) {
+ try {
+ if (filter != null && context.createFilter(filter).match(ref)) {
+ for (Mapping mapping : mapper.getActiveMappings()) {
+ if (mapping.getServiceName().equals(mapper.getServiceName(bundle))) {
+ return false;
+ }
+ }
+ Iterable<String> principals = mapper.getServicePrincipalNames(bundle, subserviceName);
+ if (principals != null && principals.iterator().hasNext()) {
+ return true;
+ }
+ String user = mapper.getServiceUserID(bundle, subserviceName);
+ if (user != null && !user.isEmpty()) {
+ return true;
+ }
+ }
+ } catch (InvalidSyntaxException e) {
+ // this shouldn't happen as the framework will have validated the filter already
+ throw new RuntimeException(e);
+ }
+ }
+ return false;
+ }
+
private static boolean isServiceMappingReference(ServiceReference serviceReference) {
Object objectClass = serviceReference.getProperty(Constants.OBJECTCLASS);
for (Object o : (Object[]) objectClass) {
@@ -89,6 +157,11 @@
return false;
}
-
-
+ private static String getSubServiceName(ServiceReference ref) {
+ Object subserviceName = ref.getProperty(ServiceUserMapped.SUBSERVICENAME);
+ if (subserviceName != null && subserviceName instanceof String) {
+ return (String) subserviceName;
+ }
+ return null;
+ }
}
diff --git a/src/main/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImpl.java b/src/main/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImpl.java
index 7fb23e4..492513b 100644
--- a/src/main/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImpl.java
+++ b/src/main/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImpl.java
@@ -34,6 +34,7 @@
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicReference;
import org.apache.sling.serviceusermapping.Mapping;
import org.apache.sling.serviceusermapping.ServicePrincipalsValidator;
@@ -81,7 +82,7 @@
@AttributeDefinition(name = "Default Mapping",
description = "If enabled and no mapping for a requested service user exists and no " +
" default user is defined, a " +
- "default mapping is applied which uses the service user \"serviceuser@\" + {bundleId} + [\":\" + subServiceName]")
+ "default mapping is applied which uses the service user \"serviceuser--\" + bundleId + [\"--\" + subServiceName]")
boolean user_enable_default_mapping() default true;
}
@@ -92,7 +93,7 @@
private String defaultUser;
- private boolean useDefaultMapping;
+ volatile boolean useDefaultMapping;
private Map<Long, MappingConfigAmendment> amendments = new HashMap<>();
@@ -108,7 +109,9 @@
private ExecutorService executorService;
- public boolean registerAsync = true;
+ boolean registerAsync = true;
+
+ private final AtomicReference<ServiceRegistration> defaultRegistration = new AtomicReference<>();
@Activate
@Modified
@@ -340,6 +343,10 @@
private void executeServiceRegistrations(final RegistrationSet registrationSet) {
+ ServiceRegistration reg = defaultRegistration.getAndSet(null);
+ if (reg != null) {
+ reg.unregister();
+ }
if (registrationSet == null) {
return;
}
@@ -388,6 +395,16 @@
}
}
+ if (this.useDefaultMapping || (defaultUser != null && !defaultUser.isEmpty())) {
+ Dictionary<String, Object> properties = new Hashtable<>();
+ properties.put(Mapping.SERVICENAME, getServiceName(savedBundleContext.getBundle()));
+ final ServiceRegistration serviceRegistration = savedBundleContext.registerService(ServiceUserMappedImpl.SERVICEUSERMAPPED,
+ new ServiceUserMappedImpl(), properties);
+ ServiceRegistration oldServiceRegistration = this.defaultRegistration.getAndSet(serviceRegistration);
+ if (oldServiceRegistration != null) {
+ oldServiceRegistration.unregister();
+ }
+ }
}
private String internalGetUserId(final String serviceName, final String subServiceName) {
@@ -417,7 +434,7 @@
}
// use default mapping if configured and no default user
- if ( this.defaultUser == null || this.defaultUser.isEmpty() ) {
+ if ( this.useDefaultMapping && (this.defaultUser == null || this.defaultUser.isEmpty() )) {
final String userName = "serviceuser--" + serviceName + (subServiceName == null ? "" : "--" + subServiceName);
log.debug("internalGetUserId: no mapping found, using default mapping [{}]", userName);
return userName;
@@ -497,7 +514,7 @@
return null;
}
- static String getServiceName(final Bundle bundle) {
+ String getServiceName(final Bundle bundle) {
return bundle.getSymbolicName();
}
diff --git a/src/test/java/org/apache/sling/serviceusermapping/impl/ServiceUserMappedBundleFilterTest.java b/src/test/java/org/apache/sling/serviceusermapping/impl/ServiceUserMappedBundleFilterTest.java
index e95ef7e..08fe051 100644
--- a/src/test/java/org/apache/sling/serviceusermapping/impl/ServiceUserMappedBundleFilterTest.java
+++ b/src/test/java/org/apache/sling/serviceusermapping/impl/ServiceUserMappedBundleFilterTest.java
@@ -53,14 +53,21 @@
final static BundleContext bundleContext1;
final static BundleContext bundleContext2;
+ final static BundleContext mapperContext;
static {
+ Bundle mapper = mock(Bundle.class);
+ when(mapper.getSymbolicName()).thenReturn("mapper");
+ mapperContext = mock(BundleContext.class);
+ when(mapperContext.getBundle()).thenReturn(mapper);
+
bundleContext1 = mock(BundleContext.class);
Bundle bundle1 = mock(Bundle.class);
when(bundleContext1.getBundle()).thenReturn(bundle1);
when(bundle1.getSymbolicName()).thenReturn(BUNDLE1);
+
bundleContext2 = mock(BundleContext.class);
Bundle bundle2 = mock(Bundle.class);
when(bundleContext2.getBundle()).thenReturn(bundle2);
@@ -83,12 +90,24 @@
when(serviceEvent.getServiceReference()).thenReturn(serviceReference);
when(serviceReference.getProperty(Constants.OBJECTCLASS)).thenReturn(new String[]{ServiceUserMappedImpl.SERVICEUSERMAPPED});
when(serviceReference.getProperty(Mapping.SERVICENAME)).thenReturn(BUNDLE1);
+ when(serviceEvent.getType()).thenReturn(ServiceEvent.REGISTERED);
- EventListenerHook eventListenerHook = new ServiceUserMappedBundleFilter();
- eventListenerHook.event(serviceEvent, map);
+ ServiceUserMappedBundleFilter eventListenerHook = new ServiceUserMappedBundleFilter();
- TestCase.assertEquals(1, map.size());
+ eventListenerHook.mapper = new ServiceUserMapperImpl();
+ eventListenerHook.start(mapperContext);
+
+ Map<BundleContext, Collection<ListenerHook.ListenerInfo>> map1 = new HashMap<>(map);
+ eventListenerHook.event(serviceEvent, map1);
+
+ TestCase.assertEquals(0, map1.size());
+
+ Map<BundleContext, Collection<ListenerHook.ListenerInfo>> map2 = new HashMap<>(map);
+ eventListenerHook.mapper.useDefaultMapping = true;
+ eventListenerHook.event(serviceEvent, map2);
+
+ TestCase.assertEquals(1, map2.size());
TestCase.assertTrue(map.containsKey(bundleContext1));
}
@@ -108,10 +127,24 @@
when(serviceReference2.getProperty(Mapping.SERVICENAME)).thenReturn(BUNDLE2);
when(serviceReference2.getProperty(Constants.OBJECTCLASS)).thenReturn(new String[]{ServiceUserMappedImpl.SERVICEUSERMAPPED});
- FindHook findHook = new ServiceUserMappedBundleFilter();
- findHook.find(bundleContext1, null, null, false, collection);
+ ServiceUserMappedBundleFilter findHook = new ServiceUserMappedBundleFilter();
- TestCase.assertEquals(1, collection.size());
+ findHook.mapper = new ServiceUserMapperImpl();
+ findHook.start(mapperContext);
+
+ List collection1 = new ArrayList(collection);
+ findHook.find(bundleContext1, null, null, false, collection1);
+
+ TestCase.assertEquals(0, collection1.size());
+
+ findHook.mapper.useDefaultMapping = true;
+
+ List collection2 = new ArrayList(collection);
+ findHook.find(bundleContext1, null, null, false, collection2);
+
+ TestCase.assertEquals(1, collection2.size());
TestCase.assertTrue(collection.contains(serviceReference1));
+
+
}
}
diff --git a/src/test/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImplTest.java b/src/test/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImplTest.java
index 41da0f6..1fc5abb 100644
--- a/src/test/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImplTest.java
+++ b/src/test/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImplTest.java
@@ -424,7 +424,7 @@
final ServiceRegistrationContextHelper context = new ServiceRegistrationContextHelper();
sum.configure(context.getBundleContext(), config);
- TestCase.assertEquals(2, context.getRegistrations(ServiceUserMappedImpl.SERVICEUSERMAPPED).size());
+ TestCase.assertEquals(3, context.getRegistrations(ServiceUserMappedImpl.SERVICEUSERMAPPED).size());
final MappingConfigAmendment mca1 = new MappingConfigAmendment();
@@ -439,7 +439,7 @@
mca1.configure(mca1Config);
sum.bindAmendment(mca1, mca1ConfigMap);
- TestCase.assertEquals(3, context.getRegistrations(ServiceUserMappedImpl.SERVICEUSERMAPPED).size());
+ TestCase.assertEquals(4, context.getRegistrations(ServiceUserMappedImpl.SERVICEUSERMAPPED).size());
final MappingConfigAmendment mca2 = new MappingConfigAmendment();
@@ -454,11 +454,11 @@
mca2.configure(mca2Config);
sum.bindAmendment(mca2, mca2ConfigMap);
- TestCase.assertEquals(4, context.getRegistrations(ServiceUserMappedImpl.SERVICEUSERMAPPED).size());
+ TestCase.assertEquals(5, context.getRegistrations(ServiceUserMappedImpl.SERVICEUSERMAPPED).size());
sum.unbindAmendment(mca1, mca1ConfigMap);
- TestCase.assertEquals(3, context.getRegistrations(ServiceUserMappedImpl.SERVICEUSERMAPPED).size());
+ TestCase.assertEquals(4, context.getRegistrations(ServiceUserMappedImpl.SERVICEUSERMAPPED).size());
}
@@ -466,6 +466,7 @@
final BundleContext bundleContext = mock(BundleContext.class);
+ final Bundle bundle = mock(Bundle.class);
final Map<String, Map<Object, Dictionary>> registrations = new HashMap<>();
public ServiceRegistrationContextHelper() {
@@ -478,6 +479,8 @@
return registerService((String) arguments[0], arguments[1], (Dictionary) arguments[2]);
}
});
+ when(bundleContext.getBundle()).thenReturn(bundle);
+ when(bundle.getSymbolicName()).thenReturn("mock");
}
private ServiceRegistration registerService(String string, Object o, Dictionary dictionary) {