README.rdoc

Authlogic

Authlogic is a clean, simple, and unobtrusive ruby authentication solution.
Put simply, its the Chuck Norris of authentication solutions for your
framework of choice.

The last thing we need is another authentication solution, right?
That's what I thought until I tried out some of the current solutions
in both rails and merb. None of them felt right. They were either too
complicated, bloated, littered my application with tons of code, or were
just confusing. This is not the simple / elegant ruby we all fell in love
with. We need a “ruby like” authentication solution. Authlogic is my
attempt to satisfy that need…

Let's take a rails application…

Wouldn't it be nice to keep your app up to date with the latest and
greatest security techniques with a simple update of a plugin?

What if you could have authentication up and running in minutes without
having to run a generator? All because it's simple, like everything
else.

What if creating a user session could be as simple as…

UserSession.create(params[:user_session])

What if your user sessions controller could look just like your other
controllers…

Look familiar? If you didn't know any better, you would think
UserSession was an ActiveRecord model. I think that's pretty cool,
because it fits nicely into the RESTful development pattern, a style we all
know and love. What about the view…

Create your session

Lets assume you are setting up a session for your User model.

Create your user_session.rb file:

# app/models/user_session.rb
class UserSession < Authlogic::Session::Base
# configuration here, just like ActiveRecord, or in an initializer
# See Authlogic::Session::Config::ClassMethods for more details
end

Ensure proper database fields

The user model needs to have the following columns. The names of these
columns can be changed with configuration. Better yet, Authlogic tries to
guess these names by checking for the existence of common names. See
Authlogic::Session::Config::ClassMethods for more details, but chances are
you won't have to specify any configuration for your field names, even
if they aren't the same names as below.

One thing to keep in mind here is that the default :crypto_provider for
Authlogic is Sha512. You are NOT forced to use this. See the
encryption methods section below for more information.

You are all set, now go use it just like you would with any other
ActiveRecord model. Either glance at the code at the beginning of this
README or check out the tutorials (see above in “helpful links”) for a more
detailed walk through.

Magic Columns

Just like ActiveRecord has “magic” columns, such as: created_at and
updated_at. Authlogic has its own “magic” columns too:

Column name Description
login_count Increased every time an explicit login is made. This will *NOT* increase if logging in by a session, cookie, or basic http auth
last_request_at Updates every time the user logs in, either by explicitly logging in, or logging in by cookie, session, or http auth
current_login_at Updates with the current time when an explicit login is made.
last_login_at Updates with the value of current_login_at before it is reset.
current_login_ip Updates with the request remote_ip when an explicit login is made.
last_login_ip Updates with the value of current_login_ip before it is reset.

Magic States

Authlogic tries to check the state of the record before creating the
session. If your record responds to the following methods and any of them
return false, validation will fail:

Method name Description
active? Is the record marked as active?
approved? Has the record been approved?
confirmed? Has the record been conirmed?

What's neat about this is that these are checked upon any type of
login. When logging in explicitly, by cookie, session, or basic http auth.
So if you mark a user inactive in the middle of their session they wont be
logged back in next time they refresh the page. Giving you complete
control.

Need Authlogic to check your own “state”? No problem, check out the hooks
section below. Add in a before_validation to do your own checking. The sky
is the limit.

Hooks / Callbacks

Just like ActiveRecord you can create your own hooks / callbacks so that
you can do whatever you want when certain actions are performed. Such as
before_save, after_save, etc.

Multiple Sessions / Session Identifiers

You're asking: “why would I want multiple sessions?”. Take this
example:

You have an app where users login and then need to re-login to view /
change their billing information. Similar to how Apple's me.com works.
What you could do is have the user login with their normal session, then
have an entirely new session that represents their “secure” session. But
wait, this is 2 users sessions. No problem:

Also, check out the Authlogic::CryptoProviders module and subclasses to get
an idea of how to write your own crypto provider. You don't have to use
the provided classes, you can easily write your own. All that you have to
do is make a class with a class level encrypt and matches? method.
That's it, the sky is the limit.

