yellowreign
yellowreign

Reputation: 3638

Opposite of Force_SSL in Rails?

I'm running a Rails 3.1.4 app that needs to have some pages use force_ssl, but others that I don't want to have SSL. Is there an opposite to force_ssl, like force_http? The issue is that I have some pages that don't need to be SSL, and they contain elements that I can't pull over using https (so the user gets the insecure error from the browser).

What happens is that when someone goes to a force_ssl page it works fine, but then when they go to other pages where it is not force_ssl, they receive the insecure page error from the browser because the https remains. Therefore, I'd like to force the pages where I can't make the elements https avoid using use SSL (ie force it back to http).

Thank you in advance.

Upvotes: 2

Views: 2201

Answers (3)

Brendon Muir
Brendon Muir

Reputation: 4612

Assuming (hoping) you've upgraded to a supported version of Rails, this is an easy way to achieve default non-SSL unless force_ssl is declared. It's in the form of an ActiveSupport::Concern:

module ForceNoSSL
  extend ActiveSupport::Concern

  ACTION_OPTIONS = [:only, :except, :if, :unless]

  def force_no_ssl_redirect
    if request.ssl?
      options = {
        :protocol => 'http://',
        :host     => request.host,
        :path     => request.fullpath,
        :status   => :moved_permanently
      }

      redirect_to ActionDispatch::Http::URL.url_for(options)
    end
  end

  class_methods do
    def force_ssl(options = {})
      super

      action_options = options.slice(*ACTION_OPTIONS)
      skip_before_action :force_no_ssl_redirect, **action_options
    end

    def force_no_ssl
      before_action :force_no_ssl_redirect
    end
  end
end

In your ApplicationController you then:

include ForceNoSSL
force_no_ssl

How it works is that by default all actions will run the force_no_ssl_redirect callback. If it's already a non-ssl connection then nothing will be done, otherwise the request will be redirected to http://.

However, if you've declared force_ssl then the force_no_ssl_redirect callback will be skipped (only for those actions specified by the ACTION_OPTIONS).

You could extend this to allow force_no_ssl to accept URL options etc... like the force_ssl action does, but for my use case this wasn't necessary.

P.S. A lot of this code comes from ActionController::ForceSSL so check that out for more insight.

Upvotes: 0

Hunt Burdick
Hunt Burdick

Reputation: 517

Got this to work without a loop. Unless it happens in browsers I am not aware of.

before_filter do
  unless params[:controller] == 'whatever_controller_name_you_are_serving_https_to'
    if request.ssl? && Rails.env.production?
      redirect_to :protocol => 'http://', :status => :moved_permanently
    end
  end
end

Upvotes: 0

kakubei
kakubei

Reputation: 5400

Ok, I found a way that seems to work for me:

In my sessions controller I added this:

force_ssl :only => [:new, :create]

So only those 2 actions will get called over SSL. Now, after a user successfully logs in, the page will redirect to a non-SSL connection.

As far as forcing the pages to be non-SSL, try this question: Rails 3.1 Force Regular HTTP, look for Joost's answer with a before_filter.

This is what he posted:

class ApplicationController < ActionController::Base
  before_filter do
    if request.ssl && Rails.env.production?
      redirect_to :protocol => 'http://', :status => :moved_permanently
    end
  end
end

Disclaimer: The code above is not mine, I copied it from the question in the link, just putting it here for convenience. Please visit the above link to see it in its original context.

Also, regarding forcing non-SSL, I'm not sure that's a great idea. If a user requests an SSL connection and you have the certificates, why not give it to them? I agree that SSL does put more strain on the browser, but some people like surfing on SSL all the time. If you have some code that does not work over SSL than that is a valid reason to force non-SSL.

Cheers.

Upvotes: 5

Related Questions