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.portal.security.auth.session;
016    
017    import com.liferay.portal.events.EventsProcessorUtil;
018    import com.liferay.portal.kernel.cluster.ClusterExecutorUtil;
019    import com.liferay.portal.kernel.cluster.ClusterNode;
020    import com.liferay.portal.kernel.exception.PortalException;
021    import com.liferay.portal.kernel.json.JSONFactoryUtil;
022    import com.liferay.portal.kernel.json.JSONObject;
023    import com.liferay.portal.kernel.messaging.DestinationNames;
024    import com.liferay.portal.kernel.messaging.MessageBusUtil;
025    import com.liferay.portal.kernel.security.auth.session.AuthenticatedSessionManager;
026    import com.liferay.portal.kernel.security.pacl.DoPrivileged;
027    import com.liferay.portal.kernel.util.CookieKeys;
028    import com.liferay.portal.kernel.util.GetterUtil;
029    import com.liferay.portal.kernel.util.Http;
030    import com.liferay.portal.kernel.util.MapUtil;
031    import com.liferay.portal.kernel.util.PropsKeys;
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.kernel.util.WebKeys;
036    import com.liferay.portal.liveusers.LiveUsers;
037    import com.liferay.portal.model.Company;
038    import com.liferay.portal.model.CompanyConstants;
039    import com.liferay.portal.model.User;
040    import com.liferay.portal.model.UserTracker;
041    import com.liferay.portal.security.auth.AuthException;
042    import com.liferay.portal.security.auth.AuthenticatedUserUUIDStoreUtil;
043    import com.liferay.portal.security.auth.Authenticator;
044    import com.liferay.portal.service.CompanyLocalServiceUtil;
045    import com.liferay.portal.service.UserLocalServiceUtil;
046    import com.liferay.portal.util.PortalUtil;
047    import com.liferay.portal.util.PropsValues;
048    import com.liferay.util.Encryptor;
049    
050    import java.util.ArrayList;
051    import java.util.Enumeration;
052    import java.util.HashMap;
053    import java.util.List;
054    import java.util.Map;
055    
056    import javax.servlet.http.Cookie;
057    import javax.servlet.http.HttpServletRequest;
058    import javax.servlet.http.HttpServletResponse;
059    import javax.servlet.http.HttpSession;
060    
061    /**
062     * @author Tomas Polesovsky
063     */
064    @DoPrivileged
065    public class AuthenticatedSessionManagerImpl
066            implements AuthenticatedSessionManager {
067    
068            @Override
069            public long getAuthenticatedUserId(
070                            HttpServletRequest request, String login, String password,
071                            String authType)
072                    throws PortalException {
073    
074                    long userId = GetterUtil.getLong(login);
075    
076                    Company company = PortalUtil.getCompany(request);
077    
078                    String requestURI = request.getRequestURI();
079    
080                    String contextPath = PortalUtil.getPathContext();
081    
082                    if (requestURI.startsWith(contextPath.concat("/api/liferay"))) {
083                            throw new AuthException();
084                    }
085                    else {
086                            Map<String, String[]> headerMap = new HashMap<>();
087    
088                            Enumeration<String> enu1 = request.getHeaderNames();
089    
090                            while (enu1.hasMoreElements()) {
091                                    String name = enu1.nextElement();
092    
093                                    Enumeration<String> enu2 = request.getHeaders(name);
094    
095                                    List<String> headers = new ArrayList<>();
096    
097                                    while (enu2.hasMoreElements()) {
098                                            String value = enu2.nextElement();
099    
100                                            headers.add(value);
101                                    }
102    
103                                    headerMap.put(
104                                            name, headers.toArray(new String[headers.size()]));
105                            }
106    
107                            Map<String, String[]> parameterMap = request.getParameterMap();
108                            Map<String, Object> resultsMap = new HashMap<>();
109    
110                            if (Validator.isNull(authType)) {
111                                    authType = company.getAuthType();
112                            }
113    
114                            int authResult = Authenticator.FAILURE;
115    
116                            if (authType.equals(CompanyConstants.AUTH_TYPE_EA)) {
117                                    authResult = UserLocalServiceUtil.authenticateByEmailAddress(
118                                            company.getCompanyId(), login, password, headerMap,
119                                            parameterMap, resultsMap);
120    
121                                    userId = MapUtil.getLong(resultsMap, "userId", userId);
122                            }
123                            else if (authType.equals(CompanyConstants.AUTH_TYPE_SN)) {
124                                    authResult = UserLocalServiceUtil.authenticateByScreenName(
125                                            company.getCompanyId(), login, password, headerMap,
126                                            parameterMap, resultsMap);
127    
128                                    userId = MapUtil.getLong(resultsMap, "userId", userId);
129                            }
130                            else if (authType.equals(CompanyConstants.AUTH_TYPE_ID)) {
131                                    authResult = UserLocalServiceUtil.authenticateByUserId(
132                                            company.getCompanyId(), userId, password, headerMap,
133                                            parameterMap, resultsMap);
134                            }
135    
136                            if (authResult != Authenticator.SUCCESS) {
137                                    User user = UserLocalServiceUtil.fetchUser(userId);
138    
139                                    if (user != null) {
140                                            UserLocalServiceUtil.checkLockout(user);
141                                    }
142    
143                                    throw new AuthException();
144                            }
145                    }
146    
147                    return userId;
148            }
149    
150            @Override
151            public void login(
152                            HttpServletRequest request, HttpServletResponse response,
153                            String login, String password, boolean rememberMe, String authType)
154                    throws Exception {
155    
156                    CookieKeys.validateSupportCookie(request);
157    
158                    HttpSession session = request.getSession();
159    
160                    Company company = PortalUtil.getCompany(request);
161    
162                    long userId = getAuthenticatedUserId(
163                            request, login, password, authType);
164    
165                    if (!PropsValues.AUTH_SIMULTANEOUS_LOGINS) {
166                            signOutSimultaneousLogins(userId);
167                    }
168    
169                    if (PropsValues.SESSION_ENABLE_PHISHING_PROTECTION) {
170                            session = renewSession(request, session);
171                    }
172    
173                    // Set cookies
174    
175                    String domain = CookieKeys.getDomain(request);
176    
177                    User user = UserLocalServiceUtil.getUserById(userId);
178    
179                    String userIdString = String.valueOf(userId);
180    
181                    session.setAttribute("j_username", userIdString);
182    
183                    if (PropsValues.PORTAL_JAAS_PLAIN_PASSWORD) {
184                            session.setAttribute("j_password", password);
185                    }
186                    else {
187                            session.setAttribute("j_password", user.getPassword());
188                    }
189    
190                    session.setAttribute("j_remoteuser", userIdString);
191    
192                    if (PropsValues.SESSION_STORE_PASSWORD) {
193                            session.setAttribute(WebKeys.USER_PASSWORD, password);
194                    }
195    
196                    Cookie companyIdCookie = new Cookie(
197                            CookieKeys.COMPANY_ID, String.valueOf(company.getCompanyId()));
198    
199                    if (Validator.isNotNull(domain)) {
200                            companyIdCookie.setDomain(domain);
201                    }
202    
203                    companyIdCookie.setPath(StringPool.SLASH);
204    
205                    Cookie idCookie = new Cookie(
206                            CookieKeys.ID,
207                            Encryptor.encrypt(company.getKeyObj(), userIdString));
208    
209                    if (Validator.isNotNull(domain)) {
210                            idCookie.setDomain(domain);
211                    }
212    
213                    idCookie.setPath(StringPool.SLASH);
214    
215                    Cookie passwordCookie = new Cookie(
216                            CookieKeys.PASSWORD,
217                            Encryptor.encrypt(company.getKeyObj(), password));
218    
219                    if (Validator.isNotNull(domain)) {
220                            passwordCookie.setDomain(domain);
221                    }
222    
223                    passwordCookie.setPath(StringPool.SLASH);
224    
225                    Cookie rememberMeCookie = new Cookie(
226                            CookieKeys.REMEMBER_ME, Boolean.TRUE.toString());
227    
228                    if (Validator.isNotNull(domain)) {
229                            rememberMeCookie.setDomain(domain);
230                    }
231    
232                    rememberMeCookie.setPath(StringPool.SLASH);
233    
234                    int loginMaxAge = PropsValues.COMPANY_SECURITY_AUTO_LOGIN_MAX_AGE;
235    
236                    String userUUID = userIdString.concat(StringPool.PERIOD).concat(
237                            String.valueOf(System.nanoTime()));
238    
239                    Cookie userUUIDCookie = new Cookie(
240                            CookieKeys.USER_UUID,
241                            Encryptor.encrypt(company.getKeyObj(), userUUID));
242    
243                    userUUIDCookie.setPath(StringPool.SLASH);
244    
245                    session.setAttribute(WebKeys.USER_UUID, userUUID);
246    
247                    if (PropsValues.SESSION_DISABLED) {
248                            rememberMe = true;
249                    }
250    
251                    if (rememberMe) {
252                            companyIdCookie.setMaxAge(loginMaxAge);
253                            idCookie.setMaxAge(loginMaxAge);
254                            passwordCookie.setMaxAge(loginMaxAge);
255                            rememberMeCookie.setMaxAge(loginMaxAge);
256                            userUUIDCookie.setMaxAge(loginMaxAge);
257                    }
258                    else {
259    
260                            // This was explicitly changed from 0 to -1 so that the cookie lasts
261                            // as long as the browser. This allows an external servlet wrapped
262                            // in AutoLoginFilter to work throughout the client connection. The
263                            // cookies ARE removed on an actual logout, so there is no security
264                            // issue. See LEP-4678 and LEP-5177.
265    
266                            companyIdCookie.setMaxAge(-1);
267                            idCookie.setMaxAge(-1);
268                            passwordCookie.setMaxAge(-1);
269                            rememberMeCookie.setMaxAge(0);
270                            userUUIDCookie.setMaxAge(-1);
271                    }
272    
273                    Cookie loginCookie = new Cookie(CookieKeys.LOGIN, login);
274    
275                    if (Validator.isNotNull(domain)) {
276                            loginCookie.setDomain(domain);
277                    }
278    
279                    loginCookie.setMaxAge(loginMaxAge);
280                    loginCookie.setPath(StringPool.SLASH);
281    
282                    Cookie screenNameCookie = new Cookie(
283                            CookieKeys.SCREEN_NAME,
284                            Encryptor.encrypt(company.getKeyObj(), user.getScreenName()));
285    
286                    if (Validator.isNotNull(domain)) {
287                            screenNameCookie.setDomain(domain);
288                    }
289    
290                    screenNameCookie.setMaxAge(loginMaxAge);
291                    screenNameCookie.setPath(StringPool.SLASH);
292    
293                    boolean secure = request.isSecure();
294    
295                    if (secure && !PropsValues.COMPANY_SECURITY_AUTH_REQUIRES_HTTPS &&
296                            !StringUtil.equalsIgnoreCase(
297                                    Http.HTTPS, PropsValues.WEB_SERVER_PROTOCOL)) {
298    
299                            Boolean httpsInitial = (Boolean)session.getAttribute(
300                                    WebKeys.HTTPS_INITIAL);
301    
302                            if ((httpsInitial == null) || !httpsInitial.booleanValue()) {
303                                    secure = false;
304                            }
305                    }
306    
307                    CookieKeys.addCookie(request, response, companyIdCookie, secure);
308                    CookieKeys.addCookie(request, response, idCookie, secure);
309                    CookieKeys.addCookie(request, response, userUUIDCookie, secure);
310    
311                    if (rememberMe) {
312                            CookieKeys.addCookie(request, response, loginCookie, secure);
313                            CookieKeys.addCookie(request, response, passwordCookie, secure);
314                            CookieKeys.addCookie(request, response, rememberMeCookie, secure);
315                            CookieKeys.addCookie(request, response, screenNameCookie, secure);
316                    }
317    
318                    AuthenticatedUserUUIDStoreUtil.register(userUUID);
319            }
320    
321            @Override
322            public void logout(HttpServletRequest request, HttpServletResponse response)
323                    throws Exception {
324    
325                    HttpSession session = request.getSession();
326    
327                    EventsProcessorUtil.process(
328                            PropsKeys.LOGOUT_EVENTS_PRE, PropsValues.LOGOUT_EVENTS_PRE, request,
329                            response);
330    
331                    String domain = CookieKeys.getDomain(request);
332    
333                    Cookie companyIdCookie = new Cookie(
334                            CookieKeys.COMPANY_ID, StringPool.BLANK);
335    
336                    if (Validator.isNotNull(domain)) {
337                            companyIdCookie.setDomain(domain);
338                    }
339    
340                    companyIdCookie.setMaxAge(0);
341                    companyIdCookie.setPath(StringPool.SLASH);
342    
343                    Cookie idCookie = new Cookie(CookieKeys.ID, StringPool.BLANK);
344    
345                    if (Validator.isNotNull(domain)) {
346                            idCookie.setDomain(domain);
347                    }
348    
349                    idCookie.setMaxAge(0);
350                    idCookie.setPath(StringPool.SLASH);
351    
352                    Cookie passwordCookie = new Cookie(
353                            CookieKeys.PASSWORD, StringPool.BLANK);
354    
355                    if (Validator.isNotNull(domain)) {
356                            passwordCookie.setDomain(domain);
357                    }
358    
359                    passwordCookie.setMaxAge(0);
360                    passwordCookie.setPath(StringPool.SLASH);
361    
362                    boolean rememberMe = GetterUtil.getBoolean(
363                            CookieKeys.getCookie(request, CookieKeys.REMEMBER_ME));
364    
365                    if (!rememberMe) {
366                            Cookie loginCookie = new Cookie(CookieKeys.LOGIN, StringPool.BLANK);
367    
368                            if (Validator.isNotNull(domain)) {
369                                    loginCookie.setDomain(domain);
370                            }
371    
372                            loginCookie.setMaxAge(0);
373                            loginCookie.setPath(StringPool.SLASH);
374    
375                            CookieKeys.addCookie(request, response, loginCookie);
376                    }
377    
378                    Cookie rememberMeCookie = new Cookie(
379                            CookieKeys.REMEMBER_ME, StringPool.BLANK);
380    
381                    if (Validator.isNotNull(domain)) {
382                            rememberMeCookie.setDomain(domain);
383                    }
384    
385                    rememberMeCookie.setMaxAge(0);
386                    rememberMeCookie.setPath(StringPool.SLASH);
387    
388                    CookieKeys.addCookie(request, response, companyIdCookie);
389                    CookieKeys.addCookie(request, response, idCookie);
390                    CookieKeys.addCookie(request, response, passwordCookie);
391                    CookieKeys.addCookie(request, response, rememberMeCookie);
392    
393                    try {
394                            session.invalidate();
395                    }
396                    catch (Exception e) {
397                    }
398    
399                    EventsProcessorUtil.process(
400                            PropsKeys.LOGOUT_EVENTS_POST, PropsValues.LOGOUT_EVENTS_POST,
401                            request, response);
402            }
403    
404            @Override
405            public HttpSession renewSession(
406                            HttpServletRequest request, HttpSession session)
407                    throws Exception {
408    
409                    // Invalidate the previous session to prevent session fixation attacks
410    
411                    String[] protectedAttributeNames =
412                            PropsValues.SESSION_PHISHING_PROTECTED_ATTRIBUTES;
413    
414                    Map<String, Object> protectedAttributes = new HashMap<>();
415    
416                    for (String protectedAttributeName : protectedAttributeNames) {
417                            Object protectedAttributeValue = session.getAttribute(
418                                    protectedAttributeName);
419    
420                            if (protectedAttributeValue == null) {
421                                    continue;
422                            }
423    
424                            protectedAttributes.put(
425                                    protectedAttributeName, protectedAttributeValue);
426                    }
427    
428                    session.invalidate();
429    
430                    session = request.getSession(true);
431    
432                    for (String protectedAttributeName : protectedAttributeNames) {
433                            Object protectedAttributeValue = protectedAttributes.get(
434                                    protectedAttributeName);
435    
436                            if (protectedAttributeValue == null) {
437                                    continue;
438                            }
439    
440                            session.setAttribute(
441                                    protectedAttributeName, protectedAttributeValue);
442                    }
443    
444                    return session;
445            }
446    
447            @Override
448            public void signOutSimultaneousLogins(long userId) throws Exception {
449                    long companyId = CompanyLocalServiceUtil.getCompanyIdByUserId(userId);
450    
451                    Map<String, UserTracker> sessionUsers = LiveUsers.getSessionUsers(
452                            companyId);
453    
454                    List<UserTracker> userTrackers = new ArrayList<>(sessionUsers.values());
455    
456                    for (UserTracker userTracker : userTrackers) {
457                            if (userId != userTracker.getUserId()) {
458                                    continue;
459                            }
460    
461                            JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
462    
463                            ClusterNode clusterNode = ClusterExecutorUtil.getLocalClusterNode();
464    
465                            if (clusterNode != null) {
466                                    jsonObject.put("clusterNodeId", clusterNode.getClusterNodeId());
467                            }
468    
469                            jsonObject.put("command", "signOut");
470                            jsonObject.put("companyId", companyId);
471                            jsonObject.put("sessionId", userTracker.getSessionId());
472                            jsonObject.put("userId", userId);
473    
474                            MessageBusUtil.sendMessage(
475                                    DestinationNames.LIVE_USERS, jsonObject.toString());
476                    }
477            }
478    
479    }