You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tomcat.apache.org by Elliot Kendall <el...@ucsf.edu> on 2014/02/11 01:20:57 UTC

AJP and attributes versus headers

We have a Java application running on Tomcat with an Apache HTTP proxy
in front. Our SSO system (Shibboleth) runs as an Apache module and sets
an HTTP header with the logged-in username, which gets passed through
to Tomcat and which the app uses Spring's
RequestHeaderAuthenticationFilter to read.

We would like to switch from HTTP to AJP for the proxy, as recommended
by our SSO vendor. When we do, though, the logged-in username ends up
in an environment variable and gets passed to Tomcat as a request
attribute rather than a header. The Spring filter is using
javax.servlet.http.HttpServletRequest.getHeader to read the value,
which fails. For things to work, it would need to use
javax.servlet.ServletRequest.getAttribute. As far as I can tell, no
filter exists in Spring that uses requests instead of headers.

Is there a way to make Tomcat expose the values of AJP request
attributes as headers so that the Spring filter can see them? Or maybe
a way to make one the user principal, accessible through
javax.servlet.http.HttpServletRequest.getUserPrincipal? Then I could
use a different Spring filter, J2eePreAuthenticatedProcessingFilter).
And if there is a way to do one or both of these, do you think I would
be better off trying to fix this on the Spring side?

Thanks for any suggestions.

-- 
Elliot Kendall
IAM Support Engineer - Single Sign On
Information Technology Services
University of California, San Francisco


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: AJP and attributes versus headers

