authlogic 0.10.4
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of authlogic might be problematic. Click here for more details.
- data/CHANGELOG.rdoc +47 -0
- data/MIT-LICENSE +20 -0
- data/Manifest +100 -0
- data/README.rdoc +292 -0
- data/Rakefile +15 -0
- data/authlogic.gemspec +38 -0
- data/init.rb +1 -0
- data/lib/authlogic.rb +25 -0
- data/lib/authlogic/active_record/acts_as_authentic.rb +265 -0
- data/lib/authlogic/active_record/authenticates_many.rb +19 -0
- data/lib/authlogic/active_record/scoped_session.rb +28 -0
- data/lib/authlogic/controller_adapters/abstract_adapter.rb +25 -0
- data/lib/authlogic/controller_adapters/rails_adapter.rb +39 -0
- data/lib/authlogic/session/active_record_trickery.rb +26 -0
- data/lib/authlogic/session/base.rb +510 -0
- data/lib/authlogic/session/callbacks.rb +56 -0
- data/lib/authlogic/session/config.rb +237 -0
- data/lib/authlogic/session/errors.rb +18 -0
- data/lib/authlogic/sha512_crypto_provider.rb +18 -0
- data/lib/authlogic/version.rb +56 -0
- data/test_app/README +256 -0
- data/test_app/Rakefile +10 -0
- data/test_app/app/controllers/application.rb +72 -0
- data/test_app/app/controllers/companies_controller.rb +2 -0
- data/test_app/app/controllers/user_sessions_controller.rb +25 -0
- data/test_app/app/controllers/users_controller.rb +61 -0
- data/test_app/app/helpers/application_helper.rb +3 -0
- data/test_app/app/helpers/companies_helper.rb +2 -0
- data/test_app/app/helpers/user_sessions_helper.rb +2 -0
- data/test_app/app/helpers/users_helper.rb +2 -0
- data/test_app/app/models/company.rb +4 -0
- data/test_app/app/models/project.rb +3 -0
- data/test_app/app/models/user.rb +5 -0
- data/test_app/app/models/user_session.rb +3 -0
- data/test_app/app/views/layouts/application.html.erb +27 -0
- data/test_app/app/views/user_sessions/new.html.erb +15 -0
- data/test_app/app/views/users/_form.erb +15 -0
- data/test_app/app/views/users/edit.html.erb +8 -0
- data/test_app/app/views/users/new.html.erb +8 -0
- data/test_app/app/views/users/show.html.erb +29 -0
- data/test_app/config/boot.rb +109 -0
- data/test_app/config/database.yml +19 -0
- data/test_app/config/environment.rb +69 -0
- data/test_app/config/environments/development.rb +17 -0
- data/test_app/config/environments/production.rb +22 -0
- data/test_app/config/environments/test.rb +22 -0
- data/test_app/config/initializers/inflections.rb +10 -0
- data/test_app/config/initializers/mime_types.rb +5 -0
- data/test_app/config/initializers/new_rails_defaults.rb +17 -0
- data/test_app/config/routes.rb +11 -0
- data/test_app/db/development.sqlite3 +0 -0
- data/test_app/db/migrate/20081023040052_create_users.rb +20 -0
- data/test_app/db/migrate/20081103003828_create_companies.rb +14 -0
- data/test_app/db/migrate/20081103003834_create_projects.rb +18 -0
- data/test_app/db/schema.rb +46 -0
- data/test_app/db/test.sqlite3 +0 -0
- data/test_app/doc/README_FOR_APP +2 -0
- data/test_app/public/404.html +30 -0
- data/test_app/public/422.html +30 -0
- data/test_app/public/500.html +30 -0
- data/test_app/public/dispatch.cgi +10 -0
- data/test_app/public/dispatch.fcgi +24 -0
- data/test_app/public/dispatch.rb +10 -0
- data/test_app/public/favicon.ico +0 -0
- data/test_app/public/images/rails.png +0 -0
- data/test_app/public/javascripts/application.js +2 -0
- data/test_app/public/javascripts/controls.js +963 -0
- data/test_app/public/javascripts/dragdrop.js +972 -0
- data/test_app/public/javascripts/effects.js +1120 -0
- data/test_app/public/javascripts/prototype.js +4225 -0
- data/test_app/public/robots.txt +5 -0
- data/test_app/public/stylesheets/scaffold.css +62 -0
- data/test_app/script/about +4 -0
- data/test_app/script/console +3 -0
- data/test_app/script/dbconsole +3 -0
- data/test_app/script/destroy +3 -0
- data/test_app/script/generate +3 -0
- data/test_app/script/performance/benchmarker +3 -0
- data/test_app/script/performance/profiler +3 -0
- data/test_app/script/performance/request +3 -0
- data/test_app/script/plugin +3 -0
- data/test_app/script/process/inspector +3 -0
- data/test_app/script/process/reaper +3 -0
- data/test_app/script/process/spawner +3 -0
- data/test_app/script/runner +3 -0
- data/test_app/script/server +3 -0
- data/test_app/test/fixtures/companies.yml +7 -0
- data/test_app/test/fixtures/projects.yml +4 -0
- data/test_app/test/fixtures/users.yml +21 -0
- data/test_app/test/functional/companies_controller_test.rb +8 -0
- data/test_app/test/functional/user_sessions_controller_test.rb +36 -0
- data/test_app/test/functional/users_controller_test.rb +8 -0
- data/test_app/test/integration/company_user_session_stories_test.rb +46 -0
- data/test_app/test/integration/user_sesion_stories_test.rb +105 -0
- data/test_app/test/integration/user_session_config_test.rb +24 -0
- data/test_app/test/integration/user_session_test.rb +161 -0
- data/test_app/test/test_helper.rb +81 -0
- data/test_app/test/unit/account_test.rb +8 -0
- data/test_app/test/unit/company_test.rb +8 -0
- data/test_app/test/unit/project_test.rb +8 -0
- data/test_app/test/unit/user_test.rb +80 -0
- metadata +201 -0
@@ -0,0 +1,26 @@
|
|
1
|
+
module Authlogic
|
2
|
+
module Session
|
3
|
+
# = ActiveRecord Trickery
|
4
|
+
#
|
5
|
+
# Authlogic looks like ActiveRecord, sounds like ActiveRecord, but its not ActiveRecord. That's the goal here. This is useful for the various rails helper methods such as form_for, error_messages_for, etc.
|
6
|
+
# These helpers exptect various methods to be present. This adds in those methods into Authlogic.
|
7
|
+
module ActiveRecordTrickery
|
8
|
+
def self.included(klass) # :nodoc:
|
9
|
+
klass.extend ClassMethods
|
10
|
+
klass.send(:include, InstanceMethods)
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods # :nodoc:
|
14
|
+
def human_attribute_name(attribute_key_name, options = {})
|
15
|
+
attribute_key_name.humanize
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
module InstanceMethods # :nodoc:
|
20
|
+
def new_record?
|
21
|
+
new_session?
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,510 @@
|
|
1
|
+
module Authlogic
|
2
|
+
module Session # :nodoc:
|
3
|
+
# = Base
|
4
|
+
#
|
5
|
+
# This is the muscle behind Authlogic. For detailed information on how to use this please refer to the README. For detailed method explanations see below.
|
6
|
+
class Base
|
7
|
+
include Config
|
8
|
+
|
9
|
+
class << self
|
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 Authlogic in a unique way outside of rails, you need to assign a controller
|
12
|
+
# object to Authlogic via Authlogic::Session::Base.controller = obj.
|
13
|
+
def activated?
|
14
|
+
!controller.blank?
|
15
|
+
end
|
16
|
+
|
17
|
+
def controller=(value) # :nodoc:
|
18
|
+
controllers[Thread.current] = value
|
19
|
+
end
|
20
|
+
|
21
|
+
def controller # :nodoc:
|
22
|
+
controllers[Thread.current]
|
23
|
+
end
|
24
|
+
|
25
|
+
# A convenince method. The same as:
|
26
|
+
#
|
27
|
+
# session = UserSession.new
|
28
|
+
# session.create
|
29
|
+
def create(*args)
|
30
|
+
session = new(*args)
|
31
|
+
session.save
|
32
|
+
end
|
33
|
+
|
34
|
+
# Same as create but calls create!, which raises an exception when authentication fails
|
35
|
+
def create!(*args)
|
36
|
+
session = new(*args)
|
37
|
+
session.save!
|
38
|
+
end
|
39
|
+
|
40
|
+
# A convenience method for session.find_record. Finds your session by session, then cookie, and finally basic http auth. Perfect for that global before_filter to find your logged in user:
|
41
|
+
#
|
42
|
+
# before_filter :load_user
|
43
|
+
#
|
44
|
+
# def load_user
|
45
|
+
# @user_session = UserSession.find
|
46
|
+
# @current_user = @user_session && @user_session.record
|
47
|
+
# end
|
48
|
+
#
|
49
|
+
# Accepts a single parameter as the id. See initialize for more information on ids. Lastly, how it finds the session can be modified via configuration.
|
50
|
+
def find(id = nil)
|
51
|
+
args = [id].compact
|
52
|
+
session = new(*args)
|
53
|
+
return session if session.find_record
|
54
|
+
nil
|
55
|
+
end
|
56
|
+
|
57
|
+
def klass # :nodoc:
|
58
|
+
@klass ||=
|
59
|
+
if klass_name
|
60
|
+
klass_name.constantize
|
61
|
+
else
|
62
|
+
nil
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def klass_name # :nodoc:
|
67
|
+
@klass_name ||=
|
68
|
+
if guessed_name = name.scan(/(.*)Session/)[0]
|
69
|
+
@klass_name = guessed_name[0]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# The current scope set, should be used in the block passed to with_scope.
|
74
|
+
def scope
|
75
|
+
scopes[Thread.current]
|
76
|
+
end
|
77
|
+
|
78
|
+
# Authentication can be scoped, but scoping authentication can get a little tricky. Checkout the section "Scoping" in the readme for more details.
|
79
|
+
#
|
80
|
+
# What with_scopes focuses on is scoping the query when finding the object and the name of the cookies.
|
81
|
+
#
|
82
|
+
# with_scope accepts a hash with any of the following options:
|
83
|
+
#
|
84
|
+
# * <tt>find_options:</tt> any options you can pass into ActiveRecord::Base.find. This is used when trying to find the record.
|
85
|
+
# * <tt>id:</tt> see the id method above
|
86
|
+
#
|
87
|
+
# So you use it just like an ActiveRecord scope, essentially:
|
88
|
+
#
|
89
|
+
# UserSession.with_scope(:find_options => {:conditions => "account_id = 2"}, :id => "account_2") do
|
90
|
+
# UserSession.find
|
91
|
+
# end
|
92
|
+
#
|
93
|
+
# Eseentially what the above does is scope the searching of the object with the sql you provided. So instead of:
|
94
|
+
#
|
95
|
+
# User.find(:first, :conditions => "login = 'ben'")
|
96
|
+
#
|
97
|
+
# it would be:
|
98
|
+
#
|
99
|
+
# User.find(:first, :conditions => "login = 'ben' and account_id = 2")
|
100
|
+
#
|
101
|
+
# You will also notice the :id option. This works just like the id method. It scopes your cookies. So the name of your cookie will be:
|
102
|
+
#
|
103
|
+
# account_2_user_credentials
|
104
|
+
#
|
105
|
+
# instead of:
|
106
|
+
#
|
107
|
+
# user_credentials
|
108
|
+
#
|
109
|
+
# What is also nifty about scoping with an :id is that it merges your id's. So if you do:
|
110
|
+
#
|
111
|
+
# UserSession.with_scope(:find_options => {:conditions => "account_id = 2"}, :id => "account_2") do
|
112
|
+
# session = UserSession.new
|
113
|
+
# session.id = :secure
|
114
|
+
# end
|
115
|
+
#
|
116
|
+
# The name of your cookies will be:
|
117
|
+
#
|
118
|
+
# secure_account_2_user_credentials
|
119
|
+
def with_scope(options = {}, &block)
|
120
|
+
raise ArgumentError.new("You must provide a block") unless block_given?
|
121
|
+
self.scope = options
|
122
|
+
result = yield
|
123
|
+
self.scope = nil
|
124
|
+
result
|
125
|
+
end
|
126
|
+
|
127
|
+
private
|
128
|
+
def controllers
|
129
|
+
@@controllers ||= {}
|
130
|
+
end
|
131
|
+
|
132
|
+
def scope=(value)
|
133
|
+
scopes[Thread.current] = value
|
134
|
+
end
|
135
|
+
|
136
|
+
def scopes
|
137
|
+
@scopes ||= {}
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
attr_accessor :login_with, :new_session
|
142
|
+
attr_reader :record, :unauthorized_record
|
143
|
+
attr_writer :id, :scope
|
144
|
+
|
145
|
+
# You can initialize a session by doing any of the following:
|
146
|
+
#
|
147
|
+
# UserSession.new
|
148
|
+
# UserSession.new(login, password)
|
149
|
+
# UserSession.new(:login => login, :password => password)
|
150
|
+
# UserSession.new(User.first)
|
151
|
+
#
|
152
|
+
# If a user has more than one session you need to pass an id so that Authlogic knows how to differentiate the sessions. The id MUST be a Symbol.
|
153
|
+
#
|
154
|
+
# UserSession.new(:my_id)
|
155
|
+
# UserSession.new(login, password, :my_id)
|
156
|
+
# UserSession.new({:login => loing, :password => password}, :my_id)
|
157
|
+
# UserSession.new(User.first, :my_id)
|
158
|
+
#
|
159
|
+
# 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.
|
160
|
+
# To solve this just pass a id called :proxy, or whatever you want. Authlogic will separate everything out.
|
161
|
+
def initialize(*args)
|
162
|
+
raise NotActivated.new(self) unless self.class.activated?
|
163
|
+
|
164
|
+
create_configurable_methods!
|
165
|
+
|
166
|
+
self.scope = self.class.scope
|
167
|
+
self.id = args.pop if args.last.is_a?(Symbol)
|
168
|
+
|
169
|
+
case args.size
|
170
|
+
when 1
|
171
|
+
credentials_or_record = args.first
|
172
|
+
case credentials_or_record
|
173
|
+
when Hash
|
174
|
+
self.credentials = credentials_or_record
|
175
|
+
else
|
176
|
+
self.unauthorized_record = credentials_or_record
|
177
|
+
end
|
178
|
+
else
|
179
|
+
send("#{login_field}=", args[0]) if args.size > 0
|
180
|
+
send("#{password_field}=", args[1]) if args.size > 1
|
181
|
+
self.remember_me = args[2] if args.size > 2
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
# Your login credentials in hash format. Usually {:login => "my login", :password => "<protected>"} depending on your configuration.
|
186
|
+
# Password is protected as a security measure. The raw password should never be publicly accessible.
|
187
|
+
def credentials
|
188
|
+
{login_field => send(login_field), password_field => "<Protected>"}
|
189
|
+
end
|
190
|
+
|
191
|
+
# Lets you set your loging and password via a hash format. This is "params" safe. It only allows for 3 keys: your login field name, password field name, and remember me.
|
192
|
+
def credentials=(values)
|
193
|
+
return if values.blank? || !values.is_a?(Hash)
|
194
|
+
values.symbolize_keys!
|
195
|
+
[login_field.to_sym, password_field.to_sym, :remember_me].each do |field|
|
196
|
+
next if !values.key?(field)
|
197
|
+
send("#{field}=", values[field])
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
# Resets everything, your errors, record, cookies, and session. Basically "logs out" a user.
|
202
|
+
def destroy
|
203
|
+
errors.clear
|
204
|
+
@record = nil
|
205
|
+
controller.cookies.delete cookie_key
|
206
|
+
controller.session[session_key] = nil
|
207
|
+
true
|
208
|
+
end
|
209
|
+
|
210
|
+
# The errors in Authlogic work JUST LIKE ActiveRecord. In fact, it uses the exact same ActiveRecord errors class. Use it the same way:
|
211
|
+
#
|
212
|
+
# === Example
|
213
|
+
#
|
214
|
+
# class UserSession
|
215
|
+
# before_validation :check_if_awesome
|
216
|
+
#
|
217
|
+
# private
|
218
|
+
# def check_if_awesome
|
219
|
+
# errors.add(:login, "must contain awesome") if login && !login.include?("awesome")
|
220
|
+
# errors.add_to_base("You must be awesome to log in") unless record.awesome?
|
221
|
+
# end
|
222
|
+
# end
|
223
|
+
def errors
|
224
|
+
@errors ||= Errors.new(self)
|
225
|
+
end
|
226
|
+
|
227
|
+
# Attempts to find the record by session, then cookie, and finally basic http auth. See the class level find method if you are wanting to use this in a before_filter to persist your session.
|
228
|
+
def find_record
|
229
|
+
return record if record
|
230
|
+
find_with.each do |find_method|
|
231
|
+
if send("valid_#{find_method}?")
|
232
|
+
if record.class.column_names.include?("last_request_at")
|
233
|
+
record.last_request_at = Time.now
|
234
|
+
record.save_without_session_maintenance(false)
|
235
|
+
end
|
236
|
+
return record
|
237
|
+
end
|
238
|
+
end
|
239
|
+
nil
|
240
|
+
end
|
241
|
+
|
242
|
+
# 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
|
243
|
+
# 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
|
244
|
+
# user sessions. Just use an id for the "secure" session and you should be good.
|
245
|
+
#
|
246
|
+
# You can set the id a number of ways:
|
247
|
+
#
|
248
|
+
# session = Session.new(:secure)
|
249
|
+
# session = Session.new("username", "password", :secure)
|
250
|
+
# session = Session.new({:username => "username", :password => "password"}, :secure)
|
251
|
+
# session.id = :secure
|
252
|
+
#
|
253
|
+
# Just be sure and set your id before you validate / create / update your session.
|
254
|
+
def id
|
255
|
+
@id
|
256
|
+
end
|
257
|
+
|
258
|
+
def inspect # :nodoc:
|
259
|
+
details = {}
|
260
|
+
case login_with
|
261
|
+
when :unauthorized_record
|
262
|
+
details[:unauthorized_record] = "<protected>"
|
263
|
+
else
|
264
|
+
details[login_field.to_sym] = send(login_field)
|
265
|
+
details[password_field.to_sym] = "<protected>"
|
266
|
+
end
|
267
|
+
"#<#{self.class.name} #{details.inspect}>"
|
268
|
+
end
|
269
|
+
|
270
|
+
# Similar to ActiveRecord's new_record? Returns true if the session has not been saved yet.
|
271
|
+
def new_session?
|
272
|
+
new_session != false
|
273
|
+
end
|
274
|
+
|
275
|
+
def remember_me # :nodoc:
|
276
|
+
return @remember_me if @set_remember_me
|
277
|
+
@remember_me ||= self.class.remember_me
|
278
|
+
end
|
279
|
+
|
280
|
+
# Accepts a boolean as a flag to remember the session or not. Basically to expire the cookie at the end of the session or keep it for "remember_me_until".
|
281
|
+
def remember_me=(value)
|
282
|
+
@set_remember_me = true
|
283
|
+
@remember_me = value
|
284
|
+
end
|
285
|
+
|
286
|
+
# Allows users to be remembered via a cookie.
|
287
|
+
def remember_me?
|
288
|
+
remember_me == true || remember_me == "true" || remember_me == "1"
|
289
|
+
end
|
290
|
+
|
291
|
+
# When to expire the cookie. See remember_me_for configuration option to change this.
|
292
|
+
def remember_me_until
|
293
|
+
return unless remember_me?
|
294
|
+
remember_me_for.from_now
|
295
|
+
end
|
296
|
+
|
297
|
+
# See the class level with_scope method on information on scopes. with_scope essentialls sets this scope with the options passed and unsets it after the block executes.
|
298
|
+
def scope
|
299
|
+
@scope ||= {}
|
300
|
+
end
|
301
|
+
|
302
|
+
# Creates / updates a new user session for you. It does all of the magic:
|
303
|
+
#
|
304
|
+
# 1. validates
|
305
|
+
# 2. sets session
|
306
|
+
# 3. sets cookie
|
307
|
+
# 4. updates magic fields
|
308
|
+
def save
|
309
|
+
if valid?
|
310
|
+
update_session!
|
311
|
+
controller.cookies[cookie_key] = {
|
312
|
+
:value => record.send(remember_token_field),
|
313
|
+
:expires => remember_me_until
|
314
|
+
}
|
315
|
+
|
316
|
+
record.login_count = record.login_count + 1 if record.respond_to?(:login_count)
|
317
|
+
|
318
|
+
if record.respond_to?(:current_login_at)
|
319
|
+
record.last_login_at = record.current_login_at if record.respond_to?(:last_login_at)
|
320
|
+
record.current_login_at = Time.now
|
321
|
+
end
|
322
|
+
|
323
|
+
if record.respond_to?(:current_login_ip)
|
324
|
+
record.last_login_ip = record.current_login_ip if record.respond_to?(:last_login_ip)
|
325
|
+
record.current_login_ip = controller.request.remote_ip
|
326
|
+
end
|
327
|
+
|
328
|
+
record.save_without_session_maintenance(false)
|
329
|
+
|
330
|
+
self.new_session = false
|
331
|
+
self
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
# Same as save but raises an exception when authentication fails
|
336
|
+
def save!
|
337
|
+
result = save
|
338
|
+
raise SessionInvalid.new(self) unless result
|
339
|
+
result
|
340
|
+
end
|
341
|
+
|
342
|
+
# 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
|
343
|
+
# the session. Basically this is another form of credentials, you are just skipping username and password validation.
|
344
|
+
def unauthorized_record=(value)
|
345
|
+
self.login_with = :unauthorized_record
|
346
|
+
@unauthorized_record = value
|
347
|
+
end
|
348
|
+
|
349
|
+
# Returns if the session is valid or not. Basically it means that a record could or could not be found. If the session is valid you will have a result when calling the "record" method. If it was unsuccessful
|
350
|
+
# you will not have a record.
|
351
|
+
def valid?
|
352
|
+
errors.clear
|
353
|
+
temp_record = validate_credentials
|
354
|
+
if errors.empty?
|
355
|
+
@record = temp_record
|
356
|
+
return true
|
357
|
+
end
|
358
|
+
false
|
359
|
+
end
|
360
|
+
|
361
|
+
# Tries to validate the session from information from a basic http auth, if it was provided.
|
362
|
+
def valid_http_auth?
|
363
|
+
controller.authenticate_with_http_basic do |login, password|
|
364
|
+
if !login.blank? && !password.blank?
|
365
|
+
send("#{login_method}=", login)
|
366
|
+
send("#{password_method}=", password)
|
367
|
+
result = valid?
|
368
|
+
if result
|
369
|
+
update_session!
|
370
|
+
return result
|
371
|
+
end
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
false
|
376
|
+
end
|
377
|
+
|
378
|
+
# Tries to validate the session from information in the cookie
|
379
|
+
def valid_cookie?
|
380
|
+
if cookie_credentials
|
381
|
+
self.unauthorized_record = search_for_record("find_by_#{remember_token_field}", cookie_credentials)
|
382
|
+
result = valid?
|
383
|
+
if result
|
384
|
+
update_session!
|
385
|
+
self.new_session = false
|
386
|
+
return result
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
false
|
391
|
+
end
|
392
|
+
|
393
|
+
# Tries to validate the session from information in the session
|
394
|
+
def valid_session?
|
395
|
+
if session_credentials
|
396
|
+
self.unauthorized_record = search_for_record("find_by_#{remember_token_field}", session_credentials)
|
397
|
+
result = valid?
|
398
|
+
if result
|
399
|
+
self.new_session = false
|
400
|
+
return result
|
401
|
+
end
|
402
|
+
end
|
403
|
+
|
404
|
+
false
|
405
|
+
end
|
406
|
+
|
407
|
+
private
|
408
|
+
def controller
|
409
|
+
self.class.controller
|
410
|
+
end
|
411
|
+
|
412
|
+
def cookie_credentials
|
413
|
+
controller.cookies[cookie_key]
|
414
|
+
end
|
415
|
+
|
416
|
+
def create_configurable_methods!
|
417
|
+
return if respond_to?(login_field) # already created these methods
|
418
|
+
|
419
|
+
self.class.class_eval <<-"end_eval", __FILE__, __LINE__
|
420
|
+
attr_reader :#{login_field}
|
421
|
+
|
422
|
+
def #{login_field}=(value)
|
423
|
+
self.login_with = :credentials
|
424
|
+
@#{login_field} = value
|
425
|
+
end
|
426
|
+
|
427
|
+
def #{password_field}=(value)
|
428
|
+
self.login_with = :credentials
|
429
|
+
@#{password_field} = value
|
430
|
+
end
|
431
|
+
|
432
|
+
def #{password_field}; end
|
433
|
+
|
434
|
+
private
|
435
|
+
# The password should not be accessible publicly. This way forms using form_for don't fill the password with the attempted password. The prevent this we just create this method that is private.
|
436
|
+
def protected_#{password_field}
|
437
|
+
@#{password_field}
|
438
|
+
end
|
439
|
+
end_eval
|
440
|
+
end
|
441
|
+
|
442
|
+
def search_for_record(method, value)
|
443
|
+
klass.send(:with_scope, :find => (scope[:find_options] || {})) do
|
444
|
+
klass.send(method, value)
|
445
|
+
end
|
446
|
+
end
|
447
|
+
|
448
|
+
def klass
|
449
|
+
self.class.klass
|
450
|
+
end
|
451
|
+
|
452
|
+
def klass_name
|
453
|
+
self.class.klass_name
|
454
|
+
end
|
455
|
+
|
456
|
+
def session_credentials
|
457
|
+
controller.session[session_key]
|
458
|
+
end
|
459
|
+
|
460
|
+
def update_session!
|
461
|
+
controller.session[session_key] = record && record.send(remember_token_field)
|
462
|
+
end
|
463
|
+
|
464
|
+
def validate_credentials
|
465
|
+
temp_record = unauthorized_record
|
466
|
+
|
467
|
+
case login_with
|
468
|
+
when :credentials
|
469
|
+
errors.add(login_field, "can not be blank") if send(login_field).blank?
|
470
|
+
errors.add(password_field, "can not be blank") if send("protected_#{password_field}").blank?
|
471
|
+
return if errors.count > 0
|
472
|
+
|
473
|
+
temp_record = search_for_record(find_by_login_method, send(login_field))
|
474
|
+
|
475
|
+
if temp_record.blank?
|
476
|
+
errors.add(login_field, "was not found")
|
477
|
+
return
|
478
|
+
end
|
479
|
+
|
480
|
+
unless temp_record.send(verify_password_method, send("protected_#{password_field}"))
|
481
|
+
errors.add(password_field, "is invalid")
|
482
|
+
return
|
483
|
+
end
|
484
|
+
when :unauthorized_record
|
485
|
+
if temp_record.blank?
|
486
|
+
errors.add_to_base("You can not log in with a blank record.")
|
487
|
+
return
|
488
|
+
end
|
489
|
+
|
490
|
+
if temp_record.new_record?
|
491
|
+
errors.add_to_base("You can not login with a new record.") if temp_record.new_record?
|
492
|
+
return
|
493
|
+
end
|
494
|
+
else
|
495
|
+
errors.add_to_base("You must provide some form of credentials before logging in.")
|
496
|
+
return
|
497
|
+
end
|
498
|
+
|
499
|
+
[:active, :approved, :confirmed].each do |required_status|
|
500
|
+
if temp_record.respond_to?("#{required_status}?") && !temp_record.send("#{required_status}?")
|
501
|
+
errors.add_to_base("Your account has not been marked as #{required_status}")
|
502
|
+
return
|
503
|
+
end
|
504
|
+
end
|
505
|
+
|
506
|
+
temp_record
|
507
|
+
end
|
508
|
+
end
|
509
|
+
end
|
510
|
+
end
|