Clean up LDAP dao
authorMathieu Baudier <mbaudier@argeo.org>
Fri, 18 Mar 2011 15:42:23 +0000 (15:42 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Fri, 18 Mar 2011 15:42:23 +0000 (15:42 +0000)
git-svn-id: https://svn.argeo.org/commons/trunk@4321 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

security/modules/org.argeo.security.dao.ldap/META-INF/spring/ldap-osgi.xml
security/modules/org.argeo.security.dao.ldap/META-INF/spring/ldap.xml
security/modules/org.argeo.security.dao.ldap/ldap.properties
security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/AbstractUserNature.java
security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/ArgeoUser.java
security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/CurrentUserService.java
security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/SimpleArgeoUser.java
security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/UserNature.java
security/runtime/org.argeo.security.ldap/src/main/java/org/argeo/security/ldap/ArgeoSecurityDaoLdap.java

index fcfa5fed17b8b2d0946c86145b092efe99495173..b09aabfe47624cdf952caf48cbf6d3923e7e6eee 100644 (file)
@@ -24,7 +24,7 @@
                context-class-loader="service-provider" />\r
        <service ref="securityDao" interface="org.argeo.security.UserAdminDao"\r
                context-class-loader="service-provider" />\r
-       <service ref="userDetailsService"\r
+       <service ref="userDetailsManager"\r
                interface="org.springframework.security.userdetails.UserDetailsService"\r
                context-class-loader="service-provider" />\r
 </beans:beans>
\ No newline at end of file
index 02ee71b1d44dfc562759038e39a385b65be16220..7a2ae9d7f4d7908515bcd37f121c12786b3761f4 100644 (file)
@@ -4,7 +4,7 @@
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
               http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.4.xsd">
 
-
+       <!-- COMMON -->
        <bean
                class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
                <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
                <property name="password" value="${argeo.ldap.manager.password}" />
        </bean>
 
+       <!-- AUTHENTICATION -->
        <bean id="authenticationProvider"
                class="org.springframework.security.providers.ldap.LdapAuthenticationProvider">
-               <constructor-arg ref="ldapAuthenticator" />
-               <constructor-arg>
-                       <bean factory-bean="securityDao" factory-method="getAuthoritiesPopulator" />
-               </constructor-arg>
+               <constructor-arg ref="passwordComparisonAuthenticator" />
+               <constructor-arg ref="authoritiesPopulator" />
                <property name="userDetailsContextMapper" ref="jcrUserDetailsContextMapper" />
        </bean>
 
-       <bean id="securityDao" class="org.argeo.security.ldap.ArgeoSecurityDaoLdap">
+       <bean id="passwordComparisonAuthenticator"
+               class="org.springframework.security.providers.ldap.authenticator.PasswordComparisonAuthenticator">
                <constructor-arg ref="contextSource" />
-               <property name="userNatureMappers" ref="userNatureMappers" />
+               <property name="userDnPatterns">
+                       <list>
+                               <value><![CDATA[${argeo.ldap.usernameAttribute}={0},${argeo.ldap.userBase}]]></value>
+                       </list>
+               </property>
                <property name="passwordEncoder" ref="passwordEncoder" />
        </bean>
 
-       <bean id="userDetailsService" factory-bean="securityDao"
-               factory-method="getUserDetailsService">
-       </bean>
-
-       <bean id="ldapAuthenticator"
-               class="org.springframework.security.providers.ldap.authenticator.PasswordComparisonAuthenticator">
+       <!-- USER DETAILS -->
+       <bean id="securityDao" class="org.argeo.security.ldap.ArgeoSecurityDaoLdap">
                <constructor-arg ref="contextSource" />
-               <property name="userDnPatterns">
+
+               <property name="userBase" value="${argeo.ldap.userBase}" />
+               <property name="usernameAttribute" value="${argeo.ldap.usernameAttribute}" />
+               <property name="groupClasses">
                        <list>
-                               <value>uid={0},ou=People</value>
+                               <value>top</value>
+                               <value>${argeo.ldap.groupClass}</value>
                        </list>
                </property>
+               <property name="groupBase" value="${argeo.ldap.groupBase}" />
+               <property name="groupRoleAttribute" value="${argeo.ldap.groupRoleAttribute}" />
+               <property name="groupMemberAttribute" value="${argeo.ldap.groupMemberAttribute}" />
+               <property name="defaultRole" value="${argeo.security.defaultRole}" />
+               <property name="rolePrefix" value="${argeo.security.rolePrefix}" />
+
                <property name="passwordEncoder" ref="passwordEncoder" />
+               <property name="usernameMapper" ref="usernameMapper" />
+               <property name="userDetailsManager" ref="userDetailsManager" />
+       </bean>
+
+       <bean id="usernameMapper"
+               class="org.springframework.security.ldap.DefaultLdapUsernameToDnMapper">
+               <constructor-arg value="${argeo.ldap.userBase}" />
+               <constructor-arg value="${argeo.ldap.usernameAttribute}" />
        </bean>
+
+       <bean id="authoritiesPopulator"
+               class="org.springframework.security.ldap.populator.DefaultLdapAuthoritiesPopulator">
+               <constructor-arg ref="contextSource" />
+               <constructor-arg value="${argeo.ldap.groupBase}" />
+               <property name="groupSearchFilter" value="${argeo.ldap.groupMemberAttribute}={0}" />
+               <property name="defaultRole" value="${argeo.security.defaultRole}" />
+               <property name="rolePrefix" value="${argeo.security.rolePrefix}" />
+       </bean>
+
+       <bean id="userDetailsManager"
+               class="org.springframework.security.userdetails.ldap.LdapUserDetailsManager">
+               <constructor-arg ref="contextSource" />
+               <property name="groupSearchBase" value="${argeo.ldap.groupBase}" />
+               <property name="groupMemberAttributeName" value="${argeo.ldap.groupMemberAttribute}" />
+               <property name="usernameMapper" ref="usernameMapper" />
+               <property name="userDetailsMapper" ref="jcrUserDetailsContextMapper" />
+       </bean>
+
+       <!-- <bean id="userDetailsService" -->
+       <!-- class="org.springframework.security.userdetails.ldap.LdapUserDetailsManager"> -->
+       <!-- <constructor-arg> -->
+       <!-- <bean -->
+       <!-- class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch"> -->
+       <!-- <constructor-arg value="${argeo.ldap.userBase}" /> -->
+       <!-- <constructor-arg value="(${argeo.ldap.usernameAttribute}={0})" /> -->
+       <!-- <constructor-arg ref="contextSource" /> -->
+       <!-- </bean> -->
+       <!-- </constructor-arg> -->
+       <!-- <constructor-arg ref="authoritiesPopulator" /> -->
+       <!-- <property name="userDetailsMapper" ref="jcrUserDetailsContextMapper" 
+               /> -->
+       <!-- </bean> -->
 </beans>
index 1b24ee3d16d6551659255c792b9dbb6eff23b4a3..66eb37b43e8610a77a05bfd4acd7f0cfe22e5c3e 100644 (file)
@@ -1,6 +1,16 @@
+argeo.security.defaultRole=ROLE_USER
+argeo.security.rolePrefix=ROLE_
+
 argeo.ldap.rootdn=dc=demo,dc=argeo,dc=org
 argeo.ldap.protocol=ldap
 argeo.ldap.host=localhost
 argeo.ldap.port=10389
 argeo.ldap.manager.userdn=uid=admin,ou=system
 argeo.ldap.manager.password=secret
+
+argeo.ldap.userBase=ou=People
+argeo.ldap.usernameAttribute=uid
+argeo.ldap.groupClass=groupOfNames
+argeo.ldap.groupBase=ou=Roles
+argeo.ldap.groupRoleAttribute=cn
+argeo.ldap.groupMemberAttribute=member
index 2a3e2579d4255f3871357ade3fe01625866665ed..bbb5eb80411be3c1f044ffbf1f8b9e739049bac6 100644 (file)
@@ -18,6 +18,7 @@ package org.argeo.security;
 
 
 /** A set of specific data attached to a user. */
+@Deprecated
 public abstract class AbstractUserNature implements UserNature {
        private static final long serialVersionUID = 1169323440459736478L;
        
index 30f52ed3b3df2d198e98815bb4eebbd32c2a96b6..465c2fab9271aa0634d51f69664b338878fe4793 100644 (file)
@@ -23,6 +23,7 @@ import java.util.Map;
 public interface ArgeoUser {
        public String getUsername();
 
+       @Deprecated
        public Map<String, UserNature> getUserNatures();
 
        /** Implementation should refuse to add new user natures via this method. */
index 0cdae48fc61b6ef020552cb0e19d711c864e9710..a82bc9bac0a3e712713bd428f1709dee684708f2 100644 (file)
@@ -7,6 +7,7 @@ public interface CurrentUserService {
 
        public void updateCurrentUserPassword(String oldPassword, String newPassword);
 
+       @Deprecated
        public void updateCurrentUserNatures(Map<String, UserNature> userNatures);
 
 }
index c021f8e4453a8e1ae61975c7839c644c9f9d7288..94c7f9389f1d0dbdb81fa94c265ece4ae446310e 100644 (file)
@@ -53,10 +53,12 @@ public class SimpleArgeoUser implements ArgeoUser, Serializable,
                return userNatures;
        }
 
+       @Deprecated
        public void updateUserNatures(Map<String, UserNature> userNaturesData) {
                updateUserNaturesWithCheck(userNatures, userNaturesData);
        }
 
+       @Deprecated
        public static void updateUserNaturesWithCheck(
                        Map<String, UserNature> userNatures,
                        Map<String, UserNature> userNaturesData) {
@@ -109,6 +111,7 @@ public class SimpleArgeoUser implements ArgeoUser, Serializable,
                this.username = username;
        }
 
+       @Deprecated
        public void setUserNatures(Map<String, UserNature> userNatures) {
                this.userNatures = userNatures;
        }
index 8931be2b002e35ffc5cdefa11643dea315828cee..cf0fa48190a1b96cbee938d44fecb9ea2963440a 100644 (file)
@@ -22,6 +22,7 @@ import java.io.Serializable;
  * A set of specific data attached to a user. TODO: is this interface really
  * useful?
  */
+@Deprecated
 public interface UserNature extends Serializable {
        @Deprecated
        /** @deprecated will be removed soon*/
index 0a10cce3f7f441362d48befcdd48f2a6b5a59115..4c6e62b98bf8bec91d19d59607ad8dd393848991 100644 (file)
@@ -36,7 +36,6 @@ import org.argeo.security.CurrentUserDao;
 import org.argeo.security.SimpleArgeoUser;
 import org.argeo.security.UserAdminDao;
 import org.argeo.security.core.ArgeoUserDetails;
-import org.springframework.beans.factory.InitializingBean;
 import org.springframework.ldap.core.ContextExecutor;
 import org.springframework.ldap.core.ContextMapper;
 import org.springframework.ldap.core.DirContextAdapter;
@@ -44,95 +43,58 @@ import org.springframework.ldap.core.DistinguishedName;
 import org.springframework.ldap.core.LdapTemplate;
 import org.springframework.ldap.core.support.BaseLdapPathContextSource;
 import org.springframework.security.context.SecurityContextHolder;
-import org.springframework.security.ldap.DefaultLdapUsernameToDnMapper;
-import org.springframework.security.ldap.LdapAuthoritiesPopulator;
 import org.springframework.security.ldap.LdapUsernameToDnMapper;
 import org.springframework.security.ldap.LdapUtils;
-import org.springframework.security.ldap.populator.DefaultLdapAuthoritiesPopulator;
-import org.springframework.security.ldap.search.FilterBasedLdapUserSearch;
 import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
 import org.springframework.security.providers.encoding.PasswordEncoder;
 import org.springframework.security.userdetails.UserDetails;
 import org.springframework.security.userdetails.UserDetailsManager;
-import org.springframework.security.userdetails.UserDetailsService;
-import org.springframework.security.userdetails.ldap.LdapUserDetailsManager;
-import org.springframework.security.userdetails.ldap.LdapUserDetailsService;
-import org.springframework.security.userdetails.ldap.UserDetailsContextMapper;
 
-public class ArgeoSecurityDaoLdap implements CurrentUserDao, UserAdminDao,
-               InitializingBean {
-       // private final static Log log = LogFactory.getLog(UserDaoLdap.class);
+/**
+ * Wraps a Spring LDAP user details manager, providing additional methods to
+ * manage roles.
+ */
+public class ArgeoSecurityDaoLdap implements CurrentUserDao, UserAdminDao {
+       private String userBase;
+       private String usernameAttribute;
+       private String groupBase;
+       private String[] groupClasses;
 
-       private UserDetailsManager userDetailsManager;
-       private LdapAuthoritiesPopulator authoritiesPopulator;
-       private String userBase = "ou=People";
-       private String usernameAttributeName = "uid";
-       private String groupBase = "ou=Roles";
-       private String[] groupClasses = { "top", "groupOfNames" };
-       private String groupRoleAttributeName = "cn";
-       private String groupMemberAttributeName = "member";
-       private String defaultRole = "ROLE_USER";
-       private String rolePrefix = "ROLE_";
-
-       private final BaseLdapPathContextSource contextSource;
-       private final LdapTemplate ldapTemplate;
+       private String groupRoleAttribute;
+       private String groupMemberAttribute;
+       private String defaultRole;
+       private String rolePrefix;
 
-       private LdapUsernameToDnMapper usernameMapper = null;
+       private final LdapTemplate ldapTemplate;
+       private final Random random;
 
-       private UserDetailsContextMapper userDetailsMapper;
-       private LdapUserDetailsService ldapUserDetailsService;
-       private List<UserNatureMapper> userNatureMappers;
+       private LdapUsernameToDnMapper usernameMapper;
+       private UserDetailsManager userDetailsManager;
 
        private PasswordEncoder passwordEncoder;
-       private Random random;
 
+       /**
+        * Standard constructor, using the LDAP context source shared with Spring
+        * Security components.
+        */
        public ArgeoSecurityDaoLdap(BaseLdapPathContextSource contextSource) {
-               this.contextSource = contextSource;
-               ldapTemplate = new LdapTemplate(this.contextSource);
-
-               try {
-                       random = SecureRandom.getInstance("SHA1PRNG");
-               } catch (NoSuchAlgorithmException e) {
-                       random = new Random(System.currentTimeMillis());
-               }
+               this(new LdapTemplate(contextSource), createRandom());
        }
 
-       public void afterPropertiesSet() throws Exception {
-               if (usernameMapper == null)
-                       usernameMapper = new DefaultLdapUsernameToDnMapper(userBase,
-                                       usernameAttributeName);
-
-               if (authoritiesPopulator == null) {
-                       DefaultLdapAuthoritiesPopulator ap = new DefaultLdapAuthoritiesPopulator(
-                                       ldapTemplate.getContextSource(), groupBase);
-                       ap.setDefaultRole(defaultRole);
-                       ap.setGroupSearchFilter(groupMemberAttributeName + "={0}");
-                       authoritiesPopulator = ap;
-               }
-
-               if (userDetailsMapper == null) {
-                       ArgeoUserDetailsContextMapper audm = new ArgeoUserDetailsContextMapper();
-                       audm.setUserNatureMappers(userNatureMappers);
-                       userDetailsMapper = audm;
-               }
-
-               if (userDetailsManager == null) {
-                       LdapUserDetailsManager ludm = new LdapUserDetailsManager(
-                                       ldapTemplate.getContextSource());
-                       ludm.setGroupSearchBase(groupBase);
-                       ludm.setUserDetailsMapper(userDetailsMapper);
-                       ludm.setUsernameMapper(usernameMapper);
-                       ludm.setGroupMemberAttributeName(groupMemberAttributeName);
-                       userDetailsManager = ludm;
-               }
+       /**
+        * Advanced constructor allowing to reuse an LDAP template and to explicitly
+        * set the random used as seed for SSHA password generation.
+        */
+       public ArgeoSecurityDaoLdap(LdapTemplate ldapTemplate, Random random) {
+               this.ldapTemplate = ldapTemplate;
+               this.random = random;
+       }
 
-               if (ldapUserDetailsService == null) {
-                       FilterBasedLdapUserSearch ldapUserSearch = new FilterBasedLdapUserSearch(
-                                       userBase, "(" + usernameAttributeName + "={0})",
-                                       contextSource);
-                       ldapUserDetailsService = new LdapUserDetailsService(ldapUserSearch,
-                                       authoritiesPopulator);
-                       ldapUserDetailsService.setUserDetailsMapper(userDetailsMapper);
+       private static Random createRandom() {
+               try {
+                       return SecureRandom.getInstance("SHA1PRNG");
+               } catch (NoSuchAlgorithmException e) {
+                       return new Random(System.currentTimeMillis());
                }
        }
 
@@ -159,22 +121,13 @@ public class ArgeoSecurityDaoLdap implements CurrentUserDao, UserAdminDao,
                return createSimpleArgeoUser(getDetails(uname));
        }
 
-       // public ArgeoUser getCurrentUser() {
-       // ArgeoUser argeoUser = ArgeoUserDetails.securityContextUser();
-       // if (argeoUser == null)
-       // return null;
-       // if (argeoUser.getRoles().contains(defaultRole))
-       // argeoUser.getRoles().remove(defaultRole);
-       // return argeoUser;
-       // }
-
        @SuppressWarnings("unchecked")
        public synchronized Set<ArgeoUser> listUsers() {
                List<String> usernames = (List<String>) ldapTemplate.listBindings(
                                new DistinguishedName(userBase), new ContextMapper() {
                                        public Object mapFromContext(Object ctxArg) {
                                                DirContextAdapter ctx = (DirContextAdapter) ctxArg;
-                                               return ctx.getStringAttribute(usernameAttributeName);
+                                               return ctx.getStringAttribute(usernameAttribute);
                                        }
                                });
 
@@ -191,7 +144,7 @@ public class ArgeoSecurityDaoLdap implements CurrentUserDao, UserAdminDao,
                                ldapTemplate.listBindings(groupBase, new ContextMapper() {
                                        public Object mapFromContext(Object ctxArg) {
                                                String groupName = ((DirContextAdapter) ctxArg)
-                                                               .getStringAttribute(groupRoleAttributeName);
+                                                               .getStringAttribute(groupRoleAttribute);
                                                String roleName = convertGroupToRole(groupName);
                                                return roleName;
                                        }
@@ -205,12 +158,11 @@ public class ArgeoSecurityDaoLdap implements CurrentUserDao, UserAdminDao,
                                        public Object mapFromContext(Object ctxArg) {
                                                DirContextAdapter ctx = (DirContextAdapter) ctxArg;
                                                String[] userDns = ctx
-                                                               .getStringAttributes(groupMemberAttributeName);
+                                                               .getStringAttributes(groupMemberAttribute);
                                                TreeSet<ArgeoUser> set = new TreeSet<ArgeoUser>();
                                                for (String userDn : userDns) {
                                                        DistinguishedName dn = new DistinguishedName(userDn);
-                                                       String username = dn
-                                                                       .getValue(usernameAttributeName);
+                                                       String username = dn.getValue(usernameAttribute);
                                                        set.add(createSimpleArgeoUser(getDetails(username)));
                                                }
                                                return Collections.unmodifiableSortedSet(set);
@@ -284,11 +236,8 @@ public class ArgeoSecurityDaoLdap implements CurrentUserDao, UserAdminDao,
                DirContextAdapter context = new DirContextAdapter();
                context.setAttributeValues("objectClass", groupClasses);
                context.setAttributeValue("cn", group);
-
                // Add superuser because cannot create empty group
-               context.setAttributeValue(groupMemberAttributeName,
-                               superuserDn.toString());
-
+               context.setAttributeValue(groupMemberAttribute, superuserDn.toString());
                ldapTemplate.bind(groupDn, context, null);
        }
 
@@ -298,6 +247,7 @@ public class ArgeoSecurityDaoLdap implements CurrentUserDao, UserAdminDao,
                ldapTemplate.unbind(dn);
        }
 
+       /** Maps a role (ROLE_XXX) to the related LDAP group (xxx) */
        protected String convertRoleToGroup(String role) {
                String group = role;
                if (group.startsWith(rolePrefix)) {
@@ -307,14 +257,15 @@ public class ArgeoSecurityDaoLdap implements CurrentUserDao, UserAdminDao,
                return group;
        }
 
-       public String convertGroupToRole(String groupName) {
+       /** Maps anLDAP group (xxx) to the related role (ROLE_XXX) */
+       protected String convertGroupToRole(String groupName) {
                groupName = groupName.toUpperCase();
 
                return rolePrefix + groupName;
        }
 
        protected Name buildGroupDn(String name) {
-               return new DistinguishedName(groupRoleAttributeName + "=" + name + ","
+               return new DistinguishedName(groupRoleAttribute + "=" + name + ","
                                + groupBase);
        }
 
@@ -326,13 +277,8 @@ public class ArgeoSecurityDaoLdap implements CurrentUserDao, UserAdminDao,
                this.userBase = userBase;
        }
 
-       public void setUsernameAttributeName(String usernameAttribute) {
-               this.usernameAttributeName = usernameAttribute;
-       }
-
-       public void setAuthoritiesPopulator(
-                       LdapAuthoritiesPopulator authoritiesPopulator) {
-               this.authoritiesPopulator = authoritiesPopulator;
+       public void setUsernameAttribute(String usernameAttribute) {
+               this.usernameAttribute = usernameAttribute;
        }
 
        protected UserDetails getDetails(String username) {
@@ -343,12 +289,12 @@ public class ArgeoSecurityDaoLdap implements CurrentUserDao, UserAdminDao,
                this.groupBase = groupBase;
        }
 
-       public void setGroupRoleAttributeName(String groupRoleAttributeName) {
-               this.groupRoleAttributeName = groupRoleAttributeName;
+       public void setGroupRoleAttribute(String groupRoleAttributeName) {
+               this.groupRoleAttribute = groupRoleAttributeName;
        }
 
-       public void setGroupMemberAttributeName(String groupMemberAttributeName) {
-               this.groupMemberAttributeName = groupMemberAttributeName;
+       public void setGroupMemberAttribute(String groupMemberAttributeName) {
+               this.groupMemberAttribute = groupMemberAttributeName;
        }
 
        public void setDefaultRole(String defaultRole) {
@@ -363,22 +309,6 @@ public class ArgeoSecurityDaoLdap implements CurrentUserDao, UserAdminDao,
                this.usernameMapper = usernameMapper;
        }
 
-       public void setUserDetailsMapper(UserDetailsContextMapper userDetailsMapper) {
-               this.userDetailsMapper = userDetailsMapper;
-       }
-
-       public LdapAuthoritiesPopulator getAuthoritiesPopulator() {
-               return authoritiesPopulator;
-       }
-
-       public UserDetailsContextMapper getUserDetailsMapper() {
-               return userDetailsMapper;
-       }
-
-       public void setUserNatureMappers(List<UserNatureMapper> userNatureMappers) {
-               this.userNatureMappers = userNatureMappers;
-       }
-
        public String getDefaultRole() {
                return defaultRole;
        }
@@ -387,10 +317,6 @@ public class ArgeoSecurityDaoLdap implements CurrentUserDao, UserAdminDao,
                this.groupClasses = groupClasses;
        }
 
-       public UserDetailsService getUserDetailsService() {
-               return ldapUserDetailsService;
-       }
-
        public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
                this.passwordEncoder = passwordEncoder;
        }