Topic: SSL Solution For Michael Hartl's RoR Tutorial Chapter 9 Exercise 3

This is my attempt at solving Chapter 9 Exercise 3 of Michael Hartl's Ruby on Rails Tutorial. I'm going to make a couple trips around the mulberry bush so please be patient with me.

CONFIGURATION

I'm running Ubuntu Linux version 10.10 with Rails 3.0.9 and Ruby 1.9.2p180. For more information on this configuration see:

http://railsforum.com/viewtopic.php?pid=140122#p140122


FIXING THE ROUTES TABLE AND RSPEC TESTS

Step 1) In routes.rb

change this:
resources :sessions, :only => [:new, :create, :destroy]

to this:
resources :sessions, :only => [:new, :create, :destroy],
                              :defaults => {:protocol => "https"}

Step 2) Restart Spork and Autotest. Notice that Autotest now logs several failures telling you that there is no route to controller "sessions" with action "create".

Step 3) In sessions_controller_spec.rb

Change this:
post :create, :session => @attr

to this:
post :create, :session => @attr, :protocol => 'https'

I had to make this change in five places.
This will fix the Autotest failures.

Step 4) Restart Spork and Autotest. All tests should pass giving a green smiley face.

Now as it turns out, all of the above was an exercise in futility. We'll see why later. Just remember that I said we'd make a couple passes around the mulberry bush. At this point you should change everything back like it was.

------------------------------------------------------------------------------

CONFIGURING WEBRICK FOR SSL/TLS

Attribution: This part of the solution came from a post by Chris Rohr at:
http://www.nearinfinity.com/blogs/chris … e_ssl.html

Step 1) Make a backup copy of /script/rails.

Step 2) Replace the contents of /script/rails with:

#!/usr/bin/env ruby1.8
# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.

require 'rubygems'
require 'rails/commands/server'
require 'rack'
require 'webrick'
require 'webrick/https'

module Rails
    class Server < ::Rack::Server
        def default_options
            super.merge({
                :Port => 3001,
                :environment => (ENV['RAILS_ENV'] || "development").dup,
                :daemonize => false,
                :debugger => false,
                :pid => File.expand_path("tmp/pids/server.pid"),
                :config => File.expand_path("config.ru"),
                :SSLEnable => true,
                :SSLVerifyClient => OpenSSL::SSL::VERIFY_NONE,
                :SSLPrivateKey => OpenSSL::PKey::RSA.new(
                       File.open("/home/name4/ssl/ca.key").read), # Fix this path!
                :SSLCertificate => OpenSSL::X509::Certificate.new(
                       File.open("/home/name4/ssl/ca.crt").read), # Fix this path!
                :SSLCertName => [["CN", WEBrick::Utils::getservername]]
            })
        end
    end
end

APP_PATH = File.expand_path('../../config/application',  __FILE__)
require File.expand_path('../../config/boot',  __FILE__)
require 'rails/commands'

Step 3) Please note the two lines above that contain "# Fix this path!" You can't fix them yet, but don't forget to fix them later after you create ca.key and ca.crt.

------------------------------------------------------------------------------

MAKING YOUR VERY OWN SSL CERTIFICATE

I know, the tutorial says you don't need to make an SSL certificate just for development. I'm sure that's true, but I couldn't figure out how to make it work without one. In any case, I thought, "How hard can it be to make my own certificate, and I need to learn how to make one anyway because one day I'll need to deploy a 'real' application."

Attribution: This part of the solution came from a post by Paul Bramscher at:
http://www.tc.umn.edu/~brams006/selfsign.html

Configuration: You need to have the openssl gems installed. That is, you need the following lines in your Gemfile:

gem 'openssl-extensions', '1.1.0'
gem 'openssl-nonblock', '0.2.1'

If necessary, add these lines to the first group of gems at the top of your Gemfile, and then from a command prompt run:

$ bundle install

You can find more extensive configuration help at:

http://railsforum.com/viewtopic.php?pid=140122#p140122

and in section 1.2.4 of the tutorial.

Now here we go.

Step 1) From a shell prompt change directory to your home directory.

$ cd ~

Step 2) Make a directory to hold your SSL certificate.

$ mkdir ssl

Step 3) Navigate to the newly created directory.

$ cd ssl

Step 4) Create your CA key.

$ openssl genrsa -des3 -out ca.key 4096

