Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 262 lines (173 sloc) 15.3 kb
1b98335 Ben Johnson Initial commit
authored
1 = Authgasm
2
e77ca8a Ben Johnson Updated readme
authored
3 Authgasm is "rails authentication done right"
1b98335 Ben Johnson Initial commit
authored
4
832b7f0 Ben Johnson Cleaned up readme
authored
5 The last thing we need is another authentication solution for rails, right? That's what I thought until I tried out some of the current solutions. 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 rails we all fell in love with. We need a "rails like" authentication solution. Authgasm is my attempt to satisfy that need...
ae1d3bb Ben Johnson Released v0.9.1
authored
6
7 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 in rails.
1b98335 Ben Johnson Initial commit
authored
8
2155477 Ben Johnson Updated readme
authored
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?
10
34b225c Ben Johnson Updated readme
authored
11 What if creating a user session could be as simple as...
e77ca8a Ben Johnson Updated readme
authored
12
4b1f8fa Ben Johnson User column_names instead of colums when determining if a column exists
authored
13 UserSession.create(params[:user_session])
e77ca8a Ben Johnson Updated readme
authored
14
34b225c Ben Johnson Updated readme
authored
15 What if your user sessions controller could look just like your other controllers...
1b98335 Ben Johnson Initial commit
authored
16
17 class UserSessionsController < ApplicationController
18 def new
19 @user_session = UserSession.new
20 end
21
22 def create
23 @user_session = UserSession.new(params[:user_session])
35f14ba Ben Johnson Released v0.10.0
authored
24 if @user_session.save
c93bec2 Ben Johnson Changed scope to id
authored
25 redirect_to account_url
1b98335 Ben Johnson Initial commit
authored
26 else
27 render :action => :new
28 end
29 end
30
31 def destroy
32 @user_session.destroy
33 end
34 end
35
24501b4 Ben Johnson Release v0.10.2
authored
36 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 Ben Johnson Initial commit
authored
37
38 <%= error_messages_for "user_session" %>
39 <% form_for @user_session do |f| %>
40 <%= f.label :login %><br />
41 <%= f.text_field :login %><br />
42 <br />
43 <%= f.label :password %><br />
44 <%= f.password_field :password %><br />
45 <br />
46 <%= f.submit "Login" %>
47 <% end %>
48
34b225c Ben Johnson Updated readme
authored
49 Or how about persisting the session...
1b98335 Ben Johnson Initial commit
authored
50
51 class ApplicationController
52 before_filter :load_user
53
54 protected
55 def load_user
56 @user_session = UserSession.find
57 @current_user = @user_session && @user_session.record
58 end
59 end
60
34b225c Ben Johnson Updated readme
authored
61 Authgasm makes this a reality. This is just the tip of the ice berg. Keep reading to find out everything Authgasm can do.
1b98335 Ben Johnson Initial commit
authored
62
63 == Helpful links
64
65 * <b>Documentation:</b> http://authgasm.rubyforge.org
66 * <b>Authgasm tutorial:</b> coming soon...
67 * <b>Live example of the tutorial above (with source):</b> coming soon....
68 * <b>Bugs / feature suggestions:</b> http://binarylogic.lighthouseapp.com/projects/18752-authgasm
69
70 == Install and use
71
72 === Install the gem / plugin
73
74 $ sudo gem install authgasm
75 $ cd vendor/plugins
76 $ sudo gem unpack authgasm
77
78 Or as a plugin
79
80 script/plugin install git://github.com/binarylogic/authgasm.git
81
77798f2 Ben Johnson Updated installation guide
authored
82 === Create your session
1b98335 Ben Johnson Initial commit
authored
83
77798f2 Ben Johnson Updated installation guide
authored
84 For this walk through lets assume you are setting up a session for your User model.
1b98335 Ben Johnson Initial commit
authored
85
77798f2 Ben Johnson Updated installation guide
authored
86 Create your user_session.rb file:
1b98335 Ben Johnson Initial commit
authored
87
77798f2 Ben Johnson Updated installation guide
authored
88 # app/models/user_session.rb
89 class UserSession < Authgasm::Session::Base
90 # configuration here, just like ActiveRecord, or in an initializer
91 # See Authgasm::Session::Config::ClassMethods for more details
92 end
1b98335 Ben Johnson Initial commit
authored
93
ae1d3bb Ben Johnson Released v0.9.1
authored
94 It is important to set your configuration for your session before you set the configuration for your model. This will save you some time. Your model will try to guess its own configuration based on what you set in the session. These are completely separate, making Authgasm as flexible as it needs to be, but the majority of the time they will be the same and no one likes to repeat their self.
1b98335 Ben Johnson Initial commit
authored
95
3691177 Ben Johnson Updated readme
authored
96 === Ensure proper database fields
1b98335 Ben Johnson Initial commit
authored
97
832b7f0 Ben Johnson Cleaned up readme
authored
98 The user model needs to have the following columns. The names of these columns can be changed with configuration. Better yet, Authgasm tries to guess these names by checking for the existence of common names. See Authgasm::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.
1b98335 Ben Johnson Initial commit
authored
99
100 t.string :login, :null => false
101 t.string :crypted_password, :null => false
102 t.string :password_salt, :null => false # not needed if you are encrypting your pw instead of using a hash algorithm
103 t.string :remember_token, :null => false
c00672f Ben Johnson Updated automatic session maintenance
authored
104 t.integer :login_count # This is optional, it is a "magic" column, just like "created_at". See below for a list of all magic columns.
1b98335 Ben Johnson Initial commit
authored
105
77798f2 Ben Johnson Updated installation guide
authored
106 === Set up your model
1b98335 Ben Johnson Initial commit
authored
107
77798f2 Ben Johnson Updated installation guide
authored
108 Make sure you have a model that you will be authenticating with. For this example let's say you have a User model:
109
110 class User < ActiveRecord::Base
111 acts_as_authentic # for options see documentation: Authgasm::ActsAsAuthentic::ClassMethods
1b98335 Ben Johnson Initial commit
authored
112 end
113
114 Done! Now go use it just like you would with any other ActiveRecord model (see above).
115
116 == Magic Columns
117
118 Just like ActiveRecord has "magic" columns, such as: created_at and updated_at. Authgasm has its own "magic" columns too:
119
120 Column name Description
ae1d3bb Ben Johnson Released v0.9.1
authored
121 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 Ben Johnson Updated readme
authored
122 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 Ben Johnson Initial commit
authored
123 current_login_at Updates with the current time when an explicit login is made.
124 last_login_at Updates with the value of current_login_at before it is reset.
125 current_login_ip Updates with the request remote_ip when an explicit login is made.
126 last_login_ip Updates with the value of current_login_ip before it is reset.
127
128 == Magic States
129
130 Authgasm 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:
131
132 Method name Description
2155477 Ben Johnson Updated readme
authored
133 active? Is the record marked as active?
1b98335 Ben Johnson Initial commit
authored
134 approved? Has the record been approved?
135 confirmed? Has the record been conirmed?
136
ff67374 Ben Johnson Cleaned up identifier doc
authored
137 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 Ben Johnson Initial commit
authored
138
35f14ba Ben Johnson Released v0.10.0
authored
139 Need Authgasm to check your own "state"? No problem, check out the hooks section below. Add in a before_validation or after_validation to do your own checking.
140
1b98335 Ben Johnson Initial commit
authored
141 == Hooks / Callbacks
142
143 Just like ActiveRecord you can create your own hooks / callbacks so that you can do whatever you want when certain actions are performed. Here they are:
144
145 before_create
146 after_create
147 before_destroy
148 after_destroy
35f14ba Ben Johnson Released v0.10.0
authored
149 before_save
150 after_save
1b98335 Ben Johnson Initial commit
authored
151 before_update
152 after_update
153 before_validation
154 after_validation
155
35f14ba Ben Johnson Released v0.10.0
authored
156 == Errors
157
158 The errors in Authgasm work JUST LIKE ActiveRecord. In fact, it uses the exact same ActiveRecord errors class. Use it the same way:
159
160 class UserSession
161 before_validation :check_if_awesome
162
163 private
164 def check_if_awesome
165 errors.add(:login, "must contain awesome") if login && !login.include?("awesome")
166 errors.add_to_base("You must be awesome to log in") unless record.awesome?
167 end
168 end
169
1b98335 Ben Johnson Initial commit
authored
170 == Automatic Session Updating
171
4b1f8fa Ben Johnson User column_names instead of colums when determining if a column exists
authored
172 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 Ben Johnson Updated readme on session updating
authored
173
20fcb6f Ben Johnson Bumped to Sha512
authored
174 Just to clear up any confusion, Authgasm 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.
175
176 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 Ben Johnson Updated readme on session updating
authored
177
34b225c Ben Johnson Updated readme
authored
178 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 Authgasm can, and you can access Authgasm 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 Ben Johnson Updated readme on session updating
authored
179
34b225c Ben Johnson Updated readme
authored
180 Fear not, because the acts_as_authentic method you call in your model takes care of this for you, by adding an after_create and after_update 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 Ben Johnson Updated readme on session updating
authored
181
34b225c Ben Johnson Updated readme
authored
182 Here is basically how this is done....
1b98335 Ben Johnson Initial commit
authored
183
34b225c Ben Johnson Updated readme
authored
184 class User < ActiveRecord::Base
185 after_create :create_sessions!
186 after_update :update_sessions!
187
188 private
189 def create_sessions!
190 # create a new UserSession if they are not logged in
191 end
192
193 def update_sessions!
194 # find their session
195 # check that their session's record is the same one as this one: session.record == self
196 # update the session with the new info: session.update
197 end
198 end
199
ae1d3bb Ben Johnson Released v0.9.1
authored
200 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.
1b98335 Ben Johnson Initial commit
authored
201
202 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!
203
ff67374 Ben Johnson Cleaned up identifier doc
authored
204 == Multiple Sessions / Session Identifiers
bf796a0 Ben Johnson Added info in the readme on multiple sessions
authored
205
206 You're asking: "why would I want multiple sessions?". Take this example:
207
35f14ba Ben Johnson Released v0.10.0
authored
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:
bf796a0 Ben Johnson Added info in the readme on multiple sessions
authored
209
210 # regular user session
211 @user_session = UserSession.new
212 @user_session.id
213 # => nil
214
215 # secure user session
216 @secure_user_session = UserSession.new(:secure)
217 @secure_user_session.id
218 # => :secure
219
7c5c3cb Ben Johnson Added info in the readme on multiple sessions
authored
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
225 For more information on ids checkout Authgasm::Session::Base#initialize
bf796a0 Ben Johnson Added info in the readme on multiple sessions
authored
226
35f14ba Ben Johnson Released v0.10.0
authored
227 == What about [insert framework here]?
228
229 As of now, authgasm supports rails right out of the box. But I designed authgasm to be framework agnostic. The only thing stopping Authgasm from being implemented in merb, or any other framework, is a simple adapter. I have not had the opportunity to use Authgasm in anything other than rails. If you want to use this in merb or any other framework take a look at authgasm/controller/rails_adapter.rb.
230
1b98335 Ben Johnson Initial commit
authored
231 == How it works
232
35f14ba Ben Johnson Released v0.10.0
authored
233 Interested in how all of this all works? Basically a before_filter is automatically set in your controller which lets Authgasm know about the current controller object. This allows Authgasm to set sessions, cookies, login via basic http auth, etc. If you are using rails in a multiple thread environment, don't worry. I kept that in mind and made this thread safe.
1b98335 Ben Johnson Initial commit
authored
234
77798f2 Ben Johnson Updated installation guide
authored
235 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 Ben Johnson Initial commit
authored
236
b49258f Ben Johnson Updated readme
authored
237 == What's wrong with the current solutions?
2155477 Ben Johnson Updated readme
authored
238
239 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.
240
832b7f0 Ben Johnson Cleaned up readme
authored
241 I don't necessarily think the current solutions are "wrong", nor am I saying Authgasm is the answer to your prayers. But, to me, the current solutions were lacking something. Here's what I came up with...
2155477 Ben Johnson Updated readme
authored
242
9f0ec4f Ben Johnson Released v0.10.0
authored
243 === Generators are not the answer
2155477 Ben Johnson Updated readme
authored
244
832b7f0 Ben Johnson Cleaned up readme
authored
245 Generators have their place, and it is not to add authentication to a rails 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 Ben Johnson Updated readme
authored
246
832b7f0 Ben Johnson Cleaned up readme
authored
247 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! Awesome! The cherry on top is the fact that you get to go through every app you've made and apply this update. You don't really have a choice either, because you can't ignore security updates.
2155477 Ben Johnson Updated readme
authored
248
832b7f0 Ben Johnson Cleaned up readme
authored
249 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 Authgasm, 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.
250
251 Lastly, there is a pattern here, why clutter up all of your applications with the same code? I recently switched over one of my apps to Authgasm and its amazing how much cleaner my app feels.
2155477 Ben Johnson Updated readme
authored
252
253 === Limited to a single authentication
254
3f5055e Ben Johnson Added stretches to the crypto provider
authored
255 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 Authgasm. Authgasm 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 Ben Johnson Updated readme
authored
256
832b7f0 Ben Johnson Cleaned up readme
authored
257 === Too presumptuous
258
4d42802 Ben Johnson Ignore invalid credential fields, dont raise an exception
authored
259 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 Ben Johnson Cleaned up readme
authored
260
1b98335 Ben Johnson Initial commit
authored
261
262 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.