Rails authentication – with sparkles!
about the gem
After playing with a bunch of other auth gems out there, in the end I decided I had to roll my own. Unlike the others (and the reason I undertook this task), Sparkly Auth errs on the side of security. By default, (that is, unless you go changing configuration options that water down its auth mechanisms), this gem produces a PCI/DSS- compliant authentication scheme which I'm now putting to work at my Real Job at Ingenico (www.ingenico.com). (We now have two Web-based payment applications depending on Sparkly Auth.)
There is an ongoing battle between security and convenience. They say you can pick one, but not both. While I'm not going to claim that Sparkly singlehandedly settles this dispute, I will say that Sparkly lets you choose between varying shades of gray, rather than choosing between black and white. Sparkly Auth provides a plethora of configuration options to let you apply a more user-friendly authentication solution to your site, while making it crystal clear what the security tradeoff will be.
Sparkly supports multiple user models, multiple controllers, and all that jazz – but doesn't force it on you. A default value is provided for virtually every possible option, and the options are conveniently tucked away in the class documentation – there for you when you need it, but not breathing down your neck when you don't.
what does security mean?
So that's the high level overview. If you've read this far then maybe you're wondering exactly what kind of authentication security Sparkly Auth brings to the table. Well, here's The List. Some other solutions out there cover portions of it; others cover other portions. But I've yet to find one (besides Sparkly) that does it all.
One last disclaimer: all of this can be modified or disabled entirely. So don't think that because it's listed here, dependencies HAVE to use it. I've got a number of side apps written that use Sparkly but, for example, completely disable the password update policy.
Enforces a strong password policy by default (7-digit uppercase, lowercase and numeric)
Enforces a periodic password update (once every 30 days)
Enforces a unique password (can't match any of the previous 4 passwords by default)
Automatically signs the user out after 30 minutes of inactivity
Provides secure single-access tokens for authentication without cookies (e.g. Web Service consumers)
Locks an account for 30 minutes after 5 invalid login attempts
Provides generators for controllers and views, so that you can add (or remove) layers quickly and painlessly – even on a per-model or per-controller basis, if your application uses more than one
Allows you to change which parent controller has access to the logged-in user (defaults to ApplicationController)
Behaviors (including even the core behavior) are plug-and-play and can be easily swapped in/out, and custom behaviors can be added
Encryption methods can be easily replaced
Since my own personal use cases for Sparkly Auth vary widely, so do its capabilities. Not only can the above be disabled, but it also sports (for example) a “Remember Me” checkbox that would otherwise circumvent some of the above precautions. Obviously, the checkbox is disabled by default.
In Rails 2, add “sparkly-auth” to your gem dependencies:
In Rails 3, add “sparkly-auth” to your Gemfile:
(In the examples below, replace 'script/generate' with 'rails generate' if you're using Rails 3.)
For a step-by-step guide, run
script/generate sparkly help
Basically, the you have to run
script/generate sparkly config script/generate sparkly migrations
and optionally (if you plan to override the controllers and/or views),
script/generate sparkly controllers script/generate sparkly views
Assuming you have a User model (or that you've edited config/initializers/sparkly_authentication.rb to taste), you should be ready to go!
You should take a quick gander at config/initializers/sparkly_authentication.rb just to see what's in there.
For added security, part of Sparkly's core behavior is to declare the login key (usually :email or :login), the :password and the :password_confirmation attributes on the authenticated model as attr_accessible. This allows you to mass assign those attributes, but disables mass assignment on any others. That means you'll have to explicitly call attr_accessible on any additional attributes you wish to mass assign. For more information (and the reason Sparkly is doing this), see the excellent Railscast on the subject by Ryan Bates at media.railscasts.com/videos/026_hackers_love_mass_assignment.mov .
Unless you disable them, Sparkly Auth will automatically generate a set of routes for its controllers. Run
and you should see something like this:
new_user_session GET /user/session/new(.:format) edit_user_session GET /user/session/edit(.:format) user_session GET /user/session(.:format) PUT /user/session(.:format) DELETE /user/session(.:format) POST /user/session(.:format) user_login /user/login user_logout /user/logout new_user GET /user/new(.:format) edit_user GET /user/edit(.:format) user GET /user(.:format) PUT /user(.:format) DELETE /user(.:format) POST /user(.:format) /:controller/:action/:id /:controller/:action/:id(.:format)
This assumes you're authenticating against a single User model. Obviously, if you're authenticating against a different model (or more than one), the routes will be changed to suit.
I'm working on rake tasks that help you migrate from other authentication solutions to Sparkly Auth, largely because I had to do so myself. So without further ado, here's how you can do that:
After running the various Sparkly migrations, simply run:
If you've set up an Authlogic encryptor other than SHA512, you'll want to use that encryptor for Sparkly. In this case, don't disable Authlogic the dependency (but DO remove the various hooks from your code), and in your config/initializers/sparkly_authentication.rb file, add the following line:
config.encryptor = Authlogic::CryptoProviders::Wordpress # or whatever.
That should be it (it was for me). If you have any troubles, drop me a line so I can update this documentation!
Note on Patches/Pull Requests
Fork the project.
Make your feature addition or bug fix.
Add tests for it. This is important so I don't break it in a future version unintentionally.
Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
Send me a pull request. Bonus points for topic branches.
Copyright © 2010 Colin MacKenzie IV. See LICENSE for details.