How to CORS-enable Apache web server (including preflight and custom headers)? - apache

General:
Request URL:x/site.php
Request Method:OPTIONS
Status Code:302 Found
Remote Address:x.x.x.x:80
Response Headers:
view source
Access-Control-Allow-Headers:Content-Type
Access-Control-Allow-Origin:*
Access-Control-Max-Age:300
Cache-Control:no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Content-Length:0
Content-Type:text/html; charset=UTF-8
Date:Thu, 02 Mar 2017 14:27:21 GMT
Expires:Thu, 19 Nov 1981 08:52:00 GMT
Location:y
Pragma:no-cache
Server:Apache/2.4.25 (Ubuntu)
Request Headers:
view source
Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8
Access-Control-Request-Headers:authorization
Access-Control-Request-Method:POST
Cache-Control:no-cache
Connection:keep-alive
DNT:1
Host:x
Origin:http://127.0.0.1:3000
Pragma:no-cache
Referer:http://127.0.0.1:3000/
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.90 Safari/537.36
Apache virtualhost config looks as so:
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "http://127.0.0.1:3000"
Header set Access-Control-Allow-Origin "http://127.0.0.1"
Header set Access-Control-Max-Age "300"
Header set Access-Control-Allow-Credentials "true"
Header set Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept"
Header set Access-Control-Allow-Methods "POST, GET, PUT, DELETE, PATCH, OPTIONS"
</IfModule>
The preflight request is skipping the apache config and hitting my webapp directly, which does a redirect (hence the 302 and the location: y).
I don't know why the preflight request is not being handled by apache?

To fully CORS-enable an Apache web server, you need to have it configured to look like this:
Header always set Access-Control-Allow-Origin "*"
Header always set Access-Control-Allow-Headers "Authorization"
Header always set Access-Control-Allow-Methods "GET"
Header always set Access-Control-Expose-Headers "Content-Security-Policy, Location"
Header always set Access-Control-Max-Age "600"
RewriteEngine On
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ $1 [R=200,L]
Longer explanation at https://benjaminhorn.io/code/setting-cors-cross-origin-resource-sharing-on-apache-with-correct-response-headers-allowing-everything-through/
Some general notes on what values to set for the various Access-Control- response headers:
Access-Control-Allow-Headers: you must set it to include any header names your request sends except    CORS-safelisted header names or so-called “forbidden” header names (names of headers set by the browser that you can’t set in your JavaScript); the spec alternatively allows the * wildcard as its value—so you can try it, though some browsers may not support it yet: Chrome bug, Firefox bug, Safari bug.
Access-Control-Allow-Methods: the spec alternatively allows the * wildcard—but again, as with Access-Control-Allow-Headers: *, some browsers may not support it yet.
Access-Control-Expose-Headers: set to include any response headers beyond Expires, Cache-Control, Content-Type, Pragma, Last-Modified, and Content-Language that your frontend code needs to read. A lot of people forget to set this and end up baffled about why they can’t read the value of a particular response header). Again the spec alternatively allows the * wildcard here, but some browsers may not support it yet.
Access-Control-Max-Age: Chrome has an upper limit of 600 (10 minutes) hardcoded, so there’s no point in setting a higher value for it than that (Chrome will just throttle it down to 10 minutes if you set it higher, and Safari limits it to only 5 minutes).
So then, about the particular request shown in the question, the specific changes and additions that would need to made are these:
Use Header always set instead of just Header set.
Use mod_rewrite to handle the OPTIONS by just sending back 200 OK with those headers.
The request has Access-Control-Request-Headers:authorization so in the Apache config, add Authorization in the Access-Control-Allow-Headers response header too.
Origin is a “forbidden” header name set by the browser, and Accept is a CORS-safelisted header name, so no need to include them in Access-Control-Allow-Headers.
The request sends no Content-Type, so no need for it in Access-Control-Allow-Headers in the response (and never needed for GET requests and otherwise only needed if the type is not application/x-www-form-urlencoded, text/plain, or multipart/form-data).
For Access-Control-Allow-Methods, the request seems to just be a GET, so unless the plan’s to also make POST/PUT/DELETE/PATCH requests, no point in including them.

Related

Apache mod_rewrite pass Headers

