Improve login mechanism, based on JAAS
authorMathieu Baudier <mbaudier@argeo.org>
Fri, 13 Feb 2015 19:30:03 +0000 (19:30 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Fri, 13 Feb 2015 19:30:03 +0000 (19:30 +0000)
git-svn-id: https://svn.argeo.org/commons/trunk@7852 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

26 files changed:
org.argeo.cms/src/org/argeo/cms/KernelHeader.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/internal/kernel/Kernel.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/jaas.cfg
org.argeo.security.core/src/org/argeo/security/SecurityUtils.java
org.argeo.security.core/src/org/argeo/security/core/AbstractSystemExecution.java
org.argeo.security.core/src/org/argeo/security/core/AuthenticatedApplicationContextInitialization.java
org.argeo.security.core/src/org/argeo/security/core/AuthenticationProvidersRegister.java
org.argeo.security.core/src/org/argeo/security/core/BundleContextCallback.java [deleted file]
org.argeo.security.core/src/org/argeo/security/core/SpringLoginModule.java [deleted file]
org.argeo.security.core/src/org/argeo/security/core/UserAdminLoginModule.java [deleted file]
org.argeo.security.core/src/org/argeo/security/login/AbstractSpringSecurityLoginModule.java [new file with mode: 0644]
org.argeo.security.core/src/org/argeo/security/login/AnonymousLoginModule.java [new file with mode: 0644]
org.argeo.security.core/src/org/argeo/security/login/BundleContextCallback.java [new file with mode: 0644]
org.argeo.security.core/src/org/argeo/security/login/BundleContextCallbackHandler.java [new file with mode: 0644]
org.argeo.security.core/src/org/argeo/security/login/EndUserLoginModule.java [new file with mode: 0644]
org.argeo.security.core/src/org/argeo/security/login/LoginCanceledException.java [new file with mode: 0644]
org.argeo.security.core/src/org/argeo/security/login/SystemLoginModule.java [new file with mode: 0644]
org.argeo.security.core/src/org/argeo/security/login/UserAdminLoginModule.java [new file with mode: 0644]
org.argeo.security.ui.rap/META-INF/jaas_default.txt [deleted file]
org.argeo.security.ui.rap/bnd.bnd
org.argeo.security.ui.rap/pom.xml
org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/AnonymousEntryPoint.java
org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/NullEntryPoint.java
org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/RapWindowAdvisor.java
org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/SecureEntryPoint.java
org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/SecureRapActivator.java

diff --git a/org.argeo.cms/src/org/argeo/cms/KernelHeader.java b/org.argeo.cms/src/org/argeo/cms/KernelHeader.java
new file mode 100644 (file)
index 0000000..db1034a
--- /dev/null
@@ -0,0 +1,8 @@
+package org.argeo.cms;
+
+/** Public properties of the CMS Kernel */
+public interface KernelHeader {
+       final static String LOGIN_CONTEXT_USER = "USER";
+       final static String LOGIN_CONTEXT_ANONYMOUS = "ANONYMOUS";
+       final static String LOGIN_CONTEXT_SYSTEM = "SYSTEM";
+}
index 848206f5c5248833707a99838b92bceb3210d031..e38704d5cd67df3f2571137ca2ce5f01f2e87657 100644 (file)
@@ -7,9 +7,7 @@ import org.apache.commons.logging.LogFactory;
 import org.argeo.ArgeoException;
 import org.argeo.jackrabbit.OsgiJackrabbitRepositoryFactory;
 import org.argeo.security.core.InternalAuthentication;
-import org.eclipse.rap.rwt.application.ApplicationConfiguration;
 import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceRegistration;
 import org.springframework.security.core.context.SecurityContextHolder;
 
 /**
@@ -34,8 +32,6 @@ final class Kernel {
        private NodeSecurity nodeSecurity;
        private NodeHttp nodeHttp;
 
-       private ServiceRegistration<ApplicationConfiguration> workbenchReg;
-
        Kernel(BundleContext bundleContext) {
                this.bundleContext = bundleContext;
        }
@@ -58,12 +54,6 @@ final class Kernel {
                        bundleContext.registerService(RepositoryFactory.class,
                                        repositoryFactory, null);
                        nodeHttp.publish();
-
-//                     if ("false".equals(bundleContext
-//                                     .getProperty(PROP_WORKBENCH_AUTOSTART))) {
-//                             WorkbenchApplicationConfiguration wac = new WorkbenchApplicationConfiguration();
-//                             registerWorkbench(wac);
-//                     }
                } catch (Exception e) {
                        log.error("Cannot initialize Argeo CMS", e);
                        throw new ArgeoException("Cannot initialize", e);
@@ -78,9 +68,6 @@ final class Kernel {
        void destroy() {
                long begin = System.currentTimeMillis();
 
-               // OSGi
-               workbenchReg.unregister();
-
                nodeHttp = null;
                nodeSecurity.destroy();
                node.destroy();
index 110d0e14372aedc99ecbd3f0160c3d6d254a5fff..0155fc5eee9eae292a04d372041ec173d0af1099 100644 (file)
@@ -1,5 +1,15 @@
-SPRING_SECURITY_CONTEXT {
-    org.argeo.security.core.SpringLoginModule required;
+USER {
+    org.argeo.security.login.EndUserLoginModule requisite;
+    org.springframework.security.authentication.jaas.SecurityContextLoginModule required;
+};
+
+ANONYMOUS {
+    org.argeo.security.login.AnonymousLoginModule requisite;
+    org.springframework.security.authentication.jaas.SecurityContextLoginModule required;
+};
+
+SYSTEM {
+    org.argeo.security.login.SystemLoginModule requisite;
     org.springframework.security.authentication.jaas.SecurityContextLoginModule required;
 };
 
index 44ddeac865a00b8c436d1ef795b2855986358c65..8c6715446a96ec78cff35bd0176f3584ffadab69 100644 (file)
@@ -19,6 +19,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
+import java.util.UUID;
 
 import org.springframework.security.authentication.AnonymousAuthenticationToken;
 import org.springframework.security.core.Authentication;
@@ -27,11 +28,20 @@ import org.springframework.security.core.context.SecurityContext;
 import org.springframework.security.core.context.SecurityContextHolder;
 
 /** Static utilities */
-public class SecurityUtils {
+public final class SecurityUtils {
+       private final static String systemKey = UUID.randomUUID().toString();
 
        private SecurityUtils() {
        }
 
+       /**
+        * @return a String which is guaranteed to be unique between and constant
+        *         within a Java static context (typically a VM launch)
+        */
+       public final static String getStaticKey() {
+               return systemKey;
+       }
+
        /** Whether the current thread has the admin role */
        public static boolean hasCurrentThreadAuthority(String authority) {
                SecurityContext securityContext = SecurityContextHolder.getContext();
index 3abc1b48299b74a7e9e26930162b445557658e65..0d075c3a60b5b0039a17fb95de648b12d2dbe952 100644 (file)
  */
 package org.argeo.security.core;
 
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.argeo.ArgeoException;
 import org.argeo.security.SystemAuthentication;
+import org.argeo.security.login.BundleContextCallbackHandler;
+import org.osgi.framework.BundleContext;
 import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.BadCredentialsException;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.context.SecurityContext;
 import org.springframework.security.core.context.SecurityContextHolder;
@@ -30,15 +36,18 @@ public abstract class AbstractSystemExecution {
                // Forces Spring Security to use inheritable strategy
                // FIXME find a better place for forcing spring security mode
                // doesn't work for the time being
-//             if (System.getProperty(SecurityContextHolder.SYSTEM_PROPERTY) == null)
-//                     SecurityContextHolder
-//                                     .setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
+               // if (System.getProperty(SecurityContextHolder.SYSTEM_PROPERTY) ==
+               // null)
+               // SecurityContextHolder
+               // .setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
        }
 
        private final static Log log = LogFactory
                        .getLog(AbstractSystemExecution.class);
        private AuthenticationManager authenticationManager;
+       private BundleContext bundleContext;
        private String systemAuthenticationKey;
+       private String loginContextName = "SYSTEM";
 
        /** Whether the current thread was authenticated by this component. */
        private ThreadLocal<Boolean> authenticatedBySelf = new ThreadLocal<Boolean>() {
@@ -76,9 +85,24 @@ public abstract class AbstractSystemExecution {
                                                InternalAuthentication.SYSTEM_KEY_DEFAULT);
                if (key == null)
                        throw new ArgeoException("No system key defined");
-               Authentication auth = authenticationManager
-                               .authenticate(new InternalAuthentication(key));
-               securityContext.setAuthentication(auth);
+               if (authenticationManager != null) {
+                       Authentication auth = authenticationManager
+                                       .authenticate(new InternalAuthentication(key));
+                       securityContext.setAuthentication(auth);
+               } else {
+                       try {
+                               // TODO test this
+                               if (bundleContext == null)
+                                       throw new ArgeoException("bundleContext must be set");
+                               BundleContextCallbackHandler callbackHandler = new BundleContextCallbackHandler(
+                                               bundleContext);
+                               LoginContext loginContext = new LoginContext(loginContextName,
+                                               callbackHandler);
+                               loginContext.login();
+                       } catch (LoginException e) {
+                               throw new BadCredentialsException("Cannot authenticate");
+                       }
+               }
                authenticatedBySelf.set(true);
                if (log.isTraceEnabled())
                        log.trace("System authenticated");
@@ -104,13 +128,20 @@ public abstract class AbstractSystemExecution {
                return authenticatedBySelf.get();
        }
 
+       @Deprecated
        public void setAuthenticationManager(
                        AuthenticationManager authenticationManager) {
+               // log.warn("This approach is deprecated, inject bundleContext instead");
                this.authenticationManager = authenticationManager;
        }
 
+       @Deprecated
        public void setSystemAuthenticationKey(String systemAuthenticationKey) {
                this.systemAuthenticationKey = systemAuthenticationKey;
        }
 
+       public void setBundleContext(BundleContext bundleContext) {
+               this.bundleContext = bundleContext;
+       }
+
 }
index 1c1059199b009949962f14c4a656798a02ad7ed8..5faa2a75110f265621290e7a04cb84294c0ffbde 100644 (file)
@@ -66,7 +66,6 @@ public class AuthenticatedApplicationContextInitialization extends
 
        public Object postProcessBeforeInitialization(Object bean, String beanName)
                        throws BeansException {
-               // authenticateAsSystem();
                return bean;
        }
 
index 317815e8b33de454ef7cbf0e620e6fc68f9ae00f..e001f4c2d6d1b99809cc671655e271ccaad4ad27 100644 (file)
@@ -27,6 +27,7 @@ import org.springframework.beans.factory.InitializingBean;
  * Maintains a list of authentication providers injected in to a provider
  * manager, in order to avoid issues with OSGi services and use packages.
  */
+@Deprecated
 public class AuthenticationProvidersRegister implements InitializingBean {
        private Log log = LogFactory.getLog(AuthenticationProvidersRegister.class);
 
diff --git a/org.argeo.security.core/src/org/argeo/security/core/BundleContextCallback.java b/org.argeo.security.core/src/org/argeo/security/core/BundleContextCallback.java
deleted file mode 100644 (file)
index 51831fd..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-package org.argeo.security.core;
-
-import javax.security.auth.callback.Callback;
-
-import org.osgi.framework.BundleContext;
-
-/** Gives access to the OSGi {@link BundleContext} */
-public class BundleContextCallback implements Callback {
-       private BundleContext bundleContext;
-
-       public BundleContext getBundleContext() {
-               return bundleContext;
-       }
-
-       public void setBundleContext(BundleContext bundleContext) {
-               this.bundleContext = bundleContext;
-       }
-
-}
diff --git a/org.argeo.security.core/src/org/argeo/security/core/SpringLoginModule.java b/org.argeo.security.core/src/org/argeo/security/core/SpringLoginModule.java
deleted file mode 100644 (file)
index 6ec4fc6..0000000
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *         http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.argeo.security.core;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.UUID;
-
-import javax.security.auth.Subject;
-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 javax.security.auth.login.LoginException;
-import javax.security.auth.spi.LoginModule;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.security.NodeAuthenticationToken;
-import org.argeo.util.LocaleCallback;
-import org.argeo.util.LocaleUtils;
-import org.osgi.framework.BundleContext;
-import org.springframework.security.authentication.AnonymousAuthenticationToken;
-import org.springframework.security.authentication.AuthenticationManager;
-import org.springframework.security.authentication.BadCredentialsException;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.authority.SimpleGrantedAuthority;
-import org.springframework.security.core.context.SecurityContextHolder;
-
-/** Login module which caches one subject per thread. */
-public class SpringLoginModule implements LoginModule {
-       final static String NODE_REPO_URI = "argeo.node.repo.uri";
-
-       private final static Log log = LogFactory.getLog(SpringLoginModule.class);
-
-       private CallbackHandler callbackHandler;
-
-       private Subject subject;
-
-       private Long waitBetweenFailedLoginAttempts = 5 * 1000l;
-
-       private Boolean remote = false;
-       private Boolean anonymous = false;
-       /** Comma separated list of locales */
-       private String availableLocales = "";
-
-       private String key = null;
-       private String anonymousRole = "ROLE_ANONYMOUS";
-
-       public SpringLoginModule() {
-
-       }
-
-       @SuppressWarnings("rawtypes")
-       public void initialize(Subject subject, CallbackHandler callbackHandler,
-                       Map sharedState, Map options) {
-               this.callbackHandler = callbackHandler;
-               this.subject = subject;
-       }
-
-       public boolean login() throws LoginException {
-               try {
-                       // thread already logged in
-                       Authentication currentAuth = SecurityContextHolder.getContext()
-                                       .getAuthentication();
-                       if (currentAuth != null) {
-                               if (subject.getPrincipals(Authentication.class).size() == 0) {
-                                       subject.getPrincipals().add(currentAuth);
-                               } else {
-                                       Authentication principal = subject
-                                                       .getPrincipals(Authentication.class).iterator()
-                                                       .next();
-                                       if (principal != currentAuth)
-                                               throw new LoginException(
-                                                               "Already authenticated with a different auth");
-                               }
-                               return true;
-                       }
-
-                       if (remote && anonymous)
-                               throw new LoginException(
-                                               "Cannot have a Spring login module which is remote and anonymous");
-
-                       // reset all principals and credentials
-                       if (log.isTraceEnabled())
-                               log.trace("Resetting all principals and credentials of "
-                                               + subject);
-                       subject.getPrincipals().clear();
-                       subject.getPrivateCredentials().clear();
-                       subject.getPublicCredentials().clear();
-
-                       Locale selectedLocale = null;
-                       // deals first with public access since it's simple
-                       if (anonymous) {
-                               // FIXME Is this code still needed?
-                               AuthenticationManager authenticationManager = null;
-
-                               // multi locale
-                               if (callbackHandler != null && availableLocales != null
-                                               && !availableLocales.trim().equals("")) {
-                                       LocaleCallback localeCallback = new LocaleCallback(
-                                                       availableLocales);
-                                       callbackHandler.handle(new Callback[] { localeCallback });
-                                       selectedLocale = localeCallback.getSelectedLocale();
-                               }
-
-                               // TODO integrate with JCR?
-                               Object principal = UUID.randomUUID().toString();
-                               List<SimpleGrantedAuthority> authorities = Collections
-                                               .singletonList(new SimpleGrantedAuthority(anonymousRole));
-                               AnonymousAuthenticationToken anonymousToken = new AnonymousAuthenticationToken(
-                                               key, principal, authorities);
-                               Authentication auth = authenticationManager
-                                               .authenticate(anonymousToken);
-                               registerAuthentication(auth);
-                       } else {
-                               if (callbackHandler == null)
-                                       throw new LoginException("No call back handler available");
-
-                               // ask for username and password
-                               NameCallback nameCallback = new NameCallback("User");
-                               PasswordCallback passwordCallback = new PasswordCallback(
-                                               "Password", false);
-                               final String defaultNodeUrl = System
-                                               .getProperty(NODE_REPO_URI,
-                                                               "http://localhost:7070/org.argeo.jcr.webapp/remoting/node");
-                               NameCallback urlCallback = new NameCallback("Site URL",
-                                               defaultNodeUrl);
-                               LocaleCallback localeCallback = new LocaleCallback(
-                                               availableLocales);
-                               BundleContextCallback bundleContextCallback = new BundleContextCallback();
-
-                               // handle callbacks
-                               if (remote)
-                                       callbackHandler.handle(new Callback[] { nameCallback,
-                                                       passwordCallback, urlCallback, localeCallback,
-                                                       bundleContextCallback });
-                               else
-                                       callbackHandler.handle(new Callback[] { nameCallback,
-                                                       passwordCallback, localeCallback,
-                                                       bundleContextCallback });
-
-                               selectedLocale = localeCallback.getSelectedLocale();
-
-                               // create credentials
-                               final String username = nameCallback.getName();
-                               if (username == null || username.trim().equals(""))
-                                       return false;
-
-                               char[] password = {};
-                               if (passwordCallback.getPassword() != null)
-                                       password = passwordCallback.getPassword();
-
-                               NodeAuthenticationToken credentials;
-                               if (remote) {
-                                       String url = urlCallback.getName();
-                                       credentials = new NodeAuthenticationToken(username,
-                                                       password, url);
-                               } else {
-                                       credentials = new NodeAuthenticationToken(username,
-                                                       password);
-                               }
-
-                               BundleContext bc = bundleContextCallback.getBundleContext();
-                               AuthenticationManager authenticationManager = bc.getService(bc
-                                               .getServiceReference(AuthenticationManager.class));
-
-                               Authentication authentication;
-                               try {
-                                       authentication = authenticationManager
-                                                       .authenticate(credentials);
-                               } catch (BadCredentialsException e) {
-                                       // wait between failed login attempts
-                                       Thread.sleep(waitBetweenFailedLoginAttempts);
-                                       throw e;
-                               }
-                               registerAuthentication(authentication);
-                               subject.getPrincipals().add(authentication);
-                       }
-
-                       if (selectedLocale != null)
-                               LocaleUtils.threadLocale.set(selectedLocale);
-
-                       return true;
-               } 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;
-               }
-       }
-
-       @Override
-       public boolean logout() throws LoginException {
-               subject.getPrincipals().clear();
-               return true;
-       }
-
-       @Override
-       public boolean commit() throws LoginException {
-               return true;
-       }
-
-       @Override
-       public boolean abort() throws LoginException {
-               return true;
-       }
-
-       /**
-        * Register an {@link Authentication} in the security context.
-        * 
-        * @param authentication
-        *            has to implement {@link Authentication}.
-        */
-       protected void registerAuthentication(Object authentication) {
-               SecurityContextHolder.getContext().setAuthentication(
-                               (Authentication) authentication);
-       }
-
-       /** Authenticates on a remote node */
-       public void setRemote(Boolean remote) {
-               this.remote = remote;
-       }
-
-       /**
-        * Request anonymous authentication (incompatible with remote)
-        */
-       public void setAnonymous(Boolean anonymous) {
-               this.anonymous = anonymous;
-       }
-
-       /** Role identifying an anonymous user */
-       public void setAnonymousRole(String anonymousRole) {
-               this.anonymousRole = anonymousRole;
-       }
-
-       /** System key */
-       public void setKey(String key) {
-               this.key = key;
-       }
-
-       public void setAvailableLocales(String locales) {
-               this.availableLocales = locales;
-       }
-
-}
diff --git a/org.argeo.security.core/src/org/argeo/security/core/UserAdminLoginModule.java b/org.argeo.security.core/src/org/argeo/security/core/UserAdminLoginModule.java
deleted file mode 100644 (file)
index 16bc623..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *         http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.argeo.security.core;
-
-import java.util.Locale;
-import java.util.Map;
-
-import javax.security.auth.Subject;
-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 javax.security.auth.login.LoginException;
-import javax.security.auth.spi.LoginModule;
-
-import org.argeo.jcr.ArgeoNames;
-import org.argeo.util.LocaleCallback;
-import org.argeo.util.LocaleUtils;
-import org.osgi.framework.BundleContext;
-import org.osgi.service.useradmin.Authorization;
-import org.osgi.service.useradmin.User;
-import org.osgi.service.useradmin.UserAdmin;
-import org.springframework.security.authentication.encoding.LdapShaPasswordEncoder;
-
-/** Login module which caches one subject per thread. */
-public class UserAdminLoginModule implements LoginModule {
-       // private final static Log log = LogFactory
-       // .getLog(UserAdminLoginModule.class);
-
-       private CallbackHandler callbackHandler;
-
-       private Subject subject;
-
-       private Long waitBetweenFailedLoginAttempts = 5 * 1000l;
-
-       /** Comma separated list of locales */
-       private String availableLocales = "";
-
-       private AuthorizationPrincipal auth = null;
-       private Locale selectedLocale = null;
-
-       private LdapShaPasswordEncoder shaPasswordEncoder = new LdapShaPasswordEncoder();
-
-       public UserAdminLoginModule() {
-
-       }
-
-       @SuppressWarnings("rawtypes")
-       public void initialize(Subject subject, CallbackHandler callbackHandler,
-                       Map sharedState, Map options) {
-               this.callbackHandler = callbackHandler;
-               this.subject = subject;
-       }
-
-       public boolean login() throws LoginException {
-               try {
-                       // TODO thread already logged in
-                       // AuthorizationPrincipal principal = subject
-                       // .getPrincipals(AuthorizationPrincipal.class).iterator();
-
-                       if (callbackHandler == null)
-                               throw new LoginException("No call back handler available");
-
-                       // ask for username and password
-                       NameCallback nameCallback = new NameCallback("User");
-                       PasswordCallback passwordCallback = new PasswordCallback(
-                                       "Password", false);
-                       LocaleCallback localeCallback = new LocaleCallback(availableLocales);
-                       BundleContextCallback bundleContextCallback = new BundleContextCallback();
-
-                       callbackHandler.handle(new Callback[] { nameCallback,
-                                       passwordCallback, localeCallback, bundleContextCallback });
-
-                       selectedLocale = localeCallback.getSelectedLocale();
-
-                       // create credentials
-                       final String username = nameCallback.getName();
-                       if (username == null || username.trim().equals(""))
-                               return false;
-
-                       char[] password = {};
-                       if (passwordCallback.getPassword() != null)
-                               password = passwordCallback.getPassword();
-
-                       BundleContext bc = bundleContextCallback.getBundleContext();
-                       UserAdmin userAdmin = bc.getService(bc
-                                       .getServiceReference(UserAdmin.class));
-
-                       User user = (User) userAdmin.getRole(username);
-                       // TODO use hash
-                       boolean authenticated = user.hasCredential(
-                                       ArgeoNames.ARGEO_PASSWORD, new String(password));
-
-                       if (!authenticated) {
-                               // wait between failed login attempts
-                               Thread.sleep(waitBetweenFailedLoginAttempts);
-                               return false;
-                       }
-
-                       Authorization authorization = userAdmin.getAuthorization(user);
-                       auth = new AuthorizationPrincipal(authorization);
-                       return true;
-               } 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;
-               }
-       }
-
-       @Override
-       public boolean logout() throws LoginException {
-               subject.getPrincipals(AuthorizationPrincipal.class).remove(auth);
-               return true;
-       }
-
-       @Override
-       public boolean commit() throws LoginException {
-               subject.getPrincipals().add(auth);
-               if (selectedLocale != null)
-                       LocaleUtils.threadLocale.set(selectedLocale);
-               return true;
-       }
-
-       @Override
-       public boolean abort() throws LoginException {
-               auth = null;
-               selectedLocale = null;
-               return true;
-       }
-
-       public void setAvailableLocales(String locales) {
-               this.availableLocales = locales;
-       }
-}
\ No newline at end of file
diff --git a/org.argeo.security.core/src/org/argeo/security/login/AbstractSpringSecurityLoginModule.java b/org.argeo.security.core/src/org/argeo/security/login/AbstractSpringSecurityLoginModule.java
new file mode 100644 (file)
index 0000000..923646f
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *         http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.security.login;
+
+import java.io.IOException;
+import java.util.Map;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.login.LoginException;
+import javax.security.auth.spi.LoginModule;
+
+import org.osgi.framework.BundleContext;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+
+/** Login module which caches one subject per thread. */
+abstract class AbstractSpringSecurityLoginModule implements LoginModule {
+       private CallbackHandler callbackHandler;
+       private Subject subject;
+
+       protected abstract Authentication processLogin(
+                       CallbackHandler callbackHandler) throws LoginException,
+                       UnsupportedCallbackException, IOException, InterruptedException;
+
+       @SuppressWarnings("rawtypes")
+       @Override
+       public void initialize(Subject subject, CallbackHandler callbackHandler,
+                       Map sharedState, Map options) {
+               this.callbackHandler = callbackHandler;
+               this.subject = subject;
+       }
+
+       @Override
+       public boolean login() throws LoginException {
+               try {
+                       // thread already logged in
+                       Authentication currentAuth = SecurityContextHolder.getContext()
+                                       .getAuthentication();
+                       if (currentAuth != null) {
+                               if (subject.getPrincipals(Authentication.class).size() == 0) {
+                                       subject.getPrincipals().add(currentAuth);
+                               } else {
+                                       Authentication principal = subject
+                                                       .getPrincipals(Authentication.class).iterator()
+                                                       .next();
+                                       if (principal != currentAuth)
+                                               throw new LoginException(
+                                                               "Already authenticated with a different auth");
+                               }
+                               return true;
+                       }
+
+                       // reset all principals and credentials
+                       // if (log.isTraceEnabled())
+                       // log.trace("Resetting all principals and credentials of "
+                       // + subject);
+                       // subject.getPrincipals().clear();
+                       // subject.getPrivateCredentials().clear();
+                       // subject.getPublicCredentials().clear();
+
+                       if (callbackHandler == null)
+                               throw new LoginException("No callback handler available");
+
+                       Authentication authentication = processLogin(callbackHandler);
+                       if (authentication != null) {
+                               SecurityContextHolder.getContext().setAuthentication(
+                                               authentication);
+                               return true;
+                       } else {
+                               throw new LoginException("No authentication returned");
+                       }
+               } 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;
+               }
+       }
+
+       @Override
+       public boolean logout() throws LoginException {
+               // subject.getPrincipals().clear();
+               return true;
+       }
+
+       @Override
+       public boolean commit() throws LoginException {
+               return true;
+       }
+
+       @Override
+       public boolean abort() throws LoginException {
+               return true;
+       }
+
+       protected AuthenticationManager getAuthenticationManager(
+                       BundleContextCallback bundleContextCallback) {
+               BundleContext bc = bundleContextCallback.getBundleContext();
+               return bc.getService(bc
+                               .getServiceReference(AuthenticationManager.class));
+
+       }
+}
diff --git a/org.argeo.security.core/src/org/argeo/security/login/AnonymousLoginModule.java b/org.argeo.security.core/src/org/argeo/security/login/AnonymousLoginModule.java
new file mode 100644 (file)
index 0000000..e94c3e0
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *         http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.security.login;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.login.LoginException;
+
+import org.argeo.security.SecurityUtils;
+import org.argeo.util.LocaleCallback;
+import org.argeo.util.LocaleUtils;
+import org.springframework.security.authentication.AnonymousAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+
+/** Login module which caches one subject per thread. */
+public class AnonymousLoginModule extends AbstractSpringSecurityLoginModule {
+       private String anonymousRole = "ROLE_ANONYMOUS";
+       /** Comma separated list of locales */
+       private String availableLocales = null;
+
+       @Override
+       protected Authentication processLogin(CallbackHandler callbackHandler)
+                       throws LoginException, UnsupportedCallbackException, IOException,
+                       InterruptedException {
+               BundleContextCallback bundleContextCallback = new BundleContextCallback();
+               Locale selectedLocale = null;
+               // multi locale
+               if (availableLocales != null && !availableLocales.trim().equals("")) {
+                       LocaleCallback localeCallback = new LocaleCallback(availableLocales);
+                       callbackHandler.handle(new Callback[] { localeCallback,
+                                       bundleContextCallback });
+                       selectedLocale = localeCallback.getSelectedLocale();
+               } else {
+                       callbackHandler.handle(new Callback[] { bundleContextCallback });
+               }
+
+               List<SimpleGrantedAuthority> authorities = Collections
+                               .singletonList(new SimpleGrantedAuthority(anonymousRole));
+               AnonymousAuthenticationToken anonymousToken = new AnonymousAuthenticationToken(
+                               SecurityUtils.getStaticKey(), null, authorities);
+
+               Authentication auth = getAuthenticationManager(bundleContextCallback)
+                               .authenticate(anonymousToken);
+
+               if (selectedLocale != null)
+                       LocaleUtils.threadLocale.set(selectedLocale);
+               return auth;
+       }
+}
diff --git a/org.argeo.security.core/src/org/argeo/security/login/BundleContextCallback.java b/org.argeo.security.core/src/org/argeo/security/login/BundleContextCallback.java
new file mode 100644 (file)
index 0000000..cf32af5
--- /dev/null
@@ -0,0 +1,19 @@
+package org.argeo.security.login;
+
+import javax.security.auth.callback.Callback;
+
+import org.osgi.framework.BundleContext;
+
+/** Gives access to the OSGi {@link BundleContext} */
+public class BundleContextCallback implements Callback {
+       private BundleContext bundleContext;
+
+       public BundleContext getBundleContext() {
+               return bundleContext;
+       }
+
+       public void setBundleContext(BundleContext bundleContext) {
+               this.bundleContext = bundleContext;
+       }
+
+}
diff --git a/org.argeo.security.core/src/org/argeo/security/login/BundleContextCallbackHandler.java b/org.argeo.security.core/src/org/argeo/security/login/BundleContextCallbackHandler.java
new file mode 100644 (file)
index 0000000..3c7f9e8
--- /dev/null
@@ -0,0 +1,41 @@
+package org.argeo.security.login;
+
+import java.io.IOException;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+import org.osgi.framework.BundleContext;
+
+/**
+ * {@link CallbackHandler} that simply wraps a {@link BundleContext} and inject
+ * it in provided {@link BundleContextCallback}
+ */
+public class BundleContextCallbackHandler implements CallbackHandler {
+       private BundleContext bundleContext;
+
+       public BundleContextCallbackHandler() {
+       }
+
+       public BundleContextCallbackHandler(BundleContext bundleContext) {
+               super();
+               this.bundleContext = bundleContext;
+       }
+
+       @Override
+       public void handle(Callback[] callbacks) throws IOException,
+                       UnsupportedCallbackException {
+               for (Callback callback : callbacks) {
+                       if (callback instanceof BundleContextCallback)
+                               ((BundleContextCallback) callback)
+                                               .setBundleContext(bundleContext);
+               }
+
+       }
+
+       public void setBundleContext(BundleContext bundleContext) {
+               this.bundleContext = bundleContext;
+       }
+
+}
diff --git a/org.argeo.security.core/src/org/argeo/security/login/EndUserLoginModule.java b/org.argeo.security.core/src/org/argeo/security/login/EndUserLoginModule.java
new file mode 100644 (file)
index 0000000..d896439
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *         http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.security.login;
+
+import java.io.IOException;
+import java.util.Locale;
+
+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 javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.login.LoginException;
+
+import org.argeo.security.NodeAuthenticationToken;
+import org.argeo.util.LocaleCallback;
+import org.argeo.util.LocaleUtils;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.core.Authentication;
+
+/** Authenticates an end user */
+public class EndUserLoginModule extends AbstractSpringSecurityLoginModule {
+       final static String NODE_REPO_URI = "argeo.node.repo.uri";
+
+       private Long waitBetweenFailedLoginAttempts = 5 * 1000l;
+
+       private Boolean remote = false;
+       /** Comma separated list of locales */
+       private String availableLocales = "";
+
+       @Override
+       protected Authentication processLogin(CallbackHandler callbackHandler)
+                       throws LoginException, UnsupportedCallbackException, IOException,
+                       InterruptedException {
+               // ask for username and password
+               NameCallback nameCallback = new NameCallback("User");
+               PasswordCallback passwordCallback = new PasswordCallback("Password",
+                               false);
+               final String defaultNodeUrl = System.getProperty(NODE_REPO_URI,
+                               "http://localhost:7070/org.argeo.jcr.webapp/remoting/node");
+               NameCallback urlCallback = new NameCallback("Site URL", defaultNodeUrl);
+               LocaleCallback localeCallback = new LocaleCallback(availableLocales);
+               BundleContextCallback bundleContextCallback = new BundleContextCallback();
+
+               // handle callbacks
+               if (remote)
+                       callbackHandler.handle(new Callback[] { nameCallback,
+                                       passwordCallback, urlCallback, localeCallback,
+                                       bundleContextCallback });
+               else
+                       callbackHandler.handle(new Callback[] { nameCallback,
+                                       passwordCallback, localeCallback, bundleContextCallback });
+
+               Locale selectedLocale = localeCallback.getSelectedLocale();
+
+               // create credentials
+               final String username = nameCallback.getName();
+               if (username == null || username.trim().equals(""))
+                       throw new LoginCanceledException();
+
+               char[] password = {};
+               if (passwordCallback.getPassword() != null)
+                       password = passwordCallback.getPassword();
+
+               NodeAuthenticationToken credentials;
+               if (remote) {
+                       String url = urlCallback.getName();
+                       credentials = new NodeAuthenticationToken(username, password, url);
+               } else {
+                       credentials = new NodeAuthenticationToken(username, password);
+               }
+
+               Authentication auth;
+               try {
+                       auth = getAuthenticationManager(bundleContextCallback)
+                                       .authenticate(credentials);
+               } catch (BadCredentialsException e) {
+                       // wait between failed login attempts
+                       Thread.sleep(waitBetweenFailedLoginAttempts);
+                       throw e;
+               }
+               if (selectedLocale != null)
+                       LocaleUtils.threadLocale.set(selectedLocale);
+
+               return auth;
+       }
+}
diff --git a/org.argeo.security.core/src/org/argeo/security/login/LoginCanceledException.java b/org.argeo.security.core/src/org/argeo/security/login/LoginCanceledException.java
new file mode 100644 (file)
index 0000000..5629e2e
--- /dev/null
@@ -0,0 +1,8 @@
+package org.argeo.security.login;
+
+import javax.security.auth.login.LoginException;
+
+public class LoginCanceledException extends LoginException {
+       private static final long serialVersionUID = 8289162094013471043L;
+
+}
diff --git a/org.argeo.security.core/src/org/argeo/security/login/SystemLoginModule.java b/org.argeo.security.core/src/org/argeo/security/login/SystemLoginModule.java
new file mode 100644 (file)
index 0000000..b1b1d34
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *         http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.security.login;
+
+import java.io.IOException;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.login.LoginException;
+
+import org.argeo.security.SecurityUtils;
+import org.argeo.security.core.InternalAuthentication;
+import org.springframework.security.core.Authentication;
+
+/** Login module which caches one subject per thread. */
+public class SystemLoginModule extends AbstractSpringSecurityLoginModule {
+       @Override
+       protected Authentication processLogin(CallbackHandler callbackHandler)
+                       throws LoginException, UnsupportedCallbackException, IOException,
+                       InterruptedException {
+               BundleContextCallback bundleContextCallback = new BundleContextCallback();
+               callbackHandler.handle(new Callback[] { bundleContextCallback });
+               InternalAuthentication anonymousToken = new InternalAuthentication(
+                               SecurityUtils.getStaticKey());
+               return getAuthenticationManager(bundleContextCallback).authenticate(
+                               anonymousToken);
+       }
+}
diff --git a/org.argeo.security.core/src/org/argeo/security/login/UserAdminLoginModule.java b/org.argeo.security.core/src/org/argeo/security/login/UserAdminLoginModule.java
new file mode 100644 (file)
index 0000000..530c060
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *         http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.security.login;
+
+import java.util.Locale;
+import java.util.Map;
+
+import javax.security.auth.Subject;
+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 javax.security.auth.login.LoginException;
+import javax.security.auth.spi.LoginModule;
+
+import org.argeo.jcr.ArgeoNames;
+import org.argeo.security.core.AuthorizationPrincipal;
+import org.argeo.util.LocaleCallback;
+import org.argeo.util.LocaleUtils;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.useradmin.Authorization;
+import org.osgi.service.useradmin.User;
+import org.osgi.service.useradmin.UserAdmin;
+import org.springframework.security.authentication.encoding.LdapShaPasswordEncoder;
+
+/** Login module which caches one subject per thread. */
+public class UserAdminLoginModule implements LoginModule {
+       // private final static Log log = LogFactory
+       // .getLog(UserAdminLoginModule.class);
+
+       private CallbackHandler callbackHandler;
+
+       private Subject subject;
+
+       private Long waitBetweenFailedLoginAttempts = 5 * 1000l;
+
+       /** Comma separated list of locales */
+       private String availableLocales = "";
+
+       private AuthorizationPrincipal auth = null;
+       private Locale selectedLocale = null;
+
+       @SuppressWarnings("unused")
+       private LdapShaPasswordEncoder shaPasswordEncoder = new LdapShaPasswordEncoder();
+
+       public UserAdminLoginModule() {
+
+       }
+
+       @SuppressWarnings("rawtypes")
+       public void initialize(Subject subject, CallbackHandler callbackHandler,
+                       Map sharedState, Map options) {
+               this.callbackHandler = callbackHandler;
+               this.subject = subject;
+       }
+
+       public boolean login() throws LoginException {
+               try {
+                       // TODO thread already logged in
+                       // AuthorizationPrincipal principal = subject
+                       // .getPrincipals(AuthorizationPrincipal.class).iterator();
+
+                       if (callbackHandler == null)
+                               throw new LoginException("No call back handler available");
+
+                       // ask for username and password
+                       NameCallback nameCallback = new NameCallback("User");
+                       PasswordCallback passwordCallback = new PasswordCallback(
+                                       "Password", false);
+                       LocaleCallback localeCallback = new LocaleCallback(availableLocales);
+                       BundleContextCallback bundleContextCallback = new BundleContextCallback();
+
+                       callbackHandler.handle(new Callback[] { nameCallback,
+                                       passwordCallback, localeCallback, bundleContextCallback });
+
+                       selectedLocale = localeCallback.getSelectedLocale();
+
+                       // create credentials
+                       final String username = nameCallback.getName();
+                       if (username == null || username.trim().equals(""))
+                               return false;
+
+                       char[] password = {};
+                       if (passwordCallback.getPassword() != null)
+                               password = passwordCallback.getPassword();
+
+                       BundleContext bc = bundleContextCallback.getBundleContext();
+                       UserAdmin userAdmin = bc.getService(bc
+                                       .getServiceReference(UserAdmin.class));
+
+                       User user = (User) userAdmin.getRole(username);
+                       // TODO use hash
+                       boolean authenticated = user.hasCredential(
+                                       ArgeoNames.ARGEO_PASSWORD, new String(password));
+
+                       if (!authenticated) {
+                               // wait between failed login attempts
+                               Thread.sleep(waitBetweenFailedLoginAttempts);
+                               return false;
+                       }
+
+                       Authorization authorization = userAdmin.getAuthorization(user);
+                       auth = new AuthorizationPrincipal(authorization);
+                       return true;
+               } 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;
+               }
+       }
+
+       @Override
+       public boolean logout() throws LoginException {
+               subject.getPrincipals(AuthorizationPrincipal.class).remove(auth);
+               return true;
+       }
+
+       @Override
+       public boolean commit() throws LoginException {
+               subject.getPrincipals().add(auth);
+               if (selectedLocale != null)
+                       LocaleUtils.threadLocale.set(selectedLocale);
+               return true;
+       }
+
+       @Override
+       public boolean abort() throws LoginException {
+               auth = null;
+               selectedLocale = null;
+               return true;
+       }
+
+       public void setAvailableLocales(String locales) {
+               this.availableLocales = locales;
+       }
+}
\ No newline at end of file
diff --git a/org.argeo.security.ui.rap/META-INF/jaas_default.txt b/org.argeo.security.ui.rap/META-INF/jaas_default.txt
deleted file mode 100644 (file)
index c74797b..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-UNIX {
-    org.eclipse.equinox.security.auth.module.ExtensionLoginModule sufficient
-        extensionId="org.argeo.security.equinox.unixLoginModule";
-};
-
-SPRING {
-    org.eclipse.equinox.security.auth.module.ExtensionLoginModule sufficient
-        extensionId="org.argeo.security.equinox.springLoginModule";
-};
-
-SPRING_ANONYMOUS {
-    org.eclipse.equinox.security.auth.module.ExtensionLoginModule sufficient
-        extensionId="org.argeo.security.equinox.anonymousSpringLoginModule";
-};
-
-SPRING_SECURITY_CONTEXT {
-    org.eclipse.equinox.security.auth.module.ExtensionLoginModule sufficient
-        extensionId="org.argeo.security.equinox.springSecurityContextLoginModule";
-};
-
-KEYRING {
-    org.argeo.security.crypto.KeyringLoginModule required;
-};
index 56feea8ccbba55ad91a716d3a9b89bc134532836..bbccd8db5ca4838bb32a46fa4cff97f9a4004ab0 100644 (file)
@@ -8,4 +8,5 @@ org.springframework.security.authentication.jaas,\
 org.springframework.core,\
 org.argeo.eclipse.spring,\
 org.argeo.eclipse.ui.specific,\
+org.argeo.cms,\
 *
index 37492bb561a5bea718c23ac1d12b0a77f922d438..6fbf0026a21054b60f0a8ec0af5c643c5f7e9182 100644 (file)
                        <artifactId>org.argeo.eclipse.ui.rap</artifactId>
                        <version>2.1.17-SNAPSHOT</version>
                </dependency>
+               <dependency>
+                       <groupId>org.argeo.commons</groupId>
+                       <artifactId>org.argeo.cms</artifactId>
+                       <version>2.1.17-SNAPSHOT</version>
+               </dependency>
        </dependencies>
 </project>
\ No newline at end of file
index 4977815ae86dc81011f1b7da8700235a43b30a36..ac0007acfa9af3bac041d356c40fefd07d01b901 100644 (file)
  */
 package org.argeo.security.ui.rap;
 
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
 import org.eclipse.rap.rwt.RWT;
-import org.eclipse.rap.rwt.application.IEntryPoint;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.ui.PlatformUI;
+import org.eclipse.rap.rwt.application.EntryPoint;
 
 /**
  * RAP entry point which authenticates the subject as anonymous, for public
  * unauthenticated access.
  */
-public class AnonymousEntryPoint implements IEntryPoint {
-       private final static Log log = LogFactory.getLog(AnonymousEntryPoint.class);
+public class AnonymousEntryPoint implements EntryPoint {
+       // private final static Log log =
+       // LogFactory.getLog(AnonymousEntryPoint.class);
 
        /**
         * How many seconds to wait before invalidating the session if the user has
         * not yet logged in.
         */
        private Integer loginTimeout = 1 * 60;
-       private Integer sessionTimeout = 15 * 60;
 
        @Override
        public int createUI() {
@@ -42,70 +38,70 @@ public class AnonymousEntryPoint implements IEntryPoint {
                // around too long
                RWT.getRequest().getSession().setMaxInactiveInterval(loginTimeout);
 
-               if (log.isDebugEnabled())
-                       log.debug("Anonymous THREAD=" + Thread.currentThread().getId()
-                                       + ", sessionStore=" + RWT.getSessionStore().getId());
+               // if (log.isDebugEnabled())
+               // log.debug("Anonymous THREAD=" + Thread.currentThread().getId()
+               // + ", sessionStore=" + RWT.getSessionStore().getId());
 
                // create display
-               final Display display = PlatformUI.createDisplay();
+               // final Display display = PlatformUI.createDisplay();
 
                // log in
-//             final ILoginContext loginContext = SecureRapActivator
-//                             .createLoginContext(SecureRapActivator.CONTEXT_SPRING_ANONYMOUS);
-//             Subject subject = null;
-//             try {
-//                     loginContext.login();
-//                     subject = loginContext.getSubject();
-//             } catch (LoginException e) {
-//                     throw new ArgeoException(
-//                                     "Unexpected exception during authentication", e);
-//             }
-//
-//             // identify after successful login
-//             if (log.isDebugEnabled())
-//                     log.debug("Authenticated " + subject);
-//             final String username = subject.getPrincipals().iterator().next()
-//                             .getName();
-//
-//             // Once the user is logged in, she can have a longer session timeout
-//             RWT.getRequest().getSession().setMaxInactiveInterval(sessionTimeout);
-//
-//             // Logout callback when the display is disposed
-//             display.disposeExec(new Runnable() {
-//                     public void run() {
-//                             log.debug("Display disposed");
-//                             logout(loginContext, username);
-//                     }
-//             });
-//
-//             //
-//             // RUN THE WORKBENCH
-//             //
-//             Integer returnCode = null;
-//             try {
-//                     returnCode = Subject.doAs(subject, new PrivilegedAction<Integer>() {
-//                             public Integer run() {
-//                                     RapWorkbenchAdvisor workbenchAdvisor = new RapWorkbenchAdvisor(
-//                                                     null);
-//                                     int result = PlatformUI.createAndRunWorkbench(display,
-//                                                     workbenchAdvisor);
-//                                     return new Integer(result);
-//                             }
-//                     });
-//                     logout(loginContext, username);
-//             } finally {
-//                     display.dispose();
-//             }
+               // final ILoginContext loginContext = SecureRapActivator
+               // .createLoginContext(SecureRapActivator.CONTEXT_SPRING_ANONYMOUS);
+               // Subject subject = null;
+               // try {
+               // loginContext.login();
+               // subject = loginContext.getSubject();
+               // } catch (LoginException e) {
+               // throw new ArgeoException(
+               // "Unexpected exception during authentication", e);
+               // }
+               //
+               // // identify after successful login
+               // if (log.isDebugEnabled())
+               // log.debug("Authenticated " + subject);
+               // final String username = subject.getPrincipals().iterator().next()
+               // .getName();
+               //
+               // // Once the user is logged in, she can have a longer session timeout
+               // RWT.getRequest().getSession().setMaxInactiveInterval(sessionTimeout);
+               //
+               // // Logout callback when the display is disposed
+               // display.disposeExec(new Runnable() {
+               // public void run() {
+               // log.debug("Display disposed");
+               // logout(loginContext, username);
+               // }
+               // });
+               //
+               // //
+               // // RUN THE WORKBENCH
+               // //
+               // Integer returnCode = null;
+               // try {
+               // returnCode = Subject.doAs(subject, new PrivilegedAction<Integer>() {
+               // public Integer run() {
+               // RapWorkbenchAdvisor workbenchAdvisor = new RapWorkbenchAdvisor(
+               // null);
+               // int result = PlatformUI.createAndRunWorkbench(display,
+               // workbenchAdvisor);
+               // return new Integer(result);
+               // }
+               // });
+               // logout(loginContext, username);
+               // } finally {
+               // display.dispose();
+               // }
                return 1;
        }
 
-//     private void logout(ILoginContext secureContext, String username) {
-//             try {
-//                     secureContext.logout();
-//                     log.info("Logged out " + (username != null ? username : "")
-//                                     + " (THREAD=" + Thread.currentThread().getId() + ")");
-//             } catch (LoginException e) {
-//                     log.error("Erorr when logging out", e);
-//             }
-//     }
+       // private void logout(ILoginContext secureContext, String username) {
+       // try {
+       // secureContext.logout();
+       // log.info("Logged out " + (username != null ? username : "")
+       // + " (THREAD=" + Thread.currentThread().getId() + ")");
+       // } catch (LoginException e) {
+       // log.error("Erorr when logging out", e);
+       // }
+       // }
 }
index 811cc28218b9aa658f69ecb99b4662854c65ecfb..002bd647f602a3d8fecb1c5d0e76c65c84f93540 100644 (file)
  */
 package org.argeo.security.ui.rap;
 
-import org.eclipse.rap.rwt.application.IEntryPoint;
+import org.eclipse.rap.rwt.application.EntryPoint;
 import org.eclipse.ui.PlatformUI;
 
 /**
  * RAP entry point which does doesing except creating the display
  */
-public class NullEntryPoint implements IEntryPoint {
+public class NullEntryPoint implements EntryPoint {
        @Override
        public int createUI() {
                // create display
index eb1dd80ee4e9c50ad9e9d6895631fb7ed493ff28..05f4787f01319e2092f97cf317965b72dea98724 100644 (file)
@@ -63,6 +63,8 @@ public class RapWindowAdvisor extends WorkbenchWindowAdvisor {
                // Handle window resize in Rap 2.1+ see
                // https://bugs.eclipse.org/bugs/show_bug.cgi?id=417254
                Display.getCurrent().addListener(SWT.Resize, new Listener() {
+                       private static final long serialVersionUID = 2970912561866704526L;
+
                        @Override
                        public void handleEvent(Event event) {
                                Rectangle bounds = event.display.getBounds();
index d78cdd15dd945179a974f47ea61f8d44c4c24d86..65657dc66204a4642d890e04dd6939aa3dd75a64 100644 (file)
@@ -26,7 +26,9 @@ import javax.servlet.http.HttpSession;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.argeo.ArgeoException;
+import org.argeo.cms.KernelHeader;
 import org.argeo.eclipse.ui.workbench.ErrorFeedback;
+import org.argeo.security.login.LoginCanceledException;
 import org.argeo.security.ui.dialogs.DefaultLoginDialog;
 import org.argeo.util.LocaleUtils;
 import org.eclipse.jface.dialogs.MessageDialog;
@@ -92,21 +94,16 @@ public class SecureEntryPoint implements EntryPoint {
                Subject subject = new Subject();
 
                // log in
-               // BundleContext bc =
-               // SecureRapActivator.getActivator().getBundleContext();
                Thread.currentThread().setContextClassLoader(
                                getClass().getClassLoader());
                final LoginContext loginContext;
                try {
-                       loginContext = new LoginContext(SPRING_SECURITY_CONTEXT_KEY,
+                       loginContext = new LoginContext(KernelHeader.LOGIN_CONTEXT_USER,
                                        subject, new DefaultLoginDialog(display.getActiveShell()));
                } catch (LoginException e1) {
                        throw new ArgeoException("Cannot initialize login context", e1);
                }
-               // final LoginModule loginModule = bc.getService(bc
-               // .getServiceReference(LoginModule.class));
-               // loginModule.initialize(subject,
-               // new DefaultLoginDialog(display.getActiveShell()), null, null);
+
                tryLogin: while (subject.getPrincipals(Authentication.class).size() == 0) {
                        try {
                                loginContext.login();
@@ -204,6 +201,9 @@ public class SecureEntryPoint implements EntryPoint {
                if (t instanceof BadCredentialsException)
                        return (BadCredentialsException) t;
 
+               if (t instanceof LoginCanceledException)
+                       return new BadCredentialsException("Login canceled");
+
                if (t.getCause() != null)
                        return wasCausedByBadCredentials(t.getCause());
                else
index 7cb799026741447c2ade9a46bbe93d10449db831..1364eeb915fef9d00c991693974690ac4b5dec4d 100644 (file)
@@ -20,11 +20,7 @@ import org.osgi.framework.BundleContext;
 
 /** Configure Equinox login context from the bundle context. */
 public class SecureRapActivator implements BundleActivator {
-
        public final static String ID = "org.argeo.security.ui.rap";
-       public final static String CONTEXT_SPRING = "SPRING";
-       public final static String CONTEXT_SPRING_ANONYMOUS = "SPRING_ANONYMOUS";
-       private static final String JAAS_CONFIG_FILE = "/META-INF/jaas_default.txt";
 
        private BundleContext bundleContext;
        private static SecureRapActivator activator = null;
@@ -46,10 +42,4 @@ public class SecureRapActivator implements BundleActivator {
        public static SecureRapActivator getActivator() {
                return activator;
        }
-
-//     static ILoginContext createLoginContext(String contextName) {
-//             URL configUrl = getActivator().getBundleContext().getBundle()
-//                             .getEntry(JAAS_CONFIG_FILE);
-//             return LoginContextFactory.createContext(contextName, configUrl);
-//     }
 }