Authentication in-rails

Post on 30-Jun-2015

723 Views

Category:

Technology

0 Downloads

Preview:

Click to see full reader

DESCRIPTION

Slides from my talk at the Eastside Incubator's Rails Chat series.With so many authentication solutions out there (Devise, OmniAuth, AuthLogic, just to name a few), this slide deck goes through various options, and guides with choosing the best authentication solution for your app. The deck covers following areas...Your Own Auth (Authentication from Scratch)Your Own Auth With Facebook ConnectOmniAuth (Facebook + Twitter)OmniAuth (Facebook + Twitter + Identity)Devise (+ Omniauthable, example includes Facebook and Twitter)All source code for this talk is available on GitHub at https://github.com/mvaidya/Authentication-In-Rails

Transcript

Social Testimonial Marketing

Ruby on Rails Authentication

Mihir Vaidya

About

Mihir A. VaidyaCo-Founder and V.P. EngineeringReadyPulse

https://www.linkedin.com/in/vaidyamihir

https://twitter.com/mihirvaidya

V.P. EngineeringDec 2011 - now

Software EngineerAugust 2010 – Dec 2011

Software EngineerFeb 2006 – August 2010

Software EngineerMay 2004 – Feb 2006

ResearcherMay 2003 – May 2004

Experience Technologies

Experience with Rails

• Started dabbling as a hobby in 2008

• Rails 2.3.2 – ReadyPulse (v1)

• Rails 3.2 – ReadyPulse (current)

Authentication – What is it? Do I need it?• Identify who is visiting your application– With Trust– And potentially give a customized

experience

Big Decision

• What Authentication Strategy should I use?– Manage My Own User Profiles? (database driven)– OAuth?

• Which provider should I pick?– Facebook– Twitter– Google– GitHub– Passport– …

– Hybrid?• Maintain Identities?

More Decisions

• Should I use an Authentication Library?• If yes, which one?– https://www.ruby-toolbox.com/categories/rail

s_authentication• What are the benefits of one library over the

other?• How hard is it to build my own

Authentication?• Does Rails provide something native?

Rails 3.1 – HTTP Basic Auth

• Limited support exists in Rails 3.1 and onwards to make it easier to write your own authentication– Basic HTTP Auth

• Quick and easy way to make parts of site private where identity is not very important.

• Example:http_basic_authenticate_with

:name => "ror", :password => "rocks", :except=>[:index]

Rails 3.1 - secure_password• has_secure_password

– Adds methods to set and authenticate against a BCrypt password– Requires the model to have a password_digest attribute– Handles complexity of

• Adding password confirmations• Validating password fields• Encrypting passwords• Authentication

– Does not handle• Session management• Helpers – current_user, authenticate_user!

– http://apidock.com/rails/ActiveModel/SecurePassword/ClassMethods/has_secure_password

• force_ssl– Called on the controller– Forces specified or all controller actions to operate only over SSL – Production and Test environments only– http://apidock.com/rails/ActionController/ForceSSL/ClassMethods/force_ssl

A Complete Authentication Solution…• How flexible is it?

– Can I change the views– Can I change routing logic?

• Important if you want to show different views to different users

• Email Confirmation– Ensure the email addresses your users give are valid and correct

• Forgotten Passwords– Happens all the time!

• Are passwords encrypted?– Remember LinkedIn - http://money.cnn.com/2012/06/06/technology/linkedin-password-hack/index.htm

• Timeouts on inactive sessions– Important if you are a banking application

• Does it federate identities with other providers– This is becoming more and more important– Many web apps allow users to connect using 3rd party identity providers such as Facebook, Twitter, Google, etc.

• How easy is it to update user profiles?• Does it allow changing user-names?• Does it allow an easy way to delete user accounts?• Does it allow an easy way to create users programmatically?• How easy is it to move to a different solution?

Options Explored

• Authentication from Scratch• Facebook Connect from Scratch• OmniAuth• Devise• AuthLogic

Authentication from Scratch• You write your own Models, Controllers, Views, and Helpers• Not so hard to get basic setup working• Advantages

– Most Flexible– Easy to setup Basic Functionality– Easy to understand

• Disadvantages– Too much work to make it complete

• Forgotten passwords, email Confirmations, field validations, restrictions, to name a few

– Lost focus from the core app– Re-inventing the wheel

Facebook Connect from Scratch• Can be done in two ways

– Server side• Pros

– More secure– No dependency on Facebook’s JS SDK (all.js)

• Cons– You need to understand the flow – The user does a full page redirect to facebook.com

» Workaround• Perform all authentication in a HTML POPUP with your own handler pages before and after Facebook OAuth calls

– Client side• Mostly JS based• Pros

– Easier to implement since FB SDK encapsulates all complexity– Authentication happens in a Pop-up – User stays on your website all the time

• Cons– all.js is bulky – 170KB (as of 7/9/2012)– Less Secure. Facebook cookie and Access Tokens are stored in local cookies. Easy to extract out

Facebook Connect – Server Flow

• http://developers.facebook.com/docs/authentication/server-side/