I am running my apache on http://localhost:8083 and i am calling an API hosted on local box i.e. http://localhost:8082
I want to map http://localhost:8083/test-call/abc/authorize call to actual service call i.e. http://localhost:8082/TestCall/abc/authorize.
I have rewrite engine as follows in httpd.conf file:
RewriteEngine on
RewriteRule "^/test-call/(.*)$" "http://localhost:8082/TestCall/$1"
I can see that the call is being mapped correctly from developer console of chrome i.e. http://localhost:8082/TestCall/abc/authorize and i have disabled CORS on my browser as i am testing the API call only.
I have added the following headers in my httpd.conf file:
Header set Access-Control-Allow-Origin "http://localhost:8083"
Header always set Access-Control-Allow-Headers "Authorization, X-Requested-With, Content-Type, content-type, x-requested-with, Accept, Access-Control-Allow-Origin, Cache-Control"
Header always set Cache-Control "no-cache, no-store, must-revalidate"
Header always set Access-Control-Allow-Methods "GET, POST, DELETE, HEAD, OPTIONS"
Header always set Access-Control-Expose-Headers "Content-Security-Policy, Location"
Header always set Access-Control-Max-Age "3600"
Header always set REMOTE_USER "abc.def#db.com"
It's a react application and the bundles are getting loaded correctly with the specified headers above and also the REMOTE_USER is getting added to the REPONSE_HEADERS but for the rewritten URL, the headers are not getting applied.
I want to pass the REMOTE_USER header in the API call after rewrite/redirect.
I have enabled mod_headers and mod_rewrite.
What am i missing?

How do I know which access-control-allow-headers to allow for CORS?

Given these request headers:
Host: api.example.org
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:41.0) Gecko/20100101 Firefox/41.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1
Origin: https://web.example.org
Access-Control-Request-Method: GET
Access-Control-Request-Headers: authorization
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
And these response headers:
Connection: keep-alive
Content-Length: 0
Content-Type: text/plain; charset=utf-8
Date: Tue, 13 Oct 2015 10:57:34 GMT
Server: nginx/1.8.0
access-control-allow-headers: Authorization, Content-Type
access-control-allow-methods: PUT, DELETE, PATCH
access-control-allow-origin: *
This works even though only the Authorization and Content-Type headers are explicitly allowed. Why didn't I have to allow other headers that my browser sends? (like DNT for example)
Update: this MDN page contains an overview of simple headers (default CORS-safelisted request headers):
A simple header (or CORS-safelisted request header) is one of the
following HTTP headers:
Accept
Accept-Language
Content-Language
Content-Type with a MIME type of its parsed value (ignoring parameters) of either application/x-www-form-urlencoded, multipart/form-data, or text/plain.
Or one of these client hint headers:
DPR
Downlink
Save-Data
Viewport-Width
Width
Without seeing your code to generate the headers, or on which system you are serving from, i.e. nginx or apache, the best I can do is refer you to http://client.cors-api.appspot.com/client which will allow you to test your CORS requests. Also, you should look at http://enable-cors.org/server.html for your specific setup. For instance on nginx, you could have something like this
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
There is a set of normal headers, and then the set of headers that you have to explicitly call out. see http://www.html5rocks.com/en/tutorials/cors/#toc-adding-cors-support-to-the-server about setting it up on a server.
The Access-Control-Allow-Headers is attached by backend, you cannot control that header on client side.Access-Control-Allow-Headers should be returned in response object.
So to include other headers into Access-Control-Allow-Headers header in response object - you have to configure your web server or update backend application which serves requests to attach desired value of Access-Control-Allow-Headers to each request.
To allow any headers in your client requests server should add Access-Control-Allow-Origin: * header to each response.
There are a lot of articles and info of how you can setup CORS to work in the way you want. For example that one - Enabling CORS

UI not updating when using tomcat with apache & mod_jk

