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.PwdEncryptor;
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
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 StringBundler sb = new StringBundler(4);
193
194 sb.append(StringPool.OPEN_CURLY_BRACE);
195 sb.append(algorithm);
196 sb.append(StringPool.CLOSE_CURLY_BRACE);
197 sb.append(
198 PwdEncryptor.encrypt(
199 algorithm, password, ldapPassword));
200
201 encryptedPassword = sb.toString();
202 }
203
204 if (ldapPassword.equals(encryptedPassword)) {
205 ldapAuthResult.setAuthenticated(true);
206 }
207 else {
208 ldapAuthResult.setAuthenticated(false);
209
210 if (_log.isWarnEnabled()) {
211 _log.warn(
212 "Passwords do not match for userDN " + userDN);
213 }
214 }
215 }
216 }
217
218 return ldapAuthResult;
219 }
220
221 protected int authenticate(
222 long companyId, long ldapServerId, String emailAddress,
223 String screenName, long userId, String password)
224 throws Exception {
225
226 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
227
228 LdapContext ldapContext = PortalLDAPUtil.getContext(
229 ldapServerId, companyId);
230
231 if (ldapContext == null) {
232 return FAILURE;
233 }
234
235 NamingEnumeration<SearchResult> enu = null;
236
237 try {
238 String baseDN = PrefsPropsUtil.getString(
239 companyId, PropsKeys.LDAP_BASE_DN + postfix);
240
241
242
243 String filter = LDAPSettingsUtil.getAuthSearchFilter(
244 ldapServerId, companyId, emailAddress, screenName,
245 String.valueOf(userId));
246
247 Properties userMappings = LDAPSettingsUtil.getUserMappings(
248 ldapServerId, companyId);
249
250 String userMappingsScreenName = GetterUtil.getString(
251 userMappings.getProperty("screenName")).toLowerCase();
252
253 SearchControls searchControls = new SearchControls(
254 SearchControls.SUBTREE_SCOPE, 1, 0,
255 new String[] {userMappingsScreenName}, false, false);
256
257 enu = ldapContext.search(baseDN, filter, searchControls);
258
259 if (enu.hasMoreElements()) {
260 if (_log.isDebugEnabled()) {
261 _log.debug("Search filter returned at least one result");
262 }
263
264 SearchResult result = enu.nextElement();
265
266 String fullUserDN = PortalLDAPUtil.getNameInNamespace(
267 ldapServerId, companyId, result);
268
269 Attributes attributes = PortalLDAPUtil.getUserAttributes(
270 ldapServerId, companyId, ldapContext, fullUserDN);
271
272 LDAPAuthResult ldapAuthResult = authenticate(
273 ldapContext, companyId, attributes, fullUserDN, password);
274
275
276
277 String errorMessage = ldapAuthResult.getErrorMessage();
278
279 if (errorMessage != null) {
280 int pos = errorMessage.indexOf(
281 PrefsPropsUtil.getString(
282 companyId, PropsKeys.LDAP_ERROR_USER_LOCKOUT));
283
284 if (pos != -1) {
285 throw new UserLockoutException();
286 }
287
288 pos = errorMessage.indexOf(
289 PrefsPropsUtil.getString(
290 companyId, PropsKeys.LDAP_ERROR_PASSWORD_EXPIRED));
291
292 if (pos != -1) {
293 throw new PasswordExpiredException();
294 }
295 }
296
297 if (!ldapAuthResult.isAuthenticated()) {
298 return FAILURE;
299 }
300
301
302
303 User user = PortalLDAPImporterUtil.importLDAPUser(
304 ldapServerId, companyId, ldapContext, attributes, password);
305
306
307
308 String resultCode = ldapAuthResult.getResponseControl();
309
310 if (resultCode.equals(LDAPAuth.RESULT_PASSWORD_RESET)) {
311 UserLocalServiceUtil.updatePasswordReset(
312 user.getUserId(), true);
313 }
314 }
315 else {
316 if (_log.isDebugEnabled()) {
317 _log.debug("Search filter did not return any results");
318 }
319
320 return DNE;
321 }
322 }
323 catch (Exception e) {
324 if (e instanceof PasswordExpiredException ||
325 e instanceof UserLockoutException) {
326
327 throw e;
328 }
329
330 _log.error("Problem accessing LDAP server", e);
331
332 return FAILURE;
333 }
334 finally {
335 if (enu != null) {
336 enu.close();
337 }
338
339 if (ldapContext != null) {
340 ldapContext.close();
341 }
342 }
343
344 return SUCCESS;
345 }
346
347 protected int authenticate(
348 long companyId, String emailAddress, String screenName, long userId,
349 String password)
350 throws Exception {
351
352 if (!AuthSettingsUtil.isLDAPAuthEnabled(companyId)) {
353 if (_log.isDebugEnabled()) {
354 _log.debug("Authenticator is not enabled");
355 }
356
357 return SUCCESS;
358 }
359
360 if (_log.isDebugEnabled()) {
361 _log.debug("Authenticator is enabled");
362 }
363
364 long[] ldapServerIds = StringUtil.split(
365 PrefsPropsUtil.getString(companyId, "ldap.server.ids"), 0L);
366
367 for (long ldapServerId : ldapServerIds) {
368 int result = authenticate(
369 companyId, ldapServerId, emailAddress, screenName, userId,
370 password);
371
372 if (result == SUCCESS) {
373 if (PrefsPropsUtil.getBoolean(
374 companyId,
375 PropsKeys.LDAP_IMPORT_USER_PASSWORD_ENABLED)) {
376
377 return result;
378 }
379
380 return Authenticator.SKIP_LIFERAY_CHECK;
381 }
382 }
383
384 for (int ldapServerId = 0;; ldapServerId++) {
385 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
386
387 String providerUrl = PrefsPropsUtil.getString(
388 companyId, PropsKeys.LDAP_BASE_PROVIDER_URL + postfix);
389
390 if (Validator.isNull(providerUrl)) {
391 break;
392 }
393
394 int result = authenticate(
395 companyId, ldapServerId, emailAddress, screenName, userId,
396 password);
397
398 if (result == SUCCESS) {
399 if (PrefsPropsUtil.getBoolean(
400 companyId,
401 PropsKeys.LDAP_IMPORT_USER_PASSWORD_ENABLED)) {
402
403 return result;
404 }
405
406 return Authenticator.SKIP_LIFERAY_CHECK;
407 }
408 }
409
410 return authenticateRequired(
411 companyId, userId, emailAddress, screenName, true, FAILURE);
412 }
413
414 protected int authenticateOmniadmin(
415 long companyId, String emailAddress, String screenName, long userId)
416 throws Exception {
417
418
419
420 if (PropsValues.AUTH_PIPELINE_ENABLE_LIFERAY_CHECK) {
421 if (userId > 0) {
422 if (OmniadminUtil.isOmniadmin(userId)) {
423 return SUCCESS;
424 }
425 }
426 else if (Validator.isNotNull(emailAddress)) {
427 try {
428 User user = UserLocalServiceUtil.getUserByEmailAddress(
429 companyId, emailAddress);
430
431 if (OmniadminUtil.isOmniadmin(user.getUserId())) {
432 return SUCCESS;
433 }
434 }
435 catch (NoSuchUserException nsue) {
436 }
437 }
438 else if (Validator.isNotNull(screenName)) {
439 try {
440 User user = UserLocalServiceUtil.getUserByScreenName(
441 companyId, screenName);
442
443 if (OmniadminUtil.isOmniadmin(user.getUserId())) {
444 return SUCCESS;
445 }
446 }
447 catch (NoSuchUserException nsue) {
448 }
449 }
450 }
451
452 return FAILURE;
453 }
454
455 protected int authenticateRequired(
456 long companyId, long userId, String emailAddress, String screenName,
457 boolean allowOmniadmin, int failureCode)
458 throws Exception {
459
460
461
462
463 if (allowOmniadmin &&
464 (authenticateOmniadmin(
465 companyId, emailAddress, screenName, userId) == SUCCESS)) {
466
467 return SUCCESS;
468 }
469
470 if (PrefsPropsUtil.getBoolean(
471 companyId, PropsKeys.LDAP_AUTH_REQUIRED)) {
472
473 return failureCode;
474 }
475 else {
476 return SUCCESS;
477 }
478 }
479
480 private static Log _log = LogFactoryUtil.getLog(LDAPAuth.class);
481
482 }