1   /**
2    * Copyright (c) 2000-2008 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portal.action;
24  
25  import com.liferay.portal.CookieNotSupportedException;
26  import com.liferay.portal.NoSuchUserException;
27  import com.liferay.portal.PasswordExpiredException;
28  import com.liferay.portal.PortalException;
29  import com.liferay.portal.SendPasswordException;
30  import com.liferay.portal.SystemException;
31  import com.liferay.portal.UserEmailAddressException;
32  import com.liferay.portal.UserIdException;
33  import com.liferay.portal.UserLockoutException;
34  import com.liferay.portal.UserPasswordException;
35  import com.liferay.portal.UserScreenNameException;
36  import com.liferay.portal.captcha.CaptchaTextException;
37  import com.liferay.portal.captcha.CaptchaUtil;
38  import com.liferay.portal.kernel.servlet.HttpHeaders;
39  import com.liferay.portal.kernel.util.Constants;
40  import com.liferay.portal.kernel.util.GetterUtil;
41  import com.liferay.portal.kernel.util.ParamUtil;
42  import com.liferay.portal.kernel.util.StringMaker;
43  import com.liferay.portal.kernel.util.StringPool;
44  import com.liferay.portal.kernel.util.Validator;
45  import com.liferay.portal.model.Company;
46  import com.liferay.portal.model.User;
47  import com.liferay.portal.model.impl.CompanyImpl;
48  import com.liferay.portal.security.auth.AuthException;
49  import com.liferay.portal.security.auth.Authenticator;
50  import com.liferay.portal.service.UserLocalServiceUtil;
51  import com.liferay.portal.struts.ActionConstants;
52  import com.liferay.portal.struts.LastPath;
53  import com.liferay.portal.theme.ThemeDisplay;
54  import com.liferay.portal.util.CookieKeys;
55  import com.liferay.portal.util.PortalUtil;
56  import com.liferay.portal.util.PropsValues;
57  import com.liferay.portal.util.WebKeys;
58  import com.liferay.util.CookieUtil;
59  import com.liferay.util.Encryptor;
60  import com.liferay.util.servlet.SessionErrors;
61  import com.liferay.util.servlet.SessionMessages;
62  import com.liferay.util.servlet.SessionParameters;
63  
64  import java.util.ArrayList;
65  import java.util.Enumeration;
66  import java.util.HashMap;
67  import java.util.List;
68  import java.util.Map;
69  
70  import javax.servlet.http.Cookie;
71  import javax.servlet.http.HttpServletRequest;
72  import javax.servlet.http.HttpServletResponse;
73  import javax.servlet.http.HttpSession;
74  import javax.servlet.jsp.PageContext;
75  
76  import org.apache.commons.logging.Log;
77  import org.apache.commons.logging.LogFactory;
78  import org.apache.struts.action.Action;
79  import org.apache.struts.action.ActionForm;
80  import org.apache.struts.action.ActionForward;
81  import org.apache.struts.action.ActionMapping;
82  
83  /**
84   * <a href="LoginAction.java.html"><b><i>View Source</i></b></a>
85   *
86   * @author Brian Wing Shun Chan
87   * @author Scott Lee
88   *
89   */
90  public class LoginAction extends Action {
91  
92      public static String getLogin(
93              HttpServletRequest req, String paramName, Company company)
94          throws PortalException, SystemException {
95  
96          String login = req.getParameter(paramName);
97  
98          if ((login == null) || (login.equals(StringPool.NULL))) {
99              login = GetterUtil.getString(
100                 CookieUtil.get(req.getCookies(), CookieKeys.LOGIN));
101 
102             if (Validator.isNull(login) &&
103                 company.getAuthType().equals(CompanyImpl.AUTH_TYPE_EA)) {
104 
105                 login = "@" + company.getMx();
106             }
107         }
108 
109         return login;
110     }
111 
112     public static void login(
113             HttpServletRequest req, HttpServletResponse res, String login,
114             String password, boolean rememberMe)
115         throws Exception {
116 
117         CookieKeys.validateSupportCookie(req);
118 
119         HttpSession ses = req.getSession();
120 
121         long userId = GetterUtil.getLong(login);
122 
123         int authResult = Authenticator.FAILURE;
124 
125         Company company = PortalUtil.getCompany(req);
126 
127         Map headerMap = new HashMap();
128 
129         Enumeration enu1 = req.getHeaderNames();
130 
131         while (enu1.hasMoreElements()) {
132             String name = (String)enu1.nextElement();
133 
134             Enumeration enu2 = req.getHeaders(name);
135 
136             List headers = new ArrayList();
137 
138             while (enu2.hasMoreElements()) {
139                 String value = (String)enu2.nextElement();
140 
141                 headers.add(value);
142             }
143 
144             headerMap.put(name, (String[])headers.toArray(new String[0]));
145         }
146 
147         Map parameterMap = req.getParameterMap();
148 
149         if (company.getAuthType().equals(CompanyImpl.AUTH_TYPE_EA)) {
150             authResult = UserLocalServiceUtil.authenticateByEmailAddress(
151                 company.getCompanyId(), login, password, headerMap,
152                 parameterMap);
153 
154             userId = UserLocalServiceUtil.getUserIdByEmailAddress(
155                 company.getCompanyId(), login);
156         }
157         else if (company.getAuthType().equals(CompanyImpl.AUTH_TYPE_SN)) {
158             authResult = UserLocalServiceUtil.authenticateByScreenName(
159                 company.getCompanyId(), login, password, headerMap,
160                 parameterMap);
161 
162             userId = UserLocalServiceUtil.getUserIdByScreenName(
163                 company.getCompanyId(), login);
164         }
165         else if (company.getAuthType().equals(CompanyImpl.AUTH_TYPE_ID)) {
166             authResult = UserLocalServiceUtil.authenticateByUserId(
167                 company.getCompanyId(), userId, password, headerMap,
168                 parameterMap);
169         }
170 
171         if (authResult == Authenticator.SUCCESS) {
172             if (PropsValues.SESSION_ENABLE_PHISHING_PROTECTION) {
173 
174                 // Invalidate the previous session to prevent phishing
175 
176                 Boolean httpsInitial = (Boolean)ses.getAttribute(
177                     WebKeys.HTTPS_INITIAL);
178 
179                 LastPath lastPath = (LastPath)ses.getAttribute(
180                     WebKeys.LAST_PATH);
181 
182                 try {
183                     ses.invalidate();
184                 }
185                 catch (IllegalStateException ise) {
186 
187                     // This only happens in Geronimo
188 
189                     if (_log.isWarnEnabled()) {
190                         _log.warn(ise.getMessage());
191                     }
192                 }
193 
194                 ses = req.getSession(true);
195 
196                 if (httpsInitial != null) {
197                     ses.setAttribute(WebKeys.HTTPS_INITIAL, httpsInitial);
198                 }
199 
200                 if (lastPath != null) {
201                     ses.setAttribute(WebKeys.LAST_PATH, lastPath);
202                 }
203             }
204 
205             // Set cookies
206 
207             String domain = CookieKeys.getDomain(req);
208 
209             User user = UserLocalServiceUtil.getUserById(userId);
210 
211             String userIdString = String.valueOf(userId);
212 
213             ses.setAttribute("j_username", userIdString);
214             ses.setAttribute("j_password", user.getPassword());
215             ses.setAttribute("j_remoteuser", userIdString);
216 
217             ses.setAttribute(WebKeys.USER_PASSWORD, password);
218 
219             Cookie companyIdCookie = new Cookie(
220                 CookieKeys.COMPANY_ID, String.valueOf(company.getCompanyId()));
221 
222             if (Validator.isNotNull(domain)) {
223                 companyIdCookie.setDomain(domain);
224             }
225 
226             companyIdCookie.setPath(StringPool.SLASH);
227 
228             Cookie idCookie = new Cookie(
229                 CookieKeys.ID,
230                 UserLocalServiceUtil.encryptUserId(userIdString));
231 
232             if (Validator.isNotNull(domain)) {
233                 idCookie.setDomain(domain);
234             }
235 
236             idCookie.setPath(StringPool.SLASH);
237 
238             Cookie passwordCookie = new Cookie(
239                 CookieKeys.PASSWORD,
240                 Encryptor.encrypt(company.getKeyObj(), password));
241 
242             if (Validator.isNotNull(domain)) {
243                 passwordCookie.setDomain(domain);
244             }
245 
246             passwordCookie.setPath(StringPool.SLASH);
247 
248             int loginMaxAge = PropsValues.COMPANY_SECURITY_AUTO_LOGIN_MAX_AGE;
249 
250             if (PropsValues.SESSION_DISABLED) {
251                 rememberMe = true;
252             }
253 
254             if (rememberMe) {
255                 companyIdCookie.setMaxAge(loginMaxAge);
256                 idCookie.setMaxAge(loginMaxAge);
257                 passwordCookie.setMaxAge(loginMaxAge);
258             }
259             else {
260 
261                 // This was explicitly changed from 0 to -1 so that the cookie
262                 // lasts as long as the browser. This allows an external servlet
263                 // wrapped in AutoLoginFilter to work throughout the client
264                 // connection. The cookies ARE removed on an actual logout, so
265                 // there is no security issue. See LEP-4678.
266 
267                 companyIdCookie.setMaxAge(-1);
268                 idCookie.setMaxAge(-1);
269                 passwordCookie.setMaxAge(-1);
270             }
271 
272             Cookie loginCookie = new Cookie(CookieKeys.LOGIN, login);
273 
274             if (Validator.isNotNull(domain)) {
275                 loginCookie.setDomain(domain);
276             }
277 
278             loginCookie.setMaxAge(loginMaxAge);
279             loginCookie.setPath(StringPool.SLASH);
280 
281             Cookie screenNameCookie = new Cookie(
282                 CookieKeys.SCREEN_NAME,
283                 Encryptor.encrypt(company.getKeyObj(), user.getScreenName()));
284 
285             if (Validator.isNotNull(domain)) {
286                 screenNameCookie.setDomain(domain);
287             }
288 
289             screenNameCookie.setMaxAge(loginMaxAge);
290             screenNameCookie.setPath(StringPool.SLASH);
291 
292             CookieKeys.addCookie(res, companyIdCookie);
293             CookieKeys.addCookie(res, idCookie);
294             CookieKeys.addCookie(res, passwordCookie);
295             CookieKeys.addCookie(res, loginCookie);
296             CookieKeys.addCookie(res, screenNameCookie);
297         }
298         else {
299             throw new AuthException();
300         }
301     }
302 
303     public ActionForward execute(
304             ActionMapping mapping, ActionForm form, HttpServletRequest req,
305             HttpServletResponse res)
306         throws Exception {
307 
308         if (PropsValues.COMPANY_SECURITY_AUTH_REQUIRES_HTTPS &&
309             !req.isSecure()) {
310 
311             ThemeDisplay themeDisplay =
312                 (ThemeDisplay)req.getAttribute(WebKeys.THEME_DISPLAY);
313 
314             StringMaker sm = new StringMaker();
315 
316             sm.append(PortalUtil.getPortalURL(req, true));
317             sm.append(themeDisplay.getURLSignIn());
318 
319             res.sendRedirect(sm.toString());
320 
321             return null;
322         }
323 
324         HttpSession ses = req.getSession();
325 
326         ThemeDisplay themeDisplay =
327             (ThemeDisplay)req.getAttribute(WebKeys.THEME_DISPLAY);
328 
329         if (ses.getAttribute("j_username") != null &&
330             ses.getAttribute("j_password") != null) {
331 
332             if (PropsValues.PORTAL_JAAS_ENABLE) {
333                 return mapping.findForward("/portal/touch_protected.jsp");
334             }
335             else {
336                 res.sendRedirect(themeDisplay.getPathMain());
337 
338                 return null;
339             }
340         }
341 
342         String cmd = ParamUtil.getString(req, Constants.CMD);
343 
344         if (cmd.equals("already-registered")) {
345             try {
346                 login(req, res);
347 
348                 if (PropsValues.PORTAL_JAAS_ENABLE) {
349                     return mapping.findForward("/portal/touch_protected.jsp");
350                 }
351                 else {
352                     String redirect = ParamUtil.getString(req, "redirect");
353 
354                     if (Validator.isNotNull(redirect)) {
355                         res.sendRedirect(redirect);
356                     }
357                     else {
358                         res.sendRedirect(themeDisplay.getPathMain());
359                     }
360 
361                     return null;
362                 }
363             }
364             catch (Exception e) {
365                 if (e instanceof AuthException) {
366                     Throwable cause = e.getCause();
367 
368                     if (cause instanceof PasswordExpiredException ||
369                         cause instanceof UserLockoutException) {
370 
371                         SessionErrors.add(req, cause.getClass().getName());
372                     }
373                     else {
374                         SessionErrors.add(req, e.getClass().getName());
375                     }
376 
377                     return mapping.findForward("portal.login");
378                 }
379                 else if (e instanceof CookieNotSupportedException ||
380                          e instanceof NoSuchUserException ||
381                          e instanceof PasswordExpiredException ||
382                          e instanceof UserEmailAddressException ||
383                          e instanceof UserIdException ||
384                          e instanceof UserLockoutException ||
385                          e instanceof UserPasswordException ||
386                          e instanceof UserScreenNameException) {
387 
388                     SessionErrors.add(req, e.getClass().getName());
389 
390                     return mapping.findForward("portal.login");
391                 }
392                 else {
393                     req.setAttribute(PageContext.EXCEPTION, e);
394 
395                     return mapping.findForward(ActionConstants.COMMON_ERROR);
396                 }
397             }
398         }
399         else if (cmd.equals("forgot-password")) {
400             try {
401                 sendPassword(req);
402 
403                 return mapping.findForward("portal.login");
404             }
405             catch (Exception e) {
406                 if (e instanceof CaptchaTextException ||
407                     e instanceof NoSuchUserException ||
408                     e instanceof SendPasswordException ||
409                     e instanceof UserEmailAddressException) {
410 
411                     SessionErrors.add(req, e.getClass().getName());
412 
413                     return mapping.findForward("portal.login");
414                 }
415                 else {
416                     req.setAttribute(PageContext.EXCEPTION, e);
417 
418                     return mapping.findForward(ActionConstants.COMMON_ERROR);
419                 }
420             }
421         }
422         else {
423             return mapping.findForward("portal.login");
424         }
425     }
426 
427     protected void login(HttpServletRequest req, HttpServletResponse res)
428         throws Exception {
429 
430         String login = ParamUtil.getString(req, "login").toLowerCase();
431         String password = ParamUtil.getString(
432             req, SessionParameters.get(req, "password"));
433         boolean rememberMe = ParamUtil.getBoolean(req, "rememberMe");
434 
435         login(req, res, login, password, rememberMe);
436     }
437 
438     protected void sendPassword(HttpServletRequest req) throws Exception {
439         ThemeDisplay themeDisplay =
440             (ThemeDisplay)req.getAttribute(WebKeys.THEME_DISPLAY);
441 
442         Company company = themeDisplay.getCompany();
443 
444         if (!company.isSendPassword()) {
445             return;
446         }
447 
448         CaptchaUtil.check(req);
449 
450         String emailAddress = ParamUtil.getString(req, "emailAddress");
451 
452         String remoteAddr = req.getRemoteAddr();
453         String remoteHost = req.getRemoteHost();
454         String userAgent = req.getHeader(HttpHeaders.USER_AGENT);
455 
456         UserLocalServiceUtil.sendPassword(
457             PortalUtil.getCompanyId(req), emailAddress, remoteAddr, remoteHost,
458             userAgent);
459 
460         SessionMessages.add(req, "request_processed", emailAddress);
461     }
462 
463     private static Log _log = LogFactory.getLog(LoginAction.class);
464 
465 }