diff --git a/src/main/java/org/codelibs/fess/cors/CorsHandler.java b/src/main/java/org/codelibs/fess/cors/CorsHandler.java new file mode 100644 index 000000000..acb01222d --- /dev/null +++ b/src/main/java/org/codelibs/fess/cors/CorsHandler.java @@ -0,0 +1,25 @@ +/* + * Copyright 2012-2023 CodeLibs Project and the Others. + * + * Licensed 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.codelibs.fess.cors; + +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +public abstract class CorsHandler { + + public abstract void process(String origin, ServletRequest request, ServletResponse response); + +} diff --git a/src/main/java/org/codelibs/fess/cors/CorsHandlerFactory.java b/src/main/java/org/codelibs/fess/cors/CorsHandlerFactory.java new file mode 100644 index 000000000..3065b9571 --- /dev/null +++ b/src/main/java/org/codelibs/fess/cors/CorsHandlerFactory.java @@ -0,0 +1,43 @@ +/* + * Copyright 2012-2023 CodeLibs Project and the Others. + * + * Licensed 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.codelibs.fess.cors; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +public class CorsHandlerFactory { + private static final Logger logger = LogManager.getLogger(CorsHandlerFactory.class); + + protected Map handerMap = new HashMap<>(); + + public void add(final String origin, final CorsHandler handler) { + if (logger.isDebugEnabled()) { + logger.debug("Loaded {}", origin); + } + handerMap.put(origin, handler); + } + + public CorsHandler get(final String origin) { + final CorsHandler handler = handerMap.get(origin); + if (handler != null) { + return handler; + } + return handerMap.get("*"); + } +} diff --git a/src/main/java/org/codelibs/fess/cors/DefaultCorsHandler.java b/src/main/java/org/codelibs/fess/cors/DefaultCorsHandler.java new file mode 100644 index 000000000..689be373c --- /dev/null +++ b/src/main/java/org/codelibs/fess/cors/DefaultCorsHandler.java @@ -0,0 +1,56 @@ +/* + * Copyright 2012-2023 CodeLibs Project and the Others. + * + * Licensed 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.codelibs.fess.cors; + +import javax.annotation.PostConstruct; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; + +import org.codelibs.fess.mylasta.direction.FessConfig; +import org.codelibs.fess.util.ComponentUtil; + +public class DefaultCorsHandler extends CorsHandler { + + protected static final String ACCESS_CONTROL_ALLOW_CREDENTIALS = "Access-Control-Allow-Credentials"; + + protected static final String ACCESS_CONTROL_MAX_AGE = "Access-Control-Max-Age"; + + protected static final String ACCESS_CONTROL_ALLOW_HEADERS = "Access-Control-Allow-Headers"; + + protected static final String ACCESS_CONTROL_ALLOW_METHODS = "Access-Control-Allow-Methods"; + + protected static final String ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin"; + + @PostConstruct + public void register() { + final CorsHandlerFactory factory = ComponentUtil.getCorsHandlerFactory(); + final FessConfig fessConfig = ComponentUtil.getFessConfig(); + fessConfig.getApiCorsAllowOriginList().forEach(s -> factory.add(s, this)); + } + + @Override + public void process(final String origin, final ServletRequest request, final ServletResponse response) { + final FessConfig fessConfig = ComponentUtil.getFessConfig(); + final HttpServletResponse httpResponse = (HttpServletResponse) response; + httpResponse.addHeader(ACCESS_CONTROL_ALLOW_ORIGIN, origin); + httpResponse.addHeader(ACCESS_CONTROL_ALLOW_METHODS, fessConfig.getApiCorsAllowMethods()); + httpResponse.addHeader(ACCESS_CONTROL_ALLOW_HEADERS, fessConfig.getApiCorsAllowHeaders()); + httpResponse.addHeader(ACCESS_CONTROL_MAX_AGE, fessConfig.getApiCorsMaxAge()); + httpResponse.addHeader(ACCESS_CONTROL_ALLOW_CREDENTIALS, fessConfig.getApiCorsAllowCredentials()); + } + +} diff --git a/src/main/java/org/codelibs/fess/filter/CorsFilter.java b/src/main/java/org/codelibs/fess/filter/CorsFilter.java index e5b12c126..fd3a2187e 100644 --- a/src/main/java/org/codelibs/fess/filter/CorsFilter.java +++ b/src/main/java/org/codelibs/fess/filter/CorsFilter.java @@ -28,7 +28,8 @@ import javax.servlet.http.HttpServletResponse; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.codelibs.core.lang.StringUtil; -import org.codelibs.fess.mylasta.direction.FessConfig; +import org.codelibs.fess.cors.CorsHandler; +import org.codelibs.fess.cors.CorsHandlerFactory; import org.codelibs.fess.util.ComponentUtil; public class CorsFilter implements Filter { @@ -37,66 +38,31 @@ public class CorsFilter implements Filter { protected static final String OPTIONS = "OPTIONS"; - protected static final String ACCESS_CONTROL_ALLOW_CREDENTIALS = "Access-Control-Allow-Credentials"; - - protected static final String ACCESS_CONTROL_MAX_AGE = "Access-Control-Max-Age"; - - protected static final String ACCESS_CONTROL_ALLOW_HEADERS = "Access-Control-Allow-Headers"; - - protected static final String ACCESS_CONTROL_ALLOW_METHODS = "Access-Control-Allow-Methods"; - - protected static final String ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin"; - - protected static final String WILDCARD = "*"; - @Override public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException { final HttpServletRequest httpRequest = (HttpServletRequest) request; final String origin = httpRequest.getHeader("Origin"); - if (StringUtil.isBlank(origin)) { - chain.doFilter(request, response); - return; - } - - if (logger.isDebugEnabled()) { - logger.debug("HTTP Request: {}", httpRequest.getMethod()); - } - - final FessConfig fessConfig = ComponentUtil.getFessConfig(); - - final String allowOrigin = getAllowOrigin(fessConfig, origin); - if (StringUtil.isNotBlank(allowOrigin)) { + if (StringUtil.isNotBlank(origin)) { if (logger.isDebugEnabled()) { - logger.debug("allowOrigin: {}", allowOrigin); + logger.debug("HTTP Request: {}", httpRequest.getMethod()); } - final HttpServletResponse httpResponse = (HttpServletResponse) response; - httpResponse.addHeader(ACCESS_CONTROL_ALLOW_ORIGIN, allowOrigin); - httpResponse.addHeader(ACCESS_CONTROL_ALLOW_METHODS, fessConfig.getApiCorsAllowMethods()); - httpResponse.addHeader(ACCESS_CONTROL_ALLOW_HEADERS, fessConfig.getApiCorsAllowHeaders()); - httpResponse.addHeader(ACCESS_CONTROL_MAX_AGE, fessConfig.getApiCorsMaxAge()); - httpResponse.addHeader(ACCESS_CONTROL_ALLOW_CREDENTIALS, fessConfig.getApiCorsAllowCredentials()); + final CorsHandlerFactory factory = ComponentUtil.getCorsHandlerFactory(); + final CorsHandler handler = factory.get(origin); + if (handler != null) { + handler.process(origin, request, response); - if (OPTIONS.equals(httpRequest.getMethod())) { - httpResponse.setStatus(HttpServletResponse.SC_ACCEPTED); - return; + if (OPTIONS.equals(httpRequest.getMethod())) { + final HttpServletResponse httpResponse = (HttpServletResponse) response; + httpResponse.setStatus(HttpServletResponse.SC_ACCEPTED); + return; + } + } else if (logger.isDebugEnabled()) { + logger.debug("No CorsHandler for {}", origin); } } chain.doFilter(request, response); } - protected String getAllowOrigin(final FessConfig fessConfig, final String origin) { - final String allowOrigin = fessConfig.getApiCorsAllowOrigin(); - if (StringUtil.isBlank(allowOrigin)) { - return StringUtil.EMPTY; - } - - if (WILDCARD.equals(allowOrigin)) { - return allowOrigin; - } - - return fessConfig.getApiCorsAllowOriginList().stream().filter(s -> s.equals(origin)).findFirst().orElse(StringUtil.EMPTY); - } - } diff --git a/src/main/java/org/codelibs/fess/util/ComponentUtil.java b/src/main/java/org/codelibs/fess/util/ComponentUtil.java index b0d75a22e..84db3a71a 100644 --- a/src/main/java/org/codelibs/fess/util/ComponentUtil.java +++ b/src/main/java/org/codelibs/fess/util/ComponentUtil.java @@ -27,6 +27,7 @@ import org.codelibs.core.crypto.CachedCipher; import org.codelibs.core.misc.DynamicProperties; import org.codelibs.fess.api.WebApiManagerFactory; import org.codelibs.fess.auth.AuthenticationManager; +import org.codelibs.fess.cors.CorsHandlerFactory; import org.codelibs.fess.crawler.client.CrawlerClientCreator; import org.codelibs.fess.crawler.client.CrawlerClientFactory; import org.codelibs.fess.crawler.entity.EsAccessResult; @@ -211,6 +212,8 @@ public final class ComponentUtil { private static final String CRAWLER_STATS_HELPER = "crawlerStatsHelper"; + private static final String CORS_HANDLER_FACTORY = "corsHandlerFactory"; + private static IndexingHelper indexingHelper; private static CrawlingConfigHelper crawlingConfigHelper; @@ -512,6 +515,10 @@ public final class ComponentUtil { return getComponent(CRAWLER_STATS_HELPER); } + public static CorsHandlerFactory getCorsHandlerFactory() { + return getComponent(CORS_HANDLER_FACTORY); + } + public static T getComponent(final Class clazz) { try { return SingletonLaContainer.getComponent(clazz); diff --git a/src/main/resources/app.xml b/src/main/resources/app.xml index 203a2124b..95a8ec0db 100644 --- a/src/main/resources/app.xml +++ b/src/main/resources/app.xml @@ -9,6 +9,7 @@ + diff --git a/src/main/resources/fess_cors.xml b/src/main/resources/fess_cors.xml new file mode 100644 index 000000000..125e8d5c8 --- /dev/null +++ b/src/main/resources/fess_cors.xml @@ -0,0 +1,11 @@ + + + + + + + + + +