Switching to a new encryption method

Switching to a new encryption method used to be a pain in the ass.
Authlogic has an option that makes this dead simple. Let's say you want
to migrate to the BCrypt encryption method from Sha512:

That's it. When a user successfully logs in and is using the old method
their password will be updated with the new method and all new
registrations will use the new method as well. Your users won't know
anything changed.

Tokens (persistence, resetting passwords, private feed access, etc.)

To start, let me define tokens as Authlogic sees it. A token is a form of
credentials that grants some type of access to their account. Depending on
the type of access, a different type of token may be needed. Put simply,
it's a way for the user to say “I am this person, let me proceed”. What
types of different access you ask? Here are just a few:

Regular account access

Access to reset their password

Access to a private feed

Access to confirm their account

There could be many more depending on your application. What's great
about Authlogic is that it doesn't care what you do or how you want to
grant access to accounts. That's up to you and your application.
Authlogic just cares about the type of tokens you need. Instead of giving
you a token for each specific task, it gives you all of the necessary
types of tokens, and you get to use them how you wish. It maintains
the tokens and gives you all of the tools you need to use them. Just add
the fields to your database and you are good to go.

Here are the 3 tokens in more detail:

Persistence token

This token is used to persist the user's session. This is the token
that is stored in the session and the cookie, so that during each request
the user stays logged in. What's unique about this token is that the
first time it is used the value is stored in the session, thus persisting
the session. This field is required and must be in your database.

Single access token

This token is used for single access only, it is not persisted. Meaning the
user provides it, Authlogic grants them access, and that's it. If they
want access again they need to provide the token again. Authlogic will
NEVER store this value in the session or a cookie. For added
security, by default this token is ONLY allowed for RSS and ATOM
requests. Also, this token does NOT change with the password.
Meaning if the user changes their password, this token will remain the
same. Lastly, this token uses a “friendly” toke (see the URL example below)
so that it is easier to email / copy and paste. You can change all of this
with configuration (see Authlogic::Session::config), so if you don't
like how this works by default, just set some simple configuration in your
session.

This field is optional, if you want to use it just add the field to your
database:

The single_access_token parameter name is configurable (see
Authlogic::Session::Config), but if that parameter exists Authlogic will
automatically use it to try and grant that user access. You don't have
to do a thing: UserSession.find will take care of it just like it does for
everything else.

For more information see:
Authlogic::ORMAdapters::ActiveRecordAdapter::ActsAsAuthentic::SingleAccess

Perishable token

This token is used for temporary account access, hence the term
“perishable”. This token is constantly changing, it changes…

In a before_validation in your model, so basically every time the record is
saved

Any time a new session is successfully saved (aka logged in)

This is perfect for resetting passwords or confirming
accounts. You email them a url with this token in it, and then use this
token to find the record and perform your action.

This field is optional, if you want to use it just add the field to your
database:

That's all you need to do to locate the record. Here is what it does
for extra security:

Ignores blank tokens all together. If a blank token is passed nil will be
returned.

It checks the age of the token, by default the threshold is 10 minutes,
meaning if the token is older than 10 minutes, it is not valid and no
record will be returned. You can change the default or just override it by
passing the threshold as the second parameter. If you don't want a
threshold at all, pass 0.

Just like the single access token this uses a friendly token, so it is
easier to email / copy and paste.

For a detailed tutorial on how to reset password using this token see the
helpful links section above.

For more information see:
Authlogic::ORMAdapters::ActiveRecordAdapter::ActsAsAuthentic::Perishability

Scoping

Scoping with authentication is a little tricky because it can come in many
different flavors:

Accounts have many users, meaning users can only belong to one account at a
time.

Accounts have and belong to many users, meaning a user can belong to more
than one account.

Users access their accounts via subdomains.

Users access their accounts by selecting their account and storing their
selection, NOT using subdomains. Maybe you store their selection in
a session, cookie, or the database. It doesn't matter.

