12

I have a Grails app using Spring Security Core running on an AWS machine behind a load balancer.

The load balancer decrypts the ssl connections and forwards to port 8080 of our instance adding appropriate X-Forwarded-Proto headers.

I would like any direct access to a secured page to redirect to the login page using https.

For example a request https://myapp.com/private/page should redirect to https://myapp.com/login/auth

I put this in my config.groovy:

grails.plugin.springsecurity.secureChannel.definition = [
    '/login/**':        'REQUIRES_SECURE_CHANNEL'
]

but this causes a redirect loop (HTTP code 302) to the http login page (http://myapp.com/login/auth)

Then I tried just with:

grails.plugin.springsecurity.secureChannel.useHeaderCheckChannelSecurity = true
grails.plugin.springsecurity.auth.forceHttps = true

but this causes a redirect (HTTP code 302) to the http login page (http://myapp.com/login/auth)

  1. The issue is presentig just with the production setup (war deployed to Tomcat behind the load balancer).
  2. If I test the same config.groovy on my loacal dev machine the redirect to https://myapp.com/login/auth happens just fine.
  3. I tried to specify a different httpsPort for spring security, again it works on my local dev machine but it is completely ignored in the deployed app that keeps redirecting to http

No luck lurking at similar posts, any idea?

Paull
  • 1,020
  • 1
  • 12
  • 21

3 Answers3

8

I also am hosting my Grails app with Spring Security Core 2.0-RC4 on AWS with https and a load balancer, and thanks to spock99 (above) and Ravi L of AWS, I got it working.

I did the following in config.groovy:

    // Required because user auth uses absolute redirects
    grails.serverURL = "http://example.com"

    grails.plugin.springsecurity.secureChannel.definition = [
        '/assets/**':     'ANY_CHANNEL',// make js, css, images available to logged out pages
        '/**':            'REQUIRES_SECURE_CHANNEL',
    ]

    // overriding values in DefaultSecurityConfig.groovy from the SpringSecurityCore 2.0-RC4 
    grails.plugin.springsecurity.secureChannel.useHeaderCheckChannelSecurity = true
    grails.plugin.springsecurity.portMapper.httpPort = 80
    grails.plugin.springsecurity.portMapper.httpsPort = 443

NOTE: The following were not needed in Spring Security Core 2.0-RC4 - they are already in DefaultSecurityConfig.groovy

    secureHeaderName = 'X-Forwarded-Proto'
    secureHeaderValue = 'http'
    insecureHeaderName = 'X-Forwarded-Proto'
    insecureHeaderValue = 'https'

I was getting false 'Unhealthy' readings because hitting '/' returns a 302 redirect to /login/auth, so I added a health() method to HomeController (which I mapped to '/health') for AWS to hit:

    class HomeController {
        @Secured('IS_AUTHENTICATED_FULLY')
        def index() { }

        @Secured('permitAll')
        def health() { render '' }
    }

Key for me was that session cookies were not being handled properly with multiple instance running on the Load Balancer (I did not discover this until setting the minimum instance to 2), so in order for users to be able to log in and stay logged in, I did the following on AWS:

1.  At Services / Elastic Beanstalk / Configuration / Load Balancing 
    a. set Application health check URL: /health
    b. left Session Stickiness: unchecked
2. At Services / EC2 / Load Balancers / Description / Port Configuration:
    For both port 80 (HTTP)  and 443 (HTTPS)
        1. Edit and select 'Enable Application Generated Cookie Stickiness'
        2. Cookie Name: JSESSIONID
Community
  • 1
  • 1
TriumphST
  • 1,194
  • 1
  • 10
  • 17
4

I just went through the same scenario. Got stuck on the https, then the redirects, and now all is well. Use these Config.groovy settings:

grails.plugin.springsecurity.secureChannel.useHeaderCheckChannelSecurity = true
grails.plugin.springsecurity.portMapper.httpPort = 80
grails.plugin.springsecurity.portMapper.httpsPort = 443
grails.plugin.springsecurity.secureChannel.secureHeaderName = 'X-Forwarded-Proto'
grails.plugin.springsecurity.secureChannel.secureHeaderValue = 'http'
grails.plugin.springsecurity.secureChannel.insecureHeaderName = 'X-Forwarded-Proto'
grails.plugin.springsecurity.secureChannel.insecureHeaderValue = 'https'

Note for those not using springsecurity 2.0, it is 'plugins' and not 'plugin' without the 's'.

My beanstalk load balancer settings look like this (I have an SSL cert installed, I didn't show it):

enter image description here

In the EC2 load balancer settings make sure your listeners are set right:

enter image description here

And finally in the EC2 security groups make sure the EB accepts requests on ports 80 and 443 from the ELB:

enter image description here

Note that nowhere in my setup of anything do I ever reference ports 8080 or 8443, even though that is what I use on my localhost for testing. Somebody reading this may think about trying to use those ports to fix the issues. My setup didn't require that.

spock99
  • 1,182
  • 1
  • 10
  • 32
  • Thanks a lot for your help but no luck! I reproduced the same setup, also moved internal port to 80 but it always redirects to http... Do you have anything in the grails.plugin.springsecurity.secureChannel.definition ? Any idea on how can I at least debug it? – Paull Dec 19 '13 at 14:50
  • 1
    I do not have a value set for secureChannel.definition. Do you have grails.serverURL set for your production environment? That is something else that was breaking my app, but I think that was related to setting up cloudfront. I did not debug it with logs. I would make a change in the config file and upload a new war, then step through each scenario using a browser to see what broke. Then I would make a change and try again. – spock99 Dec 19 '13 at 15:59
  • What version of spring security are you using? – spock99 Dec 19 '13 at 16:07
  • For production I have: grails.serverURL = "https://my.app.com". I am using ":spring-security-core:2.0-RC2" – Paull Dec 20 '13 at 15:42
  • My server url is http: // www.mycompany.com. I don't know if the http would make a difference. I'm using RC2 as well. You aren't using a VPC are you? I had a lot of trouble with VPCs and ended up ripping all the VPC out of AWS. It wasn't necessary for my setup, after conferring with AWS support for almost an hour. – spock99 Dec 21 '13 at 17:10
  • This worked for me, deploy with ElasticBeansTalk with load balancer. – Neoecos Apr 17 '15 at 03:05
1

I faced similar issue in similar environment where the front end was on https and behind the firewall grails server was on http. When session was timed out, ajax and angular $http used to get a redirect message to http://myclient.com/myWar/login/auth. This redirect request used to cause access denied in browser because original url was https and mixed content was disabled. I used to get SCRIPT7002: XMLHttpRequest: Network Error 0x80700013, Could not complete the operation due to error 80700013.” This error occurred only in production and not in test environment.

Fix is simple, simply add the following to the configuration file. grails.serverURL = "https://mywebsitespublicaddress.com/myWar"