From ec59a58bc368dc922a454d52eb70bb91dfd68793 Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Sat, 19 Sep 2009 10:10:54 +0000 Subject: [PATCH] API completely implemented git-svn-id: https://svn.argeo.org/commons/trunk@2976 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- security/demo/init.ldif | 14 ++++ security/doc/services-api.txt | 28 ++++--- .../META-INF/spring/dao.xml | 2 +- .../org/argeo/security/ArgeoSecurityDao.java | 2 + .../argeo/security/ArgeoSecurityService.java | 5 +- .../org/argeo/security/BasicArgeoUser.java | 1 + .../argeo/security/core/ArgeoUserDetails.java | 18 +++-- .../security/core/DefaultSecurityService.java | 11 ++- .../ldap/ArgeoLdapUserDetailsManager.java | 19 +++++ ...DaoLdap.java => ArgeoSecurityDaoLdap.java} | 78 +++++++++++++++---- .../security/mvc/UsersRolesController.java | 20 ++++- 11 files changed, 158 insertions(+), 40 deletions(-) create mode 100644 security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/ldap/ArgeoLdapUserDetailsManager.java rename security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/ldap/{SecurityDaoLdap.java => ArgeoSecurityDaoLdap.java} (60%) diff --git a/security/demo/init.ldif b/security/demo/init.ldif index bc1512b34..9fb8d4b6f 100644 --- a/security/demo/init.ldif +++ b/security/demo/init.ldif @@ -27,6 +27,19 @@ sn: User uid: demo userpassword:: e1NIQX1pZVNWNTVRYytlUU9hWURSU2hhL0Fqek5USkU9 +dn: uid=root,ou=users,dc=demo,dc=argeo,dc=org +objectClass: person +objectClass: inetOrgPerson +objectClass: organizationalPerson +objectClass: top +cn: demo User +description: Superuser +givenname: Root +mail: root@localhost +sn: Root +uid: root +userpassword:: e1NIQX1pZVNWNTVRYytlUU9hWURSU2hhL0Fqek5USkU9 + dn: uid=frodo,ou=users,dc=demo,dc=argeo,dc=org objectClass: person objectClass: inetOrgPerson @@ -58,3 +71,4 @@ objectClass: groupOfUniqueNames objectClass: top cn: admin uniquemember: uid=gandalf,ou=users,dc=demo,dc=argeo,dc=org +uniquemember: uid=root,ou=users,dc=demo,dc=argeo,dc=org diff --git a/security/doc/services-api.txt b/security/doc/services-api.txt index 2991d13b9..6e0ce4219 100644 --- a/security/doc/services-api.txt +++ b/security/doc/services-api.txt @@ -3,6 +3,9 @@ Security RIA API ****************** USERS ****************** +getCredentials.security +> return : userDetails of the logged user + getUsersList.security > param : getNatures > return : users[] : containing username and roles, and depending on the value of getNatures, the natures. @@ -10,18 +13,21 @@ getUsersList.security userExists.security > param : userName -deleteUser.security +deleteUser.security (ADMIN only) > param : userName getUserDetails.security > param : userName > return : userDetails : full details (roles, natures, etc). -createUser.security +createUser.security (ADMIN only) > params : userName , password -updateUserPassword.security -> param : userName , password , [oldpassword ] (depends on the admin being logged in or not) +updateUserPassword.security (ADMIN only) +> param : userName , password + +updatePassword.security +> param : password , oldpassword ****************** @@ -31,17 +37,17 @@ getRolesList.security > param : aucun > return : roles[] -getUsersForRole.security +#getUsersForRole.security > param : roleName , getNatures > return : users[] (username and eventually natures) -createRole.security +createRole.security (ADMIN only) > param : roleName -deleteRole.security +deleteRole.security (ADMIN only) > param : roleName -updateUserRoleLink.security +#updateUserRoleLink.security > params : roleName, username, action="set|unset" @@ -49,11 +55,11 @@ updateUserRoleLink.security LINKS & NATURES ************************ -createUserNature.security +#createUserNature.security > params : natureObject , userName -deleteUserNature.security +#deleteUserNature.security > params : natureObject , userName -updateUserNature.security +#updateUserNature.security > params : natureObject , userName \ No newline at end of file diff --git a/security/modules/org.argeo.security.manager.ldap/META-INF/spring/dao.xml b/security/modules/org.argeo.security.manager.ldap/META-INF/spring/dao.xml index 1d540a398..dc1ad373b 100644 --- a/security/modules/org.argeo.security.manager.ldap/META-INF/spring/dao.xml +++ b/security/modules/org.argeo.security.manager.ldap/META-INF/spring/dao.xml @@ -5,7 +5,7 @@ http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.4.xsd"> - + diff --git a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/ArgeoSecurityDao.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/ArgeoSecurityDao.java index 039e549e3..c317e15c1 100644 --- a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/ArgeoSecurityDao.java +++ b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/ArgeoSecurityDao.java @@ -13,6 +13,8 @@ public interface ArgeoSecurityDao { public void delete(String username); + public void createRole(String role, String superuserName); + public void deleteRole(String role); public void updatePassword(String oldPassword, String newPassword); diff --git a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/ArgeoSecurityService.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/ArgeoSecurityService.java index 7eecfb56a..77b699d01 100644 --- a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/ArgeoSecurityService.java +++ b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/ArgeoSecurityService.java @@ -1,8 +1,11 @@ package org.argeo.security; - public interface ArgeoSecurityService { public void newUser(ArgeoUser argeoUser); + + public void updateUserPassword(String username, String password); + public void newRole(String role); + public ArgeoSecurityDao getSecurityDao(); } diff --git a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/BasicArgeoUser.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/BasicArgeoUser.java index c6b8ce1b8..e7d81d0ec 100644 --- a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/BasicArgeoUser.java +++ b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/BasicArgeoUser.java @@ -18,6 +18,7 @@ public class BasicArgeoUser implements ArgeoUser, Serializable { public BasicArgeoUser(ArgeoUser argeoUser) { username = argeoUser.getUsername(); + password = argeoUser.getPassword(); userNatures = new ArrayList(argeoUser.getUserNatures()); roles = new ArrayList(argeoUser.getRoles()); } diff --git a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/ArgeoUserDetails.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/ArgeoUserDetails.java index 0b8368c6f..a018826f8 100644 --- a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/ArgeoUserDetails.java +++ b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/ArgeoUserDetails.java @@ -31,8 +31,8 @@ public class ArgeoUserDetails extends User implements ArgeoUser { } public ArgeoUserDetails(ArgeoUser argeoUser) { - this(argeoUser.getUsername(), argeoUser.getUserNatures(), argeoUser.getPassword(), - rolesToAuthorities(argeoUser.getRoles())); + this(argeoUser.getUsername(), argeoUser.getUserNatures(), argeoUser + .getPassword(), rolesToAuthorities(argeoUser.getRoles())); } public List getUserNatures() { @@ -61,11 +61,15 @@ public class ArgeoUserDetails extends User implements ArgeoUser { } public static BasicArgeoUser createBasicArgeoUser(UserDetails userDetails) { - BasicArgeoUser argeoUser = new BasicArgeoUser(); - argeoUser.setUsername(userDetails.getUsername()); - addAuthoritiesToRoles(userDetails.getAuthorities(), argeoUser - .getRoles()); - return argeoUser; + if (userDetails instanceof ArgeoUser) { + return new BasicArgeoUser((ArgeoUser) userDetails); + } else { + BasicArgeoUser argeoUser = new BasicArgeoUser(); + argeoUser.setUsername(userDetails.getUsername()); + addAuthoritiesToRoles(userDetails.getAuthorities(), argeoUser + .getRoles()); + return argeoUser; + } } public static ArgeoUser asArgeoUser(Authentication authentication) { diff --git a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/DefaultSecurityService.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/DefaultSecurityService.java index 6be432547..b69e02a40 100644 --- a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/DefaultSecurityService.java +++ b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/DefaultSecurityService.java @@ -4,6 +4,7 @@ import org.argeo.security.ArgeoSecurity; import org.argeo.security.ArgeoSecurityDao; import org.argeo.security.ArgeoSecurityService; import org.argeo.security.ArgeoUser; +import org.argeo.security.BasicArgeoUser; public class DefaultSecurityService implements ArgeoSecurityService { private ArgeoSecurity argeoSecurity = new DefaultArgeoSecurity(); @@ -14,9 +15,13 @@ public class DefaultSecurityService implements ArgeoSecurityService { } public void newRole(String role) { - ArgeoUser superUser = securityDao.getUser(argeoSecurity.getSuperUsername()); - superUser.getRoles().add(role); - securityDao.update(superUser); + securityDao.createRole(role, argeoSecurity.getSuperUsername()); + } + + public void updateUserPassword(String username, String password) { + BasicArgeoUser user = new BasicArgeoUser(securityDao.getUser(username)); + user.setPassword(password); + securityDao.update(user); } public void newUser(ArgeoUser user) { diff --git a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/ldap/ArgeoLdapUserDetailsManager.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/ldap/ArgeoLdapUserDetailsManager.java new file mode 100644 index 000000000..016a7bae6 --- /dev/null +++ b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/ldap/ArgeoLdapUserDetailsManager.java @@ -0,0 +1,19 @@ +package org.argeo.security.ldap; + +import org.springframework.ldap.core.ContextSource; +import org.springframework.ldap.core.DistinguishedName; +import org.springframework.security.userdetails.ldap.LdapUserDetailsManager; + +public class ArgeoLdapUserDetailsManager extends LdapUserDetailsManager { + + public ArgeoLdapUserDetailsManager(ContextSource contextSource) { + super(contextSource); + } + + @Override + protected DistinguishedName buildGroupDn(String group) { + // TODO Auto-generated method stub + return super.buildGroupDn(group); + } + +} diff --git a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/ldap/SecurityDaoLdap.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/ldap/ArgeoSecurityDaoLdap.java similarity index 60% rename from security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/ldap/SecurityDaoLdap.java rename to security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/ldap/ArgeoSecurityDaoLdap.java index 27ee4443c..ae1fceea3 100644 --- a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/ldap/SecurityDaoLdap.java +++ b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/ldap/ArgeoSecurityDaoLdap.java @@ -1,22 +1,31 @@ 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 SecurityDaoLdap implements ArgeoSecurityDao { +public class ArgeoSecurityDaoLdap implements ArgeoSecurityDao, InitializingBean { // private final static Log log = LogFactory.getLog(UserDaoLdap.class); private UserDetailsManager userDetailsManager; @@ -26,7 +35,16 @@ public class SecurityDaoLdap implements ArgeoSecurityDao { private final LdapTemplate ldapTemplate; - public SecurityDaoLdap(ContextSource contextSource) { + /* 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); } @@ -35,7 +53,7 @@ public class SecurityDaoLdap implements ArgeoSecurityDao { } public ArgeoUser getUser(String uname) { - return (ArgeoUser) userDetailsManager.loadUserByUsername(uname); + return createBasicArgeoUser(getDetails(uname)); } @SuppressWarnings("unchecked") @@ -50,9 +68,7 @@ public class SecurityDaoLdap implements ArgeoSecurityDao { List lst = new ArrayList(); for (String username : usernames) { - UserDetails userDetails = userDetailsManager - .loadUserByUsername(username); - lst.add((ArgeoUser) userDetails); + lst.add(createBasicArgeoUser(getDetails(username))); } return lst; } @@ -88,24 +104,50 @@ public class SecurityDaoLdap implements ArgeoSecurityDao { return userDetailsManager.userExists(username); } - public void deleteRole(String role) { - if(true) - throw new UnsupportedOperationException(); - - Name dn = buildRoleDn(role); + 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", role); - ldapTemplate.bind(dn, context, null); + context.setAttributeValue("cn", group); + + // Add superuser because cannot create empty group + context.setAttributeValue("uniqueMember", superuserDn.toString()); + + ldapTemplate.bind(groupDn, context, null); } - - protected Name buildRoleDn(String name) { + + 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; } @@ -122,4 +164,8 @@ public class SecurityDaoLdap implements ArgeoSecurityDao { ArgeoLdapAuthoritiesPopulator authoritiesPopulator) { this.authoritiesPopulator = authoritiesPopulator; } + + protected UserDetails getDetails(String username) { + return userDetailsManager.loadUserByUsername(username); + } } diff --git a/security/runtime/org.argeo.security.mvc/src/main/java/org/argeo/security/mvc/UsersRolesController.java b/security/runtime/org.argeo.security.mvc/src/main/java/org/argeo/security/mvc/UsersRolesController.java index 8b09b94a5..e73522cf4 100644 --- a/security/runtime/org.argeo.security.mvc/src/main/java/org/argeo/security/mvc/UsersRolesController.java +++ b/security/runtime/org.argeo.security.mvc/src/main/java/org/argeo/security/mvc/UsersRolesController.java @@ -128,7 +128,25 @@ public class UsersRolesController implements MvcConstants { @ModelAttribute(ANSWER_MODEL_KEY) public ServerAnswer deleteRole(@RequestParam("role") String role) { securityService.getSecurityDao().deleteRole(role); - return ServerAnswer.ok("Role " + role + " created"); + return ServerAnswer.ok("Role " + role + " deleted"); + } + + @RequestMapping("/updateUserPassword.security") + @ModelAttribute(ANSWER_MODEL_KEY) + public ServerAnswer updateUserPassword( + @RequestParam("username") String username, + @RequestParam("password") String password) { + securityService.updateUserPassword(username, password); + return ServerAnswer.ok("Password updated for user " + username); + } + + @RequestMapping("/updatePassword.security") + @ModelAttribute(ANSWER_MODEL_KEY) + public ServerAnswer updatePassword( + @RequestParam("password") String password, + @RequestParam("oldPassword") String oldPassword) { + securityService.getSecurityDao().updatePassword(oldPassword, password); + return ServerAnswer.ok("Password updated"); } protected void cleanUserBeforeCreate(ArgeoUser user) { -- 2.30.2