1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.jetspeed.security.impl;
18
19 import java.security.Principal;
20 import java.util.List;
21 import java.util.Map;
22
23 import javax.security.auth.Subject;
24 import javax.security.auth.callback.Callback;
25 import javax.security.auth.callback.CallbackHandler;
26 import javax.security.auth.callback.NameCallback;
27 import javax.security.auth.callback.PasswordCallback;
28 import javax.security.auth.login.FailedLoginException;
29 import javax.security.auth.login.LoginException;
30 import javax.security.auth.spi.LoginModule;
31
32 import org.apache.jetspeed.security.LoginModuleProxy;
33 import org.apache.jetspeed.security.RolePrincipal;
34 import org.apache.jetspeed.security.SecurityHelper;
35 import org.apache.jetspeed.security.User;
36 import org.apache.jetspeed.security.UserManager;
37 import org.apache.jetspeed.security.UserPrincipal;
38
39 /***
40 * <p>LoginModule implementation that authenticates a user
41 * against a relational database. OJB based implementation.</p>
42 * <p>When a user is successfully authenticated, the user principal
43 * are added to the current subject.</p>
44 * <p>The LoginModule also recognizes the debug option.</p>
45 * <p>Configuration files should provide:</p>
46 * <pre><code>
47 * Jetspeed {
48 * org.apache.jetspeed.security.impl.DefaultLoginModule required debug=true;
49 * };
50 * </code></pre>
51 * @author <a href="mailto:dlestrat@apache.org">David Le Strat</a>
52 */
53 public class DefaultLoginModule implements LoginModule
54 {
55
56 /*** <p>LoginModule debug mode is turned off by default.</p> */
57 protected boolean debug;
58
59 /*** <p>The authentication status.</p> */
60 protected boolean success;
61
62 /*** <p>The commit status.</p> */
63 protected boolean commitSuccess;
64
65 /*** <p>The Subject to be authenticated.</p> */
66 protected Subject subject;
67
68 /*** <p>A CallbackHandler for communicating with the end user (prompting for usernames and passwords, for example).</p> */
69 protected CallbackHandler callbackHandler;
70
71 /*** <p>State shared with other configured LoginModules.</p> */
72 protected Map sharedState;
73
74 /*** <p>Options specified in the login Configuration for this particular LoginModule.</p> */
75 protected Map options;
76
77 /*** <p>InternalUserPrincipal manager service.</p> */
78 protected UserManager ums;
79
80 /*** The portal user role. */
81 protected String portalUserRole;
82
83 /*** <p>The user name.</p> */
84 protected String username;
85
86
87 /***
88 * <p>The default login module constructor.</p>
89 */
90 public DefaultLoginModule()
91 {
92 LoginModuleProxy loginModuleProxy = LoginModuleProxyImpl.loginModuleProxy;
93 if (loginModuleProxy != null)
94 {
95 this.ums = loginModuleProxy.getUserManager();
96 this.portalUserRole = loginModuleProxy.getPortalUserRole();
97 }
98 debug = false;
99 success = false;
100 commitSuccess = false;
101 username = null;
102 }
103
104
105 /***
106 * Create a new login module that uses the given user manager.
107 * @param userManager the user manager to use
108 * @param portalUserRole the portal user role to use
109 */
110 protected DefaultLoginModule (UserManager userManager, String portalUserRole)
111 {
112 this.ums = userManager;
113 this.portalUserRole = portalUserRole;
114 debug = false;
115 success = false;
116 commitSuccess = false;
117 username = null;
118 }
119 protected DefaultLoginModule (UserManager userManager)
120 {
121 this(userManager, LoginModuleProxy.DEFAULT_PORTAL_USER_ROLE_NAME);
122 }
123
124 /***
125 * @see javax.security.auth.spi.LoginModule#abort()
126 */
127 public boolean abort() throws LoginException
128 {
129
130 success = false;
131 commitSuccess = false;
132 username = null;
133 if (callbackHandler instanceof PassiveCallbackHandler)
134 {
135 ((PassiveCallbackHandler) callbackHandler).clearPassword();
136 }
137 logout();
138 return true;
139 }
140
141 protected void refreshProxy()
142 {
143 if (this.ums == null)
144 {
145 LoginModuleProxy loginModuleProxy = LoginModuleProxyImpl.loginModuleProxy;
146 if (loginModuleProxy != null)
147 {
148 this.ums = loginModuleProxy.getUserManager();
149 }
150 }
151 }
152
153 /***
154 * @see javax.security.auth.spi.LoginModule#commit()
155 */
156 public boolean commit() throws LoginException
157 {
158 if (success)
159 {
160 if (subject.isReadOnly())
161 {
162 throw new LoginException("Subject is Readonly");
163 }
164 try
165 {
166
167
168 refreshProxy();
169 commitPrincipals(subject, ums.getUser(username));
170
171 username = null;
172 commitSuccess = true;
173
174 if (callbackHandler instanceof PassiveCallbackHandler)
175 {
176 ((PassiveCallbackHandler) callbackHandler).clearPassword();
177 }
178
179 }
180 catch (Exception ex)
181 {
182 ex.printStackTrace(System.out);
183 throw new LoginException(ex.getMessage());
184 }
185 }
186
187 return commitSuccess;
188 }
189
190 /***
191 * @see javax.security.auth.spi.LoginModule#login()
192 */
193 public boolean login() throws LoginException
194 {
195 if (callbackHandler == null)
196 {
197 throw new LoginException("Error: no CallbackHandler available " + "to garner authentication information from the user");
198 }
199 try
200 {
201
202 Callback[] callbacks = new Callback[] { new NameCallback("Username: "), new PasswordCallback("Password: ", false)};
203
204 callbackHandler.handle(callbacks);
205
206 username = ((NameCallback) callbacks[0]).getName();
207 String password = new String(((PasswordCallback) callbacks[1]).getPassword());
208
209 ((PasswordCallback) callbacks[1]).clearPassword();
210
211 refreshProxy();
212 success = ums.authenticate(this.username, password);
213
214 callbacks[0] = null;
215 callbacks[1] = null;
216 if (!success)
217 {
218 throw new FailedLoginException("Authentication failed: Password does not match");
219 }
220
221 return (true);
222 }
223 catch (LoginException ex)
224 {
225 throw ex;
226 }
227 catch (Exception ex)
228 {
229 success = false;
230 throw new LoginException(ex.getMessage());
231 }
232 }
233
234 /***
235 * @see javax.security.auth.spi.LoginModule#logout()
236 */
237 public boolean logout() throws LoginException
238 {
239
240 subject.getPrincipals().clear();
241 subject.getPrivateCredentials().clear();
242 subject.getPublicCredentials().clear();
243 success = false;
244 commitSuccess = false;
245
246 return true;
247 }
248
249 /***
250 * @see javax.security.auth.spi.LoginModule#initialize(javax.security.auth.Subject, javax.security.auth.callback.CallbackHandler, java.util.Map, java.util.Map)
251 */
252 public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options)
253 {
254 this.subject = subject;
255 this.callbackHandler = callbackHandler;
256 this.sharedState = sharedState;
257 this.options = options;
258
259
260 if (options.containsKey("debug"))
261 {
262 debug = "true".equalsIgnoreCase((String) options.get("debug"));
263 }
264 }
265
266
267 protected Principal getUserPrincipal(User user)
268 {
269 return SecurityHelper.getPrincipal(user.getSubject(),UserPrincipal.class);
270 }
271
272 protected List getUserRoles(User user)
273 {
274 return SecurityHelper.getPrincipals(user.getSubject(),RolePrincipal.class);
275 }
276
277 /***
278 * Default setup of the logged on Subject Principals for Tomcat
279 * @param subject
280 * @param user
281 */
282 protected void commitPrincipals(Subject subject, User user)
283 {
284
285 subject.getPrincipals().add(getUserPrincipal(user));
286 subject.getPrincipals().addAll(getUserRoles(user));
287
288
289
290 subject.getPrincipals().add(new RolePrincipalImpl(portalUserRole));
291 }
292 }