1
14
15 package com.liferay.portal.security.auth;
16
17 import com.liferay.portal.NoSuchUserException;
18 import com.liferay.portal.PasswordExpiredException;
19 import com.liferay.portal.UserLockoutException;
20 import com.liferay.portal.kernel.log.Log;
21 import com.liferay.portal.kernel.log.LogFactoryUtil;
22 import com.liferay.portal.kernel.util.PropsKeys;
23 import com.liferay.portal.kernel.util.StringPool;
24 import com.liferay.portal.kernel.util.Validator;
25 import com.liferay.portal.model.User;
26 import com.liferay.portal.security.ldap.PortalLDAPUtil;
27 import com.liferay.portal.security.pwd.PwdEncryptor;
28 import com.liferay.portal.service.UserLocalServiceUtil;
29 import com.liferay.portal.util.PrefsPropsUtil;
30 import com.liferay.portal.util.PropsValues;
31 import com.liferay.portlet.admin.util.OmniadminUtil;
32
33 import java.util.Hashtable;
34 import java.util.Map;
35
36 import javax.naming.Context;
37 import javax.naming.NamingEnumeration;
38 import javax.naming.directory.Attribute;
39 import javax.naming.directory.Attributes;
40 import javax.naming.directory.SearchControls;
41 import javax.naming.directory.SearchResult;
42 import javax.naming.ldap.Control;
43 import javax.naming.ldap.InitialLdapContext;
44 import javax.naming.ldap.LdapContext;
45
46
52 public class LDAPAuth implements Authenticator {
53
54 public static final String AUTH_METHOD_BIND = "bind";
55
56 public static final String AUTH_METHOD_PASSWORD_COMPARE =
57 "password-compare";
58
59 public static final String RESULT_PASSWORD_EXP_WARNING =
60 "2.16.840.1.113730.3.4.5";
61
62 public static final String RESULT_PASSWORD_RESET =
63 "2.16.840.1.113730.3.4.4";
64
65 public int authenticateByEmailAddress(
66 long companyId, String emailAddress, String password,
67 Map<String, String[]> headerMap, Map<String, String[]> parameterMap)
68 throws AuthException {
69
70 try {
71 return authenticate(
72 companyId, emailAddress, StringPool.BLANK, 0, password);
73 }
74 catch (Exception e) {
75 _log.error(e, e);
76
77 throw new AuthException(e);
78 }
79 }
80
81 public int authenticateByScreenName(
82 long companyId, String screenName, String password,
83 Map<String, String[]> headerMap, Map<String, String[]> parameterMap)
84 throws AuthException {
85
86 try {
87 return authenticate(
88 companyId, StringPool.BLANK, screenName, 0, password);
89 }
90 catch (Exception e) {
91 _log.error(e, e);
92
93 throw new AuthException(e);
94 }
95 }
96
97 public int authenticateByUserId(
98 long companyId, long userId, String password,
99 Map<String, String[]> headerMap, Map<String, String[]> parameterMap)
100 throws AuthException {
101
102 try {
103 return authenticate(
104 companyId, StringPool.BLANK, StringPool.BLANK, userId,
105 password);
106 }
107 catch (Exception e) {
108 _log.error(e, e);
109
110 throw new AuthException(e);
111 }
112 }
113
114 protected LDAPAuthResult authenticate(
115 LdapContext ctx, long companyId, Attributes attrs, String userDN,
116 String password)
117 throws Exception {
118
119 LDAPAuthResult ldapAuthResult = new LDAPAuthResult();
120
121
125 String authMethod = PrefsPropsUtil.getString(
126 companyId, PropsKeys.LDAP_AUTH_METHOD);
127 InitialLdapContext innerCtx = null;
128
129 if (authMethod.equals(AUTH_METHOD_BIND)) {
130 try {
131 Hashtable<String, Object> env =
132 (Hashtable<String, Object>)ctx.getEnvironment();
133
134 env.put(Context.SECURITY_PRINCIPAL, userDN);
135 env.put(Context.SECURITY_CREDENTIALS, password);
136 env.put(
137 Context.REFERRAL,
138 PrefsPropsUtil.getString(
139 companyId, PropsKeys.LDAP_REFERRAL));
140
141
143 env.put("com.sun.jndi.ldap.connect.pool", "false");
144
145 innerCtx = new InitialLdapContext(env, null);
146
147
149 Control[] responseControls = innerCtx.getResponseControls();
150
151 ldapAuthResult.setAuthenticated(true);
152 ldapAuthResult.setResponseControl(responseControls);
153 }
154 catch (Exception e) {
155 if (_log.isDebugEnabled()) {
156 _log.debug(
157 "Failed to bind to the LDAP server with userDN "
158 + userDN + " and password " + password);
159 }
160
161 _log.error(
162 "Failed to bind to the LDAP server: " + e.getMessage());
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, String emailAddress, String screenName, long userId,
211 String password)
212 throws Exception {
213
214 if (!PortalLDAPUtil.isAuthEnabled(companyId)) {
215 if (_log.isDebugEnabled()) {
216 _log.debug("Authenticator is not enabled");
217 }
218
219 return SUCCESS;
220 }
221
222 if (_log.isDebugEnabled()) {
223 _log.debug("Authenticator is enabled");
224 }
225
226 LdapContext ctx = PortalLDAPUtil.getContext(companyId);
227
228 if (ctx == null) {
229 return authenticateRequired(
230 companyId, userId, emailAddress, screenName, true, FAILURE);
231 }
232
233 try {
234 String baseDN = PrefsPropsUtil.getString(
235 companyId, PropsKeys.LDAP_BASE_DN);
236
237
239 String filter = PortalLDAPUtil.getAuthSearchFilter(
240 companyId, emailAddress, screenName, String.valueOf(userId));
241
242 SearchControls cons = new SearchControls(
243 SearchControls.SUBTREE_SCOPE, 1, 0, null, false, false);
244
245 NamingEnumeration<SearchResult> enu = ctx.search(
246 baseDN, filter, cons);
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 companyId, result);
257
258 Attributes attrs = PortalLDAPUtil.getUserAttributes(
259 companyId, ctx, fullUserDN);
260
261 LDAPAuthResult ldapAuthResult = authenticate(
262 ctx, companyId, attrs, fullUserDN, password);
263
264
266 String errorMessage = ldapAuthResult.getErrorMessage();
267
268 if (errorMessage != null) {
269 if (errorMessage.indexOf(PrefsPropsUtil.getString(
270 companyId, PropsKeys.LDAP_ERROR_USER_LOCKOUT))
271 != -1) {
272
273 throw new UserLockoutException();
274 }
275 else if (errorMessage.indexOf(PrefsPropsUtil.getString(
276 companyId, PropsKeys.LDAP_ERROR_PASSWORD_EXPIRED))
277 != -1) {
278
279 throw new PasswordExpiredException();
280 }
281 }
282
283 if (!ldapAuthResult.isAuthenticated()) {
284 return authenticateRequired(
285 companyId, userId, emailAddress, screenName, false,
286 FAILURE);
287 }
288
289
291 User user = PortalLDAPUtil.importLDAPUser(
292 companyId, ctx, attrs, password, true);
293
294
296 String resultCode = ldapAuthResult.getResponseControl();
297
298 if (resultCode.equals(LDAPAuth.RESULT_PASSWORD_RESET)) {
299 UserLocalServiceUtil.updatePasswordReset(
300 user.getUserId(), true);
301 }
302 else if (
303 resultCode.equals(LDAPAuth.RESULT_PASSWORD_EXP_WARNING)) {
304
305 UserLocalServiceUtil.updatePasswordReset(
306 user.getUserId(), true);
307 }
308 }
309 else {
310 if (_log.isDebugEnabled()) {
311 _log.debug("Search filter did not return any results");
312 }
313
314 return authenticateRequired(
315 companyId, userId, emailAddress, screenName, true, DNE);
316 }
317
318 enu.close();
319 }
320 catch (Exception e) {
321 _log.error("Problem accessing LDAP server", e);
322
323 int authResult = authenticateRequired(
324 companyId, userId, emailAddress, screenName, true, FAILURE);
325
326 if (authResult == FAILURE) {
327 throw e;
328 }
329 }
330 finally {
331 if (ctx != null) {
332 ctx.close();
333 }
334 }
335
336 return SUCCESS;
337 }
338
339 protected int authenticateOmniadmin(
340 long companyId, String emailAddress, String screenName, long userId)
341 throws Exception {
342
343
345 if (PropsValues.AUTH_PIPELINE_ENABLE_LIFERAY_CHECK) {
346 if (userId > 0) {
347 if (OmniadminUtil.isOmniadmin(userId)) {
348 return SUCCESS;
349 }
350 }
351 else if (Validator.isNotNull(emailAddress)) {
352 try {
353 User user = UserLocalServiceUtil.getUserByEmailAddress(
354 companyId, emailAddress);
355
356 if (OmniadminUtil.isOmniadmin(user.getUserId())) {
357 return SUCCESS;
358 }
359 }
360 catch (NoSuchUserException nsue) {
361 }
362 }
363 else if (Validator.isNotNull(screenName)) {
364 try {
365 User user = UserLocalServiceUtil.getUserByScreenName(
366 companyId, screenName);
367
368 if (OmniadminUtil.isOmniadmin(user.getUserId())) {
369 return SUCCESS;
370 }
371 }
372 catch (NoSuchUserException nsue) {
373 }
374 }
375 }
376
377 return FAILURE;
378 }
379
380 protected int authenticateRequired(
381 long companyId, long userId, String emailAddress, String screenName,
382 boolean allowOmniadmin, int failureCode)
383 throws Exception {
384
385
388 if (allowOmniadmin &&
389 (authenticateOmniadmin(
390 companyId, emailAddress, screenName, userId) == SUCCESS)) {
391
392 return SUCCESS;
393 }
394
395 if (PrefsPropsUtil.getBoolean(
396 companyId, PropsKeys.LDAP_AUTH_REQUIRED)) {
397
398 return failureCode;
399 }
400 else {
401 return SUCCESS;
402 }
403 }
404
405 private static Log _log = LogFactoryUtil.getLog(LDAPAuth.class);
406
407 }