Posted by André Warnier <aw...@ice-sa.com>.
Cédric Couralet wrote:
> 2014-02-11 10:41 GMT+01:00 André Warnier <aw...@ice-sa.com>:
> 
>> Cédric Couralet wrote:
>>
>>> 2014-02-11 1:20 GMT+01:00 Elliot Kendall <el...@ucsf.edu>:
>>>
>>>  We have a Java application running on Tomcat with an Apache HTTP proxy
>>>> in front. Our SSO system (Shibboleth) runs as an Apache module and sets
>>>> an HTTP header with the logged-in username, which gets passed through
>>>> to Tomcat and which the app uses Spring's
>>>> RequestHeaderAuthenticationFilter to read.
>>>>
>>>> We would like to switch from HTTP to AJP for the proxy, as recommended
>>>> by our SSO vendor. When we do, though, the logged-in username ends up
>>>> in an environment variable and gets passed to Tomcat as a request
>>>> attribute rather than a header. The Spring filter is using
>>>> javax.servlet.http.HttpServletRequest.getHeader to read the value,
>>>> which fails. For things to work, it would need to use
>>>> javax.servlet.ServletRequest.getAttribute. As far as I can tell, no
>>>> filter exists in Spring that uses requests instead of headers.
>>>>
>>>> Is there a way to make Tomcat expose the values of AJP request
>>>> attributes as headers so that the Spring filter can see them? Or maybe
>>>> a way to make one the user principal, accessible through
>>>> javax.servlet.http.HttpServletRequest.getUserPrincipal? Then I could
>>>> use a different Spring filter, J2eePreAuthenticatedProcessingFilter).
>>>> And if there is a way to do one or both of these, do you think I would
>>>> be better off trying to fix this on the Spring side?
>>>>
>>>>
>>>>  You could try setting tomcatAuthentification="false" on your AJP
>>> connector
>>> in server.xml. If Shibboleth put the value in REMOTE_USER as it should
>>> then
>>> tomcat should pick it up as the principal.
>>> Be aware that you should protect your ajp connector so that no other
>>> machine than your Apache can connect to it.
>>>
>>>
>> Cedric,
>> I think that the essence of the above is correct, but that strictly
>> speaking the details are not.
>> I do not think that the authenticated user-id from Apache is passed via
>> (or taken from) the REMOTE_USER header.  The mod_jk and mod_proxy_ajp
>> modules most probably take the Apache authenticated user-id directly from
>> the Apache "request record" (r->user), no matter how it has been set, and
>> pass it on to Tomcat throughj AJP as a request attribute.
>> The setting of the REMOTE_USER http header is just a side-effect, and may
>> be happening or not.
>> The AJP connector at the Tomcat level, if tomcatAuthentication="false",
>> then uses the value of the received AJP request attribute to set Tomcat's
>> request userPrincipal value.
>> There is no need then for anything else in Tomcat to grab the REMOTE_USER
>> header of the request.
>>
>>
> Yes, I did not mean REMOTE_USER as header but as the environment variable
> in apache httpd (I don't know how to call it).

Yes, that terminology is somewhat confused and confusing.
I call them "Apache httpd variables", because they are not like environment variables for 
the Apache httpd process itself, nor like environment variables for the cgi-bin processes 
that Apache httpd starts (SetEnv), nor like mod_perl variables (PerlSetEnv), nor are they 
http headers.
And in Tomcat/AJP parlance, the closest things are called "request attributes", but which 
at the Apache httpd level with mod_jk, one sets with the "JkEnvVar" directive; and with 
the mod_proxy module one sometimes sets them via "Parameters" or "Options".
Which are of course not the same at all as the attributes of a Tomcat Connector tag...


  I picked it up from this
> page  :
> 
> https://wiki.shibboleth.net/confluence/display/SHIB2/NativeSPJavaInstall
> 
> "Setting the tomcatAuthentication="false" attribute on the AJP
> <Connector>element allows for passing
> REMOTE_USER from Apache httpd. See Tomcat's AJP Connector documentation for
> more."
> 
> 
> 
>> I do not know Shibboleth, but I would presume that when it authenticates a
>> user, it sets the Apache r->user first. And then maybe, accessorily and/or
>> optionally, Shibbolet may add a REMOTE_USER header to the request.
>>
>> And at the Tomcat level, one /may/ have some authentication module that
>> picks up the user-id from the REMOTE_USER header of the request, and sets
>> it as the Tomcat userPrincipal.
>>
>> But what I mean to say is that both these things with the REMOTE_USER http
>> header are not mandatory.  If Apache httpd authenticates a user, by
>> whatever well-written method, the httpd r->user will be set, and the
>> proxied AJP request will contain the corresponding user-id.  And if the
>> Tomcat AJP <Connector> says tomcatAuthentication="false", then the
>> Connector will pick up this user-id from the AJP request attribute, and set
>> the Tomcat user to that value.  Independently of any REMOTE_USER header
>> being set or not.
>>
>> Of course you can always override this, and force the usage of the
>> REMOTE_USER header on both sides. But why would you do that, if a standard
>> mechanism is already built-in into AJP ?
>> (It would be different if you were using mod_proxy_http as a connector).
>>
>>
>>
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: AJP and attributes versus headers

Posted by Cédric Couralet <ce...@gmail.com>.
2014-02-11 10:41 GMT+01:00 André Warnier <aw...@ice-sa.com>:

> Cédric Couralet wrote:
>
>> 2014-02-11 1:20 GMT+01:00 Elliot Kendall <el...@ucsf.edu>:
>>
>>  We have a Java application running on Tomcat with an Apache HTTP proxy
>>> in front. Our SSO system (Shibboleth) runs as an Apache module and sets
>>> an HTTP header with the logged-in username, which gets passed through
>>> to Tomcat and which the app uses Spring's
>>> RequestHeaderAuthenticationFilter to read.
>>>
>>> We would like to switch from HTTP to AJP for the proxy, as recommended
>>> by our SSO vendor. When we do, though, the logged-in username ends up
>>> in an environment variable and gets passed to Tomcat as a request
>>> attribute rather than a header. The Spring filter is using
>>> javax.servlet.http.HttpServletRequest.getHeader to read the value,
>>> which fails. For things to work, it would need to use
>>> javax.servlet.ServletRequest.getAttribute. As far as I can tell, no
>>> filter exists in Spring that uses requests instead of headers.
>>>
>>> Is there a way to make Tomcat expose the values of AJP request
>>> attributes as headers so that the Spring filter can see them? Or maybe
>>> a way to make one the user principal, accessible through
>>> javax.servlet.http.HttpServletRequest.getUserPrincipal? Then I could
>>> use a different Spring filter, J2eePreAuthenticatedProcessingFilter).
>>> And if there is a way to do one or both of these, do you think I would
>>> be better off trying to fix this on the Spring side?
>>>
>>>
>>>  You could try setting tomcatAuthentification="false" on your AJP
>> connector
>> in server.xml. If Shibboleth put the value in REMOTE_USER as it should
>> then
>> tomcat should pick it up as the principal.
>> Be aware that you should protect your ajp connector so that no other
>> machine than your Apache can connect to it.
>>
>>
> Cedric,
> I think that the essence of the above is correct, but that strictly
> speaking the details are not.
> I do not think that the authenticated user-id from Apache is passed via
> (or taken from) the REMOTE_USER header.  The mod_jk and mod_proxy_ajp
> modules most probably take the Apache authenticated user-id directly from
> the Apache "request record" (r->user), no matter how it has been set, and
> pass it on to Tomcat throughj AJP as a request attribute.
> The setting of the REMOTE_USER http header is just a side-effect, and may
> be happening or not.
> The AJP connector at the Tomcat level, if tomcatAuthentication="false",
> then uses the value of the received AJP request attribute to set Tomcat's
> request userPrincipal value.
> There is no need then for anything else in Tomcat to grab the REMOTE_USER
> header of the request.
>
>
Yes, I did not mean REMOTE_USER as header but as the environment variable
in apache httpd (I don't know how to call it). I picked it up from this
page  :

https://wiki.shibboleth.net/confluence/display/SHIB2/NativeSPJavaInstall

"Setting the tomcatAuthentication="false" attribute on the AJP
<Connector>element allows for passing
REMOTE_USER from Apache httpd. See Tomcat's AJP Connector documentation for
more."



> I do not know Shibboleth, but I would presume that when it authenticates a
> user, it sets the Apache r->user first. And then maybe, accessorily and/or
> optionally, Shibbolet may add a REMOTE_USER header to the request.
>
> And at the Tomcat level, one /may/ have some authentication module that
> picks up the user-id from the REMOTE_USER header of the request, and sets
> it as the Tomcat userPrincipal.
>
> But what I mean to say is that both these things with the REMOTE_USER http
> header are not mandatory.  If Apache httpd authenticates a user, by
> whatever well-written method, the httpd r->user will be set, and the
> proxied AJP request will contain the corresponding user-id.  And if the
> Tomcat AJP <Connector> says tomcatAuthentication="false", then the
> Connector will pick up this user-id from the AJP request attribute, and set
> the Tomcat user to that value.  Independently of any REMOTE_USER header
> being set or not.
>
> Of course you can always override this, and force the usage of the
> REMOTE_USER header on both sides. But why would you do that, if a standard
> mechanism is already built-in into AJP ?
> (It would be different if you were using mod_proxy_http as a connector).
>
>
>

Re: AJP and attributes versus headers

Posted by André Warnier <aw...@ice-sa.com>.
Cédric Couralet wrote:
> 2014-02-11 1:20 GMT+01:00 Elliot Kendall <el...@ucsf.edu>:
> 
>> We have a Java application running on Tomcat with an Apache HTTP proxy
>> in front. Our SSO system (Shibboleth) runs as an Apache module and sets
>> an HTTP header with the logged-in username, which gets passed through
>> to Tomcat and which the app uses Spring's
>> RequestHeaderAuthenticationFilter to read.
>>
>> We would like to switch from HTTP to AJP for the proxy, as recommended
>> by our SSO vendor. When we do, though, the logged-in username ends up
>> in an environment variable and gets passed to Tomcat as a request
>> attribute rather than a header. The Spring filter is using
>> javax.servlet.http.HttpServletRequest.getHeader to read the value,
>> which fails. For things to work, it would need to use
>> javax.servlet.ServletRequest.getAttribute. As far as I can tell, no
>> filter exists in Spring that uses requests instead of headers.
>>
>> Is there a way to make Tomcat expose the values of AJP request
>> attributes as headers so that the Spring filter can see them? Or maybe
>> a way to make one the user principal, accessible through
>> javax.servlet.http.HttpServletRequest.getUserPrincipal? Then I could
>> use a different Spring filter, J2eePreAuthenticatedProcessingFilter).
>> And if there is a way to do one or both of these, do you think I would
>> be better off trying to fix this on the Spring side?
>>
>>
> You could try setting tomcatAuthentification="false" on your AJP connector
> in server.xml. If Shibboleth put the value in REMOTE_USER as it should then
> tomcat should pick it up as the principal.
> Be aware that you should protect your ajp connector so that no other
> machine than your Apache can connect to it.
> 

