Rewrite authenticated Apache2.2 user for mod_proxy_ajp - apache

I have a Tomcat connected via mod_proxy_ajp to an Apache2.2 instance. Apache does the authentication via mod_auth_kerb, and Tomcat uses request.getRemoteUser() to get the authenticated user.
This basically works, but I want to rewrite the user. However, none of the headers I set affect what is returned by request.getRemoteUser(), I only see them as additional headers, what do I have to do?
# Rewrite Magic: change REMOTE_USER to something Alfresco expects
RewriteEngine On
RewriteMap domain_map txt:/etc/apache2/rewrite-map.txt
# Grab the REMOTE_USER apache environment variable for HTTP forwarding (requires sub-request!)
RewriteCond %{LA-U:REMOTE_USER} (.*)#(.*)
# change the format and replace the domain, e.g.:
# user#some.domain ==> other.domain_user
RewriteRule . - [E=RU:${domain_map:%2|%2}_%1]
# copy processed user to HTTP headers
RequestHeader set REMOTE_USER %{RU}e
RequestHeader set HTTP_REMOTE_USER %{RU}e
RequestHeader set AJP_REMOTE_USER %{RU}e
RequestHeader set AJP_HTTP_REMOTE_USER %{RU}e
Thanks!

I suspect that the headers are not being set as you expect them to be set, and they are getting to Tomcat empty.
I have experienced some puzzling processing order issues that caused RequestHeader to ignore the environment variables set by a RewriteRule. Take a look at https://stackoverflow.com/a/9303018/239408 in case it helps

It seems the getRemoteUser() value can not be overwritten by Apache header directives, as the AJP protocol handler gets the username from some internal Apache structure. I worked around this by sending the username via http header and modifying the Java code to use that instead of using getRemoteUser().

Related

How can i add current URL to .htaccess CSP header dynamically?

I'm currently working on Shopify app, one of their main requirement is to add an iframe-protection. here is more info
Currently, to resolve this I need the CSP to set should be in this format :
Content-Security-Policy: frame-ancestors https://shopify-dev.myshopify.com https://admin.shopify.com;
The https://shopify-dev.myshopify.com in above code should be the merchant/ requester domain.
What I tried?
I created .htaccess file with following, it's not adding the dynamic url.
<IfModule mod_rewrite.c>
RewriteEngine On
Header set Content-Security-Policy "frame-ancestors '%{HTTP_HOST}' 'https://admin.shopify.com';"
</IfModule>
This is what I'm getting in console:
Apache
On Apache, you would need to do it like this instead:
### Apache ###
Header set Content-Security-Policy "frame-ancestors https://%{HTTP_HOST}e https://admin.shopify.com;"
Note the e after %{HTTP_HOST}e (specific syntax for mod_headers). I've also removed the single quotes (not present in the Spotify example) and included the https:// protocol.
The <IfModule> and RewriteEngine On directives are irrelevant here.
Reference:
https://httpd.apache.org/docs/current/mod/mod_headers.html#header
UPDATE:
LiteSpeed
However, if you are using LiteSpeed (as opposed to Apache) you will instead need to first explicitly assign the Host header to an environment variable and use this in the Header directive instead. (Apache is able to access server variables directly using this syntax, but not LiteSpeed.)
For example:
### LiteSpeed ###
# Assign the "Host" header to an env var "HOSTNAME"
SetEnvIf Host "(.*)" HOSTNAME=$1
# Use "HOSTNAME" (env var) instead in the Header directive
Header set X-Content-Security-Policy "frame-ancestors https://%{HOSTNAME}e https://admin.shopify.com;"
Attempting to use the syntax %{HTTP_HOST} (as you originally had) on Apache would have resulted in a 500 Internal Server Error (with the error "Unrecognized header format %" being reported in the error logs). However, on LiteSpeed this just outputs the literal string {HTTP_HOST} and no error.

How to disable HTTP 1.0 protocol in Apache?