Now mix and match the above, it can get pretty hairy. Fear not, because
Authlogic is designed in a manner where it doesn't care how you do it,
all that you have to do is break it down. When scoping a session there are
3 parts you might want to scope:

The model (the validations, etc)

The session (finding the record)

The cookies (the names of the session key and cookie)

I will describe each below, in order.

Scoping your model

This scopes your login field validation, so that users are allowed to have
the same login, just not in the same account.

Scoping cookies

What's neat about cookies is that if you use sub domains they
automatically scope their self. Meaning if you create a cookie in
whatever.yourdomain.com it will not exist in another.yourdomain.com. So if
you are using subdomains to scope your users, you don't have to do
anything.

But what if you *don't* want to separate your cookies by subdomains?
You can accomplish this by doing:

Done, Authlogic will give each cookie a unique name depending on the
account.

With the above information you should be able to scope your sessions any
way you want. Just mix and match the tools above to accomplish this. Also
check out the documentation on Authlogic::ActiveRecord::AuthenticatesMany.

Errors

The errors in Authlogic work JUST LIKE ActiveRecord. In fact, it uses the
exact same ActiveRecord errors class. Use it the same way:

Automatic Session Updating

This is one of my favorite features that I think is pretty cool. It's
things like this that make a library great and let you know you are on the
right track.

Just to clear up any confusion, Authlogic does not store the plain id in
the session. It stores a token. This token changes with the password, this
way stale sessions can not be persisted.

That being said…What if a user changes their password? You have to re-log
them in with the new password, recreate the session, etc, pain in the ass.
Or what if a user creates a new user account? You have to do the same
thing. Here's an even better one: what if a user is in the admin area
and changes his own password? There might even be another place passwords
can change. It shouldn't matter, your code should be written in a way
where you don't have to remember to do this.

Instead of updating sessions all over the place, doesn't it make sense
to do this at a lower level? Like the User model? You're saying “but
Ben, models can't mess around with sessions and cookies”. True…but
Authlogic can, and you can access Authlogic just like a model. I know in
most situations it's not good practice to do this but I view this in
the same class as sweepers, and feel like it actually is good practice
here. User sessions are directly tied to users, they should be connected on
the model level.

Fear not, because the acts_as_authentic method you call in your model takes
care of this for you, by adding an after_save callback to automatically
keep the session up to date. You don't have to worry about it anymore.
Don't even think about it. Let your UsersController deal with users,
not users AND sessions. ANYTIME the user changes his password
in ANY way, his session will be updated.

Here is basically how this is done.…

class User < ActiveRecord::Base
after_save :maintain_sessions!
private
def maintain_sessions!
# If we aren't logged in and a user is create log them in as that user
# If we aren't logged in and a user's password changes, log them in as that user
# If we are logged in and they change their password, update the session so they remain logged in
end
end

Obviously there is a little more to it than this, but hopefully this
clarifies any confusion. Lastly, this can be altered / disabled via a
configuration option. Just set :session_ids => nil when calling
acts_as_authentic.

When things come together like this I think its a sign that you are doing
something right. Put that in your pipe and smoke it!

Migrating from restful_authentication

Migrating from the restful_authentication plugin? I made an option
especially for you. Just do the following and everything will be taken care
of, your users won't even know anything changed:

Framework agnostic (Rails, Merb, etc.)

I designed Authlogic to be framework agnostic, meaning it doesn't care
what framework you use it in. Right out of the box it supports rails and
merb. I have not had the opportunity to use other frameworks, but the only
thing stopping Authlogic from being used in other frameworks is a simple
adapter. Check out controller_adapters/rails_adapter, or
controller_adapters/merb_adapter.

Since pretty much all of the frameworks in ruby follow the Rack
conventions, the code should be very similar across adapters. In fact that
abstract adapter assumes you are using Rack. If you are using it properly
there really isn't any code you should have to write. Check out the
merb_adapter to see for yourself. You're saying “but Ben, why not just
hook into Rack and avoid the need for controller adapters all together?”.
It's not that simple, because rails doesn't inherit from the
Rack::Request class, plus there are small differences between how rack is
implemented in each framework. Authlogic has to hook into your controller
with a before_filter anyways, so it can “activate” itself. Why not just use
the controller object?

