/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.portal.security.auth.session;
import com.liferay.portal.events.EventsProcessorUtil;
import com.liferay.portal.kernel.cluster.ClusterExecutorUtil;
import com.liferay.portal.kernel.cluster.ClusterNode;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.json.JSONFactoryUtil;
import com.liferay.portal.kernel.json.JSONObject;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.messaging.DestinationNames;
import com.liferay.portal.kernel.messaging.MessageBusUtil;
import com.liferay.portal.kernel.model.Company;
import com.liferay.portal.kernel.model.CompanyConstants;
import com.liferay.portal.kernel.model.User;
import com.liferay.portal.kernel.model.UserTracker;
import com.liferay.portal.kernel.security.auth.AuthException;
import com.liferay.portal.kernel.security.auth.AuthenticatedUserUUIDStoreUtil;
import com.liferay.portal.kernel.security.auth.Authenticator;
import com.liferay.portal.kernel.security.auth.session.AuthenticatedSessionManager;
import com.liferay.portal.kernel.security.pacl.DoPrivileged;
import com.liferay.portal.kernel.service.CompanyLocalServiceUtil;
import com.liferay.portal.kernel.service.UserLocalServiceUtil;
import com.liferay.portal.kernel.servlet.HttpHeaders;
import com.liferay.portal.kernel.util.CharPool;
import com.liferay.portal.kernel.util.CookieKeys;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.util.Http;
import com.liferay.portal.kernel.util.PortalUtil;
import com.liferay.portal.kernel.util.PropsKeys;
import com.liferay.portal.kernel.util.StringBundler;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.kernel.util.WebKeys;
import com.liferay.portal.liveusers.LiveUsers;
import com.liferay.portal.util.PropsValues;
import com.liferay.util.Encryptor;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* @author Tomas Polesovsky
*/
@DoPrivileged
public class AuthenticatedSessionManagerImpl
implements AuthenticatedSessionManager {
@Override
public long getAuthenticatedUserId(
HttpServletRequest request, String login, String password,
String authType)
throws PortalException {
User user = _getAuthenticatedUser(request, login, password, authType);
return user.getUserId();
}
@Override
public void login(
HttpServletRequest request, HttpServletResponse response,
String login, String password, boolean rememberMe, String authType)
throws Exception {
request = PortalUtil.getOriginalServletRequest(request);
String queryString = request.getQueryString();
if (queryString.contains("password=")) {
String passwordParameterName = "password=";
String portletId = PortalUtil.getPortletId(request);
if (portletId != null) {
passwordParameterName =
PortalUtil.getPortletNamespace(portletId) +
passwordParameterName;
}
int index = queryString.indexOf(passwordParameterName);
if ((index == 0) ||
((index > 0) &&
(queryString.charAt(index - 1) == CharPool.AMPERSAND))) {
if (_log.isWarnEnabled()) {
String referer = request.getHeader(HttpHeaders.REFERER);
StringBundler sb = new StringBundler(4);
sb.append("Ignoring login attempt because the password ");
sb.append("parameter was found for the request with the ");
sb.append("referer header: ");
sb.append(referer);
_log.warn(sb.toString());
}
return;
}
}
CookieKeys.validateSupportCookie(request);
HttpSession session = request.getSession();
Company company = PortalUtil.getCompany(request);
User user = _getAuthenticatedUser(request, login, password, authType);
if (!PropsValues.AUTH_SIMULTANEOUS_LOGINS) {
signOutSimultaneousLogins(user.getUserId());
}
if (PropsValues.SESSION_ENABLE_PHISHING_PROTECTION) {
session = renewSession(request, session);
}
// Set cookies
String domain = CookieKeys.getDomain(request);
if (Validator.isNull(domain)) {
domain = null;
}
String userIdString = String.valueOf(user.getUserId());
session.setAttribute("j_username", userIdString);
if (PropsValues.PORTAL_JAAS_PLAIN_PASSWORD) {
session.setAttribute("j_password", password);
}
else {
session.setAttribute("j_password", user.getPassword());
}
session.setAttribute("j_remoteuser", userIdString);
if (PropsValues.SESSION_STORE_PASSWORD) {
session.setAttribute(WebKeys.USER_PASSWORD, password);
}
Cookie companyIdCookie = new Cookie(
CookieKeys.COMPANY_ID, String.valueOf(company.getCompanyId()));
if (domain != null) {
companyIdCookie.setDomain(domain);
}
companyIdCookie.setPath(StringPool.SLASH);
Cookie idCookie = new Cookie(
CookieKeys.ID,
Encryptor.encrypt(company.getKeyObj(), userIdString));
if (domain != null) {
idCookie.setDomain(domain);
}
idCookie.setPath(StringPool.SLASH);
int loginMaxAge = PropsValues.COMPANY_SECURITY_AUTO_LOGIN_MAX_AGE;
if (PropsValues.SESSION_DISABLED) {
rememberMe = true;
}
if (rememberMe) {
companyIdCookie.setMaxAge(loginMaxAge);
idCookie.setMaxAge(loginMaxAge);
}
else {
// This was explicitly changed from 0 to -1 so that the cookie lasts
// as long as the browser. This allows an external servlet wrapped
// in AutoLoginFilter to work throughout the client connection. The
// cookies ARE removed on an actual logout, so there is no security
// issue. See LEP-4678 and LEP-5177.
companyIdCookie.setMaxAge(-1);
idCookie.setMaxAge(-1);
}
boolean secure = request.isSecure();
if (secure && !PropsValues.COMPANY_SECURITY_AUTH_REQUIRES_HTTPS &&
!StringUtil.equalsIgnoreCase(
Http.HTTPS, PropsValues.WEB_SERVER_PROTOCOL)) {
Boolean httpsInitial = (Boolean)session.getAttribute(
WebKeys.HTTPS_INITIAL);
if ((httpsInitial == null) || !httpsInitial.booleanValue()) {
secure = false;
}
}
CookieKeys.addCookie(request, response, companyIdCookie, secure);
CookieKeys.addCookie(request, response, idCookie, secure);
if (rememberMe) {
Cookie loginCookie = new Cookie(CookieKeys.LOGIN, login);
if (domain != null) {
loginCookie.setDomain(domain);
}
loginCookie.setMaxAge(loginMaxAge);
loginCookie.setPath(StringPool.SLASH);
CookieKeys.addCookie(request, response, loginCookie, secure);
Cookie passwordCookie = new Cookie(
CookieKeys.PASSWORD,
Encryptor.encrypt(company.getKeyObj(), password));
if (domain != null) {
passwordCookie.setDomain(domain);
}
passwordCookie.setMaxAge(loginMaxAge);
passwordCookie.setPath(StringPool.SLASH);
CookieKeys.addCookie(request, response, passwordCookie, secure);
Cookie rememberMeCookie = new Cookie(
CookieKeys.REMEMBER_ME, Boolean.TRUE.toString());
if (domain != null) {
rememberMeCookie.setDomain(domain);
}
rememberMeCookie.setMaxAge(loginMaxAge);
rememberMeCookie.setPath(StringPool.SLASH);
CookieKeys.addCookie(request, response, rememberMeCookie, secure);
Cookie screenNameCookie = new Cookie(
CookieKeys.SCREEN_NAME,
Encryptor.encrypt(company.getKeyObj(), user.getScreenName()));
if (domain != null) {
screenNameCookie.setDomain(domain);
}
screenNameCookie.setMaxAge(loginMaxAge);
screenNameCookie.setPath(StringPool.SLASH);
CookieKeys.addCookie(request, response, screenNameCookie, secure);
}
if (PropsValues.AUTH_USER_UUID_STORE_ENABLED) {
String userUUID = userIdString.concat(StringPool.PERIOD).concat(
String.valueOf(System.nanoTime()));
Cookie userUUIDCookie = new Cookie(
CookieKeys.USER_UUID,
Encryptor.encrypt(company.getKeyObj(), userUUID));
userUUIDCookie.setPath(StringPool.SLASH);
session.setAttribute(WebKeys.USER_UUID, userUUID);
if (rememberMe) {
userUUIDCookie.setMaxAge(loginMaxAge);
}
else {
userUUIDCookie.setMaxAge(-1);
}
CookieKeys.addCookie(request, response, userUUIDCookie, secure);
AuthenticatedUserUUIDStoreUtil.register(userUUID);
}
}
@Override
public void logout(HttpServletRequest request, HttpServletResponse response)
throws Exception {
HttpSession session = request.getSession();
EventsProcessorUtil.process(
PropsKeys.LOGOUT_EVENTS_PRE, PropsValues.LOGOUT_EVENTS_PRE, request,
response);
String domain = CookieKeys.getDomain(request);
if (Validator.isNull(domain)) {
domain = null;
}
boolean rememberMe = GetterUtil.getBoolean(
CookieKeys.getCookie(request, CookieKeys.REMEMBER_ME, false));
CookieKeys.deleteCookies(
request, response, domain, CookieKeys.COMPANY_ID,
CookieKeys.GUEST_LANGUAGE_ID, CookieKeys.ID, CookieKeys.PASSWORD,
CookieKeys.REMEMBER_ME);
if (!rememberMe) {
CookieKeys.deleteCookies(
request, response, domain, CookieKeys.LOGIN);
}
try {
session.invalidate();
}
catch (Exception e) {
}
EventsProcessorUtil.process(
PropsKeys.LOGOUT_EVENTS_POST, PropsValues.LOGOUT_EVENTS_POST,
request, response);
}
@Override
public HttpSession renewSession(
HttpServletRequest request, HttpSession session)
throws Exception {
// Invalidate the previous session to prevent session fixation attacks
String[] protectedAttributeNames =
PropsValues.SESSION_PHISHING_PROTECTED_ATTRIBUTES;
Map<String, Object> protectedAttributes = new HashMap<>();
for (String protectedAttributeName : protectedAttributeNames) {
Object protectedAttributeValue = session.getAttribute(
protectedAttributeName);
if (protectedAttributeValue == null) {
continue;
}
protectedAttributes.put(
protectedAttributeName, protectedAttributeValue);
}
session.invalidate();
session = request.getSession(true);
for (String protectedAttributeName : protectedAttributeNames) {
Object protectedAttributeValue = protectedAttributes.get(
protectedAttributeName);
if (protectedAttributeValue == null) {
continue;
}
session.setAttribute(
protectedAttributeName, protectedAttributeValue);
}
return session;
}
@Override
public void signOutSimultaneousLogins(long userId) throws Exception {
long companyId = CompanyLocalServiceUtil.getCompanyIdByUserId(userId);
Map<String, UserTracker> sessionUsers = LiveUsers.getSessionUsers(
companyId);
List<UserTracker> userTrackers = new ArrayList<>(sessionUsers.values());
for (UserTracker userTracker : userTrackers) {
if (userId != userTracker.getUserId()) {
continue;
}
JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
ClusterNode clusterNode = ClusterExecutorUtil.getLocalClusterNode();
if (clusterNode != null) {
jsonObject.put("clusterNodeId", clusterNode.getClusterNodeId());
}
jsonObject.put("command", "signOut");
jsonObject.put("companyId", companyId);
jsonObject.put("sessionId", userTracker.getSessionId());
jsonObject.put("userId", userId);
MessageBusUtil.sendMessage(
DestinationNames.LIVE_USERS, jsonObject.toString());
}
}
private User _getAuthenticatedUser(
HttpServletRequest request, String login, String password,
String authType)
throws PortalException {
long userId = GetterUtil.getLong(login);
Company company = PortalUtil.getCompany(request);
String requestURI = request.getRequestURI();
String contextPath = PortalUtil.getPathContext();
if (requestURI.startsWith(contextPath.concat("/api/liferay"))) {
throw new AuthException();
}
else {
Map<String, String[]> headerMap = new HashMap<>();
Enumeration<String> enu1 = request.getHeaderNames();
while (enu1.hasMoreElements()) {
String name = enu1.nextElement();
Enumeration<String> enu2 = request.getHeaders(name);
List<String> headers = new ArrayList<>();
while (enu2.hasMoreElements()) {
String value = enu2.nextElement();
headers.add(value);
}
headerMap.put(
name, headers.toArray(new String[headers.size()]));
}
Map<String, String[]> parameterMap = request.getParameterMap();
Map<String, Object> resultsMap = new HashMap<>();
if (Validator.isNull(authType)) {
authType = company.getAuthType();
}
int authResult = Authenticator.FAILURE;
if (authType.equals(CompanyConstants.AUTH_TYPE_EA)) {
authResult = UserLocalServiceUtil.authenticateByEmailAddress(
company.getCompanyId(), login, password, headerMap,
parameterMap, resultsMap);
}
else if (authType.equals(CompanyConstants.AUTH_TYPE_SN)) {
authResult = UserLocalServiceUtil.authenticateByScreenName(
company.getCompanyId(), login, password, headerMap,
parameterMap, resultsMap);
}
else if (authType.equals(CompanyConstants.AUTH_TYPE_ID)) {
authResult = UserLocalServiceUtil.authenticateByUserId(
company.getCompanyId(), userId, password, headerMap,
parameterMap, resultsMap);
}
User user = (User)resultsMap.get("user");
if (authResult != Authenticator.SUCCESS) {
if (user != null) {
user = UserLocalServiceUtil.fetchUser(user.getUserId());
}
if (user != null) {
UserLocalServiceUtil.checkLockout(user);
}
throw new AuthException();
}
return user;
}
}
private static final Log _log = LogFactoryUtil.getLog(
AuthenticatedSessionManagerImpl.class);
}