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 e);
167 }
168
169 ldapAuthResult.setAuthenticated(false);
170 ldapAuthResult.setErrorMessage(e.getMessage());
171 }
172 finally {
173 if (innerCtx != null) {
174 innerCtx.close();
175 }
176 }
177 }
178 else if (authMethod.equals(AUTH_METHOD_PASSWORD_COMPARE)) {
179 Attribute userPassword = attributes.get("userPassword");
180
181 if (userPassword != null) {
182 String ldapPassword = new String((byte[])userPassword.get());
183
184 String encryptedPassword = password;
185
186 String algorithm = PrefsPropsUtil.getString(
187 companyId,
188 PropsKeys.LDAP_AUTH_PASSWORD_ENCRYPTION_ALGORITHM);
189
190 if (Validator.isNotNull(algorithm)) {
191 encryptedPassword = PasswordEncryptorUtil.encrypt(
192 algorithm, password, ldapPassword);
193 }
194
195 if (ldapPassword.equals(encryptedPassword)) {
196 ldapAuthResult.setAuthenticated(true);
197 }
198 else {
199 ldapAuthResult.setAuthenticated(false);
200
201 if (_log.isDebugEnabled()) {
202 _log.debug(
203 "Passwords do not match for userDN " + userDN);
204 }
205 }
206 }
207 }
208
209 return ldapAuthResult;
210 }
211
212 protected int authenticate(
213 long ldapServerId, long companyId, String emailAddress,
214 String screenName, long userId, String password)
215 throws Exception {
216
217 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
218
219 LdapContext ldapContext = PortalLDAPUtil.getContext(
220 ldapServerId, companyId);
221
222 if (ldapContext == null) {
223 return FAILURE;
224 }
225
226 NamingEnumeration<SearchResult> enu = null;
227
228 try {
229 String baseDN = PrefsPropsUtil.getString(
230 companyId, PropsKeys.LDAP_BASE_DN + postfix);
231
232
233
234 String filter = LDAPSettingsUtil.getAuthSearchFilter(
235 ldapServerId, companyId, emailAddress, screenName,
236 String.valueOf(userId));
237
238 Properties userMappings = LDAPSettingsUtil.getUserMappings(
239 ldapServerId, companyId);
240
241 String userMappingsScreenName = GetterUtil.getString(
242 userMappings.getProperty("screenName"));
243
244 userMappingsScreenName = StringUtil.toLowerCase(
245 userMappingsScreenName);
246
247 SearchControls searchControls = new SearchControls(
248 SearchControls.SUBTREE_SCOPE, 1, 0,
249 new String[] {userMappingsScreenName}, false, false);
250
251 enu = ldapContext.search(baseDN, filter, searchControls);
252
253 if (enu.hasMoreElements()) {
254 if (_log.isDebugEnabled()) {
255 _log.debug("Search filter returned at least one result");
256 }
257
258 SearchResult result = enu.nextElement();
259
260 String fullUserDN = PortalLDAPUtil.getNameInNamespace(
261 ldapServerId, companyId, result);
262
263 Attributes attributes = PortalLDAPUtil.getUserAttributes(
264 ldapServerId, companyId, ldapContext, fullUserDN);
265
266 LDAPAuthResult ldapAuthResult = authenticate(
267 ldapContext, companyId, attributes, fullUserDN, password);
268
269
270
271 String errorMessage = ldapAuthResult.getErrorMessage();
272
273 if (errorMessage != null) {
274 int pos = errorMessage.indexOf(
275 PrefsPropsUtil.getString(
276 companyId, PropsKeys.LDAP_ERROR_USER_LOCKOUT));
277
278 if (pos != -1) {
279 throw new UserLockoutException();
280 }
281
282 pos = errorMessage.indexOf(
283 PrefsPropsUtil.getString(
284 companyId, PropsKeys.LDAP_ERROR_PASSWORD_EXPIRED));
285
286 if (pos != -1) {
287 throw new PasswordExpiredException();
288 }
289 }
290
291 if (!ldapAuthResult.isAuthenticated()) {
292 return FAILURE;
293 }
294
295
296
297 User user = PortalLDAPImporterUtil.importLDAPUser(
298 ldapServerId, companyId, ldapContext, attributes, password);
299
300
301
302 String resultCode = ldapAuthResult.getResponseControl();
303
304 if (resultCode.equals(LDAPAuth.RESULT_PASSWORD_RESET)) {
305 UserLocalServiceUtil.updatePasswordReset(
306 user.getUserId(), true);
307 }
308 }
309 else {
310 if (_log.isDebugEnabled()) {
311 _log.debug("Search filter did not return any results");
312 }
313
314 return DNE;
315 }
316 }
317 catch (Exception e) {
318 if (e instanceof PasswordExpiredException ||
319 e instanceof UserLockoutException) {
320
321 throw e;
322 }
323
324 _log.error("Problem accessing LDAP server", e);
325
326 return FAILURE;
327 }
328 finally {
329 if (enu != null) {
330 enu.close();
331 }
332
333 if (ldapContext != null) {
334 ldapContext.close();
335 }
336 }
337
338 return SUCCESS;
339 }
340
341 protected int authenticate(
342 long companyId, String emailAddress, String screenName, long userId,
343 String password)
344 throws Exception {
345
346 if (!AuthSettingsUtil.isLDAPAuthEnabled(companyId)) {
347 if (_log.isDebugEnabled()) {
348 _log.debug("Authenticator is not enabled");
349 }
350
351 return SUCCESS;
352 }
353
354 if (_log.isDebugEnabled()) {
355 _log.debug("Authenticator is enabled");
356 }
357
358 int preferredLDAPServerResult = authenticateAgainstPreferredLDAPServer(
359 companyId, emailAddress, screenName, userId, password);
360
361 if (preferredLDAPServerResult == SUCCESS) {
362 if (PrefsPropsUtil.getBoolean(
363 companyId, PropsKeys.LDAP_IMPORT_USER_PASSWORD_ENABLED)) {
364
365 return preferredLDAPServerResult;
366 }
367
368 return Authenticator.SKIP_LIFERAY_CHECK;
369 }
370
371 long[] ldapServerIds = StringUtil.split(
372 PrefsPropsUtil.getString(companyId, "ldap.server.ids"), 0L);
373
374 for (long ldapServerId : ldapServerIds) {
375 int result = authenticate(
376 ldapServerId, companyId, emailAddress, screenName, userId,
377 password);
378
379 if (result == SUCCESS) {
380 if (PrefsPropsUtil.getBoolean(
381 companyId,
382 PropsKeys.LDAP_IMPORT_USER_PASSWORD_ENABLED)) {
383
384 return result;
385 }
386
387 return Authenticator.SKIP_LIFERAY_CHECK;
388 }
389 }
390
391 for (int ldapServerId = 0;; ldapServerId++) {
392 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
393
394 String providerUrl = PrefsPropsUtil.getString(
395 companyId, PropsKeys.LDAP_BASE_PROVIDER_URL + postfix);
396
397 if (Validator.isNull(providerUrl)) {
398 break;
399 }
400
401 int result = authenticate(
402 ldapServerId, companyId, emailAddress, screenName, userId,
403 password);
404
405 if (result == SUCCESS) {
406 if (PrefsPropsUtil.getBoolean(
407 companyId,
408 PropsKeys.LDAP_IMPORT_USER_PASSWORD_ENABLED)) {
409
410 return result;
411 }
412
413 return Authenticator.SKIP_LIFERAY_CHECK;
414 }
415 }
416
417 return authenticateRequired(
418 companyId, userId, emailAddress, screenName, true, FAILURE);
419 }
420
421 protected int authenticateAgainstPreferredLDAPServer(
422 long companyId, String emailAddress, String screenName, long userId,
423 String password)
424 throws Exception {
425
426 int result = DNE;
427
428 User user = null;
429
430 try {
431 if (userId > 0) {
432 user = UserLocalServiceUtil.getUserById(companyId, userId);
433 }
434 else if (Validator.isNotNull(emailAddress)) {
435 user = UserLocalServiceUtil.getUserByEmailAddress(
436 companyId, emailAddress);
437 }
438 else if (Validator.isNotNull(screenName)) {
439 user = UserLocalServiceUtil.getUserByScreenName(
440 companyId, screenName);
441 }
442 else {
443 if (_log.isDebugEnabled()) {
444 _log.debug("Unable to get preferred LDAP server");
445 }
446
447 return result;
448 }
449 }
450 catch (NoSuchUserException nsue) {
451 if (_log.isDebugEnabled()) {
452 _log.debug("Unable to get preferred LDAP server", nsue);
453 }
454
455 return result;
456 }
457
458 long ldapServerId = user.getLdapServerId();
459
460 if (ldapServerId < 0) {
461 return result;
462 }
463
464 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
465
466 String providerUrl = PrefsPropsUtil.getString(
467 user.getCompanyId(), PropsKeys.LDAP_BASE_PROVIDER_URL + postfix);
468
469 if (Validator.isNull(providerUrl)) {
470 return result;
471 }
472
473 if (_log.isDebugEnabled()) {
474 _log.debug(
475 "Using LDAP server ID " + ldapServerId +
476 " to authenticate user " + user.getUserId());
477 }
478
479 result = authenticate(
480 ldapServerId, companyId, emailAddress, screenName, userId,
481 password);
482
483 return result;
484 }
485
486 protected int authenticateOmniadmin(
487 long companyId, String emailAddress, String screenName, long userId)
488 throws Exception {
489
490
491
492 if (!PropsValues.AUTH_PIPELINE_ENABLE_LIFERAY_CHECK) {
493 return FAILURE;
494 }
495
496 if (userId > 0) {
497 if (OmniadminUtil.isOmniadmin(userId)) {
498 return SUCCESS;
499 }
500 }
501 else if (Validator.isNotNull(emailAddress)) {
502 User user = UserLocalServiceUtil.fetchUserByEmailAddress(
503 companyId, emailAddress);
504
505 if (user != null) {
506 if (OmniadminUtil.isOmniadmin(user)) {
507 return SUCCESS;
508 }
509 }
510 }
511 else if (Validator.isNotNull(screenName)) {
512 User user = UserLocalServiceUtil.fetchUserByScreenName(
513 companyId, screenName);
514
515 if (user != null) {
516 if (OmniadminUtil.isOmniadmin(user)) {
517 return SUCCESS;
518 }
519 }
520 }
521
522 return FAILURE;
523 }
524
525 protected int authenticateRequired(
526 long companyId, long userId, String emailAddress, String screenName,
527 boolean allowOmniadmin, int failureCode)
528 throws Exception {
529
530
531
532
533 if (allowOmniadmin &&
534 (authenticateOmniadmin(
535 companyId, emailAddress, screenName, userId) == SUCCESS)) {
536
537 return SUCCESS;
538 }
539
540 if (PrefsPropsUtil.getBoolean(
541 companyId, PropsKeys.LDAP_AUTH_REQUIRED)) {
542
543 return failureCode;
544 }
545 else {
546 return SUCCESS;
547 }
548 }
549
550 private static Log _log = LogFactoryUtil.getLog(LDAPAuth.class);
551
552 }