/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.apache.usergrid.rest.utils; import org.glassfish.jersey.server.ContainerRequest; import org.glassfish.jersey.server.ContainerResponse; import java.util.Enumeration; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerResponseContext; /* Note: At one point there was a special case in this code that would convert an origin header sent with a string containing the contents "null" to an actual null and dealing with that case as if the header had not been sent at all. This, however, caused problems with the Firefox and Chrome browsers that intend that the "null" be the actual origin when the file:// protocol is used and specifically look for it in the response. By removing this special case and instead allowing the normal processing (ie. allowing "null" to be a valid origin), it removed the issue for those browsers. Safari works regardless as it actually leaves off the header (a true null). IE still doesn't work on file:// regardless for reasons unknown. */ public class CORSUtils { private static final String ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin"; private static final String ACCESS_CONTROL_ALLOW_CREDENTIALS = "Access-Control-Allow-Credentials"; private static final String ACCESS_CONTROL_ALLOW_METHODS = "Access-Control-Allow-Methods"; private static final String ACCESS_CONTROL_ALLOW_HEADERS = "Access-Control-Allow-Headers"; private static final String ACCESS_CONTROL_REQUEST_METHOD = "access-control-request-method"; private static final String ACCESS_CONTROL_REQUEST_HEADERS = "access-control-request-headers"; private static final String ORIGIN_HEADER = "origin"; private static final String REFERER_HEADER = "referer"; public static void allowAllOrigins( HttpServletRequest request, HttpServletResponse response ) { if ( request.getHeader( ACCESS_CONTROL_REQUEST_METHOD ) != null ) { @SuppressWarnings("unchecked") Enumeration<String> e = request.getHeaders( ACCESS_CONTROL_REQUEST_METHOD ); while ( e.hasMoreElements() ) { String value = e.nextElement(); response.addHeader( ACCESS_CONTROL_ALLOW_METHODS, value ); } } if ( request.getHeader( ACCESS_CONTROL_REQUEST_HEADERS ) != null ) { @SuppressWarnings("unchecked") Enumeration<String> e = request.getHeaders( ACCESS_CONTROL_REQUEST_HEADERS ); while ( e.hasMoreElements() ) { String value = e.nextElement(); response.addHeader( ACCESS_CONTROL_ALLOW_HEADERS, value ); } } boolean origin_sent = false; if ( request.getHeader( ORIGIN_HEADER ) != null ) { @SuppressWarnings("unchecked") Enumeration<String> e = request.getHeaders( ORIGIN_HEADER ); while ( e.hasMoreElements() ) { String value = e.nextElement(); if ( value != null ) { origin_sent = true; response.addHeader( ACCESS_CONTROL_ALLOW_ORIGIN, value ); } } } if ( !origin_sent ) { String origin = getOrigin( request ); if ( origin != null ) { response.addHeader( ACCESS_CONTROL_ALLOW_CREDENTIALS, "true" ); response.addHeader( ACCESS_CONTROL_ALLOW_ORIGIN, origin ); } else { response.addHeader( ACCESS_CONTROL_ALLOW_ORIGIN, "*" ); } } else { response.addHeader( ACCESS_CONTROL_ALLOW_CREDENTIALS, "true" ); } } public static ContainerResponseContext allowAllOrigins( ContainerRequestContext request, ContainerResponseContext response ) { if ( request.getHeaders().containsKey( ACCESS_CONTROL_REQUEST_METHOD ) ) { for ( String value : request.getHeaders().get( ACCESS_CONTROL_REQUEST_METHOD ) ) { response.getHeaders().add( ACCESS_CONTROL_ALLOW_METHODS, value ); } } if ( request.getHeaders().containsKey( ACCESS_CONTROL_REQUEST_HEADERS ) ) { for ( String value : request.getHeaders().get( ACCESS_CONTROL_REQUEST_HEADERS ) ) { response.getHeaders().add( ACCESS_CONTROL_ALLOW_HEADERS, value ); } } boolean origin_sent = false; if ( request.getHeaders().containsKey( ORIGIN_HEADER ) ) { for ( String value : request.getHeaders().get( ORIGIN_HEADER ) ) { if ( value != null ) { origin_sent = true; response.getHeaders().add( ACCESS_CONTROL_ALLOW_ORIGIN, value ); } } } if ( !origin_sent ) { String origin = getOrigin( request ); if ( origin != null ) { response.getHeaders().add( ACCESS_CONTROL_ALLOW_CREDENTIALS, "true" ); response.getHeaders().add( ACCESS_CONTROL_ALLOW_ORIGIN, origin ); } else { response.getHeaders().add( ACCESS_CONTROL_ALLOW_ORIGIN, "*" ); } } else { response.getHeaders().add( ACCESS_CONTROL_ALLOW_CREDENTIALS, "true" ); } return response; } public static String getOrigin( String origin, String referer ) { if ( ( origin != null ) && ( !"null".equalsIgnoreCase( origin ) ) ) { return origin; } if ( ( referer != null ) && ( referer.startsWith( "http" ) ) ) { int i = referer.indexOf( "//" ); if ( i != -1 ) { i = referer.indexOf( '/', i + 2 ); if ( i != -1 ) { return referer.substring( 0, i ); } else { return referer; } } } return null; } public static String getOrigin( HttpServletRequest request ) { String origin = request.getHeader( ORIGIN_HEADER ); String referer = request.getHeader( REFERER_HEADER ); return getOrigin( origin, referer ); } public static String getOrigin( ContainerRequestContext request ) { String origin = request.getHeaders().getFirst( ORIGIN_HEADER ); String referer = request.getHeaders().getFirst( REFERER_HEADER ); return getOrigin( origin, referer ); } }