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
60 public class LDAPAuth implements Authenticator {
61
62 public static final String AUTH_METHOD_BIND = "bind";
63
64 public static final String AUTH_METHOD_PASSWORD_COMPARE =
65 "password-compare";
66
67 public static final String RESULT_PASSWORD_RESET =
68 "2.16.840.1.113730.3.4.4";
69
70 public static final String RESULT_PASSWORD_EXP_WARNING =
71 "2.16.840.1.113730.3.4.5";
72
73 public int authenticateByEmailAddress(
74 long companyId, String emailAddress, String password,
75 Map<String, String[]> headerMap, Map<String, String[]> parameterMap)
76 throws AuthException {
77
78 try {
79 return authenticate(
80 companyId, emailAddress, StringPool.BLANK, 0, password);
81 }
82 catch (Exception e) {
83 _log.error(e, e);
84
85 throw new AuthException(e);
86 }
87 }
88
89 public int authenticateByScreenName(
90 long companyId, String screenName, String password,
91 Map<String, String[]> headerMap, Map<String, String[]> parameterMap)
92 throws AuthException {
93
94 try {
95 return authenticate(
96 companyId, StringPool.BLANK, screenName, 0, password);
97 }
98 catch (Exception e) {
99 _log.error(e, e);
100
101 throw new AuthException(e);
102 }
103 }
104
105 public int authenticateByUserId(
106 long companyId, long userId, String password,
107 Map<String, String[]> headerMap, Map<String, String[]> parameterMap)
108 throws AuthException {
109
110 try {
111 return authenticate(
112 companyId, StringPool.BLANK, StringPool.BLANK, userId,
113 password);
114 }
115 catch (Exception e) {
116 _log.error(e, e);
117
118 throw new AuthException(e);
119 }
120 }
121
122 protected int authenticate(
123 long companyId, String emailAddress, String screenName, long userId,
124 String password)
125 throws Exception {
126
127 if (!PortalLDAPUtil.isAuthEnabled(companyId)) {
128 if (_log.isDebugEnabled()) {
129 _log.debug("Authenticator is not enabled");
130 }
131
132 return SUCCESS;
133 }
134
135 if (_log.isDebugEnabled()) {
136 _log.debug("Authenticator is enabled");
137 }
138
139 LdapContext ctx = PortalLDAPUtil.getContext(companyId);
140
141 if (ctx == null) {
142 return authenticateRequired(
143 companyId, userId, emailAddress, screenName, true, FAILURE);
144 }
145
146 try {
147 String baseDN = PrefsPropsUtil.getString(
148 companyId, PropsKeys.LDAP_BASE_DN);
149
150
152 String filter = PortalLDAPUtil.getAuthSearchFilter(
153 companyId, emailAddress, screenName, String.valueOf(userId));
154
155 SearchControls cons = new SearchControls(
156 SearchControls.SUBTREE_SCOPE, 1, 0, null, false, false);
157
158 NamingEnumeration<SearchResult> enu = ctx.search(
159 baseDN, filter, cons);
160
161 if (enu.hasMoreElements()) {
162 if (_log.isDebugEnabled()) {
163 _log.debug("Search filter returned at least one result");
164 }
165
166 SearchResult result = enu.nextElement();
167
168 String fullUserDN = PortalLDAPUtil.getNameInNamespace(
169 companyId, result);
170
171 Attributes attrs = PortalLDAPUtil.getUserAttributes(
172 companyId, ctx, fullUserDN);
173
174 LDAPAuthResult ldapAuthResult = authenticate(
175 ctx, companyId, attrs, fullUserDN, password);
176
177
179 String errorMessage = ldapAuthResult.getErrorMessage();
180
181 if (errorMessage != null) {
182 if (errorMessage.indexOf(PrefsPropsUtil.getString(
183 companyId, PropsKeys.LDAP_ERROR_USER_LOCKOUT))
184 != -1) {
185
186 throw new UserLockoutException();
187 }
188 else if (errorMessage.indexOf(PrefsPropsUtil.getString(
189 companyId, PropsKeys.LDAP_ERROR_PASSWORD_EXPIRED))
190 != -1) {
191
192 throw new PasswordExpiredException();
193 }
194 }
195
196 if (!ldapAuthResult.isAuthenticated()) {
197 return authenticateRequired(
198 companyId, userId, emailAddress, screenName, false,
199 FAILURE);
200 }
201
202
204 User user = PortalLDAPUtil.importLDAPUser(
205 companyId, ctx, attrs, password, true);
206
207
209 String resultCode = ldapAuthResult.getResponseControl();
210
211 if (resultCode.equals(LDAPAuth.RESULT_PASSWORD_RESET)) {
212 UserLocalServiceUtil.updatePasswordReset(
213 user.getUserId(), true);
214 }
215 else if (
216 resultCode.equals(LDAPAuth.RESULT_PASSWORD_EXP_WARNING)) {
217
218 UserLocalServiceUtil.updatePasswordReset(
219 user.getUserId(), true);
220 }
221 }
222 else {
223 if (_log.isDebugEnabled()) {
224 _log.debug("Search filter did not return any results");
225 }
226
227 return authenticateRequired(
228 companyId, userId, emailAddress, screenName, true, DNE);
229 }
230
231 enu.close();
232 }
233 catch (Exception e) {
234 _log.error("Problem accessing LDAP server: " + e.getMessage());
235
236 int authResult = authenticateRequired(
237 companyId, userId, emailAddress, screenName, true, FAILURE);
238
239 if (authResult == FAILURE) {
240 throw e;
241 }
242 }
243 finally {
244 if (ctx != null) {
245 ctx.close();
246 }
247 }
248
249 return SUCCESS;
250 }
251
252 protected LDAPAuthResult authenticate(
253 LdapContext ctx, long companyId, Attributes attrs, String userDN,
254 String password)
255 throws Exception {
256
257 LDAPAuthResult ldapAuthResult = new LDAPAuthResult();
258
259
263 String authMethod = PrefsPropsUtil.getString(
264 companyId, PropsKeys.LDAP_AUTH_METHOD);
265 InitialLdapContext innerCtx = null;
266
267 if (authMethod.equals(AUTH_METHOD_BIND)) {
268 try {
269 Hashtable<String, Object> env =
270 (Hashtable<String, Object>)ctx.getEnvironment();
271
272 env.put(Context.SECURITY_PRINCIPAL, userDN);
273 env.put(Context.SECURITY_CREDENTIALS, password);
274 env.put(
275 Context.REFERRAL,
276 PrefsPropsUtil.getString(
277 companyId, PropsKeys.LDAP_REFERRAL));
278
279
281 env.put("com.sun.jndi.ldap.connect.pool", "false");
282
283 innerCtx = new InitialLdapContext(env, null);
284
285
287 Control[] responseControls = innerCtx.getResponseControls();
288
289 ldapAuthResult.setAuthenticated(true);
290 ldapAuthResult.setResponseControl(responseControls);
291 }
292 catch (Exception e) {
293 if (_log.isDebugEnabled()) {
294 _log.debug(
295 "Failed to bind to the LDAP server with userDN "
296 + userDN + " and password " + password);
297 }
298
299 _log.error(
300 "Failed to bind to the LDAP server: " + e.getMessage());
301
302 ldapAuthResult.setAuthenticated(false);
303 ldapAuthResult.setErrorMessage(e.getMessage());
304 }
305 finally {
306 if (innerCtx != null) {
307 innerCtx.close();
308 }
309 }
310 }
311 else if (authMethod.equals(AUTH_METHOD_PASSWORD_COMPARE)) {
312 Attribute userPassword = attrs.get("userPassword");
313
314 if (userPassword != null) {
315 String ldapPassword = new String((byte[])userPassword.get());
316
317 String encryptedPassword = password;
318
319 String algorithm = PrefsPropsUtil.getString(
320 companyId,
321 PropsKeys.LDAP_AUTH_PASSWORD_ENCRYPTION_ALGORITHM);
322
323 if (Validator.isNotNull(algorithm)) {
324 encryptedPassword =
325 "{" + algorithm + "}" +
326 PwdEncryptor.encrypt(
327 algorithm, password, ldapPassword);
328 }
329
330 if (ldapPassword.equals(encryptedPassword)) {
331 ldapAuthResult.setAuthenticated(true);
332 }
333 else {
334 ldapAuthResult.setAuthenticated(false);
335
336 if (_log.isWarnEnabled()) {
337 _log.warn(
338 "Passwords do not match for userDN " + userDN);
339 }
340 }
341 }
342 }
343
344 return ldapAuthResult;
345 }
346
347 protected int authenticateOmniadmin(
348 long companyId, String emailAddress, String screenName, long userId)
349 throws Exception {
350
351
353 if (PropsValues.AUTH_PIPELINE_ENABLE_LIFERAY_CHECK) {
354 if (userId > 0) {
355 if (OmniadminUtil.isOmniadmin(userId)) {
356 return SUCCESS;
357 }
358 }
359 else if (Validator.isNotNull(emailAddress)) {
360 try {
361 User user = UserLocalServiceUtil.getUserByEmailAddress(
362 companyId, emailAddress);
363
364 if (OmniadminUtil.isOmniadmin(user.getUserId())) {
365 return SUCCESS;
366 }
367 }
368 catch (NoSuchUserException nsue) {
369 }
370 }
371 else if (Validator.isNotNull(screenName)) {
372 try {
373 User user = UserLocalServiceUtil.getUserByScreenName(
374 companyId, screenName);
375
376 if (OmniadminUtil.isOmniadmin(user.getUserId())) {
377 return SUCCESS;
378 }
379 }
380 catch (NoSuchUserException nsue) {
381 }
382 }
383 }
384
385 return FAILURE;
386 }
387
388 protected int authenticateRequired(
389 long companyId, long userId, String emailAddress, String screenName,
390 boolean allowOmniadmin, int failureCode)
391 throws Exception {
392
393
396 if (allowOmniadmin &&
397 (authenticateOmniadmin(
398 companyId, emailAddress, screenName, userId) == SUCCESS)) {
399
400 return SUCCESS;
401 }
402
403 if (PrefsPropsUtil.getBoolean(
404 companyId, PropsKeys.LDAP_AUTH_REQUIRED)) {
405
406 return failureCode;
407 }
408 else {
409 return SUCCESS;
410 }
411 }
412
413 private static Log _log = LogFactoryUtil.getLog(LDAPAuth.class);
414
415 }