Fix graceful session and login management in RAP
[lgpl/argeo-commons.git] / security / plugins / org.argeo.security.equinox / src / main / java / org / argeo / security / equinox / SpringLoginModule.java
index c35416d9979c9fe246b9be4621a6bc233d714cff..ad6390d367a13333fc9f459a0199b7cc78bd121e 100644 (file)
@@ -15,6 +15,7 @@ import org.apache.commons.logging.LogFactory;
 import org.argeo.security.SiteAuthenticationToken;
 import org.springframework.security.Authentication;
 import org.springframework.security.AuthenticationManager;
+import org.springframework.security.BadCredentialsException;
 import org.springframework.security.context.SecurityContextHolder;
 import org.springframework.security.providers.jaas.SecurityContextLoginModule;
 
@@ -27,6 +28,8 @@ public class SpringLoginModule extends SecurityContextLoginModule {
        private CallbackHandler callbackHandler;
 
        private Subject subject;
+       
+       private Long waitBetweenFailedLoginAttempts = 5*1000l;
 
        public SpringLoginModule() {
 
@@ -41,75 +44,77 @@ public class SpringLoginModule extends SecurityContextLoginModule {
        }
 
        public boolean login() throws LoginException {
-               // try to retrieve Authentication from Subject
-               // Set<Authentication> auths =
-               // subject.getPrincipals(Authentication.class);
-               // if (auths.size() > 0)
-               // SecurityContextHolder.getContext().setAuthentication(
-               // auths.iterator().next());
-
-               // thread already logged in
-               if (SecurityContextHolder.getContext().getAuthentication() != null)
-                       return super.login();
-
-               // reset all principals and credentials
-               if (log.isTraceEnabled())
-                       log.trace("Resetting all principals and credentials of " + subject);
-               if (subject.getPrincipals() != null)
-                       subject.getPrincipals().clear();
-               if (subject.getPrivateCredentials() != null)
-                       subject.getPrivateCredentials().clear();
-               if (subject.getPublicCredentials() != null)
-                       subject.getPublicCredentials().clear();
-
-               // ask for username and password
-               Callback label = new TextOutputCallback(TextOutputCallback.INFORMATION,
-                               "Required login");
-               NameCallback nameCallback = new NameCallback("User");
-               PasswordCallback passwordCallback = new PasswordCallback("Password",
-                               false);
-
-               // NameCallback urlCallback = new NameCallback("Site URL");
-
-               if (callbackHandler == null) {
-                       throw new LoginException("No call back handler available");
-                       // return false;
-               }
                try {
+                       // thread already logged in
+                       if (SecurityContextHolder.getContext().getAuthentication() != null)
+                               return super.login();
+
+                       // reset all principals and credentials
+                       if (log.isTraceEnabled())
+                               log.trace("Resetting all principals and credentials of "
+                                               + subject);
+                       if (subject.getPrincipals() != null)
+                               subject.getPrincipals().clear();
+                       if (subject.getPrivateCredentials() != null)
+                               subject.getPrivateCredentials().clear();
+                       if (subject.getPublicCredentials() != null)
+                               subject.getPublicCredentials().clear();
+
+                       // ask for username and password
+                       Callback label = new TextOutputCallback(
+                                       TextOutputCallback.INFORMATION, "Required login");
+                       NameCallback nameCallback = new NameCallback("User");
+                       PasswordCallback passwordCallback = new PasswordCallback(
+                                       "Password", false);
+
+                       // NameCallback urlCallback = new NameCallback("Site URL");
+
+                       if (callbackHandler == null)
+                               throw new LoginException("No call back handler available");
                        callbackHandler.handle(new Callback[] { label, nameCallback,
                                        passwordCallback });
-               } catch (Exception e) {
-                       throw new RuntimeException("Unexpected exception when handling", e);
-               }
 
-               // Set user name and password
-               String username = nameCallback.getName();
-               String password = "";
-               if (passwordCallback.getPassword() != null) {
-                       password = String.valueOf(passwordCallback.getPassword());
+                       // Set user name and password
+                       String username = nameCallback.getName();
+                       if (username == null || username.trim().equals(""))
+                               return false;
+
+                       String password = "";
+                       if (passwordCallback.getPassword() != null)
+                               password = String.valueOf(passwordCallback.getPassword());
+
+                       // String url = urlCallback.getName();
+                       // TODO: set it via system properties
+                       String workspace = null;
+
+                       SiteAuthenticationToken credentials = new SiteAuthenticationToken(
+                                       username, password, null, workspace);
+
+                       Authentication authentication;
+                       try {
+                               authentication = authenticationManager
+                                               .authenticate(credentials);
+                       } catch (BadCredentialsException e) {
+                               // wait between failed login attempts
+                               Thread.sleep(waitBetweenFailedLoginAttempts);
+                               throw e;
+                       }
+                       registerAuthentication(authentication);
+                       boolean res = super.login();
+                       return res;
+               } catch (LoginException e) {
+                       throw e;
+               } catch (ThreadDeath e) {
+                       LoginException le = new LoginException(
+                                       "Spring Security login thread died");
+                       le.initCause(e);
+                       throw le;
+               } catch (Exception e) {
+                       LoginException le = new LoginException(
+                                       "Spring Security login failed");
+                       le.initCause(e);
+                       throw le;
                }
-
-               // String url = urlCallback.getName();
-               // TODO: set it via system properties
-               String workspace = null;
-
-               SiteAuthenticationToken credentials = new SiteAuthenticationToken(
-                               username, password, null, workspace);
-
-               // try {
-               Authentication authentication = authenticationManager
-                               .authenticate(credentials);
-               registerAuthentication(authentication);
-               boolean res = super.login();
-               return res;
-               // } catch (BadCredentialsException bce) {
-               // throw bce;
-               // } catch (LoginException e) {
-               // // LoginException loginException = new LoginException(
-               // // "Bad credentials");
-               // // loginException.initCause(e);
-               // throw e;
-               // }
        }
 
        @Override