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.CompanyConstants;
47  import com.liferay.portal.model.User;
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.Encryptor;
59  import com.liferay.util.servlet.SessionErrors;
60  import com.liferay.util.servlet.SessionMessages;
61  import com.liferay.util.servlet.SessionParameters;
62  
63  import java.util.ArrayList;
64  import java.util.Enumeration;
65  import java.util.HashMap;
66  import java.util.List;
67  import java.util.Map;
68  
69  import javax.servlet.http.Cookie;
70  import javax.servlet.http.HttpServletRequest;
71  import javax.servlet.http.HttpServletResponse;
72  import javax.servlet.http.HttpSession;
73  import javax.servlet.jsp.PageContext;
74  
75  import org.apache.commons.logging.Log;
76  import org.apache.commons.logging.LogFactory;
77  import org.apache.struts.action.Action;
78  import org.apache.struts.action.ActionForm;
79  import org.apache.struts.action.ActionForward;
80  import org.apache.struts.action.ActionMapping;
81  
82  /**
83   * <a href="LoginAction.java.html"><b><i>View Source</i></b></a>
84   *
85   * @author Brian Wing Shun Chan
86   * @author Scott Lee
87   *
88   */
89  public class LoginAction extends Action {
90  
91      public static String getLogin(
92              HttpServletRequest req, String paramName, Company company)
93          throws PortalException, SystemException {
94  
95          String login = req.getParameter(paramName);
96  
97          if ((login == null) || (login.equals(StringPool.NULL))) {
98              login = GetterUtil.getString(
99                  CookieKeys.getCookie(req, CookieKeys.LOGIN));
100 
101             if (Validator.isNull(login) &&
102                 company.getAuthType().equals(CompanyConstants.AUTH_TYPE_EA)) {
103 
104                 login = "@" + company.getMx();
105             }
106         }
107 
108         return login;
109     }
110 
111     public static void login(
112             HttpServletRequest req, HttpServletResponse res, String login,
113             String password, boolean rememberMe)
114         throws Exception {
115 
116         CookieKeys.validateSupportCookie(req);
117 
118         HttpSession ses = req.getSession();
119 
120         long userId = GetterUtil.getLong(login);
121 
122         int authResult = Authenticator.FAILURE;
123 
124         Company company = PortalUtil.getCompany(req);
125 
126         Map<String, String[]> headerMap = new HashMap<String, String[]>();
127 
128         Enumeration<String> enu1 = req.getHeaderNames();
129 
130         while (enu1.hasMoreElements()) {
131             String name = enu1.nextElement();
132 
133             Enumeration<String> enu2 = req.getHeaders(name);
134 
135             List<String> headers = new ArrayList<String>();
136 
137             while (enu2.hasMoreElements()) {
138                 String value = enu2.nextElement();
139 
140                 headers.add(value);
141             }
142 
143             headerMap.put(name, headers.toArray(new String[headers.size()]));
144         }
145 
146         Map<String, String[]> parameterMap = req.getParameterMap();
147 
148         if (company.getAuthType().equals(CompanyConstants.AUTH_TYPE_EA)) {
149             authResult = UserLocalServiceUtil.authenticateByEmailAddress(
150                 company.getCompanyId(), login, password, headerMap,
151                 parameterMap);
152 
153             userId = UserLocalServiceUtil.getUserIdByEmailAddress(
154                 company.getCompanyId(), login);
155         }
156         else if (company.getAuthType().equals(CompanyConstants.AUTH_TYPE_SN)) {
157             authResult = UserLocalServiceUtil.authenticateByScreenName(
158                 company.getCompanyId(), login, password, headerMap,
159                 parameterMap);
160 
161             userId = UserLocalServiceUtil.getUserIdByScreenName(
162                 company.getCompanyId(), login);
163         }
164         else if (company.getAuthType().equals(CompanyConstants.AUTH_TYPE_ID)) {
165             authResult = UserLocalServiceUtil.authenticateByUserId(
166                 company.getCompanyId(), userId, password, headerMap,
167                 parameterMap);
168         }
169 
170         if (authResult == Authenticator.SUCCESS) {
171             if (PropsValues.SESSION_ENABLE_PHISHING_PROTECTION) {
172 
173                 // Invalidate the previous session to prevent phishing
174 
175                 Boolean httpsInitial = (Boolean)ses.getAttribute(
176                     WebKeys.HTTPS_INITIAL);
177 
178                 LastPath lastPath = (LastPath)ses.getAttribute(
179                     WebKeys.LAST_PATH);
180 
181                 try {
182                     ses.invalidate();
183                 }
184                 catch (IllegalStateException ise) {
185 
186                     // This only happens in Geronimo
187 
188                     if (_log.isWarnEnabled()) {
189                         _log.warn(ise.getMessage());
190                     }
191                 }
192 
193                 ses = req.getSession(true);
194 
195                 if (httpsInitial != null) {
196                     ses.setAttribute(WebKeys.HTTPS_INITIAL, httpsInitial);
197                 }
198 
199                 if (lastPath != null) {
200                     ses.setAttribute(WebKeys.LAST_PATH, lastPath);
201                 }
202             }
203 
204             // Set cookies
205 
206             String domain = CookieKeys.getDomain(req);
207 
208             User user = UserLocalServiceUtil.getUserById(userId);
209 
210             String userIdString = String.valueOf(userId);
211 
212             ses.setAttribute("j_username", userIdString);
213             ses.setAttribute("j_password", user.getPassword());
214             ses.setAttribute("j_remoteuser", userIdString);
215 
216             ses.setAttribute(WebKeys.USER_PASSWORD, password);
217 
218             Cookie companyIdCookie = new Cookie(
219                 CookieKeys.COMPANY_ID, String.valueOf(company.getCompanyId()));
220 
221             if (Validator.isNotNull(domain)) {
222                 companyIdCookie.setDomain(domain);
223             }
224 
225             companyIdCookie.setPath(StringPool.SLASH);
226 
227             Cookie idCookie = new Cookie(
228                 CookieKeys.ID,
229                 UserLocalServiceUtil.encryptUserId(userIdString));
230 
231             if (Validator.isNotNull(domain)) {
232                 idCookie.setDomain(domain);
233             }
234 
235             idCookie.setPath(StringPool.SLASH);
236 
237             Cookie passwordCookie = new Cookie(
238                 CookieKeys.PASSWORD,
239                 Encryptor.encrypt(company.getKeyObj(), password));
240 
241             if (Validator.isNotNull(domain)) {
242                 passwordCookie.setDomain(domain);
243             }
244 
245             passwordCookie.setPath(StringPool.SLASH);
246 
247             Cookie rememberMeCookie = new Cookie(
248                 CookieKeys.REMEMBER_ME, Boolean.TRUE.toString());
249 
250             if (Validator.isNotNull(domain)) {
251                 rememberMeCookie.setDomain(domain);
252             }
253 
254             rememberMeCookie.setPath(StringPool.SLASH);
255 
256             int loginMaxAge = PropsValues.COMPANY_SECURITY_AUTO_LOGIN_MAX_AGE;
257 
258             if (PropsValues.SESSION_DISABLED) {
259                 rememberMe = true;
260             }
261 
262             if (rememberMe) {
263                 companyIdCookie.setMaxAge(loginMaxAge);
264                 idCookie.setMaxAge(loginMaxAge);
265                 passwordCookie.setMaxAge(loginMaxAge);
266                 rememberMeCookie.setMaxAge(loginMaxAge);
267             }
268             else {
269 
270                 // This was explicitly changed from 0 to -1 so that the cookie
271                 // lasts as long as the browser. This allows an external servlet
272                 // wrapped in AutoLoginFilter to work throughout the client
273                 // connection. The cookies ARE removed on an actual logout, so
274                 // there is no security issue. See LEP-4678 and LEP-5177.
275 
276                 companyIdCookie.setMaxAge(-1);
277                 idCookie.setMaxAge(-1);
278                 passwordCookie.setMaxAge(-1);
279                 rememberMeCookie.setMaxAge(0);
280             }
281 
282             Cookie loginCookie = new Cookie(CookieKeys.LOGIN, login);
283 
284             if (Validator.isNotNull(domain)) {
285                 loginCookie.setDomain(domain);
286             }
287 
288             loginCookie.setMaxAge(loginMaxAge);
289             loginCookie.setPath(StringPool.SLASH);
290 
291             Cookie screenNameCookie = new Cookie(
292                 CookieKeys.SCREEN_NAME,
293                 Encryptor.encrypt(company.getKeyObj(), user.getScreenName()));
294 
295             if (Validator.isNotNull(domain)) {
296                 screenNameCookie.setDomain(domain);
297             }
298 
299             screenNameCookie.setMaxAge(loginMaxAge);
300             screenNameCookie.setPath(StringPool.SLASH);
301 
302             CookieKeys.addCookie(res, companyIdCookie);
303             CookieKeys.addCookie(res, idCookie);
304             CookieKeys.addCookie(res, passwordCookie);
305             CookieKeys.addCookie(res, rememberMeCookie);
306             CookieKeys.addCookie(res, loginCookie);
307             CookieKeys.addCookie(res, screenNameCookie);
308         }
309         else {
310             throw new AuthException();
311         }
312     }
313 
314     public ActionForward execute(
315             ActionMapping mapping, ActionForm form, HttpServletRequest req,
316             HttpServletResponse res)
317         throws Exception {
318 
319         if (PropsValues.COMPANY_SECURITY_AUTH_REQUIRES_HTTPS &&
320             !req.isSecure()) {
321 
322             ThemeDisplay themeDisplay =
323                 (ThemeDisplay)req.getAttribute(WebKeys.THEME_DISPLAY);
324 
325             StringMaker sm = new StringMaker();
326 
327             sm.append(PortalUtil.getPortalURL(req, true));
328             sm.append(themeDisplay.getURLSignIn());
329 
330             res.sendRedirect(sm.toString());
331 
332             return null;
333         }
334 
335         HttpSession ses = req.getSession();
336 
337         ThemeDisplay themeDisplay =
338             (ThemeDisplay)req.getAttribute(WebKeys.THEME_DISPLAY);
339 
340         if (ses.getAttribute("j_username") != null &&
341             ses.getAttribute("j_password") != null) {
342 
343             if (PropsValues.PORTAL_JAAS_ENABLE) {
344                 return mapping.findForward("/portal/touch_protected.jsp");
345             }
346             else {
347                 res.sendRedirect(themeDisplay.getPathMain());
348 
349                 return null;
350             }
351         }
352 
353         String cmd = ParamUtil.getString(req, Constants.CMD);
354 
355         if (cmd.equals("already-registered")) {
356             try {
357                 login(req, res);
358 
359                 if (PropsValues.PORTAL_JAAS_ENABLE) {
360                     return mapping.findForward("/portal/touch_protected.jsp");
361                 }
362                 else {
363                     String redirect = ParamUtil.getString(req, "redirect");
364 
365                     if (Validator.isNotNull(redirect)) {
366                         res.sendRedirect(redirect);
367                     }
368                     else {
369                         res.sendRedirect(themeDisplay.getPathMain());
370                     }
371 
372                     return null;
373                 }
374             }
375             catch (Exception e) {
376                 if (e instanceof AuthException) {
377                     Throwable cause = e.getCause();
378 
379                     if (cause instanceof PasswordExpiredException ||
380                         cause instanceof UserLockoutException) {
381 
382                         SessionErrors.add(req, cause.getClass().getName());
383                     }
384                     else {
385                         SessionErrors.add(req, e.getClass().getName());
386                     }
387 
388                     return mapping.findForward("portal.login");
389                 }
390                 else if (e instanceof CookieNotSupportedException ||
391                          e instanceof NoSuchUserException ||
392                          e instanceof PasswordExpiredException ||
393                          e instanceof UserEmailAddressException ||
394                          e instanceof UserIdException ||
395                          e instanceof UserLockoutException ||
396                          e instanceof UserPasswordException ||
397                          e instanceof UserScreenNameException) {
398 
399                     SessionErrors.add(req, e.getClass().getName());
400 
401                     return mapping.findForward("portal.login");
402                 }
403                 else {
404                     req.setAttribute(PageContext.EXCEPTION, e);
405 
406                     return mapping.findForward(ActionConstants.COMMON_ERROR);
407                 }
408             }
409         }
410         else if (cmd.equals("forgot-password")) {
411             try {
412                 sendPassword(req);
413 
414                 return mapping.findForward("portal.login");
415             }
416             catch (Exception e) {
417                 if (e instanceof CaptchaTextException ||
418                     e instanceof NoSuchUserException ||
419                     e instanceof SendPasswordException ||
420                     e instanceof UserEmailAddressException) {
421 
422                     SessionErrors.add(req, e.getClass().getName());
423 
424                     return mapping.findForward("portal.login");
425                 }
426                 else {
427                     req.setAttribute(PageContext.EXCEPTION, e);
428 
429                     return mapping.findForward(ActionConstants.COMMON_ERROR);
430                 }
431             }
432         }
433         else {
434             if (Validator.isNotNull(PropsValues.AUTH_LOGIN_URL)) {
435                 res.sendRedirect(PropsValues.AUTH_LOGIN_URL);
436 
437                 return null;
438             }
439             else {
440                 return mapping.findForward("portal.login");
441             }
442         }
443     }
444 
445     protected void login(HttpServletRequest req, HttpServletResponse res)
446         throws Exception {
447 
448         String login = ParamUtil.getString(req, "login").toLowerCase();
449         String password = ParamUtil.getString(
450             req, SessionParameters.get(req, "password"));
451         boolean rememberMe = ParamUtil.getBoolean(req, "rememberMe");
452 
453         login(req, res, login, password, rememberMe);
454     }
455 
456     protected void sendPassword(HttpServletRequest req) throws Exception {
457         ThemeDisplay themeDisplay =
458             (ThemeDisplay)req.getAttribute(WebKeys.THEME_DISPLAY);
459 
460         Company company = themeDisplay.getCompany();
461 
462         if (!company.isSendPassword()) {
463             return;
464         }
465 
466         CaptchaUtil.check(req);
467 
468         String emailAddress = ParamUtil.getString(req, "emailAddress");
469 
470         String remoteAddr = req.getRemoteAddr();
471         String remoteHost = req.getRemoteHost();
472         String userAgent = req.getHeader(HttpHeaders.USER_AGENT);
473 
474         UserLocalServiceUtil.sendPassword(
475             PortalUtil.getCompanyId(req), emailAddress, remoteAddr, remoteHost,
476             userAgent);
477 
478         SessionMessages.add(req, "request_processed", emailAddress);
479     }
480 
481     private static Log _log = LogFactory.getLog(LoginAction.class);
482 
483 }