fix #2018 cors support

This commit is contained in:
Shinsuke Sugaya 2019-02-14 06:53:22 +09:00
parent 0643349425
commit 8eadcbb48b
5 changed files with 231 additions and 0 deletions

View file

@ -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);
}
}

View file

@ -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'. <br>
* The value is, e.g. * <br>
* @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'. <br>
* The value is, e.g. GET, POST, OPTIONS, DELETE, PUT <br>
* @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'. <br>
* The value is, e.g. 3600 <br>
* @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}. <br>
* The value is, e.g. 3600 <br>
* @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'. <br>
* The value is, e.g. Origin, Content-Type, Accept, Authorization <br>
* @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'. <br>
* The value is, e.g. true <br>
* @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? <br>
* The value is, e.g. true <br>
* @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'. <br>
* The value is, e.g. <br>
@ -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");

View file

@ -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<String> getApiCorsAllowOriginList() {
List<String> list = (List<String>) 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;
}
}

View file

@ -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=

View file

@ -35,6 +35,11 @@
</init-param>
</filter>
<filter>
<filter-name>corsFilter</filter-name>
<filter-class>org.codelibs.fess.filter.CorsFilter</filter-class>
</filter>
<filter>
<filter-name>webApiFilter</filter-name>
<filter-class>org.codelibs.fess.filter.WebApiFilter</filter-class>
@ -77,6 +82,12 @@
<dispatcher>INCLUDE</dispatcher>
</filter-mapping>
<filter-mapping>
<filter-name>corsFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
<filter-mapping>
<filter-name>webApiFilter</filter-name>
<url-pattern>/*</url-pattern>