X-Git-Url: https://git.argeo.org/?a=blobdiff_plain;f=security%2Fruntime%2Forg.argeo.security.ldap%2Fsrc%2Fmain%2Fjava%2Forg%2Fargeo%2Fsecurity%2Fldap%2Fjcr%2FJcrUserDetailsContextMapper.java;h=86c788a448e5188f8afd6902188e955b492bf2fb;hb=b614eb03ce70d86fd6d02fc443ce11e7125e467d;hp=b5b77474cb2e40bc71c3a29d797640cc03e72f7e;hpb=772c16a288d19cc10a320c3798b30d6d02f969ba;p=lgpl%2Fargeo-commons.git diff --git a/security/runtime/org.argeo.security.ldap/src/main/java/org/argeo/security/ldap/jcr/JcrUserDetailsContextMapper.java b/security/runtime/org.argeo.security.ldap/src/main/java/org/argeo/security/ldap/jcr/JcrUserDetailsContextMapper.java index b5b77474c..86c788a44 100644 --- a/security/runtime/org.argeo.security.ldap/src/main/java/org/argeo/security/ldap/jcr/JcrUserDetailsContextMapper.java +++ b/security/runtime/org.argeo.security.ldap/src/main/java/org/argeo/security/ldap/jcr/JcrUserDetailsContextMapper.java @@ -1,25 +1,184 @@ package org.argeo.security.ldap.jcr; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import javax.jcr.Node; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.jcr.RepositoryFactory; import javax.jcr.Session; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.ArgeoException; +import org.argeo.jcr.ArgeoJcrConstants; +import org.argeo.jcr.ArgeoNames; +import org.argeo.jcr.JcrUtils; +import org.argeo.security.SystemExecutionService; +import org.argeo.security.jcr.JcrUserDetails; import org.springframework.ldap.core.DirContextAdapter; import org.springframework.ldap.core.DirContextOperations; import org.springframework.security.GrantedAuthority; import org.springframework.security.userdetails.UserDetails; import org.springframework.security.userdetails.ldap.UserDetailsContextMapper; +/** + * Maps LDAP attributes and JCR properties. This class is meant to be robust, + * checks of which values should be mandatory should be performed at a higher + * level. + */ public class JcrUserDetailsContextMapper implements UserDetailsContextMapper { - private Session session; + private final static Log log = LogFactory + .getLog(JcrUserDetailsContextMapper.class); + + private Map propertyToAttributes = new HashMap(); + private SystemExecutionService systemExecutionService; + private String homeBasePath = "/home"; + private RepositoryFactory repositoryFactory; + + public UserDetails mapUserFromContext(final DirContextOperations ctx, + final String username, GrantedAuthority[] authorities) { + if (repositoryFactory == null) + throw new ArgeoException("No JCR repository factory registered"); + final String userHomePath = usernameToHomePath(username); + systemExecutionService.executeAsSystem(new Runnable() { + public void run() { + Session session = null; + try { + Repository nodeRepo = JcrUtils.getRepositoryByAlias( + repositoryFactory, ArgeoJcrConstants.ALIAS_NODE); + session = nodeRepo.login(); + Node userProfile = JcrUtils.mkdirs(session, userHomePath + + '/' + ArgeoNames.ARGEO_USER_PROFILE); + for (String jcrProperty : propertyToAttributes.keySet()) + ldapToJcr(userProfile, jcrProperty, ctx); + session.save(); + if (log.isDebugEnabled()) + log.debug("Mapped " + ctx.getDn() + " to " + + userProfile); + } catch (RepositoryException e) { + throw new ArgeoException("Cannot synchronize JCR and LDAP", + e); + } finally { + session.logout(); + } + } + }); - public UserDetails mapUserFromContext(DirContextOperations ctx, - String username, GrantedAuthority[] authority) { - // TODO Auto-generated method stub - return null; + // password + byte[] arr = (byte[]) ctx.getAttributeSortedStringSet("userPassword") + .first(); + JcrUserDetails userDetails = new JcrUserDetails(userHomePath, username, + new String(arr), true, true, true, true, authorities); + Arrays.fill(arr, (byte) 0); + return userDetails; } - public void mapUserToContext(UserDetails user, DirContextAdapter ctx) { - // TODO Auto-generated method stub + public void mapUserToContext(UserDetails user, final DirContextAdapter ctx) { + if (!(user instanceof JcrUserDetails)) + throw new ArgeoException("Unsupported user details: " + + user.getClass()); + + ctx.setAttributeValues("objectClass", new String[] { "inetOrgPerson" }); + ctx.setAttributeValue("uid", user.getUsername()); + ctx.setAttributeValue("userPassword", user.getPassword()); + + final JcrUserDetails jcrUserDetails = (JcrUserDetails) user; + systemExecutionService.executeAsSystem(new Runnable() { + public void run() { + Session session = null; + try { + Repository nodeRepo = JcrUtils.getRepositoryByAlias( + repositoryFactory, ArgeoJcrConstants.ALIAS_NODE); + session = nodeRepo.login(); + Node userProfile = session.getNode(jcrUserDetails + .getHomePath() + + '/' + + ArgeoNames.ARGEO_USER_PROFILE); + for (String jcrProperty : propertyToAttributes.keySet()) + jcrToLdap(userProfile, jcrProperty, ctx); + if (log.isDebugEnabled()) + log.debug("Mapped " + userProfile + " to " + + ctx.getDn()); + } catch (RepositoryException e) { + throw new ArgeoException("Cannot synchronize JCR and LDAP", + e); + } finally { + session.logout(); + } + } + }); + } + protected String usernameToHomePath(String username) { + return homeBasePath + '/' + JcrUtils.firstCharsToPath(username, 2) + + '/' + username; } + protected void ldapToJcr(Node userProfile, String jcrProperty, + DirContextOperations ctx) { + try { + String ldapAttribute; + if (propertyToAttributes.containsKey(jcrProperty)) + ldapAttribute = propertyToAttributes.get(jcrProperty); + else + throw new ArgeoException( + "No LDAP attribute mapped for JCR proprty " + + jcrProperty); + + String value = ctx.getStringAttribute(ldapAttribute); + if (value == null) + return; + userProfile.setProperty(jcrProperty, value); + } catch (Exception e) { + throw new ArgeoException("Cannot map JCR property " + jcrProperty + + " from LDAP", e); + } + } + + protected void jcrToLdap(Node userProfile, String jcrProperty, + DirContextOperations ctx) { + try { + if (!userProfile.hasProperty(jcrProperty)) + return; + String value = userProfile.getProperty(jcrProperty).getString(); + + String ldapAttribute; + if (propertyToAttributes.containsKey(jcrProperty)) + ldapAttribute = propertyToAttributes.get(jcrProperty); + else + throw new ArgeoException( + "No LDAP attribute mapped for JCR proprty " + + jcrProperty); + ctx.setAttributeValue(ldapAttribute, value); + } catch (Exception e) { + throw new ArgeoException("Cannot map JCR property " + jcrProperty + + " from LDAP", e); + } + } + + public void setPropertyToAttributes(Map propertyToAttributes) { + this.propertyToAttributes = propertyToAttributes; + } + + public void setSystemExecutionService( + SystemExecutionService systemExecutionService) { + this.systemExecutionService = systemExecutionService; + } + + public void setHomeBasePath(String homeBasePath) { + this.homeBasePath = homeBasePath; + } + + public void register(RepositoryFactory repositoryFactory, + Map parameters) { + this.repositoryFactory = repositoryFactory; + } + + public void unregister(RepositoryFactory repositoryFactory, + Map parameters) { + this.repositoryFactory = null; + } }