Change password dialog
authorMathieu Baudier <mbaudier@argeo.org>
Fri, 21 Jan 2011 00:28:19 +0000 (00:28 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Fri, 21 Jan 2011 00:28:19 +0000 (00:28 +0000)
Support for hashing

git-svn-id: https://svn.argeo.org/commons/trunk@4062 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

12 files changed:
security/eclipse/plugins/org.argeo.security.ui.application/src/main/java/org/argeo/security/ui/application/SecureActionBarAdvisor.java
security/eclipse/plugins/org.argeo.security.ui/META-INF/spring/commands.xml
security/eclipse/plugins/org.argeo.security.ui/icons/password.gif [new file with mode: 0644]
security/eclipse/plugins/org.argeo.security.ui/plugin.xml
security/eclipse/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/commands/OpenChangePasswordDialog.java [new file with mode: 0644]
security/eclipse/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/dialogs/AbstractLoginDialog.java
security/eclipse/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/dialogs/ChangePasswordDialog.java [new file with mode: 0644]
security/eclipse/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/dialogs/DefaultLoginDialog.java
security/runtime/org.argeo.security.core/pom.xml
security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/ArgeoSecurityDao.java
security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/DefaultSecurityService.java
security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/ldap/ArgeoSecurityDaoLdap.java

index 956467fa24af47fdc9987c06026b408b87e22c67..5d7c58e0c8479f23d8a4a21aa8cfc65b88731c48 100644 (file)
@@ -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) {
index 121eb3dc90ea1f7ffb9172bfa816c40db561557d..d4415d6593936bb49ebd0592db1726fb60bd2630 100644 (file)
@@ -12,4 +12,8 @@
                scope="prototype">
                <property name="securityService" ref="securityService" />
        </bean>
+       <bean id="org.argeo.security.ui.openChangePasswordDialog" class="org.argeo.security.ui.commands.OpenChangePasswordDialog"
+               scope="prototype">
+               <property name="securityService" ref="securityService" />
+       </bean>
 </beans>
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 (file)
index 0000000..a6b251f
Binary files /dev/null and b/security/eclipse/plugins/org.argeo.security.ui/icons/password.gif differ
index fbb88b0bb168b76da27bc4e84015fb047a2cf263..ec50448398912a21728b0a2081622fd2fc14a4cf 100644 (file)
             id="org.argeo.security.ui.addRole"
             name="AddRole">
       </command>
+      <command
+            defaultHandler="org.argeo.eclipse.spring.SpringCommandHandler"
+            id="org.argeo.security.ui.openChangePasswordDialog"
+            name="OpenChangePasswordDialog">
+      </command>
     </extension>
      <extension
          id="menu:org.eclipse.ui.main.menu"
                 </command>
              </toolbar>
           </menuContribution>
+        <menuContribution
+                allPopups="false"
+                locationURI="toolbar:org.eclipse.ui.main.toolbar">
+             <toolbar
+                   id="org.argeo.security.ui.mainToolbar">
+                <command
+                      commandId="org.argeo.security.ui.openChangePasswordDialog"
+                      disabledIcon="icons/password.gif"
+                      icon="icons/password.gif"
+                      label="Change password"
+                      style="push"
+                      tooltip="Change password">
+                </command>
+             </toolbar>
+          </menuContribution>
   </extension>
  </plugin>
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 (file)
index 0000000..7047115
--- /dev/null
@@ -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;
+       }
+
+}
index d13414e1345a761eeee8ee52b8d22f4485f0eac0..d3d1be38b5154b785f6ea3b36ac68a43697e1f2e 100644 (file)
@@ -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 (file)
index 0000000..e2e78e8
--- /dev/null
@@ -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");
+       }
+
+}
index d5d60d0c7efb514024e38680a791a10446c4d0aa..d00e961fb3acd4a221c3071e13f26cbd3ad40638 100644 (file)
@@ -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;
        }
 
index 8f370aaa778cfcda2cb6735dfd4f09457215fbef..7facfdb1e115e12a65a03e57009d0177e948213e 100644 (file)
                        <optional>true</optional>
                </dependency>
 
+<!--           <dependency>-->
+<!--                   <groupId>org.apache.commons</groupId>-->
+<!--                   <artifactId>com.springsource.org.apache.commons.codec</artifactId>-->
+<!--           </dependency>-->
+
                <!-- TEST -->
                <dependency>
                        <groupId>org.junit</groupId>
index 85d83afa55c3b716baefddc4a942d785c19c52a4..de2664851a648143fd630569f9208170f496d7b3 100644 (file)
@@ -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);
 }
index 23e2372c8a5b1adb171c7e5a462d3ddad0e62be3..b9220b2692af7305657593944012b950cc96754c 100644 (file)
@@ -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);
        }
 
index 3d6d8ff9949dd9c22664abb6788ae508e5a55a73..807875db617328c879d311f6586feff66dffd16c 100644 (file)
@@ -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<UserNatureMapper> 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<ArgeoUser> 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)) {