Improve RAP security
[lgpl/argeo-commons.git] / security / runtime / org.argeo.security.ldap / src / main / java / org / argeo / security / ldap / jcr / JcrUserDetailsContextMapper.java
index 2d9fb1c1adf05cecf42a85c3137602d2b70d4163..0e8dbab32abff9c117bf466460c9f88126f7579d 100644 (file)
@@ -1,8 +1,11 @@
 package org.argeo.security.ldap.jcr;
 
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Random;
 import java.util.concurrent.Executor;
 
 import javax.jcr.Node;
@@ -10,6 +13,7 @@ import javax.jcr.Repository;
 import javax.jcr.RepositoryException;
 import javax.jcr.RepositoryFactory;
 import javax.jcr.Session;
+import javax.jcr.nodetype.NodeType;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -22,6 +26,8 @@ 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.context.SecurityContextHolder;
+import org.springframework.security.providers.encoding.PasswordEncoder;
 import org.springframework.security.userdetails.UserDetails;
 import org.springframework.security.userdetails.ldap.UserDetailsContextMapper;
 
@@ -42,19 +48,38 @@ public class JcrUserDetailsContextMapper implements UserDetailsContextMapper,
 
        private Map<String, String> propertyToAttributes = new HashMap<String, String>();
        private Executor systemExecutor;
-       private RepositoryFactory repositoryFactory;
+       private Session session;
+
+       private PasswordEncoder passwordEncoder;
+       private final Random random;
+
+       public JcrUserDetailsContextMapper() {
+               random = createRandom();
+       }
+
+       private static Random createRandom() {
+               try {
+                       return SecureRandom.getInstance("SHA1PRNG");
+               } catch (NoSuchAlgorithmException e) {
+                       return new Random(System.currentTimeMillis());
+               }
+       }
 
        public UserDetails mapUserFromContext(final DirContextOperations ctx,
                        final String username, GrantedAuthority[] authorities) {
-               if (repositoryFactory == null)
-                       throw new ArgeoException("No JCR repository factory registered");
+               // if (repository == null)
+               // throw new ArgeoException("No JCR repository registered");
                final StringBuffer userHomePathT = new StringBuffer("");
-               systemExecutor.execute(new Runnable() {
+               Runnable action = new Runnable() {
                        public void run() {
                                String userHomepath = mapLdapToJcr(username, ctx);
                                userHomePathT.append(userHomepath);
                        }
-               });
+               };
+               if (SecurityContextHolder.getContext().getAuthentication() == null)// authentication
+                       systemExecutor.execute(action);
+               else
+                       action.run();
 
                // password
                byte[] arr = (byte[]) ctx
@@ -69,18 +94,24 @@ public class JcrUserDetailsContextMapper implements UserDetailsContextMapper,
 
        /** @return path to the user home node */
        protected String mapLdapToJcr(String username, DirContextOperations ctx) {
-               Session session = null;
+               // Session session = null;
                try {
-                       Repository nodeRepo = JcrUtils.getRepositoryByAlias(
-                                       repositoryFactory, ArgeoJcrConstants.ALIAS_NODE);
-                       session = nodeRepo.login();
+                       // Repository nodeRepo = JcrUtils.getRepositoryByAlias(
+                       // repositoryFactory, ArgeoJcrConstants.ALIAS_NODE);
+                       // session = nodeRepo.login();
                        Node userHome = JcrUtils.getUserHome(session, username);
                        if (userHome == null)
                                userHome = createUserHome(session, username);
                        String userHomePath = userHome.getPath();
-                       Node userProfile = userHome.hasNode(ARGEO_USER_PROFILE) ? userHome
-                                       .getNode(ARGEO_USER_PROFILE) : userHome
-                                       .addNode(ARGEO_USER_PROFILE);
+                       Node userProfile;
+                       if (userHome.hasNode(ARGEO_USER_PROFILE)) {
+                               userProfile = userHome.getNode(ARGEO_USER_PROFILE);
+                       } else {
+                               userProfile = userHome.addNode(ARGEO_USER_PROFILE);
+                               userProfile.addMixin(NodeType.MIX_TITLE);
+                               userProfile.addMixin(NodeType.MIX_CREATED);
+                               userProfile.addMixin(NodeType.MIX_LAST_MODIFIED);
+                       }
                        for (String jcrProperty : propertyToAttributes.keySet())
                                ldapToJcr(userProfile, jcrProperty, ctx);
                        session.save();
@@ -91,7 +122,7 @@ public class JcrUserDetailsContextMapper implements UserDetailsContextMapper,
                        JcrUtils.discardQuietly(session);
                        throw new ArgeoException("Cannot synchronize JCR and LDAP", e);
                } finally {
-                       session.logout();
+                       // JcrUtils.logoutQuietly(session);
                }
        }
 
@@ -120,31 +151,40 @@ public class JcrUserDetailsContextMapper implements UserDetailsContextMapper,
 
                ctx.setAttributeValues("objectClass", userClasses);
                ctx.setAttributeValue(usernameAttribute, user.getUsername());
-               ctx.setAttributeValue(passwordAttribute, user.getPassword());
+               ctx.setAttributeValue(passwordAttribute,
+                               encodePassword(user.getPassword()));
 
                final JcrUserDetails jcrUserDetails = (JcrUserDetails) user;
-               systemExecutor.execute(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() + '/' + 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();
-                               }
-                       }
-               });
+               // systemExecutor.execute(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()
+                                       + '/' + 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 encodePassword(String password) {
+               if (!password.startsWith("{")) {
+                       byte[] salt = new byte[16];
+                       random.nextBytes(salt);
+                       return passwordEncoder.encodePassword(password, salt);
+               } else {
+                       return password;
+               }
        }
 
        protected void ldapToJcr(Node userProfile, String jcrProperty,
@@ -201,15 +241,15 @@ public class JcrUserDetailsContextMapper implements UserDetailsContextMapper,
                this.homeBasePath = homeBasePath;
        }
 
-       public void register(RepositoryFactory repositoryFactory,
-                       Map<String, String> parameters) {
-               this.repositoryFactory = repositoryFactory;
-       }
-
-       public void unregister(RepositoryFactory repositoryFactory,
-                       Map<String, String> parameters) {
-               this.repositoryFactory = null;
-       }
+       // public void register(RepositoryFactory repositoryFactory,
+       // Map<String, String> parameters) {
+       // this.repositoryFactory = repositoryFactory;
+       // }
+       //
+       // public void unregister(RepositoryFactory repositoryFactory,
+       // Map<String, String> parameters) {
+       // this.repositoryFactory = null;
+       // }
 
        public void setUsernameAttribute(String usernameAttribute) {
                this.usernameAttribute = usernameAttribute;
@@ -223,4 +263,12 @@ public class JcrUserDetailsContextMapper implements UserDetailsContextMapper,
                this.userClasses = userClasses;
        }
 
+       public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
+               this.passwordEncoder = passwordEncoder;
+       }
+
+       public void setSession(Session session) {
+               this.session = session;
+       }
+
 }