Edit a header value in nginx - nginx

Background
So I've got a server running a tomcat application hidden behind an Apache proxy. The proxy provides a more user friendly url as well as SSL encryption with automatic redirects so that the app is only accessible on https.
I'm busy migrating this to an nginx proxy.
One of the issues I've had is that upon login, my app sends back a "LocationAfterLogon" header in the http response in the form of
http://192.168.x.x:8080/myapp/index.jsp.
That IP address returned is from the proxied server not visible on the internet. So then the browser gets a connection error trying to navigate to it.
As a workaround, I've used nginx directives:
proxy_hide_header: to hide the LocationAfterLogin header coming back from the proxied server
add_header: to add a new LocationAfterLogin url.
So my config looks as follows
#header for location after logon of demo app
add_header LocationAfterLogon http://example.com/demo/index.jsp;
#hide the real LocationAfterLogon
proxy_hide_header LocationAfterLogon;
The Problem
I need to be able to do a regex replace or similar on LocationAfterLogon because it won't always be to index.jsp, depending on which url was intercepted by the login page.
I am aware that I can also rewrite the tomcat app to send back a relative URL instead, but I'd like to do it all in nginx config.
I've also read about nginx more_set_headers. Haven't tried it yet. Does it allow me to edit the headers?
Apache has the Header edit directive which I was using previously, so I'm looking for something like that.
TL;DR
Is is possible to edit a header location using regex replace or similar in Nginx?

You can use the map directive to rewrite your header:
map $upstream_http_locationafterlogon $new_location {
~regexp new_value;
}
proxy_hide_header LocationAfterLogon;
add_header LocationAfterLogon $new_location;
See the documentation: http://nginx.org/en/docs/http/ngx_http_map_module.html

Related

How do I tell TYPO3 what it's URL is when using a reverse proxy?

I have:
A url www.my-website.com
A machine running TYPO3 with some hostname like typo3-website.my.internal.domain.com
A machine running Nginx which uses proxy_pass to send requests from www.my-website.com to typo3-website.my.internal.domain.com
A DNS A record for www.my-website.com pointing to the reverse-proxy machine.
When a backend user is working in the Page module, and they do right-click 'Show' on a page, it tries to open the page at the hostname of the machine TYPO3 is running on.
I want it to open the page under the actual website URL instead.
What setting do I need to change to make this work?
Things I have already tried which did not help:
Setting the trusted hosts pattern
'reverseProxyIP' => '*'
'reverseProxyHeaderMultiValue' => 'last'
I needed to create a domain record. That partially fixed it.
This still leaves problems where images use the wrong URL in the backend.
This means, that, for example, the little dotted lines in the page tree module do not display.
To fix that, I used a clue from this forum thread. I needed to set the HTTP_HOST variable to my domain and send it to PHP fpm:
location ~ \.php$ {
try_files $uri = 404;
include ${pkgs.nginx}/conf/fastcgi.conf;
fastcgi_pass unix:/var/run/phpfpm/default.sock;
# Assorted fastcgi_blah
fastcgi_param HTTP_HOST "www.my-domain.com";
}
If you're trying to get TYPO to see the request as a request for a specific domain, you may want to use the following on your proxy block:
proxy_set_header Host $proxy_host;

Allow cross origin application side (no control of API)

I have an application which should be able to read in data from any data source, meaning any API from any domain.
How to get around the Cross-Origin problem when you don't have any control over the API or even the domain it is coming from?
I know that you could simulate the same domain by adding a
location /data/ {
proxy_pass http://exampleAPIdomain.com/data/;
}
block to allow for a specific API domain (here: exampleAPIdomain.com), but in my case I want to be open for any domain.
Is that even possible?
Yes, that is possible by using a variable in the proxy_pass-directive:
proxy_pass $somevariable$request_uri;
You can set the actual host via a header for example, then the directive would be:
proxy_pass $http_someheader$request_uri;
Security note: If you expose this to the internet without some form of authorization, then everybody can use your proxy to proxy anything.

Nginx is ignoring my headers

I'm working with apache on my local instance and nginx on production.
I have a javascript application that is setting headers in API calls to authenticate the user. It's working fine on local with my apache server. However for some reason, my custom headers are ignored by Nginx.
I tried to add this line in my site configuration:
add_header 'Access-Control-Allow-Origin' '*';
But it still ignore the headers.
Does anyone know where I should look to bypass this ?
Cheers,
Maxime
I found what was the issue.
My custom headers were API_USER and API_TOKEN.
There is a directive in Nginx that says to ignore headers with a '_' in the name, more info here
So I've updated my custom headers to x-api-user and x-api-token and now it's working like a charm !

