Bug 62496

Summary: Add option to write auth information (remote user/auth type) to response headers
Product: Tomcat 8 Reporter: Michael Osipov <michaelo>
Component: CatalinaAssignee: Tomcat Developers Mailing List <dev>
Status: RESOLVED FIXED    
Severity: enhancement    
Priority: P2    
Version: 8.5.x-trunk   
Target Milestone: ----   
Hardware: All   
OS: All   
Bug Depends on: 63556    
Bug Blocks:    

Description Michael Osipov 2018-06-27 14:26:20 UTC
I have a fairly simple usecase for an enhancement request from which a lot of users can benefit.

Use case:

* Apache HTTPd (2.4.33) <====> Tomcat (8.5.30) via mod_proxy
* Apache logs with CustomLog ... common
* VirtualHost does not only proxy Tomcat, also hosts other unrelated apps (.e.g, Subversion), so changing the log format is not an option
* Tomcat performs authentication
* Apache logs the requests, but remote_user column is empty. This is ugly and I do not really want duplicate logging, i.e., on both sides or if both need to be consistent.

Thanks to rjung@ and jim@ I worked out a solution which does a nice job.

httpd-tomcat.conf:
> <Location "/app">
>     ProxyPreserveHost On
>     ProxyPass ..
>     ProxyPassReverse ..
>     RequestHeader set X-Forwarded-Proto "https"
>     Header note X-Remote-User REMOTE_USER
>     LuaHookLog /usr/local/etc/apache24/register_remote_user.lua register_remote_user
> </Location>

register_remote_user.lua:
> require 'apache2'
> 
> function register_remote_user(r)
>     local remote_user = r.notes["REMOTE_USER"]
>     if remote_user ~= nil then
>         r.user = remote_user
>         -- not implemented in mod_lua
>         -- r.ap_auth_type = "SPNEGO"
>     end
>     return apache2.OK
> end

On the Tomcat side I have added:
> public class ResponseRemoteUserValve extends ValveBase {
> 
> 	@Override
> 	public void invoke(Request request, Response response) throws IOException, ServletException {
> 		String remoteUser = request.getRemoteUser();
> 
> 		if (remoteUser != null) {
> 			response.setHeader("X-Remote-User", remoteUser);
> 		}
> 
> 		getNext().invoke(request, response);
> 	}
> 
> }

Ideally for request#getAuthType() to X-Remote-AuthType too. I think this is suitable for either AuthenticatorBase or RemoteIPValve.

Comments and ideas welcome!
Comment 1 Michael Osipov 2018-06-27 15:19:05 UTC
One glitch: "Header unset X-Remote-User" is missing from the config.
Comment 2 Christopher Schultz 2018-06-27 15:45:30 UTC
Seems reasonable.

Care to prepare a patch, including javadoc + XML/HTML documentation?
Comment 3 Michael Osipov 2018-06-27 15:53:25 UTC
(In reply to Christopher Schultz from comment #2)
> Seems reasonable.
> 
> Care to prepare a patch, including javadoc + XML/HTML documentation?

The patch isn't an issue. I'd like to assess where (classwise) it fits best.
Comment 4 Christopher Schultz 2018-06-27 16:29:30 UTC
Well, there doesn't seem to be a need to implement this as a Valve (unless I'm missing something important), so let's implement it as a Filter.

The other filters Tomcat provides are all in the org.apache.catalina.filters package. The class name you have now seems awkward, but I don't have a better idea for it.

It would be nice to be able to set the header field-names, and enable either/or X-Remote-User and X-Remote-AuthType.
Comment 5 Rainer Jung 2018-06-27 17:03:34 UTC
I wonder how hard it would be to rewrite something like mod_headers in Java. Similar to our RewriteValve that mimics mod_rewrite. That would be more flexible, but we would need to find a good place to put the config for the headers valve or filter. The RewriteValve uses it's own rewrite.config due to the goal of config compatibility with httpd, but mod_headers config syntax is much simpler, so maybe it can be transformed to xml style without getting to ugly.

Just an idea...
Comment 6 Rainer Jung 2018-06-27 17:07:00 UTC
I should have added, how such a headers filter or valve would then be used:

Header set X-Remote-User %{REMOTE_USER}

That would be httpd syntax, it could be adjusted for our uses. Also %{REMOTE_USER} is httpd syntax and also used by our own RewriteValve, but we could instead use something else.
Comment 7 Michael Osipov 2018-06-27 18:22:48 UTC
(In reply to Christopher Schultz from comment #4)
> Well, there doesn't seem to be a need to implement this as a Valve (unless
> I'm missing something important), so let's implement it as a Filter.

That is true, but opted for Valve because I can phyically register it *after* my authenticator (in context.xml) guaranteeing that auth has actually happened. I had it at Host level and it did not work of course.

Why do we need that actually separately? Why not add it to AuthenticatorBase? That seems to be perfect.

> It would be nice to be able to set the header field-names, and enable
> either/or X-Remote-User and X-Remote-AuthType.

Agreed.
Comment 8 Michael Osipov 2018-06-27 18:25:02 UTC
(In reply to Christopher Schultz from comment #4)

Oh, I forgot. Here is the code I have put on the server now: https://sourceforge.net/p/mo-tomcat-ext/code/121/
Comment 9 Michael Osipov 2019-08-01 10:00:16 UTC
Fixed in:
- master for 9.0.23 onwards
- 8.5.x for 8.5.44 onwards
- 7.0.x for 7.0.97 onwards