]> git.argeo.org Git - lgpl/argeo-commons.git/blob - SpringLoginModule.java
71ce5715bc937f5d6a4d310d913aa24af8c3da71
[lgpl/argeo-commons.git] / SpringLoginModule.java
1 package org.argeo.security.equinox;
2
3 import java.util.Map;
4
5 import javax.security.auth.Subject;
6 import javax.security.auth.callback.Callback;
7 import javax.security.auth.callback.CallbackHandler;
8 import javax.security.auth.callback.NameCallback;
9 import javax.security.auth.callback.PasswordCallback;
10 import javax.security.auth.login.LoginException;
11
12 import org.apache.commons.logging.Log;
13 import org.apache.commons.logging.LogFactory;
14 import org.argeo.security.NodeAuthenticationToken;
15 import org.springframework.security.Authentication;
16 import org.springframework.security.AuthenticationManager;
17 import org.springframework.security.BadCredentialsException;
18 import org.springframework.security.context.SecurityContextHolder;
19 import org.springframework.security.providers.jaas.SecurityContextLoginModule;
20
21 /** Login module which caches one subject per thread. */
22 public class SpringLoginModule extends SecurityContextLoginModule {
23 final static String NODE_REPO_URI = "argeo.node.repo.uri";
24
25 private final static Log log = LogFactory.getLog(SpringLoginModule.class);
26
27 private AuthenticationManager authenticationManager;
28
29 private CallbackHandler callbackHandler;
30
31 private Subject subject;
32
33 private Long waitBetweenFailedLoginAttempts = 5 * 1000l;
34
35 private Boolean remote = false;
36
37 public SpringLoginModule() {
38
39 }
40
41 @SuppressWarnings("rawtypes")
42 public void initialize(Subject subject, CallbackHandler callbackHandler,
43 Map sharedState, Map options) {
44 super.initialize(subject, callbackHandler, sharedState, options);
45 this.callbackHandler = callbackHandler;
46 this.subject = subject;
47 }
48
49 public boolean login() throws LoginException {
50 try {
51 // thread already logged in
52 if (SecurityContextHolder.getContext().getAuthentication() != null)
53 return super.login();
54
55 // reset all principals and credentials
56 if (log.isTraceEnabled())
57 log.trace("Resetting all principals and credentials of "
58 + subject);
59 if (subject.getPrincipals() != null)
60 subject.getPrincipals().clear();
61 if (subject.getPrivateCredentials() != null)
62 subject.getPrivateCredentials().clear();
63 if (subject.getPublicCredentials() != null)
64 subject.getPublicCredentials().clear();
65
66 if (callbackHandler == null)
67 throw new LoginException("No call back handler available");
68
69 // ask for username and password
70 NameCallback nameCallback = new NameCallback("User");
71 PasswordCallback passwordCallback = new PasswordCallback(
72 "Password", false);
73 final String defaultNodeUrl = "http://localhost:7070/org.argeo.jcr.webapp/remoting/node";
74 final String defaultSecurityWorkspace = "security";
75 NameCallback urlCallback = new NameCallback("Site URL",
76 defaultNodeUrl);
77 NameCallback securityWorkspaceCallback = new NameCallback(
78 "Security Workspace", defaultSecurityWorkspace);
79
80 // handle callbacks
81 if (remote)
82 callbackHandler.handle(new Callback[] { nameCallback,
83 passwordCallback, urlCallback,
84 securityWorkspaceCallback });
85 else
86 callbackHandler.handle(new Callback[] { nameCallback,
87 passwordCallback });
88
89 // create credentials
90 String username = nameCallback.getName();
91 if (username == null || username.trim().equals(""))
92 return false;
93
94 String password = "";
95 if (passwordCallback.getPassword() != null)
96 password = String.valueOf(passwordCallback.getPassword());
97
98 NodeAuthenticationToken credentials;
99 if (remote) {
100 String url = urlCallback.getName();
101 String workspace = securityWorkspaceCallback.getName();
102 credentials = new NodeAuthenticationToken(username, password,
103 url, workspace);
104 } else {
105 credentials = new NodeAuthenticationToken(username, password);
106 }
107
108 Authentication authentication;
109 try {
110 authentication = authenticationManager
111 .authenticate(credentials);
112 } catch (BadCredentialsException e) {
113 // wait between failed login attempts
114 Thread.sleep(waitBetweenFailedLoginAttempts);
115 throw e;
116 }
117 registerAuthentication(authentication);
118 boolean res = super.login();
119 return res;
120 } catch (LoginException e) {
121 throw e;
122 } catch (ThreadDeath e) {
123 LoginException le = new LoginException(
124 "Spring Security login thread died");
125 le.initCause(e);
126 throw le;
127 } catch (Exception e) {
128 LoginException le = new LoginException(
129 "Spring Security login failed");
130 le.initCause(e);
131 throw le;
132 }
133 }
134
135 @Override
136 public boolean logout() throws LoginException {
137 subject.getPrincipals().clear();
138 return super.logout();
139 }
140
141 /**
142 * Register an {@link Authentication} in the security context.
143 *
144 * @param authentication
145 * has to implement {@link Authentication}.
146 */
147 protected void registerAuthentication(Object authentication) {
148 SecurityContextHolder.getContext().setAuthentication(
149 (Authentication) authentication);
150 }
151
152 public void setAuthenticationManager(
153 AuthenticationManager authenticationManager) {
154 this.authenticationManager = authenticationManager;
155 }
156
157 public void setRemote(Boolean remote) {
158 this.remote = remote;
159 }
160 }