Use bind authentication in LDAP
authorMathieu Baudier <mbaudier@argeo.org>
Wed, 23 Mar 2011 10:45:09 +0000 (10:45 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Wed, 23 Mar 2011 10:45:09 +0000 (10:45 +0000)
Deifnitive node definitions for user home and profiles

git-svn-id: https://svn.argeo.org/commons/trunk@4341 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

security/modules/org.argeo.security.dao.ldap/META-INF/spring/ldap.xml
security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/editors/ArgeoUserEditor.java
security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/views/UsersView.java
security/runtime/org.argeo.security.ldap/src/main/java/org/argeo/security/ldap/jcr/JcrUserDetailsContextMapper.java
server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/ArgeoNames.java
server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/ArgeoTypes.java
server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java
server/runtime/org.argeo.server.jcr/src/main/resources/org/argeo/jcr/argeo.cnd

index 77a6ac7d5b48d9281420f38a67c5b9d8c562abd2..e990cad8b2937789e087fa032f092295314c0118 100644 (file)
        <!-- AUTHENTICATION -->
        <bean id="ldapAuthenticationProvider"
                class="org.springframework.security.providers.ldap.LdapAuthenticationProvider">
-               <constructor-arg ref="passwordComparisonAuthenticator" />
+               <constructor-arg ref="ldapAuthenticator" />
                <constructor-arg ref="authoritiesPopulator" />
                <property name="userDetailsContextMapper" ref="jcrUserDetailsContextMapper" />
        </bean>
 
-       <bean id="passwordComparisonAuthenticator"
-               class="org.springframework.security.providers.ldap.authenticator.PasswordComparisonAuthenticator">
+       <bean id="ldapAuthenticator"
+               class="org.springframework.security.providers.ldap.authenticator.BindAuthenticator">
                <constructor-arg ref="contextSource" />
                <property name="userDnPatterns">
                        <list>
                                <value><![CDATA[${argeo.ldap.usernameAttribute}={0},${argeo.ldap.userBase}]]></value>
                        </list>
                </property>
-               <property name="passwordAttributeName" value="${argeo.ldap.passwordAttribute}" />
-               <property name="passwordEncoder" ref="passwordEncoder" />
        </bean>
 
+       <!-- DOESN'T WORK WITH SSHA -->
+       <!-- <bean id="passwordComparisonAuthenticator" -->
+       <!-- class="org.springframework.security.providers.ldap.authenticator.PasswordComparisonAuthenticator"> -->
+       <!-- <constructor-arg ref="contextSource" /> -->
+       <!-- <property name="userDnPatterns"> -->
+       <!-- <list> -->
+       <!-- <value><![CDATA[${argeo.ldap.usernameAttribute}={0},${argeo.ldap.userBase}]]></value> -->
+       <!-- </list> -->
+       <!-- </property> -->
+       <!-- <property name="passwordAttributeName" value="${argeo.ldap.passwordAttribute}" 
+               /> -->
+       <!-- <property name="passwordEncoder" ref="passwordEncoder" /> -->
+       <!-- </bean> -->
+
        <!-- USER DETAILS -->
        <bean id="securityDao" class="org.argeo.security.ldap.ArgeoSecurityDaoLdap">
                <constructor-arg ref="contextSource" />
index a0e4dfc82332faf44b9dfbc04e909e44b02fae4b..41b27b5ddda0df9ffed0c2f2e404c781d95aaf2b 100644 (file)
@@ -53,7 +53,7 @@ public class ArgeoUserEditor extends FormEditor {
        protected void addPages() {
                try {
                        addPage(new DefaultUserMainPage(this,
-                                       userHome.getNode(ArgeoNames.ARGEO_USER_PROFILE)));
+                                       userHome.getNode(ArgeoNames.ARGEO_PROFILE)));
                        addPage(new UserRolesPage(this, userDetails, userAdminService));
                } catch (Exception e) {
                        throw new ArgeoException("Cannot add pages", e);
index af3a886efb950c58f91b31958cc15da068e2e96b..8ddba7683ab8be9ebb869c5f200d14fe84f7f3c3 100644 (file)
@@ -106,7 +106,7 @@ public class UsersView extends ViewPart implements ArgeoNames, ArgeoTypes,
                                                .getWorkspace()
                                                .getQueryManager()
                                                .createQuery(
-                                                               "select [" + ARGEO_USER_PROFILE + "] from ["
+                                                               "select [" + ARGEO_PROFILE + "] from ["
                                                                                + ARGEO_USER_HOME + "]", Query.JCR_SQL2);
                                NodeIterator nit = query.execute().getNodes();
                                List<Node> userProfiles = new ArrayList<Node>();
@@ -142,13 +142,13 @@ public class UsersView extends ViewPart implements ArgeoNames, ArgeoTypes,
                                        else
                                                return userName;
                                case 1:
-                                       return userHome.getNode(ARGEO_USER_PROFILE)
+                                       return userHome.getNode(ARGEO_PROFILE)
                                                        .getProperty(ARGEO_FIRST_NAME).getString();
                                case 2:
-                                       return userHome.getNode(ARGEO_USER_PROFILE)
+                                       return userHome.getNode(ARGEO_PROFILE)
                                                        .getProperty(ARGEO_LAST_NAME).getString();
                                case 3:
-                                       return userHome.getNode(ARGEO_USER_PROFILE)
+                                       return userHome.getNode(ARGEO_PROFILE)
                                                        .getProperty(ARGEO_PRIMARY_EMAIL).getString();
                                default:
                                        throw new ArgeoException("Unmanaged column " + columnIndex);
index bfbed855860f4f37f57d1444600a6f7c2a3559fa..6b166d5c5613dfd58483ccc2382758d40e2e5c1a 100644 (file)
@@ -17,7 +17,6 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.argeo.ArgeoException;
 import org.argeo.jcr.ArgeoNames;
-import org.argeo.jcr.ArgeoTypes;
 import org.argeo.jcr.JcrUtils;
 import org.argeo.security.jcr.JcrUserDetails;
 import org.springframework.ldap.core.DirContextAdapter;
@@ -103,13 +102,14 @@ public class JcrUserDetailsContextMapper implements UserDetailsContextMapper,
                        // session = nodeRepo.login();
                        Node userHome = JcrUtils.getUserHome(session, username);
                        if (userHome == null)
-                               userHome = createUserHome(session, username);
+                               userHome = JcrUtils.createUserHome(session, homeBasePath,
+                                               username);
                        String userHomePath = userHome.getPath();
-                       Node userProfile;
-                       if (userHome.hasNode(ARGEO_USER_PROFILE)) {
-                               userProfile = userHome.getNode(ARGEO_USER_PROFILE);
+                       Node userProfile = userHome.getNode(ARGEO_PROFILE);
+                       if (userHome.hasNode(ARGEO_PROFILE)) {
+                               userProfile = userHome.getNode(ARGEO_PROFILE);
                        } else {
-                               userProfile = userHome.addNode(ARGEO_USER_PROFILE);
+                               userProfile = userHome.addNode(ARGEO_PROFILE);
                                userProfile.addMixin(NodeType.MIX_TITLE);
                                userProfile.addMixin(NodeType.MIX_CREATED);
                                userProfile.addMixin(NodeType.MIX_LAST_MODIFIED);
@@ -128,24 +128,6 @@ public class JcrUserDetailsContextMapper implements UserDetailsContextMapper,
                }
        }
 
-       protected Node createUserHome(Session session, String username) {
-               try {
-                       Node userHome = JcrUtils.mkdirs(session,
-                                       usernameToHomePath(username));
-                       userHome.addMixin(ArgeoTypes.ARGEO_USER_HOME);
-                       userHome.setProperty(ARGEO_USER_ID, username);
-                       return userHome;
-               } catch (RepositoryException e) {
-                       throw new ArgeoException("Cannot create home node for user "
-                                       + username, e);
-               }
-       }
-
-       protected String usernameToHomePath(String username) {
-               return homeBasePath + '/' + JcrUtils.firstCharsToPath(username, 2)
-                               + '/' + username;
-       }
-
        public void mapUserToContext(UserDetails user, final DirContextAdapter ctx) {
                if (!(user instanceof JcrUserDetails))
                        throw new ArgeoException("Unsupported user details: "
@@ -165,7 +147,7 @@ public class JcrUserDetailsContextMapper implements UserDetailsContextMapper,
                        // repositoryFactory, ArgeoJcrConstants.ALIAS_NODE);
                        // session = nodeRepo.login();
                        Node userProfile = session.getNode(jcrUserDetails.getHomePath()
-                                       + '/' + ARGEO_USER_PROFILE);
+                                       + '/' + ARGEO_PROFILE);
                        for (String jcrProperty : propertyToAttributes.keySet())
                                jcrToLdap(userProfile, jcrProperty, ctx);
                        if (log.isDebugEnabled())
index 4026e87ecbcd4aef414434a951d502334fbeb48c..65f9e8d06dc942361f98afba756df5bdbd9b2329 100644 (file)
@@ -6,9 +6,9 @@ public interface ArgeoNames {
 
        public final static String ARGEO_URI = "argeo:uri";
        public final static String ARGEO_USER_ID = "argeo:userID";
-       
+
        // user profile
-       public final static String ARGEO_USER_PROFILE = "argeo:userProfile";
+       public final static String ARGEO_PROFILE = "argeo:profile";
        public final static String ARGEO_FIRST_NAME = "argeo:firstName";
        public final static String ARGEO_LAST_NAME = "argeo:lastName";
        public final static String ARGEO_PRIMARY_EMAIL = "argeo:primaryEmail";
index dec1a2875f60292b842712e43e115c387b68a596..6410b79ade5488665e7db626b3b39872d439d6cd 100644 (file)
@@ -4,4 +4,5 @@ package org.argeo.jcr;
 public interface ArgeoTypes {
        public final static String ARGEO_LINK = "argeo:link";
        public final static String ARGEO_USER_HOME = "argeo:userHome";
+       public final static String ARGEO_USER_PROFILE = "argeo:userProfile";
 }
index 72b94fbcd0590baef6c4b30049282dd61cdc0ae0..77309feea0ad8e88c507b81f279184ac3b750373 100644 (file)
@@ -650,6 +650,12 @@ public class JcrUtils implements ArgeoJcrConstants {
                return getUserHome(session, userID);
        }
 
+       /** Get the profile of the user attached to this session. */
+       public static Node getUserProfile(Session session) {
+               String userID = session.getUserID();
+               return getUserProfile(session, userID);
+       }
+
        /**
         * Returns the home node of the session user or null if none was found.
         * 
@@ -681,4 +687,58 @@ public class JcrUtils implements ArgeoJcrConstants {
                        throw new ArgeoException("Cannot find home for user " + userID, e);
                }
        }
+
+       public static Node getUserProfile(Session session, String userID) {
+               try {
+                       QueryObjectModelFactory qomf = session.getWorkspace()
+                                       .getQueryManager().getQOMFactory();
+                       Selector sel = qomf.selector(ArgeoTypes.ARGEO_USER_PROFILE,
+                                       "userProfile");
+                       DynamicOperand userIdDop = qomf.propertyValue("userProfile",
+                                       ArgeoNames.ARGEO_USER_ID);
+                       StaticOperand userIdSop = qomf.literal(session.getValueFactory()
+                                       .createValue(userID));
+                       Constraint constraint = qomf.comparison(userIdDop,
+                                       QueryObjectModelFactory.JCR_OPERATOR_EQUAL_TO, userIdSop);
+                       Query query = qomf.createQuery(sel, constraint, null, null);
+                       Node userHome = JcrUtils.querySingleNode(query);
+                       return userHome;
+               } catch (RepositoryException e) {
+                       throw new ArgeoException("Cannot find profile for user " + userID,
+                                       e);
+               }
+       }
+
+       public static Node createUserHome(Session session, String homeBasePath,
+                       String username) {
+               try {
+                       if (session.hasPendingChanges())
+                               throw new ArgeoException(
+                                               "Session has pending changes, save them first");
+                       String homePath = homeBasePath + '/'
+                                       + firstCharsToPath(username, 2) + '/' + username;
+                       Node userHome = JcrUtils.mkdirs(session, homePath);
+
+                       Node userProfile = userHome.addNode(ArgeoNames.ARGEO_PROFILE);
+                       userProfile.addMixin(ArgeoTypes.ARGEO_USER_PROFILE);
+                       userProfile.setProperty(ArgeoNames.ARGEO_USER_ID, username);
+                       session.save();
+                       // we need to save the profile before adding the user home type
+                       PropertyIterator pit = userHome.getProperties();
+                       while (pit.hasNext()) {
+                               Property p = pit.nextProperty();
+                               log.debug(p.getName() + "=" + p.getValue().getString());
+                       }
+                       userHome.addMixin(ArgeoTypes.ARGEO_USER_HOME);
+                       // see
+                       // http://jackrabbit.510166.n4.nabble.com/Jackrabbit-2-0-beta-6-Problem-adding-a-Mixin-type-with-mandatory-properties-after-setting-propertiesn-td1290332.html
+                       userHome.setProperty(ArgeoNames.ARGEO_USER_ID, username);
+                       session.save();
+                       return userHome;
+               } catch (RepositoryException e) {
+                       discardQuietly(session);
+                       throw new ArgeoException("Cannot create home node for user "
+                                       + username, e);
+               }
+       }
 }
index 979e102713bb73856a4c079b72340738024cb992..a2d790a949bd26640325e54264373836e7b0330c 100644 (file)
@@ -6,11 +6,13 @@ mixin
 // URI(s)
 - argeo:uri (STRING) m
 
-// HOME DIRECTORIES
-[argeo:home] > nt:unstructured, mix:created, mix:lastModified
-orderable
-+ * (argeo:userHome) *
-
+// USER NODES
+// user should be lower case, between 3 and 15 characters long
 [argeo:userHome] > mix:created, mix:lastModified
 mixin
-- argeo:userID (STRING) m
+- argeo:userID (STRING) m < '^[a-z0-9_]{3,15}$'
++ argeo:profile (argeo:userProfile)
+
+[argeo:userProfile] > mix:created, mix:lastModified, mix:title, mix:versionable
+mixin
+- argeo:userID (STRING) m < '^[a-z0-9_]{3,15}$'