001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.login.util;
016    
017    import com.liferay.portal.kernel.cluster.ClusterExecutorUtil;
018    import com.liferay.portal.kernel.cluster.ClusterNode;
019    import com.liferay.portal.kernel.exception.PortalException;
020    import com.liferay.portal.kernel.json.JSONFactoryUtil;
021    import com.liferay.portal.kernel.json.JSONObject;
022    import com.liferay.portal.kernel.language.LanguageUtil;
023    import com.liferay.portal.kernel.log.Log;
024    import com.liferay.portal.kernel.log.LogFactoryUtil;
025    import com.liferay.portal.kernel.messaging.DestinationNames;
026    import com.liferay.portal.kernel.messaging.MessageBusUtil;
027    import com.liferay.portal.kernel.servlet.SessionMessages;
028    import com.liferay.portal.kernel.util.CookieKeys;
029    import com.liferay.portal.kernel.util.GetterUtil;
030    import com.liferay.portal.kernel.util.HtmlUtil;
031    import com.liferay.portal.kernel.util.Http;
032    import com.liferay.portal.kernel.util.MapUtil;
033    import com.liferay.portal.kernel.util.ParamUtil;
034    import com.liferay.portal.kernel.util.StringPool;
035    import com.liferay.portal.kernel.util.StringUtil;
036    import com.liferay.portal.kernel.util.Validator;
037    import com.liferay.portal.liveusers.LiveUsers;
038    import com.liferay.portal.model.Company;
039    import com.liferay.portal.model.CompanyConstants;
040    import com.liferay.portal.model.User;
041    import com.liferay.portal.model.UserTracker;
042    import com.liferay.portal.security.auth.AuthException;
043    import com.liferay.portal.security.auth.AuthenticatedUserUUIDStoreUtil;
044    import com.liferay.portal.security.auth.Authenticator;
045    import com.liferay.portal.service.CompanyLocalServiceUtil;
046    import com.liferay.portal.service.ServiceContext;
047    import com.liferay.portal.service.ServiceContextFactory;
048    import com.liferay.portal.service.UserLocalServiceUtil;
049    import com.liferay.portal.theme.ThemeDisplay;
050    import com.liferay.portal.util.PortalUtil;
051    import com.liferay.portal.util.PortletKeys;
052    import com.liferay.portal.util.PropsValues;
053    import com.liferay.portal.util.WebKeys;
054    import com.liferay.portlet.PortletURLFactoryUtil;
055    import com.liferay.util.Encryptor;
056    
057    import java.util.ArrayList;
058    import java.util.Enumeration;
059    import java.util.HashMap;
060    import java.util.LinkedHashMap;
061    import java.util.List;
062    import java.util.Map;
063    
064    import javax.portlet.ActionRequest;
065    import javax.portlet.PortletMode;
066    import javax.portlet.PortletModeException;
067    import javax.portlet.PortletPreferences;
068    import javax.portlet.PortletRequest;
069    import javax.portlet.PortletURL;
070    import javax.portlet.WindowState;
071    import javax.portlet.WindowStateException;
072    
073    import javax.servlet.http.Cookie;
074    import javax.servlet.http.HttpServletRequest;
075    import javax.servlet.http.HttpServletResponse;
076    import javax.servlet.http.HttpSession;
077    
078    /**
079     * @author Brian Wing Shun Chan
080     * @author Scott Lee
081     */
082    public class LoginUtil {
083    
084            public static long getAuthenticatedUserId(
085                            HttpServletRequest request, String login, String password,
086                            String authType)
087                    throws PortalException {
088    
089                    long userId = GetterUtil.getLong(login);
090    
091                    Company company = PortalUtil.getCompany(request);
092    
093                    String requestURI = request.getRequestURI();
094    
095                    String contextPath = PortalUtil.getPathContext();
096    
097                    if (requestURI.startsWith(contextPath.concat("/api/liferay"))) {
098                            throw new AuthException();
099                    }
100                    else {
101                            Map<String, String[]> headerMap = new HashMap<String, String[]>();
102    
103                            Enumeration<String> enu1 = request.getHeaderNames();
104    
105                            while (enu1.hasMoreElements()) {
106                                    String name = enu1.nextElement();
107    
108                                    Enumeration<String> enu2 = request.getHeaders(name);
109    
110                                    List<String> headers = new ArrayList<String>();
111    
112                                    while (enu2.hasMoreElements()) {
113                                            String value = enu2.nextElement();
114    
115                                            headers.add(value);
116                                    }
117    
118                                    headerMap.put(
119                                            name, headers.toArray(new String[headers.size()]));
120                            }
121    
122                            Map<String, String[]> parameterMap = request.getParameterMap();
123                            Map<String, Object> resultsMap = new HashMap<String, Object>();
124    
125                            if (Validator.isNull(authType)) {
126                                    authType = company.getAuthType();
127                            }
128    
129                            int authResult = Authenticator.FAILURE;
130    
131                            if (authType.equals(CompanyConstants.AUTH_TYPE_EA)) {
132                                    authResult = UserLocalServiceUtil.authenticateByEmailAddress(
133                                            company.getCompanyId(), login, password, headerMap,
134                                            parameterMap, resultsMap);
135    
136                                    userId = MapUtil.getLong(resultsMap, "userId", userId);
137                            }
138                            else if (authType.equals(CompanyConstants.AUTH_TYPE_SN)) {
139                                    authResult = UserLocalServiceUtil.authenticateByScreenName(
140                                            company.getCompanyId(), login, password, headerMap,
141                                            parameterMap, resultsMap);
142    
143                                    userId = MapUtil.getLong(resultsMap, "userId", userId);
144                            }
145                            else if (authType.equals(CompanyConstants.AUTH_TYPE_ID)) {
146                                    authResult = UserLocalServiceUtil.authenticateByUserId(
147                                            company.getCompanyId(), userId, password, headerMap,
148                                            parameterMap, resultsMap);
149                            }
150    
151                            if (authResult != Authenticator.SUCCESS) {
152                                    throw new AuthException();
153                            }
154                    }
155    
156                    return userId;
157            }
158    
159            public static Map<String, String> getEmailDefinitionTerms(
160                    PortletRequest portletRequest, String emailFromAddress,
161                    String emailFromName, boolean showPasswordTerms) {
162    
163                    ThemeDisplay themeDisplay = (ThemeDisplay)portletRequest.getAttribute(
164                            WebKeys.THEME_DISPLAY);
165    
166                    Map<String, String> definitionTerms =
167                            new LinkedHashMap<String, String>();
168    
169                    definitionTerms.put(
170                            "[$FROM_ADDRESS$]", HtmlUtil.escape(emailFromAddress));
171                    definitionTerms.put("[$FROM_NAME$]", HtmlUtil.escape(emailFromName));
172    
173                    if (showPasswordTerms) {
174                            definitionTerms.put(
175                                    "[$PASSWORD_RESET_URL$]",
176                                    LanguageUtil.get(
177                                            themeDisplay.getLocale(), "the-password-reset-url"));
178                    }
179    
180                    Company company = themeDisplay.getCompany();
181    
182                    definitionTerms.put("[$PORTAL_URL$]", company.getVirtualHostname());
183    
184                    definitionTerms.put(
185                            "[$REMOTE_ADDRESS$]",
186                            LanguageUtil.get(
187                                    themeDisplay.getLocale(), "the-browser's-remote-address"));
188                    definitionTerms.put(
189                            "[$REMOTE_HOST$]",
190                            LanguageUtil.get(
191                                    themeDisplay.getLocale(), "the-browser's-remote-host"));
192                    definitionTerms.put(
193                            "[$TO_ADDRESS$]",
194                            LanguageUtil.get(
195                                    themeDisplay.getLocale(),
196                                    "the-address-of-the-email-recipient"));
197                    definitionTerms.put(
198                            "[$TO_NAME$]",
199                            LanguageUtil.get(
200                                    themeDisplay.getLocale(), "the-name-of-the-email-recipient"));
201                    definitionTerms.put(
202                            "[$USER_ID$]",
203                            LanguageUtil.get(themeDisplay.getLocale(), "the-user-id"));
204    
205                    if (showPasswordTerms) {
206                            definitionTerms.put(
207                                    "[$USER_PASSWORD$]",
208                                    LanguageUtil.get(
209                                            themeDisplay.getLocale(), "the-user-password"));
210                    }
211    
212                    definitionTerms.put(
213                            "[$USER_SCREENNAME$]",
214                            LanguageUtil.get(themeDisplay.getLocale(), "the-user-screen-name"));
215    
216                    return definitionTerms;
217            }
218    
219            public static String getEmailFromAddress(
220                    PortletPreferences preferences, long companyId) {
221    
222                    return PortalUtil.getEmailFromAddress(
223                            preferences, companyId, PropsValues.LOGIN_EMAIL_FROM_ADDRESS);
224            }
225    
226            public static String getEmailFromName(
227                    PortletPreferences preferences, long companyId) {
228    
229                    return PortalUtil.getEmailFromName(
230                            preferences, companyId, PropsValues.LOGIN_EMAIL_FROM_NAME);
231            }
232    
233            public static String getLogin(
234                    HttpServletRequest request, String paramName, Company company) {
235    
236                    String login = request.getParameter(paramName);
237    
238                    if ((login == null) || login.equals(StringPool.NULL)) {
239                            login = GetterUtil.getString(
240                                    CookieKeys.getCookie(request, CookieKeys.LOGIN, false));
241    
242                            if (PropsValues.COMPANY_LOGIN_PREPOPULATE_DOMAIN &&
243                                    Validator.isNull(login) &&
244                                    company.getAuthType().equals(CompanyConstants.AUTH_TYPE_EA)) {
245    
246                                    login = "@" + company.getMx();
247                            }
248                    }
249    
250                    return login;
251            }
252    
253            public static PortletURL getLoginURL(HttpServletRequest request, long plid)
254                    throws PortletModeException, WindowStateException {
255    
256                    PortletURL portletURL = PortletURLFactoryUtil.create(
257                            request, PortletKeys.LOGIN, plid, PortletRequest.RENDER_PHASE);
258    
259                    portletURL.setParameter("saveLastPath", Boolean.FALSE.toString());
260                    portletURL.setParameter("struts_action", "/login/login");
261                    portletURL.setPortletMode(PortletMode.VIEW);
262                    portletURL.setWindowState(WindowState.MAXIMIZED);
263    
264                    return portletURL;
265            }
266    
267            public static void login(
268                            HttpServletRequest request, HttpServletResponse response,
269                            String login, String password, boolean rememberMe, String authType)
270                    throws Exception {
271    
272                    CookieKeys.validateSupportCookie(request);
273    
274                    HttpSession session = request.getSession();
275    
276                    Company company = PortalUtil.getCompany(request);
277    
278                    long userId = getAuthenticatedUserId(
279                            request, login, password, authType);
280    
281                    if (!PropsValues.AUTH_SIMULTANEOUS_LOGINS) {
282                            signOutSimultaneousLogins(userId);
283                    }
284    
285                    if (PropsValues.SESSION_ENABLE_PHISHING_PROTECTION) {
286                            session = renewSession(request, session);
287                    }
288    
289                    // Set cookies
290    
291                    String domain = CookieKeys.getDomain(request);
292    
293                    User user = UserLocalServiceUtil.getUserById(userId);
294    
295                    String userIdString = String.valueOf(userId);
296    
297                    session.setAttribute("j_username", userIdString);
298    
299                    if (PropsValues.PORTAL_JAAS_PLAIN_PASSWORD) {
300                            session.setAttribute("j_password", password);
301                    }
302                    else {
303                            session.setAttribute("j_password", user.getPassword());
304                    }
305    
306                    session.setAttribute("j_remoteuser", userIdString);
307    
308                    if (PropsValues.SESSION_STORE_PASSWORD) {
309                            session.setAttribute(WebKeys.USER_PASSWORD, password);
310                    }
311    
312                    Cookie companyIdCookie = new Cookie(
313                            CookieKeys.COMPANY_ID, String.valueOf(company.getCompanyId()));
314    
315                    if (Validator.isNotNull(domain)) {
316                            companyIdCookie.setDomain(domain);
317                    }
318    
319                    companyIdCookie.setPath(StringPool.SLASH);
320    
321                    Cookie idCookie = new Cookie(
322                            CookieKeys.ID,
323                            Encryptor.encrypt(company.getKeyObj(), userIdString));
324    
325                    if (Validator.isNotNull(domain)) {
326                            idCookie.setDomain(domain);
327                    }
328    
329                    idCookie.setPath(StringPool.SLASH);
330    
331                    Cookie passwordCookie = new Cookie(
332                            CookieKeys.PASSWORD,
333                            Encryptor.encrypt(company.getKeyObj(), password));
334    
335                    if (Validator.isNotNull(domain)) {
336                            passwordCookie.setDomain(domain);
337                    }
338    
339                    passwordCookie.setPath(StringPool.SLASH);
340    
341                    Cookie rememberMeCookie = new Cookie(
342                            CookieKeys.REMEMBER_ME, Boolean.TRUE.toString());
343    
344                    if (Validator.isNotNull(domain)) {
345                            rememberMeCookie.setDomain(domain);
346                    }
347    
348                    rememberMeCookie.setPath(StringPool.SLASH);
349    
350                    int loginMaxAge = PropsValues.COMPANY_SECURITY_AUTO_LOGIN_MAX_AGE;
351    
352                    String userUUID = userIdString.concat(StringPool.PERIOD).concat(
353                            String.valueOf(System.nanoTime()));
354    
355                    Cookie userUUIDCookie = new Cookie(
356                            CookieKeys.USER_UUID,
357                            Encryptor.encrypt(company.getKeyObj(), userUUID));
358    
359                    userUUIDCookie.setPath(StringPool.SLASH);
360    
361                    session.setAttribute(WebKeys.USER_UUID, userUUID);
362    
363                    if (PropsValues.SESSION_DISABLED) {
364                            rememberMe = true;
365                    }
366    
367                    if (rememberMe) {
368                            companyIdCookie.setMaxAge(loginMaxAge);
369                            idCookie.setMaxAge(loginMaxAge);
370                            passwordCookie.setMaxAge(loginMaxAge);
371                            rememberMeCookie.setMaxAge(loginMaxAge);
372                            userUUIDCookie.setMaxAge(loginMaxAge);
373                    }
374                    else {
375    
376                            // This was explicitly changed from 0 to -1 so that the cookie lasts
377                            // as long as the browser. This allows an external servlet wrapped
378                            // in AutoLoginFilter to work throughout the client connection. The
379                            // cookies ARE removed on an actual logout, so there is no security
380                            // issue. See LEP-4678 and LEP-5177.
381    
382                            companyIdCookie.setMaxAge(-1);
383                            idCookie.setMaxAge(-1);
384                            passwordCookie.setMaxAge(-1);
385                            rememberMeCookie.setMaxAge(0);
386                            userUUIDCookie.setMaxAge(-1);
387                    }
388    
389                    Cookie loginCookie = new Cookie(CookieKeys.LOGIN, login);
390    
391                    if (Validator.isNotNull(domain)) {
392                            loginCookie.setDomain(domain);
393                    }
394    
395                    loginCookie.setMaxAge(loginMaxAge);
396                    loginCookie.setPath(StringPool.SLASH);
397    
398                    Cookie screenNameCookie = new Cookie(
399                            CookieKeys.SCREEN_NAME,
400                            Encryptor.encrypt(company.getKeyObj(), user.getScreenName()));
401    
402                    if (Validator.isNotNull(domain)) {
403                            screenNameCookie.setDomain(domain);
404                    }
405    
406                    screenNameCookie.setMaxAge(loginMaxAge);
407                    screenNameCookie.setPath(StringPool.SLASH);
408    
409                    boolean secure = request.isSecure();
410    
411                    if (secure && !PropsValues.COMPANY_SECURITY_AUTH_REQUIRES_HTTPS &&
412                            !StringUtil.equalsIgnoreCase(
413                                    Http.HTTPS, PropsValues.WEB_SERVER_PROTOCOL)) {
414    
415                            Boolean httpsInitial = (Boolean)session.getAttribute(
416                                    WebKeys.HTTPS_INITIAL);
417    
418                            if ((httpsInitial == null) || !httpsInitial.booleanValue()) {
419                                    secure = false;
420                            }
421                    }
422    
423                    CookieKeys.addCookie(request, response, companyIdCookie, secure);
424                    CookieKeys.addCookie(request, response, idCookie, secure);
425                    CookieKeys.addCookie(request, response, userUUIDCookie, secure);
426    
427                    if (rememberMe) {
428                            CookieKeys.addCookie(request, response, loginCookie, secure);
429                            CookieKeys.addCookie(request, response, passwordCookie, secure);
430                            CookieKeys.addCookie(request, response, rememberMeCookie, secure);
431                            CookieKeys.addCookie(request, response, screenNameCookie, secure);
432                    }
433    
434                    AuthenticatedUserUUIDStoreUtil.register(userUUID);
435            }
436    
437            public static HttpSession renewSession(
438                            HttpServletRequest request, HttpSession session)
439                    throws Exception {
440    
441                    // Invalidate the previous session to prevent phishing
442    
443                    String[] protectedAttributeNames =
444                            PropsValues.SESSION_PHISHING_PROTECTED_ATTRIBUTES;
445    
446                    Map<String, Object> protectedAttributes = new HashMap<String, Object>();
447    
448                    for (String protectedAttributeName : protectedAttributeNames) {
449                            Object protectedAttributeValue = session.getAttribute(
450                                    protectedAttributeName);
451    
452                            if (protectedAttributeValue == null) {
453                                    continue;
454                            }
455    
456                            protectedAttributes.put(
457                                    protectedAttributeName, protectedAttributeValue);
458                    }
459    
460                    try {
461                            session.invalidate();
462                    }
463                    catch (IllegalStateException ise) {
464    
465                            // This only happens in Geronimo
466    
467                            if (_log.isWarnEnabled()) {
468                                    _log.warn(ise.getMessage());
469                            }
470                    }
471    
472                    session = request.getSession(true);
473    
474                    for (String protectedAttributeName : protectedAttributeNames) {
475                            Object protectedAttributeValue = protectedAttributes.get(
476                                    protectedAttributeName);
477    
478                            if (protectedAttributeValue == null) {
479                                    continue;
480                            }
481    
482                            session.setAttribute(
483                                    protectedAttributeName, protectedAttributeValue);
484                    }
485    
486                    return session;
487            }
488    
489            public static void sendPassword(ActionRequest actionRequest)
490                    throws Exception {
491    
492                    String toAddress = ParamUtil.getString(actionRequest, "emailAddress");
493    
494                    sendPassword(actionRequest, null, null, toAddress, null, null);
495            }
496    
497            public static void sendPassword(
498                            ActionRequest actionRequest, String fromName, String fromAddress,
499                            String toAddress, String subject, String body)
500                    throws Exception {
501    
502                    HttpServletRequest request = PortalUtil.getHttpServletRequest(
503                            actionRequest);
504    
505                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
506                            WebKeys.THEME_DISPLAY);
507    
508                    Company company = themeDisplay.getCompany();
509    
510                    if (!company.isSendPassword() && !company.isSendPasswordResetLink()) {
511                            return;
512                    }
513    
514                    ServiceContext serviceContext = ServiceContextFactory.getInstance(
515                            User.class.getName(), actionRequest);
516    
517                    UserLocalServiceUtil.sendPassword(
518                            company.getCompanyId(), toAddress, fromName, fromAddress, subject,
519                            body, serviceContext);
520    
521                    SessionMessages.add(actionRequest, "requestProcessed", toAddress);
522            }
523    
524            public static void signOutSimultaneousLogins(long userId) throws Exception {
525                    long companyId = CompanyLocalServiceUtil.getCompanyIdByUserId(userId);
526    
527                    Map<String, UserTracker> sessionUsers = LiveUsers.getSessionUsers(
528                            companyId);
529    
530                    List<UserTracker> userTrackers = new ArrayList<UserTracker>(
531                            sessionUsers.values());
532    
533                    for (UserTracker userTracker : userTrackers) {
534                            if (userId != userTracker.getUserId()) {
535                                    continue;
536                            }
537    
538                            JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
539    
540                            ClusterNode clusterNode = ClusterExecutorUtil.getLocalClusterNode();
541    
542                            if (clusterNode != null) {
543                                    jsonObject.put("clusterNodeId", clusterNode.getClusterNodeId());
544                            }
545    
546                            jsonObject.put("command", "signOut");
547                            jsonObject.put("companyId", companyId);
548                            jsonObject.put("sessionId", userTracker.getSessionId());
549                            jsonObject.put("userId", userId);
550    
551                            MessageBusUtil.sendMessage(
552                                    DestinationNames.LIVE_USERS, jsonObject.toString());
553                    }
554            }
555    
556            private static final Log _log = LogFactoryUtil.getLog(LoginUtil.class);
557    
558    }