1
22
23 package com.liferay.portal.security.auth;
24
25 import com.liferay.portal.NoSuchUserException;
26 import com.liferay.portal.PasswordExpiredException;
27 import com.liferay.portal.UserLockoutException;
28 import com.liferay.portal.kernel.log.Log;
29 import com.liferay.portal.kernel.log.LogFactoryUtil;
30 import com.liferay.portal.kernel.util.PropsKeys;
31 import com.liferay.portal.kernel.util.StringPool;
32 import com.liferay.portal.kernel.util.StringUtil;
33 import com.liferay.portal.kernel.util.Validator;
34 import com.liferay.portal.model.User;
35 import com.liferay.portal.security.ldap.PortalLDAPUtil;
36 import com.liferay.portal.security.pwd.PwdEncryptor;
37 import com.liferay.portal.service.UserLocalServiceUtil;
38 import com.liferay.portal.util.PrefsPropsUtil;
39 import com.liferay.portal.util.PropsValues;
40 import com.liferay.portlet.admin.util.OmniadminUtil;
41
42 import java.util.Hashtable;
43 import java.util.Map;
44
45 import javax.naming.Context;
46 import javax.naming.NamingEnumeration;
47 import javax.naming.directory.Attribute;
48 import javax.naming.directory.Attributes;
49 import javax.naming.directory.SearchControls;
50 import javax.naming.directory.SearchResult;
51 import javax.naming.ldap.Control;
52 import javax.naming.ldap.InitialLdapContext;
53 import javax.naming.ldap.LdapContext;
54
55
61 public class LDAPAuth implements Authenticator {
62
63 public static final String AUTH_METHOD_BIND = "bind";
64
65 public static final String AUTH_METHOD_PASSWORD_COMPARE =
66 "password-compare";
67
68 public static final String RESULT_PASSWORD_EXP_WARNING =
69 "2.16.840.1.113730.3.4.5";
70
71 public static final String RESULT_PASSWORD_RESET =
72 "2.16.840.1.113730.3.4.4";
73
74 public int authenticateByEmailAddress(
75 long companyId, String emailAddress, String password,
76 Map<String, String[]> headerMap, Map<String, String[]> parameterMap)
77 throws AuthException {
78
79 try {
80 return authenticate(
81 companyId, emailAddress, StringPool.BLANK, 0, password);
82 }
83 catch (Exception e) {
84 _log.error(e, e);
85
86 throw new AuthException(e);
87 }
88 }
89
90 public int authenticateByScreenName(
91 long companyId, String screenName, String password,
92 Map<String, String[]> headerMap, Map<String, String[]> parameterMap)
93 throws AuthException {
94
95 try {
96 return authenticate(
97 companyId, StringPool.BLANK, screenName, 0, password);
98 }
99 catch (Exception e) {
100 _log.error(e, e);
101
102 throw new AuthException(e);
103 }
104 }
105
106 public int authenticateByUserId(
107 long companyId, long userId, String password,
108 Map<String, String[]> headerMap, Map<String, String[]> parameterMap)
109 throws AuthException {
110
111 try {
112 return authenticate(
113 companyId, StringPool.BLANK, StringPool.BLANK, userId,
114 password);
115 }
116 catch (Exception e) {
117 _log.error(e, e);
118
119 throw new AuthException(e);
120 }
121 }
122
123 protected LDAPAuthResult authenticate(
124 LdapContext ctx, long companyId, Attributes attrs, String userDN,
125 String password)
126 throws Exception {
127
128 LDAPAuthResult ldapAuthResult = new LDAPAuthResult();
129
130
134 String authMethod = PrefsPropsUtil.getString(
135 companyId, PropsKeys.LDAP_AUTH_METHOD);
136 InitialLdapContext innerCtx = null;
137
138 if (authMethod.equals(AUTH_METHOD_BIND)) {
139 try {
140 Hashtable<String, Object> env =
141 (Hashtable<String, Object>)ctx.getEnvironment();
142
143 env.put(Context.SECURITY_PRINCIPAL, userDN);
144 env.put(Context.SECURITY_CREDENTIALS, password);
145 env.put(
146 Context.REFERRAL,
147 PrefsPropsUtil.getString(
148 companyId, PropsKeys.LDAP_REFERRAL));
149
150
152 env.put("com.sun.jndi.ldap.connect.pool", "false");
153
154 innerCtx = new InitialLdapContext(env, null);
155
156
158 Control[] responseControls = innerCtx.getResponseControls();
159
160 ldapAuthResult.setAuthenticated(true);
161 ldapAuthResult.setResponseControl(responseControls);
162 }
163 catch (Exception e) {
164 if (_log.isDebugEnabled()) {
165 _log.debug(
166 "Failed to bind to the LDAP server with userDN "
167 + userDN + " and password " + password);
168 }
169
170 _log.error(
171 "Failed to bind to the LDAP server: " + e.getMessage());
172
173 ldapAuthResult.setAuthenticated(false);
174 ldapAuthResult.setErrorMessage(e.getMessage());
175 }
176 finally {
177 if (innerCtx != null) {
178 innerCtx.close();
179 }
180 }
181 }
182 else if (authMethod.equals(AUTH_METHOD_PASSWORD_COMPARE)) {
183 Attribute userPassword = attrs.get("userPassword");
184
185 if (userPassword != null) {
186 String ldapPassword = new String((byte[])userPassword.get());
187
188 String encryptedPassword = password;
189
190 String algorithm = PrefsPropsUtil.getString(
191 companyId,
192 PropsKeys.LDAP_AUTH_PASSWORD_ENCRYPTION_ALGORITHM);
193
194 if (Validator.isNotNull(algorithm)) {
195 encryptedPassword =
196 "{" + algorithm + "}" +
197 PwdEncryptor.encrypt(
198 algorithm, password, ldapPassword);
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 = PortalLDAPUtil.getPropertyPostfix(ldapServerId);
224
225 LdapContext ctx = PortalLDAPUtil.getContext(ldapServerId, companyId);
226
227 if (ctx == null) {
228 return FAILURE;
229 }
230
231 try {
232 String baseDN = PrefsPropsUtil.getString(
233 companyId, PropsKeys.LDAP_BASE_DN + postfix);
234
235
237 String filter = PortalLDAPUtil.getAuthSearchFilter(
238 ldapServerId, companyId, emailAddress, screenName,
239 String.valueOf(userId));
240
241 SearchControls cons = new SearchControls(
242 SearchControls.SUBTREE_SCOPE, 1, 0, null, false, false);
243
244 NamingEnumeration<SearchResult> enu = ctx.search(
245 baseDN, filter, cons);
246
247 if (enu.hasMoreElements()) {
248 if (_log.isDebugEnabled()) {
249 _log.debug("Search filter returned at least one result");
250 }
251
252 SearchResult result = enu.nextElement();
253
254 String fullUserDN = PortalLDAPUtil.getNameInNamespace(
255 ldapServerId, companyId, result);
256
257 Attributes attrs = PortalLDAPUtil.getUserAttributes(
258 ldapServerId, companyId, ctx, fullUserDN);
259
260 LDAPAuthResult ldapAuthResult = authenticate(
261 ctx, companyId, attrs, fullUserDN, password);
262
263
265 String errorMessage = ldapAuthResult.getErrorMessage();
266
267 if (errorMessage != null) {
268 if (errorMessage.indexOf(PrefsPropsUtil.getString(
269 companyId, PropsKeys.LDAP_ERROR_USER_LOCKOUT))
270 != -1) {
271
272 throw new UserLockoutException();
273 }
274 else if (errorMessage.indexOf(PrefsPropsUtil.getString(
275 companyId, PropsKeys.LDAP_ERROR_PASSWORD_EXPIRED))
276 != -1) {
277
278 throw new PasswordExpiredException();
279 }
280 }
281
282 if (!ldapAuthResult.isAuthenticated()) {
283 return FAILURE;
284 }
285
286
288 User user = PortalLDAPUtil.importLDAPUser(
289 ldapServerId, companyId, ctx, attrs, password, true);
290
291
293 String resultCode = ldapAuthResult.getResponseControl();
294
295 if (resultCode.equals(LDAPAuth.RESULT_PASSWORD_RESET)) {
296 UserLocalServiceUtil.updatePasswordReset(
297 user.getUserId(), true);
298 }
299 else if (
300 resultCode.equals(LDAPAuth.RESULT_PASSWORD_EXP_WARNING)) {
301
302 UserLocalServiceUtil.updatePasswordReset(
303 user.getUserId(), true);
304 }
305 }
306 else {
307 if (_log.isDebugEnabled()) {
308 _log.debug("Search filter did not return any results");
309 }
310
311 return DNE;
312 }
313
314 enu.close();
315 }
316 catch (Exception e) {
317 _log.error("Problem accessing LDAP server: " + e.getMessage());
318
319 return FAILURE;
320 }
321 finally {
322 if (ctx != null) {
323 ctx.close();
324 }
325 }
326
327 return SUCCESS;
328 }
329
330 protected int authenticate(
331 long companyId, String emailAddress, String screenName, long userId,
332 String password)
333 throws Exception {
334
335 if (!PortalLDAPUtil.isAuthEnabled(companyId)) {
336 if (_log.isDebugEnabled()) {
337 _log.debug("Authenticator is not enabled");
338 }
339
340 return SUCCESS;
341 }
342
343 if (_log.isDebugEnabled()) {
344 _log.debug("Authenticator is enabled");
345 }
346
347 long[] ldapServerIds = StringUtil.split(
348 PrefsPropsUtil.getString(companyId, "ldap.server.ids"), 0L);
349
350 if (ldapServerIds.length <= 0) {
351 ldapServerIds = new long[] {0};
352 }
353
354 for (long ldapServerId : ldapServerIds) {
355 int result = authenticate(
356 companyId, ldapServerId, emailAddress, screenName, userId,
357 password);
358
359 if (result == SUCCESS) {
360 return result;
361 }
362 }
363
364 return authenticateRequired(
365 companyId, userId, emailAddress, screenName, true, FAILURE);
366 }
367
368 protected int authenticateOmniadmin(
369 long companyId, String emailAddress, String screenName, long userId)
370 throws Exception {
371
372
374 if (PropsValues.AUTH_PIPELINE_ENABLE_LIFERAY_CHECK) {
375 if (userId > 0) {
376 if (OmniadminUtil.isOmniadmin(userId)) {
377 return SUCCESS;
378 }
379 }
380 else if (Validator.isNotNull(emailAddress)) {
381 try {
382 User user = UserLocalServiceUtil.getUserByEmailAddress(
383 companyId, emailAddress);
384
385 if (OmniadminUtil.isOmniadmin(user.getUserId())) {
386 return SUCCESS;
387 }
388 }
389 catch (NoSuchUserException nsue) {
390 }
391 }
392 else if (Validator.isNotNull(screenName)) {
393 try {
394 User user = UserLocalServiceUtil.getUserByScreenName(
395 companyId, screenName);
396
397 if (OmniadminUtil.isOmniadmin(user.getUserId())) {
398 return SUCCESS;
399 }
400 }
401 catch (NoSuchUserException nsue) {
402 }
403 }
404 }
405
406 return FAILURE;
407 }
408
409 protected int authenticateRequired(
410 long companyId, long userId, String emailAddress, String screenName,
411 boolean allowOmniadmin, int failureCode)
412 throws Exception {
413
414
417 if (allowOmniadmin &&
418 (authenticateOmniadmin(
419 companyId, emailAddress, screenName, userId) == SUCCESS)) {
420
421 return SUCCESS;
422 }
423
424 if (PrefsPropsUtil.getBoolean(
425 companyId, PropsKeys.LDAP_AUTH_REQUIRED)) {
426
427 return failureCode;
428 }
429 else {
430 return SUCCESS;
431 }
432 }
433
434 private static Log _log = LogFactoryUtil.getLog(LDAPAuth.class);
435
436 }