Cedric,
I think that the essence of the above is correct, but that strictly speaking the details 
are not.
I do not think that the authenticated user-id from Apache is passed via (or taken from) 
the REMOTE_USER header.  The mod_jk and mod_proxy_ajp modules most probably take the 
Apache authenticated user-id directly from the Apache "request record" (r->user), no 
matter how it has been set, and pass it on to Tomcat throughj AJP as a request attribute.
The setting of the REMOTE_USER http header is just a side-effect, and may be happening or not.
The AJP connector at the Tomcat level, if tomcatAuthentication="false", then uses the 
value of the received AJP request attribute to set Tomcat's request userPrincipal value.
There is no need then for anything else in Tomcat to grab the REMOTE_USER header of the 
request.

I do not know Shibboleth, but I would presume that when it authenticates a user, it sets 
the Apache r->user first. And then maybe, accessorily and/or optionally, Shibbolet may add 
a REMOTE_USER header to the request.

And at the Tomcat level, one /may/ have some authentication module that picks up the 
user-id from the REMOTE_USER header of the request, and sets it as the Tomcat userPrincipal.

But what I mean to say is that both these things with the REMOTE_USER http header are not 
mandatory.  If Apache httpd authenticates a user, by whatever well-written method, the 
httpd r->user will be set, and the proxied AJP request will contain the corresponding 
user-id.  And if the Tomcat AJP <Connector> says tomcatAuthentication="false", then the 
Connector will pick up this user-id from the AJP request attribute, and set the Tomcat 
user to that value.  Independently of any REMOTE_USER header being set or not.

