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.PropsUtil;
38 import com.liferay.portal.util.PropsValues;
39 import com.liferay.portlet.admin.util.OmniadminUtil;
40
41 import java.util.Map;
42 import java.util.Properties;
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, Map headerMap,
76 Map 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, Map headerMap,
92 Map 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, Map headerMap,
108 Map 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
143 if (authenticateOmniadmin(companyId, emailAddress, userId) == SUCCESS) {
144 return SUCCESS;
145 }
146
147 String baseDN = PrefsPropsUtil.getString(
148 companyId, PropsUtil.LDAP_BASE_DN);
149
150 LdapContext ctx = PortalLDAPUtil.getContext(companyId);
151
152 if (ctx == null) {
153 return authenticateRequired(
154 companyId, userId, emailAddress, FAILURE);
155 }
156
157
159 String filter = PortalLDAPUtil.getAuthSearchFilter(
160 companyId, emailAddress, screenName, String.valueOf(userId));
161
162 try {
163 SearchControls cons = new SearchControls(
164 SearchControls.SUBTREE_SCOPE, 1, 0, null, false, false);
165
166 NamingEnumeration enu = ctx.search(baseDN, filter, cons);
167
168 if (enu.hasMore()) {
169 if (_log.isDebugEnabled()) {
170 _log.debug("Search filter returned at least one result");
171 }
172
173 SearchResult result = (SearchResult)enu.next();
174
175 String fullUserDN = PortalLDAPUtil.getNameInNamespace(
176 companyId, result);
177
178 Attributes attrs = PortalLDAPUtil.getAttributes(
179 ctx, fullUserDN);
180
181 LDAPAuthResult ldapAuthResult = authenticate(
182 ctx, companyId, attrs, fullUserDN, password);
183
184
186 String errorMessage = ldapAuthResult.getErrorMessage();
187
188 if (errorMessage != null) {
189 if (errorMessage.indexOf(PrefsPropsUtil.getString(
190 companyId, PropsUtil.LDAP_ERROR_USER_LOCKOUT))
191 != -1) {
192
193 throw new UserLockoutException();
194 }
195 else if (errorMessage.indexOf(PrefsPropsUtil.getString(
196 companyId, PropsUtil.LDAP_ERROR_PASSWORD_EXPIRED))
197 != -1) {
198
199 throw new PasswordExpiredException();
200 }
201 }
202
203 if (!ldapAuthResult.isAuthenticated()) {
204 return authenticateRequired(
205 companyId, userId, emailAddress, FAILURE);
206 }
207
208
210 User user = PortalLDAPUtil.importLDAPUser(
211 companyId, ctx, attrs, password, true);
212
213
215 String resultCode = ldapAuthResult.getResponseControl();
216
217 if (resultCode.equals(LDAPAuth.RESULT_PASSWORD_RESET)) {
218 UserLocalServiceUtil.updatePasswordReset(
219 user.getUserId(), true);
220 }
221 else if (
222 resultCode.equals(LDAPAuth.RESULT_PASSWORD_EXP_WARNING)) {
223
224 UserLocalServiceUtil.updatePasswordReset(
225 user.getUserId(), true);
226 }
227 }
228 else {
229 if (_log.isDebugEnabled()) {
230 _log.debug("Search filter did not return any results");
231 }
232
233 return authenticateRequired(
234 companyId, userId, emailAddress, DNE);
235 }
236 }
237 catch (Exception e) {
238 _log.error("Problem accessing LDAP server: " + e.getMessage());
239
240 if (authenticateRequired(
241 companyId, userId, emailAddress, FAILURE) == FAILURE) {
242
243 throw e;
244 }
245 }
246 finally {
247 ctx.close();
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, PropsUtil.LDAP_AUTH_METHOD);
266
267 if (authMethod.equals(AUTH_METHOD_BIND)) {
268 try {
269 Properties env = (Properties)ctx.getEnvironment();
270
271 env.put(Context.SECURITY_PRINCIPAL, userDN);
272 env.put(Context.SECURITY_CREDENTIALS, password);
273 env.put(Context.REFERRAL, "follow");
274
275 ctx = new InitialLdapContext(env, null);
276
277
279 Control[] responseControls = ctx.getResponseControls();
280
281 ldapAuthResult.setAuthenticated(true);
282 ldapAuthResult.setResponseControl(responseControls);
283 }
284 catch (Exception e) {
285 _log.error(
286 "Failed to bind to the LDAP server with userDN " + userDN +
287 " and password " + password + ": " + e.getMessage());
288
289 ldapAuthResult.setAuthenticated(false);
290 ldapAuthResult.setErrorMessage(e.getMessage());
291 }
292 }
293 else if (authMethod.equals(AUTH_METHOD_PASSWORD_COMPARE)) {
294 Attribute userPassword = attrs.get("userPassword");
295
296 if (userPassword != null) {
297 String ldapPassword = new String((byte[])userPassword.get());
298
299 String encryptedPassword = password;
300
301 String algorithm = PrefsPropsUtil.getString(
302 companyId,
303 PropsUtil.LDAP_AUTH_PASSWORD_ENCRYPTION_ALGORITHM);
304
305 if (Validator.isNotNull(algorithm)) {
306 encryptedPassword =
307 "{" + algorithm + "}" +
308 PwdEncryptor.encrypt(
309 algorithm, password, ldapPassword);
310 }
311
312 if (ldapPassword.equals(encryptedPassword)) {
313 ldapAuthResult.setAuthenticated(true);
314 }
315 else {
316 ldapAuthResult.setAuthenticated(false);
317
318 _log.error(
319 "LDAP password " + ldapPassword +
320 " does not match with given password " +
321 encryptedPassword + " for userDN " + userDN);
322 }
323 }
324 }
325
326 return ldapAuthResult;
327 }
328
329 protected int authenticateOmniadmin(
330 long companyId, String emailAddress, long userId)
331 throws Exception {
332
333
335 if (PropsValues.AUTH_PIPELINE_ENABLE_LIFERAY_CHECK) {
336 if (userId > 0) {
337 if (OmniadminUtil.isOmniadmin(userId)) {
338 return SUCCESS;
339 }
340 }
341 else if (Validator.isNotNull(emailAddress)) {
342 try {
343 User user = UserLocalServiceUtil.getUserByEmailAddress(
344 companyId, emailAddress);
345
346 if (OmniadminUtil.isOmniadmin(user.getUserId())) {
347 return SUCCESS;
348 }
349 }
350 catch (NoSuchUserException nsue) {
351 }
352 }
353 }
354
355 return FAILURE;
356 }
357
358 protected int authenticateRequired(
359 long companyId, long userId, String emailAddress, int failureCode)
360 throws Exception {
361
362 if (PrefsPropsUtil.getBoolean(
363 companyId, PropsUtil.LDAP_AUTH_REQUIRED)) {
364
365 return failureCode;
366 }
367 else {
368 return SUCCESS;
369 }
370 }
371
372 private static Log _log = LogFactoryUtil.getLog(LDAPAuth.class);
373
374 }