ofbiz——关于过滤器ControlFilter的配置

慕宜民
2023-12-01

在ofbiz组件的web.xml文件中,我们能看到如下配置:

    <filter>
        <display-name>ControlFilter</display-name>
        <filter-name>ControlFilter</filter-name>
        <filter-class>org.apache.ofbiz.webapp.control.ControlFilter</filter-class>
        <init-param>
            <param-name>allowedPaths</param-name>
            <param-value>/error:/control:/select:/index.html:/index.jsp:/default.html:/default.jsp:/images:/js:/ws</param-value>
        </init-param>
        <init-param>
            <param-name>redirectPath</param-name>
            <param-value>/control/main</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>ControlFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

具体allowedPaths参数配置的过滤逻辑是什么呢?

接下来通过研究ControlFilter类的源码分析出结果。

源码所在目录apache-ofbiz-16.11.02\framework\webapp\src\main\java\org\apache\ofbiz\webapp\control

ControlFilter.java

package org.apache.ofbiz.webapp.control;

import java.io.IOException;
import java.util.Set;
import java.util.HashSet;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.ofbiz.base.util.Debug;

/*
 * A Filter used to specify a whitelist of allowed paths to the OFBiz application.
 * Requests that do not match any of the paths listed in allowedPaths are redirected to redirectPath, or an error code
 * is returned (the error code can be set in errorCode, the default value is 403).
 * If forceRedirectAll is set to Y then allowedPaths is ignored and all requests are redirected to redirectPath; note
 * that forceRedirectAll is ignored if redirectPath is not set.
 *
 * Init parameters:
 *   - forceRedirectAll: when set to Y, and redirectPath is set, then redirects all traffic to redirectPath
 *   - allowedPaths: a colon separated list of URL or URI that are allowed;
 *     non matching request paths are redirected, or an error code is returned,
 *     according to the setup of redirectPath and errorCode
 *   - redirectPath: if the path requested is not in the allowedPaths, or forceRedirectAll is set to Y,
 *     specifies the the path to which the request is redirected to;
 *   - errorCode: the error code set in the response if the path requested is not in the allowedPaths
 *     and redirectPath is not set; defaults to 403
 *
 * Interaction with the context:
 *   - for its internal logic (to avoid an infinite loop of redirections when forceRedirectAll is set) the filter sets
 *     a session parameter (_FORCE_REDIRECT_=true) before the first redirection; the parameter is removed during the
 *     second pass before the request is forwarded to the next filter in the chain
 *   - the filter skips the check against the whitelist of allowed paths if a request attribute
 *     with name _FORWARDED_FROM_SERVLET_ is present; this attribute is typically set by the ControlServlet to indicate
 *     that the request path is safe and should not be checked again
 */


public class ControlFilter implements Filter {
    public static final String FORWARDED_FROM_SERVLET = "_FORWARDED_FROM_SERVLET_";

    private static final String module = ControlFilter.class.getName();
    private boolean redirectAll;
    private boolean redirectPathIsUrl;
    private String redirectPath;
    protected int errorCode;
    private Set<String> allowedPaths = new HashSet<>();

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        redirectPath = filterConfig.getInitParameter("redirectPath");
        redirectPathIsUrl = (redirectPath != null && redirectPath.toLowerCase().startsWith("http"));
        String redirectAllString = filterConfig.getInitParameter("forceRedirectAll");
        redirectAll = (redirectPath != null && redirectAllString != null && "Y".equalsIgnoreCase(redirectAllString));
        String errorCodeString = filterConfig.getInitParameter("errorCode");
        errorCode = 403;
        if (errorCodeString != null) {
            try {
                errorCode = Integer.parseInt(errorCodeString);
            } catch (NumberFormatException nfe) {
                Debug.logWarning(nfe, "Error code specified would not parse to Integer: " + errorCodeString, module);
                Debug.logWarning(nfe, "The default error code will be used: " + errorCode, module);
            }
        }
        String allowedPathsString = filterConfig.getInitParameter("allowedPaths");
        if (allowedPathsString != null) {
            String[] result = allowedPathsString.split(":");
            for (int x = 0; x < result.length; x++) {
                allowedPaths.add(result[x]);
            }
            // if an URI is specified in the redirectPath parameter, it is added to the allowed list
            if (redirectPath != null && !redirectPathIsUrl) {
                allowedPaths.add(redirectPath);
            }

        }
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        // check if we are told to redirect everything
        if (redirectAll) {
            // little trick here so we don't loop on ourselves
            if (httpRequest.getSession().getAttribute("_FORCE_REDIRECT_") == null) {
                httpRequest.getSession().setAttribute("_FORCE_REDIRECT_", "true");
                Debug.logWarning("Redirecting user to: " + redirectPath, module);
                if (redirectPathIsUrl) {
                    httpResponse.sendRedirect(redirectPath);
                } else {
                    httpResponse.sendRedirect(httpRequest.getContextPath() + redirectPath);
                }
                return;
            } else {
                httpRequest.getSession().removeAttribute("_FORCE_REDIRECT_");
                chain.doFilter(httpRequest, httpResponse);
                return;
            }
        }

        if (httpRequest.getAttribute(FORWARDED_FROM_SERVLET) == null && !allowedPaths.isEmpty()) {
            // check to make sure the requested url is allowed
            // get the request URI without the webapp mount point
            String requestUri = httpRequest.getRequestURI().substring(httpRequest.getContextPath().length());
            int offset = requestUri.indexOf("/", 1);
            if (offset == -1) {
                offset = requestUri.length();
            }
            while (!allowedPaths.contains(requestUri.substring(0, offset))) {
                offset = requestUri.indexOf("/", offset + 1);
                if (offset == -1) {
                    if (allowedPaths.contains(requestUri)) {
                        break;
                    }
                    // path not allowed
                    if (redirectPath == null) {
                        httpResponse.sendError(errorCode, httpRequest.getRequestURI());
                    } else {
                        if (redirectPathIsUrl) {
                            httpResponse.sendRedirect(redirectPath);
                        } else {
                            httpResponse.sendRedirect(httpRequest.getContextPath() + redirectPath);
                        }
                    }
                    if (Debug.infoOn()) {
                        Debug.logInfo("[Filtered request]: " + httpRequest.getRequestURI() + " --> " + (redirectPath == null? errorCode: redirectPath), module);
                    }
                    return;
                }
            }
            chain.doFilter(request, httpResponse);
        }
    }

    @Override
    public void destroy() {

    }
}


1. 通过源码分析,我们很容易知道allowedPaths是一个Set类型数据,她是通过冒号(:)分割字符串后将其添加到allowedPaths成员中。

2. 并且如果redirectPath不为空,并且不是以http开头的话,也放入allowedPaths中。

3. 过滤规则。只要前面uri与allowedPaths中的匹配就能通过,否则会被拦截。

        举个例子:请求的url是https://10.100.1.240:8089/booking/control/FindStudent/test/ceshi/abc.jsp

依次匹配: /control    , /control/FindStudent,  /control/FindStudent/test  ,    /control/FindStudent/test/ceshi    ,      /control/FindStudent/test/ceshi/abc.jsp

allowedPaths中的元素只要有一个和上面的匹配上了就能通过过滤器了,否则请求会被过滤重定向到redirectPath


大致逻辑就是这样,之前还想定义一个所有请求都能通过的allowedPaths,经过分析好像不行,要么就直接不使用该过滤器了,使用了就得配置allowedPaths。





 类似资料: