sorcery

Magical Authentication for Rails 3 and Sinatra. Supports ActiveRecord and Mongoid.

Inspired by restful_authentication, Authlogic and Devise. Crypto code taken almost unchanged from Authlogic. OAuth code inspired by OmniAuth and Ryan Bates’s railscasts about it.

Philosophy

Sorcery is a stripped-down, bare-bones authentication library, with which you can write your own authentication flow. It was built with a few goals in mind:

  • Less is more - less than 20 public methods to remember for the entire feature-set make the lib easy to ‘get’.

  • No built-in or generated code - use the library’s methods inside *your own* MVC structures, and don’t fight to fix someone else’s.

  • Magic yes, Voodoo no - the lib should be easy to hack for most developers.

  • Configuration over Confusion - Centralized (1 file), Simple & short configuration as possible, not drowning in syntactic sugar.

  • Keep MVC cleanly separated - DB is for models, sessions are for controllers. Models stay unaware of sessions.

Hopefully, I’ve achieved this. If not, let me know.

Example Rails 3 app using sorcery: github.com/NoamB/sorcery-example-app

Example Sinatra app using sorcery: github.com/NoamB/sorcery-example-app-sinatra

Documentation: rubydoc.info/gems/sorcery/0.5.21/frames

Check out the tutorials in the github wiki!

API Summary

Below is a summary of the library methods. Most method names are self explaining and the rest are commented:

# core
 # this is a before filter
(username,password,remember_me = false)
logout
logged_in?
current_user
redirect_back_or_to # used when a user tries to access a page while logged out, is asked to login, and we want to return him back to the page he originally wanted.
@user.external? # external users, such as facebook/twitter etc.
User.authenticates_with_sorcery!

# activity logging
current_users

# http basic auth
 # this is a before filter

# external
(provider) # sends the user to an external service (twitter etc.) to authenticate.
(provider) # tries to login from the external provider's callback.
create_from(provider) # create the user in the local app db.

# remember me
remember_me!
forget_me!

# reset password
User.load_from_reset_password_token(token)
@user.deliver_reset_password_instructions!
@user.change_password!(new_password)

# user activation
User.load_from_activation_token(token)
@user.activate!

Please see the tutorials in the github wiki for detailed usage information.

Installation:

If using bundler, first add ‘sorcery’ to your Gemfile:

gem “sorcery”

And run bundle install

Otherwise simply

gem install sorcery

Rails 3 Configuration:

For Rails 3 create an initializer file using:

rake sorcery:bootstrap

This will create the file as config/initializers/sorcery.rb . Inside it the comments will tell you everything you need to know.

For your convenience, Sorcery includes a migrations generator for Rails, which can be used like so:

rails g sorcery_migration [list of submodules]

For example, for only the core functionality use:

rails g sorcery_migration core

To generate migrations for both the core AND ‘remember_me’ submodule:

rails g sorcery_migration core remember_me

These migrations use the default fields. You can choose to use these migrations or make your own tables and fields. Sorcery tries not to impose a database structure and naming scheme on your application.

Sinatra Configuration:

For Sinatra you’ll need to create the initializer manually. You can do it in the main app file or in a separate file you require (see example in example app). The code looks as follows:

Sorcery::Controller::Config.submodules = [] # specify here the submodules you want to include

Sorcery::Controller::Config.configure do |config|
  config.session_timeout = 10.minutes
  ...
  ...

  config.user_config do |user|
    user.username_attribute_name                      = :email
    ...
	...
	
  end
end

Finally, to make all the code above take effect, we’ll need to re-include the sorcery controller module:

include Sorcery::Controller::Adapters::Sinatra
include Sorcery::Controller

Full Features List by module:

Core (see lib/sorcery/model.rb and lib/sorcery/controller.rb):

  • login/logout, optional return user to requested url on login, configurable redirect for non-logged-in users.

  • password encryption, algorithms: bcrypt(default), md5, sha1, sha256, sha512, aes256, custom(yours!), none. Configurable stretches and salt.

  • configurable attribute names for username, password and email.

User Activation (see lib/sorcery/model/submodules/user_activation.rb):

  • User activation by email with optional success email.

  • configurable attribute names.

  • configurable mailer, method name, and attribute name.

  • configurable temporary token expiration.

  • Optionally prevent non-active users to login.

Reset Password (see lib/sorcery/model/submodules/reset_password.rb):

  • Reset password with email verification.

  • configurable mailer, method name, and attribute name.

  • configurable temporary token expiration.

  • configurable time between emails (hammering protection).

Remember Me (see lib/sorcery/model/submodules/remember_me.rb):

  • Remember me with configurable expiration.

  • configurable attribute names.

Session Timeout (see lib/sorcery/controller/submodules/session_timeout.rb):

  • Configurable session timeout.

  • Optionally session timeout will be calculated from last user action.

Brute Force Protection (see lib/sorcery/model/submodules/brute_force_protection.rb):

  • Brute force login hammering protection.

  • configurable logins before lock and lock duration.

Basic HTTP Authentication (see lib/sorcery/controller/submodules/http_basic_auth.rb):

  • A before filter for requesting authentication with HTTP Basic.

  • automatic login from HTTP Basic.

  • automatic login is disabled if session key changed.

Activity Logging (see lib/sorcery/model/submodules/activity_logging.rb):

  • automatic logging of last login, last logout and last activity time.

  • an easy method of collecting the list of currently logged in users.

  • configurable timeout by which to decide whether to include a user in the list of logged in users.

External (see lib/sorcery/controller/submodules/external.rb):

  • OAuth1 and OAuth2 support (currently twitter & facebook)

  • configurable db field names and authentications table.

Next Planned Features:

I’ve got some thoughts which include (unordered):

  • Passing a block to encrypt, allowing the developer to define his own mix of salting and encrypting

  • Forgot username, maybe as part of the reset_password module

  • Scoping logins (to a subdomain or another arbitrary field)

  • Allowing storing the salt and crypted password in the same DB field for extra security

  • Other reset password strategies (security questions?)

  • Other brute force protection strategies (captcha)

Have an idea? Let me know, and it might get into the gem!

Other stuff:

  • Improve specs speed

  • Provide an easy way to run specs after install

  • Improve documentation

  • Try to reduce the number of library methods, and find better names to some

Backward compatibility

While the lib is young and evolving fast I’m breaking backward compatibility quite often. I’m constantly finding better ways to do things and throwing away old ways. To let you know when things are changing in a non-compatible way, I’m bumping the minor version of the gem. The patch version changes are backward compatible.

In short, an app that works with x.3.1 should be able to upgrade to x.3.2 with no code changes. The same cannot be said about upgrading to x.4.0 and above, however.

Contributing to sorcery

Your feedback is very welcome and will make this gem much much better for you, me and everyone else. Besides feedback on code, features, suggestions and bug reports, you may want to actually make an impact on the code. For this:

  • Fork it.

  • Fix it.

  • Test it.

  • Commit it.

  • Send me a pull request so I’ll… Pull it.

If you feel sorcery has made your life easier, and you would like to express your thanks via a donation, my paypal email is in the contact details.

Contact

Feel free to ask questions using these contact details: email: [email protected] ( also for paypal ) twitter: @nbenari

Copyright © 2010 Noam Ben Ari ([email protected]). See LICENSE.txt for further details.