<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
  <id>tag:moocode.com,2005:/blog</id>
  <link rel="alternate" type="text/html" href="https://moocode.com"/>
  <link rel="self" type="application/atom+xml" href="https://moocode.com/blog.atom"/>
  <title>Stories From The Field - The moocode blog</title>
  <updated>2011-10-28T11:42:54+01:00</updated>
  <entry>
    <id>tag:moocode.com,2005:Post/7</id>
    <published>2011-10-28T10:36:53+01:00</published>
    <updated>2011-10-28T13:05:18+01:00</updated>
    <link rel="alternate" type="text/html" href="https://moocode.com/posts/7-build-a-simple-twilio-customer-support-line-in-10-minutes"/>
    <title>Build a Simple Twilio Customer Support Line in 10 minutes</title>
    <content type="html">&lt;p&gt;Twilio recently &lt;a href="http://www.twilio.com/blog/2011/10/twilio-launches-in-europe-opens-office-london.html"&gt;launched in the UK&lt;/a&gt; supporting 0800 (freephone) and 0207 (central london) numbers so I thought I'd have a go at setting up a customer support line for my company.  This post walks you through a simple implementation.&lt;/p&gt;

&lt;h2&gt;Setting up&lt;/h2&gt;

&lt;p&gt;If you want to follow along with this example you'll need &lt;a href="https://www.twilio.com/try-twilio?moocode"&gt;a free demo Twilio account&lt;/a&gt;, &lt;a href="https://api.heroku.com/signup"&gt;free Heroku account&lt;/a&gt;, &lt;a href="http://git-scm.com/"&gt;git&lt;/a&gt; and the &lt;a href="http://www.sinatrarb.com/"&gt;sinatra&lt;/a&gt; and &lt;a href="https://github.com/heroku/heroku"&gt;heroku&lt;/a&gt; ruby gems.&lt;/p&gt;

&lt;h2&gt;Hello Moocode&lt;/h2&gt;

&lt;p&gt;To test the setup we'll create a very simple implementation and deploy it.  This implementation will just say hello and then hang up.&lt;/p&gt;

&lt;p&gt;In a &lt;code&gt;twilio&lt;/code&gt; folder I created &lt;code&gt;app.rb&lt;/code&gt; with the following:&lt;/p&gt;

&lt;pre class="brush: ruby"&gt;require 'rubygems'
require 'sinatra'

get '/hello' do
  response =&amp;lt;&amp;lt;EOF
&amp;lt;Response&gt;
  &amp;lt;Say&gt;Hello from moocode&amp;lt;/Say&gt;
&amp;lt;/Response&gt;
EOF
end
&lt;/pre&gt;


&lt;p&gt;To get this to run on Heroku we also need two other files, a &lt;code&gt;config.ru&lt;/code&gt; rack configuration file&lt;/p&gt;

&lt;pre class="brush: ruby"&gt;
require './app'
run Sinatra::Application
&lt;/pre&gt;


&lt;p&gt;and &lt;code&gt;Gemfile&lt;/code&gt; so Heroku knows it needs to load the sinatra gem.&lt;/p&gt;

&lt;pre class="brush:ruby"&gt;
source 'http://rubygems.org'
gem 'sinatra'
&lt;/pre&gt;


&lt;p&gt;If you want to test this locally I recommend using &lt;a href="http://code.macournoyer.com/thin/"&gt;thin&lt;/a&gt;.  You can start the application with &lt;code&gt;thin -R config.ru start&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We should be ready to deploy this to Heroku now, but first we will initialise a git repository and add all the files&lt;/p&gt;

&lt;pre class="brush: shell"&gt;
git init
git add .
git commit -m 'initial commit with hello twilio implementation'
&lt;/pre&gt;


&lt;p&gt;now create the application on Heroku and do our first push&lt;/p&gt;

&lt;pre class="brush:shell"&gt;
heroku create
git push heroku master
&lt;/pre&gt;


&lt;p&gt;Heroku will give you your application url in response to the create command so you can now test it out it should be something along the lines of&lt;/p&gt;

&lt;p&gt;&lt;code&gt;http://superior-scallops-2020.heroku.com/hello&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Assuming that is all working, we add that URL to the sandbox &lt;code&gt;Voice URL&lt;/code&gt; in your &lt;a href="https://www.twilio.com/user/account"&gt;Twilio account&lt;/a&gt;, make sure to set the method to &lt;code&gt;GET&lt;/code&gt; instead of &lt;code&gt;POST&lt;/code&gt;.  You can now try it out using the twilio client and you should hear your welcome message!&lt;/p&gt;

&lt;p&gt;There is a lot of good information in the request from Twilio that we can use in our system implementation like what number was called and what country and number the person is calling from.&lt;/p&gt;

&lt;h2&gt;Adding some meat&lt;/h2&gt;

&lt;p&gt;Everything is now working end-to-end so we can focus on the implementation of our support system.  The goal is to have Twilio call my support phone number during normal UK business hours and ask the user to leave a message out of hours.&lt;/p&gt;

&lt;pre class="brush: ruby"&gt;

get '/start' do
  case Time.now.utc.hour
    when 9..19 then redirect '/support'
    else redirect '/voicemail'
  end
end

get '/voicemail' do
  response =&amp;lt;&amp;lt;EOF
&amp;lt;Response&gt;
  &amp;lt;Say&gt;
    Welcome to moocode. Sorry our support team is not available.  
    Please leave a message including your phone number or email address 
    after the beep.
  &amp;lt;/Say&gt;  
  &amp;lt;Record action="/recording" /&gt;
