KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > sape > carbon > services > security > auth > jaas > JaasCarbonLoginModule


1 /*
2  * The contents of this file are subject to the Sapient Public License
3  * Version 1.0 (the "License"); you may not use this file except in compliance
4  * with the License. You may obtain a copy of the License at
5  * http://carbon.sf.net/License.html.
6  *
7  * Software distributed under the License is distributed on an "AS IS" basis,
8  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
9  * the specific language governing rights and limitations under the License.
10  *
11  * The Original Code is The Carbon Component Framework.
12  *
13  * The Initial Developer of the Original Code is Sapient Corporation
14  *
15  * Copyright (C) 2003 Sapient Corporation. All Rights Reserved.
16  */

17
18 package org.sape.carbon.services.security.auth.jaas;
19
20 import java.io.IOException JavaDoc;
21 import java.security.Principal JavaDoc;
22 import java.util.HashSet JavaDoc;
23 import java.util.Map JavaDoc;
24 import java.util.Set JavaDoc;
25
26 import javax.security.auth.Subject JavaDoc;
27 import javax.security.auth.callback.Callback JavaDoc;
28 import javax.security.auth.callback.CallbackHandler JavaDoc;
29 import javax.security.auth.callback.NameCallback JavaDoc;
30 import javax.security.auth.callback.PasswordCallback JavaDoc;
31 import javax.security.auth.callback.UnsupportedCallbackException JavaDoc;
32 import javax.security.auth.login.LoginException JavaDoc;
33 import javax.security.auth.spi.LoginModule JavaDoc;
34
35 import org.sape.carbon.core.component.Lookup;
36 import org.sape.carbon.core.exception.ExceptionUtility;
37
38 import org.sape.carbon.services.security.management.SecurityManagementDataStoreException;
39 import org.sape.carbon.services.security.management.UnknownPrincipalException;
40 import org.sape.carbon.services.security.management.UserManager;
41
42 /**
43  * JAAS Login Module for Carbon User Manager service.
44  *
45  * <p>
46  * The basic implementation here generates a <code>NameCallback</code> and
47  * <code>PasswordCallback</code> and uses them to retreive the username
48  * and String based password of the user. Credential is mostly handled
49  * as an <code>Object</code> reference, and hence adjusting the
50  * credential to be something other than a String is possible.
51  * </p>
52  *
53  * @author $Author: dvoet $ $Date: 2003/10/28 19:02:00 $
54  * @version $Revision: 1.7 $
55  *
56  * @since carbon 1.2
57  */

