Authentication in-rails
-
Upload
mihir-vaidya -
Category
Technology
-
view
723 -
download
0
description
Transcript of Authentication in-rails
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
Demo: has_secure_password
• Source Code– https://github.com/mvaidya/Authentication-
In-Rails/tree/master/Code/YourOwnAuth2/Posts
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)}
OmniAuth Identity – Resources
• Source Code– https://github.com/mvaidya/Authentication-
In-Rails/tree/master/Code/OmniAuthWithIdentity
• Resources– https://
github.com/intridea/omniauth-identity– http://railscasts.com/episodes/304-omniaut
h-identity
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• [email protected]
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
Authentication from Scratch – Resources
• Sample Code– https://github.com/mvaidya/Authentication-
In-Rails/tree/master/Code/YourOwnAuth/Posts
• Resources– http://
railscasts.com/episodes/250-authentication-from-scratch?autoplay=true• Does not talk about authenticate_user!
Before filter– https://github.com/ryanb/nifty-generators