Well I have a weired issue, I was trying fronting tomcat with apache mod_jk using worker.
If I update my form with something like http://server.internal:8080 i.e tomcat then it works fine i.e updates are shown on screen and onrefresh the updates retain.
But if I update form with apache i.e http://server.internal/ then updates are seen in database but on refresh UI shows old values only, after refreshing 5-10 times then UI shows new values.
Also during refresh sometimes it shows old values while sometimes new values in the form.
I am using tomcat 7 + apache 2.2 + mod_jk on windows server.
I have disabled caching modules but still getting error.
Not sure where and how to debug such an issue.
Edited ---------
Request headers with apache
Cache-Control no-cache,no-store,private,pre-check=0,post-check=0,max-age=0
Connection close
Content-Encoding gzip
Content-Length 10174
Content-Type text/html;charset=utf-8
Date Thu, 11 Dec 2014 19:39:36 GMT
Expires -1
Pragma no-cache
Server Apache/2.2.25 (Win32) mod_jk/1.2.40
Vary Accept-Encoding
Request headers with tomcat
Content-Type text/html;charset=utf-8
Date Thu, 11 Dec 2014 19:43:43 GMT
Server Apache-Coyote/1.1
Transfer-Encoding chunked
Response Header with apache
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding gzip, deflate
Accept-Language en-US,en;q=0.5
Cache-Control max-age=0
Connection keep-alive
Cookie JSESSIONID=7D3ACA49B478E8B3A126B37252B62481
Host server
User-Agent Mozilla/5.0 (Windows NT 6.0; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0
Response header with tomcat
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding gzip, deflate
Accept-Language en-US,en;q=0.5
Connection keep-alive
Cookie JSESSIONID=7D3ACA49B478E8B3A126B37252B62481
Host server:8080
User-Agent Mozilla/5.0 (Windows NT 6.0; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0
Does not look a caching issue, tried with KeepAlive off also
I think its problem with the browser local history, delete the history in your browser and try again.mostly it will works fine.
This definitely smells like a caching issue. To be sure, explicitly purge your browser's cache (or disable it) and see if that helps. If it does, you may
want to add this in your apache's httpd.conf (replace the pattern */yourform.jsp by something that matches your form page(s)) in order to mark these pages as "uncacheable":
<Proxy */yourform.jsp>
Header unset Pragma
Header Always set Cache-Control: "no-cache,no-store,private,pre-check=0,post-check=0,max-age=0"
Header Always set Pragma: "no-cache"
Header Always set Expires "-1"
</Proxy>

HTTP headers automatically set

I am starting to learn about http correctly.
I am working in lamp stack.
On the command line i am requesting a local page which will be served with apache to see the headers that are returned.
curl -i local.testsite
The page i am requesting has no content and i am not setting any headers but there are already a lot of headers sent in the response such as:
HTTP/1.1 200 OK
Date: Thu, 17 Jan 2013 20:28:52 GMT
Server: Apache/2.2.22 (Ubuntu)
X-Powered-By: PHP/5.3.10-1ubuntu3.4
Vary: Accept-Encoding
Content-Length: 0
Content-Type: text/html
So if i am not setting these, does apache set these automatically?
Yes Apache is setting those by default. By the way, if you only care about the headers, you should use
curl -I local.testsite
-I returns the headers only (HTTP HEAD request), such that even if you had content on the page you would only get the header.
Some are set by PHP:
The X-Powered-By header is set by the expose_php INI setting.
The Content-Type header is set by the default_mimetype INI setting.
The others are set by Apache:
The Server header is set by the ServerSignature directive.
The Vary: Accept-Encoding header is usually sent when mod_deflate is enabled.
Date and Content-Length are not configurable as they are part of the HTTP spec. Date is included as a MUST (except under some conditions) and Content-Length as a SHOULD.
See also How to remove date header from apache? and How to disable the Content-Length response header with Apache?.

How do you set the Access-Control-Allow-Origin header for the HTTP basic authentication response in Apache?

I want to use XHR to log in to a site that uses HTTP basic authentication. The following piece does this.
http = new XMLHttpRequest();
http.open("get", "http://...", false, username, password);
http.send("");
The problem is that this does not work from a domain that is different from the one where the authentication is. The solution is simple enough: set the Access-Control-Allow-Origin header to *. So I changed my Apache configuration to this:
<Location />
Header set Access-Control-Allow-Origin "*"
AuthType Basic
AuthName "trac"
AuthUserFile /home/admin/development/pass.htpasswd
Require valid-user
</Location>
Responses from that page look like:
HTTP/1.1 401 Authorization Required
Connection: Keep-Alive
Content-Encoding: gzip
Content-Length: 345
Content-Type: text/html; charset=iso-8859-1
Date: Sun, 11 Sep 2011 01:17:55 GMT
Keep-Alive: timeout=15, max=100
Vary: Accept-Encoding
WWW-Authenticate: Basic realm="trac"
The responses do not have the Access-Control-Allow-Origin header. This seems strange.
When I use the same Header directive for the inside pages, the header is set.
Why was the header not set?
How do you set the Access-Control-Allow-Origin header for the HTTP basic authentication response in Apache?
The answer is:
Header always set Access-Control-Allow-Origin "*"
instead of
Header set Access-Control-Allow-Origin "*"
And the reason is in the documentation of Header directive:
Header [condition] set|append|merge|add|unset|echo|edit header [value] [replacement] [early|env=[!]variable]
The optional condition argument determines which internal table of responses headers this directive will operate against. Other components of the server may have stored their response headers in either the table that corresponds to onsuccess or the table that corresponds to always. "Always" in this context refers to whether headers you add will be sent during both a successful and unsucessful response, but if your action is a function of an existing header, you will have to read on for further complications.
The default value of onsuccess may need to be changed to always under the circumstances similar to those listed below. Note also that repeating this directive with both conditions makes sense in some scenarios because always is not a superset of onsuccess with respect to existing headers:
You're adding a header to a non-success (non-2xx) response, such as a redirect, in which case only the table corresponding to always is used in the ultimate response.
You're modifying or removing a header generated by a CGI script, in which case the CGI scripts are in the table corresponding to always and not in the default table.
You're modifying or removing a header generated by some piece of the server but that header is not being found by the default onsuccess condition.
In your case you send a 401 response instead of a classical 200 response, and the Header is only set on 200 responses if you do not use the always keyword.