]> git.argeo.org Git - lgpl/argeo-commons.git/blob - SpringLoginModule.java
dada3440525caf6c95b3e0172c25c33201223713
[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.SiteAuthenticationToken;
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 // ask for username and password
67 NameCallback nameCallback = new NameCallback("User");
68 PasswordCallback passwordCallback = new PasswordCallback(
69 "Password", false);
70
71 NameCallback urlCallback = new NameCallback("Site URL");
72
73 if (callbackHandler == null)
74 throw new LoginException("No call back handler available");
75 if (remote)
76 callbackHandler.handle(new Callback[] { nameCallback,
77 passwordCallback, urlCallback });
78 else
79 callbackHandler.handle(new Callback[] { nameCallback,
80 passwordCallback });
81
82 // Set user name and password
83 String username = nameCallback.getName();
84 if (username == null || username.trim().equals(""))
85 return false;
86
87 String password = "";
88 if (passwordCallback.getPassword() != null)
89 password = String.valueOf(passwordCallback.getPassword());
90
91 String url = remote ? urlCallback.getName() : null;
92 if (remote && (url == null || url.trim().equals("")))
93 // for convenience, may be removed in the future
94 url = System.getProperty(NODE_REPO_URI);
95
96 // TODO: set it via system properties
97 String workspace = null;
98
99 SiteAuthenticationToken credentials = new SiteAuthenticationToken(
100 username, password, url, workspace);
101
102 Authentication authentication;
103 try {
104 authentication = authenticationManager
105 .authenticate(credentials);
106 } catch (BadCredentialsException e) {
107 // wait between failed login attempts
108 Thread.sleep(waitBetweenFailedLoginAttempts);
109 throw e;
110 }
111 registerAuthentication(authentication);
112 boolean res = super.login();
113 return res;
114 } catch (LoginException e) {
115 throw e;
116 } catch (ThreadDeath e) {
117 LoginException le = new LoginException(
118 "Spring Security login thread died");
119 le.initCause(e);
120 throw le;
121 } catch (Exception e) {
122 LoginException le = new LoginException(
123 "Spring Security login failed");
124 le.initCause(e);
125 throw le;
126 }
127 }
128
129 @Override
130 public boolean logout() throws LoginException {
131 subject.getPrincipals().clear();
132 return super.logout();
133 }
134
135 /**
136 * Register an {@link Authentication} in the security context.
137 *
138 * @param authentication
139 * has to implement {@link Authentication}.
140 */
141 protected void registerAuthentication(Object authentication) {
142 SecurityContextHolder.getContext().setAuthentication(
143 (Authentication) authentication);
144 }
145
146 public void setAuthenticationManager(
147 AuthenticationManager authenticationManager) {
148 this.authenticationManager = authenticationManager;
149 }
150
151 public void setRemote(Boolean remote) {
152 this.remote = remote;
153 }
154 }