How to Reproduce sendRedirect issue - HTTPS change to HTTP

I am using response.sendRedirect() to redirect the user to Home page, once the user gets authenticated successfully. This is to avoid the "Login redirect vulnerability".
However, because of above change, One of my customer is facing issue where his HTTPS request are getting converted to HTTP (with ip address in the URL). The reason for the same is explained here
http://geekexplains.blogspot.in/2008/06/https-becoming-http-in-case-of.html
Now, How can i reproduce the issue (or setup the environment) so that I can verify my fix. I thought I could reproduce by setting up Apache server infront of tomcat but I am not able to reproduce above mentioned issue.
In Apache httpd.conf i have below entries
ProxyPass /myconsole ajp://localhost:8009/myconsole
ProxyPassReverse /myconsole ajp://localhost:8009/myconsole
Accessed the application like,
http://myapacheserver/myconsole/Login.jsp
After the successful login, I am getting redirected to
http://myapacheserver/myconsole/Home.jsp
I am expecting to redirect to the IP address. something like http://10.32.24.14:8080/myconsole/Home.jsp.
In the customer environment he is getting redirected to the ip address of App server (tomcat).
Any pointer would be helpful.
Thanks
Note:
For those interested, I am building the full URL by getting the first part of URI from the configuration file.
//Get the LB URI part. Eg: https://dev.loadbalancer.com/
String loadBalancerURI = getConfig().getLoadBalancerRequestURI();
String redirectURL = request.getContextPath() + "/Home.jsp";
//Prepend the LoadBalancer URI with redirect URI
if(loadBalancerURI != null)
{
redirectURL = loadBalancerURI + "/" + redirectURL;
}
//redirect to home page
response.sendRedirect(redirectURL);
return;
Edit: More info on the setup. The customer has F5 load balancer where the SSL traffic stops and then there is a Apache Reverse Proxy servers which proxy to pool of tomcat servers. The issue is when we do redirect the redirect URL is for Tomcat Servers. What we are expecting is to have the load balancer URL in the redirect URL.
Is it possible to do some change in the Apache server which will rewrite the URL in the HTTP header in the response send by Tomcat?
I'm not sure if you're really using a load balancer or if you just called one of your methods getLoadBalancerRequestURI, but where you only have one server, just use :
response.sendRedirect("./Home.jsp");
Its not necessary to specify the full url.
But if you do need to build the full url as you are doing, you can use something like this to check if its https://
String protocol = "https";
if( request.getRequestURL().toString().toLowerCase().startsWith("http://" ) )
{
protocol = "http";
}
Then make sure to build the url with the proper protocol.
See this link ..
So when an https request redirect happens, the target server has no clue what's the original request's protocol. It only receives an http request. Thus, the response for that would be an http response.
http://www.hoitikwong.com/2013/03/the-mystery-case-of-https-becoming-http.html
I was able to reproduce the issue (when HTTP-HTTPS redirect) which my customer was facing.
The communication from Apache (HTTPD server) to Tomcat (Web container) generally happens by using one of the following connectors (may be some other way as well).
mod_jk
mod_proxy_ajp
mod_proxy_http
mod_rewrite
I am able to reproduce the issue only when i use the mod_rewrite. If i use either mod_jk or mod_proxy_ajp or mod_proxy_http approach then the redirect works fine. But when i use mod_rewrite then when the redirect happens I am able to observe the HTTPS-HTTP conversion.

How to make nginx(proxy) cache the actual content instead of just the headers when a http 302/301 response is received by the proxy_pass server?

I'm trying to use nginx as a temporary http cache in order to minimize requests to content. My content is on multiple servers so I can't use a static proxy_pass parameter to the direct location but instead of that I use a rewrite to a php script:
rewrite /([^/]+\.jpg) /index.php?file=$1 break;
proxy_pass http://www.phpserver.com;
The php script(that would be http://www.phpserver.com/index.php) then returns a redirect with http code 301 to the actual file location(like http://www.contentserver1.com/filepath/file.jpg).
The problem is that nginx returns the redirect headers instead of retrieving,caching and returning the actual content.
So how do I make it to get the content from the actual server instead of just caching the headers?
Nginx can work only as proxy. It doesn't know anything about logic of you application (site), it's just proxies requests, and can put to cache responses.
For make this schema work, you must remove rewrite section from nginx, and move this logic to phpserver.com. phpserver must download this file and output it to nginx. Even if it very hard operation, nginx would cache this response and when next request will be received, nginx will give response direct from his cache.

Resources