Question

We have a Grails web application, running in tomcat7 behind Apache2. Everything works fine by using ProxyPass with the ajp protocol:

ProxyPass         / ajp://localhost:9013/
ProxyPassreverse  / ajp://localhost:9013/

where 9013 is our AJP port in tomcat's server.xml.

Now, our problem is this however. Our Grails application runs both HTTP and HTTPS. When going to a certain area in the application, Spring Security (Grails Spring Security Core plugin) redirects you from the address using HTTP to HTTPS, for example when hitting:

http://www.example.com/secure/path

Spring Security will redirect you to:

https://www.example.com/secure/path

But now, when it redirects there, the server hangs and finally Firefox gives the "Firefox has detected that the server is redirecting the request for this address in a way that will never complete." error.

Am I correct in assuming that some redirecting with the AJP proxy is going bad? Can anyone provide some more information regarding how this setup will work?


On looking further, we have found the following:

When hitting the application in tomcat directly (via IP and ports) everything works 100%. But as soon as we go through Apache, the Spring Security redirect does not work. you keep getting the following in the Apache logs:

staging.server.com:80 41.133.194.248 - - [05/Apr/2012:14:03:41 +0200] "GET /user/signup HTTP/1.1" 302 223 "http://staging.server.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:11.0) Gecko/20100101 Firefox/11.0"
staging.server.com:80 41.133.194.248 - - [05/Apr/2012:14:03:42 +0200] "GET /user/signup HTTP/1.1" 302 223 "http://staging.server.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:11.0) Gecko/20100101 Firefox/11.0"
staging.server.com:80 41.133.194.248 - - [05/Apr/2012:14:03:42 +0200] "GET /user/signup HTTP/1.1" 302 223 "http://staging.server.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:11.0) Gecko/20100101 Firefox/11.0"
staging.server.com:80 41.133.194.248 - - [05/Apr/2012:14:03:42 +0200] "GET /user/signup HTTP/1.1" 302 223 "http://staging.server.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:11.0) Gecko/20100101 Firefox/11.0"

...

rather than redirecting to https it seems apache magically makes it try http again. Thanks

Was it helpful?

Solution

Disclaimer, I am no expert on Grails.

But from what you have described, the configuration could be as follows:

SSL is offloaded to apache httpd. Hence only the ajp connector needs to be configured in Tomcat, or perhaps with an additional http connector for testing purpose only. Configuring enable SSL for apache httpd by following http://httpd.apache.org/docs/2.0/ssl/ssl_howto.html and

<VirtualHost _default_:80>

    RedirectPermanent /secure/path https://www.example.com/secure/path
    ProxyPass         / ajp://localhost:8009/
    ProxyPassreverse  / ajp://localhost:8009/
</VirtualHost>

<VirtualHost _default_:443>

    # SSL config
    ...
    ProxyPass         / ajp://localhost:8009/
    ProxyPassreverse  / ajp://localhost:8009/
</VirtualHost>

should work.

Another benefit is that you may see performance improvement when SSL is offloaded to apache httpd.

In addition, why not force SSL for everything:

<VirtualHost _default_:80>
RedirectPermanent / https://www.example.com/
</VirtualHost>

<VirtualHost _default_:443>

# SSL config
    ...

ProxyPass         / ajp://localhost:8009/
ProxyPassreverse  / ajp://localhost:8009/
</VirtualHost>

As to why you have infinite loop, it might be related to Spring Security's sendRedirect. If you can post your full apache VirtualHost and tomcat ajp connector configuration, it may give us more clue.

OTHER TIPS

While i cant tell you YET how to resolve it i can tell you WHAT the problem is.

Its essentially with the rewrite entry point.

So part of what you are supposed to do in these situations is set :

grails.plugins.springsecurity.secureChannel.useHeaderCheckChannelSecurity = true

This will then look up if we are truly on http/https via setting a header the default is :

RequestHeader set X-Forwarded-Proto "http"

Now i have this working fine in nginx. With apache on the front the problem is that the rewrite rules ARENT picking up the apache server. They merely pick up the self. So while its going it basically hit an infinite redirection cause all it knows is the 9013 server you are on.

Right now i think i am going just write my own custom HttpsEntry but i imagine there are some apache settings to make this work right.

Grails/Spring-Security has the properties:

grails {
   // redirect ports
   plugins {
      springsecurity {
         portMapper {
            httpPort = 80
            httpsPort = 443
         }
      }
   }
}

That you can use for that with the afforementioned httpd-config (Ports 80/443 with SSL terminated at Apache) from hongo. You might also want to set the server.url property appropriately.

Not sure how spring-security-core decides which port to use when switching to HTTPS, but the default Tomcat config has redirectPort="8443" for the AJP connector, maybe you need to change to 443 so that the redirect will hit Apache's HTTPS port.

Btw ... here is your answer.

So do the port mapper settings and use the channel security like i said before.

That channel security is needed to know when to forward to http/https

But inside the redirect you need to preserve the proxy settings so request.getServerPort() can find them. You can add this to your Apache httpd.conf:

ProxyPreserveHost On

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top