/**
* 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.servlet.filters.authverifier;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.security.access.control.AccessControlUtil;
import com.liferay.portal.kernel.security.auth.AccessControlContext;
import com.liferay.portal.kernel.security.auth.verifier.AuthVerifierResult;
import com.liferay.portal.kernel.servlet.ProtectedServletRequest;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.util.Http;
import com.liferay.portal.kernel.util.HttpUtil;
import com.liferay.portal.kernel.util.MapUtil;
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.security.auth.AuthVerifierPipeline;
import com.liferay.portal.servlet.filters.BasePortalFilter;
import com.liferay.portal.util.PropsUtil;
import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* <p>
* See https://issues.liferay.com/browse/LPS-27888.
* </p>
*
* @author Tomas Polesovsky
* @author Raymond Augé
*/
public class AuthVerifierFilter extends BasePortalFilter {
@Override
public void init(FilterConfig filterConfig) {
super.init(filterConfig);
Enumeration<String> enu = filterConfig.getInitParameterNames();
while (enu.hasMoreElements()) {
String name = enu.nextElement();
String value = filterConfig.getInitParameter(name);
_initParametersMap.put(name, value);
}
String portalPropertyPrefix = GetterUtil.getString(
_initParametersMap.get("portal_property_prefix"));
if (Validator.isNotNull(portalPropertyPrefix)) {
Properties properties = PropsUtil.getProperties(
portalPropertyPrefix, true);
for (Map.Entry<Object, Object> entry : properties.entrySet()) {
_initParametersMap.put(
(String)entry.getKey(), entry.getValue());
}
}
if (_initParametersMap.containsKey("hosts.allowed")) {
String hostsAllowedString = (String)_initParametersMap.get(
"hosts.allowed");
String[] hostsAllowed = StringUtil.split(hostsAllowedString);
for (String hostAllowed : hostsAllowed) {
_hostsAllowed.add(hostAllowed);
}
_initParametersMap.remove("hosts.allowed");
}
if (_initParametersMap.containsKey("https.required")) {
_httpsRequired = GetterUtil.getBoolean(
_initParametersMap.get("https.required"));
_initParametersMap.remove("https.required");
}
if (_initParametersMap.containsKey("use_permission_checker")) {
_initParametersMap.remove("use_permission_checker");
if (_log.isWarnEnabled()) {
_log.warn("use_permission_checker is deprecated");
}
}
}
@Override
protected void processFilter(
HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain)
throws Exception {
if (!_isAccessAllowed(request, response)) {
return;
}
if (_isApplySSL(request, response)) {
return;
}
AccessControlUtil.initAccessControlContext(
request, response, _initParametersMap);
AuthVerifierResult.State state = AccessControlUtil.verifyRequest();
AccessControlContext accessControlContext =
AccessControlUtil.getAccessControlContext();
AuthVerifierResult authVerifierResult =
accessControlContext.getAuthVerifierResult();
if (_log.isDebugEnabled()) {
_log.debug("Auth verifier result " + authVerifierResult);
}
if (state == AuthVerifierResult.State.INVALID_CREDENTIALS) {
if (_log.isDebugEnabled()) {
_log.debug("Result state doesn't allow us to continue.");
}
}
else if (state == AuthVerifierResult.State.NOT_APPLICABLE) {
_log.error("Invalid state " + state);
}
else if (state == AuthVerifierResult.State.SUCCESS) {
long userId = authVerifierResult.getUserId();
AccessControlUtil.initContextUser(userId);
String authType = MapUtil.getString(
accessControlContext.getSettings(),
AuthVerifierPipeline.AUTH_TYPE);
ProtectedServletRequest protectedServletRequest =
new ProtectedServletRequest(
request, String.valueOf(userId), authType);
accessControlContext.setRequest(protectedServletRequest);
Class<?> clazz = getClass();
processFilter(
clazz.getName(), protectedServletRequest, response,
filterChain);
}
else {
_log.error("Unimplemented state " + state);
}
}
private boolean _isAccessAllowed(
HttpServletRequest request, HttpServletResponse response)
throws IOException {
String remoteAddr = request.getRemoteAddr();
if (AccessControlUtil.isAccessAllowed(request, _hostsAllowed)) {
if (_log.isDebugEnabled()) {
_log.debug("Access allowed for " + remoteAddr);
}
return true;
}
if (_log.isWarnEnabled()) {
_log.warn("Access denied for " + remoteAddr);
}
response.sendError(
HttpServletResponse.SC_FORBIDDEN,
"Access denied for " + remoteAddr);
return false;
}
private boolean _isApplySSL(
HttpServletRequest request, HttpServletResponse response)
throws IOException {
if (!_httpsRequired || request.isSecure()) {
return false;
}
if (_log.isDebugEnabled()) {
String completeURL = HttpUtil.getCompleteURL(request);
_log.debug("Securing " + completeURL);
}
StringBundler redirectURL = new StringBundler(5);
redirectURL.append(Http.HTTPS_WITH_SLASH);
redirectURL.append(request.getServerName());
redirectURL.append(request.getServletPath());
String queryString = request.getQueryString();
if (Validator.isNotNull(queryString)) {
redirectURL.append(StringPool.QUESTION);
redirectURL.append(request.getQueryString());
}
if (_log.isDebugEnabled()) {
_log.debug("Redirect to " + redirectURL);
}
response.sendRedirect(redirectURL.toString());
return true;
}
private static final Log _log = LogFactoryUtil.getLog(
AuthVerifierFilter.class.getName());
private final Set<String> _hostsAllowed = new HashSet<>();
private boolean _httpsRequired;
private final Map<String, Object> _initParametersMap = new HashMap<>();
}