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 public int authenticateByEmailAddress(
070 long companyId, String emailAddress, String password,
071 Map<String, String[]> headerMap, Map<String, String[]> parameterMap)
072 throws AuthException {
073
074 try {
075 return authenticate(
076 companyId, emailAddress, StringPool.BLANK, 0, password);
077 }
078 catch (Exception e) {
079 _log.error(e, e);
080
081 throw new AuthException(e);
082 }
083 }
084
085 public int authenticateByScreenName(
086 long companyId, String screenName, String password,
087 Map<String, String[]> headerMap, Map<String, String[]> parameterMap)
088 throws AuthException {
089
090 try {
091 return authenticate(
092 companyId, StringPool.BLANK, screenName, 0, password);
093 }
094 catch (Exception e) {
095 _log.error(e, e);
096
097 throw new AuthException(e);
098 }
099 }
100
101 public int authenticateByUserId(
102 long companyId, long userId, String password,
103 Map<String, String[]> headerMap, Map<String, String[]> parameterMap)
104 throws AuthException {
105
106 try {
107 return authenticate(
108 companyId, StringPool.BLANK, StringPool.BLANK, userId,
109 password);
110 }
111 catch (Exception e) {
112 _log.error(e, e);
113
114 throw new AuthException(e);
115 }
116 }
117
118 protected LDAPAuthResult authenticate(
119 LdapContext ctx, long companyId, Attributes attributes,
120 String userDN, String password)
121 throws Exception {
122
123 LDAPAuthResult ldapAuthResult = new LDAPAuthResult();
124
125
126
127
128
129 String authMethod = PrefsPropsUtil.getString(
130 companyId, PropsKeys.LDAP_AUTH_METHOD);
131 InitialLdapContext innerCtx = null;
132
133 if (authMethod.equals(AUTH_METHOD_BIND)) {
134 try {
135 Hashtable<String, Object> env =
136 (Hashtable<String, Object>)ctx.getEnvironment();
137
138 env.put(Context.SECURITY_PRINCIPAL, userDN);
139 env.put(Context.SECURITY_CREDENTIALS, password);
140 env.put(
141 Context.REFERRAL,
142 PrefsPropsUtil.getString(
143 companyId, PropsKeys.LDAP_REFERRAL));
144
145
146
147 env.put("com.sun.jndi.ldap.connect.pool", "false");
148
149 innerCtx = new InitialLdapContext(env, null);
150
151
152
153 Control[] responseControls = innerCtx.getResponseControls();
154
155 ldapAuthResult.setAuthenticated(true);
156 ldapAuthResult.setResponseControl(responseControls);
157 }
158 catch (Exception e) {
159 if (_log.isDebugEnabled()) {
160 _log.debug(
161 "Failed to bind to the LDAP server with userDN " +
162 userDN + " and password " + password);
163 }
164
165 _log.error("Failed to bind to the LDAP server", e);
166
167 ldapAuthResult.setAuthenticated(false);
168 ldapAuthResult.setErrorMessage(e.getMessage());
169 }
170 finally {
171 if (innerCtx != null) {
172 innerCtx.close();
173 }
174 }
175 }
176 else if (authMethod.equals(AUTH_METHOD_PASSWORD_COMPARE)) {
177 Attribute userPassword = attributes.get("userPassword");
178
179 if (userPassword != null) {
180 String ldapPassword = new String((byte[])userPassword.get());
181
182 String encryptedPassword = password;
183
184 String algorithm = PrefsPropsUtil.getString(
185 companyId,
186 PropsKeys.LDAP_AUTH_PASSWORD_ENCRYPTION_ALGORITHM);
187
188 if (Validator.isNotNull(algorithm)) {
189 StringBundler sb = new StringBundler(4);
190
191 sb.append(StringPool.OPEN_CURLY_BRACE);
192 sb.append(algorithm);
193 sb.append(StringPool.CLOSE_CURLY_BRACE);
194 sb.append(
195 PwdEncryptor.encrypt(
196 algorithm, password, ldapPassword));
197
198 encryptedPassword = sb.toString();
199 }
200
201 if (ldapPassword.equals(encryptedPassword)) {
202 ldapAuthResult.setAuthenticated(true);
203 }
204 else {
205 ldapAuthResult.setAuthenticated(false);
206
207 if (_log.isWarnEnabled()) {
208 _log.warn(
209 "Passwords do not match for userDN " + userDN);
210 }
211 }
212 }
213 }
214
215 return ldapAuthResult;
216 }
217
218 protected int authenticate(
219 long companyId, long ldapServerId, String emailAddress,
220 String screenName, long userId, String password)
221 throws Exception {
222
223 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
224
225 LdapContext ldapContext = PortalLDAPUtil.getContext(
226 ldapServerId, companyId);
227
228 if (ldapContext == null) {
229 return FAILURE;
230 }
231
232 NamingEnumeration<SearchResult> enu = null;
233
234 try {
235 String baseDN = PrefsPropsUtil.getString(
236 companyId, PropsKeys.LDAP_BASE_DN + postfix);
237
238
239
240 String filter = LDAPSettingsUtil.getAuthSearchFilter(
241 ldapServerId, companyId, emailAddress, screenName,
242 String.valueOf(userId));
243
244 Properties userMappings = LDAPSettingsUtil.getUserMappings(
245 ldapServerId, companyId);
246
247 String userMappingsScreenName = GetterUtil.getString(
248 userMappings.getProperty("screenName")).toLowerCase();
249
250 SearchControls searchControls = new SearchControls(
251 SearchControls.SUBTREE_SCOPE, 1, 0,
252 new String[] {userMappingsScreenName}, false, false);
253
254 enu = ldapContext.search(baseDN, filter, searchControls);
255
256 if (enu.hasMoreElements()) {
257 if (_log.isDebugEnabled()) {
258 _log.debug("Search filter returned at least one result");
259 }
260
261 SearchResult result = enu.nextElement();
262
263 String fullUserDN = PortalLDAPUtil.getNameInNamespace(
264 ldapServerId, companyId, result);
265
266 Attributes attributes = PortalLDAPUtil.getUserAttributes(
267 ldapServerId, companyId, ldapContext, fullUserDN);
268
269 LDAPAuthResult ldapAuthResult = authenticate(
270 ldapContext, companyId, attributes, fullUserDN, password);
271
272
273
274 String errorMessage = ldapAuthResult.getErrorMessage();
275
276 if (errorMessage != null) {
277 int pos = errorMessage.indexOf(
278 PrefsPropsUtil.getString(
279 companyId, PropsKeys.LDAP_ERROR_USER_LOCKOUT));
280
281 if (pos != -1) {
282 throw new UserLockoutException();
283 }
284
285 pos = errorMessage.indexOf(
286 PrefsPropsUtil.getString(
287 companyId, PropsKeys.LDAP_ERROR_PASSWORD_EXPIRED));
288
289 if (pos != -1) {
290 throw new PasswordExpiredException();
291 }
292 }
293
294 if (!ldapAuthResult.isAuthenticated()) {
295 return FAILURE;
296 }
297
298
299
300 User user = PortalLDAPImporterUtil.importLDAPUser(
301 ldapServerId, companyId, ldapContext, attributes, password);
302
303
304
305 String resultCode = ldapAuthResult.getResponseControl();
306
307 if (resultCode.equals(LDAPAuth.RESULT_PASSWORD_RESET)) {
308 UserLocalServiceUtil.updatePasswordReset(
309 user.getUserId(), true);
310 }
311 }
312 else {
313 if (_log.isDebugEnabled()) {
314 _log.debug("Search filter did not return any results");
315 }
316
317 return DNE;
318 }
319 }
320 catch (Exception e) {
321 if (e instanceof PasswordExpiredException ||
322 e instanceof UserLockoutException) {
323
324 throw e;
325 }
326
327 _log.error("Problem accessing LDAP server", e);
328
329 return FAILURE;
330 }
331 finally {
332 if (enu != null) {
333 enu.close();
334 }
335
336 if (ldapContext != null) {
337 ldapContext.close();
338 }
339 }
340
341 return SUCCESS;
342 }
343
344 protected int authenticate(
345 long companyId, String emailAddress, String screenName, long userId,
346 String password)
347 throws Exception {
348
349 if (!AuthSettingsUtil.isLDAPAuthEnabled(companyId)) {
350 if (_log.isDebugEnabled()) {
351 _log.debug("Authenticator is not enabled");
352 }
353
354 return SUCCESS;
355 }
356
357 if (_log.isDebugEnabled()) {
358 _log.debug("Authenticator is enabled");
359 }
360
361 long[] ldapServerIds = StringUtil.split(
362 PrefsPropsUtil.getString(companyId, "ldap.server.ids"), 0L);
363
364 for (long ldapServerId : ldapServerIds) {
365 int result = authenticate(
366 companyId, ldapServerId, emailAddress, screenName, userId,
367 password);
368
369 if (result == SUCCESS) {
370 return result;
371 }
372 }
373
374 for (int ldapServerId = 0;; ldapServerId++) {
375 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
376
377 String providerUrl = PrefsPropsUtil.getString(
378 companyId, PropsKeys.LDAP_BASE_PROVIDER_URL + postfix);
379
380 if (Validator.isNull(providerUrl)) {
381 break;
382 }
383
384 int result = authenticate(
385 companyId, ldapServerId, emailAddress, screenName, userId,
386 password);
387
388 if (result == SUCCESS) {
389 return result;
390 }
391 }
392
393 return authenticateRequired(
394 companyId, userId, emailAddress, screenName, true, FAILURE);
395 }
396
397 protected int authenticateOmniadmin(
398 long companyId, String emailAddress, String screenName, long userId)
399 throws Exception {
400
401
402
403 if (PropsValues.AUTH_PIPELINE_ENABLE_LIFERAY_CHECK) {
404 if (userId > 0) {
405 if (OmniadminUtil.isOmniadmin(userId)) {
406 return SUCCESS;
407 }
408 }
409 else if (Validator.isNotNull(emailAddress)) {
410 try {
411 User user = UserLocalServiceUtil.getUserByEmailAddress(
412 companyId, emailAddress);
413
414 if (OmniadminUtil.isOmniadmin(user.getUserId())) {
415 return SUCCESS;
416 }
417 }
418 catch (NoSuchUserException nsue) {
419 }
420 }
421 else if (Validator.isNotNull(screenName)) {
422 try {
423 User user = UserLocalServiceUtil.getUserByScreenName(
424 companyId, screenName);
425
426 if (OmniadminUtil.isOmniadmin(user.getUserId())) {
427 return SUCCESS;
428 }
429 }
430 catch (NoSuchUserException nsue) {
431 }
432 }
433 }
434
435 return FAILURE;
436 }
437
438 protected int authenticateRequired(
439 long companyId, long userId, String emailAddress, String screenName,
440 boolean allowOmniadmin, int failureCode)
441 throws Exception {
442
443
444
445
446 if (allowOmniadmin &&
447 (authenticateOmniadmin(
448 companyId, emailAddress, screenName, userId) == SUCCESS)) {
449
450 return SUCCESS;
451 }
452
453 if (PrefsPropsUtil.getBoolean(
454 companyId, PropsKeys.LDAP_AUTH_REQUIRED)) {
455
456 return failureCode;
457 }
458 else {
459 return SUCCESS;
460 }
461 }
462
463 private static Log _log = LogFactoryUtil.getLog(LDAPAuth.class);
464
465 }