require "active_support/core_ext/hash/except" require "active_support/core_ext/hash/slice" module ActionController # This module provides a method which will redirect the browser to use HTTPS # protocol. This will ensure that user's sensitive information will be # transferred safely over the internet. You _should_ always force the 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 # the user from getting their session hijacked when accessing the site over # 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 # * host - Redirect to a different host name # * subdomain - Redirect to a different subdomain # * domain - Redirect to a different domain # * port - Redirect to a non-standard port # * path - Redirect to a different path # # ==== Redirect Options # You can pass any of the following options to affect the redirect status and response # * status - Redirect with a custom status (default is 301 Moved Permanently) # * flash - Set a flash message when redirecting # * alert - Set an alert message when redirecting # * notice - Set a notice message when redirecting # # ==== Action Options # You can pass any of the following options to affect the before_action callback # * only - The callback should be run only for this action # * except - The callback should be run for all actions except this action # * if - A symbol naming an instance method or a proc; the # callback will be called only when it returns a true value. # * unless - 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 # * host_or_options - Either a host name or any of the url & # redirect options available to the force_ssl 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) && request.respond_to?(:flash) redirect_to secure_url, options.slice(*REDIRECT_OPTIONS) end end end end