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.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(CompanyImpl.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 headerMap = new HashMap();
127 
128         Enumeration enu1 = req.getHeaderNames();
129 
130         while (enu1.hasMoreElements()) {
131             String name = (String)enu1.nextElement();
132 
133             Enumeration enu2 = req.getHeaders(name);
134 
135             List headers = new ArrayList();
136 
137             while (enu2.hasMoreElements()) {
138                 String value = (String)enu2.nextElement();
139 
140                 headers.add(value);
141             }
142 
143             headerMap.put(name, (String[])headers.toArray(new String[0]));
144         }
145 
146         Map parameterMap = req.getParameterMap();
147 
148         if (company.getAuthType().equals(CompanyImpl.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(CompanyImpl.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(CompanyImpl.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, loginCookie);
306             CookieKeys.addCookie(res, screenNameCookie);
307         }
308         else {
309             throw new AuthException();
310         }
311     }
312 
313     public ActionForward execute(
314             ActionMapping mapping, ActionForm form, HttpServletRequest req,
315             HttpServletResponse res)
316         throws Exception {
317 
318         if (PropsValues.COMPANY_SECURITY_AUTH_REQUIRES_HTTPS &&
319             !req.isSecure()) {
320 
321             ThemeDisplay themeDisplay =
322                 (ThemeDisplay)req.getAttribute(WebKeys.THEME_DISPLAY);
323 
324             StringMaker sm = new StringMaker();
325 
326             sm.append(PortalUtil.getPortalURL(req, true));
327             sm.append(themeDisplay.getURLSignIn());
328 
329             res.sendRedirect(sm.toString());
330 
331             return null;
332         }
333 
334         HttpSession ses = req.getSession();
335 
336         ThemeDisplay themeDisplay =
337             (ThemeDisplay)req.getAttribute(WebKeys.THEME_DISPLAY);
338 
339         if (ses.getAttribute("j_username") != null &&
340             ses.getAttribute("j_password") != null) {
341 
342             if (PropsValues.PORTAL_JAAS_ENABLE) {
343                 return mapping.findForward("/portal/touch_protected.jsp");
344             }
345             else {
346                 res.sendRedirect(themeDisplay.getPathMain());
347 
348                 return null;
349             }
350         }
351 
352         String cmd = ParamUtil.getString(req, Constants.CMD);
353 
354         if (cmd.equals("already-registered")) {
355             try {
356                 login(req, res);
357 
358                 if (PropsValues.PORTAL_JAAS_ENABLE) {
359                     return mapping.findForward("/portal/touch_protected.jsp");
360                 }
361                 else {
362                     String redirect = ParamUtil.getString(req, "redirect");
363 
364                     if (Validator.isNotNull(redirect)) {
365                         res.sendRedirect(redirect);
366                     }
367                     else {
368                         res.sendRedirect(themeDisplay.getPathMain());
369                     }
370 
371                     return null;
372                 }
373             }
374             catch (Exception e) {
375                 if (e instanceof AuthException) {
376                     Throwable cause = e.getCause();
377 
378                     if (cause instanceof PasswordExpiredException ||
379                         cause instanceof UserLockoutException) {
380 
381                         SessionErrors.add(req, cause.getClass().getName());
382                     }
383                     else {
384                         SessionErrors.add(req, e.getClass().getName());
385                     }
386 
387                     return mapping.findForward("portal.login");
388                 }
389                 else if (e instanceof CookieNotSupportedException ||
390                          e instanceof NoSuchUserException ||
391                          e instanceof PasswordExpiredException ||
392                          e instanceof UserEmailAddressException ||
393                          e instanceof UserIdException ||
394                          e instanceof UserLockoutException ||
395                          e instanceof UserPasswordException ||
396                          e instanceof UserScreenNameException) {
397 
398                     SessionErrors.add(req, e.getClass().getName());
399 
400                     return mapping.findForward("portal.login");
401                 }
402                 else {
403                     req.setAttribute(PageContext.EXCEPTION, e);
404 
405                     return mapping.findForward(ActionConstants.COMMON_ERROR);
406                 }
407             }
408         }
409         else if (cmd.equals("forgot-password")) {
410             try {
411                 sendPassword(req);
412 
413                 return mapping.findForward("portal.login");
414             }
415             catch (Exception e) {
416                 if (e instanceof CaptchaTextException ||
417                     e instanceof NoSuchUserException ||
418                     e instanceof SendPasswordException ||
419                     e instanceof UserEmailAddressException) {
420 
421                     SessionErrors.add(req, e.getClass().getName());
422 
423                     return mapping.findForward("portal.login");
424                 }
425                 else {
426                     req.setAttribute(PageContext.EXCEPTION, e);
427 
428                     return mapping.findForward(ActionConstants.COMMON_ERROR);
429                 }
430             }
431         }
432         else {
433             return mapping.findForward("portal.login");
434         }
435     }
436 
437     protected void login(HttpServletRequest req, HttpServletResponse res)
438         throws Exception {
439 
440         String login = ParamUtil.getString(req, "login").toLowerCase();
441         String password = ParamUtil.getString(
442             req, SessionParameters.get(req, "password"));
443         boolean rememberMe = ParamUtil.getBoolean(req, "rememberMe");
444 
445         login(req, res, login, password, rememberMe);
446     }
447 
448     protected void sendPassword(HttpServletRequest req) throws Exception {
449         ThemeDisplay themeDisplay =
450             (ThemeDisplay)req.getAttribute(WebKeys.THEME_DISPLAY);
451 
452         Company company = themeDisplay.getCompany();
453 
454         if (!company.isSendPassword()) {
455             return;
456         }
457 
458         CaptchaUtil.check(req);
459 
460         String emailAddress = ParamUtil.getString(req, "emailAddress");
461 
462         String remoteAddr = req.getRemoteAddr();
463         String remoteHost = req.getRemoteHost();
464         String userAgent = req.getHeader(HttpHeaders.USER_AGENT);
465 
466         UserLocalServiceUtil.sendPassword(
467             PortalUtil.getCompanyId(req), emailAddress, remoteAddr, remoteHost,
468             userAgent);
469 
470         SessionMessages.add(req, "request_processed", emailAddress);
471     }
472 
473     private static Log _log = LogFactory.getLog(LoginAction.class);
474 
475 }