authgasm 0.10.1 → 0.10.2

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.rdoc CHANGED
@@ -1,3 +1,9 @@
1
+ == 0.10.2 released 2008-10-24
2
+
3
+ * Added in stretches to the default Sha512 encryption algorithm.
4
+ * Use column_names instead of columns when determining if a column is present.
5
+ * Improved validation callbacks. after_validation should only be run if valid? = true. Also clear errors before the "before_validation" callback.
6
+
1
7
  == 0.10.1 released 2008-10-24
2
8
 
3
9
  * Sessions now store the "remember token" instead of the id. This is much safer and guarantees all "sessions" that are logged in are logged in with a valid password. This way stale sessions can't be persisted.
data/README.rdoc CHANGED
@@ -10,7 +10,7 @@ Wouldn't it be nice to keep your app up to date with the latest and greatest sec
10
10
 
11
11
  What if creating a user session could be as simple as...
12
12
 
13
- UserSession.create(params[:user])
13
+ UserSession.create(params[:user_session])
14
14
 
15
15
  What if your user sessions controller could look just like your other controllers...
16
16
 
@@ -33,7 +33,7 @@ What if your user sessions controller could look just like your other controller
33
33
  end
34
34
  end
35
35
 
36
- Look familiar? If you didn't know any better, you would think UserSession was an ActiveRecord model. I think that's pretty cool. Why is that cool? Because it fits nicely into the RESTful development pattern and its a style we all know and love. Wouldn't this be cool too...
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...
37
37
 
38
38
  <%= error_messages_for "user_session" %>
39
39
  <% form_for @user_session do |f| %>
@@ -95,7 +95,7 @@ It is important to set your configuration for your session before you set the co
95
95
 
96
96
  === Ensure proper database fields
97
97
 
98
- The user model needs to have the following columns. The names of these columns can be changed with configuration.
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.
99
99
 
100
100
  t.string :login, :null => false
101
101
  t.string :crypted_password, :null => false
@@ -169,7 +169,7 @@ The errors in Authgasm work JUST LIKE ActiveRecord. In fact, it uses the exact s
169
169
 
170
170
  == Automatic Session Updating
171
171
 
172
- This is one of my favorite features that I think its pretty cool. It's things like this that make a library great and let you know you are on the right track.
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.
173
173
 
174
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
175
 
@@ -244,13 +244,13 @@ I don't necessarily think the current solutions are "wrong", nor am I saying Aut
244
244
 
245
245
  Generators have their place, and it certainly 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.
246
246
 
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 litter your application with code that you get to maintain. You get to make sure it stays up with the latest and greatest security techniques. How fun! Oh, 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. When ActiveRecord releases an update do you go through it line by line and manually apply it in each one of your apps? No.
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 litter your application with code that you get to maintain. You get to make sure it stays up with the latest and greatest security techniques. How fun! Oh, 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.
248
248
 
249
249
  Security moves fast, and hackers make sure of this. As a result, it should be easy to update. Doesn't it make sense to leverage a library to handle this functionality for you? This way, when some new security technique is released, or a bug with your authentication system is found, you can fix it with a simple update. Just like everything else in ruby / rails.
250
250
 
251
251
  === Limited to a single authentication
252
252
 
253
- 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 make 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.
253
+ 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.
254
254
 
255
255
 
