Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 479 lines (300 sloc) 31.267 kb
43e849c @binarylogic Released v0.10.4
authored
1 = Authlogic
1b98335 @binarylogic Initial commit
authored
2
62ac95a @binarylogic Added should_be_authentic shoulda macro
authored
3 Authlogic is a clean, simple, and unobtrusive ruby authentication solution. Put simply, its the Chuck Norris of authentication solutions for your framework of choice.
1b98335 @binarylogic Initial commit
authored
4
72f3a21 @binarylogic Added AES256 as an option for crypto_providers
authored
5 So what is Authlogic, and why would I create a solution to a problem that already has plenty of solutions? Because none of the solutions felt right to me, RESTful development and authentication just didn't seem to go well together. It was like trying to fit a square peg in a round hole. All of the current solutions, for both rails and merb, just seemed to force that square peg in the round hole for me. Just because they did it for me doesn't make it 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...
1b98335 @binarylogic Initial commit
authored
6
9bca67d @binarylogic Reorganized ORM code and tests
authored
7 Let's take a rails application...
8
9 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?
2155477 @binarylogic Updated readme
authored
10
791f700 @binarylogic Released v1.0.0 (see changelog)
authored
11 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.
43e849c @binarylogic Released v0.10.4
authored
12
34b225c @binarylogic Updated readme
authored
13 What if creating a user session could be as simple as...
e77ca8a @binarylogic Updated readme
authored
14
4b1f8fa @binarylogic User column_names instead of colums when determining if a column exists
authored
15 UserSession.create(params[:user_session])
e77ca8a @binarylogic Updated readme
authored
16
34b225c @binarylogic Updated readme
authored
17 What if your user sessions controller could look just like your other controllers...
1b98335 @binarylogic Initial commit
authored
18
19 class UserSessionsController < ApplicationController
20 def new
21 @user_session = UserSession.new
22 end
23
24 def create
25 @user_session = UserSession.new(params[:user_session])
35f14ba @binarylogic Released v0.10.0
authored
26 if @user_session.save
c93bec2 @binarylogic Changed scope to id
authored
27 redirect_to account_url
1b98335 @binarylogic Initial commit
authored
28 else
29 render :action => :new
30 end
31 end
32
33 def destroy
ebdebfa @binarylogic Released v1.1.1
authored
34 current_user_session.destroy
4caccd0 @binarylogic Released 1.2.1
authored
35 redirect_to new_user_session_url
1b98335 @binarylogic Initial commit
authored
36 end
37 end
38
24501b4 @binarylogic Release v0.10.2
authored
39 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...
1b98335 @binarylogic Initial commit
authored
40
41 <% form_for @user_session do |f| %>
791f700 @binarylogic Released v1.0.0 (see changelog)
authored
42 <%= f.error_messages %>
1b98335 @binarylogic Initial commit
authored
43 <%= f.label :login %><br />
44 <%= f.text_field :login %><br />
45 <br />
46 <%= f.label :password %><br />
47 <%= f.password_field :password %><br />
48 <br />
49 <%= f.submit "Login" %>
50 <% end %>
51
34b225c @binarylogic Updated readme
authored
52 Or how about persisting the session...
1b98335 @binarylogic Initial commit
authored
53
54 class ApplicationController
ebdebfa @binarylogic Released v1.1.1
authored
55 helper_method :current_user_session, :current_user
1b98335 @binarylogic Initial commit
authored
56
dbd8b8f @binarylogic Release v1.2.0
authored
57 private
ebdebfa @binarylogic Released v1.1.1
authored
58 def current_user_session
59 return @current_user_session if defined?(@current_user_session)
60 @current_user_session = UserSession.find
61 end
62
63 end current_user
64 return @current_user if defined?(@current_user)
65 @current_user = current_user_session && current_user_session.user
1b98335 @binarylogic Initial commit
authored
66 end
67 end
68
72f3a21 @binarylogic Added AES256 as an option for crypto_providers
authored
69 Authlogic and REST are like peas and carrots, as Forrest Gump would say. But This is just the tip of the ice berg. Keep reading to find out everything Authlogic can do.
1b98335 @binarylogic Initial commit
authored
70
71 == Helpful links
72
43e849c @binarylogic Released v0.10.4
authored
73 * <b>Documentation:</b> http://authlogic.rubyforge.org
049c048 @binarylogic Added check foreck for echoe gem if meta tasks are executed
authored
74 * <b>Tutorial: Authlogic basic setup:</b> http://www.binarylogic.com/2008/11/3/tutorial-authlogic-basic-setup
75 * <b>Tutorial: Reset passwords with Authlogic the RESTful way:</b> http://www.binarylogic.com/2008/11/16/tutorial-reset-passwords-with-authlogic
a15093e @binarylogic Add OpenID tutorial link
authored
76 * <b>Tutorial: Using OpenID with Authlogic:</b> http://www.binarylogic.com/2008/11/21/tutorial-using-openid-with-authlogic
d10f713 @binarylogic Added act_like_old_restful_authentication options for acts_as_authentic ...
authored
77 * <b>Live example of the tutorials above (with source):</b> http://authlogicexample.binarylogic.com
a623f67 @binarylogic Release v1.3.3
authored
78 * <b>Tutorial: Easily migrate from restful_authentication:</b> http://www.binarylogic.com/2008/11/23/tutorial-easily-migrate-from-restful_authentication-to-authlogic
79 * <b>Tutorial: Upgrade passwords easily with Authlogic:</b> http://www.binarylogic.com/2008/11/23/tutorial-upgrade-passwords-easily-with-authlogic
43e849c @binarylogic Released v0.10.4
authored
80 * <b>Bugs / feature suggestions:</b> http://binarylogic.lighthouseapp.com/projects/18752-authlogic
1b98335 @binarylogic Initial commit
authored
81
82 == Install and use
83
93a4787 @binarylogic Added Sha1 crypto provider to help with the restful_authentication trans...
authored
84 Install the gem / plugin (recommended)
1b98335 @binarylogic Initial commit
authored
85
43e849c @binarylogic Released v0.10.4
authored
86 $ sudo gem install authlogic
1b98335 @binarylogic Initial commit
authored
87
62ac95a @binarylogic Added should_be_authentic shoulda macro
authored
88 Now add the gem dependency in your config:
1d38644 @binarylogic Added last_request_at_threshold cconfig option
authored
89
93a4787 @binarylogic Added Sha1 crypto provider to help with the restful_authentication trans...
authored
90 # config/environment.rb
ebdebfa @binarylogic Released v1.1.1
authored
91 config.gem "authlogic"
93a4787 @binarylogic Added Sha1 crypto provider to help with the restful_authentication trans...
authored
92
62ac95a @binarylogic Added should_be_authentic shoulda macro
authored
93 Or you install this as a plugin (for older versions of rails)
1b98335 @binarylogic Initial commit
authored
94
43e849c @binarylogic Released v0.10.4
authored
95 script/plugin install git://github.com/binarylogic/authlogic.git
1b98335 @binarylogic Initial commit
authored
96
6af9b61 @binarylogic Updated readme
authored
97 === Create your session
98
99 Lets assume you are setting up a session for your User model.
100
101 Create your user_session.rb file:
102
103 # app/models/user_session.rb
1d38644 @binarylogic Added last_request_at_threshold cconfig option
authored
104 class UserSession < Authlogic::Session::Base
6af9b61 @binarylogic Updated readme
authored
105 # configuration here, just like ActiveRecord, or in an initializer
1d38644 @binarylogic Added last_request_at_threshold cconfig option
authored
106 # See Authlogic::Session::Config::ClassMethods for more details
6af9b61 @binarylogic Updated readme
authored
107 end
108
109 === Ensure proper database fields
110
1d38644 @binarylogic Added last_request_at_threshold cconfig option
authored
111 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.
6af9b61 @binarylogic Updated readme
authored
112
dbd8b8f @binarylogic Release v1.2.0
authored
113 t.string :login, :null => false
114 t.string :crypted_password, :null => false
115 t.string :password_salt, :null => false # not needed if you are encrypting your pw instead of using a hash algorithm.
4caccd0 @binarylogic Released 1.2.1
authored
116 t.string :persistence_token, :null => false
117 t.string :single_access_token, :null => false # optional, see the tokens section below.
118 t.string :perishable_token, :null => false # optional, see the tokens section below.
72f3a21 @binarylogic Added AES256 as an option for crypto_providers
authored
119 t.integer :login_count, :null => false, :default => 0 # optional, this is a "magic" column, see the magic columns section below
6af9b61 @binarylogic Updated readme
authored
120
121 === Set up your model
122
123 Make sure you have a model that you will be authenticating with. For this example let's say you have a User model:
124
125 class User < ActiveRecord::Base
ebdebfa @binarylogic Released v1.1.1
authored
126 acts_as_authentic # for options see documentation: Authlogic::ORMAdapters::ActiveRecordAdapter::ActsAsAuthentic::Config
6af9b61 @binarylogic Updated readme
authored
127 end
128
d10f713 @binarylogic Added act_like_old_restful_authentication options for acts_as_authentic ...
authored
129 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.
130
131 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.
1b98335 @binarylogic Initial commit
authored
132
72f3a21 @binarylogic Added AES256 as an option for crypto_providers
authored
133 == Migrating from restful_authentication
134
135 This is for migrating an existing application from restful_authentication to Authlogic. If you are starting a new application, please ignore this section.
136
137 For those that are switching existing apps over, 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:
138
139 # app/models/user.rb
140 class User < ActiveRecord::Base
141 acts_as_authentic :act_like_restful_authentication => true
142 end
143
144 Or you can transition your users to the Authlogic password system:
145
146 # app/models/user.rb
147 class User < ActiveRecord::Base
148 acts_as_authentic :transition_from_restful_authentication => true
149 end
150
151 For more information checkout my blog post on this: http://www.binarylogic.com/2008/11/23/tutorial-easily-migrate-from-restful_authentication-to-authlogic
152
1b98335 @binarylogic Initial commit
authored
153 == Magic Columns
154
43e849c @binarylogic Released v0.10.4
authored
155 Just like ActiveRecord has "magic" columns, such as: created_at and updated_at. Authlogic has its own "magic" columns too:
1b98335 @binarylogic Initial commit
authored
156
157 Column name Description
ae1d3bb @binarylogic Released v0.9.1
authored
158 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
e77ca8a @binarylogic Updated readme
authored
159 last_request_at Updates every time the user logs in, either by explicitly logging in, or logging in by cookie, session, or http auth
1b98335 @binarylogic Initial commit
authored
160 current_login_at Updates with the current time when an explicit login is made.
161 last_login_at Updates with the value of current_login_at before it is reset.
162 current_login_ip Updates with the request remote_ip when an explicit login is made.
163 last_login_ip Updates with the value of current_login_ip before it is reset.
164
165 == Magic States
166
43e849c @binarylogic Released v0.10.4
authored
167 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:
1b98335 @binarylogic Initial commit
authored
168
169 Method name Description
2155477 @binarylogic Updated readme
authored
170 active? Is the record marked as active?
1b98335 @binarylogic Initial commit
authored
171 approved? Has the record been approved?
172 confirmed? Has the record been conirmed?
72f3a21 @binarylogic Added AES256 as an option for crypto_providers
authored
173
174 Authlogic does nothing to define these methods for you, its up to you to define what they mean. If your object responds to these methods Authlogic will use them, otherwise they are ignored.
1b98335 @binarylogic Initial commit
authored
175
ff67374 @binarylogic Cleaned up identifier doc
authored
176 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.
1b98335 @binarylogic Initial commit
authored
177
2479aa0 @binarylogic Allow for login_count to be nil and initialize with 1
authored
178 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.
35f14ba @binarylogic Released v0.10.0
authored
179
1b98335 @binarylogic Initial commit
authored
180 == Hooks / Callbacks
181
dbd8b8f @binarylogic Release v1.2.0
authored
182 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.
1b98335 @binarylogic Initial commit
authored
183
184 before_create
185 after_create
72f3a21 @binarylogic Added AES256 as an option for crypto_providers
authored
186
1b98335 @binarylogic Initial commit
authored
187 before_destroy
188 after_destroy
72f3a21 @binarylogic Added AES256 as an option for crypto_providers
authored
189
c190c77 @binarylogic Forced logged_in and logged_out named scopes to use seconds for the limi...
authored
190 before_find
191 after_find
72f3a21 @binarylogic Added AES256 as an option for crypto_providers
authored
192
35f14ba @binarylogic Released v0.10.0
authored
193 before_save
194 after_save
72f3a21 @binarylogic Added AES256 as an option for crypto_providers
authored
195
1b98335 @binarylogic Initial commit
authored
196 before_update
197 after_update
72f3a21 @binarylogic Added AES256 as an option for crypto_providers
authored
198
1b98335 @binarylogic Initial commit
authored
199 before_validation
200 after_validation
dbd8b8f @binarylogic Release v1.2.0
authored
201
202 See Authlogic::Session::Callbacks for more information
203
43e849c @binarylogic Released v0.10.4
authored
204 == Multiple Sessions / Session Identifiers
205
206 You're asking: "why would I want multiple sessions?". Take this example:
207
208 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:
209
210 # regular user session
211 @user_session = UserSession.new
212 @user_session.id
213 # => nil
dbd8b8f @binarylogic Release v1.2.0
authored
214
43e849c @binarylogic Released v0.10.4
authored
215 # secure user session
216 @secure_user_session = UserSession.new(:secure)
217 @secure_user_session.id
218 # => :secure
219
220 This will keep everything separate. The :secure session will store its info in a separate cookie, separate session, etc. Just set the id and you are good to go. Need to retrieve the session?
221
222 @user_session = UserSession.find
223 @secure_user_session = UserSession.find(:secure)
224
c190c77 @binarylogic Forced logged_in and logged_out named scopes to use seconds for the limi...
authored
225 For more information on ids checkout Authlogic::Session::Base#id
43e849c @binarylogic Released v0.10.4
authored
226
d10f713 @binarylogic Added act_like_old_restful_authentication options for acts_as_authentic ...
authored
227 == Encryption methods
228
72f3a21 @binarylogic Added AES256 as an option for crypto_providers
authored
229 Authlogic is designed so you can use *any* encryption method you want. It delegates this task to a class of your choice. Authlogic comes preloaded with some common algorithms:
bd75ed0 @binarylogic Delegate human_attribute_name to ActiveRecord to gain I18n support
authored
230
231 1. Authlogic::CryptoProviders::Sha1 (used mainly for migrating from restful_authentication)
72f3a21 @binarylogic Added AES256 as an option for crypto_providers
authored
232 2. Authlogic::CryptoProviders::Sha512 (default)
233 3. Authlogic::CryptoProviders::BCrypt (requires bcrypt-ruby gem)
234 4. Authlogic::CryptoProviders::AES256 (requires you to supply a key, see the AES256 class in the docs for more info)
bd75ed0 @binarylogic Delegate human_attribute_name to ActiveRecord to gain I18n support
authored
235
236 By default Authlogic uses salted Sha512 with 20 stretches, but you can easily change this. For example, if you wanted to use the BCrypt algorithm just do the following:
d10f713 @binarylogic Added act_like_old_restful_authentication options for acts_as_authentic ...
authored
237
238 acts_as_authentic :crypto_provider => Authlogic::CryptoProviders::BCrypt
239
a623f67 @binarylogic Release v1.3.3
authored
240 For more information on BCrypt checkout my blog post on it: http://www.binarylogic.com/2008/11/22/storing-nuclear-launch-codes-in-your-app-enter-bcrypt-for-authlogic
241
72f3a21 @binarylogic Added AES256 as an option for crypto_providers
authored
242 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, all of the encryption and decryption logic is left to you.
a623f67 @binarylogic Release v1.3.3
authored
243
244 == Switching to a new encryption method
245
246 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:
247
248 acts_as_authentic :crypto_provider => Authlogic::CryptoProviders::BCrypt,
249 :transition_from_crypto_provider => Authlogic::CryptoProviders::Sha512
250
251 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.
d10f713 @binarylogic Added act_like_old_restful_authentication options for acts_as_authentic ...
authored
252
72f3a21 @binarylogic Added AES256 as an option for crypto_providers
authored
253 But wait, what if a couple of years later CCrypt comes out and its better than BCrypt and you're still in the middle of transitioning all of your users to BCrypt. Oh no!
254
255 Not to worry, because Authlogic can transition your users from more than one algorithm. Just pass an array to :transition_from_crypto_provider
256
257 acts_as_authentic :crypto_provider => CCrypt,
258 :transition_from_crypto_provider => [Authlogic::CryptoProviders::Sha512, Authlogic::CryptoProviders::BCrypt]
259
260 That's it, specify as many as you want. One thing to keep in mind here is that if you are using BCrypt you should never have to do this. All that you need to do is increase the cost to make the algorithm stronger, no need to jump to entirely new algorithm. I did this for example purposes only.
261
4caccd0 @binarylogic Released 1.2.1
authored
262 == Tokens (persistence, resetting passwords, private feed access, etc.)
dbd8b8f @binarylogic Release v1.2.0
authored
263
4caccd0 @binarylogic Released 1.2.1
authored
264 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:
dbd8b8f @binarylogic Release v1.2.0
authored
265
4caccd0 @binarylogic Released 1.2.1
authored
266 1. Regular account access
267 2. Access to reset their password
268 3. Access to a private feed
269 4. Access to confirm their account
dbd8b8f @binarylogic Release v1.2.0
authored
270
4caccd0 @binarylogic Released 1.2.1
authored
271 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.
dbd8b8f @binarylogic Release v1.2.0
authored
272
4caccd0 @binarylogic Released 1.2.1
authored
273 Here are the 3 tokens in more detail:
dbd8b8f @binarylogic Release v1.2.0
authored
274
72f3a21 @binarylogic Added AES256 as an option for crypto_providers
authored
275 === 1. Persistence token
ebdebfa @binarylogic Released v1.1.1
authored
276
4caccd0 @binarylogic Released 1.2.1
authored
277 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.
278
72f3a21 @binarylogic Added AES256 as an option for crypto_providers
authored
279 === 2. Single access token
4caccd0 @binarylogic Released 1.2.1
authored
280
049c048 @binarylogic Added check foreck for echoe gem if meta tasks are executed
authored
281 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.
4caccd0 @binarylogic Released 1.2.1
authored
282
283 This field is optional, if you want to use it just add the field to your database:
ebdebfa @binarylogic Released v1.1.1
authored
284
c190c77 @binarylogic Forced logged_in and logged_out named scopes to use seconds for the limi...
authored
285 t.string :single_access_token, :null => false
286 # or call it feeds_token, feed_token, or whatever you want with configuration
ebdebfa @binarylogic Released v1.1.1
authored
287
4caccd0 @binarylogic Released 1.2.1
authored
288 This is great for private feed access. So your URL to that user's private feed could look something like:
289
290 http://www.mydomain.com/account/feed.rss?single_access_token=4LiXF7FiGUppIPubBPey
291
292 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.
293
294 For more information see: Authlogic::ORMAdapters::ActiveRecordAdapter::ActsAsAuthentic::SingleAccess
295
72f3a21 @binarylogic Added AES256 as an option for crypto_providers
authored
296 === 3. Perishable token
4caccd0 @binarylogic Released 1.2.1
authored
297
298 This token is used for temporary account access, hence the term "perishable". This token is constantly changing, it changes...
299
300 1. In a before_validation in your model, so basically every time the record is saved
301 2. Any time a new session is successfully saved (aka logged in)
302
303 This is perfect for <b>resetting passwords</b> or <b>confirming accounts</b>. You email them a url with this token in it, and then use this token to find the record and perform your action.
304
305 This field is optional, if you want to use it just add the field to your database:
306
307 t.string :perishable_token, :null => false
308 # or call it password_reset_token, pw_reset_token, activation_token, or whatever you want with configuration
dbd8b8f @binarylogic Release v1.2.0
authored
309
4caccd0 @binarylogic Released 1.2.1
authored
310 Finding the record with this token couldn't be easier, Authlogic provides a special finder method that you can use. I highly recommend using it as it adds extra security:
dbd8b8f @binarylogic Release v1.2.0
authored
311
4caccd0 @binarylogic Released 1.2.1
authored
312 User.find_using_perishable_token(token)
313 User.find_using_perishable_token(token, 20.minutes)
ebdebfa @binarylogic Released v1.1.1
authored
314
4caccd0 @binarylogic Released 1.2.1
authored
315 That's all you need to do to locate the record. Here is what it does for extra security:
ebdebfa @binarylogic Released v1.1.1
authored
316
4caccd0 @binarylogic Released 1.2.1
authored
317 1. Ignores blank tokens all together. If a blank token is passed nil will be returned.
318 2. 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.
ebdebfa @binarylogic Released v1.1.1
authored
319
049c048 @binarylogic Added check foreck for echoe gem if meta tasks are executed
authored
320 Just like the single access token this uses a friendly token, so it is easier to email / copy and paste.
321
4caccd0 @binarylogic Released 1.2.1
authored
322 For a detailed tutorial on how to reset password using this token see the helpful links section above.
ebdebfa @binarylogic Released v1.1.1
authored
323
4caccd0 @binarylogic Released 1.2.1
authored
324 For more information see: Authlogic::ORMAdapters::ActiveRecordAdapter::ActsAsAuthentic::Perishability
ebdebfa @binarylogic Released v1.1.1
authored
325
43e849c @binarylogic Released v0.10.4
authored
326 == Scoping
327
328 Scoping with authentication is a little tricky because it can come in many different flavors:
329
330 1. Accounts have many users, meaning users can only belong to one account at a time.
331 2. Accounts have and belong to many users, meaning a user can belong to more than one account.
332 3. Users access their accounts via subdomains.
333 4. 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.
334
335 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:
336
337 1. The model (the validations, etc)
338 2. The session (finding the record)
339 3. The cookies (the names of the session key and cookie)
340
341 I will describe each below, in order.
342
343 === Scoping your model
344
345 This scopes your login field validation, so that users are allowed to have the same login, just not in the same account.
346
347 # app/models/user.rb
348 class User < ActiveRecord::Base
349 acts_as_authentic :scope => :account_id
350 end
351
352 === Scoping your session
353
2479aa0 @binarylogic Allow for login_count to be nil and initialize with 1
authored
354 When the session tries to validate it searches for a record. You want to scope that search. No problem...
43e849c @binarylogic Released v0.10.4
authored
355
356 The goal of Authlogic was to not try and introduce anything new. As a result I came up with:
357
358 @account.user_sessions.find
359 @account.user_sessions.create
360 @account.user_sessions.build
361 # ... etc
362
363 This works just like ActiveRecord, so it should come natural. Here is how you get this functionality:
364
365 class Account < ActiveRecord::Base
366 authenticates_many :user_sessions
367 end
368
369 === Scoping cookies
370
2479aa0 @binarylogic Allow for login_count to be nil and initialize with 1
authored
371 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.
43e849c @binarylogic Released v0.10.4
authored
372
2479aa0 @binarylogic Allow for login_count to be nil and initialize with 1
authored
373 But what if you *don't* want to separate your cookies by subdomains? You can accomplish this by doing:
43e849c @binarylogic Released v0.10.4
authored
374
c190c77 @binarylogic Forced logged_in and logged_out named scopes to use seconds for the limi...
authored
375 ActionController::Base.session_options[:session_domain] = '.mydomain.com'
43e849c @binarylogic Released v0.10.4
authored
376
377 If for some reason the above doesn't work for you, do some simple Google searches. There are a million blog posts on this.
378
379 Now let's look at this from the other angle. What if you are *NOT* using subdomains, but still want to separate cookies for each account. Simple, set the :scope_cookies option for authenticate_many:
380
381 class Account < ActiveRecord::Base
382 authenticates_many :user_sessions, :scope_cookies => true
383 end
384
385 Done, Authlogic will give each cookie a unique name depending on the account.
386
2479aa0 @binarylogic Allow for login_count to be nil and initialize with 1
authored
387 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.
1b98335 @binarylogic Initial commit
authored
388
35f14ba @binarylogic Released v0.10.0
authored
389 == Errors
390
43e849c @binarylogic Released v0.10.4
authored
391 The errors in Authlogic work JUST LIKE ActiveRecord. In fact, it uses the exact same ActiveRecord errors class. Use it the same way:
35f14ba @binarylogic Released v0.10.0
authored
392
393 class UserSession
394 before_validation :check_if_awesome
395
396 private
397 def check_if_awesome
398 errors.add(:login, "must contain awesome") if login && !login.include?("awesome")
399 errors.add_to_base("You must be awesome to log in") unless record.awesome?
400 end
401 end
402
1b98335 @binarylogic Initial commit
authored
403 == Automatic Session Updating
404
4b1f8fa @binarylogic User column_names instead of colums when determining if a column exists
authored
405 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.
718f2cf @binarylogic Updated readme on session updating
authored
406
72f3a21 @binarylogic Added AES256 as an option for crypto_providers
authored
407 Just to clear up any confusion, Authlogic stores both the record id and the persistence token in the session. Why? So stale sessions can not be persisted. It stores the id so it can quickly find the record, and the persistence token to ensure no sessions are stale. The persistence token changes with the password, if someone is logged in and their password is changed, they should be logged out, unless they made the change. That being said, the person making the change needs their session to be updated with the new persistence token, so they stay logged in, which is what this section is all about.
20fcb6f @binarylogic Bumped to Sha512
authored
408
409 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.
718f2cf @binarylogic Updated readme on session updating
authored
410
43e849c @binarylogic Released v0.10.4
authored
411 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.
718f2cf @binarylogic Updated readme on session updating
authored
412
ec0eb78 @binarylogic Updated readme
authored
413 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.
718f2cf @binarylogic Updated readme on session updating
authored
414
34b225c @binarylogic Updated readme
authored
415 Here is basically how this is done....
1b98335 @binarylogic Initial commit
authored
416
34b225c @binarylogic Updated readme
authored
417 class User < ActiveRecord::Base
ec0eb78 @binarylogic Updated readme
authored
418 after_save :maintain_sessions!
34b225c @binarylogic Updated readme
authored
419
420 private
ec0eb78 @binarylogic Updated readme
authored
421 def maintain_sessions!
72f3a21 @binarylogic Added AES256 as an option for crypto_providers
authored
422 # If we aren't logged in and a user is created, log them in as that user
c190c77 @binarylogic Forced logged_in and logged_out named scopes to use seconds for the limi...
authored
423 # If we aren't logged in and a user's password changes, log them in as that user
424 # If we are logged in and they change their password, update the session so they remain logged in
34b225c @binarylogic Updated readme
authored
425 end
426 end
427
72f3a21 @binarylogic Added AES256 as an option for crypto_providers
authored
428 Obviously there is a little more to it than this, but hopefully this clarifies any confusion. Basically if you are *logged out* and you are changing passwords, Authlogic will log you in, since you already know the password for that account. Lastly, this can be altered / disabled via a configuration option. Just set :session_ids => nil when calling acts_as_authentic.
1b98335 @binarylogic Initial commit
authored
429
430 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!
431
791f700 @binarylogic Released v1.0.0 (see changelog)
authored
432 == Framework agnostic (Rails, Merb, etc.)
35f14ba @binarylogic Released v0.10.0
authored
433
791f700 @binarylogic Released v1.0.0 (see changelog)
authored
434 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.
435
72f3a21 @binarylogic Added AES256 as an option for crypto_providers
authored
436 Since pretty much all of the frameworks in ruby follow the Rack standards, the code should be very similar across adapters. In fact that abstract adapter assumes you are following the Rack standards. If your framework is following the rack standards, there really isn't any code you should have to write. Check out the merb_adapter to see for yourself, the merb adapter is basically blank. 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? Also when we have access to the controller object we can do other nifty things. Checkout the OpenID tutorial in the helpful links section above to see what I mean.
791f700 @binarylogic Released v1.0.0 (see changelog)
authored
437
438 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.
35f14ba @binarylogic Released v0.10.0
authored
439
1b98335 @binarylogic Initial commit
authored
440 == How it works
441
72f3a21 @binarylogic Added AES256 as an option for crypto_providers
authored
442 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.
1b98335 @binarylogic Initial commit
authored
443
77798f2 @binarylogic Updated installation guide
authored
444 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.
1b98335 @binarylogic Initial commit
authored
445
b49258f @binarylogic Updated readme
authored
446 == What's wrong with the current solutions?
2155477 @binarylogic Updated readme
authored
447
448 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.
449
43e849c @binarylogic Released v0.10.4
authored
450 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...
2155477 @binarylogic Updated readme
authored
451
ec0eb78 @binarylogic Updated readme
authored
452 === Generators are messy
2155477 @binarylogic Updated readme
authored
453
791f700 @binarylogic Released v1.0.0 (see changelog)
authored
454 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.
2155477 @binarylogic Updated readme
authored
455
a03f931 @binarylogic Fix readme errors
authored
456 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.
2155477 @binarylogic Updated readme
authored
457
43e849c @binarylogic Released v0.10.4
authored
458 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.
832b7f0 @binarylogic Cleaned up readme
authored
459
ec0eb78 @binarylogic Updated readme
authored
460 Lastly, there is a pattern here, why clutter up all of your applications with the same code over and over?
2155477 @binarylogic Updated readme
authored
461
dbd8b8f @binarylogic Release v1.2.0
authored
462 === Why test the same code over and over?
c190c77 @binarylogic Forced logged_in and logged_out named scopes to use seconds for the limi...
authored
463
464 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.
465
2155477 @binarylogic Updated readme
authored
466 === Limited to a single authentication
467
43e849c @binarylogic Released v0.10.4
authored
468 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.
2155477 @binarylogic Updated readme
authored
469
832b7f0 @binarylogic Cleaned up readme
authored
470 === Too presumptuous
471
4d42802 @binarylogic Ignore invalid credential fields, dont raise an exception
authored
472 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.
832b7f0 @binarylogic Cleaned up readme
authored
473
ec0eb78 @binarylogic Updated readme
authored
474 === Disclaimer
475
72f3a21 @binarylogic Added AES256 as an option for crypto_providers
authored
476 I am not trying to "bash" any other authentication solutions. These are just my opinions, formulate your own opinion. I released Authlogic because I was "scratching my own itch". It has made my life easier and I enjoy using it, hopefully it does the same for you.
ec0eb78 @binarylogic Updated readme
authored
477
1b98335 @binarylogic Initial commit
authored
478
479 Copyright (c) 2008 Ben Johnson of [Binary Logic](http://www.binarylogic.com), released under the MIT license
Something went wrong with that request. Please try again.