From 7f23c34bcf51716cfb8f3853d47680035747052f Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Wed, 23 Mar 2011 10:45:09 +0000 Subject: [PATCH] Use bind authentication in LDAP Deifnitive node definitions for user home and profiles git-svn-id: https://svn.argeo.org/commons/trunk@4341 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- .../META-INF/spring/ldap.xml | 22 +++++-- .../ui/admin/editors/ArgeoUserEditor.java | 2 +- .../security/ui/admin/views/UsersView.java | 8 +-- .../ldap/jcr/JcrUserDetailsContextMapper.java | 32 +++------- .../main/java/org/argeo/jcr/ArgeoNames.java | 4 +- .../main/java/org/argeo/jcr/ArgeoTypes.java | 1 + .../src/main/java/org/argeo/jcr/JcrUtils.java | 60 +++++++++++++++++++ .../main/resources/org/argeo/jcr/argeo.cnd | 14 +++-- 8 files changed, 100 insertions(+), 43 deletions(-) diff --git a/security/modules/org.argeo.security.dao.ldap/META-INF/spring/ldap.xml b/security/modules/org.argeo.security.dao.ldap/META-INF/spring/ldap.xml index 77a6ac7d5..e990cad8b 100644 --- a/security/modules/org.argeo.security.dao.ldap/META-INF/spring/ldap.xml +++ b/security/modules/org.argeo.security.dao.ldap/META-INF/spring/ldap.xml @@ -27,23 +27,35 @@ - + - + - - + + + + + + + + + + + + + diff --git a/security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/editors/ArgeoUserEditor.java b/security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/editors/ArgeoUserEditor.java index a0e4dfc82..41b27b5dd 100644 --- a/security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/editors/ArgeoUserEditor.java +++ b/security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/editors/ArgeoUserEditor.java @@ -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); diff --git a/security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/views/UsersView.java b/security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/views/UsersView.java index af3a886ef..8ddba7683 100644 --- a/security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/views/UsersView.java +++ b/security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/views/UsersView.java @@ -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 userProfiles = new ArrayList(); @@ -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); 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 bfbed8558..6b166d5c5 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 @@ -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()) diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/ArgeoNames.java b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/ArgeoNames.java index 4026e87ec..65f9e8d06 100644 --- a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/ArgeoNames.java +++ b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/ArgeoNames.java @@ -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"; diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/ArgeoTypes.java b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/ArgeoTypes.java index dec1a2875..6410b79ad 100644 --- a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/ArgeoTypes.java +++ b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/ArgeoTypes.java @@ -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"; } diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java index 72b94fbcd..77309feea 100644 --- a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java +++ b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java @@ -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); + } + } } diff --git a/server/runtime/org.argeo.server.jcr/src/main/resources/org/argeo/jcr/argeo.cnd b/server/runtime/org.argeo.server.jcr/src/main/resources/org/argeo/jcr/argeo.cnd index 979e10271..a2d790a94 100644 --- a/server/runtime/org.argeo.server.jcr/src/main/resources/org/argeo/jcr/argeo.cnd +++ b/server/runtime/org.argeo.server.jcr/src/main/resources/org/argeo/jcr/argeo.cnd @@ -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}$' -- 2.30.2