Step 5) Generate your certificate.

Note: This command actually makes you a certificate authority (although not a trusted one) so you can use it to run a server and/or sign other SSL certificates.

openssl req -new -x509 -days 7300 -key ca.key -out ca.crt

You will now be asked to enter a pass phrase. Since this certificate is just for local testing enter something short and simple like "passphrase". Then press Enter. Note: The pass phrase will not display on the terminal, and the cursor will not move. Don't let this bother you. Just type the passphrase and press Enter.

Be sure to write the pass phrase on a yellow sticky note, and post it somewhere where everyone can see it. lol

If you prefer a more secure pass phrase, you can get a truly random character string from:

https://www.grc.com/passwords.htm

Step 6)

After you enter the pass phrase you will be asked a series of questions. Here are the questions and some possible answers:

Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:Texas
Locality Name (eg, city) []:Dallas
Organization Name (eg, company) [Internet Widgits Pty Ltd]:None Whatsoever
Organizational Unit Name (eg, section) []:Software Development
Common Name (eg, YOUR name) []:localhost
Email Address []:localhost@mycomputer.com

Step 7)

Your certificate is now ready to use, but there's still one tiny step to complete. Open /script/rails with your favorite text editor, and fix the paths in the two lines that contain "# Fix this path!"

-------------------------------------------------------------------------


TESTING YOUR NEW CERTIFICATE

Step 1) Shut down Webrick if it's already running.

Step 2) From a command prompt start Webrick.

$ rails server

Webrick will prompt you to:

Enter PEM pass phrase:

Type the pass phrase you wrote on the yellow sticky note then press Enter. As before the pass phrase will not display.

Step 3) Start your favorite browser and enter the following URL:

https://localhost:3001/

At this point your browser will probably complain bitterly that the certificate is not trusted. Don't let that browser push you around. Tell it to trust the certificate anyway!

Step 4)

Your Sample App should appear, and it should be fully operational. But there's still one tiny problem.

-------------------------------------------------------------------------

WHY DO ALL THE PAGES DISPLAY IN SECURE MODE?

Well, remember the mulberry bush? If I were the creator of the universe, which, alas, I am not, we would simply re-edit routes.rb replacing this:

resources :sessions, :only => [:new, :create, :destroy]

with this:

resources :sessions, :only => [:new, :create, :destroy],
                              :defaults => {:protocol => "https"}
                             
Unfortunately, this maneuver doesn't accomplish a thing (except to break the rspec tests).

You can run two instances of the Webrick server. I've run an HTTP version on port 3000 along with an HTTPS version on port 3001. Unfortunately, this doesn't fix anything either. Whichever Webrick server you launch Sample App on is the server you will keep using. Apparently at least one developer has gotten this to work. Check out Alan's comment at the end of the post at:

http://www.nearinfinity.com/blogs/chris … e_ssl.html

This situation isn't necessarily all bad. Check out the post at:

https://www.eff.org/pages/how-deploy-https-correctly

In this post the Electronic Frontier Foundation makes the point that requiring HTTPS for passwords only is a twentieth century concept. Now days most web pages have content coming from a multitude of third party sources (i.e. ad servers). This third party content can attempt to steal your session cookie, which is almost as effective as stealing your user id and password.

All security issues aside, I'd still like to know how to get Rails/Webrick to route some pages to HTTP and others to HTTPS. If anyone out there on the Rails knows how to do it, I'd love to read your comment.

Doug Witmer

Last edited by DougW4 (2011-07-25 20:47:09)

Re: SSL Solution For Michael Hartl's RoR Tutorial Chapter 9 Exercise 3

I've made it work as needed.

1. Added redirect to https for #new and #create actions in the beginning of SessionsController:
 

before_filter :require_ssl, :only => [:new, :create]
  def require_ssl
    redirect_to :protocol => "https://", :port => '3001' unless request.ssl?
  end

2. Changed redirect after successful login in sessions_controller#create
from

"redirect_to user" 

to

"redirect_to user_path(user, :protocol => "http://",:port => 3000, :only_path => false)"

3. Made a copy of script/rails to script/rails_ssl
4. Modified script/rails_ssl according to post by Chris Rohr
5. Run 1st WEBrick server with default command ">rails server"
6. Run 2nd WEBrick server for https as ">ruby script/rails_ssl server"