Enable CORS for tomcat applications with credentia

2020-03-24 07:03发布

问题:

I have a simple GWT application running from IIS on my server. I am trying to test HTTP requests to tomcat running on the same server. However, since both the application servers are running on different ports, my browser (chrome and firefox) treats the requests as a CORS request.

To enable tomcat to accept CORS request, I updated it to Tomcat 7.0.52 and enabled the CORS filter in the global web.xml configuration. I tested this simple setup and it seems to work. Here is the code in GWT:

        String url = "http://bavarians:8080/";
        RequestBuilder rb = new RequestBuilder(RequestBuilder.GET, url);
        box.setText(url);
        try
        {
            rb.sendRequest("", new RequestCallback(){

                @Override
                public void onResponseReceived(Request request, Response response)
                {
                    Window.alert(response.getStatusCode() + response.getStatusText());
                }

                @Override
                public void onError(Request request, Throwable exception)
                {
                    Window.alert("Request failed");

                }});
        }
        catch (RequestException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

Here is the CORS filter associated with it:

<filter>
  <filter-name>CorsFilter</filter-name>
  <filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
  <init-param>
    <param-name>cors.allowed.origins</param-name>
    <param-value>http://bavarians</param-value>
  </init-param>
  <init-param>
    <param-name>cors.allowed.methods</param-name>
    <param-value>GET,POST,HEAD,OPTIONS,PUT</param-value>
  </init-param>
  <init-param>
    <param-name>cors.allowed.headers</param-name>
    <param-value>Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers, Authorization</param-value>
  </init-param>
  <init-param>
    <param-name>cors.exposed.headers</param-name>
    <param-value>Access-Control-Allow-Origin,Access-Control-Allow-Credentials, Authorization</param-value>
  </init-param>
  <init-param>
    <param-name>cors.support.credentials</param-name>
    <param-value>true</param-value>
  </init-param>
  <init-param>
    <param-name>cors.preflight.maxage</param-name>
    <param-value>10</param-value>
  </init-param>
</filter>
<filter-mapping>
  <filter-name>CorsFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

With this setup, I get a 200 OK response from tomcat. So its safe to assume that CORS filter is working. To back this up, I took a fiddler trace and all looked good.

Now, since I want to access one of the apps of tomcat(solr), I need basic authentication with my CORS request. This brings a preflight request into picture. Since I setup my CORS filter to enable credential use, I didn't need any changes to it. So, I made the following change to my code

        String url = "http://bavarians:8080/solr/select?wt=xml&q=tag_name:abcd&username=domain\\userid";
        RequestBuilder rb = new RequestBuilder(RequestBuilder.GET, url);
        box.setText(url);
        rb.setHeader("Authorization", "Basic YWRtaW46YWRtaW4=");
        rb.setIncludeCredentials(true);

Now, when I try to use this code, it gets inside the onResponseReceived code block and gives an alert box with "0" value. When I took a fiddler trace, I get this:

It makes sense for the browser to send a preflight request since I am adding the custom header to the request. But I don't understand why tomcat responds with a 401 code despite adding the authorization header to its CORS filter configuration.

I'd appreciate any help or response


EDIT: One more thing that I have noticed- if my URL is just "bavarians:8080/solr/";, tomcat successfully authorizes the preflighted request and the immediate next request is processed as a normal GET request with a 200 OK response. But if I enter the function name and query with the URL, I get 401 again. Accessing the above URL from browser requires Basic Authentication. So CORSFilter does work until some point

回答1:

Credentials won't be sent in the preflight request, so you have to configure Tomcat to let the request reach the CorsFilter even when unauthenticated. That is, you have to declare a <security-constraint> with <http-method>OPTIONS</http-method> and no <auth-constraint>.



回答2:

I've found that the Tomcat config is port specific. So if you just put your site domain, it will assume only port 80. Otherwise you will need to specify the port:

<init-param>
  <param-name>cors.allowed.origins</param-name>
  <param-value>http://bavarians:8080</param-value>
</init-param>


回答3:

Do not forget to use this code at the end of web.xml file just before </web-app> closing tag

 <filter>
        <filter-name>CorsFilter</filter-name>
        <filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
        <init-param>
            <param-name>cors.allowed.origins</param-name>
            <param-value>*</param-value>
        </init-param>
        <init-param>
            <param-name>cors.exposed.headers</param-name>
            <param-value>Access-Control-Allow-Origin,Access-Control-Allow-Credentials</param-value>
        </init-param>
        <init-param>
            <param-name>cors.allowed.headers</param-name>
            <param-value>Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization</param-value>
        </init-param>
        <init-param>
            <param-name>cors.support.credentials</param-name>
            <param-value>false</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CorsFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>