authgasm 0.9.1 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +8 -0
- data/Manifest +4 -2
- data/README.rdoc +25 -3
- data/authgasm.gemspec +9 -6
- data/init.rb +0 -1
- data/lib/authgasm.rb +4 -1
- data/lib/authgasm/acts_as_authentic.rb +32 -6
- data/lib/authgasm/controller_adapters/abstract_adapter.rb +25 -0
- data/lib/authgasm/controller_adapters/rails_adapter.rb +39 -0
- data/lib/authgasm/session/active_record_trickery.rb +1 -1
- data/lib/authgasm/session/base.rb +136 -103
- data/lib/authgasm/session/callbacks.rb +24 -16
- data/lib/authgasm/session/config.rb +1 -9
- data/lib/authgasm/session/errors.rb +6 -0
- data/lib/authgasm/version.rb +2 -2
- data/test_app/app/controllers/user_sessions_controller.rb +1 -1
- data/test_app/db/development.sqlite3 +0 -0
- data/test_app/db/test.sqlite3 +0 -0
- data/test_app/test/fixtures/users.yml +3 -1
- data/test_app/test/functional/user_sessions_controller_test.rb +24 -3
- data/test_app/test/integration/user_sesion_stories_test.rb +85 -0
- data/test_app/test/integration/user_session_test.rb +158 -0
- data/test_app/test/test_helper.rb +46 -1
- metadata +8 -5
- data/lib/authgasm/controller.rb +0 -16
- data/test_app/test/unit/ass_test.rb +0 -8
data/CHANGELOG.rdoc
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
== 0.10.0 released 2008-10-24
|
2
|
+
|
3
|
+
* Do not allow instantiation if the session has not been activated with a controller object. Just like ActiveRecord won't let you do anything without a DB connection.
|
4
|
+
* Abstracted controller implementation to allow for rails, merb, etc adapters. So this is not confined to the rails framework.
|
5
|
+
* Removed create and update methods and added save, like ActiveRecord.
|
6
|
+
* after_validation should be able to change the result if it adds errors on callbacks.
|
7
|
+
* Completed tests.
|
8
|
+
|
1
9
|
== 0.9.1 released 2008-10-24
|
2
10
|
|
3
11
|
* Changed scope to id. Makes more sense to call it an id and fits better with the ActiveRecord model.
|
data/Manifest
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
CHANGELOG.rdoc
|
2
2
|
init.rb
|
3
3
|
lib/authgasm/acts_as_authentic.rb
|
4
|
-
lib/authgasm/
|
4
|
+
lib/authgasm/controller_adapters/abstract_adapter.rb
|
5
|
+
lib/authgasm/controller_adapters/rails_adapter.rb
|
5
6
|
lib/authgasm/session/active_record_trickery.rb
|
6
7
|
lib/authgasm/session/base.rb
|
7
8
|
lib/authgasm/session/callbacks.rb
|
@@ -77,6 +78,7 @@ test_app/script/server
|
|
77
78
|
test_app/test/fixtures/users.yml
|
78
79
|
test_app/test/functional/user_sessions_controller_test.rb
|
79
80
|
test_app/test/functional/users_controller_test.rb
|
81
|
+
test_app/test/integration/user_sesion_stories_test.rb
|
82
|
+
test_app/test/integration/user_session_test.rb
|
80
83
|
test_app/test/test_helper.rb
|
81
|
-
test_app/test/unit/ass_test.rb
|
82
84
|
test_app/test/unit/user_test.rb
|
data/README.rdoc
CHANGED
@@ -19,7 +19,7 @@ What if your user sessions controller could look just like your other controller
|
|
19
19
|
|
20
20
|
def create
|
21
21
|
@user_session = UserSession.new(params[:user_session])
|
22
|
-
if @user_session.
|
22
|
+
if @user_session.save
|
23
23
|
redirect_to account_url
|
24
24
|
else
|
25
25
|
render :action => :new
|
@@ -134,6 +134,8 @@ Authgasm tries to check the state of the record before creating the session. If
|
|
134
134
|
|
135
135
|
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.
|
136
136
|
|
137
|
+
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.
|
138
|
+
|
137
139
|
== Hooks / Callbacks
|
138
140
|
|
139
141
|
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:
|
@@ -142,11 +144,27 @@ Just like ActiveRecord you can create your own hooks / callbacks so that you can
|
|
142
144
|
after_create
|
143
145
|
before_destroy
|
144
146
|
after_destroy
|
147
|
+
before_save
|
148
|
+
after_save
|
145
149
|
before_update
|
146
150
|
after_update
|
147
151
|
before_validation
|
148
152
|
after_validation
|
149
153
|
|
154
|
+
== Errors
|
155
|
+
|
156
|
+
The errors in Authgasm work JUST LIKE ActiveRecord. In fact, it uses the exact same ActiveRecord errors class. Use it the same way:
|
157
|
+
|
158
|
+
class UserSession
|
159
|
+
before_validation :check_if_awesome
|
160
|
+
|
161
|
+
private
|
162
|
+
def check_if_awesome
|
163
|
+
errors.add(:login, "must contain awesome") if login && !login.include?("awesome")
|
164
|
+
errors.add_to_base("You must be awesome to log in") unless record.awesome?
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
150
168
|
== Automatic Session Updating
|
151
169
|
|
152
170
|
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.
|
@@ -183,7 +201,7 @@ When things come together like this I think its a sign that you are doing someth
|
|
183
201
|
|
184
202
|
You're asking: "why would I want multiple sessions?". Take this example:
|
185
203
|
|
186
|
-
You have an app where users login and then need to re-login to view / change their billing information. Similar to how
|
204
|
+
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:
|
187
205
|
|
188
206
|
# regular user session
|
189
207
|
@user_session = UserSession.new
|
@@ -202,9 +220,13 @@ This will keep everything separate. The :secure session will store its info in a
|
|
202
220
|
|
203
221
|
For more information on ids checkout Authgasm::Session::Base#initialize
|
204
222
|
|
223
|
+
== What about [insert framework here]?
|
224
|
+
|
225
|
+
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.
|
226
|
+
|
205
227
|
== How it works
|
206
228
|
|
207
|
-
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
|
229
|
+
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.
|
208
230
|
|
209
231
|
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.
|
210
232
|
|
data/authgasm.gemspec
CHANGED
@@ -1,18 +1,18 @@
|
|
1
1
|
|
2
|
-
# Gem::Specification for Authgasm-0.
|
2
|
+
# Gem::Specification for Authgasm-0.10.0
|
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.
|
8
|
+
version: 0.10.0
|
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-
|
15
|
+
date: 2008-10-27 00:00:00 -04:00
|
16
16
|
default_executable:
|
17
17
|
dependencies:
|
18
18
|
- !ruby/object:Gem::Dependency
|
@@ -54,7 +54,8 @@ extensions: []
|
|
54
54
|
extra_rdoc_files:
|
55
55
|
- CHANGELOG.rdoc
|
56
56
|
- lib/authgasm/acts_as_authentic.rb
|
57
|
-
- lib/authgasm/
|
57
|
+
- lib/authgasm/controller_adapters/abstract_adapter.rb
|
58
|
+
- lib/authgasm/controller_adapters/rails_adapter.rb
|
58
59
|
- lib/authgasm/session/active_record_trickery.rb
|
59
60
|
- lib/authgasm/session/base.rb
|
60
61
|
- lib/authgasm/session/callbacks.rb
|
@@ -68,7 +69,8 @@ files:
|
|
68
69
|
- CHANGELOG.rdoc
|
69
70
|
- init.rb
|
70
71
|
- lib/authgasm/acts_as_authentic.rb
|
71
|
-
- lib/authgasm/
|
72
|
+
- lib/authgasm/controller_adapters/abstract_adapter.rb
|
73
|
+
- lib/authgasm/controller_adapters/rails_adapter.rb
|
72
74
|
- lib/authgasm/session/active_record_trickery.rb
|
73
75
|
- lib/authgasm/session/base.rb
|
74
76
|
- lib/authgasm/session/callbacks.rb
|
@@ -144,8 +146,9 @@ files:
|
|
144
146
|
- test_app/test/fixtures/users.yml
|
145
147
|
- test_app/test/functional/user_sessions_controller_test.rb
|
146
148
|
- test_app/test/functional/users_controller_test.rb
|
149
|
+
- test_app/test/integration/user_sesion_stories_test.rb
|
150
|
+
- test_app/test/integration/user_session_test.rb
|
147
151
|
- test_app/test/test_helper.rb
|
148
|
-
- test_app/test/unit/ass_test.rb
|
149
152
|
- test_app/test/unit/user_test.rb
|
150
153
|
- authgasm.gemspec
|
151
154
|
has_rdoc: true
|
data/init.rb
CHANGED
data/lib/authgasm.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
|
+
require "digest/sha2"
|
1
2
|
require File.dirname(__FILE__) + "/authgasm/version"
|
2
|
-
|
3
|
+
|
4
|
+
require File.dirname(__FILE__) + "/authgasm/controller_adapters/rails_adapter" if defined?(Rails)
|
5
|
+
|
3
6
|
require File.dirname(__FILE__) + "/authgasm/sha256_crypto_provider"
|
4
7
|
require File.dirname(__FILE__) + "/authgasm/acts_as_authentic"
|
5
8
|
require File.dirname(__FILE__) + "/authgasm/session/active_record_trickery"
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module Authgasm
|
2
|
-
module
|
2
|
+
module ActsAsAuthentic # :nodoc:
|
3
3
|
def self.included(base)
|
4
4
|
base.extend(ClassMethods)
|
5
5
|
end
|
@@ -20,6 +20,7 @@ module Authgasm
|
|
20
20
|
# Class method name Description
|
21
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
24
|
#
|
24
25
|
# Named Scopes
|
25
26
|
# User.logged_in Find all users who are logged in, based on your :logged_in_timeout option
|
@@ -31,6 +32,7 @@ module Authgasm
|
|
31
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.
|
32
33
|
# user.randomize_password! Basically resets the password to a random password using only letters and numbers
|
33
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.
|
34
36
|
#
|
35
37
|
# === Options
|
36
38
|
# * <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.
|
@@ -107,6 +109,17 @@ module Authgasm
|
|
107
109
|
def self.crypto_provider
|
108
110
|
#{options[:crypto_provider]}
|
109
111
|
end
|
112
|
+
|
113
|
+
def self.forget_all!
|
114
|
+
# Paginate these to save on memory
|
115
|
+
records = nil
|
116
|
+
i = 0
|
117
|
+
begin
|
118
|
+
records = find(:all, :limit => 50, :offset => i)
|
119
|
+
records.each { |record| records.update_attribute(:#{options[:remember_token_field]}, unique_token) }
|
120
|
+
i += 50
|
121
|
+
end while !records.blank?
|
122
|
+
end
|
110
123
|
end_eval
|
111
124
|
|
112
125
|
# Instance methods
|
@@ -125,12 +138,13 @@ module Authgasm
|
|
125
138
|
return if pass.blank?
|
126
139
|
self.tried_to_set_#{options[:password_field]} = true
|
127
140
|
@#{options[:password_field]} = pass
|
128
|
-
salt = [Array.new(6) {rand(256).chr}.join].pack("m").chomp
|
129
141
|
self.#{options[:remember_token_field]} = self.class.unique_token
|
130
|
-
self.#{options[:password_salt_field]}
|
142
|
+
self.#{options[:password_salt_field]} = self.class.unique_token
|
143
|
+
self.#{options[:crypted_password_field]} = crypto_provider.encrypt(@#{options[:password_field]} + #{options[:password_salt_field]})
|
131
144
|
end
|
132
145
|
|
133
146
|
def valid_#{options[:password_field]}?(attempted_password)
|
147
|
+
return false if attempted_password.blank?
|
134
148
|
attempted_password == #{options[:crypted_password_field]} || #{options[:crypted_password_field]} == crypto_provider.encrypt(attempted_password + #{options[:password_salt_field]})
|
135
149
|
end
|
136
150
|
end_eval
|
@@ -145,6 +159,7 @@ module Authgasm
|
|
145
159
|
end
|
146
160
|
|
147
161
|
def valid_#{options[:password_field]}?(attemtped_password)
|
162
|
+
return false if attempted_password.blank?
|
148
163
|
attempted_password == #{options[:crypted_password_field]} || #{options[:crypted_password_field]} = crypto_provider.decrypt(attempted_password)
|
149
164
|
end
|
150
165
|
end_eval
|
@@ -158,6 +173,10 @@ module Authgasm
|
|
158
173
|
self.class.crypto_provider
|
159
174
|
end
|
160
175
|
|
176
|
+
def forget!
|
177
|
+
update_attribute(:#{options[:remember_token_field]}, self.class.unique_token)
|
178
|
+
end
|
179
|
+
|
161
180
|
def randomize_#{options[:password_field]}!
|
162
181
|
chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
|
163
182
|
newpass = ""
|
@@ -166,6 +185,13 @@ module Authgasm
|
|
166
185
|
self.confirm_#{options[:password_field]} = newpass
|
167
186
|
end
|
168
187
|
|
188
|
+
def save_from_session(*args)
|
189
|
+
@saving_from_session = true
|
190
|
+
result = save(*args)
|
191
|
+
@saving_from_session = false
|
192
|
+
result
|
193
|
+
end
|
194
|
+
|
169
195
|
protected
|
170
196
|
def create_sessions!
|
171
197
|
return if !#{options[:session_class]}.activated? || #{options[:session_ids].inspect}.blank?
|
@@ -183,7 +209,7 @@ module Authgasm
|
|
183
209
|
end
|
184
210
|
|
185
211
|
def update_sessions!
|
186
|
-
return if !#{options[:session_class]}.activated?
|
212
|
+
return if @saving_from_session || !#{options[:session_class]}.activated?
|
187
213
|
|
188
214
|
#{options[:session_ids].inspect}.each do |session_id|
|
189
215
|
session = #{options[:session_class]}.find(*[session_id].compact)
|
@@ -192,7 +218,7 @@ module Authgasm
|
|
192
218
|
next if !session || session.record != self
|
193
219
|
|
194
220
|
# We know we are logged in and this is our record, update the session
|
195
|
-
session.
|
221
|
+
session.save
|
196
222
|
end
|
197
223
|
end
|
198
224
|
|
@@ -215,4 +241,4 @@ module Authgasm
|
|
215
241
|
end
|
216
242
|
end
|
217
243
|
|
218
|
-
ActiveRecord::Base.send(:include, Authgasm::
|
244
|
+
ActiveRecord::Base.send(:include, Authgasm::ActsAsAuthentic)
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Authgasm
|
2
|
+
module ControllerAdapters # :nodoc:
|
3
|
+
# = Abstract Adapter
|
4
|
+
# Allows you to use Authgasm in any framework you want, not just rails. See tha RailsAdapter for an example of how to adapter Authgasm to work with your framework.
|
5
|
+
class AbstractAdapter
|
6
|
+
attr_accessor :controller
|
7
|
+
|
8
|
+
def initialize(controller)
|
9
|
+
self.controller = controller
|
10
|
+
end
|
11
|
+
|
12
|
+
def authenticate_with_http_basic(*args, &block)
|
13
|
+
end
|
14
|
+
|
15
|
+
def cookies
|
16
|
+
end
|
17
|
+
|
18
|
+
def request
|
19
|
+
end
|
20
|
+
|
21
|
+
def session
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Authgasm
|
2
|
+
module ControllerAdapters
|
3
|
+
# = Rails Adapter
|
4
|
+
# Adapts authgasm to work with rails. The point is to close the gap between what authgasm expects and what the rails controller object
|
5
|
+
# provides. Similar to how ActiveRecord has an adapter for MySQL, PostgreSQL, SQLite, etc.
|
6
|
+
class RailsAdapter < AbstractAdapter
|
7
|
+
def authenticate_with_http_basic(*args, &block)
|
8
|
+
controller.authenticate_with_http_basic(*args, &block)
|
9
|
+
end
|
10
|
+
|
11
|
+
def cookies
|
12
|
+
controller.send(:cookies)
|
13
|
+
end
|
14
|
+
|
15
|
+
def request
|
16
|
+
controller.request
|
17
|
+
end
|
18
|
+
|
19
|
+
def session
|
20
|
+
controller.session
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# = Rails Implementation
|
25
|
+
# Lets Authgasm know about the controller object, AKA "activates" authgasm.
|
26
|
+
module RailsImplementation
|
27
|
+
def self.included(klass) # :nodoc:
|
28
|
+
klass.prepend_before_filter :set_controller
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
def set_controller
|
33
|
+
Authgasm::Session::Base.controller = RailsAdapter.new(self)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
ActionController::Base.send(:include, Authgasm::ControllerAdapters::RailsImplementation)
|
@@ -7,7 +7,9 @@ module Authgasm
|
|
7
7
|
include Config
|
8
8
|
|
9
9
|
class << self
|
10
|
-
# Returns true if a controller have been set and can be used properly.
|
10
|
+
# Returns true if a controller have been set and can be used properly. This MUST be set before anything can be done. Similar to how ActiveRecord won't allow you to do anything
|
11
|
+
# without establishing a DB connection. By default this is done for you automatically, but if you are using Authgasm in a unique way outside of rails, you need to assign a controller
|
12
|
+
# object to Authgasm via Authgasm::Session::Base.controller = obj.
|
11
13
|
def activated?
|
12
14
|
!controller.blank?
|
13
15
|
end
|
@@ -26,13 +28,13 @@ module Authgasm
|
|
26
28
|
# session.create
|
27
29
|
def create(*args)
|
28
30
|
session = new(*args)
|
29
|
-
session.
|
31
|
+
session.save
|
30
32
|
end
|
31
33
|
|
32
34
|
# Same as create but calls create!, which raises an exception when authentication fails
|
33
35
|
def create!(*args)
|
34
36
|
session = new(*args)
|
35
|
-
session.
|
37
|
+
session.save!
|
36
38
|
end
|
37
39
|
|
38
40
|
# Finds your session by session, then cookie, and finally basic http auth. Perfect for that global before_filter to find your logged in user:
|
@@ -49,9 +51,13 @@ module Authgasm
|
|
49
51
|
args = [id].compact
|
50
52
|
session = new(*args)
|
51
53
|
find_with.each do |find_method|
|
52
|
-
|
53
|
-
|
54
|
-
|
54
|
+
if session.send("valid_#{find_method}?")
|
55
|
+
if session.record.class.column_names.include?("last_request_at")
|
56
|
+
session.record.last_request_at = Time.now
|
57
|
+
session.record.save_from_session(false)
|
58
|
+
end
|
59
|
+
return session
|
60
|
+
end
|
55
61
|
end
|
56
62
|
nil
|
57
63
|
end
|
@@ -72,29 +78,15 @@ module Authgasm
|
|
72
78
|
end
|
73
79
|
end
|
74
80
|
|
75
|
-
# Convenience method. The same as:
|
76
|
-
#
|
77
|
-
# session = UserSession.new
|
78
|
-
# session.update
|
79
|
-
def update(*args)
|
80
|
-
session = new(*args)
|
81
|
-
session.update
|
82
|
-
end
|
83
|
-
|
84
|
-
# The same as update but calls update!, which raises an exception when authentication fails
|
85
|
-
def update!(*args)
|
86
|
-
session = new(*args)
|
87
|
-
session.update!
|
88
|
-
end
|
89
|
-
|
90
81
|
private
|
91
82
|
def controllers
|
92
83
|
@@controllers ||= {}
|
93
84
|
end
|
94
85
|
end
|
95
86
|
|
96
|
-
attr_accessor :login_with, :
|
87
|
+
attr_accessor :login_with, :new_session, :remember_me
|
97
88
|
attr_reader :record, :unauthorized_record
|
89
|
+
attr_writer :id
|
98
90
|
|
99
91
|
# You can initialize a session by doing any of the following:
|
100
92
|
#
|
@@ -111,6 +103,8 @@ module Authgasm
|
|
111
103
|
# Ids are rarely used, but they can be useful. For example, what if users allow other users to login into their account via proxy? Now that user can "technically" be logged into 2 accounts at once.
|
112
104
|
# To solve this just pass a id called :proxy, or whatever you want. Authgasm will separate everything out.
|
113
105
|
def initialize(*args)
|
106
|
+
raise NotActivated.new(self) unless self.class.activated?
|
107
|
+
|
114
108
|
create_configurable_methods!
|
115
109
|
|
116
110
|
self.id = args.pop if args.last.is_a?(Symbol)
|
@@ -131,45 +125,6 @@ module Authgasm
|
|
131
125
|
end
|
132
126
|
end
|
133
127
|
|
134
|
-
# Creates a new user session for you. It does all of the magic:
|
135
|
-
#
|
136
|
-
# 1. validates
|
137
|
-
# 2. sets session
|
138
|
-
# 3. sets cookie
|
139
|
-
# 4. updates magic fields
|
140
|
-
def create(updating = false)
|
141
|
-
if valid?(true)
|
142
|
-
cookies[cookie_key] = {
|
143
|
-
:value => record.send(remember_token_field),
|
144
|
-
:expires => remember_me? ? remember_me_for.from_now : nil
|
145
|
-
}
|
146
|
-
|
147
|
-
if !updating
|
148
|
-
record.login_count = record.login_count + 1 if record.respond_to?(:login_count)
|
149
|
-
|
150
|
-
if record.respond_to?(:current_login_at)
|
151
|
-
record.last_login_at = record.current_login_at if record.respond_to?(:last_login_at)
|
152
|
-
record.current_login_at = Time.now
|
153
|
-
end
|
154
|
-
|
155
|
-
if record.respond_to?(:current_login_ip)
|
156
|
-
record.last_login_ip = record.current_login_ip if record.respond_to?(:last_login_ip)
|
157
|
-
record.current_login_ip = controller.request.remote_ip
|
158
|
-
end
|
159
|
-
|
160
|
-
record.save(false)
|
161
|
-
end
|
162
|
-
|
163
|
-
self
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
# Same as create but raises an exception when authentication fails
|
168
|
-
def create!(updating = false)
|
169
|
-
raise SessionInvalid.new(self) unless create(updating)
|
170
|
-
end
|
171
|
-
alias_method :start!, :create!
|
172
|
-
|
173
128
|
# Your login credentials in hash format. Usually {:login => "my login", :password => "<protected>"} depending on your configuration.
|
174
129
|
# Password is protected as a security measure. The raw password should never be publicly accessible.
|
175
130
|
def credentials
|
@@ -178,8 +133,8 @@ module Authgasm
|
|
178
133
|
|
179
134
|
# Lets you set your loging and password via a hash format.
|
180
135
|
def credentials=(values)
|
181
|
-
values.
|
182
|
-
raise(ArgumentError, "Only 2 credentials are allowed: #{login_field} and #{password_field}") if
|
136
|
+
return if values.blank? || !values.is_a?(Hash)
|
137
|
+
raise(ArgumentError, "Only 2 credentials are allowed: #{login_field} and #{password_field}") if (values.keys - [login_field.to_sym, login_field.to_s, password_field.to_sym, password_field.to_s]).size > 0
|
183
138
|
values.each { |field, value| send("#{field}=", value) }
|
184
139
|
end
|
185
140
|
|
@@ -187,21 +142,49 @@ module Authgasm
|
|
187
142
|
def destroy
|
188
143
|
errors.clear
|
189
144
|
@record = nil
|
190
|
-
cookies.delete cookie_key
|
191
|
-
session[session_key] = nil
|
145
|
+
controller.cookies.delete cookie_key
|
146
|
+
controller.session[session_key] = nil
|
192
147
|
true
|
193
148
|
end
|
194
149
|
|
195
|
-
#
|
150
|
+
# The errors in Authgasm work JUST LIKE ActiveRecord. In fact, it uses the exact same ActiveRecord errors class. Use it the same way:
|
151
|
+
#
|
152
|
+
# === Example
|
153
|
+
#
|
154
|
+
# class UserSession
|
155
|
+
# before_validation :check_if_awesome
|
156
|
+
#
|
157
|
+
# private
|
158
|
+
# def check_if_awesome
|
159
|
+
# errors.add(:login, "must contain awesome") if login && !login.include?("awesome")
|
160
|
+
# errors.add_to_base("You must be awesome to log in") unless record.awesome?
|
161
|
+
# end
|
162
|
+
# end
|
196
163
|
def errors
|
197
164
|
@errors ||= Errors.new(self)
|
198
165
|
end
|
199
166
|
|
167
|
+
# Allows you to set a unique identifier for your session, so that you can have more than 1 session at a time. A good example when this might be needed is when you want to have a normal user session
|
168
|
+
# and a "secure" user session. The secure user session would be created only when they want to modify their billing information, or other sensative information. Similar to me.com. This requires 2
|
169
|
+
# user sessions. Just use an id for the "secure" session and you should be good.
|
170
|
+
#
|
171
|
+
# You can set the id a number of ways:
|
172
|
+
#
|
173
|
+
# session = Session.new(:secure)
|
174
|
+
# session = Session.new("username", "password", :secure)
|
175
|
+
# session = Session.new({:username => "username", :password => "password"}, :secure)
|
176
|
+
# session.id = :secure
|
177
|
+
#
|
178
|
+
# Just be sure and set your id before you validate / create / update your session.
|
179
|
+
def id
|
180
|
+
@id
|
181
|
+
end
|
182
|
+
|
200
183
|
def inspect # :nodoc:
|
201
184
|
details = {}
|
202
185
|
case login_with
|
203
186
|
when :unauthorized_record
|
204
|
-
details[:unauthorized_record] =
|
187
|
+
details[:unauthorized_record] = "<protected>"
|
205
188
|
else
|
206
189
|
details[login_field.to_sym] = send(login_field)
|
207
190
|
details[password_field.to_sym] = "<protected>"
|
@@ -209,16 +192,62 @@ module Authgasm
|
|
209
192
|
"#<#{self.class.name} #{details.inspect}>"
|
210
193
|
end
|
211
194
|
|
195
|
+
|
196
|
+
def new_session?
|
197
|
+
new_session != false
|
198
|
+
end
|
199
|
+
|
212
200
|
# Allows users to be remembered via a cookie.
|
213
201
|
def remember_me?
|
214
|
-
remember_me == true || remember_me
|
202
|
+
remember_me == true || remember_me == "true" || remember_me == "1"
|
215
203
|
end
|
216
204
|
|
217
205
|
# When to expire the cookie. See remember_me_for configuration option to change this.
|
218
206
|
def remember_me_until
|
207
|
+
return unless remember_me?
|
219
208
|
remember_me_for.from_now
|
220
209
|
end
|
221
210
|
|
211
|
+
# Creates / updates a new user session for you. It does all of the magic:
|
212
|
+
#
|
213
|
+
# 1. validates
|
214
|
+
# 2. sets session
|
215
|
+
# 3. sets cookie
|
216
|
+
# 4. updates magic fields
|
217
|
+
def save
|
218
|
+
if valid?
|
219
|
+
update_session!
|
220
|
+
controller.cookies[cookie_key] = {
|
221
|
+
:value => record.send(remember_token_field),
|
222
|
+
:expires => remember_me_until
|
223
|
+
}
|
224
|
+
|
225
|
+
record.login_count = record.login_count + 1 if record.respond_to?(:login_count)
|
226
|
+
|
227
|
+
if record.respond_to?(:current_login_at)
|
228
|
+
record.last_login_at = record.current_login_at if record.respond_to?(:last_login_at)
|
229
|
+
record.current_login_at = Time.now
|
230
|
+
end
|
231
|
+
|
232
|
+
if record.respond_to?(:current_login_ip)
|
233
|
+
record.last_login_ip = record.current_login_ip if record.respond_to?(:last_login_ip)
|
234
|
+
record.current_login_ip = controller.request.remote_ip
|
235
|
+
end
|
236
|
+
|
237
|
+
record.save_from_session(false)
|
238
|
+
|
239
|
+
self.new_session = false
|
240
|
+
self
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
# Same as save but raises an exception when authentication fails
|
245
|
+
def save!
|
246
|
+
result = save
|
247
|
+
raise SessionInvalid.new(self) unless result
|
248
|
+
result
|
249
|
+
end
|
250
|
+
|
222
251
|
# Sometimes you don't want to create a session via credentials (login and password). Maybe you already have the record. Just set this record to this and it will be authenticated when you try to validate
|
223
252
|
# the session. Basically this is another form of credentials, you are just skipping username and password validation.
|
224
253
|
def unauthorized_record=(value)
|
@@ -226,21 +255,12 @@ module Authgasm
|
|
226
255
|
@unauthorized_record = value
|
227
256
|
end
|
228
257
|
|
229
|
-
|
230
|
-
def update
|
231
|
-
create(true)
|
232
|
-
end
|
233
|
-
|
234
|
-
# Same as update but raises an exception if validation is failed
|
235
|
-
def update!
|
236
|
-
create!(true)
|
237
|
-
end
|
238
|
-
|
239
|
-
def valid?(set_session = false)
|
258
|
+
def valid?
|
240
259
|
errors.clear
|
241
260
|
temp_record = unauthorized_record
|
242
261
|
|
243
|
-
|
262
|
+
case login_with
|
263
|
+
when :credentials
|
244
264
|
errors.add(login_field, "can not be blank") if login.blank?
|
245
265
|
errors.add(password_field, "can not be blank") if protected_password.blank?
|
246
266
|
return false if errors.count > 0
|
@@ -256,6 +276,19 @@ module Authgasm
|
|
256
276
|
errors.add(password_field, "is invalid")
|
257
277
|
return false
|
258
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
|
259
292
|
end
|
260
293
|
|
261
294
|
[:approved, :confirmed, :inactive].each do |required_status|
|
@@ -268,34 +301,34 @@ module Authgasm
|
|
268
301
|
# All is good, lets set the record
|
269
302
|
@record = temp_record
|
270
303
|
|
271
|
-
# Now lets set the session to make things easier on successive requests. This is nice when logging in from a cookie, the next requests will be right from the session, which is quicker.
|
272
|
-
if set_session
|
273
|
-
session[session_key] = record.id
|
274
|
-
if record.class.column_names.include?("last_request_at")
|
275
|
-
record.last_request_at = Time.now
|
276
|
-
record.save(false)
|
277
|
-
end
|
278
|
-
end
|
279
|
-
|
280
304
|
true
|
281
305
|
end
|
282
306
|
|
283
|
-
def valid_http_auth?
|
307
|
+
def valid_http_auth?
|
284
308
|
controller.authenticate_with_http_basic do |login, password|
|
285
309
|
if !login.blank? && !password.blank?
|
286
310
|
send("#{login_method}=", login)
|
287
311
|
send("#{password_method}=", password)
|
288
|
-
|
312
|
+
result = valid?
|
313
|
+
if result
|
314
|
+
update_session!
|
315
|
+
return result
|
316
|
+
end
|
289
317
|
end
|
290
318
|
end
|
291
319
|
|
292
320
|
false
|
293
321
|
end
|
294
322
|
|
295
|
-
def valid_cookie?
|
323
|
+
def valid_cookie?
|
296
324
|
if cookie_credentials
|
297
325
|
self.unauthorized_record = klass.send("find_by_#{remember_token_field}", cookie_credentials)
|
298
|
-
valid?
|
326
|
+
result = valid?
|
327
|
+
if result
|
328
|
+
update_session!
|
329
|
+
self.new_session = false
|
330
|
+
return result
|
331
|
+
end
|
299
332
|
end
|
300
333
|
|
301
334
|
false
|
@@ -304,7 +337,11 @@ module Authgasm
|
|
304
337
|
def valid_session?
|
305
338
|
if session_credentials
|
306
339
|
self.unauthorized_record = klass.find_by_id(session_credentials)
|
307
|
-
|
340
|
+
result = valid?
|
341
|
+
if result
|
342
|
+
self.new_session = false
|
343
|
+
return result
|
344
|
+
end
|
308
345
|
end
|
309
346
|
|
310
347
|
false
|
@@ -315,12 +352,8 @@ module Authgasm
|
|
315
352
|
self.class.controller
|
316
353
|
end
|
317
354
|
|
318
|
-
def cookies
|
319
|
-
controller.send(:cookies)
|
320
|
-
end
|
321
|
-
|
322
355
|
def cookie_credentials
|
323
|
-
cookies[cookie_key]
|
356
|
+
controller.cookies[cookie_key]
|
324
357
|
end
|
325
358
|
|
326
359
|
def create_configurable_methods!
|
@@ -356,12 +389,12 @@ module Authgasm
|
|
356
389
|
@password
|
357
390
|
end
|
358
391
|
|
359
|
-
def
|
360
|
-
controller.session
|
392
|
+
def session_credentials
|
393
|
+
controller.session[session_key]
|
361
394
|
end
|
362
395
|
|
363
|
-
def
|
364
|
-
session[session_key]
|
396
|
+
def update_session!
|
397
|
+
controller.session[session_key] = record && record.id
|
365
398
|
end
|
366
399
|
end
|
367
400
|
end
|