68 * user's distinguished name and then authentication is attempted. |
68 * user's distinguished name and then authentication is attempted. |
69 * An (anonymous) search is performed using the supplied username in |
69 * An (anonymous) search is performed using the supplied username in |
70 * conjunction with a specified search filter. |
70 * conjunction with a specified search filter. |
71 * If successful then authentication is attempted using the user's |
71 * If successful then authentication is attempted using the user's |
72 * distinguished name and the supplied password. |
72 * distinguished name and the supplied password. |
73 * To enable this mode, set the <code>userFilter</code> option and omit the |
73 * To enable this mode, set the {@code userFilter} option and omit the |
74 * <code>authIdentity</code> option. |
74 * {@code authIdentity} option. |
75 * Use search-first mode when the user's distinguished name is not |
75 * Use search-first mode when the user's distinguished name is not |
76 * known in advance. |
76 * known in advance. |
77 * |
77 * |
78 * <p> In authentication-first mode, authentication is attempted using the |
78 * <p> In authentication-first mode, authentication is attempted using the |
79 * supplied username and password and then the LDAP directory is searched. |
79 * supplied username and password and then the LDAP directory is searched. |
80 * If authentication is successful then a search is performed using the |
80 * If authentication is successful then a search is performed using the |
81 * supplied username in conjunction with a specified search filter. |
81 * supplied username in conjunction with a specified search filter. |
82 * To enable this mode, set the <code>authIdentity</code> and the |
82 * To enable this mode, set the {@code authIdentity} and the |
83 * <code>userFilter</code> options. |
83 * {@code userFilter} options. |
84 * Use authentication-first mode when accessing an LDAP directory |
84 * Use authentication-first mode when accessing an LDAP directory |
85 * that has been configured to disallow anonymous searches. |
85 * that has been configured to disallow anonymous searches. |
86 * |
86 * |
87 * <p> In authentication-only mode, authentication is attempted using the |
87 * <p> In authentication-only mode, authentication is attempted using the |
88 * supplied username and password. The LDAP directory is not searched because |
88 * supplied username and password. The LDAP directory is not searched because |
89 * the user's distinguished name is already known. |
89 * the user's distinguished name is already known. |
90 * To enable this mode, set the <code>authIdentity</code> option to a valid |
90 * To enable this mode, set the {@code authIdentity} option to a valid |
91 * distinguished name and omit the <code>userFilter</code> option. |
91 * distinguished name and omit the {@code userFilter} option. |
92 * Use authentication-only mode when the user's distinguished name is |
92 * Use authentication-only mode when the user's distinguished name is |
93 * known in advance. |
93 * known in advance. |
94 * |
94 * |
95 * <p> The following option is mandatory and must be specified in this |
95 * <p> The following option is mandatory and must be specified in this |
96 * module's login {@link Configuration}: |
96 * module's login {@link Configuration}: |
97 * <dl><dt></dt><dd> |
97 * <dl><dd> |
98 * <dl> |
98 * <dl> |
99 * <dt> <code>userProvider=<b>ldap_urls</b></code> |
99 * <dt> <code>userProvider=<b>ldap_urls</b></code> |
100 * </dt> |
100 * </dt> |
101 * <dd> This option identifies the LDAP directory that stores user entries. |
101 * <dd> This option identifies the LDAP directory that stores user entries. |
102 * <b>ldap_urls</b> is a list of space-separated LDAP URLs |
102 * <b>ldap_urls</b> is a list of space-separated LDAP URLs |
118 * the LDAP URL. </dd> |
118 * the LDAP URL. </dd> |
119 * </dl></dl> |
119 * </dl></dl> |
120 * |
120 * |
121 * <p> This module also recognizes the following optional {@link Configuration} |
121 * <p> This module also recognizes the following optional {@link Configuration} |
122 * options: |
122 * options: |
123 * <dl><dt></dt><dd> |
123 * <dl><dd> |
124 * <dl> |
124 * <dl> |
125 * <dt> <code>userFilter=<b>ldap_filter</b></code> </dt> |
125 * <dt> <code>userFilter=<b>ldap_filter</b></code> </dt> |
126 * <dd> This option specifies the search filter to use to locate a user's |
126 * <dd> This option specifies the search filter to use to locate a user's |
127 * entry in the LDAP directory. It is used to determine a user's |
127 * entry in the LDAP directory. It is used to determine a user's |
128 * distinguished name. |
128 * distinguished name. |
129 * <code><b>ldap_filter</b></code> is an LDAP filter string |
129 * <b>{@code ldap_filter}</b> is an LDAP filter string |
130 * (<a href="http://www.ietf.org/rfc/rfc2254.txt">RFC 2254</a>). |
130 * (<a href="http://www.ietf.org/rfc/rfc2254.txt">RFC 2254</a>). |
131 * If it contains the special token "<code><b>{USERNAME}</b></code>" |
131 * If it contains the special token "<b>{@code {USERNAME}}</b>" |
132 * then that token will be replaced with the supplied username value |
132 * then that token will be replaced with the supplied username value |
133 * before the filter is used to search the directory. </dd> |
133 * before the filter is used to search the directory. </dd> |
134 * |
134 * |
135 * <dt> <code>authIdentity=<b>auth_id</b></code> </dt> |
135 * <dt> <code>authIdentity=<b>auth_id</b></code> </dt> |
136 * <dd> This option specifies the identity to use when authenticating a user |
136 * <dd> This option specifies the identity to use when authenticating a user |
137 * to the LDAP directory. |
137 * to the LDAP directory. |
138 * <code><b>auth_id</b></code> may be an LDAP distinguished name string |
138 * <b>{@code auth_id}</b> may be an LDAP distinguished name string |
139 * (<a href="http://www.ietf.org/rfc/rfc2253.txt">RFC 2253</a>) or some |
139 * (<a href="http://www.ietf.org/rfc/rfc2253.txt">RFC 2253</a>) or some |
140 * other string name. |
140 * other string name. |
141 * It must contain the special token "<code><b>{USERNAME}</b></code>" |
141 * It must contain the special token "<b>{@code {USERNAME}}</b>" |
142 * which will be replaced with the supplied username value before the |
142 * which will be replaced with the supplied username value before the |
143 * name is used for authentication. |
143 * name is used for authentication. |
144 * Note that if this option does not contain a distinguished name then |
144 * Note that if this option does not contain a distinguished name then |
145 * the <code>userFilter</code> option must also be specified. </dd> |
145 * the {@code userFilter} option must also be specified. </dd> |
146 * |
146 * |
147 * <dt> <code>authzIdentity=<b>authz_id</b></code> </dt> |
147 * <dt> <code>authzIdentity=<b>authz_id</b></code> </dt> |
148 * <dd> This option specifies an authorization identity for the user. |
148 * <dd> This option specifies an authorization identity for the user. |
149 * <code><b>authz_id</b></code> is any string name. |
149 * <b>{@code authz_id}</b> is any string name. |
150 * If it comprises a single special token with curly braces then |
150 * If it comprises a single special token with curly braces then |
151 * that token is treated as a attribute name and will be replaced with a |
151 * that token is treated as a attribute name and will be replaced with a |
152 * single value of that attribute from the user's LDAP entry. |
152 * single value of that attribute from the user's LDAP entry. |
153 * If the attribute cannot be found then the option is ignored. |
153 * If the attribute cannot be found then the option is ignored. |
154 * When this option is supplied and the user has been successfully |
154 * When this option is supplied and the user has been successfully |
155 * authenticated then an additional {@link UserPrincipal} |
155 * authenticated then an additional {@link UserPrincipal} |
156 * is created using the authorization identity and it is associated with |
156 * is created using the authorization identity and it is associated with |
157 * the current {@link Subject}. </dd> |
157 * the current {@link Subject}. </dd> |
158 * |
158 * |
159 * <dt> <code>useSSL</code> </dt> |
159 * <dt> {@code useSSL} </dt> |
160 * <dd> if <code>false</code>, this module does not establish an SSL connection |
160 * <dd> if {@code false}, this module does not establish an SSL connection |
161 * to the LDAP server before attempting authentication. SSL is used to |
161 * to the LDAP server before attempting authentication. SSL is used to |
162 * protect the privacy of the user's password because it is transmitted |
162 * protect the privacy of the user's password because it is transmitted |
163 * in the clear over LDAP. |
163 * in the clear over LDAP. |
164 * By default, this module uses SSL. </dd> |
164 * By default, this module uses SSL. </dd> |
165 * |
165 * |
166 * <dt> <code>useFirstPass</code> </dt> |
166 * <dt> {@code useFirstPass} </dt> |
167 * <dd> if <code>true</code>, this module retrieves the username and password |
167 * <dd> if {@code true}, this module retrieves the username and password |
168 * from the module's shared state, using "javax.security.auth.login.name" |
168 * from the module's shared state, using "javax.security.auth.login.name" |
169 * and "javax.security.auth.login.password" as the respective keys. The |
169 * and "javax.security.auth.login.password" as the respective keys. The |
170 * retrieved values are used for authentication. If authentication fails, |
170 * retrieved values are used for authentication. If authentication fails, |
171 * no attempt for a retry is made, and the failure is reported back to |
171 * no attempt for a retry is made, and the failure is reported back to |
172 * the calling application.</dd> |
172 * the calling application.</dd> |
173 * |
173 * |
174 * <dt> <code>tryFirstPass</code> </dt> |
174 * <dt> {@code tryFirstPass} </dt> |
175 * <dd> if <code>true</code>, this module retrieves the username and password |
175 * <dd> if {@code true}, this module retrieves the username and password |
176 * from the module's shared state, using "javax.security.auth.login.name" |
176 * from the module's shared state, using "javax.security.auth.login.name" |
177 * and "javax.security.auth.login.password" as the respective keys. The |
177 * and "javax.security.auth.login.password" as the respective keys. The |
178 * retrieved values are used for authentication. If authentication fails, |
178 * retrieved values are used for authentication. If authentication fails, |
179 * the module uses the {@link CallbackHandler} to retrieve a new username |
179 * the module uses the {@link CallbackHandler} to retrieve a new username |
180 * and password, and another attempt to authenticate is made. If the |
180 * and password, and another attempt to authenticate is made. If the |
181 * authentication fails, the failure is reported back to the calling |
181 * authentication fails, the failure is reported back to the calling |
182 * application.</dd> |
182 * application.</dd> |
183 * |
183 * |
184 * <dt> <code>storePass</code> </dt> |
184 * <dt> {@code storePass} </dt> |
185 * <dd> if <code>true</code>, this module stores the username and password |
185 * <dd> if {@code true}, this module stores the username and password |
186 * obtained from the {@link CallbackHandler} in the module's shared state, |
186 * obtained from the {@link CallbackHandler} in the module's shared state, |
187 * using |
187 * using |
188 * "javax.security.auth.login.name" and |
188 * "javax.security.auth.login.name" and |
189 * "javax.security.auth.login.password" as the respective keys. This is |
189 * "javax.security.auth.login.password" as the respective keys. This is |
190 * not performed if existing values already exist for the username and |
190 * not performed if existing values already exist for the username and |
191 * password in the shared state, or if authentication fails.</dd> |
191 * password in the shared state, or if authentication fails.</dd> |
192 * |
192 * |
193 * <dt> <code>clearPass</code> </dt> |
193 * <dt> {@code clearPass} </dt> |
194 * <dd> if <code>true</code>, this module clears the username and password |
194 * <dd> if {@code true}, this module clears the username and password |
195 * stored in the module's shared state after both phases of authentication |
195 * stored in the module's shared state after both phases of authentication |
196 * (login and commit) have completed.</dd> |
196 * (login and commit) have completed.</dd> |
197 * |
197 * |
198 * <dt> <code>debug</code> </dt> |
198 * <dt> {@code debug} </dt> |
199 * <dd> if <code>true</code>, debug messages are displayed on the standard |
199 * <dd> if {@code true}, debug messages are displayed on the standard |
200 * output stream. |
200 * output stream. |
201 * </dl> |
201 * </dl> |
202 * </dl> |
202 * </dl> |
203 * |
203 * |
204 * <p> |
204 * <p> |
207 * may also be specified in the {@link Configuration}. |
207 * may also be specified in the {@link Configuration}. |
208 * They are added to the environment and passed to the LDAP provider. |
208 * They are added to the environment and passed to the LDAP provider. |
209 * Note that the following four JNDI properties are set by this module directly |
209 * Note that the following four JNDI properties are set by this module directly |
210 * and are ignored if also present in the configuration: |
210 * and are ignored if also present in the configuration: |
211 * <ul> |
211 * <ul> |
212 * <li> <code>java.naming.provider.url</code> |
212 * <li> {@code java.naming.provider.url} |
213 * <li> <code>java.naming.security.principal</code> |
213 * <li> {@code java.naming.security.principal} |
214 * <li> <code>java.naming.security.credentials</code> |
214 * <li> {@code java.naming.security.credentials} |
215 * <li> <code>java.naming.security.protocol</code> |
215 * <li> {@code java.naming.security.protocol} |
216 * </ul> |
216 * </ul> |
217 * |
217 * |
218 * <p> |
218 * <p> |
219 * Three sample {@link Configuration}s are shown below. |
219 * Three sample {@link Configuration}s are shown below. |
220 * The first one activates search-first mode. It identifies the LDAP server |
220 * The first one activates search-first mode. It identifies the LDAP server |
221 * and specifies that users' entries be located by their <code>uid</code> and |
221 * and specifies that users' entries be located by their {@code uid} and |
222 * <code>objectClass</code> attributes. It also specifies that an identity |
222 * {@code objectClass} attributes. It also specifies that an identity |
223 * based on the user's <code>employeeNumber</code> attribute should be created. |
223 * based on the user's {@code employeeNumber} attribute should be created. |
224 * The second one activates authentication-first mode. It requests that the |
224 * The second one activates authentication-first mode. It requests that the |
225 * LDAP server be located dynamically, that authentication be performed using |
225 * LDAP server be located dynamically, that authentication be performed using |
226 * the supplied username directly but without the protection of SSL and that |
226 * the supplied username directly but without the protection of SSL and that |
227 * users' entries be located by one of three naming attributes and their |
227 * users' entries be located by one of three naming attributes and their |
228 * <code>objectClass</code> attribute. |
228 * {@code objectClass} attribute. |
229 * The third one activates authentication-only mode. It identifies alternative |
229 * The third one activates authentication-only mode. It identifies alternative |
230 * LDAP servers, it specifies the distinguished name to use for |
230 * LDAP servers, it specifies the distinguished name to use for |
231 * authentication and a fixed identity to use for authorization. No directory |
231 * authentication and a fixed identity to use for authorization. No directory |
232 * search is performed. |
232 * search is performed. |
233 * |
233 * |
234 * <pre> |
234 * <pre>{@literal |
235 * |
235 * |
236 * ExampleApplication { |
236 * ExampleApplication { |
237 * com.sun.security.auth.module.LdapLoginModule REQUIRED |
237 * com.sun.security.auth.module.LdapLoginModule REQUIRED |
238 * userProvider="ldap://ldap-svr/ou=people,dc=example,dc=com" |
238 * userProvider="ldap://ldap-svr/ou=people,dc=example,dc=com" |
239 * userFilter="(&(uid={USERNAME})(objectClass=inetOrgPerson))" |
239 * userFilter="(&(uid={USERNAME})(objectClass=inetOrgPerson))" |
240 * authzIdentity="{EMPLOYEENUMBER}" |
240 * authzIdentity="{EMPLOYEENUMBER}" |
241 * debug=true; |
241 * debug=true; |
242 * }; |
242 * }; |
243 * |
243 * |
244 * ExampleApplication { |
244 * ExampleApplication { |
245 * com.sun.security.auth.module.LdapLoginModule REQUIRED |
245 * com.sun.security.auth.module.LdapLoginModule REQUIRED |
246 * userProvider="ldap:///cn=users,dc=example,dc=com" |
246 * userProvider="ldap:///cn=users,dc=example,dc=com" |
371 private Matcher filterMatcher = null; |
370 private Matcher filterMatcher = null; |
372 private Hashtable<String, Object> ldapEnvironment; |
371 private Hashtable<String, Object> ldapEnvironment; |
373 private SearchControls constraints = null; |
372 private SearchControls constraints = null; |
374 |
373 |
375 /** |
374 /** |
376 * Initialize this <code>LoginModule</code>. |
375 * Initialize this {@code LoginModule}. |
377 * |
376 * |
378 * @param subject the <code>Subject</code> to be authenticated. |
377 * @param subject the {@code Subject} to be authenticated. |
379 * @param callbackHandler a <code>CallbackHandler</code> to acquire the |
378 * @param callbackHandler a {@code CallbackHandler} to acquire the |
380 * username and password. |
379 * username and password. |
381 * @param sharedState shared <code>LoginModule</code> state. |
380 * @param sharedState shared {@code LoginModule} state. |
382 * @param options options specified in the login |
381 * @param options options specified in the login |
383 * <code>Configuration</code> for this particular |
382 * {@code Configuration} for this particular |
384 * <code>LoginModule</code>. |
383 * {@code LoginModule}. |
385 */ |
384 */ |
386 // Unchecked warning from (Map<String, Object>)sharedState is safe |
385 // Unchecked warning from (Map<String, Object>)sharedState is safe |
387 // since javax.security.auth.login.LoginContext passes a raw HashMap. |
386 // since javax.security.auth.login.LoginContext passes a raw HashMap. |
388 @SuppressWarnings("unchecked") |
387 @SuppressWarnings("unchecked") |
389 public void initialize(Subject subject, CallbackHandler callbackHandler, |
388 public void initialize(Subject subject, CallbackHandler callbackHandler, |