42 import com.sun.security.auth.UnixNumericUserPrincipal; |
42 import com.sun.security.auth.UnixNumericUserPrincipal; |
43 import com.sun.security.auth.UnixNumericGroupPrincipal; |
43 import com.sun.security.auth.UnixNumericGroupPrincipal; |
44 |
44 |
45 |
45 |
46 /** |
46 /** |
47 * <p> The module prompts for a username and password |
47 * The module prompts for a username and password |
48 * and then verifies the password against the password stored in |
48 * and then verifies the password against the password stored in |
49 * a directory service configured under JNDI. |
49 * a directory service configured under JNDI. |
50 * |
50 * |
51 * <p> This <code>LoginModule</code> interoperates with |
51 * <p> This {@code LoginModule} interoperates with |
52 * any conformant JNDI service provider. To direct this |
52 * any conformant JNDI service provider. To direct this |
53 * <code>LoginModule</code> to use a specific JNDI service provider, |
53 * {@code LoginModule} to use a specific JNDI service provider, |
54 * two options must be specified in the login <code>Configuration</code> |
54 * two options must be specified in the login {@code Configuration} |
55 * for this <code>LoginModule</code>. |
55 * for this {@code LoginModule}. |
56 * <pre> |
56 * <pre> |
57 * user.provider.url=<b>name_service_url</b> |
57 * user.provider.url=<b>name_service_url</b> |
58 * group.provider.url=<b>name_service_url</b> |
58 * group.provider.url=<b>name_service_url</b> |
59 * </pre> |
59 * </pre> |
60 * |
60 * |
61 * <b>name_service_url</b> specifies |
61 * <b>name_service_url</b> specifies |
62 * the directory service and path where this <code>LoginModule</code> |
62 * the directory service and path where this {@code LoginModule} |
63 * can access the relevant user and group information. Because this |
63 * can access the relevant user and group information. Because this |
64 * <code>LoginModule</code> only performs one-level searches to |
64 * {@code LoginModule} only performs one-level searches to |
65 * find the relevant user information, the <code>URL</code> |
65 * find the relevant user information, the {@code URL} |
66 * must point to a directory one level above where the user and group |
66 * must point to a directory one level above where the user and group |
67 * information is stored in the directory service. |
67 * information is stored in the directory service. |
68 * For example, to instruct this <code>LoginModule</code> |
68 * For example, to instruct this {@code LoginModule} |
69 * to contact a NIS server, the following URLs must be specified: |
69 * to contact a NIS server, the following URLs must be specified: |
70 * <pre> |
70 * <pre> |
71 * user.provider.url="nis://<b>NISServerHostName</b>/<b>NISDomain</b>/user" |
71 * user.provider.url="nis://<b>NISServerHostName</b>/<b>NISDomain</b>/user" |
72 * group.provider.url="nis://<b>NISServerHostName</b>/<b>NISDomain</b>/system/group" |
72 * group.provider.url="nis://<b>NISServerHostName</b>/<b>NISDomain</b>/system/group" |
73 * </pre> |
73 * </pre> |
88 * (for example, <i>ou=People,o=Sun,c=US</i> and <i>ou=Groups,o=Sun,c=US</i> |
88 * (for example, <i>ou=People,o=Sun,c=US</i> and <i>ou=Groups,o=Sun,c=US</i> |
89 * for user and group information, respectively). |
89 * for user and group information, respectively). |
90 * |
90 * |
91 * <p> The format in which the user's information must be stored in |
91 * <p> The format in which the user's information must be stored in |
92 * the directory service is specified in RFC 2307. Specifically, |
92 * the directory service is specified in RFC 2307. Specifically, |
93 * this <code>LoginModule</code> will search for the user's entry in the |
93 * this {@code LoginModule} will search for the user's entry in the |
94 * directory service using the user's <i>uid</i> attribute, |
94 * directory service using the user's <i>uid</i> attribute, |
95 * where <i>uid=<b>username</b></i>. If the search succeeds, |
95 * where <i>uid=<b>username</b></i>. If the search succeeds, |
96 * this <code>LoginModule</code> will then |
96 * this {@code LoginModule} will then |
97 * obtain the user's encrypted password from the retrieved entry |
97 * obtain the user's encrypted password from the retrieved entry |
98 * using the <i>userPassword</i> attribute. |
98 * using the <i>userPassword</i> attribute. |
99 * This <code>LoginModule</code> assumes that the password is stored |
99 * This {@code LoginModule} assumes that the password is stored |
100 * as a byte array, which when converted to a <code>String</code>, |
100 * as a byte array, which when converted to a {@code String}, |
101 * has the following format: |
101 * has the following format: |
102 * <pre> |
102 * <pre> |
103 * "{crypt}<b>encrypted_password</b>" |
103 * "{crypt}<b>encrypted_password</b>" |
104 * </pre> |
104 * </pre> |
105 * |
105 * |
106 * The LDAP directory server must be configured |
106 * The LDAP directory server must be configured |
107 * to permit read access to the userPassword attribute. |
107 * to permit read access to the userPassword attribute. |
108 * If the user entered a valid username and password, |
108 * If the user entered a valid username and password, |
109 * this <code>LoginModule</code> associates a |
109 * this {@code LoginModule} associates a |
110 * <code>UnixPrincipal</code>, <code>UnixNumericUserPrincipal</code>, |
110 * {@code UnixPrincipal}, {@code UnixNumericUserPrincipal}, |
111 * and the relevant UnixNumericGroupPrincipals with the |
111 * and the relevant UnixNumericGroupPrincipals with the |
112 * <code>Subject</code>. |
112 * {@code Subject}. |
113 * |
113 * |
114 * <p> This LoginModule also recognizes the following <code>Configuration</code> |
114 * <p> This LoginModule also recognizes the following {@code Configuration} |
115 * options: |
115 * options: |
116 * <pre> |
116 * <pre> |
117 * debug if, true, debug messages are output to System.out. |
117 * debug if, true, debug messages are output to System.out. |
118 * |
118 * |
119 * useFirstPass if, true, this LoginModule retrieves the |
119 * useFirstPass if, true, this LoginModule retrieves the |
142 * "javax.security.auth.login.password" as the respective |
142 * "javax.security.auth.login.password" as the respective |
143 * keys. This is not performed if existing values already |
143 * keys. This is not performed if existing values already |
144 * exist for the username and password in the shared state, |
144 * exist for the username and password in the shared state, |
145 * or if authentication fails. |
145 * or if authentication fails. |
146 * |
146 * |
147 * clearPass if, true, this <code>LoginModule</code> clears the |
147 * clearPass if, true, this {@code LoginModule} clears the |
148 * username and password stored in the module's shared state |
148 * username and password stored in the module's shared state |
149 * after both phases of authentication (login and commit) |
149 * after both phases of authentication (login and commit) |
150 * have completed. |
150 * have completed. |
151 * </pre> |
151 * </pre> |
152 * |
152 * |
206 private static final String GROUP_ID = "gidNumber"; |
206 private static final String GROUP_ID = "gidNumber"; |
207 private static final String NAME = "javax.security.auth.login.name"; |
207 private static final String NAME = "javax.security.auth.login.name"; |
208 private static final String PWD = "javax.security.auth.login.password"; |
208 private static final String PWD = "javax.security.auth.login.password"; |
209 |
209 |
210 /** |
210 /** |
211 * Initialize this <code>LoginModule</code>. |
211 * Initialize this {@code LoginModule}. |
212 * |
212 * |
213 * <p> |
213 * @param subject the {@code Subject} to be authenticated. |
214 * |
214 * |
215 * @param subject the <code>Subject</code> to be authenticated. <p> |
215 * @param callbackHandler a {@code CallbackHandler} for communicating |
216 * |
|
217 * @param callbackHandler a <code>CallbackHandler</code> for communicating |
|
218 * with the end user (prompting for usernames and |
216 * with the end user (prompting for usernames and |
219 * passwords, for example). <p> |
217 * passwords, for example). |
220 * |
218 * |
221 * @param sharedState shared <code>LoginModule</code> state. <p> |
219 * @param sharedState shared {@code LoginModule} state. |
222 * |
220 * |
223 * @param options options specified in the login |
221 * @param options options specified in the login |
224 * <code>Configuration</code> for this particular |
222 * {@code Configuration} for this particular |
225 * <code>LoginModule</code>. |
223 * {@code LoginModule}. |
226 */ |
224 */ |
227 // Unchecked warning from (Map<String, Object>)sharedState is safe |
225 // Unchecked warning from (Map<String, Object>)sharedState is safe |
228 // since javax.security.auth.login.LoginContext passes a raw HashMap. |
226 // since javax.security.auth.login.LoginContext passes a raw HashMap. |
229 // Unchecked warnings from options.get(String) are safe since we are |
227 // Unchecked warnings from options.get(String) are safe since we are |
230 // passing known keys. |
228 // passing known keys. |
253 clearPass = |
251 clearPass = |
254 "true".equalsIgnoreCase((String)options.get("clearPass")); |
252 "true".equalsIgnoreCase((String)options.get("clearPass")); |
255 } |
253 } |
256 |
254 |
257 /** |
255 /** |
258 * <p> Prompt for username and password. |
256 * Prompt for username and password. |
259 * Verify the password against the relevant name service. |
257 * Verify the password against the relevant name service. |
260 * |
258 * |
261 * <p> |
259 * @return true always, since this {@code LoginModule} |
262 * |
|
263 * @return true always, since this <code>LoginModule</code> |
|
264 * should not be ignored. |
260 * should not be ignored. |
265 * |
261 * |
266 * @exception FailedLoginException if the authentication fails. <p> |
262 * @exception FailedLoginException if the authentication fails. |
267 * |
263 * |
268 * @exception LoginException if this <code>LoginModule</code> |
264 * @exception LoginException if this {@code LoginModule} |
269 * is unable to perform the authentication. |
265 * is unable to perform the authentication. |
270 */ |
266 */ |
271 public boolean login() throws LoginException { |
267 public boolean login() throws LoginException { |
272 |
268 |
273 if (userProvider == null) { |
269 if (userProvider == null) { |
365 * (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL LoginModules |
361 * (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL LoginModules |
366 * succeeded). |
362 * succeeded). |
367 * |
363 * |
368 * <p> If this LoginModule's own authentication attempt |
364 * <p> If this LoginModule's own authentication attempt |
369 * succeeded (checked by retrieving the private state saved by the |
365 * succeeded (checked by retrieving the private state saved by the |
370 * <code>login</code> method), then this method associates a |
366 * {@code login} method), then this method associates a |
371 * <code>UnixPrincipal</code> |
367 * {@code UnixPrincipal} |
372 * with the <code>Subject</code> located in the |
368 * with the {@code Subject} located in the |
373 * <code>LoginModule</code>. If this LoginModule's own |
369 * {@code LoginModule}. If this LoginModule's own |
374 * authentication attempted failed, then this method removes |
370 * authentication attempted failed, then this method removes |
375 * any state that was originally saved. |
371 * any state that was originally saved. |
376 * |
|
377 * <p> |
|
378 * |
372 * |
379 * @exception LoginException if the commit fails |
373 * @exception LoginException if the commit fails |
380 * |
374 * |
381 * @return true if this LoginModule's own login and commit |
375 * @return true if this LoginModule's own login and commit |
382 * attempts succeeded, or false otherwise. |
376 * attempts succeeded, or false otherwise. |
416 commitSucceeded = true; |
410 commitSucceeded = true; |
417 return true; |
411 return true; |
418 } |
412 } |
419 |
413 |
420 /** |
414 /** |
421 * <p> This method is called if the LoginContext's |
415 * This method is called if the LoginContext's |
422 * overall authentication failed. |
416 * overall authentication failed. |
423 * (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL LoginModules |
417 * (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL LoginModules |
424 * did not succeed). |
418 * did not succeed). |
425 * |
419 * |
426 * <p> If this LoginModule's own authentication attempt |
420 * <p> If this LoginModule's own authentication attempt |
427 * succeeded (checked by retrieving the private state saved by the |
421 * succeeded (checked by retrieving the private state saved by the |
428 * <code>login</code> and <code>commit</code> methods), |
422 * {@code login} and {@code commit} methods), |
429 * then this method cleans up any state that was originally saved. |
423 * then this method cleans up any state that was originally saved. |
430 * |
|
431 * <p> |
|
432 * |
424 * |
433 * @exception LoginException if the abort fails. |
425 * @exception LoginException if the abort fails. |
434 * |
426 * |
435 * @return false if this LoginModule's own login and/or commit attempts |
427 * @return false if this LoginModule's own login and/or commit attempts |
436 * failed, and true otherwise. |
428 * failed, and true otherwise. |
462 |
454 |
463 /** |
455 /** |
464 * Logout a user. |
456 * Logout a user. |
465 * |
457 * |
466 * <p> This method removes the Principals |
458 * <p> This method removes the Principals |
467 * that were added by the <code>commit</code> method. |
459 * that were added by the {@code commit} method. |
468 * |
|
469 * <p> |
|
470 * |
460 * |
471 * @exception LoginException if the logout fails. |
461 * @exception LoginException if the logout fails. |
472 * |
462 * |
473 * @return true in all cases since this <code>LoginModule</code> |
463 * @return true in all cases since this {@code LoginModule} |
474 * should not be ignored. |
464 * should not be ignored. |
475 */ |
465 */ |
476 public boolean logout() throws LoginException { |
466 public boolean logout() throws LoginException { |
477 if (subject.isReadOnly()) { |
467 if (subject.isReadOnly()) { |
478 cleanState(); |
468 cleanState(); |
672 * |
660 * |
673 * <p> Also note that this method will set the username and password |
661 * <p> Also note that this method will set the username and password |
674 * values in the shared state in case subsequent LoginModules |
662 * values in the shared state in case subsequent LoginModules |
675 * want to use them via use/tryFirstPass. |
663 * want to use them via use/tryFirstPass. |
676 * |
664 * |
677 * <p> |
|
678 * |
|
679 * @param getPasswdFromSharedState boolean that tells this method whether |
665 * @param getPasswdFromSharedState boolean that tells this method whether |
680 * to retrieve the password from the sharedState. |
666 * to retrieve the password from the sharedState. |
681 */ |
667 */ |
682 private void getUsernamePassword(boolean getPasswdFromSharedState) |
668 private void getUsernamePassword(boolean getPasswdFromSharedState) |
683 throws LoginException { |
669 throws LoginException { |