Extending the Authentication from Scratch to include Facebook Connect

• Create a Facebook App on https://developers.facebook.com/apps

• Add a handler in SessionsController to handle Facebook Connect callbacks– Ref: Sessions#fb_auth in the sample code

• Create Sessions in the Facebook Connect callback

Facebook Connect from Scratch

• Source Code– https://

github.com/mvaidya/Authentication-In-Rails/tree/master/Code/YourOwnAuthWithFBConnect/Posts• Performs identity matching• Allows the user to login using Facebook or

create a password on the website or both

OmniAuth• One of the best solutions to support Authentication from multiple providers• Implemented as a rack middleware

– Very easy to keep is separate from the core application• Follows a very modular Strategy Pattern – all strategies are listed here

– E.g. omniauth-facebook, omniauth-twitter, etc.– Each Strategy is a separate gem

• Cool – easy to maintain

• Does not provide – controller logic– session management (session[:user_id]) – helpers (current_user, authenticate_user!)

• No views required for Registration and Login• omniauth-identity is an afterthought!

OmniAuth – Big Steps• Create a Facebook App - https://developers.facebook.com/apps

• Create a controller to manage login sessions

• Create a model to store user info including Authentication provider and user ids– E.g. User(provider:string, uid:string, name:string)

• Add gems for all providers u want to support– gem ‘omniauth-twitter’– gem ‘omniauth-facebook’– bundle install

• Add an initializer– config/omniauth.rb

• You register OmniAuth as a rack middleware and configure providersRails.application.config.middleware.use OmniAuth::Builder do

provider :twitter, APP_CONFIG[:twitter]['consumer_key'],APP_CONFIG[:twitter]['consumer_secret']

provider :facebook,APP_CONFIG[:facebook]['app_id'],APP_CONFIG[:facebook]['app_secret'],:client_options => { :ssl => { :ca_file => "#{Rails.root}/config/ca-bundle.crt" } }

End

• Add login links that point to “/auth/:provider”• Setup auth callbacks (/auth/:provider/callback) as SessionsController, create action

– request.env[“omniauth.auth”] has the hash containing user information and tokens from the identity provider (facebook, twitter, etc)

OmniAuth - Gotchas

• Facebook Strategy – Facebook’s SSL Root Cert will not be found– Solutions:

• https://github.com/intridea/omniauth/issues/260 • http://

stackoverflow.com/questions/3977303/omniauth-facebook-certificate-verify-failed

• How to handle Login failures?– Add the following in your omniauth.rb initializerOmniAuth.config.on_failure = -> env do

env[ActionDispatch::Flash::KEY] ||= ActionDispatch::Flash::FlashHash.newenv[ActionDispatch::Flash::KEY][:error] = "Authentication failed, please try again."SessionsController.action(:new).call(env) #call whatever controller/action that displays your signup form

end

OmniAuth - Resources

• Sample Code– Has code to authenticate with Facebook as well as

Twitter– Add Facebook application id and secret to

app_config.yml– Add Twitter consumer key and secret to app_config.yml– https://github.com/mvaidya/Authentication-In-Rails/tree/

master/Code/OmniAuth/Posts• Resources

– https://github.com/intridea/omniauth/wiki– http://railscasts.com/episodes/241-simple-omniauth

OmniAuth Identity

• Follow instructions here to add database authentication (or omniauth-identity strategy) to your existing omniauth solution– https://github.com/intridea/omniauth-identity

• This will enable users to login using an OAuth provider, or register and create an account in your website

• A big Afterthought. Done almost right – Needs an additional Identities table which is different from the Users table

OmniAuth Identity - Gotchas

• You also need to support "POST" on this route– '/auth/:provider/callback' => 'sessions#create'

• Login uses the email address by default. – It can be customized

• It provides it’s own Registration and Login UI, which won’t look anything like your app– Validations on the Identity model wont show up on the

register/login UI– UI can be customized

• Does not tie identities together!

OmniAuth Identity – Gotchas

• Handle Registration Failures!– In your omniauth initializer, add the

on_failed_registration key to identity provider

provider :identity, on_failed_registration: lambda { |env|# lambda is used so that the class IdentitiesController is not cached (important for dev environment).

# That way, changes to the controller will be picked up automatically since # lamda is the rack application to handle failures and not IndentitiesController#new directly

IdentitiesController.action(:new).call(env)}

Devise• One of the most popular and very customizable• Versatile and most Complete

– Comprised of 12 customizable modules• Very easy to configure• Very good and rich documentation

– It’s wiki has covered almost all possible scenarios in which it can be customized• Strong community support• Devise is a Engine

– It gives you the entire stack – Models, Views, Controllers, Helpers• No need to write your own session handlers, or helpers (current_user, authenticate_user!)

– This could cause a major drawback• Hard to understand what is going on in the background!• Have to override its controllers and views to customize

• Third Party auth providers can be easily integrated using omniauth– Omniauthable module

Devise – Big Steps• Install the gem

– gem ‘devise’– bundle

• Run generators and run migrations– rails g devise:install