256
256
  Copyright (c) 2008 Ben Johnson of [Binary Logic](http://www.binarylogic.com), released under the MIT license
data/authgasm.gemspec CHANGED
@@ -1,18 +1,18 @@
1
1
 
2
- # Gem::Specification for Authgasm-0.10.1
2
+ # Gem::Specification for Authgasm-0.10.2
3
3
  # Originally generated by Echoe
4
4
 
5
5
  --- !ruby/object:Gem::Specification
6
6
  name: authgasm
7
7
  version: !ruby/object:Gem::Version
8
- version: 0.10.1
8
+ version: 0.10.2
9
9
  platform: ruby
10
10
  authors:
11
11
  - Ben Johnson of Binary Logic
12
12
  autorequire:
13
13
  bindir: bin
14
14
 
15
- date: 2008-10-28 00:00:00 -04:00
15
+ date: 2008-10-29 00:00:00 -04:00
16
16
  default_executable:
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
@@ -7,32 +7,33 @@ module Authgasm
7
7
  # = Acts As Authentic
8
8
  # Provides and "acts_as" method to include in your models to help with authentication. See method below.
9
9
  module ClassMethods
10
- # Call this method in your model to add in basic authentication madness:
10
+ # Call this method in your model to add in basic authentication madness that your authgasm session expects.
11
11
  #
12
- # 1. Adds various validations for the login field
13
- # 2. Adds various validations for the password field
14
- # 3. Handles password encryption
15
- # 4. Adds usefule methods to dealing with authentication
12
+ # <b>Please keep in mind</b> that based on your configuration the method names could change. For example, if you pass the option:
13
+ #
14
+ # :password_field => :pass
15
+ #
16
+ # The method will not be password=, it will be pass=. Same with valid_password?, it will be valid_pass?, etc.
16
17
  #
17
18
  # === Methods
18
19
  # For example purposes lets assume you have a User model.
19
20
  #
20
21
  # Class method name Description
21
- # User.unique_token returns unique token generated by your :crypto_provider
22
22
  # User.crypto_provider The class that you set in your :crypto_provider option
23
- # User.forget_all! Resets all records so they will not be remembered on their next visit. Basically makes their cookies invalid
23
+ # User.forget_all! Finds all records, loops through them, and calls forget! on each record. This is paginated to save on memory.
24
+ # User.unique_token returns unique token generated by your :crypto_provider
24
25
  #
25
26
  # Named Scopes
26
- # User.logged_in Find all users who are logged in, based on your :logged_in_timeout option
27
- # User.logged_out Same as above, but logged out
27
+ # User.logged_in Find all users who are logged in, based on your :logged_in_timeout option.
28
+ # User.logged_out Same as above, but logged out.
28
29
  #
29
30
  # Isntace method name
30
- # user.password= Method name based on the :password_field option. This is used to set the password. Pass the *raw* password to this
31
- # user.confirm_password= Confirms the password, needed to change the password
32
- # user.valid_password?(pass) Based on the valid of :password_field. Determines if the password passed is valid. The password could be encrypted or raw.
33
- # user.randomize_password! Basically resets the password to a random password using only letters and numbers
34
- # user.logged_in? Based on the :logged_in_timeout option. Tells you if the user is logged in or not
35
- # user.forget! Changes their remember token, making their cookie invalid.
31
+ # user.password= Method name based on the :password_field option. This is used to set the password. Pass the *raw* password to this.
32
+ # user.confirm_password= Confirms the password, needed to change the password.
33
+ # user.valid_password?(pass) Determines if the password passed is valid. The password could be encrypted or raw.
34
+ # user.randomize_password! Basically resets the password to a random password using only letters and numbers.
35
+ # user.logged_in? Based on the :logged_in_timeout option. Tells you if the user is logged in or not.
36
+ # user.forget! Changes their remember token, making their cookie and session invalid. A way to log the user out withouth changing their password.
36
37
  #
37
38
  # === Options
38
39
  # * <tt>session_class:</tt> default: "#{name}Session", the related session class. Used so that you don't have to repeat yourself here. A lot of the configuration will be based off of the configuration values of this class.
@@ -55,15 +56,15 @@ module Authgasm
55
56
  options[:login_field_type] ||= options[:login_field] == :email ? :email : :login
56
57
  options[:password_field] ||= options[:session_class].password_field
57
58
  options[:crypted_password_field] ||=
58
- (columns.include?("crypted_password") && :crypted_password) ||
59
- (columns.include?("encrypted_password") && :encrypted_password) ||
60
- (columns.include?("password_hash") && :password_hash) ||
61
- (columns.include?("pw_hash") && :pw_hash) ||
59
+ (column_names.include?("crypted_password") && :crypted_password) ||
60
+ (column_names.include?("encrypted_password") && :encrypted_password) ||
61
+ (column_names.include?("password_hash") && :password_hash) ||
62
+ (column_names.include?("pw_hash") && :pw_hash) ||
62
63
  :crypted_password
63
64
  options[:password_salt_field] ||=
64
- (columns.include?("password_salt") && :password_salt) ||
65
- (columns.include?("pw_salt") && :pw_salt) ||
66
- (columns.include?("salt") && :salt) ||
65
+ (column_names.include?("password_salt") && :password_salt) ||
66
+ (column_names.include?("pw_salt") && :pw_salt) ||
67
+ (column_names.include?("salt") && :salt) ||
67
68
  :password_salt
68
69
  options[:remember_token_field] ||= options[:session_class].remember_token_field
69
70
  options[:logged_in_timeout] ||= 10.minutes
@@ -117,7 +118,7 @@ module Authgasm
117
118
  i = 0
118
119
  begin
119
120
  records = find(:all, :limit => 50, :offset => i)
120
- records.each { |record| records.update_attribute(:#{options[:remember_token_field]}, unique_token) }
121
+ records.each { |record| record.forget! }
121
122
  i += 50
122
123
  end while !records.blank?
123
124
  end
@@ -210,7 +211,7 @@ module Authgasm
210
211
  end
211
212
 
212
213
  def find_my_sessions
213
- return if @saving_from_session || !#{options[:session_class]}.activated?
214
+ return if @saving_from_session || !#{options[:session_class]}.activated? || #{options[:session_ids].inspect}.blank?
214
215
 
215
216
  @my_sessions = []
216
217
  #{options[:session_ids].inspect}.each do |session_id|
@@ -224,7 +225,7 @@ module Authgasm
224
225
  end
225
226
 
226
227
  def update_sessions!
227
- return if @saving_from_session || !#{options[:session_class]}.activated?
228
+ return if @saving_from_session || @my_sessions.blank?
228
229
 
229
230
  @my_sessions.each do |stale_session|
230
231
  stale_session.unauthorized_record = self
@@ -257,51 +257,12 @@ module Authgasm
257
257
 
258
258
  def valid?
259
259
  errors.clear
260
- temp_record = unauthorized_record
261
-
262
- case login_with
263
- when :credentials
264
- errors.add(login_field, "can not be blank") if send(login_field).blank?
265
- errors.add(password_field, "can not be blank") if send("protected_#{password_field}").blank?
266
- return false if errors.count > 0
267
-
268
- temp_record = klass.send(find_by_login_method, send(login_field))
269
-
270
- if temp_record.blank?
271
- errors.add(login_field, "was not found")
272
- return false
273
- end
274
-
275
- unless temp_record.send(verify_password_method, send("protected_#{password_field}"))
276
- errors.add(password_field, "is invalid")
277
- return false
278
- end
279
- when :unauthorized_record
280
- if temp_record.blank?
281
- errors.add_to_base("You can not log in with a blank record.")
282
- return false
283
- end
284
-
285
- if temp_record.new_record?
286
- errors.add_to_base("You can not login with a new record.") if temp_record.new_record?
287
- return false
288
- end
289
- else
290
- errors.add_to_base("You must provide some form of credentials before logging in.")
291
- return false
260
+ temp_record = validate_credentials
261
+ if errors.empty?
262
+ @record = temp_record
263
+ return true
292
264
  end
293
-
294
- [:active, :approved, :confirmed].each do |required_status|
295
- if temp_record.respond_to?("#{required_status}?") && !temp_record.send("#{required_status}?")
296
- errors.add_to_base("Your account has not been marked as #{required_status}")
297
- return false
298
- end
299
- end
300
-
301
- # All is good, lets set the record
302
- @record = temp_record
303
-
304
- true
265
+ false
305
266
  end
306
267
 
307
268
  def valid_http_auth?
@@ -397,6 +358,51 @@ module Authgasm
397
358
  def update_session!
398
359
  controller.session[session_key] = record && record.send(remember_token_field)
399
360
  end
361
+
362
+ def validate_credentials
363
+ temp_record = unauthorized_record
364
+
365
+ case login_with
366
+ when :credentials
367
+ errors.add(login_field, "can not be blank") if send(login_field).blank?
368
+ errors.add(password_field, "can not be blank") if send("protected_#{password_field}").blank?
369
+ return if errors.count > 0
370
+
371
+ temp_record = klass.send(find_by_login_method, send(login_field))
372
+
373
+ if temp_record.blank?
374
+ errors.add(login_field, "was not found")
375
+ return
376
+ end
377
+
378
+ unless temp_record.send(verify_password_method, send("protected_#{password_field}"))
379
+ errors.add(password_field, "is invalid")
380
+ return
381
+ end
382
+ when :unauthorized_record
383
+ if temp_record.blank?
384
+ errors.add_to_base("You can not log in with a blank record.")
385
+ return
386
+ end
387
+
388
+ if temp_record.new_record?
389
+ errors.add_to_base("You can not login with a new record.") if temp_record.new_record?
390
+ return
391
+ end
392
+ else
393
+ errors.add_to_base("You must provide some form of credentials before logging in.")
394
+ return
395
+ end
396
+
397
+ [:active, :approved, :confirmed].each do |required_status|
398
+ if temp_record.respond_to?("#{required_status}?") && !temp_record.send("#{required_status}?")
399
+ errors.add_to_base("Your account has not been marked as #{required_status}")
400
+ return
401
+ end
402
+ end
403
+
404
+ temp_record
405
+ end
400
406
  end
401
407
  end
402
408
  end
@@ -7,7 +7,7 @@ module Authgasm
7
7
  CALLBACKS = %w(before_create after_create before_destroy after_destroy before_save after_save before_update after_update before_validation after_validation)
8
8
 
9
9
  def self.included(base) #:nodoc:
10
- [:destroy, :save, :valid?].each do |method|
10
+ [:destroy, :save, :valid?, :validate_credentials].each do |method|
11
11
  base.send :alias_method_chain, method, :callbacks
12
12
  end
13
13
 
@@ -41,15 +41,16 @@ module Authgasm
41
41
  result
42
42
  end
43
43
 
44
- def valid_with_callbacks? # :nodoc:
45
- run_callbacks(:before_validation)
44
+ def valid_with_callbacks?
46
45
  result = valid_without_callbacks?
47
- if result
48
- run_callbacks(:after_validation)
49
- result = errors.empty?
50
- end
46
+ run_callbacks(:after_validation) if result
51
47
  result
52
48
  end
49
+
50
+ def validate_credentials_with_callbacks # :nodoc:
51
+ run_callbacks(:before_validation)
52
+ validate_credentials_without_callbacks
53
+ end
53
54
  end
54
55
  end
55
56
  end
@@ -91,7 +91,7 @@ module Authgasm
91
91
  # * <tt>Default:</tt> Guesses based on the model columns, tries login, username, and email. If none are present it defaults to login
92
92
  # * <tt>Accepts:</tt> Symbol or String
93
93
  def login_field
94
- @login_field ||= (klass.columns.include?("login") && :login) || (klass.columns.include?("username") && :username) || (klass.columns.include?("email") && :email) || :login
94
+ @login_field ||= (klass.column_names.include?("login") && :login) || (klass.column_names.include?("username") && :username) || (klass.column_names.include?("email") && :email) || :login
95
95
  end
96
96
  attr_writer :login_field
97
97
 
@@ -100,7 +100,7 @@ module Authgasm
100
100
  # * <tt>Default:</tt> Guesses based on the model columns, tries password and pass. If none are present it defaults to password
101
101
  # * <tt>Accepts:</tt> Symbol or String
102
102
  def password_field
103
- @password_field ||= (klass.columns.include?("password") && :password) || (klass.columns.include?("pass") && :pass) || :password
103
+ @password_field ||= (klass.column_names.include?("password") && :password) || (klass.column_names.include?("pass") && :pass) || :password
104
104
  end
105
105
  attr_writer :password_field
106
106
 
@@ -126,10 +126,10 @@ module Authgasm
126
126
  # * <tt>Accepts:</tt> Symbol or String
127
127
  def remember_token_field
128
128
  @remember_token_field ||=
129
- (klass.columns.include?("remember_token") && :remember_token) ||
130
- (klass.columns.include?("remember_key") && :remember_key) ||
131
- (klass.columns.include?("cookie_token") && :cookie_token) ||
132
- (klass.columns.include?("cookie_key") && :cookie_key) ||
129
+ (klass.column_names.include?("remember_token") && :remember_token) ||
130
+ (klass.column_names.include?("remember_key") && :remember_key) ||
131
+ (klass.column_names.include?("cookie_token") && :cookie_token) ||
132
+ (klass.column_names.include?("cookie_key") && :cookie_key) ||
133
133
  :remember_token
134
134
  end
135
135
  attr_writer :remember_token_field
@@ -6,8 +6,11 @@ module Authgasm
6
6
  #
7
7
  # If you are encrypting via a hash just don't include a decrypt method, since hashes can't be decrypted. Authgasm will notice this adjust accordingly.
8
8
  class Sha512CryptoProvider
9
+ STRETCHES = 20
9
10
  def self.encrypt(pass)
10
- Digest::SHA512.hexdigest(pass)
11
+ digest = pass
12
+ STRETCHES.times { digest = Digest::SHA512.hexdigest(digest) }
13
+ digest
11
14
  end
12
15
  end
13
16
  end
@@ -44,7 +44,7 @@ module Authgasm # :nodoc:
44
44
 
45
45
  MAJOR = 0
46
46
  MINOR = 10
47
- TINY = 1
47
+ TINY = 2
48
48
 
49
49
  # The current version as a Version instance
50
50
  CURRENT = new(MAJOR, MINOR, TINY)
Binary file
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: authgasm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.1
4
+ version: 0.10.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Johnson of Binary Logic
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-10-28 00:00:00 -04:00
12
+ date: 2008-10-29 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency