jcollum
jcollum

Reputation: 46613

how can I fix a redirect loop when using Devise with SSL on staging server?

I've installed a self signed cert on my staging server. I'm using that to test my ssl set up. I'm using Devise 1.5 for logins and following this article on the devise wiki for ssl / http config.

The docs say:

And make sure to enable SSL on the server (Nginx, Apache, etc.). If the servers are not configured properly, Rails will not recognize the request as SSL (even if it is), and cause an infinite redirect loop.

Ok that sure looks like what is happening, but I strongly suspect I don't need to 'flip the switch' on SSL (this is an EngineYard instance). I have an SSL cert installed on the server.

I've checked the file /etc/nginx/servers/MyAppName.ssl.conf and it has these lines:

  ssl on;
  ssl_certificate /etc/nginx/ssl/MyAppName.crt;
  ssl_certificate_key /etc/nginx/ssl/MyAppName.key;
  ssl_prefer_server_ciphers on;
  ssl_protocols  SSLv3 TLSv1;

So that looks ... right? I don't want to mess with it that's for sure.

My RegistrationsController has force_ssl :only => [:new, :create, :edit, :update], so all authentication actions should be forcing ssl as far as I can tell. SessionsController has force_ssl :only => [:new, :create].

I realize that there's a lot of moving parts here, but what should I look at next?

Here's the rails logs:

Started GET "/users/sign_in" for 98.246.164.160 at 2012-02-29 20:47:39 +0000
[29 Feb 20:47 23166   INFO]   Processing by Devise::SessionsController#new as HTML
[29 Feb 20:47 23166  DEBUG] Parameters: {"action"=>"new", "controller"=>"devise/sessions"}
[29 Feb 20:47 23166   INFO] Redirected to https://ec2-xxx-xxx-106-255.us-west-2.compute.amazonaws.com/users/sign_in
[29 Feb 20:47 23166   INFO] Completed 301 Moved Permanently in 1ms
[29 Feb 20:47 23166   INFO] 

Started GET "/users/sign_in" for 98.246.164.160 at 2012-02-29 20:47:39 +0000
[29 Feb 20:47 23166   INFO]   Processing by Devise::SessionsController#new as HTML
[29 Feb 20:47 23166  DEBUG] Parameters: {"action"=>"new", "controller"=>"devise/sessions"}
[29 Feb 20:47 23166   INFO] Redirected to http://ec2-xxx-xxx-106-255.us-west-2.compute.amazonaws.com/users/sign_in
[29 Feb 20:47 23166   INFO] Completed 302 Found in 1ms
[29 Feb 20:47 23166   INFO] 

Started GET "/users/sign_in" for 98.246.164.160 at 2012-02-29 20:47:39 +0000
[29 Feb 20:47 23166   INFO]   Processing by Devise::SessionsController#new as HTML
[29 Feb 20:47 23166  DEBUG] Parameters: {"action"=>"new", "controller"=>"devise/sessions"}
[29 Feb 20:47 23166   INFO] Redirected to https://ec2-xxx-xxx-106-255.us-west-2.compute.amazonaws.com/users/sign_in
[29 Feb 20:47 23166   INFO] Completed 301 Moved Permanently in 1ms

Upvotes: 0

Views: 1647

Answers (2)

Don Law
Don Law

Reputation: 1329

For those of you who arrived here via Google, let me post another possible cause of this problem that just wasted my day, hopefully it won't waste yours.

If you are using Passenger in production, and you configure it with a VirtualHost in Apache (in conf/httpd.conf for example), but you do NOT configure it in conf.d/ssl.conf, you could get the looping problem. The symptom you will have if this misconfiguration is causing your problem will be that request.ssl? will always be false, even if you explicitly enter https in your request. To check your symptom, you can put a before_filter debugging hook in application_controller.rb with something like:

class ApplicationController < ActionController::Base
before_filter :check_ssl

  def check_ssl
    logger.info("==== ssl: #{request.ssl? }")
  end

end

If it always logs ==== ssl: false even when you send it a https://whatever request, then the VirtualHost configuration might be your problem. If you put your DocumentRoot and Directory directives for your rails app in the VirtualHost in conf.d/ssl.conf, it will fix the problem. At least it did for me.

Upvotes: 1

jcollum
jcollum

Reputation: 46613

The solution to this lied in the 'ensure_proper_protocol' method from the gist. I renamed it to make it more readable and it looks like this:

def ssl_forced_action?
    (params[:controller] == 'devise/sessions' && ['new', 'create'].include?(params[:action])) ||
        (params[:controller] == 'devise/registrations' && ['new', 'create', 'edit', 'update'].include?(params[:action])) ||
        (params[:controller] == 'users/omniauth_callbacks')
  end

Note that the original used users/sessions.

Upvotes: 0

Related Questions