&amp;lt;/Response&gt;
EOF
end

get '/support' do
  response =&amp;lt;&amp;lt;EOF
&amp;lt;Response&gt;
  &amp;lt;Say&gt;Welcome to moocode. Please wait while we connect you.&amp;lt;/Say&gt;
  &amp;lt;Dial&gt;+440123456789&amp;lt;/Dial&gt;
&amp;lt;/Response&gt;
EOF
end

post '/recording' do
  recording_url = params['RecordingUrl']
  # email the recording url to the support team via sendhub.net ;)
  response =&amp;lt;&amp;lt;EOF
&amp;lt;Response&gt;
  &amp;lt;Say&gt;Thank you.  We'll be in touch shortly.  Goodbye.&amp;lt;/Say&gt;
  &amp;lt;Hangup/&gt;
&amp;lt;/Response&gt;
EOF
end

&lt;/pre&gt;


&lt;p&gt;Don't forget to update the &lt;code&gt;Voice URL&lt;/code&gt; in your Twilio account to point to &lt;code&gt;/start&lt;/code&gt; and try out your new Customer Support switchboard!&lt;/p&gt;

&lt;p&gt;The main commands in use there are &lt;code&gt;Dial&lt;/code&gt; and &lt;code&gt;Record&lt;/code&gt;. You will need to update the telephone number to your own. We pass in the action to &lt;code&gt;Record&lt;/code&gt; so it will post the recording URL to our server and we can then send that on to the support team, or store it in our customer database.&lt;/p&gt;

&lt;p&gt;If you want to go live with your new system you just need to purchase a telephone number (from $1/month!) and point it at your URL.&lt;/p&gt;

&lt;h2&gt;Further ideas&lt;/h2&gt;

&lt;p&gt;This is a simple yet effective implementation but we could add a lot more logic to the example like redirecting the user to a different support team based on the country they are calling from, calling a fallback support number if the first one doesn't answer and call different people depending on the time of day if you have a support team in a different time zone.&lt;/p&gt;

&lt;p&gt;You could also improve your support process by looking up the customer by their phone number and present that information to the support team.&lt;/p&gt;

&lt;p&gt;This example just touches the surface of what is available via the Twilio API.  It's quite fun to play with so let me know below if you do anything great.&lt;/p&gt;
</content>
    <author>
      <name>Richard Taylor</name>
    </author>
  </entry>
  <entry>
    <id>tag:moocode.com,2005:Post/6</id>
    <published>2011-09-24T16:19:05+01:00</published>
    <updated>2011-09-30T12:00:16+01:00</updated>
    <link rel="alternate" type="text/html" href="https://moocode.com/posts/6-code-your-own-multi-user-private-git-server-in-5-minutes"/>
    <title>Code Your Own Multi-User Private Git Server in 5 Minutes</title>
    <content type="html">&lt;p&gt;Following on from last weeks post about &lt;a href="/posts/5-simple-two-factor-ssh-authentication"&gt;Simple Two Factor SSH Authentication&lt;/a&gt; this post shows you how to use the same SSH trick to create a multi-user private &lt;a href="http://git-scm.com/"&gt;git&lt;/a&gt; server.  I believe the principles here can also be applied to &lt;a href="http://mercurial.selenic.com/"&gt;mercurial&lt;/a&gt; or &lt;a href="http://subversion.tigris.org/"&gt;subversion&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I was recently working on a client project that we converted to git, we hired an agency to work on the front-end for the project and they had four users that needed access.  I didn't really want to create them individual accounts on the server so I started thinking how I could securely manage multiple-user access to a git repository running under a single &lt;code&gt;git&lt;/code&gt; user without giving them shell access.&lt;/p&gt;

&lt;p&gt;After a bit of research I identified two possible candidates &lt;a href="http://eagain.net/gitweb/?p=gitosis.git;a=summary"&gt;gitosis&lt;/a&gt; and &lt;a href="https://github.com/sitaramc/gitolite"&gt;gitolite&lt;/a&gt; but they seemed overkill for what I was trying to achieve.&lt;/p&gt;

&lt;h2&gt;Setting up the environment&lt;/h2&gt;

&lt;p&gt;We'll assume we have a &lt;code&gt;git&lt;/code&gt; user on the server and create a test repository in the home directory&lt;/p&gt;

&lt;pre class="brush: bash"&gt;
git init --bare testing.git
&lt;/pre&gt;


&lt;p&gt;Now we need to add my SSH key in &lt;code&gt;authorized_keys&lt;/code&gt; with &lt;code&gt;rw&lt;/code&gt; (read-write) permissions&lt;/p&gt;

&lt;pre class="brush: bash"&gt;
command="/usr/bin/gitserve richard rw",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa AAA...zzz me@example.com
&lt;/pre&gt;


&lt;p&gt;The first part of that line holds all the magic, firstly we will be invoking the script &lt;code&gt;/usr/bin/gitserve&lt;/code&gt; with two parameters, a &lt;code&gt;user identifier&lt;/code&gt; and the &lt;code&gt;permissions&lt;/code&gt; that anyone authorising with this key has.&lt;/p&gt;