Of course you can always override this, and force the usage of the REMOTE_USER header on 
both sides. But why would you do that, if a standard mechanism is already built-in into AJP ?
(It would be different if you were using mod_proxy_http as a connector).

> 
> 
> 
>> Thanks for any suggestions.
>>
>> --
>> Elliot Kendall
>> IAM Support Engineer - Single Sign On
>> Information Technology Services
>> University of California, San Francisco
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
>> For additional commands, e-mail: users-help@tomcat.apache.org
>>
>>
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: AJP and attributes versus headers

Posted by André Warnier <aw...@ice-sa.com>.
Elliot Kendall wrote:
>> You could try setting tomcatAuthentification="false" on your AJP connector
>> in server.xml. If Shibboleth put the value in REMOTE_USER as it should then
>> tomcat should pick it up as the principal.
>> Be aware that you should protect your ajp connector so that no other
>> machine than your Apache can connect to it.
> 
> This was one of the first things I tried, and when it didn't work I
> thought I must be missing something. Of course, now that you've
> inspired me to try again it works flawlessly. Thanks!
> 
> I am still curious as to why the AJP connector populates incoming
> request headers as attributes, though.

It doesn't.  Read the previous responses.
Incoming HTTP request headers are passed to Tomcat as HTTP request headers.
Request attributes are something else.

  It seems like it has the
> potential to cause problems without offering any obvious benefits.
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: AJP and attributes versus headers

Posted by Christopher Schultz <ch...@christopherschultz.net>.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Elliot,

On 2/11/14, 12:41 PM, Elliot Kendall wrote:
>> You could try setting tomcatAuthentification="false" on your AJP
>> connector in server.xml. If Shibboleth put the value in
>> REMOTE_USER as it should then tomcat should pick it up as the
>> principal. Be aware that you should protect your ajp connector so
>> that no other machine than your Apache can connect to it.
> 
> This was one of the first things I tried, and when it didn't work
> I thought I must be missing something. Of course, now that you've 
> inspired me to try again it works flawlessly. Thanks!
> 
> I am still curious as to why the AJP connector populates incoming 
> request headers as attributes, though. It seems like it has the 
> potential to cause problems without offering any obvious benefits.

So, your subjective preference for request headers is better than
someone else's subjective preference for request attributes, so things
should change? Not likely.

I would argue that the data is not coming-across from anywhere else as
an HTTP header, so why should HTTP headers be added for the last-link?
You can consider Apache httpd as a reverse proxy, and if it were using
HTTP as the protocol (instead of AJP) then HTTP headers would be the
only way to go, so that would be a reasonable argument for headers
versus attributes.

Remember that you can always write a Filter (or Valve, if you need to
work at a lower level) that does anything you want, including copying
headers to attributes or vice-versa.

- -chris
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1
Comment: GPGTools - http://gpgtools.org
Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/