HTTP 1.0 has security weakness related to session hijacking.
I want to disable it on my web server.
You can check against the SERVER_PROTOCOL variable in a mod-rewrite clause. Be sure to put this rule as the first one.
RewriteEngine On
RewriteCond %{SERVER_PROTOCOL} ^HTTP/1\.0$
RewriteCond %{REQUEST_URI} !^/path/to/403/document.html$
RewriteRule ^ - [F]
The additional negative check for !^/path/to/403/document.html$ is so that the forbidden page can be shown to the users. It would otherwise lead to a recursion.
If you are on a name-based virtual host (and each virtual server does not have its own separate IP address), then it is technically impossible to connect to your virtual host using HTTP/1.0; Only the default server --the first virtual server defined-- will be accessible. This is because HTTP/1.0 does not support the HTTP "Host" request header, and the Host header is required on name-based virtual hosts in order to "pick" which virtual host the request is being addressed to. In most cases, the response to a true HTTP/1.0 request will be a 400-Bad Request.If you did manage to get that code working, but you later tried to use custom error documents (see Apache core ErrorDocument directive), then the result of blocking a request would be an 'infinite' loop: The server would try to respond with a 403-Forbidden response code, and to serve the custom 403 error document. But this would result in another 403 error because access to all resources --including the custom 403 page-- is denied. So the server would generate another 403 error and then try to respond to it, creating another 403, and another, and another... This would continue until either the client or the server gave up.
I'd suggest something like:
SetEnvIf Request_Protocol HTTP/1\.0$ Bad_Req
SetEnvIf Request_URI ^/path-to-your-custom-403-error-page\.html$
Allow_Bad_Req
#Order Deny,Allow
Deny from env=BadReq
Allow from env=Allow_Bad_Req
In mod_rewrite, something like:
RewriteCond %{THE_REQUEST} HTTP/1\.0$
RewriteCond %{REQUEST_URI} !^/path-to-your-custom-403-error-page\.html$
This will (note the FUTURE tense - as of October 2018) be possible with Apache 2.5, using the PolicyVersion directive in mod_policy. The PolicyVersion directive sets the lowest level of the HTTP protocol that is accepted by the server, virtual host, or directory structure - depending on where the directive is placed.
First enable the policy module:
a2enmod mod_policy
Then in the server config, vhost, or directory (will not work in .htaccess), add:
PolicyVersion enforce HTTP/1.1
Finally restart the server:
systemctl restart apache2

Push http header into cookie

I'm trying to propagate an http header across proxies using a cookie from apache 2.4 to nginx.
Apache is only around to do kerberos authentication against Active Directory. Due to the overhead that the AD authentication adds to every get request, I want to limit the authentication. The idea is to set a cookie that expires after x time and only perform the auth through apache if the cookie doesn't exist.
Furthermore, I want the remote_user from apache made available to nginx.
Nginx listens on port 80, and does an auth sub-request to apache on port 81 (same host)
I am able to set http headers in apache, but these get lost in nginx land.
I first tried reading the specific http header that I am interested in from nginx, but I can't see it once the request is transferred to nginx, although I can see them being set on the apache side.
My second idea was to push the header that I am interested in to a server cookie and then extract it in the nginx side, but the cookie value is always empty.
In the apache conf I have:
RewriteRule .* - [E=PROXY_USER:%{LA-U:REMOTE_USER}]
Header add X-Auth-User %{PROXY_USER}e
I can see that header fine on the apache side, but nothing on the nginx side.
Trying to pump the data into a cookie in apache:
RewriteCond %{LA-U:REMOTE_USER} (.*)
RewriteRule ^/ - [env=COOKIE1:%1]
RewriteRule .* - [CO=acaprox:tst=%{COOKIE1}e:.my-domain.com:300:/] [R=307,L]
The trouble with this approach is that the value of test is always empty.
I also tried reusing the environment variable that I can successfully push into the header, into the cookie, but it is also always empty:
RewriteRule .* - [CO=cookietest:tst=%{ENV:PROXY_USER}:.my-domain.com:300:/] [R=307,L]
As is probably blatantly obvious, I don't have much experience in this space.
The issue appears to be related to remote_user, other variables work with the approach I was using.
The solution for me was to set an additional header at the upstream proxy (ie, x-remote-user), and then pull the value from it if the auth_request was successful.
auth_request $user $upstream_http_x_remote_user
The $user variable can then be pushed into a cookie

Apache httpd mod_headers disobedience

I have a client sending basic authentication credentials in a header named "Basic authentication", instead of the correct "Authorization". I can't fix the client, so I'm trying to work around the problem on the server.
This works and sets the "X-Authorization" header to whatever value was sent by the client in the "Basic authentication" header:
SetEnvIf ^Basic.authentication$ ^(.*)$ fixauth=$1
RequestHeader set X-Authorization %{fixauth}e env=fixauth
This sets the environment variable fixauth, but then RequestHeader does nothing:
SetEnvIf ^Basic.authentication$ ^(.*)$ fixauth=$1
RequestHeader set Authorization %{fixauth}e env=fixauth
Using "RequestHeader add" makes no difference. It looks as if mod_header would be refusing to touch the Authorization header, but there is nothing about it in the documentation and nothing that I could find in the source code.
What exactly is the problem? Why does setting X-Authorization work, but setting Authorization does not?

mod_rewrite: add a header if it doesn't already exist

I am attempting to add CORS handling using apache and mod_rewrite. The apache instance is front-ending multiple tomcat applications using mod_jk. Some of these applications have their own logic for adding CORS headers Access-Control-Allow-Origin, Access-Control-Max-Age, etc.
For the applications that didn't take care of the CORS logic, I would like to manage it on apache using mod rewrite.
Does anyone know if its possible to add a header to an HTTP response using mod_rewrite only if the header doesn't already exist? The browser reports an error if the CORS origin header is written twice.
mod_rewrite is to rewrite url's, not to set headers. What you want to use is mod_headers (documentation).
I don't know if mod_rewrite runs before mod_headers, but I would suggest to set environment variables using SetEnvIf instead (documentation).
You can do something like this:
SetEnvIf Request_URI "^/my/app/(.*)/?$" ADDHEADERS=1
Header set Access-Control-Max-Age 123456 env=ADDHEADERS