import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Arrays;
+import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
+import java.util.SortedSet;
import java.util.concurrent.Executor;
import javax.jcr.Node;
import javax.jcr.Property;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
-import javax.jcr.nodetype.NodeType;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.argeo.security.jcr.JcrUserDetails;
import org.springframework.ldap.core.DirContextAdapter;
import org.springframework.ldap.core.DirContextOperations;
+import org.springframework.security.BadCredentialsException;
import org.springframework.security.GrantedAuthority;
import org.springframework.security.context.SecurityContextHolder;
import org.springframework.security.providers.encoding.PasswordEncoder;
private PasswordEncoder passwordEncoder;
private final Random random;
+ /** 0 is always sync */
+ private Long syncLatency = 10 * 60 * 1000l;
+
public JcrUserDetailsContextMapper() {
random = createRandom();
}
public UserDetails mapUserFromContext(final DirContextOperations ctx,
final String username, GrantedAuthority[] authorities) {
+ if (ctx == null)
+ throw new ArgeoException("No LDAP information found for user "
+ + username);
+
final StringBuffer userHomePathT = new StringBuffer("");
Runnable action = new Runnable() {
public void run() {
}
// password
- byte[] arr = (byte[]) ctx
- .getAttributeSortedStringSet(passwordAttribute).first();
+ SortedSet<?> passwordAttributes = ctx
+ .getAttributeSortedStringSet(passwordAttribute);
+ String password;
+ if (passwordAttributes == null || passwordAttributes.size() == 0) {
+ throw new ArgeoException("No password found for user " + username);
+ } else {
+ byte[] arr = (byte[]) passwordAttributes.first();
+ password = new String(arr);
+ // erase password
+ Arrays.fill(arr, (byte) 0);
+ }
JcrUserDetails userDetails = new JcrUserDetails(
- userHomePathT.toString(), username, new String(arr), true,
- true, true, true, authorities);
- // erase password
- Arrays.fill(arr, (byte) 0);
+ userHomePathT.toString(), username, password, true, true, true,
+ true, authorities);
return userDetails;
}
/** @return path to the user home node */
- protected String mapLdapToJcr(String username, DirContextOperations ctx) {
+ protected synchronized String mapLdapToJcr(String username,
+ DirContextOperations ctx) {
+ String usernameLdap = ctx.getStringAttribute(usernameAttribute);
+ // log.debug("username=" + username + ", usernameLdap=" + usernameLdap);
+ if (!username.equals(usernameLdap)) {
+ String msg = "Provided username '" + username
+ + "' is different from username stored in LDAP '"
+ + usernameLdap + "'";
+ // we log it because the exception may not be displayed
+ log.error(msg);
+ throw new BadCredentialsException(msg);
+ }
+
try {
+
Node userHome = JcrUtils.getUserHome(session, username);
- if (userHome == null)
+ boolean justCreatedHome = false;
+ if (userHome == null) {
userHome = JcrUtils.createUserHome(session, homeBasePath,
username);
+ justCreatedHome = true;
+ }
String userHomePath = userHome.getPath();
- Node userProfile = userHome.getNode(ARGEO_PROFILE);
+ Node userProfile; // = userHome.getNode(ARGEO_PROFILE);
if (userHome.hasNode(ARGEO_PROFILE)) {
userProfile = userHome.getNode(ARGEO_PROFILE);
+ if (syncLatency != 0 && !justCreatedHome) {
+ Calendar lastModified = userProfile.getProperty(
+ Property.JCR_LAST_MODIFIED).getDate();
+ long timeSinceLastUpdate = System.currentTimeMillis()
+ - lastModified.getTimeInMillis();
+ if (timeSinceLastUpdate < syncLatency)// skip sync
+ return userHomePath;
+ }
} else {
- userProfile = userHome.addNode(ARGEO_PROFILE);
- userProfile.addMixin(NodeType.MIX_TITLE);
- userProfile.addMixin(NodeType.MIX_CREATED);
- userProfile.addMixin(NodeType.MIX_LAST_MODIFIED);
+ throw new ArgeoException("We should never reach this point");
+ // userProfile = userHome.addNode(ARGEO_PROFILE);
+ // userProfile.addMixin(NodeType.MIX_TITLE);
+ // userProfile.addMixin(NodeType.MIX_CREATED);
+ // userProfile.addMixin(NodeType.MIX_LAST_MODIFIED);
}
+ session.getWorkspace().getVersionManager()
+ .checkout(userProfile.getPath());
for (String jcrProperty : propertyToAttributes.keySet())
ldapToJcr(userProfile, jcrProperty, ctx);
.getProperty(ARGEO_FIRST_NAME).getString()
+ " "
+ userProfile.getProperty(ARGEO_LAST_NAME).getString());
-
+ JcrUtils.updateLastModified(userProfile);
session.save();
+ session.getWorkspace().getVersionManager()
+ .checkin(userProfile.getPath());
if (log.isTraceEnabled())
log.trace("Mapped " + ctx.getDn() + " to " + userProfile);
return userHomePath;
+ jcrProperty);
String value = ctx.getStringAttribute(ldapAttribute);
- if (value == null)
- return;
- userProfile.setProperty(jcrProperty, value);
+ String jcrValue = userProfile.hasProperty(jcrProperty) ? userProfile
+ .getProperty(jcrProperty).getString() : null;
+ if (value != null && jcrValue != null) {
+ if (!value.equals(jcrValue))
+ userProfile.setProperty(jcrProperty, value);
+ } else if (value != null && jcrValue == null) {
+ userProfile.setProperty(jcrProperty, value);
+ } else if (value == null && jcrValue != null) {
+ userProfile.setProperty(jcrProperty, value);
+ }
} catch (Exception e) {
throw new ArgeoException("Cannot map JCR property " + jcrProperty
+ " from LDAP", e);
if (ldapAttribute.equals("description")) {
String value = userProfile.getProperty(jcrProperty).getString();
- if(value.trim().equals(""))
+ if (value.trim().equals(""))
return;
}
this.session = session;
}
+ /**
+ * Time in ms during which the LDAP server is not checked. 0 is always sync.
+ */
+ public void setSyncLatency(Long syncLatency) {
+ this.syncLatency = syncLatency;
+ }
+
}