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.StringPool;
31 import com.liferay.portal.kernel.util.Validator;
32 import com.liferay.portal.model.User;
33 import com.liferay.portal.security.ldap.PortalLDAPUtil;
34 import com.liferay.portal.security.pwd.PwdEncryptor;
35 import com.liferay.portal.service.UserLocalServiceUtil;
36 import com.liferay.portal.util.PrefsPropsUtil;
37 import com.liferay.portal.util.PropsKeys;
38 import com.liferay.portal.util.PropsValues;
39 import com.liferay.portlet.admin.util.OmniadminUtil;
40
41 import java.util.Hashtable;
42 import java.util.Map;
43
44 import javax.naming.Context;
45 import javax.naming.NamingEnumeration;
46 import javax.naming.directory.Attribute;
47 import javax.naming.directory.Attributes;
48 import javax.naming.directory.SearchControls;
49 import javax.naming.directory.SearchResult;
50 import javax.naming.ldap.Control;
51 import javax.naming.ldap.InitialLdapContext;
52 import javax.naming.ldap.LdapContext;
53
54
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_RESET =
69 "2.16.840.1.113730.3.4.4";
70
71 public static final String RESULT_PASSWORD_EXP_WARNING =
72 "2.16.840.1.113730.3.4.5";
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 int authenticate(
124 long companyId, String emailAddress, String screenName, long userId,
125 String password)
126 throws Exception {
127
128 if (!PortalLDAPUtil.isAuthEnabled(companyId)) {
129 if (_log.isDebugEnabled()) {
130 _log.debug("Authenticator is not enabled");
131 }
132
133 return SUCCESS;
134 }
135
136 if (_log.isDebugEnabled()) {
137 _log.debug("Authenticator is enabled");
138 }
139
140 LdapContext ctx = PortalLDAPUtil.getContext(companyId);
141
142 if (ctx == null) {
143 return authenticateRequired(
144 companyId, userId, emailAddress, screenName, true, FAILURE);
145 }
146
147 try {
148 String baseDN = PrefsPropsUtil.getString(
149 companyId, PropsKeys.LDAP_BASE_DN);
150
151
153 String filter = PortalLDAPUtil.getAuthSearchFilter(
154 companyId, emailAddress, screenName, String.valueOf(userId));
155
156 SearchControls cons = new SearchControls(
157 SearchControls.SUBTREE_SCOPE, 1, 0, null, false, false);
158
159 NamingEnumeration<SearchResult> enu = ctx.search(
160 baseDN, filter, cons);
161
162 if (enu.hasMoreElements()) {
163 if (_log.isDebugEnabled()) {
164 _log.debug("Search filter returned at least one result");
165 }
166
167 SearchResult result = enu.nextElement();
168
169 String fullUserDN = PortalLDAPUtil.getNameInNamespace(
170 companyId, result);
171
172 Attributes attrs = PortalLDAPUtil.getUserAttributes(
173 companyId, ctx, fullUserDN);
174
175 LDAPAuthResult ldapAuthResult = authenticate(
176 ctx, companyId, attrs, fullUserDN, password);
177
178
180 String errorMessage = ldapAuthResult.getErrorMessage();
181
182 if (errorMessage != null) {
183 if (errorMessage.indexOf(PrefsPropsUtil.getString(
184 companyId, PropsKeys.LDAP_ERROR_USER_LOCKOUT))
185 != -1) {
186
187 throw new UserLockoutException();
188 }
189 else if (errorMessage.indexOf(PrefsPropsUtil.getString(
190 companyId, PropsKeys.LDAP_ERROR_PASSWORD_EXPIRED))
191 != -1) {
192
193 throw new PasswordExpiredException();
194 }
195 }
196
197 if (!ldapAuthResult.isAuthenticated()) {
198 return authenticateRequired(
199 companyId, userId, emailAddress, screenName, false,
200 FAILURE);
201 }
202
203
205 User user = PortalLDAPUtil.importLDAPUser(
206 companyId, ctx, attrs, password, true);
207
208
210 String resultCode = ldapAuthResult.getResponseControl();
211
212 if (resultCode.equals(LDAPAuth.RESULT_PASSWORD_RESET)) {
213 UserLocalServiceUtil.updatePasswordReset(
214 user.getUserId(), true);
215 }
216 else if (
217 resultCode.equals(LDAPAuth.RESULT_PASSWORD_EXP_WARNING)) {
218
219 UserLocalServiceUtil.updatePasswordReset(
220 user.getUserId(), true);
221 }
222 }
223 else {
224 if (_log.isDebugEnabled()) {
225 _log.debug("Search filter did not return any results");
226 }
227
228 return authenticateRequired(
229 companyId, userId, emailAddress, screenName, true, DNE);
230 }
231
232 enu.close();
233 }
234 catch (Exception e) {
235 _log.error("Problem accessing LDAP server: " + e.getMessage());
236
237 int authResult = authenticateRequired(
238 companyId, userId, emailAddress, screenName, true, FAILURE);
239
240 if (authResult == FAILURE) {
241 throw e;
242 }
243 }
244 finally {
245 if (ctx != null) {
246 ctx.close();
247 }
248 }
249
250 return SUCCESS;
251 }
252
253 protected LDAPAuthResult authenticate(
254 LdapContext ctx, long companyId, Attributes attrs, String userDN,
255 String password)
256 throws Exception {
257
258 LDAPAuthResult ldapAuthResult = new LDAPAuthResult();
259
260
264 String authMethod = PrefsPropsUtil.getString(
265 companyId, PropsKeys.LDAP_AUTH_METHOD);
266 InitialLdapContext innerCtx = null;
267
268 if (authMethod.equals(AUTH_METHOD_BIND)) {
269 try {
270 Hashtable<String, Object> env =
271 (Hashtable<String, Object>)ctx.getEnvironment();
272
273 env.put(Context.SECURITY_PRINCIPAL, userDN);
274 env.put(Context.SECURITY_CREDENTIALS, password);
275 env.put(
276 Context.REFERRAL,
277 PrefsPropsUtil.getString(
278 companyId, PropsKeys.LDAP_REFERRAL));
279
280
282 env.put("com.sun.jndi.ldap.connect.pool", "false");
283
284 innerCtx = new InitialLdapContext(env, null);
285
286
288 Control[] responseControls = innerCtx.getResponseControls();
289
290 ldapAuthResult.setAuthenticated(true);
291 ldapAuthResult.setResponseControl(responseControls);
292 }
293 catch (Exception e) {
294 if (_log.isDebugEnabled()) {
295 _log.debug(
296 "Failed to bind to the LDAP server with userDN "
297 + userDN + " and password " + password);
298 }
299
300 _log.error(
301 "Failed to bind to the LDAP server: " + e.getMessage());
302
303 ldapAuthResult.setAuthenticated(false);
304 ldapAuthResult.setErrorMessage(e.getMessage());
305 }
306 finally {
307 if (innerCtx != null) {
308 innerCtx.close();
309 }
310 }
311 }
312 else if (authMethod.equals(AUTH_METHOD_PASSWORD_COMPARE)) {
313 Attribute userPassword = attrs.get("userPassword");
314
315 if (userPassword != null) {
316 String ldapPassword = new String((byte[])userPassword.get());
317
318 String encryptedPassword = password;
319
320 String algorithm = PrefsPropsUtil.getString(
321 companyId,
322 PropsKeys.LDAP_AUTH_PASSWORD_ENCRYPTION_ALGORITHM);
323
324 if (Validator.isNotNull(algorithm)) {
325 encryptedPassword =
326 "{" + algorithm + "}" +
327 PwdEncryptor.encrypt(
328 algorithm, password, ldapPassword);
329 }
330
331 if (ldapPassword.equals(encryptedPassword)) {
332 ldapAuthResult.setAuthenticated(true);
333 }
334 else {
335 ldapAuthResult.setAuthenticated(false);
336
337 if (_log.isWarnEnabled()) {
338 _log.warn(
339 "Passwords do not match for userDN " + userDN);
340 }
341 }
342 }
343 }
344
345 return ldapAuthResult;
346 }
347
348 protected int authenticateOmniadmin(
349 long companyId, String emailAddress, String screenName, long userId)
350 throws Exception {
351
352
354 if (PropsValues.AUTH_PIPELINE_ENABLE_LIFERAY_CHECK) {
355 if (userId > 0) {
356 if (OmniadminUtil.isOmniadmin(userId)) {
357 return SUCCESS;
358 }
359 }
360 else if (Validator.isNotNull(emailAddress)) {
361 try {
362 User user = UserLocalServiceUtil.getUserByEmailAddress(
363 companyId, emailAddress);
364
365 if (OmniadminUtil.isOmniadmin(user.getUserId())) {
366 return SUCCESS;
367 }
368 }
369 catch (NoSuchUserException nsue) {
370 }
371 }
372 else if (Validator.isNotNull(screenName)) {
373 try {
374 User user = UserLocalServiceUtil.getUserByScreenName(
375 companyId, screenName);
376
377 if (OmniadminUtil.isOmniadmin(user.getUserId())) {
378 return SUCCESS;
379 }
380 }
381 catch (NoSuchUserException nsue) {
382 }
383 }
384 }
385
386 return FAILURE;
387 }
388
389 protected int authenticateRequired(
390 long companyId, long userId, String emailAddress, String screenName,
391 boolean allowOmniadmin, int failureCode)
392 throws Exception {
393
394
397 if (allowOmniadmin &&
398 (authenticateOmniadmin(
399 companyId, emailAddress, screenName, userId) == SUCCESS)) {
400
401 return SUCCESS;
402 }
403
404 if (PrefsPropsUtil.getBoolean(
405 companyId, PropsKeys.LDAP_AUTH_REQUIRED)) {
406
407 return failureCode;
408 }
409 else {
410 return SUCCESS;
411 }
412 }
413
414 private static Log _log = LogFactoryUtil.getLog(LDAPAuth.class);
415
416 }