&lt;p&gt;Then there are some &lt;a href="http://man.he.net/man5/authorized_keys"&gt;extra options&lt;/a&gt; to disable port-forwarding, X11 forwarding, agent-forwarding, and finally deny the user access to a shell (we'll only be executing git commands for this user).&lt;/p&gt;

&lt;h2&gt;The implementation&lt;/h2&gt;

&lt;p&gt;I've chosen to implement this in ruby but any language would do.  Put the following in &lt;code&gt;/usr/bin/gitserve&lt;/code&gt;&lt;/p&gt;

&lt;pre class="brush: ruby"&gt;
#!/usr/bin/env ruby

# user and permissions are passed from authorized_keys

user = ARGV[0]
permissions = ARGV[1]
command = ENV['SSH_ORIGINAL_COMMAND']
abort unless user and permissions and command

# check the supplied command contains a valid git action 

valid_actions = ['git-receive-pack', 'git-upload-pack']
action = command.split[0]
abort unless valid_actions.include? action

# check the permissions for this user

abort "read denied for #{user}" unless permissions =~ /r/
abort "write denied for #{user}" if action == 'git-receive-pack' and permissions !~ /w/

STDERR.write "user #{user} authorized\n"

# user made a valid request so handing over to git-shell

Kernel.exec 'git', 'shell', '-c', command
&lt;/pre&gt;


&lt;p&gt;When you execute git against a remote SSH repository it uses one of two commands &lt;code&gt;git-receive-pack&lt;/code&gt; or &lt;code&gt;git-upload-pack&lt;/code&gt; so we first verify those commands since we don't want our git users to be able to execute anything else.&lt;/p&gt;

&lt;p&gt;Next we check what permissions the user has, read-only &lt;code&gt;(r)&lt;/code&gt; or read-write &lt;code&gt;(rw)&lt;/code&gt; and grant access depending on what action they are trying to perform.&lt;/p&gt;

&lt;p&gt;Finally if the user is valid we pass execution to &lt;a href="http://linux.die.net/man/1/git-shell"&gt;git-shell&lt;/a&gt; with the original command.&lt;/p&gt;

&lt;h2&gt;Testing it out&lt;/h2&gt;

&lt;pre class="brush: bash"&gt;

$ git clone git@myserver:testing.git
Cloning into testing...
user richard authorized
warning: You appear to have cloned an empty repository.
$ cd testing
$ touch README
$ git add .
$ git commit -m 'added readme'
$ git push origin master
user richard authorized
Counting objects: 3, done.
Writing objects: 100% (3/3), 213 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
To git@myserver:testing.git
 * [new branch]      master -&gt; master

&lt;/pre&gt;


&lt;p&gt;That seems to work!  We can now easily add more users with read-only or read-write permissions by just adding a new line to the &lt;code&gt;authorized_keys&lt;/code&gt; file with the corresponding users public key.&lt;/p&gt;

&lt;h2&gt;Wrapping up&lt;/h2&gt;

&lt;p&gt;This solution is very simple and works for my scenario.  It doesn't allow you to decide per-repository who has access to what but since you know which user has authorized in the script and what repository they are trying to access (in the command) it would be trivial to add support for per-repository access.&lt;/p&gt;

&lt;p&gt;That's all for now, if you have any tips and tricks please leave them in the comments below and if you're looking for a great hosted private git solution please check out &lt;a href="https://repodrop.com/?s=b6"&gt;repodrop&lt;/a&gt;.&lt;/p&gt;
</content>
    <author>
      <name>Richard Taylor</name>
    </author>
  </entry>
  <entry>
    <id>tag:moocode.com,2005:Post/5</id>
    <published>2011-09-22T17:24:37+01:00</published>
    <updated>2011-09-27T16:29:11+01:00</updated>
    <link rel="alternate" type="text/html" href="https://moocode.com/posts/5-simple-two-factor-ssh-authentication-with-google-authenticator"/>
    <title>Simple Two-Factor SSH Authentication with Google Authenticator</title>
    <content type="html">&lt;p&gt;In a two-part post I'm going to show you some tricks you can do with SSH logins.   This post covers setting up two-factor SSH authentication with the &lt;a href="http://code.google.com/p/google-authenticator/"&gt;Google Authenticator&lt;/a&gt; app.&lt;/p&gt;

&lt;p&gt;I was recently getting some servers in shape so I can pass the Payment Card Industry standards questionnaire and one requirement was two-factor authentication access to the server.  I queried whether SSH key + passphrase was acceptable but didn't get a clear answer so I figured I'd explore setting up another authentication factor myself, plus it piqued my interest.&lt;/p&gt;

&lt;p&gt;After a bit of research I found it was possible using a &lt;a href="http://code.google.com/p/google-authenticator/source/browse/#hg%2Flibpam"&gt;PAM module&lt;/a&gt; but it doesn't work along with SSH key authentication (only password authentication) and I only use SSH key logins for my servers.&lt;/p&gt;

&lt;h2&gt;The magic&lt;/h2&gt;

&lt;p&gt;I wanted to find the simplest method of implementing this so I started looking at what we can do with SSH itself.  There is an option in the &lt;code&gt;&lt;a href="http://man.he.net/man5/authorized_keys"&gt;authorized_keys&lt;/a&gt;&lt;/code&gt; file that allows you to run a command when a user authorizes with a particular key eg.&lt;/p&gt;

&lt;pre class="brush: bash"&gt;
command="/usr/bin/my_script" ssh-dsa AAA...zzz me@example.com
&lt;/pre&gt;


&lt;p&gt;The &lt;code&gt;command="..."&lt;/code&gt; part invokes a different command upon key authentication and runs the &lt;code&gt;/usr/bin/my_script&lt;/code&gt; instead.  Now we've got a starting point to work on the Google Authenticator logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UPDATE&lt;/strong&gt; A number of comments on hacker news suggest the use of ForceCommand in &lt;a href="http://unixhelp.ed.ac.uk/CGI/man-cgi?sshd_config+5"&gt;sshd_config&lt;/a&gt; to apply this globally.&lt;/p&gt;

&lt;h2&gt;Simple implementation&lt;/h2&gt;

&lt;p&gt;I've chosen ruby to implement this simple example but in theory you could use anything you want.  This is a naive implementation but it will prove the concept.  You're going to need the &lt;a href="http://rubygems.org/gems/rotp"&gt;rotp&lt;/a&gt; library as well for this to work &lt;code&gt;gem install rotp&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We put the following in &lt;code&gt;/usr/bin/two_factor_ssh&lt;/code&gt;&lt;/p&gt;

&lt;pre class="brush: ruby"&gt;
#!/usr/bin/env ruby
require 'rubygems'
require 'rotp'

# we'll pass in a secret to this script from the authorized_keys file
abort unless secret = ARGV[0]

# prompt the user for their validation code

STDERR.write "Enter the validation code: "
until validation_code = STDIN.gets.strip
  sleep 1
end

# check the validation code is correct

abort "Invalid" unless validation_code == ROTP::TOTP.new(secret).now.to_s

# user has validated so we'll give them their shell

Kernel.exec ENV['SSH_ORIGINAL_COMMAND'] || ENV['SHELL']
&lt;/pre&gt;


&lt;p&gt;The secret is in &lt;code&gt;&lt;a href="http://ruby-doc.org/core/classes/Kernel.html#M001438"&gt;Kernel.exec&lt;/a&gt;&lt;/code&gt; which, upon successful validation, replaces the &lt;code&gt;two_factor_ssh&lt;/code&gt; script process with the original command the user was attempting or their default shell so it is a completely seamless experience from that point on.&lt;/p&gt;

&lt;h2&gt;Generating the secret&lt;/h2&gt;

&lt;p&gt;We need to generate a secret token that is shared between the Google Authenticator app and the server.&lt;/p&gt;

&lt;p&gt;Here's a little script that will spit out a new token and a link to a QR code that can be scanned into the Google Authenticator application.&lt;/p&gt;

&lt;pre class="brush: ruby"&gt;
#!/usr/bin/env ruby
require 'rubygems'
require 'rotp'

secret = ROTP::Base32.random_base32
data = "otpauth://totp/#{`hostname -s`.strip}?secret=#{secret}"
url = "https://chart.googleapis.com/chart?chs=200x200&amp;chld=M|0&amp;cht=qr&amp;chl=#{data}"

puts "Your secret key is: #{secret}"
puts url
&lt;/pre&gt;


&lt;p&gt;Running this produces:&lt;/p&gt;

&lt;pre class="brush: text"&gt;
Your secret key is: 4rr7kc47sc5a2fgt
https://chart.googleapis.com/chart?chs=200x200&amp;chld=M|0&amp;cht=qr&amp;chl=otpauth://totp/myserver?secret=4rr7kc47sc5a2fgt
&lt;/pre&gt;


&lt;p&gt;We can scan the QR code directly into Google Authenticator and then update our &lt;code&gt;authorized_keys&lt;/code&gt; file as follows:&lt;/p&gt;

&lt;pre class="brush: shell"&gt;
command="/usr/bin/two_factor_ssh 4rr7kc47sc5a2fgt" ssh-dsa AAA...zzz me@example.com
&lt;/pre&gt;


&lt;p&gt;That should do it!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UPDATE&lt;/strong&gt; &lt;a href="http://twitter.com/js4all"&gt;@js4all&lt;/a&gt; has identified a security problem with a certain version of OpenSSH which prints out the command (including parameters!) in the debug when connecting.  To work around this problem instead of using the secret above, pass through an identifier and then put the security key inside the script and perform a lookup there.&lt;/p&gt;

&lt;h2&gt;Testing it out&lt;/h2&gt;

&lt;pre class="brush: bash"&gt;

[richard@mbp ~]$ ssh moocode@myserver
Enter the validation code: wrong
Invalid
Connection to myserver closed.
[richard@mbp ~]$
[richard@mbp ~]$ ssh moocode@myserver
Enter the validation code: 410353
moocode@myserver:~$

&lt;/pre&gt;


&lt;p&gt;Great, that seems to work as expected.&lt;/p&gt;

&lt;h2&gt;Wrapping up&lt;/h2&gt;

&lt;p&gt;I've got a slightly &lt;a href="http://bit.ly/qWP2Ns"&gt;more involved example&lt;/a&gt; that adds in support for 'remember me' by IP address for a fixed period of time so you don't have to reach for the phone on every single login from the same IP.&lt;/p&gt;

&lt;p&gt;The extended example also does some primitive logging but I'd like to add in a better auditing system (another PCI compliance requirement) as this would allow us to know which key is used to log into the server and whether they validated.&lt;/p&gt;

&lt;p&gt;We should also probably have a fallback mechanism (a master key or 5 one-time codes like Google does) so we don't inadvertently lock ourselves out of the server.&lt;/p&gt;

&lt;p&gt;If you have any tips or ideas please leave them in the comments below and if you liked this post &lt;a href="https://twitter.com/moocode"&gt;follow us on twitter&lt;/a&gt; so you'll get notified about next weeks follow-up post.&lt;/p&gt;

&lt;p&gt;&lt;img src="https://www.google.com/s2/u/0/favicons?domain=ycombinator.com" title="Hacker News Icon" alt="Hacker News Icon" /&gt; &lt;a href="http://news.ycombinator.com/item?id=3029680"&gt;Comments on Hacker News&lt;/a&gt;&lt;/p&gt;
</content>
    <author>
      <name>Richard Taylor</name>
    </author>
  </entry>
  <entry>
    <id>tag:moocode.com,2005:Post/4</id>
    <published>2011-09-03T15:38:02+01:00</published>
    <updated>2011-09-29T15:57:18+01:00</updated>
    <link rel="alternate" type="text/html" href="https://moocode.com/posts/4-launch-repodrop-private-git-repository-hosting"/>
    <title>Launch: RepoDrop - Private Git Repository Hosting</title>
    <content type="html">&lt;p&gt;We're proud to announce &lt;a href="https://repodrop.com/"&gt;RepoDrop - Private Git Repository Hosting&lt;/a&gt; our first paid product! RepoDrop offers developers and designers everywhere a simple, secure, affordable service to host their Git repositories remotely.&lt;/p&gt;

&lt;p&gt;&lt;img src="https://d2nqqs42pvbac6.cloudfront.net/repodrop/assets/site/preview-repolist-664fb222f5f921c55bf5066c278d4f7d.png" alt="RepoDrop Screenshot" /&gt;&lt;/p&gt;

&lt;p&gt;We have tried to keep it as simple as possible while still providing enough features but if there is anything else you need please let us know in the comments below.&lt;/p&gt;

&lt;p&gt;We've also tried to keep the subscription plan as simple as possible, you pay only for storage space, can host an unlimited number of repositories and can share each repository with an unlimited number of collaborators.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://repodrop.com/"&gt;Try it free&lt;/a&gt; for 14 days with no commitment.&lt;/p&gt;
</content>
    <author>
      <name>Richard Taylor</name>
    </author>
  </entry>
  <entry>
    <id>tag:moocode.com,2005:Post/3</id>
    <published>2011-06-29T10:18:17+01:00</published>
    <updated>2011-07-15T11:33:33+01:00</updated>
    <link rel="alternate" type="text/html" href="https://moocode.com/posts/3-using-the-google-authenticator-app-with-rails"/>
    <title>Using the Google Authenticator App with Rails</title>
    <content type="html">&lt;p&gt;Following on from last weeks post on &lt;a href="https://moocode.com/posts/2-two-factor-authentication-with-rails"&gt;Two-factor Authentication with Rails&lt;/a&gt; this post adds support for the &lt;a href="http://www.google.com/support/accounts/bin/answer.py?answer=1066447"&gt;Google Authenticator&lt;/a&gt; app for Android, iPhone and Blackberry. The full source code is available on &lt;a href="https://github.com/moomerman/two_factor_auth_rails"&gt;github&lt;/a&gt; and there is now a live demo available on &lt;a href="https://two-factor-demo.heroku.com/"&gt;heroku&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Integration&lt;/h2&gt;

&lt;p&gt;The integration is very straight-forward thanks to the &lt;a href="https://github.com/mdp/rotp"&gt;ROTP library&lt;/a&gt;.  Add it to your &lt;code&gt;Gemfile&lt;/code&gt;.&lt;/p&gt;

&lt;pre class="brush: ruby"&gt;
gem 'rotp'
&lt;/pre&gt;


&lt;p&gt;The authentication mechanism works by having a per-user shared key between your web application and the app on the phone so we're going to add one to our &lt;code&gt;User&lt;/code&gt; model:&lt;/p&gt;

&lt;pre class="brush: ruby"&gt;
add_column :users, :auth_secret, :string
&lt;/pre&gt;


&lt;p&gt;And assign a random base32 string when you create a new &lt;code&gt;User&lt;/code&gt;.&lt;/p&gt;

&lt;pre class="brush: ruby"&gt;
class User &lt; ActiveRecord::Base
  ...
  before_validation :assign_auth_secret, :on =&gt; :create
  ...
  def assign_auth_secret
    self.auth_secret = ROTP::Base32.random_base32
  end
end
&lt;/pre&gt;


&lt;p&gt;Now we can present that auth_secret to the user when they sign up and they can add it to Google Authenticator.  The app can also scan a QR Code to save the user having to enter the secret manually.  This helper uses Google Charts to generate the QR Code:&lt;/p&gt;

&lt;pre class="brush: ruby"&gt;
module SessionsHelper
  def google_authenticator_qrcode(user)
    data = "otpauth://totp/two_factor_demo?secret=#{user.auth_secret}"
    data = Rack::Utils.escape(data)
    url = "https://chart.googleapis.​com/chart?chs=200x200&amp;chld=M|0&amp;cht=qr&amp;chl=#{data}"
    return image_tag(url, :alt =&gt; 'Google Authenticator QRCode')
  end
end
&lt;/pre&gt;


&lt;p&gt;All that is left to do is validate the code in our &lt;code&gt;Session&lt;/code&gt; model when the user enters it.&lt;/p&gt;

&lt;pre class="brush: ruby"&gt;

def validates?
  return true if self.validation_code == ROTP::TOTP.new(self.user.auth_secret).now.to_s
end

&lt;/pre&gt;


&lt;p&gt;That's it.  You can &lt;a href="https://two-factor-demo.heroku.com/"&gt;try it out&lt;/a&gt; on the demo site.&lt;/p&gt;
</content>
    <author>
      <name>Richard Taylor</name>
    </author>
  </entry>
  <entry>
    <id>tag:moocode.com,2005:Post/2</id>
    <published>2011-06-24T12:13:06+01:00</published>
    <updated>2011-06-29T11:18:04+01:00</updated>
    <link rel="alternate" type="text/html" href="https://moocode.com/posts/2-two-factor-authentication-with-rails"/>
    <title>Two-factor Authentication with Rails</title>
    <content type="html">&lt;p&gt;Web application security is a hot topic at the moment with the recent high-profile hacks and publication of user email/password lists so any measures that can be taken to further protect users should be considered depending on the nature of your web application.  This post walks through setting up two-factor authentication for a Rails application.&lt;/p&gt;

&lt;p&gt;Two-factor authentication helps to protect users by requiring two pieces of information to log in; one that the user knows (their password usually) and another that is random, unique, time-sensitive and only generated on demand.&lt;/p&gt;

&lt;p&gt;Typically this second code is sent to the user in real-time either by Email, SMS, Automated Voice or by the use of a 'code generating' mobile application (like &lt;a href="http://www.google.com/support/a/bin/answer.py?answer=1037451"&gt;Google Authenticator&lt;/a&gt;).  Using this mechanism ensures that someone who has access to your login and password still can't use the web application unless they also have access to your secondary authentication mechanism (email account or mobile phone in this case).&lt;/p&gt;

&lt;p&gt;This implementation uses Email for simplicity but adding other delivery mechanisms is very easy to do.  Rather than requiring the user to perform two-factor authentication every time they log in we use a permanent cookie to remember the 'validation' of the client for 30 days.  The source code for the full application is &lt;a href="https://github.com/moomerman/two_factor_auth_rails"&gt;available on github&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;The implementation&lt;/h2&gt;

&lt;p&gt;First we're going to create a table to store each unique client (or device) the user logs in from and some other useful information to identify the client and track validation.&lt;/p&gt;

&lt;pre class="brush: ruby"&gt;
rails g model session
&lt;/pre&gt;


&lt;p&gt;Then complete the migration like this:&lt;/p&gt;

&lt;pre class="brush: ruby"&gt;
class CreateSessions &lt; ActiveRecord::Migration
  def change
    create_table :sessions do |t|
      t.references :user
      
      t.string   :client_id, :null =&gt; false
      t.string   :ip_address, :null =&gt; false
      t.string   :user_agent
      t.integer  :login_count, :null =&gt; false, :default =&gt; 0
      
      t.string   :unique_key
      t.datetime :unique_key_generated_at
      
      t.integer  :confirmation_failure_count, :null =&gt; false, :default =&gt; 0
      t.datetime :client_confirmed_at
      t.datetime :authenticated_at
      t.datetime :finished_at
      
      t.timestamps
    end
    add_index :sessions, [:user_id, :client_id], :unique =&gt; true
  end
end
&lt;/pre&gt;


&lt;p&gt;Our &lt;code&gt;ApplicationController&lt;/code&gt; adds some filters to control access to your resources, we're using a simple &lt;code&gt;User&lt;/code&gt; authentication model here but this should fit in nicely with any user authentication you're using:&lt;/p&gt;

&lt;pre class="brush: ruby"&gt;

class ApplicationController &lt; ActionController::Base
  protect_from_forgery
  helper_method :current_user, :current_session
  before_filter :user_required, :session_required, :confirmed_session_required
  
  private
    def current_user
      @current_user ||= User.find_by_id(session[:user_id]) if session[:user_id]
      session[:user_id] = nil unless @current_user
      @current_user
    end
    
    def current_session
      @current_session ||= Session.find_by_id(session[:user_session_id])
      session[:user_session_id] = nil unless @current_session
      @current_session
    end
    
    def user_required
      redirect_to :new_session unless current_user
    end
    
    def session_required
      redirect_to :track_sessions unless current_session
    end
    
    def confirmed_session_required
      redirect_to confirm_session_url(current_session), 
        :alert =&gt; "This device is not recognised" unless current_session.confirmed?
    end
end
&lt;/pre&gt;


&lt;p&gt;The authentication flow is forced via the &lt;code&gt;SessionsController#track method&lt;/code&gt; which is the meat of the implementation:&lt;/p&gt;

&lt;pre class="brush: ruby"&gt;
def track
  Session.perform_housekeeping
    
  # assign a new id for this client if it isn't recognised
  client_id = cookies.signed[:_client_id] ||= UUIDTools::UUID.timestamp_create.to_s
  @session = Session.find_or_initialize_by_user_id_and_client_id(current_user.id, client_id)
    
  # check if we have already authenticated this session
  redirect_to params[:next] || :root and return if @session == current_session
    
  @session.update_attributes(
    :ip_address =&gt; request.remote_ip,
    :user_agent =&gt; request.user_agent,
    :client_id =&gt;  client_id,
    :login_count =&gt; @session.login_count + 1,
    :authenticated_at =&gt; Time.now.utc,
    :finished_at =&gt; nil
  )
    
  # sign up session is trusted
  @session.confirm! if session[:first_visit]
    
  session[:user_session_id] = @session.id
    
  # remember this client
  cookies.permanent.signed[:_client_id] = {
    :value =&gt; @session.client_id, 
    :secure =&gt; Rails.env.production? ? true : false,
    :httponly =&gt; true
  }
    
  @session.send_confirmation_code unless @session.confirmed?
    
  flash.keep # pass on any flash messages
  redirect_to params[:next] || :root
end
&lt;/pre&gt;


&lt;p&gt;Unless the session is valid,  the unique token is sent via email and the user is forced to a page where they can enter the code.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;SessionController#validate&lt;/code&gt; method also tracks the number of failed attempts to enter the validation code to prevent brute-force attacks and if the user exceeds 3 attempts a new code is generated and sent.  We could potentially implement a delay here as well if required.&lt;/p&gt;

&lt;pre class="brush: ruby"&gt;
def validate
  @session.validation_code = params[:session][:validation_code]
  if @session == current_session and @session.validates?
    @session.confirm!
    redirect_to :root, :notice =&gt; 'This device is now validated'
  else
    @session.increment! :confirmation_failure_count
    if @session.too_many_failures?
      @session.send_confirmation_code
      flash[:alert] = "Too many validation failures. We've sent you another code."
    end
    redirect_to :action =&gt; :confirm
  end
end
&lt;/pre&gt;


&lt;p&gt;Finally the &lt;code&gt;Session&lt;/code&gt; model contains all the business logic for managing the session, an abbreviated version is below:&lt;/p&gt;

&lt;pre class="brush: ruby"&gt;


class Session &amp;lt; ActiveRecord::Base
  attr_accessor :email, :password, :validation_code
  
  validates_uniqueness_of :client_id, :scope =&gt; :user_id
  belongs_to :user
  default_scope :order =&gt; 'authenticated_at DESC'
  
  scope :confirmed, where('client_confirmed_at IS NOT NULL')
  scope :expired, lambda { confirmed.where("client_confirmed_at &amp;lt; ?", Time.zone.now - 30.days) }  
   
  def validates?
    return false if self.unique_key_generated_at &amp;lt; (Time.now.utc - 10.minutes)
    return false unless self.validation_code == self.unique_key
    return true
  end
  
  def send_confirmation_code
    assign_unique_key!
    self.update_attribute :confirmation_failure_count, 0
    # Could also easily do SMS or Automated Voice call here
    Mailer.session_confirmation(self).deliver
  end
  
  def self.perform_housekeeping
    # invalidate any expired sessions (30 days old)
    self.expired.update_all :client_confirmed_at =&gt; nil
  end
  
  private
    def assign_unique_key!
      assign_unique_key
      self.save!
    end
    
    # Assigns a time-sensitive random validation key
    def assign_unique_key
      # generate zero padded random 5 digits
      self.unique_key = ActiveSupport::SecureRandom.random_number(10 **5).to_s.rjust(5,'0')
      self.unique_key_generated_at = Time.now.utc
    end
end

&lt;/pre&gt;


&lt;h2&gt;Wrapping up&lt;/h2&gt;

&lt;p&gt;This implementation is relatively straight-forward and not too intrusive for the end-user.  An added bonus is that the user can review and invalidate any unused sessions.&lt;/p&gt;

&lt;p&gt;I thought about trying to package this up into a gem but I find that with this kind of thing a one-size-fits-all approach usually doesn't work.  I hope it helps anyone else looking to do two-factor authentication and welcome any feedback on this implementation.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://moocode.com/posts/3-using-the-google-authenticator-app-with-rails"&gt;next post&lt;/a&gt; continues with this theme and adds support for Google Authenticator.&lt;/p&gt;
</content>
    <author>
      <name>Richard Taylor</name>
    </author>
  </entry>
  <entry>
    <id>tag:moocode.com,2005:Post/1</id>
    <published>2011-05-26T13:32:03+01:00</published>
    <updated>2011-08-31T14:42:16+01:00</updated>
    <link rel="alternate" type="text/html" href="https://moocode.com/posts/1-deploying-a-rails-3-1-application-to-production"/>
    <title>Deploying a Rails 3.1 application to production</title>
    <content type="html">&lt;p&gt;There is a big change to the handling of assets in Rails 3.1 compared to previous versions called &lt;a href="http://www.farbeyondprogramming.com/2011/05/64-rails-david-heinemeier-hansson-explaining-the-asset-pipeline"&gt;the asset pipeline&lt;/a&gt; and this can have an effect on your production deployments, more so than any previous Rails update I can remember.  Here is a list of the gotchas I came across and how to fix them.&lt;/p&gt;

&lt;p&gt;My deployment tools consist of &lt;a href="https://github.com/capistrano/capistrano/wiki"&gt;capistrano&lt;/a&gt;, &lt;a href="http://nginx.net"&gt;nginx&lt;/a&gt; and &lt;a href="http://unicorn.bogomips.org/"&gt;unicorn&lt;/a&gt; so the solutions listed here may be specific to those but you'll get the general idea if you are using something else.  Information is correct as of the Rails 3.1.0.rc1 release, I'll update it if further releases change any of this (updates are now inline).&lt;/p&gt;

&lt;h3&gt;Javscript Runtime&lt;/h3&gt;

&lt;p&gt;The thing that has surprised me most is the requirement to have a javascript runtime present on the production server.  To me this isn't a small thing, it's a rather large new dependency that I have to manage.&lt;/p&gt;

&lt;p&gt;Update: Further release candidates have made the javascript runtime optional in production if you precompile assets before you deploy. If you want to precompile as part of your deployment process (like I do) then you will still need to follow these instructions.&lt;/p&gt;

&lt;p&gt;If you deploy your application without a &lt;a href="https://github.com/sstephenson/execjs"&gt;suitable runtime&lt;/a&gt; you are likely to see the following error message:&lt;/p&gt;

&lt;pre class="brush: plain"&gt;
Could not find a JavaScript runtime. 
See https://github.com/sstephenson/execjs for a list of available 
runtimes.
&lt;/pre&gt;


&lt;p&gt;To fix this, I chose one of the available ruby-wrapped runtimes, &lt;a href="https://github.com/cowboyd/therubyracer"&gt;therubyracer&lt;/a&gt;, and configured it in my &lt;code&gt;Gemfile&lt;/code&gt;:&lt;/p&gt;

&lt;pre class="brush: ruby"&gt;
group :production do
  ...
  gem 'therubyracer'
end
&lt;/pre&gt;


&lt;p&gt;Be prepared to sit back and wait while it compiles and installs when you do your first deployment.&lt;/p&gt;

&lt;p&gt;Update: If you're deploying to Heroku please read &lt;a href="http://devcenter.heroku.com/articles/rails31_heroku_cedar"&gt;this article&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Asset Compilation&lt;/h3&gt;

&lt;p&gt;In production you generally won't want to use the asset pipeline directly, instead you will run the &lt;code&gt;assets:precompile&lt;/code&gt; rake task so your webserver can serve the generated assets. My &lt;a href="https://github.com/capistrano/capistrano/wiki"&gt;capistrano&lt;/a&gt; configuration in &lt;code&gt;/config/deploy.rb&lt;/code&gt; is:&lt;/p&gt;

&lt;pre class="brush: ruby"&gt;
after 'deploy:update_code' do
  ...
  run "cd #{release_path}; RAILS_ENV=production rake assets:precompile"
end
&lt;/pre&gt;


&lt;p&gt;This will copy all the assets to &lt;code&gt;/public/assets/&lt;/code&gt; and encode the MD5 hash of the contents into the path name.  This is a great improvement as far as caching is concerned but has some side-effects (see below).&lt;/p&gt;

&lt;p&gt;One interesting thing I haven't discovered yet is what happens if you have two assets with the same name in different folders? I guess one of them will win and the other will be ignored, or it will throw an error.&lt;/p&gt;

&lt;h3&gt;CSS Assets&lt;/h3&gt;

&lt;p&gt;A frustration I had with the new asset pipeline code and the production environment is inconsistent behaviour.  One thing I liked about the asset pipeline in development is that it will 'find' the assets for you. In your CSS you can specify something like:&lt;/p&gt;

&lt;pre class="brush: css"&gt;
body { 
  background: #00ff00 url('rails.png') no-repeat fixed center;
}
&lt;/pre&gt;


&lt;p&gt;As long as your &lt;code&gt;rails.png&lt;/code&gt; asset exists somewhere in the &lt;code&gt;/app/assets/&lt;/code&gt; folder it will be served.&lt;/p&gt;

&lt;p&gt;However, when you run the &lt;code&gt;assets:precompile&lt;/code&gt; rake task as described above the asset you were referencing now becomes:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/public/assets/rails-9c0a079bdd7701d7e729bd956823d153.png&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;but the compiled CSS isn't changed accordingly to point to this generated asset.  I thought this was a bug but apparently it is expected behaviour.  You can see the comments on &lt;a href="https://github.com/rails/rails/issues/1209"&gt;this rails ticket&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In short, you should either not use the asset pipeline (ie. reference your images directly using &lt;code&gt;/images/rails.png&lt;/code&gt; as before) or use erb to generate your asset paths by appending &lt;code&gt;.erb&lt;/code&gt; to the CSS filename and using the &lt;code&gt;asset_path&lt;/code&gt; helper as follows:&lt;/p&gt;

&lt;pre class="brush: css"&gt;
body { 
  background: #00ff00 url(&lt;%= asset_path 'rails.png' %&gt;) no-repeat fixed center;
}
&lt;/pre&gt;


&lt;h3&gt;Asset Caching&lt;/h3&gt;

&lt;p&gt;If you've got this far and all your assets are compiled and are being referenced correctly you'll want to update your web server configuration to take advantage of this new cachability.  My &lt;a href="http://nginx.net"&gt;nginx&lt;/a&gt; configuration was updated with:&lt;/p&gt;

&lt;pre class="brush: plain"&gt;

location ~* ^/assets {
  expires max;
  add_header Cache-Control public;
  break;
}

&lt;/pre&gt;


&lt;h3&gt;Other Bits &amp;amp; Pieces&lt;/h3&gt;

&lt;p&gt;At the time of writing I wasn't able to deploy with the latest version of &lt;code&gt;rake&lt;/code&gt;.  I was getting &lt;code&gt;undefined method `task'&lt;/code&gt; errors in production so ended up hard coding &lt;code&gt;gem 'rake', '0.8.7'&lt;/code&gt; in my &lt;code&gt;Gemfile&lt;/code&gt;.  I expect this will get fixed before the final release.&lt;/p&gt;

&lt;p&gt;Update: The rake issue above is now fixed in the latest versions of Rake and Rails.&lt;/p&gt;

&lt;p&gt;I'm also having some trouble with the include declaration of javascript assets.  I ended up just including all of them and I believe some of them may be getting included more than once, but I'm assuming it is my fault.&lt;/p&gt;

&lt;p&gt;That's all for now, I hope you find this information useful when deploying your Rails 3.1 applications.  Please feel free to leave your war stories in the comments below.&lt;/p&gt;

&lt;p&gt;&lt;img src="https://www.google.com/s2/u/0/favicons?domain=ycombinator.com" title="Hacker News Icon" alt="Hacker News Icon" /&gt; &lt;a href="http://news.ycombinator.com/item?id=2590571"&gt;Comments on Hacker News&lt;/a&gt;&lt;br/&gt;
&lt;img src="https://www.google.com/s2/u/0/favicons?domain=reddit.com" title="Reddit Icon" alt="Reddit Icon" /&gt; &lt;a href="http://www.reddit.com/r/rails/comments/hl9t1/deploying_a_rails_31_application_to_production/"&gt;Comments on Reddit&lt;/a&gt;&lt;/p&gt;
</content>
    <author>
      <name>Richard Taylor</name>
    </author>
  </entry>
</feed>
