Author: pauls
Date: Mon Jul 10 15:40:52 2017
New Revision: 1801482
URL: http://svn.apache.org/viewvc?rev=1801482&view=rev
Log:
SLING-6963: Add Service user declaration based on principal names - patch
provided by Angela Schreiber.
Added:
sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/ServicePrincipalsValidator.java
Modified:
sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/ServiceUserMapper.java
sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/Mapping.java
sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/MappingConfigAmendment.java
sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/MappingInventoryPrinter.java
sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImpl.java
sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/package-info.java
sling/trunk/bundles/extensions/serviceusermapper/src/test/java/org/apache/sling/serviceusermapping/impl/MappingTest.java
sling/trunk/bundles/extensions/serviceusermapper/src/test/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImplTest.java
Added:
sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/ServicePrincipalsValidator.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/ServicePrincipalsValidator.java?rev=1801482&view=auto
==============================================================================
---
sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/ServicePrincipalsValidator.java
(added)
+++
sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/ServicePrincipalsValidator.java
Mon Jul 10 15:40:52 2017
@@ -0,0 +1,37 @@
+/*
+ * 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.serviceusermapping;
+
+import org.osgi.annotation.versioning.ConsumerType;
+
+/**
+ * The {@code ServicePrincipalsValidator} allows to implement validation of
configured
+ * service user mappings.
+ */
+@ConsumerType
+public interface ServicePrincipalsValidator {
+
+ /**
+ * Validates the configured service principal names.
+ *
+ * @param serviceUserId The principal names associated with the service.
+ * @param serviceName The name of the service
+ * @param subServiceName The optional sub service name.
+ * @return {@code true} if all configured service principal names are
valid; {@code false} otherwise.
+ */
+ boolean isValid(Iterable<String> servicePrincipalNames, String
serviceName, String subServiceName);
+}
\ No newline at end of file
Modified:
sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/ServiceUserMapper.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/ServiceUserMapper.java?rev=1801482&r1=1801481&r2=1801482&view=diff
==============================================================================
---
sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/ServiceUserMapper.java
(original)
+++
sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/ServiceUserMapper.java
Mon Jul 10 15:40:52 2017
@@ -71,4 +71,19 @@ public interface ServiceUserMapper {
* optional {@code serviceInfo}.
*/
String getServiceUserID(Bundle bundle, String subServiceName);
+
+ /**
+ * Returns the principal names to access the data store on behalf of the
+ * service.
+ *
+ * @param bundle The bundle implementing the service request access to
resources.
+ * @param subServiceName Name of the sub service. This parameter is
optional
+ * and may be an empty string or {@code null}.
+ * @return The principal names to use to provide access to the resources
for
+ * the service. This may be {@code null} if no mapping has been
defined
+ * for the service identified by the bundle and the optional
{@code serviceInfo}
+ * or if no principal names have been specified with the mapping.
+ * In this case {@link #getServiceUserID(Bundle, String)} should
be used instead.
+ */
+ Iterable<String> getServicePrincipalNames(Bundle bundle, String
subServiceName);
}
Modified:
sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/Mapping.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/Mapping.java?rev=1801482&r1=1801481&r2=1801482&view=diff
==============================================================================
---
sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/Mapping.java
(original)
+++
sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/Mapping.java
Mon Jul 10 15:40:52 2017
@@ -18,9 +18,12 @@
*/
package org.apache.sling.serviceusermapping.impl;
+import java.util.HashSet;
+import java.util.Set;
+
/**
* The <code>Mapping</code> class defines the mapping of a service's name and
- * optional service information to a user name.
+ * optional service information to a user name and optionally to a set of
principal names.
*/
class Mapping implements Comparable<Mapping> {
@@ -36,11 +39,14 @@ class Mapping implements Comparable<Mapp
private final String userName;
+ private final Set<String> principalNames;
+
/**
* Creates a mapping entry for the entry specification of the form:
*
* <pre>
- * spec = serviceName [ ":" subServiceName ] "=" userName .
+ * spec = serviceName [ ":" subServiceName ] "=" userName | "["
principalNames "]"
+ * principalNames = principalName ["," principalNames]
* </pre>
*
* @param spec The mapping specification.
@@ -56,7 +62,7 @@ class Mapping implements Comparable<Mapp
if (colon == 0 || equals <= 0) {
throw new IllegalArgumentException("serviceName is required");
} else if (equals == spec.length() - 1) {
- throw new IllegalArgumentException("userName is required");
+ throw new IllegalArgumentException("userName or principalNames is
required");
} else if (colon + 1 == equals) {
throw new IllegalArgumentException("serviceInfo must not be
empty");
}
@@ -69,18 +75,38 @@ class Mapping implements Comparable<Mapp
this.subServiceName = spec.substring(colon + 1, equals);
}
- this.userName = spec.substring(equals + 1);
+ String s = spec.substring(equals + 1);
+ if (s.charAt(0) == '[' && s.charAt(s.length()-1) == ']') {
+ this.userName = null;
+ this.principalNames = extractPrincipalNames(s);
+ } else {
+ this.userName = s;
+ this.principalNames = null;
+ }
+ }
+
+ static Set<String> extractPrincipalNames(String s) {
+ String[] sArr = s.substring(1, s.length() - 1).split(",");
+ Set<String> set = new HashSet<>();
+ for (String name : sArr) {
+ String n = name.trim();
+ if (!n.isEmpty()) {
+ set.add(n);
+ }
+ }
+ return set;
}
/**
* Returns the user name if the {@code serviceName} and the
- * {@code serviceInfo} match. Otherwise {@code null} is returned.
+ * {@code serviceInfo} match and a single user name is configured (in
contrast
+ * to a set of principal names). Otherwise {@code null} is returned.
*
* @param serviceName The name of the service to match. If this is
* {@code null} this mapping will not match.
* @param subServiceName The Subservice Name to match. This may be
* {@code null}.
- * @return The user name if this mapping matches or {@code null} otherwise.
+ * @return The user name if this mapping matches and the configuration
doesn't specify a set of principal names; {@code null} otherwise.
*/
String map(final String serviceName, final String subServiceName) {
if (this.serviceName.equals(serviceName) &&
equals(this.subServiceName, subServiceName)) {
@@ -90,14 +116,37 @@ class Mapping implements Comparable<Mapp
return null;
}
+ /**
+ * Returns the principal names if the {@code serviceName} and the
+ * {@code serviceInfo} match and principal names have been configured.
+ * Otherwise {@code null} is returned. If no principal names are configured
+ * {@link #map(String, String)} needs to be used instead.
+ *
+ * @param serviceName The name of the service to match. If this is
+ * {@code null} this mapping will not match.
+ * @param subServiceName The Subservice Name to match. This may be
+ * {@code null}.
+ * @return An iterable of principals names this mapping matches and the
configuration
+ * does specify a set of principal names (intstead of a single user name);
{@code null}
+ * otherwise.
+ */
+ Iterable<String> mapPrincipals(final String serviceName, final String
subServiceName) {
+ if (this.serviceName.equals(serviceName) &&
equals(this.subServiceName, subServiceName)) {
+ return principalNames;
+ }
+
+ return null;
+ }
+
private boolean equals(String str1, String str2) {
return ((str1 == null) ? str2 == null : str1.equals(str2));
}
@Override
public String toString() {
+ String name = (userName != null) ? "userName=" + userName :
"principleNames" + principalNames.toString();
return "Mapping [serviceName=" + serviceName + ", subServiceName="
- + subServiceName + ", userName=" + userName + "]";
+ + subServiceName + ", " + name;
}
public String getServiceName() {
Modified:
sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/MappingConfigAmendment.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/MappingConfigAmendment.java?rev=1801482&r1=1801481&r2=1801482&view=diff
==============================================================================
---
sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/MappingConfigAmendment.java
(original)
+++
sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/MappingConfigAmendment.java
Mon Jul 10 15:40:52 2017
@@ -46,10 +46,12 @@ public class MappingConfigAmendment impl
int service_ranking() default 0;
@AttributeDefinition(name = "Service Mappings",
- description = "Provides mappings from service name to user names. "
- + "Each entry is of the form 'bundleId [ \":\" subServiceName
] \"=\" userName' "
- + "where bundleId and subServiceName identify the service and
userName "
- + "defines the name of the user to provide to the service.
Invalid entries are logged and ignored.")
+ description = "Provides mappings from service name to user (and
optionally principal) names. "
+ + "Each entry is of the form 'bundleId [ \":\" subServiceName
] \"=\" userName' | \"[\" principalNames \"]\" "
+ + "where bundleId and subServiceName identify the service and
userName/principalNames "
+ + "defines the name(s) of the user/principals to provide to
the service. "
+ + "'principalNames is defined to be a comma separated list of
principal names. "
+ + "Invalid entries are logged and ignored.")
String[] user_mapping() default {};
// Internal Name hint for web console.
Modified:
sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/MappingInventoryPrinter.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/MappingInventoryPrinter.java?rev=1801482&r1=1801481&r2=1801482&view=diff
==============================================================================
---
sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/MappingInventoryPrinter.java
(original)
+++
sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/MappingInventoryPrinter.java
Mon Jul 10 15:40:52 2017
@@ -21,6 +21,7 @@ package org.apache.sling.serviceusermapp
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
@@ -62,16 +63,49 @@ public class MappingInventoryPrinter imp
return m.map(m.getServiceName(), m.getSubServiceName());
}
+ private String[] getMappedPrincipalNames(Mapping m) {
+ Iterable<String> principalNames = m.mapPrincipals(m.getServiceName(),
m.getSubServiceName());
+ if (principalNames == null) {
+ return null;
+ } else {
+ List<String> l = new ArrayList<>();
+ for (String pName : principalNames) {
+ l.add(pName);
+ }
+ return l.toArray(new String[l.size()]);
+ }
+ }
+
private SortedMap<String, List<Mapping>> getMappingsByUser(List<Mapping>
mappings) {
SortedMap<String, List<Mapping>> result = new TreeMap<String,
List<Mapping>>();
for(Mapping m : mappings) {
final String user = getMappedUser(m);
- List<Mapping> list = result.get(user);
- if(list == null) {
- list = new ArrayList<Mapping>();
- result.put(user, list);
+ if (user != null) {
+ List<Mapping> list = result.get(user);
+ if (list == null) {
+ list = new ArrayList<Mapping>();
+ result.put(user, list);
+ }
+ list.add(m);
+ }
+ }
+ return result;
+ }
+
+ private SortedMap<String, List<Mapping>>
getMappingsByPrincipalName(List<Mapping> mappings) {
+ SortedMap<String, List<Mapping>> result = new TreeMap<String,
List<Mapping>>();
+ for(Mapping m : mappings) {
+ final String[] principalNames = getMappedPrincipalNames(m);
+ if (principalNames != null) {
+ for (String pName : principalNames) {
+ List<Mapping> list = result.get(pName);
+ if (list == null) {
+ list = new ArrayList<Mapping>();
+ result.put(pName, list);
+ }
+ list.add(m);
+ }
}
- list.add(m);
}
return result;
}
@@ -80,19 +114,26 @@ public class MappingInventoryPrinter imp
w.object();
w.key("serviceName").value(m.getServiceName());
w.key("subServiceName").value(m.getSubServiceName());
- w.key("user").value(getMappedUser(m));
+ String[] pNames = getMappedPrincipalNames(m);
+ if (pNames != null) {
+ w.key("principals").value(pNames);
+ } else {
+ w.key("user").value(getMappedUser(m));
+ }
w.endObject();
}
private void renderJson(PrintWriter out) throws IOException {
final List<Mapping> data = mapper.getActiveMappings();
final Map<String, List<Mapping>> byUser = getMappingsByUser(data);
+ final Map<String, List<Mapping>> byPrincipalName =
getMappingsByPrincipalName(data);
final JSONWriter w = new JSONWriter(out);
w.object();
w.key("title").value("Service User Mappings");
w.key("mappingsCount").value(data.size());
w.key("uniqueUsersCount").value(byUser.keySet().size());
+ w.key("uniquePrincipalsCount").value(byPrincipalName.keySet().size());
w.key("mappingsByUser");
w.object();
@@ -106,6 +147,18 @@ public class MappingInventoryPrinter imp
}
w.endObject();
+ w.key("mappingsByPrincipal");
+ w.object();
+ for(Map.Entry<String, List<Mapping>> e : byPrincipalName.entrySet()) {
+ w.key(e.getKey());
+ w.array();
+ for(Mapping m : e.getValue()) {
+ asJSON(w,m);
+ }
+ w.endArray();
+ }
+ w.endObject();
+
w.endObject();
}
@@ -117,24 +170,43 @@ public class MappingInventoryPrinter imp
final String sub = m.getSubServiceName();
w.print(sub == null ? "" : sub);
w.print(SEP);
- w.println(getMappedUser(m));
+ String[] principalNames = getMappedPrincipalNames(m);
+ if (principalNames != null) {
+ w.println(Arrays.toString(principalNames));
+ } else {
+ w.println(getMappedUser(m));
+ }
}
private void renderText(PrintWriter out) {
final List<Mapping> data = mapper.getActiveMappings();
- final Map<String, List<Mapping>> byUser = getMappingsByUser(data);
- final String formatInfo = " (format: service name / sub service name /
user)";
+ final Map<String, List<Mapping>> byUser = getMappingsByUser(data);
out.print("*** Mappings by user (");
out.print(byUser.keySet().size());
out.print(" users):");
- out.println(formatInfo);
+ out.println(" (format: service name / sub service name / user)");
for(Map.Entry<String, List<Mapping>> e : byUser.entrySet()) {
out.print(" ");
out.println(e.getKey());
for(Mapping m : e.getValue()) {
+ asText(out, m, " ");
+ }
+ }
+
+ final Map<String, List<Mapping>> byPrincipalName =
getMappingsByPrincipalName(data);
+
+ out.print("*** Mappings by principals (");
+ out.print(byPrincipalName.keySet().size());
+ out.print(" principals):");
+ out.println(" (format: service name / sub service name / principal
names)");
+
+ for(Map.Entry<String, List<Mapping>> e : byPrincipalName.entrySet()) {
+ out.print(" ");
+ out.println(e.getKey());
+ for(Mapping m : e.getValue()) {
asText(out, m, " ");
}
}
Modified:
sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImpl.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImpl.java?rev=1801482&r1=1801481&r2=1801482&view=diff
==============================================================================
---
sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImpl.java
(original)
+++
sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImpl.java
Mon Jul 10 15:40:52 2017
@@ -35,6 +35,7 @@ import java.util.concurrent.CopyOnWriteA
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import org.apache.sling.serviceusermapping.ServicePrincipalsValidator;
import org.apache.sling.serviceusermapping.ServiceUserMapped;
import org.apache.sling.serviceusermapping.ServiceUserMapper;
import org.apache.sling.serviceusermapping.ServiceUserValidator;
@@ -65,9 +66,10 @@ public class ServiceUserMapperImpl imple
@AttributeDefinition(name = "Service Mappings",
description = "Provides mappings from service name to user names. "
- + "Each entry is of the form 'bundleId [ \":\" subServiceName
] \"=\" userName' "
+ + "Each entry is of the form 'bundleId [ \":\" subServiceName
] \"=\" userName' | \"[\" principalNames \"]\" "
+ "where bundleId and subServiceName identify the service and
userName "
- + "defines the name of the user to provide to the service.
Invalid entries are logged and ignored.")
+ + "defines the name of the user to provide to the service;
alternative the the mapping"
+ + "can define a comma separated set of principalNames instead
of the userName. Invalid entries are logged and ignored.")
String[] user_mapping() default {};
@AttributeDefinition(name = "Default User",
@@ -95,7 +97,9 @@ public class ServiceUserMapperImpl imple
private Mapping[] activeMappings = new Mapping[0];
- private final List<ServiceUserValidator> validators = new
CopyOnWriteArrayList<>();
+ private final List<ServiceUserValidator> userValidators = new
CopyOnWriteArrayList<>();
+
+ private final List<ServicePrincipalsValidator> principalsValidators = new
CopyOnWriteArrayList<>();
private SortedMap<Mapping, Registration> activeRegistrations = new
TreeMap<>();
@@ -166,7 +170,7 @@ public class ServiceUserMapperImpl imple
*/
@Reference(cardinality=ReferenceCardinality.MULTIPLE, policy=
ReferencePolicy.DYNAMIC)
protected synchronized void bindServiceUserValidator(final
ServiceUserValidator serviceUserValidator) {
- validators.add(serviceUserValidator);
+ userValidators.add(serviceUserValidator);
restartAllActiveServiceUserMappedServices();
}
@@ -175,7 +179,26 @@ public class ServiceUserMapperImpl imple
* @param serviceUserValidator
*/
protected synchronized void unbindServiceUserValidator(final
ServiceUserValidator serviceUserValidator) {
- validators.remove(serviceUserValidator);
+ userValidators.remove(serviceUserValidator);
+ restartAllActiveServiceUserMappedServices();
+ }
+
+ /**
+ * bind the servicePrincipalsValidator
+ * @param servicePrincipalsValidator
+ */
+ @Reference(cardinality=ReferenceCardinality.MULTIPLE, policy=
ReferencePolicy.DYNAMIC)
+ protected synchronized void bindServicePrincipalsValidator(final
ServicePrincipalsValidator servicePrincipalsValidator) {
+ principalsValidators.add(servicePrincipalsValidator);
+ restartAllActiveServiceUserMappedServices();
+ }
+
+ /**
+ * unbind the servicePrincipalsValidator
+ * @param servicePrincipalsValidator
+ */
+ protected synchronized void unbindServicePrincipalsValidator(final
ServicePrincipalsValidator servicePrincipalsValidator) {
+ principalsValidators.remove(servicePrincipalsValidator);
restartAllActiveServiceUserMappedServices();
}
@@ -194,6 +217,21 @@ public class ServiceUserMapperImpl imple
return result;
}
+ /**
+ * @see
org.apache.sling.serviceusermapping.ServiceUserMapper#getServicePrincipalNames(org.osgi.framework.Bundle,
java.lang.String)
+ */
+ @Override
+ public Iterable<String> getServicePrincipalNames(Bundle bundle, String
subServiceName) {
+ final String serviceName = getServiceName(bundle);
+ final Iterable<String> names = internalGetPrincipalNames(serviceName,
subServiceName);
+ final boolean valid = areValidPrincipals(names, serviceName,
subServiceName);
+ final Iterable<String> result = valid ? names : null;
+ log.debug(
+ "getServicePrincipalNames(bundle {}, subServiceName {})
returns [{}] (raw principalNames={}, valid={})",
+ new Object[] { bundle, subServiceName, result, names, valid});
+ return result;
+ }
+
@Reference(cardinality=ReferenceCardinality.MULTIPLE,policy=ReferencePolicy.DYNAMIC,updated="updateAmendment")
protected synchronized void bindAmendment(final MappingConfigAmendment
amendment, final Map<String, Object> props) {
final Long key = (Long) props.get(Constants.SERVICE_ID);
@@ -393,8 +431,8 @@ public class ServiceUserMapperImpl imple
log.debug("isValidUser: userId is null -> invalid");
return false;
}
- if ( !validators.isEmpty() ) {
- for (final ServiceUserValidator validator : validators) {
+ if ( !userValidators.isEmpty() ) {
+ for (final ServiceUserValidator validator : userValidators) {
if ( validator.isValid(userId, serviceName, subServiceName) ) {
log.debug("isValidUser: Validator {} accepts userId [{}]
-> valid", validator, userId);
return true;
@@ -408,6 +446,64 @@ public class ServiceUserMapperImpl imple
}
}
+ private boolean areValidPrincipals(final Iterable<String> principalNames,
final String serviceName, final String subServiceName) {
+ if (principalNames == null) {
+ log.debug("areValidPrincipals: principalNames are null ->
invalid");
+ return false;
+ }
+ if ( !principalsValidators.isEmpty() ) {
+ for (final ServicePrincipalsValidator validator :
principalsValidators) {
+ if ( validator.isValid(principalNames, serviceName,
subServiceName) ) {
+ log.debug("areValidPrincipals: Validator {} accepts
principal names [{}] -> valid", validator, principalNames);
+ return true;
+ }
+ }
+ log.debug("areValidPrincipals: No validator accepted principal
names [{}] -> invalid", principalNames);
+ return false;
+ } else {
+ log.debug("areValidPrincipals: No active validators for principal
names [{}] -> valid", principalNames);
+ return true;
+ }
+ }
+
+ private Iterable<String> internalGetPrincipalNames(final String
serviceName, final String subServiceName) {
+ log.debug(
+ "internalGetPrincipalNames: {} active mappings, looking for
mapping for {}/{}",
+ new Object[] { this.activeMappings.length, serviceName,
subServiceName });
+
+ for (final Mapping mapping : this.activeMappings) {
+ final Iterable<String> principalNames =
mapping.mapPrincipals(serviceName, subServiceName);
+ if (principalNames != null) {
+ log.debug("Got principalNames [{}] from {}/{}", new Object[]
{principalNames, serviceName, subServiceName });
+ return principalNames;
+ }
+ }
+
+ for (Mapping mapping : this.activeMappings) {
+ final Iterable<String> principalNames =
mapping.mapPrincipals(serviceName, null);
+ if (principalNames != null) {
+ log.debug("Got principalNames [{}] from {}/{}", new Object[]
{principalNames, serviceName });
+ return principalNames;
+ }
+ }
+
+ // second round without serviceInfo
+ log.debug(
+ "internalGetPrincipalNames: {} active mappings, looking for
mapping for {}/<no subServiceName>",
+ this.activeMappings.length, serviceName);
+
+ for (Mapping mapping : this.activeMappings) {
+ final Iterable<String> principalNames =
mapping.mapPrincipals(serviceName, null);
+ if (principalNames != null) {
+ log.debug("Got principalNames [{}] from {}/<no
subServiceName>", principalNames, serviceName);
+ return principalNames;
+ }
+ }
+
+ log.debug("internalGetPrincipalNames: no mapping found.");
+ return null;
+ }
+
static String getServiceName(final Bundle bundle) {
return bundle.getSymbolicName();
}
Modified:
sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/package-info.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/package-info.java?rev=1801482&r1=1801481&r2=1801482&view=diff
==============================================================================
---
sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/package-info.java
(original)
+++
sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/package-info.java
Mon Jul 10 15:40:52 2017
@@ -17,6 +17,6 @@
* under the License.
*/
[email protected]("1.2.1")
[email protected]("1.3.0")
package org.apache.sling.serviceusermapping;
Modified:
sling/trunk/bundles/extensions/serviceusermapper/src/test/java/org/apache/sling/serviceusermapping/impl/MappingTest.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/serviceusermapper/src/test/java/org/apache/sling/serviceusermapping/impl/MappingTest.java?rev=1801482&r1=1801481&r2=1801482&view=diff
==============================================================================
---
sling/trunk/bundles/extensions/serviceusermapper/src/test/java/org/apache/sling/serviceusermapping/impl/MappingTest.java
(original)
+++
sling/trunk/bundles/extensions/serviceusermapper/src/test/java/org/apache/sling/serviceusermapping/impl/MappingTest.java
Mon Jul 10 15:40:52 2017
@@ -19,69 +19,43 @@
package org.apache.sling.serviceusermapping.impl;
import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.Set;
import junit.framework.TestCase;
-
-import org.apache.sling.serviceusermapping.impl.Mapping;
import org.junit.Test;
public class MappingTest {
- @Test
+ @Test(expected = NullPointerException.class)
public void test_constructor_null() {
- try {
- new Mapping(null);
- TestCase.fail("NullPointerException expected");
- } catch (NullPointerException npe) {
- // expected
- }
+ new Mapping(null);
}
- @Test
+ @Test(expected = IllegalArgumentException.class)
public void test_constructor_empty() {
- try {
- new Mapping("");
- TestCase.fail("IllegalArgumentException expected");
- } catch (IllegalArgumentException iae) {
- // expected
- }
+ new Mapping("");
}
- @Test
+ @Test(expected = IllegalArgumentException.class)
public void test_constructor_missing_user_name() {
- try {
- new Mapping("serviceName");
- TestCase.fail("IllegalArgumentException expected");
- } catch (IllegalArgumentException iae) {
- // expected
- }
+ new Mapping("serviceName");
- try {
- new Mapping("serviceName=");
- TestCase.fail("IllegalArgumentException expected");
- } catch (IllegalArgumentException iae) {
- // expected
- }
}
- @Test
+ @Test(expected = IllegalArgumentException.class)
+ public void test_constructor_missing_user_name2() {
+ new Mapping("serviceName=");
+ }
+
+ @Test(expected = IllegalArgumentException.class)
public void test_constructor_missing_service_name() {
- try {
- new Mapping("=user");
- TestCase.fail("IllegalArgumentException expected");
- } catch (IllegalArgumentException iae) {
- // expected
- }
+ new Mapping("=user");
}
- @Test
+ @Test(expected = IllegalArgumentException.class)
public void test_constructor_empty_service_info() {
- try {
- new Mapping("srv:=user");
- TestCase.fail("IllegalArgumentException expected");
- } catch (IllegalArgumentException iae) {
- // expected
- }
+ new Mapping("srv:=user");
}
@Test
@@ -91,41 +65,115 @@ public class MappingTest {
@Test
public void test_constructor_and_map() {
- assertMapping("service", null, "user");
- assertMapping("service", "subServiceName", "user");
+ assertMapping("service", null, "user", (String[]) null);
+ assertMapping("service", "subServiceName", "user", (String[]) null);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void test_constructor_and_null_principals() {
+ assertMapping("service", "subServiceName", null, (String[]) null);
+ }
+
+ @Test
+ public void test_constructor_and_map_empty_principals() {
+ assertMapping("service", "subServiceName", null);
+ }
+
+ @Test
+ public void test_constructor_and_map_with_empty_principal() {
+ assertMapping("service", "subServiceName", null, "principal", "",
"principal1");
+ }
+
+ @Test
+ public void test_constructor_and_map_with_null_principal() {
+ assertMapping("service", "subServiceName", null, "principal", null,
"principal1");
+ }
+
+ @Test
+ public void test_constructor_and_map_single_principal() {
+ assertMapping("service", "subServiceName", null, "principal");
+ }
+
+ @Test
+ public void test_constructor_and_map_duplicate_principals() {
+ assertMapping("service", "subServiceName", null, "principal",
"principal");
+ }
+
+ @Test
+ public void test_constructor_and_map_principals() {
+ assertMapping("service", "subServiceName", null, "principal1",
"principal2", "principal3");
}
- private void assertMapping(final String serviceName, final String
subServiceName, final String userName) {
+ @Test
+ public void test_constructor_and_map_user_and_principals() {
+ assertMapping("service", "subServiceName", "user", "principal1",
"principal2", "principal3");
+ }
+
+ private void assertMapping(final String serviceName, final String
subServiceName, final String userName, final String... principalNames) {
StringBuilder spec = new StringBuilder();
spec.append(serviceName);
if (subServiceName != null) {
spec.append(':').append(subServiceName);
}
- spec.append('=').append(userName);
+ spec.append('=');
+
+ String expectedUserName = null;
+ Set<String> expectedPrincipalsNames = null;
+ if (principalNames != null) {
+ spec.append(Arrays.toString(principalNames));
+ expectedPrincipalsNames =
Mapping.extractPrincipalNames(Arrays.toString(principalNames));
+ } else if (userName != null) {
+ spec.append(userName);
+ expectedUserName = userName;
+ }
// spec analysis
final Mapping mapping = new Mapping(spec.toString());
- TestCase.assertEquals(getField(mapping, "serviceName"), serviceName);
- TestCase.assertEquals(getField(mapping, "subServiceName"),
subServiceName);
- TestCase.assertEquals(getField(mapping, "userName"), userName);
+ TestCase.assertEquals(serviceName, getField(mapping, "serviceName"));
+ TestCase.assertEquals(subServiceName, getField(mapping,
"subServiceName"));
+ if (expectedUserName == null) {
+ TestCase.assertNull(getField(mapping, "userName"));
+ } else {
+ TestCase.assertEquals(expectedUserName, getField(mapping,
"userName"));
+ }
+ if (principalNames == null) {
+ TestCase.assertNull(getSetField(mapping, "principalNames"));
+ } else {
+ TestCase.assertEquals(expectedPrincipalsNames,
getSetField(mapping, "principalNames"));
+ }
// mapping
- TestCase.assertEquals(userName, mapping.map(serviceName,
subServiceName));
+ if (expectedUserName == null) {
+ TestCase.assertNull(mapping.map(serviceName, subServiceName));
+ } else {
+ TestCase.assertEquals(userName, mapping.map(serviceName,
subServiceName));
+ }
+
+ if (expectedPrincipalsNames == null) {
+ TestCase.assertNull(mapping.mapPrincipals(serviceName,
subServiceName));
+ } else {
+ TestCase.assertEquals(expectedPrincipalsNames,
mapping.mapPrincipals(serviceName, subServiceName));
+ }
+
if (subServiceName == null) {
// Mapping without subServiceName must not match request with any
// subServiceName
TestCase.assertNull(mapping.map(serviceName, subServiceName +
"-garbage"));
+ TestCase.assertNull(mapping.mapPrincipals(serviceName,
subServiceName + "-garbage"));
} else {
// Mapping with subServiceName must not match request without
// subServiceName
TestCase.assertNull(mapping.map(serviceName, null));
+ TestCase.assertNull(mapping.mapPrincipals(serviceName, null));
}
// no match for different service name
TestCase.assertNull(mapping.map(serviceName + "-garbage",
subServiceName));
+ TestCase.assertNull(mapping.mapPrincipals(serviceName + "-garbage",
subServiceName));
// no match for null service name
TestCase.assertNull(mapping.map(null, subServiceName));
+ TestCase.assertNull(mapping.mapPrincipals(null, subServiceName));
}
private String getField(final Object object, final String fieldName) {
@@ -136,6 +184,17 @@ public class MappingTest {
} catch (Exception e) {
TestCase.fail("Cannot get field " + fieldName + ": " +
e.toString());
return null; // will not get here, quiesce compiler
+ }
+ }
+
+ private Set<String> getSetField(final Object object, final String
fieldName) {
+ try {
+ Field f = object.getClass().getDeclaredField(fieldName);
+ f.setAccessible(true);
+ return (Set<String>) f.get(object);
+ } catch (Exception e) {
+ TestCase.fail("Cannot get field " + fieldName + ": " +
e.toString());
+ return null; // will not get here, quiesce compiler
}
}
}
Modified:
sling/trunk/bundles/extensions/serviceusermapper/src/test/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImplTest.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/serviceusermapper/src/test/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImplTest.java?rev=1801482&r1=1801481&r2=1801482&view=diff
==============================================================================
---
sling/trunk/bundles/extensions/serviceusermapper/src/test/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImplTest.java
(original)
+++
sling/trunk/bundles/extensions/serviceusermapper/src/test/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImplTest.java
Mon Jul 10 15:40:52 2017
@@ -18,14 +18,22 @@
*/
package org.apache.sling.serviceusermapping.impl;
+import static junit.framework.TestCase.assertFalse;
+import static junit.framework.TestCase.assertNull;
+import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import java.util.Arrays;
import java.util.Dictionary;
import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
import java.util.Map;
+import java.util.Set;
+import org.apache.sling.serviceusermapping.ServicePrincipalsValidator;
import org.apache.sling.serviceusermapping.ServiceUserValidator;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
@@ -44,6 +52,10 @@ public class ServiceUserMapperImplTest {
private static final String BUNDLE_SYMBOLIC3 = "bundle3";
+ private static final String BUNDLE_SYMBOLIC4 = "bundle4";
+
+ private static final String BUNDLE_SYMBOLIC5 = "bundle5";
+
private static final String SUB = "sub";
private static final String NONE = "none";
@@ -62,6 +74,10 @@ public class ServiceUserMapperImplTest {
private static final Bundle BUNDLE3;
+ private static final Bundle BUNDLE4;
+
+ private static final Bundle BUNDLE5;
+
static {
BUNDLE1 = mock(Bundle.class);
when(BUNDLE1.getSymbolicName()).thenReturn(BUNDLE_SYMBOLIC1);
@@ -71,6 +87,12 @@ public class ServiceUserMapperImplTest {
BUNDLE3 = mock(Bundle.class);
when(BUNDLE3.getSymbolicName()).thenReturn(BUNDLE_SYMBOLIC3);
+
+ BUNDLE4 = mock(Bundle.class);
+ when(BUNDLE4.getSymbolicName()).thenReturn(BUNDLE_SYMBOLIC4);
+
+ BUNDLE5 = mock(Bundle.class);
+ when(BUNDLE5.getSymbolicName()).thenReturn(BUNDLE_SYMBOLIC5);
}
@Test
@@ -184,6 +206,125 @@ public class ServiceUserMapperImplTest {
}
@Test
+ public void test_getServicePrincipalNames() {
+ ServiceUserMapperImpl.Config config =
mock(ServiceUserMapperImpl.Config.class);
+ when(config.user_mapping()).thenReturn(new String[] {
+ BUNDLE_SYMBOLIC1 + "=[" + SAMPLE + "]", //
+ BUNDLE_SYMBOLIC2 + "=[ " + ANOTHER + " ]", //
+ BUNDLE_SYMBOLIC3 + "=[" + SAMPLE + "," + ANOTHER + "]", //
+ BUNDLE_SYMBOLIC4 + "=[ " + SAMPLE + ", " + ANOTHER + " ]", //
+ BUNDLE_SYMBOLIC5 + "=[]", //
+ BUNDLE_SYMBOLIC1 + ":" + SUB + "=[" + SAMPLE_SUB + "]", //
+ BUNDLE_SYMBOLIC2 + ":" + SUB + "=[" + SAMPLE_SUB + "," +
ANOTHER_SUB + "]" //
+ });
+
+ final ServiceUserMapperImpl sum = new ServiceUserMapperImpl();
+ sum.configure(null, config);
+
+ assertEqualPrincipalNames(sum.getServicePrincipalNames(BUNDLE1, null),
SAMPLE);
+ assertEqualPrincipalNames(sum.getServicePrincipalNames(BUNDLE2, null),
ANOTHER);
+ assertEqualPrincipalNames(sum.getServicePrincipalNames(BUNDLE3, null),
SAMPLE, ANOTHER);
+ assertEqualPrincipalNames(sum.getServicePrincipalNames(BUNDLE4, null),
SAMPLE, ANOTHER);
+ assertEqualPrincipalNames(sum.getServicePrincipalNames(BUNDLE5, null));
+ assertEqualPrincipalNames(sum.getServicePrincipalNames(BUNDLE1, SUB),
SAMPLE_SUB);
+ assertEqualPrincipalNames(sum.getServicePrincipalNames(BUNDLE2, SUB),
SAMPLE_SUB, ANOTHER_SUB);
+ }
+
+ @Test
+ public void test_getServicePrincipalNames_EmptySubService() {
+ ServiceUserMapperImpl.Config config =
mock(ServiceUserMapperImpl.Config.class);
+ when(config.user_mapping()).thenReturn(new String[] {
+ BUNDLE_SYMBOLIC1 + "=[" + SAMPLE + "]", //
+ BUNDLE_SYMBOLIC2 + "=[ " + ANOTHER + " ]", //
+ });
+
+ final ServiceUserMapperImpl sum = new ServiceUserMapperImpl();
+ sum.configure(null, config);
+
+ assertEqualPrincipalNames(sum.getServicePrincipalNames(BUNDLE1, ""),
SAMPLE);
+ assertEqualPrincipalNames(sum.getServicePrincipalNames(BUNDLE2, ""),
ANOTHER);
+ }
+
+ @Test
+ public void test_getServicePrincipalNames_WithUserNameConfig() {
+ ServiceUserMapperImpl.Config config =
mock(ServiceUserMapperImpl.Config.class);
+ when(config.user_mapping()).thenReturn(new String[] {
+ BUNDLE_SYMBOLIC1 + "=" + SAMPLE, //
+ BUNDLE_SYMBOLIC1 + ":" + SUB + "=" + SAMPLE_SUB, //
+ });
+ when(config.user_default()).thenReturn(NONE);
+ when(config.user_enable_default_mapping()).thenReturn(false);
+
+ final ServiceUserMapperImpl sum = new ServiceUserMapperImpl();
+ sum.configure(null, config);
+
+ assertNull(sum.getServicePrincipalNames(BUNDLE1, null));
+ assertNull(SAMPLE_SUB, sum.getServicePrincipalNames(BUNDLE1, SUB));
+ }
+
+ @Test
+ public void test_getServicePrincipalNames_IgnoresDefaultUser() {
+ ServiceUserMapperImpl.Config config =
mock(ServiceUserMapperImpl.Config.class);
+ when(config.user_default()).thenReturn(NONE);
+ when(config.user_enable_default_mapping()).thenReturn(true);
+
+ final ServiceUserMapperImpl sum = new ServiceUserMapperImpl();
+ sum.configure(null, config);
+
+ assertNull(sum.getServicePrincipalNames(BUNDLE1, null));
+ assertNull(sum.getServicePrincipalNames(BUNDLE1, SUB));
+ }
+
+ @Test
+ public void test_getServicePrincipalnames_WithServicePrincipalsValidator()
{
+ ServiceUserMapperImpl.Config config =
mock(ServiceUserMapperImpl.Config.class);
+ when(config.user_mapping()).thenReturn(new String[] {
+ BUNDLE_SYMBOLIC1 + "=[" + SAMPLE + "]", //
+ BUNDLE_SYMBOLIC2 + "=[" + SAMPLE + "," + ANOTHER + "]", //
+ BUNDLE_SYMBOLIC1 + ":" + SUB + "=[" + SAMPLE + "," +
SAMPLE_SUB + "]", //
+ BUNDLE_SYMBOLIC2 + ":" + SUB + "=[" + ANOTHER_SUB + "," +
SAMPLE_SUB + "," + SAMPLE + "]"//
+ });
+
+ final ServiceUserMapperImpl sum = new ServiceUserMapperImpl();
+ sum.configure(null, config);
+ ServicePrincipalsValidator validator = new
ServicePrincipalsValidator() {
+ @Override
+ public boolean isValid(Iterable<String> servicePrincipalNames,
String serviceName, String subServiceName) {
+ for (String pName : servicePrincipalNames) {
+ if (SAMPLE.equals(pName)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ };
+ sum.bindServicePrincipalsValidator(validator);
+
+ assertNull(sum.getServicePrincipalNames(BUNDLE1, null));
+ assertNull(sum.getServicePrincipalNames(BUNDLE2, null));
+ assertNull(sum.getServicePrincipalNames(BUNDLE1, SUB));
+ assertNull(sum.getServicePrincipalNames(BUNDLE2, SUB));
+ }
+
+ private static void assertEqualPrincipalNames(Iterable<String> result,
String... expected) {
+ if (expected == null) {
+ assertNull(result);
+ } else if (expected.length == 0) {
+ assertFalse(result.iterator().hasNext());
+ } else {
+ Set<String> resultSet = new HashSet<>();
+ Iterator<String> it = result.iterator();
+ while (it.hasNext()) {
+ resultSet.add(it.next());
+ }
+ Set<String> expectedSet = new HashSet<>();
+ expectedSet.addAll(Arrays.asList(expected));
+ assertEquals(expectedSet, resultSet);
+ }
+ }
+
+
+ @Test
public void test_amendment() {
ServiceUserMapperImpl.Config config =
mock(ServiceUserMapperImpl.Config.class);
when(config.user_mapping()).thenReturn(new String[] {