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