schneikai
2/23/2014 - 2:03 PM

Use SSL in Rails development. First: to create a local SSL certificate and start a SSL webserver checkout *shell.sh*. Second: to configure R

Use SSL in Rails development. First: to create a local SSL certificate and start a SSL webserver checkout shell.sh. Second: to configure Rails checkout rails.rb

# In development the website probably runs on a non default ssl port and you would
# have to specify that port all the time when doing *force_ssl* in development.
# So to make this more easy you can configure the SSL port in your
# *config/environment/development.rb*. For example if it runs on port 3001 use
#
#   config.ssl_port = 3001
#
# and then include this module in your ApplicationController and use
# *force_ssl_with_configured_port* instead of *force_ssl*
#
#   class ApplicationController < ActionController::Base
#     include SSLWithConfiguredPort
#     force_ssl_with_configured_port
#
#     ...
#   end
    
module SSLWithConfiguredPort
  extend ActiveSupport::Concern

  module ClassMethods
    def force_ssl_with_configured_port(options = {})
      options[:port] = Rails.application.config.ssl_port if options[:port].blank? && Rails.application.config.try(:ssl_port).present?
      force_ssl options
    end
  end
end
# Create a ssh directory in your app directory
mkdir .ssl

# Create a self signed certificate
# It'll ask you for address data and you can specify what you like but for
# *Common Name* use: "localhost.ssl"
openssl req -new -newkey rsa:2048 -sha1 -days 365 -nodes -x509 -keyout .ssl/localhost.key -out .ssl/localhost.crt

# Add localhost.ssl to /private/etc/hosts
echo "127.0.0.1 localhost.ssl" | sudo tee -a /private/etc/hosts

# That's it. Now you need to run two development webservers one for 
# HTTP and the other for HTTPS SSL request. I recommend *Thin* as the webserver
# because the Rails default webserver won't understand SSL.
# If you don't have Thin add *gem 'thin', group: :development* to your GEMFILE 
# and run
bundle install

# To start the regular webserver just use
bundle exec rails s

# To start the SSL webserver open another terminal window and run
bundle exec thin start -p 3001 --ssl --ssl-verify --ssl-key-file .ssl/localhost.key --ssl-cert-file .ssl/localhost.crt

# Now the HTTP website is available via *localhost:3000* in your browser and the
# SSL website is running under *localhost:3001*.
# To enable SSL in Rails you could now simply use *force_ssl* in your 
# ApplicationController but there is two more things to think about:
# In development our SSL webserver is running on port 3001 so we would
# actually need to use *force_ssl port: 3001* but then this wouldn't
# work for production.
# Also there is a good chance you might not always want to use SSL in development
# so it would be nice if we could just enable or disable SSL in the config.

# To make all this work first copy the file *ssl_with_configured_port.rb* to
# your *lib* directory. Second to enable SSL add *config.use_ssl = true* 
# to your environment config. You will probably add it
# to *config/environment/production.rb* and maybe to *development.rb* if you want
# to test SSL in development. Now add the port of your development SSL site to
# *config/environment/development.rb* like so *config.ssl_port = 3001*.
# Finally change your ApplicationController to look like this:

class ApplicationController < ActionController::Base
  # Include the module we just created.
  include SSLWithConfiguredPort
  # Instead of *force_ssl* we use *force_ssl_with_configured_port* that will read
  # the SSL port from the config. We added a *if* so that this will only run 
  # if the *use_ssl?* method below returns true.
  force_ssl_with_configured_port if: :use_ssl?
  
  private
    # This will return true if the config has *config.use_ssl = true*
    def use_ssl?
      Rails.application.config.try(:use_ssl).is_a?(TrueClass)
    end
end