Use standard JAAS login context for RAP login
authorMathieu Baudier <mbaudier@argeo.org>
Sat, 7 Feb 2015 21:41:24 +0000 (21:41 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Sat, 7 Feb 2015 21:41:24 +0000 (21:41 +0000)
git-svn-id: https://svn.argeo.org/commons/trunk@7763 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelConstants.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeSecurity.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/SpringLoginModule.java [deleted file]
org.argeo.cms/src/org/argeo/cms/internal/kernel/jaas.cfg [new file with mode: 0644]
org.argeo.security.core/src/org/argeo/security/core/BundleContextCallback.java [new file with mode: 0644]
org.argeo.security.core/src/org/argeo/security/core/SpringLoginModule.java [new file with mode: 0644]
org.argeo.security.core/src/org/argeo/security/core/ThreadedLoginModule.java [deleted file]
org.argeo.security.ui.rap/bnd.bnd
org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/SecureEntryPoint.java
org.argeo.security.ui/src/org/argeo/security/ui/SecurityUiPlugin.java
org.argeo.security.ui/src/org/argeo/security/ui/dialogs/DefaultLoginDialog.java

index 4d53917b48d26f257e42234769d153e9f849129f..eb60f45963c5b4c8de912c1d7c9f5f90f1b915c6 100644 (file)
@@ -17,6 +17,7 @@ interface KernelConstants {
        final static String DEFAULT_SECURITY_KEY = "argeo";
        final static String ANONYMOUS_USER = "anonymous";
        final static String ADMIN_USER = "root";
+       final static String JAAS_CONFIG = "/org/argeo/cms/internal/kernel/jaas.cfg";
 
        // Roles
        final static String ROLE_USER = "ROLE_USER";
index 6ad8fb15c582f61968813cfae4c0d6c7f0202788..b5d2eb412365b6f01b78313ac681761b7b0b2976 100644 (file)
@@ -1,7 +1,8 @@
 package org.argeo.cms.internal.kernel;
 
+import java.net.URL;
+
 import javax.jcr.RepositoryException;
-import javax.security.auth.spi.LoginModule;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -9,11 +10,8 @@ import org.argeo.cms.CmsException;
 import org.argeo.security.UserAdminService;
 import org.argeo.security.core.InternalAuthentication;
 import org.argeo.security.core.InternalAuthenticationProvider;
-import org.argeo.security.core.ThreadedLoginModule;
 import org.argeo.security.jcr.SimpleJcrSecurityModel;
 import org.argeo.security.jcr.jackrabbit.JackrabbitUserAdminService;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.swt.widgets.Display;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceRegistration;
 import org.springframework.security.authentication.AnonymousAuthenticationProvider;
@@ -33,15 +31,18 @@ class NodeSecurity implements AuthenticationManager {
        private final InternalAuthenticationProvider internalAuth;
        private final AnonymousAuthenticationProvider anonymousAuth;
        private final JackrabbitUserAdminService jackrabbitUserAdmin;
-       private Login loginModule;
 
        private ServiceRegistration<AuthenticationManager> authenticationManagerReg;
        private ServiceRegistration<UserAdminService> userAdminReg;
        private ServiceRegistration<UserDetailsManager> userDetailsManagerReg;
-       private ServiceRegistration<LoginModule> loginModuleReg;
 
        public NodeSecurity(BundleContext bundleContext, JackrabbitNode node)
                        throws RepositoryException {
+               URL url = getClass().getClassLoader().getResource(
+                               KernelConstants.JAAS_CONFIG);
+               System.setProperty("java.security.auth.login.config",
+                               url.toExternalForm());
+
                this.bundleContext = bundleContext;
 
                internalAuth = new InternalAuthenticationProvider(
@@ -54,8 +55,6 @@ class NodeSecurity implements AuthenticationManager {
                jackrabbitUserAdmin.setRepository(node);
                jackrabbitUserAdmin.setSecurityModel(new SimpleJcrSecurityModel());
                jackrabbitUserAdmin.init();
-
-               loginModule = new Login();
        }
 
        public void publish() {
@@ -68,9 +67,6 @@ class NodeSecurity implements AuthenticationManager {
                // userAdminReg =
                // bundleContext.registerService(UserDetailsService.class,
                // jackrabbitUserAdmin, null);
-
-               loginModuleReg = bundleContext.registerService(LoginModule.class,
-                               loginModule, null);
        }
 
        void destroy() {
@@ -82,7 +78,6 @@ class NodeSecurity implements AuthenticationManager {
                userDetailsManagerReg.unregister();
                userAdminReg.unregister();
                authenticationManagerReg.unregister();
-               loginModuleReg.unregister();
        }
 
        @Override
@@ -99,18 +94,4 @@ class NodeSecurity implements AuthenticationManager {
                        throw new CmsException("Could not authenticate " + authentication);
                return auth;
        }
-
-       private class Login extends ThreadedLoginModule {
-
-               @Override
-               protected LoginModule createLoginModule() {
-                       SpringLoginModule springLoginModule = new SpringLoginModule();
-                       springLoginModule.setAuthenticationManager(NodeSecurity.this);
-                       if (Display.getCurrent() != null) {
-
-                       }
-                       return springLoginModule;
-               }
-
-       }
 }
diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/SpringLoginModule.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/SpringLoginModule.java
deleted file mode 100644 (file)
index f3e0b60..0000000
+++ /dev/null
@@ -1,255 +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.cms.internal.kernel;
-
-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 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.springframework.security.authentication.AnonymousAuthenticationToken;
-import org.springframework.security.authentication.AuthenticationManager;
-import org.springframework.security.authentication.BadCredentialsException;
-import org.springframework.security.authentication.jaas.SecurityContextLoginModule;
-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. */
-class SpringLoginModule extends SecurityContextLoginModule {
-       final static String NODE_REPO_URI = "argeo.node.repo.uri";
-
-       private final static Log log = LogFactory.getLog(SpringLoginModule.class);
-
-       private AuthenticationManager authenticationManager;
-
-       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) {
-               super.initialize(subject, callbackHandler, sharedState, 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 super.login();
-                       }
-
-                       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) {
-                               // 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);
-
-                               // handle callbacks
-                               if (remote)
-                                       callbackHandler.handle(new Callback[] { nameCallback,
-                                                       passwordCallback, urlCallback, localeCallback });
-                               else
-                                       callbackHandler.handle(new Callback[] { nameCallback,
-                                                       passwordCallback, localeCallback });
-
-                               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);
-                               }
-
-                               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 super.login();
-               } 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 super.logout();
-       }
-
-       /**
-        * 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);
-       }
-
-       public void setAuthenticationManager(
-                       AuthenticationManager authenticationManager) {
-               this.authenticationManager = authenticationManager;
-       }
-
-       /** 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.cms/src/org/argeo/cms/internal/kernel/jaas.cfg b/org.argeo.cms/src/org/argeo/cms/internal/kernel/jaas.cfg
new file mode 100644 (file)
index 0000000..110d0e1
--- /dev/null
@@ -0,0 +1,8 @@
+SPRING_SECURITY_CONTEXT {
+    org.argeo.security.core.SpringLoginModule required;
+    org.springframework.security.authentication.jaas.SecurityContextLoginModule required;
+};
+
+KEYRING {
+    org.argeo.security.crypto.KeyringLoginModule required;
+};
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
new file mode 100644 (file)
index 0000000..51831fd
--- /dev/null
@@ -0,0 +1,19 @@
+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
new file mode 100644 (file)
index 0000000..75051d2
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+ * 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 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.authentication.jaas.SecurityContextLoginModule;
+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 extends SecurityContextLoginModule {
+       final static String NODE_REPO_URI = "argeo.node.repo.uri";
+
+       private final static Log log = LogFactory.getLog(SpringLoginModule.class);
+
+       // private AuthenticationManager authenticationManager;
+
+       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) {
+               super.initialize(subject, callbackHandler, sharedState, 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 super.login();
+                       }
+
+                       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 super.login();
+               } 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 super.logout();
+       }
+
+       @Override
+       public boolean commit() throws LoginException {
+               return super.commit();
+       }
+
+       @Override
+       public boolean abort() throws LoginException {
+               return super.abort();
+       }
+
+       /**
+        * 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);
+       }
+
+       // public void setAuthenticationManager(
+       // AuthenticationManager authenticationManager) {
+       // this.authenticationManager = authenticationManager;
+       // }
+
+       /** 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/ThreadedLoginModule.java b/org.argeo.security.core/src/org/argeo/security/core/ThreadedLoginModule.java
deleted file mode 100644 (file)
index 8ddac89..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-package org.argeo.security.core;
-
-import java.util.Map;
-
-import javax.security.auth.Subject;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.login.LoginException;
-import javax.security.auth.spi.LoginModule;
-
-/** Attach login modules to threads. */
-public abstract class ThreadedLoginModule implements LoginModule {
-       private ThreadLocal<LoginModule> loginModule = new ThreadLocal<LoginModule>() {
-
-               @Override
-               protected LoginModule initialValue() {
-                       return createLoginModule();
-               }
-
-       };
-
-       protected abstract LoginModule createLoginModule();
-
-       @Override
-       public void initialize(Subject subject, CallbackHandler callbackHandler,
-                       Map<String, ?> sharedState, Map<String, ?> options) {
-               loginModule.get().initialize(subject, callbackHandler, sharedState,
-                               options);
-       }
-
-       @Override
-       public boolean login() throws LoginException {
-               return loginModule.get().login();
-       }
-
-       @Override
-       public boolean commit() throws LoginException {
-               return loginModule.get().commit();
-       }
-
-       @Override
-       public boolean abort() throws LoginException {
-               return loginModule.get().abort();
-       }
-
-       @Override
-       public boolean logout() throws LoginException {
-               return loginModule.get().logout();
-       }
-
-}
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..4dfbbceee8d74e271c015b7fc239403c94d21dc1 100644 (file)
@@ -0,0 +1,3 @@
+Import-Package: org.argeo.security.core,\
+org.springframework.security.authentication.jaas,\
+*
\ No newline at end of file
index 15915218615a01b360535f78ad89a53c802e0bad..d78cdd15dd945179a974f47ea61f8d44c4c24d86 100644 (file)
@@ -18,8 +18,8 @@ package org.argeo.security.ui.rap;
 import java.security.PrivilegedAction;
 
 import javax.security.auth.Subject;
+import javax.security.auth.login.LoginContext;
 import javax.security.auth.login.LoginException;
-import javax.security.auth.spi.LoginModule;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpSession;
 
@@ -34,7 +34,6 @@ import org.eclipse.rap.rwt.RWT;
 import org.eclipse.rap.rwt.application.EntryPoint;
 import org.eclipse.swt.widgets.Display;
 import org.eclipse.ui.PlatformUI;
-import org.osgi.framework.BundleContext;
 import org.springframework.security.authentication.BadCredentialsException;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.context.SecurityContext;
@@ -93,16 +92,27 @@ public class SecureEntryPoint implements EntryPoint {
                Subject subject = new Subject();
 
                // log in
-               BundleContext bc = SecureRapActivator.getActivator().getBundleContext();
-               final LoginModule loginModule = bc.getService(bc
-                               .getServiceReference(LoginModule.class));
-               loginModule.initialize(subject,
-                               new DefaultLoginDialog(display.getActiveShell()), null, null);
+               // BundleContext bc =
+               // SecureRapActivator.getActivator().getBundleContext();
+               Thread.currentThread().setContextClassLoader(
+                               getClass().getClassLoader());
+               final LoginContext loginContext;
+               try {
+                       loginContext = new LoginContext(SPRING_SECURITY_CONTEXT_KEY,
+                                       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 {
-                               if (!loginModule.login()) {
-                                       throw new ArgeoException("Login failed");
-                               }
+                               loginContext.login();
+                               // if () {
+                               // throw new ArgeoException("Login failed");
+                               // }
 
                                if (subject.getPrincipals(Authentication.class).size() == 0)
                                        throw new ArgeoException("Login succeeded but no auth");// fatal
@@ -141,7 +151,7 @@ public class SecureEntryPoint implements EntryPoint {
                                log.debug("Display disposed");
                                // logout(loginContext, username);
                                try {
-                                       loginModule.logout();
+                                       loginContext.logout();
                                } catch (LoginException e) {
                                        log.error("Error when logging out", e);
                                }
@@ -162,7 +172,7 @@ public class SecureEntryPoint implements EntryPoint {
                                }
                        });
                        // Explicit exit from workbench
-                       logout(loginModule, username);
+                       logout(loginContext, username);
                } finally {
                        display.dispose();
                }
@@ -214,9 +224,9 @@ public class SecureEntryPoint implements EntryPoint {
                        return null;
        }
 
-       private void logout(LoginModule loginModule, String username) {
+       private void logout(LoginContext loginContext, String username) {
                try {
-                       loginModule.logout();
+                       loginContext.logout();
                        SecurityContextHolder.clearContext();
 
                        HttpServletRequest httpRequest = RWT.getRequest();
index 03584185bf06ad73193068ec1b2d717543262459..a19fec17d02cb9ad107e23eaba5768d7f3ccf11e 100644 (file)
@@ -43,6 +43,7 @@ public class SecurityUiPlugin extends AbstractUIPlugin {
        private ServiceRegistration defaultCallbackHandlerReg;
 
        private static SecurityUiPlugin plugin;
+       private static BundleContext bundleContext;
 
        public static InheritableThreadLocal<Display> display = new InheritableThreadLocal<Display>() {
 
@@ -55,6 +56,7 @@ public class SecurityUiPlugin extends AbstractUIPlugin {
        public void start(BundleContext context) throws Exception {
                super.start(context);
                plugin = this;
+               bundleContext = context;
 
                defaultCallbackHandler = new DefaultCallbackHandler();
                defaultCallbackHandlerReg = context.registerService(
@@ -63,6 +65,7 @@ public class SecurityUiPlugin extends AbstractUIPlugin {
 
        public void stop(BundleContext context) throws Exception {
                plugin = null;
+               bundleContext = null;
                defaultCallbackHandlerReg.unregister();
                super.stop(context);
        }
@@ -76,6 +79,10 @@ public class SecurityUiPlugin extends AbstractUIPlugin {
                return plugin;
        }
 
+       public static BundleContext getBundleContext() {
+               return bundleContext;
+       }
+
        public static ImageDescriptor getImageDescriptor(String path) {
                return imageDescriptorFromPlugin(PLUGIN_ID, path);
        }
index 57ba01b5bab8863799a9a1c656ff40f919b3f465..c2c5c079d7b774dc836df50b2403be3192515769 100644 (file)
@@ -21,6 +21,7 @@ import javax.security.auth.callback.NameCallback;
 import javax.security.auth.callback.PasswordCallback;
 import javax.security.auth.callback.TextOutputCallback;
 
+import org.argeo.security.core.BundleContextCallback;
 import org.argeo.security.ui.SecurityUiPlugin;
 import org.argeo.util.LocaleCallback;
 import org.eclipse.swt.SWT;
@@ -95,6 +96,9 @@ public class DefaultLoginDialog extends AbstractLoginDialog {
                                createPasswordHandler(composite, (PasswordCallback) callback);
                        } else if (callback instanceof LocaleCallback) {
                                createLocaleHandler(composite, (LocaleCallback) callback);
+                       } else if (callback instanceof BundleContextCallback) {
+                               ((BundleContextCallback) callback)
+                                               .setBundleContext(SecurityUiPlugin.getBundleContext());
                        }
                }
        }