/* * Copyright 2012-2016 Eric F. Savage, code@efsavage.com * * 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 com.ajah.servlet.filter; import java.io.IOException; 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 com.ajah.servlet.util.ResponseHeader; import com.ajah.util.StringUtils; import com.ajah.util.config.Config; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.extern.java.Log; /** * Sets a Access-Control-Allow-Origin based on the "ajah.header.cors" property. * If set, will also set a "Access-Control-Allow-Headers" as defined by property * "ajah.header.cors-headers", defaults to * "Origin, X-Requested-With, Content-Type, Accept". * * @author <a href="http://efsavage.com">Eric F. Savage</a>, * <a href="mailto:code@efsavage.com">code@efsavage.com</a>. */ @Data @Log @EqualsAndHashCode(callSuper = true) public class CorsFilter extends BaseFilter { @Override public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException { String value = Config.i.get("ajah.header.cors", "null"); doFilter(value, request, response, chain); } protected void doFilter(String value, final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException { if (StringUtils.isBlank(value)) { log.fine("Value is blank, not applying any headers"); super.doFilter(request, response, chain); return; } if (value.contains(",")) { final HttpServletRequest servletRequest = (HttpServletRequest) request; String origin = servletRequest.getHeader("Origin"); log.finest("Origin: " + origin); if (StringUtils.isBlank(origin) && Config.i.getBoolean("ajah.header.cors.referer-as-origin", false)) { origin = servletRequest.getHeader("Referer"); log.finest("Origin blank, using referer: " + origin); } if (origin != null && origin.endsWith("/")) { origin = origin.substring(0, origin.length() - 1); log.finest("Origin trimmed: " + origin); } String newValue = "null"; // CORS headers don't support multi-match so we'll see if the // inbound request is one of the specified domains if (!StringUtils.isBlank(origin) && origin != null) { final String[] candidates = value.split(","); for (final String candidate : candidates) { log.finest("Candidate: " + candidate); if (origin.equals(candidate)) { newValue = candidate; break; } } } value = newValue; } ((HttpServletResponse) response).addHeader(ResponseHeader.ACCESS_CONTROL_ALLOW_ORIGIN.getHeader(), value); ((HttpServletResponse) response).addHeader(ResponseHeader.ACCESS_CONTROL_ALLOW_CREDENTIALS.getHeader(), "true"); final String headers = Config.i.get("ajah.header.cors-headers", "Origin, X-Requested-With, Content-Type, Accept"); ((HttpServletResponse) response).addHeader(ResponseHeader.ACCESS_CONTROL_ALLOW_HEADERS.getHeader(), headers); final String methods = Config.i.get("ajah.header.cors-methods", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH"); ((HttpServletResponse) response).addHeader(ResponseHeader.ACCESS_CONTROL_ALLOW_METHODS.getHeader(), methods); super.doFilter(request, response, chain); } }