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