blob: fce6eafa6eaa620c386d62ffa11800e6b7161bb8 [file] [log] [blame]
/*******************************************************************************
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*******************************************************************************/
package org.apache.ofbiz.product.category;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.oro.text.regex.Pattern;
import org.apache.oro.text.regex.Perl5Matcher;
import org.apache.ofbiz.base.util.Debug;
import org.apache.ofbiz.base.util.StringUtil;
import org.apache.ofbiz.base.util.UtilHttp;
import org.apache.ofbiz.base.util.UtilValidate;
import org.apache.ofbiz.webapp.control.ConfigXMLReader;
import org.apache.ofbiz.webapp.control.ConfigXMLReader.ControllerConfig;
import org.apache.ofbiz.webapp.control.ControlFilter;
import org.apache.ofbiz.webapp.control.WebAppConfigurationException;
/**
* SeoContextFilter - Restricts access to raw files and configures servlet objects.
*/
public class SeoContextFilter implements Filter {
public static final String module = SeoContextFilter.class.getName();
protected Set<String> WebServlets = new HashSet<>();
private FilterConfig config;
private String allowedPaths = "";
private String redirectPath = "";
private String errorCode = "";
private List<String> allowedPathList = new ArrayList<String>();
public void init(FilterConfig config) throws ServletException {
this.config = config;
allowedPaths = config.getInitParameter("allowedPaths");
redirectPath = config.getInitParameter("redirectPath");
errorCode = config.getInitParameter("errorCode");
if (UtilValidate.isNotEmpty(allowedPaths)) {
allowedPathList = StringUtil.split(allowedPaths, ":");
}
Map<String, ? extends ServletRegistration> servletRegistrations = config.getServletContext().getServletRegistrations();
for (String key : servletRegistrations.keySet()) {
Collection<String> servlets = servletRegistrations.get(key).getMappings();
for (String servlet : servlets) {
if (servlet.endsWith("/*")) {
servlet = servlet.substring(0, servlet.length() - 2);
if (UtilValidate.isNotEmpty(servlet) && !WebServlets.contains(servlet)) {
WebServlets.add(servlet);
}
}
}
}
}
/**
* @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
String uri = httpRequest.getRequestURI();
boolean forwarded = forwardUri(httpResponse, uri);
if (forwarded) {
return;
}
URL controllerConfigURL = ConfigXMLReader.getControllerConfigURL(config.getServletContext());
ControllerConfig controllerConfig = null;
Map<String, ConfigXMLReader.RequestMap> requestMaps = null;
try {
controllerConfig = ConfigXMLReader.getControllerConfig(controllerConfigURL);
requestMaps = controllerConfig.getRequestMapMap();
} catch (WebAppConfigurationException e) {
Debug.logError(e, "Exception thrown while parsing controller.xml file: ", module);
throw new ServletException(e);
}
Set<String> uris = requestMaps.keySet();
// test to see if we have come through the control servlet already, if not do the processing
String requestPath = null;
String contextUri = null;
if (httpRequest.getAttribute(ControlFilter.FORWARDED_FROM_SERVLET) == null) {
requestPath = httpRequest.getServletPath();
if (requestPath == null) requestPath = "";
if (requestPath.lastIndexOf("/") > 0) {
if (requestPath.indexOf("/") == 0) {
requestPath = "/" + requestPath.substring(1, requestPath.indexOf("/", 1));
} else {
requestPath = requestPath.substring(1, requestPath.indexOf("/"));
}
}
String requestInfo = httpRequest.getServletPath();
if (requestInfo == null) requestInfo = "";
if (requestInfo.lastIndexOf("/") >= 0) {
requestInfo = requestInfo.substring(0, requestInfo.lastIndexOf("/")) + "/*";
}
StringBuilder contextUriBuffer = new StringBuilder();
if (httpRequest.getContextPath() != null) {
contextUriBuffer.append(httpRequest.getContextPath());
}
if (httpRequest.getServletPath() != null) {
contextUriBuffer.append(httpRequest.getServletPath());
}
if (httpRequest.getPathInfo() != null) {
contextUriBuffer.append(httpRequest.getPathInfo());
}
contextUri = contextUriBuffer.toString();
List<String> pathItemList = StringUtil.split(httpRequest.getPathInfo(), "/");
String viewName = "";
if (pathItemList != null) {
viewName = pathItemList.get(0);
}
String requestUri = UtilHttp.getRequestUriFromTarget(httpRequest.getRequestURI());
// check to make sure the requested url is allowed
if (!allowedPathList.contains(requestPath) && !allowedPathList.contains(requestInfo) && !allowedPathList.contains(httpRequest.getServletPath())
&& !allowedPathList.contains(requestUri) && !allowedPathList.contains("/" + viewName)
&& (UtilValidate.isEmpty(requestPath) && UtilValidate.isEmpty(httpRequest.getServletPath()) && !uris.contains(viewName))) {
String filterMessage = "[Filtered request]: " + contextUri;
if (redirectPath == null) {
if (UtilValidate.isEmpty(viewName)) {
// redirect without any url change in browser
RequestDispatcher rd = request.getRequestDispatcher(SeoControlServlet.defaultPage);
rd.forward(request, response);
} else {
int error = 404;
if (UtilValidate.isNotEmpty(errorCode)) {
try {
error = Integer.parseInt(errorCode);
} catch (NumberFormatException nfe) {
Debug.logWarning(nfe, "Error code specified would not parse to Integer : " + errorCode, module);
}
}
filterMessage = filterMessage + " (" + error + ")";
httpResponse.sendError(error, contextUri);
request.setAttribute("filterRequestUriError", contextUri);
}
} else {
filterMessage = filterMessage + " (" + redirectPath + ")";
if (!redirectPath.toLowerCase().startsWith("http")) {
redirectPath = httpRequest.getContextPath() + redirectPath;
}
// httpResponse.sendRedirect(redirectPath);
if (uri.equals("") || uri.equals("/")) {
// redirect without any url change in browser
RequestDispatcher rd = request.getRequestDispatcher(redirectPath);
rd.forward(request, response);
} else {
// redirect with url change in browser
httpResponse.setStatus(SeoConfigUtil.getDefaultResponseCode());
httpResponse.setHeader("Location", redirectPath);
}
}
Debug.logWarning(filterMessage, module);
return;
} else if ((allowedPathList.contains(requestPath) || allowedPathList.contains(requestInfo) || allowedPathList.contains(httpRequest.getServletPath())
|| allowedPathList.contains(requestUri) || allowedPathList.contains("/" + viewName))
&& !WebServlets.contains(httpRequest.getServletPath())) {
request.setAttribute(SeoControlServlet.REQUEST_IN_ALLOW_LIST, Boolean.TRUE);
}
}
// we're done checking; continue on
chain.doFilter(httpRequest, httpResponse);
}
@Override
public void destroy() {
}
/**
* Forward a uri according to forward pattern regular expressions. Note: this is developed for Filter usage.
*
* @param uri String to reverse transform
* @return String
*/
protected static boolean forwardUri(HttpServletResponse response, String uri) {
Perl5Matcher matcher = new Perl5Matcher();
boolean foundMatch = false;
Integer responseCodeInt = null;
if (SeoConfigUtil.checkUseUrlRegexp() && SeoConfigUtil.getSeoPatterns() != null && SeoConfigUtil.getForwardReplacements() != null) {
Iterator<String> keys = SeoConfigUtil.getSeoPatterns().keySet().iterator();
while (keys.hasNext()) {
String key = keys.next();
Pattern pattern = SeoConfigUtil.getSeoPatterns().get(key);
String replacement = SeoConfigUtil.getForwardReplacements().get(key);
if (matcher.matches(uri, pattern)) {
for (int i = matcher.getMatch().groups(); i > 0; i--) {
replacement = replacement.replaceAll("\\$" + i, matcher.getMatch().group(i));
}
uri = replacement;
responseCodeInt = SeoConfigUtil.getForwardResponseCodes().get(key);
foundMatch = true;
// be careful, we don't break after finding a match
}
}
}
if (foundMatch) {
if (responseCodeInt == null) {
response.setStatus(SeoConfigUtil.getDefaultResponseCode());
} else {
response.setStatus(responseCodeInt.intValue());
}
response.setHeader("Location", uri);
} else {
Debug.logInfo("Can NOT forward this url: " + uri, module);
}
return foundMatch;
}
}