001
014
015 package com.liferay.portal.security.auth;
016
017 import com.liferay.portal.NoSuchUserException;
018 import com.liferay.portal.PasswordExpiredException;
019 import com.liferay.portal.UserLockoutException;
020 import com.liferay.portal.kernel.log.Log;
021 import com.liferay.portal.kernel.log.LogFactoryUtil;
022 import com.liferay.portal.kernel.util.GetterUtil;
023 import com.liferay.portal.kernel.util.PropsKeys;
024 import com.liferay.portal.kernel.util.StringPool;
025 import com.liferay.portal.kernel.util.StringUtil;
026 import com.liferay.portal.kernel.util.Validator;
027 import com.liferay.portal.model.User;
028 import com.liferay.portal.security.ldap.LDAPSettingsUtil;
029 import com.liferay.portal.security.ldap.PortalLDAPImporterUtil;
030 import com.liferay.portal.security.ldap.PortalLDAPUtil;
031 import com.liferay.portal.security.pwd.PasswordEncryptorUtil;
032 import com.liferay.portal.service.UserLocalServiceUtil;
033 import com.liferay.portal.util.PrefsPropsUtil;
034 import com.liferay.portal.util.PropsValues;
035 import com.liferay.portlet.admin.util.OmniadminUtil;
036
037 import java.util.Hashtable;
038 import java.util.Map;
039 import java.util.Properties;
040
041 import javax.naming.Context;
042 import javax.naming.NamingEnumeration;
043 import javax.naming.directory.Attribute;
044 import javax.naming.directory.Attributes;
045 import javax.naming.directory.SearchControls;
046 import javax.naming.directory.SearchResult;
047 import javax.naming.ldap.Control;
048 import javax.naming.ldap.InitialLdapContext;
049 import javax.naming.ldap.LdapContext;
050
051
056 public class LDAPAuth implements Authenticator {
057
058 public static final String AUTH_METHOD_BIND = "bind";
059
060 public static final String AUTH_METHOD_PASSWORD_COMPARE =
061 "password-compare";
062
063 public static final String RESULT_PASSWORD_EXP_WARNING =
064 "2.16.840.1.113730.3.4.5";
065
066 public static final String RESULT_PASSWORD_RESET =
067 "2.16.840.1.113730.3.4.4";
068
069 @Override
070 public int authenticateByEmailAddress(
071 long companyId, String emailAddress, String password,
072 Map<String, String[]> headerMap, Map<String, String[]> parameterMap)
073 throws AuthException {
074
075 try {
076 return authenticate(
077 companyId, emailAddress, StringPool.BLANK, 0, password);
078 }
079 catch (Exception e) {
080 _log.error(e, e);
081
082 throw new AuthException(e);
083 }
084 }
085
086 @Override
087 public int authenticateByScreenName(
088 long companyId, String screenName, String password,
089 Map<String, String[]> headerMap, Map<String, String[]> parameterMap)
090 throws AuthException {
091
092 try {
093 return authenticate(
094 companyId, StringPool.BLANK, screenName, 0, password);
095 }
096 catch (Exception e) {
097 _log.error(e, e);
098
099 throw new AuthException(e);
100 }
101 }
102
103 @Override
104 public int authenticateByUserId(
105 long companyId, long userId, String password,
106 Map<String, String[]> headerMap, Map<String, String[]> parameterMap)
107 throws AuthException {
108
109 try {
110 return authenticate(
111 companyId, StringPool.BLANK, StringPool.BLANK, userId,
112 password);
113 }
114 catch (Exception e) {
115 _log.error(e, e);
116
117 throw new AuthException(e);
118 }
119 }
120
121 protected LDAPAuthResult authenticate(
122 LdapContext ctx, long companyId, Attributes attributes,
123 String userDN, String password)
124 throws Exception {
125
126 LDAPAuthResult ldapAuthResult = new LDAPAuthResult();
127
128
129
130
131
132 String authMethod = PrefsPropsUtil.getString(
133 companyId, PropsKeys.LDAP_AUTH_METHOD);
134 InitialLdapContext innerCtx = null;
135
136 if (authMethod.equals(AUTH_METHOD_BIND)) {
137 try {
138 Hashtable<String, Object> env =
139 (Hashtable<String, Object>)ctx.getEnvironment();
140
141 env.put(Context.SECURITY_PRINCIPAL, userDN);
142 env.put(Context.SECURITY_CREDENTIALS, password);
143 env.put(
144 Context.REFERRAL,
145 PrefsPropsUtil.getString(
146 companyId, PropsKeys.LDAP_REFERRAL));
147
148
149
150 env.put("com.sun.jndi.ldap.connect.pool", "false");
151
152 innerCtx = new InitialLdapContext(env, null);
153
154
155
156 Control[] responseControls = innerCtx.getResponseControls();
157
158 ldapAuthResult.setAuthenticated(true);
159 ldapAuthResult.setResponseControl(responseControls);
160 }
161 catch (Exception e) {
162 if (_log.isDebugEnabled()) {
163 _log.debug(
164 "Failed to bind to the LDAP server with userDN " +
165 userDN + " and password " + password);
166 }
167
168 _log.error("Failed to bind to the LDAP server", e);
169
170 ldapAuthResult.setAuthenticated(false);
171 ldapAuthResult.setErrorMessage(e.getMessage());
172 }
173 finally {
174 if (innerCtx != null) {
175 innerCtx.close();
176 }
177 }
178 }
179 else if (authMethod.equals(AUTH_METHOD_PASSWORD_COMPARE)) {
180 Attribute userPassword = attributes.get("userPassword");
181
182 if (userPassword != null) {
183 String ldapPassword = new String((byte[])userPassword.get());
184
185 String encryptedPassword = password;
186
187 String algorithm = PrefsPropsUtil.getString(
188 companyId,
189 PropsKeys.LDAP_AUTH_PASSWORD_ENCRYPTION_ALGORITHM);
190
191 if (Validator.isNotNull(algorithm)) {
192 encryptedPassword = PasswordEncryptorUtil.encrypt(
193 algorithm, password, ldapPassword);
194 }
195
196 if (ldapPassword.equals(encryptedPassword)) {
197 ldapAuthResult.setAuthenticated(true);
198 }
199 else {
200 ldapAuthResult.setAuthenticated(false);
201
202 if (_log.isWarnEnabled()) {
203 _log.warn(
204 "Passwords do not match for userDN " + userDN);
205 }
206 }
207 }
208 }
209
210 return ldapAuthResult;
211 }
212
213 protected int authenticate(
214 long ldapServerId, long companyId, String emailAddress,
215 String screenName, long userId, String password)
216 throws Exception {
217
218 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
219
220 LdapContext ldapContext = PortalLDAPUtil.getContext(
221 ldapServerId, companyId);
222
223 if (ldapContext == null) {
224 return FAILURE;
225 }
226
227 NamingEnumeration<SearchResult> enu = null;
228
229 try {
230 String baseDN = PrefsPropsUtil.getString(
231 companyId, PropsKeys.LDAP_BASE_DN + postfix);
232
233
234
235 String filter = LDAPSettingsUtil.getAuthSearchFilter(
236 ldapServerId, companyId, emailAddress, screenName,
237 String.valueOf(userId));
238
239 Properties userMappings = LDAPSettingsUtil.getUserMappings(
240 ldapServerId, companyId);
241
242 String userMappingsScreenName = GetterUtil.getString(
243 userMappings.getProperty("screenName")).toLowerCase();
244
245 SearchControls searchControls = new SearchControls(
246 SearchControls.SUBTREE_SCOPE, 1, 0,
247 new String[] {userMappingsScreenName}, false, false);
248
249 enu = ldapContext.search(baseDN, filter, searchControls);
250
251 if (enu.hasMoreElements()) {
252 if (_log.isDebugEnabled()) {
253 _log.debug("Search filter returned at least one result");
254 }
255
256 SearchResult result = enu.nextElement();
257
258 String fullUserDN = PortalLDAPUtil.getNameInNamespace(
259 ldapServerId, companyId, result);
260
261 Attributes attributes = PortalLDAPUtil.getUserAttributes(
262 ldapServerId, companyId, ldapContext, fullUserDN);
263
264 LDAPAuthResult ldapAuthResult = authenticate(
265 ldapContext, companyId, attributes, fullUserDN, password);
266
267
268
269 String errorMessage = ldapAuthResult.getErrorMessage();
270
271 if (errorMessage != null) {
272 int pos = errorMessage.indexOf(
273 PrefsPropsUtil.getString(
274 companyId, PropsKeys.LDAP_ERROR_USER_LOCKOUT));
275
276 if (pos != -1) {
277 throw new UserLockoutException();
278 }
279
280 pos = errorMessage.indexOf(
281 PrefsPropsUtil.getString(
282 companyId, PropsKeys.LDAP_ERROR_PASSWORD_EXPIRED));
283
284 if (pos != -1) {
285 throw new PasswordExpiredException();
286 }
287 }
288
289 if (!ldapAuthResult.isAuthenticated()) {
290 return FAILURE;
291 }
292
293
294
295 User user = PortalLDAPImporterUtil.importLDAPUser(
296 ldapServerId, companyId, ldapContext, attributes, password);
297
298
299
300 String resultCode = ldapAuthResult.getResponseControl();
301
302 if (resultCode.equals(LDAPAuth.RESULT_PASSWORD_RESET)) {
303 UserLocalServiceUtil.updatePasswordReset(
304 user.getUserId(), true);
305 }
306 }
307 else {
308 if (_log.isDebugEnabled()) {
309 _log.debug("Search filter did not return any results");
310 }
311
312 return DNE;
313 }
314 }
315 catch (Exception e) {
316 if (e instanceof PasswordExpiredException ||
317 e instanceof UserLockoutException) {
318
319 throw e;
320 }
321
322 _log.error("Problem accessing LDAP server", e);
323
324 return FAILURE;
325 }
326 finally {
327 if (enu != null) {
328 enu.close();
329 }
330
331 if (ldapContext != null) {
332 ldapContext.close();
333 }
334 }
335
336 return SUCCESS;
337 }
338
339 protected int authenticate(
340 long companyId, String emailAddress, String screenName, long userId,
341 String password)
342 throws Exception {
343
344 if (!AuthSettingsUtil.isLDAPAuthEnabled(companyId)) {
345 if (_log.isDebugEnabled()) {
346 _log.debug("Authenticator is not enabled");
347 }
348
349 return SUCCESS;
350 }
351
352 if (_log.isDebugEnabled()) {
353 _log.debug("Authenticator is enabled");
354 }
355
356 int preferredLDAPServerResult = authenticateAgainstPreferredLDAPServer(
357 companyId, emailAddress, screenName, userId, password);
358
359 if (preferredLDAPServerResult == SUCCESS) {
360 if (PrefsPropsUtil.getBoolean(
361 companyId, PropsKeys.LDAP_IMPORT_USER_PASSWORD_ENABLED)) {
362
363 return preferredLDAPServerResult;
364 }
365
366 return Authenticator.SKIP_LIFERAY_CHECK;
367 }
368
369 long[] ldapServerIds = StringUtil.split(
370 PrefsPropsUtil.getString(companyId, "ldap.server.ids"), 0L);
371
372 for (long ldapServerId : ldapServerIds) {
373 int result = authenticate(
374 ldapServerId, companyId, emailAddress, screenName, userId,
375 password);
376
377 if (result == SUCCESS) {
378 if (PrefsPropsUtil.getBoolean(
379 companyId,
380 PropsKeys.LDAP_IMPORT_USER_PASSWORD_ENABLED)) {
381
382 return result;
383 }
384
385 return Authenticator.SKIP_LIFERAY_CHECK;
386 }
387 }
388
389 for (int ldapServerId = 0;; ldapServerId++) {
390 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
391
392 String providerUrl = PrefsPropsUtil.getString(
393 companyId, PropsKeys.LDAP_BASE_PROVIDER_URL + postfix);
394
395 if (Validator.isNull(providerUrl)) {
396 break;
397 }
398
399 int result = authenticate(
400 ldapServerId, companyId, emailAddress, screenName, userId,
401 password);
402
403 if (result == SUCCESS) {
404 if (PrefsPropsUtil.getBoolean(
405 companyId,
406 PropsKeys.LDAP_IMPORT_USER_PASSWORD_ENABLED)) {
407
408 return result;
409 }
410
411 return Authenticator.SKIP_LIFERAY_CHECK;
412 }
413 }
414
415 return authenticateRequired(
416 companyId, userId, emailAddress, screenName, true, FAILURE);
417 }
418
419 protected int authenticateAgainstPreferredLDAPServer(
420 long companyId, String emailAddress, String screenName, long userId,
421 String password)
422 throws Exception {
423
424 int result = DNE;
425
426 User user = null;
427
428 try {
429 if (userId > 0) {
430 user = UserLocalServiceUtil.getUserById(companyId, userId);
431 }
432 else if (Validator.isNotNull(emailAddress)) {
433 user = UserLocalServiceUtil.getUserByEmailAddress(
434 companyId, emailAddress);
435 }
436 else if (Validator.isNotNull(screenName)) {
437 user = UserLocalServiceUtil.getUserByScreenName(
438 companyId, screenName);
439 }
440 else {
441 if (_log.isDebugEnabled()) {
442 _log.debug("Unable to get preferred LDAP server");
443 }
444
445 return result;
446 }
447 }
448 catch (NoSuchUserException nsue) {
449 if (_log.isDebugEnabled()) {
450 _log.debug("Unable to get preferred LDAP server", nsue);
451 }
452
453 return result;
454 }
455
456 long ldapServerId = user.getLdapServerId();
457
458 if (ldapServerId < 0) {
459 return result;
460 }
461
462 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
463
464 String providerUrl = PrefsPropsUtil.getString(
465 user.getCompanyId(), PropsKeys.LDAP_BASE_PROVIDER_URL + postfix);
466
467 if (Validator.isNull(providerUrl)) {
468 return result;
469 }
470
471 if (_log.isDebugEnabled()) {
472 _log.debug(
473 "Using LDAP server ID " + ldapServerId +
474 " to authenticate user " + user.getUserId());
475 }
476
477 result = authenticate(
478 ldapServerId, companyId, emailAddress, screenName, userId,
479 password);
480
481 return result;
482 }
483
484 protected int authenticateOmniadmin(
485 long companyId, String emailAddress, String screenName, long userId)
486 throws Exception {
487
488
489
490 if (!PropsValues.AUTH_PIPELINE_ENABLE_LIFERAY_CHECK) {
491 return FAILURE;
492 }
493
494 if (userId > 0) {
495 if (OmniadminUtil.isOmniadmin(userId)) {
496 return SUCCESS;
497 }
498 }
499 else if (Validator.isNotNull(emailAddress)) {
500 User user = UserLocalServiceUtil.fetchUserByEmailAddress(
501 companyId, emailAddress);
502
503 if (user != null) {
504 if (OmniadminUtil.isOmniadmin(user)) {
505 return SUCCESS;
506 }
507 }
508 }
509 else if (Validator.isNotNull(screenName)) {
510 User user = UserLocalServiceUtil.fetchUserByScreenName(
511 companyId, screenName);
512
513 if (user != null) {
514 if (OmniadminUtil.isOmniadmin(user)) {
515 return SUCCESS;
516 }
517 }
518 }
519
520 return FAILURE;
521 }
522
523 protected int authenticateRequired(
524 long companyId, long userId, String emailAddress, String screenName,
525 boolean allowOmniadmin, int failureCode)
526 throws Exception {
527
528
529
530
531 if (allowOmniadmin &&
532 (authenticateOmniadmin(
533 companyId, emailAddress, screenName, userId) == SUCCESS)) {
534
535 return SUCCESS;
536 }
537
538 if (PrefsPropsUtil.getBoolean(
539 companyId, PropsKeys.LDAP_AUTH_REQUIRED)) {
540
541 return failureCode;
542 }
543 else {
544 return SUCCESS;
545 }
546 }
547
548 private static Log _log = LogFactoryUtil.getLog(LDAPAuth.class);
549
550 }