+package org.argeo.security.equinox;
+
+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.callback.TextOutputCallback;
+import javax.security.auth.login.LoginException;
+
+import org.springframework.security.Authentication;
+import org.springframework.security.AuthenticationManager;
+import org.springframework.security.BadCredentialsException;
+import org.springframework.security.context.SecurityContextHolder;
+import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
+import org.springframework.security.providers.jaas.SecurityContextLoginModule;
+
+/** Login module which caches one subject per thread. */
+public class SpringLoginModule extends SecurityContextLoginModule {
+ private AuthenticationManager authenticationManager;
+
+ private CallbackHandler callbackHandler;
+
+ public SpringLoginModule() {
+
+ }
+
+ @SuppressWarnings("rawtypes")
+ public void initialize(Subject subject, CallbackHandler callbackHandler,
+ Map sharedState, Map options) {
+ super.initialize(subject, callbackHandler, sharedState, options);
+ // this.subject.set(subject);
+ this.callbackHandler = callbackHandler;
+ }
+
+ public boolean login() throws LoginException {
+ // thread already logged in
+ if (SecurityContextHolder.getContext().getAuthentication() != null)
+ return super.login();
+
+ // if (getSubject().getPrincipals(Authentication.class).size() == 1) {
+ // registerAuthentication(getSubject()
+ // .getPrincipals(Authentication.class).iterator().next());
+ // return super.login();
+ // } else if (getSubject().getPrincipals(Authentication.class).size() >
+ // 1) {
+ // throw new LoginException(
+ // "Multiple Authentication principals not supported: "
+ // + getSubject().getPrincipals(Authentication.class));
+ // } else {
+ // ask for username and password
+ Callback label = new TextOutputCallback(TextOutputCallback.INFORMATION,
+ "Required login");
+ NameCallback nameCallback = new NameCallback("User");
+ PasswordCallback passwordCallback = new PasswordCallback("Password",
+ false);
+
+ if (callbackHandler == null) {
+ throw new LoginException("No call back handler available");
+ // return false;
+ }
+ try {
+ callbackHandler.handle(new Callback[] { label, nameCallback,
+ passwordCallback });
+ } catch (Exception e) {
+ LoginException le = new LoginException("Callback handling failed");
+ le.initCause(e);
+ throw le;
+ }
+
+ // Set user name and password
+ String username = nameCallback.getName();
+ String password = "";
+ if (passwordCallback.getPassword() != null) {
+ password = String.valueOf(passwordCallback.getPassword());
+ }
+ UsernamePasswordAuthenticationToken credentials = new UsernamePasswordAuthenticationToken(
+ username, password);
+
+ try {
+ Authentication authentication = authenticationManager
+ .authenticate(credentials);
+ registerAuthentication(authentication);
+ boolean res = super.login();
+ // if (log.isDebugEnabled())
+ // log.debug("User " + username + " logged in");
+ return res;
+ } catch (BadCredentialsException bce) {
+ throw bce;
+ } catch (Exception e) {
+ LoginException loginException = new LoginException(
+ "Bad credentials");
+ loginException.initCause(e);
+ throw loginException;
+ }
+ // }
+ }
+
+ @Override
+ public boolean logout() throws LoginException {
+ 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;
+ }
+
+ // protected Subject getSubject() {
+ // return subject.get();
+ // }
+
+}