Improve Security UI
authorMathieu Baudier <mbaudier@argeo.org>
Tue, 31 May 2011 16:11:17 +0000 (16:11 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Tue, 31 May 2011 16:11:17 +0000 (16:11 +0000)
git-svn-id: https://svn.argeo.org/commons/trunk@4550 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

eclipse/runtime/org.argeo.eclipse.ui/src/main/java/org/argeo/eclipse/ui/dialogs/SingleValue.java
security/plugins/org.argeo.security.ui.admin/META-INF/spring/commands.xml
security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/commands/RefreshUsersList.java
security/plugins/org.argeo.security.ui.admin/src/main/java/org/argeo/security/ui/admin/editors/DefaultUserMainPage.java
security/plugins/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/SecureEntryPoint.java
security/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/commands/OpenChangePasswordDialog.java
security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/UserAdminService.java
security/runtime/org.argeo.security.ldap/src/main/java/org/argeo/security/ldap/ArgeoLdapUserDetailsManager.java
security/runtime/org.argeo.security.ldap/src/main/java/org/argeo/security/ldap/jcr/JcrUserDetailsContextMapper.java

index d3e67978f9de29755d021a85ca57d8bfcb4448bb..c15a76736528b0fdd849b892071923e05e3507c1 100644 (file)
@@ -14,7 +14,7 @@ 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 */
+/** Dialog retrieve a single value. */
 public class SingleValue extends TitleAreaDialog {
        private Text valueT;
        private String value;
index 96d25ddb6a8ccba207b15af7377438866d5fc939..7f6781cc1e5b4014f39587bfd50450f7f0e33e6a 100644 (file)
@@ -22,5 +22,6 @@
        <bean id="refreshUsersList" class="org.argeo.security.ui.admin.commands.RefreshUsersList"
                scope="prototype">
                <property name="userAdminService" ref="userAdminService" />
+               <property name="session" ref="session" />
        </bean>
 </beans>
index a66b79067d78a348c2727a7263ea23a8247baa35..6cf9a774971d70bed95350a39882effa89649273 100644 (file)
@@ -1,5 +1,17 @@
 package org.argeo.security.ui.admin.commands;
 
+import java.util.Set;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.query.Query;
+
+import org.argeo.ArgeoException;
+import org.argeo.jcr.ArgeoNames;
+import org.argeo.jcr.ArgeoTypes;
+import org.argeo.jcr.JcrUtils;
 import org.argeo.security.UserAdminService;
 import org.argeo.security.ui.admin.views.UsersView;
 import org.eclipse.core.commands.AbstractHandler;
@@ -7,11 +19,37 @@ import org.eclipse.core.commands.ExecutionEvent;
 import org.eclipse.core.commands.ExecutionException;
 import org.eclipse.ui.handlers.HandlerUtil;
 
-/** Refresh the main EBI list. */
+/**
+ * Refreshes the main EBI list, removing nodes which are not referenced by user
+ * admin service.
+ */
 public class RefreshUsersList extends AbstractHandler {
        private UserAdminService userAdminService;
+       private Session session;
 
        public Object execute(ExecutionEvent event) throws ExecutionException {
+               Set<String> users = userAdminService.listUsers();
+               try {
+                       Query query = session
+                                       .getWorkspace()
+                                       .getQueryManager()
+                                       .createQuery(
+                                                       "select * from [" + ArgeoTypes.ARGEO_USER_HOME
+                                                                       + "]", Query.JCR_SQL2);
+                       NodeIterator nit = query.execute().getNodes();
+                       while (nit.hasNext()) {
+                               Node node = nit.nextNode();
+                               String username = node.getProperty(ArgeoNames.ARGEO_USER_ID)
+                                               .getString();
+                               if (!users.contains(username))
+                                       node.remove();
+                       }
+                       session.save();
+               } catch (RepositoryException e) {
+                       JcrUtils.discardQuietly(session);
+                       throw new ArgeoException("Cannot list users", e);
+               }
+
                userAdminService.synchronize();
                UsersView view = (UsersView) HandlerUtil
                                .getActiveWorkbenchWindow(event).getActivePage()
@@ -24,4 +62,8 @@ public class RefreshUsersList extends AbstractHandler {
                this.userAdminService = userAdminService;
        }
 
+       public void setSession(Session session) {
+               this.session = session;
+       }
+
 }
\ No newline at end of file
index cfaf6e4fb6aa47c0d7b571f4ffa53f4cb2b46883..22927bd1126c6713f9a30ba705ad5a28ee69cba7 100644 (file)
@@ -118,6 +118,7 @@ public class DefaultUserMainPage extends FormPage implements ArgeoNames {
                                                        email.getText());
                                        userProfile.setProperty(Property.JCR_DESCRIPTION,
                                                        description.getText());
+                                       userProfile.getSession().save();
                                        super.commit(onSave);
                                        if (log.isTraceEnabled())
                                                log.trace("General part committed");
index 638b33a12ef0d0aea8738350ae536305b37407a6..d38bd8bc0b6ac7226597d02a95bc95c12500a5ba 100644 (file)
@@ -8,11 +8,15 @@ import javax.security.auth.login.LoginException;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.eclipse.equinox.security.auth.ILoginContext;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.MessageDialog;
 import org.eclipse.rwt.RWT;
 import org.eclipse.rwt.lifecycle.IEntryPoint;
 import org.eclipse.rwt.service.SessionStoreEvent;
 import org.eclipse.rwt.service.SessionStoreListener;
+import org.eclipse.swt.graphics.Image;
 import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
 import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
 import org.eclipse.ui.application.WorkbenchAdvisor;
@@ -21,6 +25,7 @@ import org.eclipse.ui.application.WorkbenchWindowAdvisor;
 public class SecureEntryPoint implements IEntryPoint, SessionStoreListener {
        private final static Log log = LogFactory.getLog(SecureEntryPoint.class);
 
+       @SuppressWarnings("unchecked")
        @Override
        public int createUI() {
                // 15 mins session timeout
@@ -41,6 +46,8 @@ public class SecureEntryPoint implements IEntryPoint, SessionStoreListener {
                        subject = loginContext.getSubject();
                } catch (LoginException e) {
                        log.error("Error when logging in.", e);
+                       MessageDialog.openInformation(display.getActiveShell(),
+                                       "Login failed", "Login failed");
                        display.dispose();
                        RWT.getRequest().getSession().setMaxInactiveInterval(1);
                        try {
@@ -48,6 +55,7 @@ public class SecureEntryPoint implements IEntryPoint, SessionStoreListener {
                        } catch (InterruptedException e1) {
                                // silent
                        }
+                       // throw new RuntimeException("Login failed", e);
                        return -1;
                }
 
@@ -121,6 +129,19 @@ public class SecureEntryPoint implements IEntryPoint, SessionStoreListener {
        // log.debug("Workbench closed");
        // }
 
+       static class FailedLogin extends MessageDialog {
+
+               public FailedLogin(Shell parentShell, String dialogTitle,
+                               Image dialogTitleImage, String dialogMessage,
+                               int dialogImageType, String[] dialogButtonLabels,
+                               int defaultIndex) {
+                       super(parentShell, "Failed ", dialogTitleImage, dialogMessage,
+                                       dialogImageType, dialogButtonLabels, defaultIndex);
+                       // TODO Auto-generated constructor stub
+               }
+
+       }
+
        @SuppressWarnings("rawtypes")
        private PrivilegedAction getRunAction(final Display display) {
                return new PrivilegedAction() {
index ab52b116c8bae9830af02768fff52654295fab13..c23e52006f46bb32beab80bac2f64f377259386b 100644 (file)
@@ -4,6 +4,8 @@ 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.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.MessageDialog;
 import org.eclipse.ui.handlers.HandlerUtil;
 import org.springframework.security.userdetails.UserDetailsManager;
 
@@ -14,7 +16,10 @@ public class OpenChangePasswordDialog extends AbstractHandler {
        public Object execute(ExecutionEvent event) throws ExecutionException {
                ChangePasswordDialog dialog = new ChangePasswordDialog(
                                HandlerUtil.getActiveShell(event), userDetailsManager);
-               dialog.open();
+               if (dialog.open() == Dialog.OK) {
+                       MessageDialog.openInformation(HandlerUtil.getActiveShell(event),
+                                       "Password changed", "Password changed.");
+               }
                return null;
        }
 
index 964c9dff2d7332a0630f943daef4ca07a78cf9e7..8844534c3cd6b7408ccadea8e3f9a8f40c62df17 100644 (file)
@@ -24,6 +24,9 @@ public interface UserAdminService extends UserDetailsManager {
        /*
         * USERS
         */
+       /** List all users. */
+       public Set<String> listUsers();
+
        /** List users having this role (except the super user). */
        public Set<String> listUsersInRole(String role);
 
index 040d650d7bba1c085aef3c379ffd1ba85fd601f1..392ac4a27edcea9d2ef911097e3a83659f03dc0c 100644 (file)
@@ -10,10 +10,13 @@ import java.util.Random;
 import java.util.Set;
 import java.util.TreeSet;
 
+import org.argeo.ArgeoException;
 import org.argeo.security.UserAdminDao;
 import org.argeo.security.UserAdminService;
 import org.springframework.ldap.core.ContextSource;
+import org.springframework.security.Authentication;
 import org.springframework.security.GrantedAuthority;
+import org.springframework.security.context.SecurityContextHolder;
 import org.springframework.security.providers.encoding.PasswordEncoder;
 import org.springframework.security.userdetails.UserDetails;
 import org.springframework.security.userdetails.ldap.LdapUserDetailsManager;
@@ -41,7 +44,22 @@ public class ArgeoLdapUserDetailsManager extends LdapUserDetailsManager
 
        @Override
        public void changePassword(String oldPassword, String newPassword) {
-               super.changePassword(oldPassword, encodePassword(newPassword));
+               Authentication authentication = SecurityContextHolder.getContext()
+                               .getAuthentication();
+               if (authentication == null)
+                       throw new ArgeoException(
+                                       "Cannot change password without authentication");
+               String username = authentication.getName();
+               UserDetails userDetails = loadUserByUsername(username);
+               String currentPassword = userDetails.getPassword();
+               if (currentPassword == null)
+                       throw new ArgeoException("Cannot access current password");
+               if (!passwordEncoder
+                               .isPasswordValid(currentPassword, oldPassword, null))
+                       throw new ArgeoException("Old password invalid");
+               // Spring Security LDAP 2.0 is buggy when used with OpenLDAP and called
+               // with oldPassword argument
+               super.changePassword(null, encodePassword(newPassword));
        }
 
        public void newRole(String role) {
@@ -58,6 +76,10 @@ public class ArgeoLdapUserDetailsManager extends LdapUserDetailsManager
                userAdminDao.deleteRole(role);
        }
 
+       public Set<String> listUsers() {
+               return userAdminDao.listUsers();
+       }
+
        public Set<String> listUsersInRole(String role) {
                Set<String> lst = new TreeSet<String>(
                                userAdminDao.listUsersInRole(role));
index 7e2d89e6d62805adaf15f424cf8fecedc099fbd6..ec4255af9a6a1777583f058fda55cae186e2e902 100644 (file)
@@ -6,6 +6,7 @@ import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Random;
+import java.util.SortedSet;
 import java.util.concurrent.Executor;
 
 import javax.jcr.Node;
@@ -64,6 +65,10 @@ public class JcrUserDetailsContextMapper implements UserDetailsContextMapper,
 
        public UserDetails mapUserFromContext(final DirContextOperations ctx,
                        final String username, GrantedAuthority[] authorities) {
+               if (ctx == null)
+                       throw new ArgeoException("No LDAP information found for user "
+                                       + username);
+
                final StringBuffer userHomePathT = new StringBuffer("");
                Runnable action = new Runnable() {
                        public void run() {
@@ -85,13 +90,20 @@ public class JcrUserDetailsContextMapper implements UserDetailsContextMapper,
                }
 
                // password
-               byte[] arr = (byte[]) ctx
-                               .getAttributeSortedStringSet(passwordAttribute).first();
+               SortedSet<?> passwordAttributes = ctx
+                               .getAttributeSortedStringSet(passwordAttribute);
+               String password;
+               if (passwordAttributes == null || passwordAttributes.size() == 0) {
+                       throw new ArgeoException("No password found for user " + username);
+               } else {
+                       byte[] arr = (byte[]) passwordAttributes.first();
+                       password = new String(arr);
+                       // erase password
+                       Arrays.fill(arr, (byte) 0);
+               }
                JcrUserDetails userDetails = new JcrUserDetails(
-                               userHomePathT.toString(), username, new String(arr), true,
-                               true, true, true, authorities);
-               // erase password
-               Arrays.fill(arr, (byte) 0);
+                               userHomePathT.toString(), username, password, true, true, true,
+                               true, authorities);
                return userDetails;
        }
 
@@ -210,7 +222,7 @@ public class JcrUserDetailsContextMapper implements UserDetailsContextMapper,
 
                        if (ldapAttribute.equals("description")) {
                                String value = userProfile.getProperty(jcrProperty).getString();
-                               if(value.trim().equals(""))
+                               if (value.trim().equals(""))
                                        return;
                        }