diff options
Diffstat (limited to 'actionpack/lib/action_controller/metal/force_ssl.rb')
-rw-r--r-- | actionpack/lib/action_controller/metal/force_ssl.rb | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/actionpack/lib/action_controller/metal/force_ssl.rb b/actionpack/lib/action_controller/metal/force_ssl.rb new file mode 100644 index 0000000000..d920668184 --- /dev/null +++ b/actionpack/lib/action_controller/metal/force_ssl.rb @@ -0,0 +1,97 @@ +require 'active_support/core_ext/hash/except' +require 'active_support/core_ext/hash/slice' + +module ActionController + # This module provides a method which will redirect browser to use HTTPS + # protocol. This will ensure that user's sensitive information will be + # transferred safely over the internet. You _should_ always force browser + # to use HTTPS when you're transferring sensitive information such as + # user authentication, account information, or credit card information. + # + # Note that if you are really concerned about your application security, + # you might consider using +config.force_ssl+ in your config file instead. + # That will ensure all the data transferred via HTTPS protocol and prevent + # user from getting session hijacked when accessing the site under unsecured + # HTTP protocol. + module ForceSSL + extend ActiveSupport::Concern + include AbstractController::Callbacks + + ACTION_OPTIONS = [:only, :except, :if, :unless] + URL_OPTIONS = [:protocol, :host, :domain, :subdomain, :port, :path] + REDIRECT_OPTIONS = [:status, :flash, :alert, :notice] + + module ClassMethods + # Force the request to this particular controller or specified actions to be + # under HTTPS protocol. + # + # If you need to disable this for any reason (e.g. development) then you can use + # an +:if+ or +:unless+ condition. + # + # class AccountsController < ApplicationController + # force_ssl if: :ssl_configured? + # + # def ssl_configured? + # !Rails.env.development? + # end + # end + # + # ==== URL Options + # You can pass any of the following options to affect the redirect url + # * <tt>host</tt> - Redirect to a different host name + # * <tt>subdomain</tt> - Redirect to a different subdomain + # * <tt>domain</tt> - Redirect to a different domain + # * <tt>port</tt> - Redirect to a non-standard port + # * <tt>path</tt> - Redirect to a different path + # + # ==== Redirect Options + # You can pass any of the following options to affect the redirect status and response + # * <tt>status</tt> - Redirect with a custom status (default is 301 Moved Permanently) + # * <tt>flash</tt> - Set a flash message when redirecting + # * <tt>alert</tt> - Set an alert message when redirecting + # * <tt>notice</tt> - Set a notice message when redirecting + # + # ==== Action Options + # You can pass any of the following options to affect the before_action callback + # * <tt>only</tt> - The callback should be run only for this action + # * <tt>except</tt> - The callback should be run for all actions except this action + # * <tt>if</tt> - A symbol naming an instance method or a proc; the callback + # will be called only when it returns a true value. + # * <tt>unless</tt> - A symbol naming an instance method or a proc; the callback + # will be called only when it returns a false value. + def force_ssl(options = {}) + action_options = options.slice(*ACTION_OPTIONS) + redirect_options = options.except(*ACTION_OPTIONS) + before_action(action_options) do + force_ssl_redirect(redirect_options) + end + end + end + + # Redirect the existing request to use the HTTPS protocol. + # + # ==== Parameters + # * <tt>host_or_options</tt> - Either a host name or any of the url & redirect options + # available to the <tt>force_ssl</tt> method. + def force_ssl_redirect(host_or_options = nil) + unless request.ssl? + options = { + :protocol => 'https://', + :host => request.host, + :path => request.fullpath, + :status => :moved_permanently + } + + if host_or_options.is_a?(Hash) + options.merge!(host_or_options) + elsif host_or_options + options[:host] = host_or_options + end + + secure_url = ActionDispatch::Http::URL.url_for(options.slice(*URL_OPTIONS)) + flash.keep if respond_to?(:flash) + redirect_to secure_url, options.slice(*REDIRECT_OPTIONS) + end + end + end +end |