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