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
I know this post is a year old, but I recently had similar issues and hope that someone might find this useful.
I see you are using a load balancer. You have to do the following:
Step 1
Make sure that port 443 is open on your EC2 instance and not being blocked by a firewall. You can run
sudo netstat -tlnp
on linux to check which ports are open. The output should look something like this:
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 937/sshd
tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN 1060/mysqld
tcp6 0 0 :::22 :::* LISTEN 937/sshd
tcp6 0 0 :::443 :::* LISTEN 2798/apache2
tcp6 0 0 :::80 :::* LISTEN 2798/apache2
Step 2
Make sure your security groups are setup as follows:
EC2 (INBOUND)
- HTTP TCP 80 LOAD BALANCER
- HTTPS TCP 443 LOAD BALANCER
Load Balancer (Outbound)
- HTTP TCP 80 EC2 Instance
- HTTPS TCP 443 EC2 Instance
Step 3
Make sure your EC2 instance is listening on port 443 (/etc/apache2/ports.conf) :
Listen 80
Listen 443
If you are using a virtual host, make sure it looks like this:
<VirtualHost *:80>
DocumentRoot /var/www/html/mysite.com
ServerName mysite.com
ServerAlias www.mysite.com
<Directory /var/www/html/mysite.com>
AllowOverride All
RewriteEngine On
Require all granted
Options -Indexes +FollowSymLinks
</Directory>
</VirtualHost>
<VirtualHost *:443>
DocumentRoot /var/www/html/mysite.com
ServerName mysite.com
ServerAlias www.mysite.com
SSLEngine on
SSLCertificateFile /usr/local/ssl/public.crt
SSLCertificateKeyFile /usr/local/ssl/private/private.key
SSLCACertificateFile /usr/local/ssl/intermediate.crt
</VirtualHost>
Step 4
Upload your certificate files in .pem format using the following commands:
aws iam upload-server-certificate --server-certificate-name my-server-cert
--certificate-body file://my-certificate.pem --private-key file://my-private-key.pem
--certificate-chain file://my-certificate-chain.pem
Step 4
Create a listener on the Load Balancer which has the EC2 instance attached to it. The listener is for HTTPS and port 443. The listener will ask for a certificate and it will have the one you added from the aws cli already listed. If it is not listed, log out of the AWS console and log back in.
After, this, traffic via HTTPS will start flowing to your EC2 instance.
I had similar issues, and posted my question and answer here: HTTPS only works on localhost
Best Answer
Your spring configuration should be agnostic to the used protocol. If you use something like "requires-channel", you'll run into problems sooner or later, especially if you want to deploy the same application to a development environment without https.
Instead, consider to configure your tomcat properly. You can do this with RemoteIpValve. Depending on which headers the loadbalancer sends, your server.xml configuration needs to contain something like this:
Spring will determine the absolute redirect address based on the ServletRequest, so change the httpsServerPort if you are using something else than 443: