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