package org.argeo.security.ldap; import static org.argeo.security.core.ArgeoUserDetails.createBasicArgeoUser; import java.util.ArrayList; import java.util.List; import javax.naming.Name; import javax.naming.NamingException; import javax.naming.directory.DirContext; import org.argeo.security.ArgeoSecurityDao; import org.argeo.security.ArgeoUser; 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.ContextSource; import org.springframework.ldap.core.DirContextAdapter; import org.springframework.ldap.core.DistinguishedName; import org.springframework.ldap.core.LdapTemplate; import org.springframework.security.ldap.DefaultLdapUsernameToDnMapper; import org.springframework.security.ldap.LdapUsernameToDnMapper; import org.springframework.security.ldap.LdapUtils; import org.springframework.security.userdetails.UserDetails; import org.springframework.security.userdetails.UserDetailsManager; public class ArgeoSecurityDaoLdap implements ArgeoSecurityDao, InitializingBean { // private final static Log log = LogFactory.getLog(UserDaoLdap.class); private UserDetailsManager userDetailsManager; private ArgeoLdapAuthoritiesPopulator authoritiesPopulator; private String userBase = "ou=users"; private String usernameAttribute = "uid"; private final LdapTemplate ldapTemplate; /* TODO: factorize with user details manager */ private LdapUsernameToDnMapper usernameMapper = null; public void afterPropertiesSet() throws Exception { if (usernameMapper == null) usernameMapper = new DefaultLdapUsernameToDnMapper(userBase, usernameAttribute); } public ArgeoSecurityDaoLdap(ContextSource contextSource) { ldapTemplate = new LdapTemplate(contextSource); } public void create(ArgeoUser user) { userDetailsManager.createUser(new ArgeoUserDetails(user)); } public ArgeoUser getUser(String uname) { return createBasicArgeoUser(getDetails(uname)); } @SuppressWarnings("unchecked") public List listUsers() { List usernames = (List) ldapTemplate.listBindings( new DistinguishedName(userBase), new ContextMapper() { public Object mapFromContext(Object ctxArg) { DirContextAdapter ctx = (DirContextAdapter) ctxArg; return ctx.getStringAttribute(usernameAttribute); } }); List lst = new ArrayList(); for (String username : usernames) { lst.add(createBasicArgeoUser(getDetails(username))); } return lst; } @SuppressWarnings("unchecked") public List listEditableRoles() { return (List) ldapTemplate.listBindings(authoritiesPopulator .getGroupSearchBase(), new ContextMapper() { public Object mapFromContext(Object ctxArg) { String groupName = ((DirContextAdapter) ctxArg) .getStringAttribute(authoritiesPopulator .getGroupRoleAttribute()); String roleName = authoritiesPopulator .convertGroupToRole(groupName); return roleName; } }); } public void update(ArgeoUser user) { userDetailsManager.updateUser(new ArgeoUserDetails(user)); } public void delete(String username) { userDetailsManager.deleteUser(username); } public void updatePassword(String oldPassword, String newPassword) { userDetailsManager.changePassword(oldPassword, newPassword); } public Boolean userExists(String username) { return userDetailsManager.userExists(username); } public void createRole(String role, final String superuserName) { String group = convertRoleToGroup(role); DistinguishedName superuserDn = (DistinguishedName) ldapTemplate .executeReadWrite(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws NamingException { return LdapUtils.getFullDn(usernameMapper .buildDn(superuserName), ctx); } }); Name groupDn = buildGroupDn(group); DirContextAdapter context = new DirContextAdapter(); context.setAttributeValues("objectClass", new String[] { "top", "groupOfUniqueNames" }); context.setAttributeValue("cn", group); // Add superuser because cannot create empty group context.setAttributeValue("uniqueMember", superuserDn.toString()); ldapTemplate.bind(groupDn, context, null); } public void deleteRole(String role) { String group = convertRoleToGroup(role); Name dn = buildGroupDn(group); ldapTemplate.unbind(dn); } protected String convertRoleToGroup(String role) { // FIXME: factorize with spring security String group = role; if (group.startsWith("ROLE_")) { group = group.substring("ROLE_".length()); group = group.toLowerCase(); } return group; } protected Name buildGroupDn(String name) { return new DistinguishedName("cn=" + name + "," + authoritiesPopulator.getGroupSearchBase()); } public void setUserDetailsManager(UserDetailsManager userDetailsManager) { this.userDetailsManager = userDetailsManager; } public void setUserBase(String userBase) { this.userBase = userBase; } public void setUsernameAttribute(String usernameAttribute) { this.usernameAttribute = usernameAttribute; } public void setAuthoritiesPopulator( ArgeoLdapAuthoritiesPopulator authoritiesPopulator) { this.authoritiesPopulator = authoritiesPopulator; } protected UserDetails getDetails(String username) { return userDetailsManager.loadUserByUsername(username); } }