diff --git a/src/main/java/org/codelibs/fess/filter/CorsFilter.java b/src/main/java/org/codelibs/fess/filter/CorsFilter.java
new file mode 100644
index 000000000..057ad71d0
--- /dev/null
+++ b/src/main/java/org/codelibs/fess/filter/CorsFilter.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2012-2019 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.filter;
+
+import java.io.IOException;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.codelibs.core.lang.StringUtil;
+import org.codelibs.fess.mylasta.direction.FessConfig;
+import org.codelibs.fess.util.ComponentUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class CorsFilter implements Filter {
+
+ private static final Logger logger = LoggerFactory.getLogger(CorsFilter.class);
+
+ 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 (logger.isDebugEnabled()) {
+ logger.debug("allowOrigin: " + allowOrigin);
+ }
+ 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());
+
+ if (httpRequest.getMethod().equals(OPTIONS)) {
+ httpResponse.setStatus(HttpServletResponse.SC_ACCEPTED);
+ return;
+ }
+ }
+
+ 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/mylasta/direction/FessConfig.java b/src/main/java/org/codelibs/fess/mylasta/direction/FessConfig.java
index 960d81c2b..744799d6b 100644
--- a/src/main/java/org/codelibs/fess/mylasta/direction/FessConfig.java
+++ b/src/main/java/org/codelibs/fess/mylasta/direction/FessConfig.java
@@ -199,6 +199,21 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
/** The key of the configuration. e.g. */
String API_DASHBOARD_RESPONSE_HEADERS = "api.dashboard.response.headers";
+ /** The key of the configuration. e.g. * */
+ String API_CORS_ALLOW_ORIGIN = "api.cors.allow.origin";
+
+ /** The key of the configuration. e.g. GET, POST, OPTIONS, DELETE, PUT */
+ String API_CORS_ALLOW_METHODS = "api.cors.allow.methods";
+
+ /** The key of the configuration. e.g. 3600 */
+ String API_CORS_MAX_AGE = "api.cors.max.age";
+
+ /** The key of the configuration. e.g. Origin, Content-Type, Accept, Authorization */
+ String API_CORS_ALLOW_HEADERS = "api.cors.allow.headers";
+
+ /** The key of the configuration. e.g. true */
+ String API_CORS_ALLOW_CREDENTIALS = "api.cors.allow.credentials";
+
/** The key of the configuration. e.g. */
String VIRTUAL_HOST_HEADERS = "virtual.host.headers";
@@ -1847,6 +1862,56 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
*/
Integer getApiDashboardResponseHeadersAsInteger();
+ /**
+ * Get the value for the key 'api.cors.allow.origin'.
+ * The value is, e.g. *
+ * @return The value of found property. (NotNull: if not found, exception but basically no way)
+ */
+ String getApiCorsAllowOrigin();
+
+ /**
+ * Get the value for the key 'api.cors.allow.methods'.
+ * The value is, e.g. GET, POST, OPTIONS, DELETE, PUT
+ * @return The value of found property. (NotNull: if not found, exception but basically no way)
+ */
+ String getApiCorsAllowMethods();
+
+ /**
+ * Get the value for the key 'api.cors.max.age'.
+ * The value is, e.g. 3600
+ * @return The value of found property. (NotNull: if not found, exception but basically no way)
+ */
+ String getApiCorsMaxAge();
+
+ /**
+ * Get the value for the key 'api.cors.max.age' as {@link Integer}.
+ * The value is, e.g. 3600
+ * @return The value of found property. (NotNull: if not found, exception but basically no way)
+ * @throws NumberFormatException When the property is not integer.
+ */
+ Integer getApiCorsMaxAgeAsInteger();
+
+ /**
+ * Get the value for the key 'api.cors.allow.headers'.
+ * The value is, e.g. Origin, Content-Type, Accept, Authorization
+ * @return The value of found property. (NotNull: if not found, exception but basically no way)
+ */
+ String getApiCorsAllowHeaders();
+
+ /**
+ * Get the value for the key 'api.cors.allow.credentials'.
+ * The value is, e.g. true
+ * @return The value of found property. (NotNull: if not found, exception but basically no way)
+ */
+ String getApiCorsAllowCredentials();
+
+ /**
+ * Is the property for the key 'api.cors.allow.credentials' true?
+ * The value is, e.g. true
+ * @return The determination, true or false. (if not found, exception but basically no way)
+ */
+ boolean isApiCorsAllowCredentials();
+
/**
* Get the value for the key 'virtual.host.headers'.
* The value is, e.g.
@@ -6202,6 +6267,34 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
return getAsInteger(FessConfig.API_DASHBOARD_RESPONSE_HEADERS);
}
+ public String getApiCorsAllowOrigin() {
+ return get(FessConfig.API_CORS_ALLOW_ORIGIN);
+ }
+
+ public String getApiCorsAllowMethods() {
+ return get(FessConfig.API_CORS_ALLOW_METHODS);
+ }
+
+ public String getApiCorsMaxAge() {
+ return get(FessConfig.API_CORS_MAX_AGE);
+ }
+
+ public Integer getApiCorsMaxAgeAsInteger() {
+ return getAsInteger(FessConfig.API_CORS_MAX_AGE);
+ }
+
+ public String getApiCorsAllowHeaders() {
+ return get(FessConfig.API_CORS_ALLOW_HEADERS);
+ }
+
+ public String getApiCorsAllowCredentials() {
+ return get(FessConfig.API_CORS_ALLOW_CREDENTIALS);
+ }
+
+ public boolean isApiCorsAllowCredentials() {
+ return is(FessConfig.API_CORS_ALLOW_CREDENTIALS);
+ }
+
public String getVirtualHostHeaders() {
return get(FessConfig.VIRTUAL_HOST_HEADERS);
}
@@ -8491,6 +8584,11 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
defaultMap.put(FessConfig.API_JSON_RESPONSE_HEADERS, "");
defaultMap.put(FessConfig.API_GSA_RESPONSE_HEADERS, "");
defaultMap.put(FessConfig.API_DASHBOARD_RESPONSE_HEADERS, "");
+ defaultMap.put(FessConfig.API_CORS_ALLOW_ORIGIN, "*");
+ defaultMap.put(FessConfig.API_CORS_ALLOW_METHODS, "GET, POST, OPTIONS, DELETE, PUT");
+ defaultMap.put(FessConfig.API_CORS_MAX_AGE, "3600");
+ defaultMap.put(FessConfig.API_CORS_ALLOW_HEADERS, "Origin, Content-Type, Accept, Authorization");
+ defaultMap.put(FessConfig.API_CORS_ALLOW_CREDENTIALS, "true");
defaultMap.put(FessConfig.VIRTUAL_HOST_HEADERS, "");
defaultMap.put(FessConfig.HTTP_PROXY_HOST, "");
defaultMap.put(FessConfig.HTTP_PROXY_PORT, "8080");
diff --git a/src/main/java/org/codelibs/fess/mylasta/direction/FessProp.java b/src/main/java/org/codelibs/fess/mylasta/direction/FessProp.java
index 614dd9fda..b3329cdfb 100644
--- a/src/main/java/org/codelibs/fess/mylasta/direction/FessProp.java
+++ b/src/main/java/org/codelibs/fess/mylasta/direction/FessProp.java
@@ -70,6 +70,8 @@ import org.lastaflute.web.validation.theme.typed.LongTypeValidator;
public interface FessProp {
+ String CORS_ALLOW_ORIGIN = "CorsAllowOrigin";
+
String API_DASHBOARD_RESPONSE_HEADER_LIST = "apiDashboardResponseHeaderList";
String API_JSON_RESPONSE_HEADER_LIST = "apiJsonResponseHeaderList";
@@ -1969,4 +1971,17 @@ public interface FessProp {
}
return list;
}
+
+ String getApiCorsAllowOrigin();
+
+ default List getApiCorsAllowOriginList() {
+ List list = (List) propMap.get(CORS_ALLOW_ORIGIN);
+ if (list == null) {
+ list =
+ split(getApiCorsAllowOrigin(), "\n").get(
+ stream -> stream.map(String::trim).filter(StringUtil::isNotEmpty).collect(Collectors.toList()));
+ propMap.put(CORS_ALLOW_ORIGIN, list);
+ }
+ return list;
+ }
}
diff --git a/src/main/resources/fess_config.properties b/src/main/resources/fess_config.properties
index 84ebd8998..950281c6d 100644
--- a/src/main/resources/fess_config.properties
+++ b/src/main/resources/fess_config.properties
@@ -136,6 +136,11 @@ api.search.scroll=false
api.json.response.headers=
api.gsa.response.headers=
api.dashboard.response.headers=
+api.cors.allow.origin=*
+api.cors.allow.methods=GET, POST, OPTIONS, DELETE, PUT
+api.cors.max.age=3600
+api.cors.allow.headers=Origin, Content-Type, Accept, Authorization
+api.cors.allow.credentials=true
# Virtual Host: Host:fess.codelibs.org=fess
virtual.host.headers=
diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml
index d76fb9f00..6cc636738 100644
--- a/src/main/webapp/WEB-INF/web.xml
+++ b/src/main/webapp/WEB-INF/web.xml
@@ -35,6 +35,11 @@
+
+ corsFilter
+ org.codelibs.fess.filter.CorsFilter
+
+
webApiFilter
org.codelibs.fess.filter.WebApiFilter
@@ -77,6 +82,12 @@
INCLUDE
+
+ corsFilter
+ /*
+ REQUEST
+
+
webApiFilter
/*