• The script will display additional instructions on the console• Make sure you follow them all

– rails g devise user– rake db:migrate

• Customize views?– rake g devise:views

• This will copy devise views to views/devise directory. You can change them any way you want

• Additional Customizations?– config/initializers/devise– https://github.com/plataformatec/devise/wiki/_pages

Devise – Gotchas

• Remember: Devise is an Engine– All customizations will require you to override on or

more of the following• Controllers• Routes• Helpers• Views• Libs

– But almost all scenarios are well documented on their wiki pages.

Devise – Pleasant Surprise

• If you are using simple_form, generated views use simple_form as well :)

• Add OmniAuth to devise– https://

github.com/plataformatec/devise/wiki/OmniAuth%3A-Overview• Cool: it detects duplicate identities and resolves

them– E.g. what happens if a user connects with a Facebook

account, whose email address has already been used?

Devise – Resources

• Source Code– https://github.com/mvaidya/Authentication-In-Rails/tree

/master/Code/Devise/Posts• Resources

– https://github.com/plataformatec/devise– https://github.com/plataformatec/devise/wiki/_pages– Devise needs an email provider if you are using

Confirmable• Setup email with AWS SES and SMTP

– http://blog.readypulse.com/2012/01/06/amazon-ses-smtp-emails-using-rails-3-1-in-three-easy-steps/

– http://railscasts.com/episodes?utf8=%E2%9C%93&search=devise

AuthLogic

• https://github.com/binarylogic/authlogic/• One of the oldest Authentication Systems• Advantages

– Handles the logic of authenticating users– Flexible

• leaves the user-flow including all MVC up to the developer• So the developer can do anything he wants

• Disadvantages– Takes up significantly more setup time as compared to Devise

and OmniAuth– Poor support for Third Party providers

OAuth with AuthLogic

• Supported by way of AuthLogic “add ons”• For Facebook, they use Facebooker2 gem– Pretty poor choice

My Favorite• Devise

– I find this as the most complete solution– It hides almost everything from you

• I get to focus more on my app– But

• It has a very rich wiki which has so far addressed all my customization needs easily

• Devise + OmniAuth (omniauthable)– Good, if you don’t care a lot of complicated actions with Facebook graph API. It could be

get complicated – especially if you have multiple providers in the mix• Devise + Facebook + Twitter + Google from Scratch

– Facebook and Twitter have their authentication protocols very well documented– Best to do it on your own

• Gives you solid understanding• You can perform advanced functions on the graph much more easily since you have control

on your code• Identity matching!

What do we use at ReadyPulse?

• Devise• Facebook Connect (from scratch)• Twitter OAuth (using twitter_oauth gem)• Why?

– Devise was the most complete solution that worked out of the box– Highly customizable to fit all of our scenarios– Awesome documentation– We don’t use Facebook and Twitter for user authentication

• Users add their Facebook and Twitter accounts in ReadyPulse to create a holistic view of their brands

– Identity matching

Reminder: Always Encrypt Passwords• Never store plain passwords• Use a one way encryption algorithm

– Hash(password) <unique_encrypted_password>• bcrypt-ruby

– Ruby binding for the OpenBSD bcrypt() password hashing algorithm– https://github.com/codahale/bcrypt-ruby#readme

• Want more secure passwords?– Use SALT– Small chunk of random data added to the beginning of the password before it is

encrypted– Hash(salt + password) <unique_hard_to_break_encrypted_password>

• Even more secure?– Use iterations

• A good read - http://www.jasypt.org/howtoencryptuserpasswords.html

Use Iterations for even stronger Passwords

• Feed the results of a hash function back to the same hash function

• Do it “n” times

• Save the “n” in user table along with the SALT and Digest

We are hiring

Ruby on Rails engineers• http://www.readypulse.com/jobs• jobs@readypulse.com

THANK YOUQuestions & Answers

APPENDIX

Authentication from Scratch – Big Steps• Models

– User• Manages the user profile and Identity• Validations • Callbacks

– UserSession• Manages the users’ current logged in sessions

• Controllers – UsersController

• Actions– new // New User Profile Form– create // Save User Profile to Database– edit // Edit Profile Form

– UserSessionsController• Actions

– new // Login Form– create // Validate credentials and store user info in the session – session[:user_id] = user.id– destroy // Logout (destroy session object) -- session[:user_id] = nil

• Views• Helper Methods

– current_user // @current_user ||= User.find_by_id(session[:user_id]) if session[:user_id]– authenticate_user! // used as a before filter on controller actions that need authenticated user to be present

Authentication from Scratch - Remember• Do not store passwords in Plain Text!

– Use a password Salt to create a Hash the User’s password– Save password_salt and password_hash both in the database– Verfication time: Use the password_salt to compute the hash

and compare with the stored password_hash– bcrypt-ruby gem provides a salt based encryption

• password_salt = BCrypt::Engine.generate_salt• password_hash = BCrypt::Engine.hash_secret(password, password_salt)

• Do not allow mass assignment on password_salt and password_hash fields– Use attr_accessible

top related