The point in all of this rambling is that implementing Authlogic is as
simple as creating an adapter. I created both the rails and merb adapters
in under 10 minutes. If you have an adapter you created and would like to
add please let me know and I will add it into the source.

How it works

Interested in how all of this all works? Basically a before_filter is
automatically set in your controller which lets Authlogic know about the
current controller object. This “activates” Authlogic and allows Authlogic
to set sessions, cookies, login via basic http auth, etc. If you are using
your framework in a multiple thread environment, don't worry. I kept
that in mind and made this thread safe.

From there it is pretty simple. When you try to create a new session the
record is authenticated and then all of the session / cookie magic is done
for you. The sky is the limit.

What's wrong with the current solutions?

You probably don't care, but I think releasing the millionth
authentication solution for a framework that has been around for over 4
years requires a little explanation.

I don't necessarily think the current solutions are “wrong”, nor am I
saying Authlogic is the answer to your prayers. But, to me, the current
solutions were lacking something. Here's what I came up with…

Generators are messy

Generators have their place, and it is not to add authentication to an app.
It doesn't make sense. Generators are meant to be a starting point for
repetitive tasks that have no sustainable pattern. Take controllers, the
set up is the same thing over and over, but they eventually evolve to a
point where there is no clear cut pattern. Trying to extract a pattern out
into a library would be extremely hard, messy, and overly complicated. As a
result, generators make sense here.

Authentication is a one time set up process for your app. It's the same
thing over and over and the pattern never really changes. The only time it
changes is to conform with newer / stricter security techniques. This is
exactly why generators should not be an authentication solution. Generators
add code to your application, once code crosses that line, you are
responsible for maintaining it. You get to make sure it stays up with the
latest and greatest security techniques. And when the plugin you used
releases some major update, you can't just re-run the generator, you
get to sift through the code to see what changed. You don't really have
a choice either, because you can't ignore security updates.

Using a library that hundreds of other people use has it advantages.
Probably one of the biggest advantages if that you get to benefit from
other people using the same code. When Bob in California figures out a new
awesome security technique and adds it into Authlogic, you get to benefit
from that with a single update. The catch is that this benefit is limited
to code that is not “generated” or added into your app. As I said above,
once code is “generated” and added into your app, it's your
responsibility.

Lastly, there is a pattern here, why clutter up all of your applications
with the same code over and over?

Why test the same code over and over?

I've noticed my apps get cluttered with authentication tests, and they
are the same exact tests! This irritates me. When you have identical tests
across your apps thats a red flag that code can be extracted into a
library. What's great about Authlogic is that I tested it for you. You
don't write tests that test the internals of ActiveRecord do you? The
same applies for Authlogic. Only test code that you've written.
Essentially testing authentication is similar to testing any another
RESTful controller. This makes your tests focused and easier to understand.

Limited to a single authentication

I recently had an app where you could log in as a user and also log in as
an employee. I won't go into the specifics of the app, but it made the
most sense to do it this way. So I had two sessions in one app. None of the
current solutions I found easily supported this. They all assumed a single
session. One session was messy enough, adding another just put me over the
edge and eventually forced me to write Authlogic. Authlogic can support 100
different sessions easily and in a clean format. Just like an app can
support 100 different models and 100 different records of each model.

Too presumptuous

A lot of them forced me to name my password column as “this”, or the key of
my cookie had to be “this”. They were a little too presumptuous. I am
probably overly picky, but little details like that should be configurable.
This also made it very hard to implement into an existing app.

Disclaimer

I am not trying to “bash” any other authentication solutions. These are
just my opinions, formulate your own opinion. I released Authlogic because
it has made my life easier and I enjoy using it, hopefully it does the same
for you.