From c95922edc1d65ef4ef568d66e29ab0bd679693ef Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Fri, 21 Jan 2011 00:28:19 +0000 Subject: [PATCH] Change password dialog Support for hashing git-svn-id: https://svn.argeo.org/commons/trunk@4062 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- .../application/SecureActionBarAdvisor.java | 2 + .../META-INF/spring/commands.xml | 4 + .../org.argeo.security.ui/icons/password.gif | Bin 0 -> 564 bytes .../plugins/org.argeo.security.ui/plugin.xml | 20 +++++ .../ui/commands/OpenChangePasswordDialog.java | 25 +++++++ .../ui/dialogs/AbstractLoginDialog.java | 9 +++ .../ui/dialogs/ChangePasswordDialog.java | 70 ++++++++++++++++++ .../ui/dialogs/DefaultLoginDialog.java | 8 +- .../runtime/org.argeo.security.core/pom.xml | 5 ++ .../org/argeo/security/ArgeoSecurityDao.java | 6 ++ .../security/core/DefaultSecurityService.java | 4 +- .../security/ldap/ArgeoSecurityDaoLdap.java | 50 +++++++++---- 12 files changed, 185 insertions(+), 18 deletions(-) create mode 100644 security/eclipse/plugins/org.argeo.security.ui/icons/password.gif create mode 100644 security/eclipse/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/commands/OpenChangePasswordDialog.java create mode 100644 security/eclipse/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/dialogs/ChangePasswordDialog.java diff --git a/security/eclipse/plugins/org.argeo.security.ui.application/src/main/java/org/argeo/security/ui/application/SecureActionBarAdvisor.java b/security/eclipse/plugins/org.argeo.security.ui.application/src/main/java/org/argeo/security/ui/application/SecureActionBarAdvisor.java index 956467fa2..5d7c58e0c 100644 --- a/security/eclipse/plugins/org.argeo.security.ui.application/src/main/java/org/argeo/security/ui/application/SecureActionBarAdvisor.java +++ b/security/eclipse/plugins/org.argeo.security.ui.application/src/main/java/org/argeo/security/ui/application/SecureActionBarAdvisor.java @@ -18,6 +18,7 @@ public class SecureActionBarAdvisor extends ActionBarAdvisor { private IWorkbenchAction newWindowAction; private IWorkbenchAction preferences; private IWorkbenchAction helpContentAction; + private IWorkbenchAction changePassword; // private IWorkbenchAction aboutAction; private final Boolean isRcp; @@ -46,6 +47,7 @@ public class SecureActionBarAdvisor extends ActionBarAdvisor { newWindowAction = ActionFactory.OPEN_NEW_WINDOW.create(window); register(newWindowAction); } + } protected void fillMenuBar(IMenuManager menuBar) { diff --git a/security/eclipse/plugins/org.argeo.security.ui/META-INF/spring/commands.xml b/security/eclipse/plugins/org.argeo.security.ui/META-INF/spring/commands.xml index 121eb3dc9..d4415d659 100644 --- a/security/eclipse/plugins/org.argeo.security.ui/META-INF/spring/commands.xml +++ b/security/eclipse/plugins/org.argeo.security.ui/META-INF/spring/commands.xml @@ -12,4 +12,8 @@ scope="prototype"> + + + diff --git a/security/eclipse/plugins/org.argeo.security.ui/icons/password.gif b/security/eclipse/plugins/org.argeo.security.ui/icons/password.gif new file mode 100644 index 0000000000000000000000000000000000000000..a6b251fc8553fe59749bc1a6baa172ae3d9e2723 GIT binary patch literal 564 zcmZ?wbhEHb6krfwc*el6<-kp^tmVFWt9&x&CDd(8Yuetu_-sJgrktMr1^ov~CLOAn zcC=~EiMIKt{L426Rc;Qg+8kc9HL`A7Y~zlM&OMdWk4#;C`rflom+!s3@#uZmiZfU4 zzrFh4?c5#LcAUPm+k2& zU!HCI`+o1=4~PDKI{x?5$-ke^ZJVU>^;XB9hy8z^%=+_e-k)dl|2$i;v0HIVzw*I( z7Rx#15+*@oPB6j z@yTtS*G_M`d124zw-5h=0mEPdia%Kx85jZ>bU=;*#R&uZ#D;(-IW|_grjE`IUR6<+ zt_cA=@}kTWCvY=O@8VLIoi;mwQ$tBsjBz1{hOCs7jJK7Q=L8XjHIiO7ettF{UBW7I z;y#8>{{Fs(6NEG+-Cexh-MwAhy9AYGER78uw6)AEy95-aE%bD)ZFS5oy7<*3T=gBD iogGbGyV&^{-0V$iek@Qtd}3+3i;&tDF|8m425SKKG1WZ) literal 0 HcmV?d00001 diff --git a/security/eclipse/plugins/org.argeo.security.ui/plugin.xml b/security/eclipse/plugins/org.argeo.security.ui/plugin.xml index fbb88b0bb..ec5044839 100644 --- a/security/eclipse/plugins/org.argeo.security.ui/plugin.xml +++ b/security/eclipse/plugins/org.argeo.security.ui/plugin.xml @@ -95,6 +95,11 @@ id="org.argeo.security.ui.addRole" name="AddRole"> + + + + + + + + diff --git a/security/eclipse/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/commands/OpenChangePasswordDialog.java b/security/eclipse/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/commands/OpenChangePasswordDialog.java new file mode 100644 index 000000000..70471159d --- /dev/null +++ b/security/eclipse/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/commands/OpenChangePasswordDialog.java @@ -0,0 +1,25 @@ +package org.argeo.security.ui.commands; + +import org.argeo.security.ArgeoSecurityService; +import org.argeo.security.ui.dialogs.ChangePasswordDialog; +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.ui.handlers.HandlerUtil; + +/** Opens the change password dialog. */ +public class OpenChangePasswordDialog extends AbstractHandler { + private ArgeoSecurityService securityService; + + public Object execute(ExecutionEvent event) throws ExecutionException { + ChangePasswordDialog dialog = new ChangePasswordDialog( + HandlerUtil.getActiveShell(event), securityService); + dialog.open(); + return null; + } + + public void setSecurityService(ArgeoSecurityService securityService) { + this.securityService = securityService; + } + +} diff --git a/security/eclipse/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/dialogs/AbstractLoginDialog.java b/security/eclipse/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/dialogs/AbstractLoginDialog.java index d13414e13..d3d1be38b 100644 --- a/security/eclipse/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/dialogs/AbstractLoginDialog.java +++ b/security/eclipse/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/dialogs/AbstractLoginDialog.java @@ -4,6 +4,8 @@ import java.io.IOException; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; @@ -102,6 +104,13 @@ public abstract class AbstractLoginDialog extends TitleAreaDialog implements // Call the adapter to handle the callbacks if (!isCancelled()) internalHandle(); + else + // clear callbacks are when cancelling + for (Callback callback : callbacks) + if (callback instanceof PasswordCallback) + ((PasswordCallback) callback).setPassword(null); + else if (callback instanceof NameCallback) + ((NameCallback) callback).setName(null); } }, true, new NullProgressMonitor(), Display.getDefault()); } catch (final Exception e) { diff --git a/security/eclipse/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/dialogs/ChangePasswordDialog.java b/security/eclipse/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/dialogs/ChangePasswordDialog.java new file mode 100644 index 000000000..e2e78e814 --- /dev/null +++ b/security/eclipse/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/dialogs/ChangePasswordDialog.java @@ -0,0 +1,70 @@ +package org.argeo.security.ui.dialogs; + +import org.argeo.ArgeoException; +import org.argeo.security.ArgeoSecurityService; +import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.dialogs.TitleAreaDialog; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + +/** Dialog to change the current user password */ +public class ChangePasswordDialog extends TitleAreaDialog { + private Text currentPassword, newPassword1, newPassword2; + private ArgeoSecurityService securityService; + + public ChangePasswordDialog(Shell parentShell, + ArgeoSecurityService securityService) { + super(parentShell); + this.securityService = securityService; + } + + protected Point getInitialSize() { + return new Point(300, 250); + } + + protected Control createDialogArea(Composite parent) { + Composite dialogarea = (Composite) super.createDialogArea(parent); + dialogarea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + Composite composite = new Composite(dialogarea, SWT.NONE); + composite.setLayout(new GridLayout(2, false)); + composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + currentPassword = createLP(composite, "Current password"); + newPassword1 = createLP(composite, "New password"); + newPassword2 = createLP(composite, "Repeat new password"); + + setMessage("Change password", IMessageProvider.INFORMATION); + parent.pack(); + return composite; + } + + @Override + protected void okPressed() { + if (!newPassword1.getText().equals(newPassword2.getText())) + throw new ArgeoException("Passwords are different"); + securityService.updateCurrentUserPassword(currentPassword.getText(), + newPassword1.getText()); + close(); + } + + /** Creates label and password. */ + protected Text createLP(Composite parent, String label) { + new Label(parent, SWT.NONE).setText(label); + Text text = new Text(parent, SWT.SINGLE | SWT.LEAD | SWT.PASSWORD + | SWT.BORDER); + text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + return text; + } + + protected void configureShell(Shell shell) { + super.configureShell(shell); + shell.setText("Change password"); + } + +} diff --git a/security/eclipse/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/dialogs/DefaultLoginDialog.java b/security/eclipse/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/dialogs/DefaultLoginDialog.java index d5d60d0c7..d00e961fb 100644 --- a/security/eclipse/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/dialogs/DefaultLoginDialog.java +++ b/security/eclipse/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/dialogs/DefaultLoginDialog.java @@ -30,16 +30,18 @@ public class DefaultLoginDialog extends AbstractLoginDialog { } protected Point getInitialSize() { - return new Point(300, 200); + return new Point(300, 250); } protected Control createDialogArea(Composite parent) { Composite dialogarea = (Composite) super.createDialogArea(parent); - dialogarea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + // dialogarea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, + // true)); Composite composite = new Composite(dialogarea, SWT.NONE); composite.setLayout(new GridLayout(2, false)); - composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); createCallbackHandlers(composite); + parent.pack(); return composite; } diff --git a/security/runtime/org.argeo.security.core/pom.xml b/security/runtime/org.argeo.security.core/pom.xml index 8f370aaa7..7facfdb1e 100644 --- a/security/runtime/org.argeo.security.core/pom.xml +++ b/security/runtime/org.argeo.security.core/pom.xml @@ -123,6 +123,11 @@ true + + + + + org.junit 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 85d83afa5..de2664851 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 @@ -56,4 +56,10 @@ public interface ArgeoSecurityDao { public ArgeoUser getUserWithPassword(String username); public String getDefaultRole(); + + /** Validates a raw password against an encoded one. */ + public Boolean isPasswordValid(String encoded, String raw); + + /** Encodes a raw password. */ + public String encodePassword(String raw); } 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 23e2372c8..b9220b269 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 @@ -62,9 +62,9 @@ public class DefaultSecurityService implements ArgeoSecurityService { public void updateCurrentUserPassword(String oldPassword, String newPassword) { SimpleArgeoUser user = new SimpleArgeoUser(getCurrentUser()); - if (!user.getPassword().equals(oldPassword)) + if (!securityDao.isPasswordValid(user.getPassword(), oldPassword)) throw new ArgeoException("Old password is not correct."); - user.setPassword(newPassword); + user.setPassword(securityDao.encodePassword(newPassword)); securityDao.update(user); } diff --git a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/ldap/ArgeoSecurityDaoLdap.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/ldap/ArgeoSecurityDaoLdap.java index 3d6d8ff99..807875db6 100644 --- a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/ldap/ArgeoSecurityDaoLdap.java +++ b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/ldap/ArgeoSecurityDaoLdap.java @@ -18,8 +18,11 @@ package org.argeo.security.ldap; import static org.argeo.security.core.ArgeoUserDetails.createSimpleArgeoUser; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; import java.util.ArrayList; import java.util.List; +import java.util.Random; import javax.naming.Name; import javax.naming.NamingException; @@ -44,6 +47,7 @@ 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.ldap.authenticator.LdapShaPasswordEncoder; import org.springframework.security.userdetails.UserDetails; import org.springframework.security.userdetails.UserDetailsManager; import org.springframework.security.userdetails.UserDetailsService; @@ -74,6 +78,19 @@ public class ArgeoSecurityDaoLdap implements ArgeoSecurityDao, InitializingBean private LdapUserDetailsService ldapUserDetailsService; private List userNatureMappers; + private LdapShaPasswordEncoder ldapShaPasswordEncoder = new LdapShaPasswordEncoder(); + private Random random; + + 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()); + } + } + public void afterPropertiesSet() throws Exception { if (usernameMapper == null) usernameMapper = new DefaultLdapUsernameToDnMapper(userBase, @@ -113,11 +130,6 @@ public class ArgeoSecurityDaoLdap implements ArgeoSecurityDao, InitializingBean } } - public ArgeoSecurityDaoLdap(BaseLdapPathContextSource contextSource) { - this.contextSource = contextSource; - ldapTemplate = new LdapTemplate(this.contextSource); - } - public synchronized void create(ArgeoUser user) { userDetailsManager.createUser(new ArgeoUserDetails(user)); } @@ -132,14 +144,14 @@ public class ArgeoSecurityDaoLdap implements ArgeoSecurityDao, InitializingBean 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; -// } + // 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 List listUsers() { @@ -220,6 +232,18 @@ public class ArgeoSecurityDaoLdap implements ArgeoSecurityDao, InitializingBean ldapTemplate.unbind(dn); } + public Boolean isPasswordValid(String encoded, String raw) { + return ldapShaPasswordEncoder.isPasswordValid(encoded, raw, null); + } + + public String encodePassword(String raw) { + byte[] salt = null; + // TODO: check that Linux auth supports SSHA + // byte[] salt = new byte[16]; + // random.nextBytes(salt); + return ldapShaPasswordEncoder.encodePassword(raw, salt); + } + protected String convertRoleToGroup(String role) { String group = role; if (group.startsWith(rolePrefix)) { -- 2.30.2