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
314 ctx = new InitialLdapContext(env, null);
315
316
318 Control[] responseControls = ctx.getResponseControls();
319
320 ldapAuthResult.setAuthenticated(true);
321 ldapAuthResult.setResponseControl(responseControls);
322 }
323 catch (Exception e) {
324 _log.error(
325 "Failed to bind to the LDAP server with userDN " + userDN +
326 " and password " + password + ": " + e.getMessage());
327
328 ldapAuthResult.setAuthenticated(false);
329 ldapAuthResult.setErrorMessage(e.getMessage());
330 }
331 }
332 else if (authMethod.equals(AUTH_METHOD_PASSWORD_COMPARE)) {
333 if (userPassword != null) {
334 String ldapPassword = new String((byte[])userPassword.get());
335
336 String encryptedPassword = password;
337
338 String algorithm = PrefsPropsUtil.getString(
339 companyId,
340 PropsUtil.LDAP_AUTH_PASSWORD_ENCRYPTION_ALGORITHM);
341
342 if (Validator.isNotNull(algorithm)) {
343 encryptedPassword =
344 "{" + algorithm + "}" +
345 PwdEncryptor.encrypt(
346 algorithm, password, ldapPassword);
347 }
348
349 if (ldapPassword.equals(encryptedPassword)) {
350 ldapAuthResult.setAuthenticated(true);
351 }
352 else {
353 ldapAuthResult.setAuthenticated(false);
354
355 _log.error(
356 "LDAP password " + ldapPassword +
357 " does not match with given password " +
358 encryptedPassword + " for user id " + userId);
359 }
360 }
361 }
362
363 return ldapAuthResult;
364 }
365
366 protected int authenticateOmniadmin(
367 long companyId, String emailAddress, long userId)
368 throws Exception {
369
370
372 if (GetterUtil.getBoolean(PropsUtil.get(
373 PropsUtil.AUTH_PIPELINE_ENABLE_LIFERAY_CHECK))) {
374
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 }
393
394 return FAILURE;
395 }
396
397 protected int authenticateRequired(
398 long companyId, long userId, String emailAddress, int failureCode)
399 throws Exception {
400
401 if (PrefsPropsUtil.getBoolean(
402 companyId, PropsUtil.LDAP_AUTH_REQUIRED)) {
403
404 return failureCode;
405 }
406 else {
407 return SUCCESS;
408 }
409 }
410
411 private static Log _log = LogFactoryUtil.getLog(LDAPAuth.class);
412
413 }