58 public class JaasCarbonLoginModule implements LoginModule JavaDoc {
59     /**
60      * Name of the key expected to hold the location of the UserManager
61      * service that will provide back end logic for the Carbon Login
62      * Module.
63      */

64     public static final String JavaDoc USERMANAGER_COMPONENT_KEY =
65         "USERMANAGER_COMPONENT_KEY";
66
67     /** Hold the UserManager providing backend logic. */
68     protected UserManager userManager;
69
70     /** subject for this login. */
71     protected Subject JavaDoc subject;
72
73     /** Handles retreiving the Username and Credential. */
74     protected CallbackHandler JavaDoc callbackHandler;
75
76     /** Flag indicating if login has succeeded. */
77     protected boolean authenticated = false;
78
79     /** Flag indicating if principals have been added */
80     protected boolean principalsInSubject;
81
82     /** List of principals added to the subject. */
83     protected Set JavaDoc principalsForSubject = new HashSet JavaDoc();
84
85     /**
86      * Initialize the module by storing all state internally and getting a
87      * reference to the UserManager object.
88      *
89      * @param subject the Subject to be authenticated.
90      * @param callbackHandler a CallbackHandler for communicating with the
91      * end user (prompting for usernames and passwords, for
92      * example).
93      * @param sharedState state shared with other configured LoginModules.
94      * @param options options specified in the login Configuration for
95      * this particular LoginModule.
96      */

97     public void initialize(
98         Subject JavaDoc subject, CallbackHandler JavaDoc callbackHandler, Map JavaDoc sharedState,
99         Map JavaDoc options) {
100         // only called (once!) after the constructor and before login
101
this.subject = subject;
102         this.callbackHandler = callbackHandler;
103         this.userManager =
104             (UserManager) Lookup.getInstance().fetchComponent(
105                 (String JavaDoc) options.get(
106                     JaasCarbonLoginModule.USERMANAGER_COMPONENT_KEY));
107     }
108
109     /**
110      * Builds the callbacks, executes against them, gets username/credential,
111      * validates against Carbon UserManager service.
112      *
113      * @return if the user has been authenticated by this module
114      * @throws LoginException indicates an error in the login process
115      */

116     public boolean login() throws LoginException JavaDoc {
117         Callback JavaDoc[] callbacks = buildCallbacks();
118         executeCallbacks(callbacks);
119
120         String JavaDoc username = getUsername(callbacks);
121         Object JavaDoc credential = getCredential(callbacks);
122
123         try {
124             authenticated = userManager.authenticate(username, credential);
125         } catch (SecurityManagementDataStoreException smdse) {
126             throw new LoginException JavaDoc(
127                 "Caught SecurityManagementDataStoreException authenticating " +
128                 "user: " + ExceptionUtility.printStackTracesToString(smdse));
129         }
130
131         if (authenticated) {
132             addMainPrincipal(username);
133             addContainingGroups(username);
134         }
135
136         return authenticated;
137     }
138
139     /**
140      * Commit this modules login by adding principals to the
141      * subject.
142      * <p>
143      * This method adds in all principals withing the
144      * <code>principalsForSubject</code> member variable.
145      * </p>
146      *
147      * @return always return true
148      * @throws LoginException indicates an error committing the login
149      */

150     public boolean commit() throws LoginException JavaDoc {
151         boolean result = false;
152
153         if (authenticated) {
154             subject.getPrincipals().addAll(principalsForSubject);
155             principalsInSubject = true;
156             result = true;
157         }
158
159         return result;
160     }
161
162     /**
163      * Abort the login.
164      * <p>
165      * If the Principals inside the <code>principalsForSubject</code>
166      * member variable have already been added, they will be removed
167      * from the subject's principal list.
168      * </p>
169      *
170      * @return always return true
171      * @throws LoginException indicates an error aborting the login
172      */

173     public boolean abort() throws LoginException JavaDoc {
174         if (principalsInSubject) {
175             subject.getPrincipals().removeAll(principalsForSubject);
176             principalsInSubject = false;
177         }
178
179         return true;
180     }
181
182     /**
183      * Empty implementation that always returns true.
184      *
185      * @return always returns true
186      * @throws LoginException indicates a failure logging the user out
187      * of the system.
188      */

189     public boolean logout() throws LoginException JavaDoc {
190         return true;
191     }
192
193     /**
194      * Internal method to build the list of callbacks that are used.
195      * <p>
196      * The default implementation will create a <code>NameCallback</code>
197      * and <code>PasswordCallback</code> and place them into the
198      * array of callbacks.
199      * </p>
200      *
201      * @return array of callbacks to be executed by the handler
202      * @throws LoginException indicates an error building the callbacks.
203      * @see javax.security.auth.callback.NameCallback
204      * @see javax.security.auth.callback.PasswordCallback
205      */

206     protected Callback JavaDoc[] buildCallbacks() throws LoginException JavaDoc {
207         if (callbackHandler == null) {
208             throw new LoginException JavaDoc("No CallbackHandler Specified");
209         }
210
211         Callback JavaDoc[] callbacks = new Callback JavaDoc[2];
212
213         // add in the user name callback
214
callbacks[0] = new NameCallback JavaDoc(getUsernamePrompt());
215
216         // add in the name callback with echo-on set to false
217
callbacks[1] = new PasswordCallback JavaDoc(getCredentialPrompt(), false);
218
219         return callbacks;
220     }
221
222     /**
223      * Executes all callbacks in the list by telling the
224      * <code>CallbackHandler</code> to handle them.
225      *
226      * @param callbacks array of callbacks to be handled
227      * @throws LoginException indicates an error executing the callbacks
228      */

229     protected void executeCallbacks(Callback JavaDoc[] callbacks)
230         throws LoginException JavaDoc {
231         // Call the callback handler, who in turn, calls back to the
232
// callback objects, handing them the user name and credential.
233
// These callback objects hold onto the user name and credential.
234
// The login module retrieves the user name and credential
235
// from them later.
236
try {
237             callbackHandler.handle(callbacks);
238         } catch (IOException JavaDoc ioe) {
239             throw new LoginException JavaDoc(
240                 "Error communicating with the user when executing callbacks. "
241                 + "Caused by ["
242                 + ExceptionUtility.printStackTracesToString(ioe)
243                 + "]");
244
245         } catch (UnsupportedCallbackException JavaDoc uce) {
246             throw new LoginException JavaDoc(
247                 "Error executing unsupported callback. "
248                 + "Caused by ["
249                 + ExceptionUtility.printStackTracesToString(uce)
250                 + "]");
251
252         }
253
254     }
255
256     /**
257      * Get the username from the array of callbacks.
258      * <p>
259      * The default implementation iterates through the list of
260      * callbacks until the first <code>NameCallback</code> object
261      * gives a non-nullname.
262      * </p>
263      *
264      * @param callbacks list of callbacks to get a name from
265      * @return the first username encountered or null if none are found
266      */

267     protected String JavaDoc getUsername(Callback JavaDoc[] callbacks) {
268         String JavaDoc username = null;
269
270         // Iterate over the callbacks until the first username
271
// call back and retreive it.
272
for (int i = 0; (i < callbacks.length) && (username == null);
273                 i++) {
274             if (callbacks[i] instanceof NameCallback JavaDoc) {
275                 username = ((NameCallback JavaDoc) callbacks[i]).getName();
276             }
277         }
278
279         return username;
280     }
281
282     /**
283      * Get the credential from the array of callbacks.
284      * <p>
285      * The default implementation iterates through the list of
286      * callbacks until the first <code>PasswordCallback</code> object
287      * gives a non-null password. It then converts the char[] result
288      * from the callback into a string a returns it.
289      * </p>
290      *
291      * @param callbacks list of callbacks to get a name from
292      * @return the first password encountered or null if none are found
293      */

294     protected Object JavaDoc getCredential(Callback JavaDoc[] callbacks) {
295         char[] passwordArray = null;
296         String JavaDoc password = null;
297
298         // Iterate over the callbacks until the first username
299
// call back and retreive it.
300
for (int i = 0; (i < callbacks.length) && (passwordArray == null);
301                 i++) {
302             if (callbacks[i] instanceof PasswordCallback JavaDoc) {
303                 passwordArray =
304                     ((PasswordCallback JavaDoc) callbacks[i]).getPassword();
305             }
306         }
307
308         if (passwordArray != null) {
309             password = new String JavaDoc(passwordArray);
310         }
311
312         return password;
313     }
314
315     /**
316      * Adds the main Principal object to <code>principalsForSubject</code>
317      * object.
318      * <p>
319      * The default will add the Carbon implementation of the user object.
320      * If a specific type of user object must be supplied, this method
321      * can be overriden.
322      * </p>
323      *
324      * @param username the name of the user to add the main principal for
325      */

326     protected void addMainPrincipal(String JavaDoc username) throws LoginException JavaDoc {
327         try {
328             principalsForSubject.add(userManager.retreiveUser(username));
329         } catch (SecurityManagementDataStoreException smdse) {
330             throw new LoginException JavaDoc(
331                 "Caught SecurityManagementDataStoreException retrieving user: " +
332                 ExceptionUtility.printStackTracesToString(smdse));
333         }
334     }
335
336     /**
337      * Adds all groups containing the given username.
338      * <p>
339      * The default will add the Carbon implementation of the group object.
340      * If a specific type of group object must be supplied, this method
341      * can be overriden.
342      * </p>
343      *
344      * @param username the name of the user to add the containing groups
345      * @throws LoginException indicates an error retreiving groups for
346      * a user.
347      */

348     protected void addContainingGroups(String JavaDoc username)
349         throws LoginException JavaDoc {
350
351         try {
352             Principal JavaDoc user = userManager.retreiveUser(username);
353
354             principalsForSubject.addAll(userManager.retreiveGroups(user));
355         } catch (SecurityManagementDataStoreException smdse) {
356             throw new LoginException JavaDoc(
357                 "Caught SecurityManagementDataStoreException retrieving user or groups: " +
358                 ExceptionUtility.printStackTracesToString(smdse));
359         } catch (UnknownPrincipalException upe) {
360             throw new LoginException JavaDoc(
361                 "Error retreving groups for unknown user. "
362                 + "Caused by ["
363                 + ExceptionUtility.printStackTracesToString(upe)
364                 + "]");
365         }
366     }
367
368     /**
369      * Returns the string prompt associated with the default
370      * <code>NameCallback</code> object.
371      *
372      * @return name prompt
373      * @see javax.security.auth.callback.NameCallback
374      */

375     protected String JavaDoc getUsernamePrompt() {
376         return "username: ";
377     }
378
379     /**
380      * Returns the string prompt associated with the default
381      * <code>PasswordCallback</code> object.
382      *
383      * @return password prompt
384      * @see javax.security.auth.callback.PasswordCallback
385      */

386     protected String JavaDoc getCredentialPrompt() {
387         return "password: ";
388     }
389 }
390
Popular Tags