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