Updated properties sync to use a mapping defined in the OSGI configs such that the name and relative path of the save property can be configured (instead of using the saml attribute's Friendly Name)
diff --git a/saml-handler/src/main/java/org/apache/sling/auth/saml2/AuthenticationHandlerSAML2Config.java b/saml-handler/src/main/java/org/apache/sling/auth/saml2/AuthenticationHandlerSAML2Config.java
index 4b0ac3b..7b16619 100644
--- a/saml-handler/src/main/java/org/apache/sling/auth/saml2/AuthenticationHandlerSAML2Config.java
+++ b/saml-handler/src/main/java/org/apache/sling/auth/saml2/AuthenticationHandlerSAML2Config.java
@@ -66,7 +66,7 @@
String saml2groupMembershipAttr() default "";
@AttributeDefinition(name = "Synchronize User Attributes",
- description="List of Names from SAML Response to Synchronize")
+ description="Map of attributes from SAML Response to Synchronize. For example, urn:oid:1.2.840.113549.1.9.1=./profile/email saves this attribute if it exists under the users profile node with the property name 'email' ")
String[] syncAttrs() default {};
@AttributeDefinition(name = "SAML2 Session Attribute",
diff --git a/saml-handler/src/main/java/org/apache/sling/auth/saml2/impl/AbstractSamlHandler.java b/saml-handler/src/main/java/org/apache/sling/auth/saml2/impl/AbstractSamlHandler.java
index 7f365c4..719cbbb 100644
--- a/saml-handler/src/main/java/org/apache/sling/auth/saml2/impl/AbstractSamlHandler.java
+++ b/saml-handler/src/main/java/org/apache/sling/auth/saml2/impl/AbstractSamlHandler.java
@@ -23,6 +23,9 @@
import org.apache.sling.auth.core.spi.DefaultAuthenticationFeedbackHandler;
import org.apache.sling.auth.saml2.AuthenticationHandlerSAML2Config;
+import java.util.HashMap;
+import java.util.Map;
+
abstract class AbstractSamlHandler extends DefaultAuthenticationFeedbackHandler {
// OSGI Configs
@@ -43,6 +46,7 @@
private String acsPath;
private String[] syncAttrs;
private String saml2LogoutURL;
+ private Map syncAttrMap;
public static final String GOTO_URL_SESSION_ATTRIBUTE = "gotoURL";
public static final String SAML2_REQUEST_ID = "saml2RequestID";
@@ -66,6 +70,7 @@
this.acsPath = config.acsPath();
this.syncAttrs = config.syncAttrs();
this.saml2LogoutURL = config.saml2LogoutURL();
+ setSyncMap();
}
// GETTERS
@@ -120,11 +125,20 @@
String[] getSyncAttrs() {
return this.syncAttrs;
}
+ Map<String,String> getSyncAttrMap(){ return this.syncAttrMap; }
String getACSURL() {
final String domain = entityID.endsWith("/") ? entityID.substring(0, entityID.length()-1) : entityID;
return domain + this.getAcsPath();
}
-
+ void setSyncMap(){
+ this.syncAttrMap = new HashMap<>();
+ for(String attr : getSyncAttrs()){
+ String[] parts = attr.split("=");
+ if(parts != null && parts.length==2){
+ this.syncAttrMap.put(parts[0],parts[1]);
+ }
+ }
+ }
}
diff --git a/saml-handler/src/main/java/org/apache/sling/auth/saml2/impl/AuthenticationHandlerSAML2Impl.java b/saml-handler/src/main/java/org/apache/sling/auth/saml2/impl/AuthenticationHandlerSAML2Impl.java
index fb0a11a..0e5a288 100644
--- a/saml-handler/src/main/java/org/apache/sling/auth/saml2/impl/AuthenticationHandlerSAML2Impl.java
+++ b/saml-handler/src/main/java/org/apache/sling/auth/saml2/impl/AuthenticationHandlerSAML2Impl.java
@@ -478,20 +478,14 @@
// start a user object
Saml2User saml2User = new Saml2User();
- // get list of configured attribute names to synchronize from the IDP assertion to the user's properties
- List<String> attrNamesToSync = null;
- if (this.getSyncAttrs() != null && this.getSyncAttrs().length > 0) {
- attrNamesToSync = Arrays.asList(this.getSyncAttrs());
- }
-
// iterate the attribute assertions
for (Attribute attribute : assertion.getAttributeStatements().get(0).getAttributes()) {
if (attribute.getName().equals(this.getSaml2userIDAttr())) {
setUserId(attribute, saml2User);
} else if (attribute.getName().equals(this.getSaml2groupMembershipAttr())) {
setGroupMembership(attribute, saml2User);
- } else if (attrNamesToSync != null && attrNamesToSync.contains(attribute.getName())) {
- syncUserAttributes(attribute, saml2User);
+ } else if (this.getSyncAttrMap() != null && this.getSyncAttrMap().containsKey(attribute.getName())){
+ syncUserAttributes(attribute, saml2User, this.getSyncAttrMap().get(attribute.getName()));
}
}
@@ -535,16 +529,12 @@
}
}
- private void syncUserAttributes(Attribute attribute, Saml2User saml2User) {
+ private void syncUserAttributes(Attribute attribute, Saml2User saml2User, String propertyName) {
for (XMLObject attributeValue : attribute.getAttributeValues()) {
- if ( ((XSString) attributeValue).getValue() != null ) {
- if (attribute.getFriendlyName() != null && !attribute.getFriendlyName().isEmpty()) {
- saml2User.addUserProperty(attribute.getFriendlyName(), attributeValue);
- logger.debug("sync attr name: {0}", attribute.getFriendlyName());
- logger.debug("attribute value: {0}", ((XSString) attributeValue).getValue());
- } else {
- logger.warn("attribute has no friendly name and cannot be added: {0}", ((XSString) attributeValue).getValue());
- }
+ if (((XSString) attributeValue).getValue() != null ) {
+ saml2User.addUserProperty(propertyName, attributeValue);
+ logger.debug("sync attr name: {0}", propertyName);
+ logger.debug("attribute value: {0}", ((XSString) attributeValue).getValue());
}
}
}
diff --git a/saml-handler/src/main/java/org/apache/sling/auth/saml2/impl/Saml2UserMgtServiceImpl.java b/saml-handler/src/main/java/org/apache/sling/auth/saml2/impl/Saml2UserMgtServiceImpl.java
index 51b4db5..c9ec1e8 100644
--- a/saml-handler/src/main/java/org/apache/sling/auth/saml2/impl/Saml2UserMgtServiceImpl.java
+++ b/saml-handler/src/main/java/org/apache/sling/auth/saml2/impl/Saml2UserMgtServiceImpl.java
@@ -163,7 +163,7 @@
try {
User jcrUser = (User) this.userManager.getAuthorizable(user.getId());
for (Map.Entry<String,String> entry : user.getUserProperties().entrySet()) {
- jcrUser.setProperty("./profile/"+entry.getKey(), vf.createValue(entry.getValue()));
+ jcrUser.setProperty(entry.getKey(), vf.createValue(entry.getValue()));
}
session.save();
return true;
diff --git a/saml-handler/src/test/java/org/apache/sling/auth/saml2/SamlHandlerIT.java b/saml-handler/src/test/java/org/apache/sling/auth/saml2/SamlHandlerIT.java
index 32c705d..18fa9cc 100644
--- a/saml-handler/src/test/java/org/apache/sling/auth/saml2/SamlHandlerIT.java
+++ b/saml-handler/src/test/java/org/apache/sling/auth/saml2/SamlHandlerIT.java
@@ -19,7 +19,6 @@
package org.apache.sling.auth.saml2;
-import com.google.common.collect.Iterators;
import org.apache.commons.lang3.StringUtils;
import org.apache.jackrabbit.api.JackrabbitSession;
import org.apache.jackrabbit.api.security.user.Authorizable;
@@ -68,7 +67,6 @@
import java.util.Base64;
import java.util.Iterator;
import java.util.List;
-
import static org.apache.sling.auth.core.spi.AuthenticationHandler.REQUEST_LOGIN_PARAMETER;
import static org.apache.sling.auth.saml2.impl.JKSHelper.IDP_ALIAS;
import static org.apache.sling.auth.saml2.impl.JKSHelper.SP_ALIAS;
@@ -200,10 +198,10 @@
.asOption(),
// supply the required configuration so the auth handler service will activate
testBundle("bundle.filename"), // from TestSupport
-// urn:oid:1.2.840.113549.1.9.1 = email
-// urn:oid:2.5.4.4 = surname
-// urn:oid:2.5.4.42 = givenName
-// phone is configured but not included
+// urn:oid:1.2.840.113549.1.9.1=profile/email
+// urn:oid:2.5.4.4=profile/surname
+// urn:oid:2.5.4.42=profile/givenName
+// phone=profile/phone is configured but not included in assertion
factoryConfiguration("org.apache.sling.auth.saml2.AuthenticationHandlerSAML2")
.put("path", "/")
.put("entityID", "http://localhost:8080/")
@@ -211,7 +209,7 @@
.put("saml2userIDAttr", "urn:oid:0.9.2342.19200300.100.1.1")
.put("saml2userHome", "/home/users/saml")
.put("saml2groupMembershipAttr", "urn:oid:2.16.840.1.113719.1.1.4.1.25")
- .put("syncAttrs", new String[]{"urn:oid:2.5.4.4","urn:oid:2.5.4.42","phone","urn:oid:1.2.840.113549.1.9.1"})
+ .put("syncAttrs", new String[]{"urn:oid:2.5.4.4=./profile/surname","urn:oid:2.5.4.42=./profile/givenName","phone=./profile/phone","urn:oid:1.2.840.113549.1.9.1=./profile/email"})
.put("saml2SPEnabled", true)
.put("saml2SPEncryptAndSign", false)
.put("jksFileLocation", "")