iQIcBAEBCAAGBQJS+m5kAAoJEBzwKT+lPKRYqWIQALXd4PgwTXZmcn7kFvjia5SH
z+aVB4ikoaOtJbcxjyVNjz72zISwxlWLUkqbRNUBtSJfNW0dkvfluco+qxdLRr1h
lLBuvdpLOM3JBkBvtTEHHZi/Hj55wtnfxLjuH3oR4jf2Ca7G+duxs3WbO8SmaOxq
H/zwCI0DVVbZw9VhNL6QRbayFlUdBF22EVUzeOqeMDTopRAZnvjsAzjrUUgxA1eI
wBBPsJvMHSVwq7+brgEbbd/iQJD1KgYFVIKyyDUoloqZyhhS5EtD/K3xg9xwh2T0
o9VsU0HOPjSeYdhRmNw3+xKq1KrH59C4VJ28gIcu3e+RQA1LGHC2/y6vPA5TT9yi
eec0etvaergZ8+EMMauanQt+VlqQ2eyPuDmXUEQvBlzYW33GULY3mFefNjLX/Q6i
FEMPE0nD8R999334sOE3r/3JgwqH31xBRScHrTTvuBwutW902t0fhhauhcHkJZyj
iokJ4y3Ix8TdxBs6+xVDg/oSAG8EFON7z95qP5U6tgFs6yaUuHsoOMandE9nU/VE
OI75aeQv+Bp2xC/vTI4uSg9WAhLIeQisdRfrzq/Pk0TSMReV72kMAR1b1fH/AzMe
QyRyaYGCbfLEyPDaNAVBEFUm0tCpmXWrxRmapw9ZmE3kS7+ycFLeEcaqW1odfOWw
kSCwBKjxSzIrjPMQQ1vp
=TuKx
-----END PGP SIGNATURE-----

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: AJP and attributes versus headers

Posted by Elliot Kendall <el...@ucsf.edu>.
> You could try setting tomcatAuthentification="false" on your AJP connector
> in server.xml. If Shibboleth put the value in REMOTE_USER as it should then
> tomcat should pick it up as the principal.
> Be aware that you should protect your ajp connector so that no other
> machine than your Apache can connect to it.

This was one of the first things I tried, and when it didn't work I
thought I must be missing something. Of course, now that you've
inspired me to try again it works flawlessly. Thanks!

I am still curious as to why the AJP connector populates incoming
request headers as attributes, though. It seems like it has the
potential to cause problems without offering any obvious benefits.

-- 
Elliot Kendall
IAM Support Engineer - Single Sign On
Information Technology Services
University of California, San Francisco


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: AJP and attributes versus headers

Posted by Cédric Couralet <ce...@gmail.com>.
2014-02-11 1:20 GMT+01:00 Elliot Kendall <el...@ucsf.edu>:

> We have a Java application running on Tomcat with an Apache HTTP proxy
> in front. Our SSO system (Shibboleth) runs as an Apache module and sets
> an HTTP header with the logged-in username, which gets passed through
> to Tomcat and which the app uses Spring's
> RequestHeaderAuthenticationFilter to read.
>
> We would like to switch from HTTP to AJP for the proxy, as recommended
> by our SSO vendor. When we do, though, the logged-in username ends up
> in an environment variable and gets passed to Tomcat as a request
> attribute rather than a header. The Spring filter is using
> javax.servlet.http.HttpServletRequest.getHeader to read the value,
> which fails. For things to work, it would need to use
> javax.servlet.ServletRequest.getAttribute. As far as I can tell, no
> filter exists in Spring that uses requests instead of headers.
>
> Is there a way to make Tomcat expose the values of AJP request
> attributes as headers so that the Spring filter can see them? Or maybe
> a way to make one the user principal, accessible through
> javax.servlet.http.HttpServletRequest.getUserPrincipal? Then I could
> use a different Spring filter, J2eePreAuthenticatedProcessingFilter).
> And if there is a way to do one or both of these, do you think I would
> be better off trying to fix this on the Spring side?
>
>
You could try setting tomcatAuthentification="false" on your AJP connector
in server.xml. If Shibboleth put the value in REMOTE_USER as it should then
tomcat should pick it up as the principal.
Be aware that you should protect your ajp connector so that no other
machine than your Apache can connect to it.




> Thanks for any suggestions.
>
> --
> Elliot Kendall
> IAM Support Engineer - Single Sign On
> Information Technology Services
> University of California, San Francisco
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
> For additional commands, e-mail: users-help@tomcat.apache.org
>
>