nulogy-authlogic 3.1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +3 -0
- data/Gemfile.lock +62 -0
- data/LICENSE +20 -0
- data/README.rdoc +250 -0
- data/Rakefile +50 -0
- data/VERSION.yml +5 -0
- data/authlogic.gemspec +192 -0
- data/generators/session/session_generator.rb +9 -0
- data/generators/session/templates/session.rb +2 -0
- data/init.rb +1 -0
- data/lib/authlogic.rb +64 -0
- data/lib/authlogic/acts_as_authentic/base.rb +109 -0
- data/lib/authlogic/acts_as_authentic/email.rb +110 -0
- data/lib/authlogic/acts_as_authentic/logged_in_status.rb +59 -0
- data/lib/authlogic/acts_as_authentic/login.rb +142 -0
- data/lib/authlogic/acts_as_authentic/magic_columns.rb +24 -0
- data/lib/authlogic/acts_as_authentic/password.rb +355 -0
- data/lib/authlogic/acts_as_authentic/perishable_token.rb +105 -0
- data/lib/authlogic/acts_as_authentic/persistence_token.rb +68 -0
- data/lib/authlogic/acts_as_authentic/restful_authentication.rb +61 -0
- data/lib/authlogic/acts_as_authentic/session_maintenance.rb +139 -0
- data/lib/authlogic/acts_as_authentic/single_access_token.rb +65 -0
- data/lib/authlogic/acts_as_authentic/validations_scope.rb +32 -0
- data/lib/authlogic/authenticates_many/association.rb +42 -0
- data/lib/authlogic/authenticates_many/base.rb +54 -0
- data/lib/authlogic/controller_adapters/abstract_adapter.rb +67 -0
- data/lib/authlogic/controller_adapters/merb_adapter.rb +30 -0
- data/lib/authlogic/controller_adapters/rails_adapter.rb +50 -0
- data/lib/authlogic/controller_adapters/sinatra_adapter.rb +61 -0
- data/lib/authlogic/crypto_providers/aes256.rb +43 -0
- data/lib/authlogic/crypto_providers/bcrypt.rb +90 -0
- data/lib/authlogic/crypto_providers/md5.rb +34 -0
- data/lib/authlogic/crypto_providers/sha1.rb +35 -0
- data/lib/authlogic/crypto_providers/sha256.rb +50 -0
- data/lib/authlogic/crypto_providers/sha512.rb +50 -0
- data/lib/authlogic/crypto_providers/wordpress.rb +43 -0
- data/lib/authlogic/i18n.rb +84 -0
- data/lib/authlogic/i18n/translator.rb +15 -0
- data/lib/authlogic/random.rb +33 -0
- data/lib/authlogic/regex.rb +25 -0
- data/lib/authlogic/session/activation.rb +58 -0
- data/lib/authlogic/session/active_record_trickery.rb +72 -0
- data/lib/authlogic/session/base.rb +37 -0
- data/lib/authlogic/session/brute_force_protection.rb +96 -0
- data/lib/authlogic/session/callbacks.rb +96 -0
- data/lib/authlogic/session/cookies.rb +182 -0
- data/lib/authlogic/session/existence.rb +93 -0
- data/lib/authlogic/session/foundation.rb +77 -0
- data/lib/authlogic/session/http_auth.rb +99 -0
- data/lib/authlogic/session/id.rb +41 -0
- data/lib/authlogic/session/klass.rb +69 -0
- data/lib/authlogic/session/magic_columns.rb +95 -0
- data/lib/authlogic/session/magic_states.rb +59 -0
- data/lib/authlogic/session/params.rb +101 -0
- data/lib/authlogic/session/password.rb +240 -0
- data/lib/authlogic/session/perishable_token.rb +18 -0
- data/lib/authlogic/session/persistence.rb +70 -0
- data/lib/authlogic/session/priority_record.rb +34 -0
- data/lib/authlogic/session/scopes.rb +101 -0
- data/lib/authlogic/session/session.rb +62 -0
- data/lib/authlogic/session/timeout.rb +82 -0
- data/lib/authlogic/session/unauthorized_record.rb +50 -0
- data/lib/authlogic/session/validation.rb +82 -0
- data/lib/authlogic/test_case.rb +120 -0
- data/lib/authlogic/test_case/mock_controller.rb +55 -0
- data/lib/authlogic/test_case/mock_cookie_jar.rb +14 -0
- data/lib/authlogic/test_case/mock_logger.rb +10 -0
- data/lib/authlogic/test_case/mock_request.rb +19 -0
- data/lib/authlogic/test_case/rails_request_adapter.rb +30 -0
- data/lib/generators/authlogic/USAGE +8 -0
- data/lib/generators/authlogic/session_generator.rb +14 -0
- data/lib/generators/authlogic/templates/session.rb +2 -0
- data/rails/init.rb +1 -0
- data/shoulda_macros/authlogic.rb +69 -0
- data/test/acts_as_authentic_test/base_test.rb +18 -0
- data/test/acts_as_authentic_test/email_test.rb +116 -0
- data/test/acts_as_authentic_test/logged_in_status_test.rb +50 -0
- data/test/acts_as_authentic_test/login_test.rb +116 -0
- data/test/acts_as_authentic_test/magic_columns_test.rb +27 -0
- data/test/acts_as_authentic_test/password_test.rb +236 -0
- data/test/acts_as_authentic_test/perishable_token_test.rb +90 -0
- data/test/acts_as_authentic_test/persistence_token_test.rb +55 -0
- data/test/acts_as_authentic_test/restful_authentication_test.rb +40 -0
- data/test/acts_as_authentic_test/session_maintenance_test.rb +84 -0
- data/test/acts_as_authentic_test/single_access_test.rb +44 -0
- data/test/authenticates_many_test.rb +16 -0
- data/test/crypto_provider_test/aes256_test.rb +14 -0
- data/test/crypto_provider_test/bcrypt_test.rb +14 -0
- data/test/crypto_provider_test/sha1_test.rb +23 -0
- data/test/crypto_provider_test/sha256_test.rb +14 -0
- data/test/crypto_provider_test/sha512_test.rb +14 -0
- data/test/fixtures/companies.yml +5 -0
- data/test/fixtures/employees.yml +17 -0
- data/test/fixtures/projects.yml +3 -0
- data/test/fixtures/users.yml +24 -0
- data/test/i18n_test.rb +33 -0
- data/test/libs/affiliate.rb +7 -0
- data/test/libs/company.rb +6 -0
- data/test/libs/employee.rb +7 -0
- data/test/libs/employee_session.rb +2 -0
- data/test/libs/ldaper.rb +3 -0
- data/test/libs/ordered_hash.rb +9 -0
- data/test/libs/project.rb +3 -0
- data/test/libs/user.rb +5 -0
- data/test/libs/user_session.rb +5 -0
- data/test/random_test.rb +42 -0
- data/test/session_test/activation_test.rb +43 -0
- data/test/session_test/active_record_trickery_test.rb +46 -0
- data/test/session_test/brute_force_protection_test.rb +101 -0
- data/test/session_test/callbacks_test.rb +54 -0
- data/test/session_test/cookies_test.rb +136 -0
- data/test/session_test/credentials_test.rb +0 -0
- data/test/session_test/existence_test.rb +64 -0
- data/test/session_test/http_auth_test.rb +57 -0
- data/test/session_test/id_test.rb +17 -0
- data/test/session_test/klass_test.rb +40 -0
- data/test/session_test/magic_columns_test.rb +62 -0
- data/test/session_test/magic_states_test.rb +60 -0
- data/test/session_test/params_test.rb +53 -0
- data/test/session_test/password_test.rb +106 -0
- data/test/session_test/perishability_test.rb +15 -0
- data/test/session_test/persistence_test.rb +21 -0
- data/test/session_test/scopes_test.rb +60 -0
- data/test/session_test/session_test.rb +59 -0
- data/test/session_test/timeout_test.rb +52 -0
- data/test/session_test/unauthorized_record_test.rb +13 -0
- data/test/session_test/validation_test.rb +23 -0
- data/test/test_helper.rb +168 -0
- metadata +252 -0
@@ -0,0 +1,9 @@
|
|
1
|
+
class SessionGenerator < Rails::Generator::NamedBase
|
2
|
+
def manifest
|
3
|
+
record do |m|
|
4
|
+
m.class_collisions class_name
|
5
|
+
m.directory File.join('app/models', class_path)
|
6
|
+
m.template 'session.rb', File.join('app/models', class_path, "#{file_name}.rb")
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/rails/init.rb"
|
data/lib/authlogic.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
require "active_record"
|
2
|
+
|
3
|
+
AUTHLOGIC_PATH = File.dirname(__FILE__) + "/authlogic/"
|
4
|
+
|
5
|
+
[
|
6
|
+
"i18n",
|
7
|
+
"random",
|
8
|
+
"regex",
|
9
|
+
|
10
|
+
"controller_adapters/abstract_adapter",
|
11
|
+
|
12
|
+
"crypto_providers/md5",
|
13
|
+
"crypto_providers/sha1",
|
14
|
+
"crypto_providers/sha256",
|
15
|
+
"crypto_providers/sha512",
|
16
|
+
"crypto_providers/bcrypt",
|
17
|
+
"crypto_providers/aes256",
|
18
|
+
|
19
|
+
"authenticates_many/base",
|
20
|
+
"authenticates_many/association",
|
21
|
+
|
22
|
+
"acts_as_authentic/email",
|
23
|
+
"acts_as_authentic/logged_in_status",
|
24
|
+
"acts_as_authentic/login",
|
25
|
+
"acts_as_authentic/magic_columns",
|
26
|
+
"acts_as_authentic/password",
|
27
|
+
"acts_as_authentic/perishable_token",
|
28
|
+
"acts_as_authentic/persistence_token",
|
29
|
+
"acts_as_authentic/restful_authentication",
|
30
|
+
"acts_as_authentic/session_maintenance",
|
31
|
+
"acts_as_authentic/single_access_token",
|
32
|
+
"acts_as_authentic/validations_scope",
|
33
|
+
"acts_as_authentic/base",
|
34
|
+
|
35
|
+
"session/activation",
|
36
|
+
"session/active_record_trickery",
|
37
|
+
"session/brute_force_protection",
|
38
|
+
"session/callbacks",
|
39
|
+
"session/cookies",
|
40
|
+
"session/existence",
|
41
|
+
"session/foundation",
|
42
|
+
"session/http_auth",
|
43
|
+
"session/id",
|
44
|
+
"session/klass",
|
45
|
+
"session/magic_columns",
|
46
|
+
"session/magic_states",
|
47
|
+
"session/params",
|
48
|
+
"session/password",
|
49
|
+
"session/perishable_token",
|
50
|
+
"session/persistence",
|
51
|
+
"session/priority_record",
|
52
|
+
"session/scopes",
|
53
|
+
"session/session",
|
54
|
+
"session/timeout",
|
55
|
+
"session/unauthorized_record",
|
56
|
+
"session/validation",
|
57
|
+
"session/base"
|
58
|
+
].each do |library|
|
59
|
+
require AUTHLOGIC_PATH + library
|
60
|
+
end
|
61
|
+
|
62
|
+
require AUTHLOGIC_PATH + "controller_adapters/rails_adapter" if defined?( Rails )
|
63
|
+
require AUTHLOGIC_PATH + "controller_adapters/merb_adapter" if defined?( Merb )
|
64
|
+
require AUTHLOGIC_PATH + "controller_adapters/sinatra_adapter" if defined?( Sinatra )
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module Authlogic
|
2
|
+
module ActsAsAuthentic
|
3
|
+
# Provides the base functionality for acts_as_authentic
|
4
|
+
module Base
|
5
|
+
def self.included(klass)
|
6
|
+
klass.class_eval do
|
7
|
+
class_attribute :acts_as_authentic_modules, :acts_as_authentic_config
|
8
|
+
self.acts_as_authentic_modules ||= []
|
9
|
+
self.acts_as_authentic_config ||= {}
|
10
|
+
extend Config
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module Config
|
15
|
+
# This includes a lot of helpful methods for authenticating records which The Authlogic::Session module relies on.
|
16
|
+
# To use it just do:
|
17
|
+
#
|
18
|
+
# class User < ActiveRecord::Base
|
19
|
+
# acts_as_authentic
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# Configuration is easy:
|
23
|
+
#
|
24
|
+
# acts_as_authentic do |c|
|
25
|
+
# c.my_configuration_option = my_value
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# See the various sub modules for the configuration they provide.
|
29
|
+
def acts_as_authentic(unsupported_options = nil, &block)
|
30
|
+
# Stop all configuration if the DB is not set up
|
31
|
+
raise StandardError.new("You must establish a database connection before using acts_as_authentic") if !db_setup?
|
32
|
+
|
33
|
+
raise ArgumentError.new("You are using the old v1.X.X configuration method for Authlogic. Instead of " +
|
34
|
+
"passing a hash of configuration options to acts_as_authentic, pass a block: acts_as_authentic { |c| c.my_option = my_value }") if !unsupported_options.nil?
|
35
|
+
|
36
|
+
yield self if block_given?
|
37
|
+
acts_as_authentic_modules.each { |mod| include mod }
|
38
|
+
end
|
39
|
+
|
40
|
+
# Since this part of Authlogic deals with another class, ActiveRecord, we can't just start including things
|
41
|
+
# in ActiveRecord itself. A lot of these module includes need to be triggered by the acts_as_authentic method
|
42
|
+
# call. For example, you don't want to start adding in email validations and what not into a model that has
|
43
|
+
# nothing to do with Authlogic.
|
44
|
+
#
|
45
|
+
# That being said, this is your tool for extending Authlogic and "hooking" into the acts_as_authentic call.
|
46
|
+
def add_acts_as_authentic_module(mod, action = :append)
|
47
|
+
modules = acts_as_authentic_modules.clone
|
48
|
+
case action
|
49
|
+
when :append
|
50
|
+
modules << mod
|
51
|
+
when :prepend
|
52
|
+
modules = [mod] + modules
|
53
|
+
end
|
54
|
+
modules.uniq!
|
55
|
+
self.acts_as_authentic_modules = modules
|
56
|
+
end
|
57
|
+
|
58
|
+
# This is the same as add_acts_as_authentic_module, except that it removes the module from the list.
|
59
|
+
def remove_acts_as_authentic_module(mod)
|
60
|
+
modules = acts_as_authentic_modules.clone
|
61
|
+
modules.delete(mod)
|
62
|
+
self.acts_as_authentic_modules = modules
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
def db_setup?
|
67
|
+
begin
|
68
|
+
column_names
|
69
|
+
true
|
70
|
+
rescue Exception
|
71
|
+
false
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def rw_config(key, value, default_value = nil, read_value = nil)
|
76
|
+
if value == read_value
|
77
|
+
acts_as_authentic_config.include?(key) ? acts_as_authentic_config[key] : default_value
|
78
|
+
else
|
79
|
+
config = acts_as_authentic_config.clone
|
80
|
+
config[key] = value
|
81
|
+
self.acts_as_authentic_config = config
|
82
|
+
value
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def first_column_to_exist(*columns_to_check)
|
87
|
+
if db_setup?
|
88
|
+
columns_to_check.each { |column_name| return column_name.to_sym if column_names.include?(column_name.to_s) }
|
89
|
+
end
|
90
|
+
columns_to_check.first && columns_to_check.first.to_sym
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
::ActiveRecord::Base.send :include, Authlogic::ActsAsAuthentic::Base
|
98
|
+
::ActiveRecord::Base.send :include, Authlogic::ActsAsAuthentic::Email
|
99
|
+
::ActiveRecord::Base.send :include, Authlogic::ActsAsAuthentic::LoggedInStatus
|
100
|
+
::ActiveRecord::Base.send :include, Authlogic::ActsAsAuthentic::Login
|
101
|
+
::ActiveRecord::Base.send :include, Authlogic::ActsAsAuthentic::MagicColumns
|
102
|
+
::ActiveRecord::Base.send :include, Authlogic::ActsAsAuthentic::Password
|
103
|
+
::ActiveRecord::Base.send :include, Authlogic::ActsAsAuthentic::PerishableToken
|
104
|
+
::ActiveRecord::Base.send :include, Authlogic::ActsAsAuthentic::PersistenceToken
|
105
|
+
::ActiveRecord::Base.send :include, Authlogic::ActsAsAuthentic::RestfulAuthentication
|
106
|
+
::ActiveRecord::Base.send :include, Authlogic::ActsAsAuthentic::SessionMaintenance
|
107
|
+
::ActiveRecord::Base.send :include, Authlogic::ActsAsAuthentic::SingleAccessToken
|
108
|
+
::ActiveRecord::Base.send :include, Authlogic::ActsAsAuthentic::ValidationsScope
|
109
|
+
|
@@ -0,0 +1,110 @@
|
|
1
|
+
module Authlogic
|
2
|
+
module ActsAsAuthentic
|
3
|
+
# Sometimes models won't have an explicit "login" or "username" field. Instead they want to use the email field.
|
4
|
+
# In this case, authlogic provides validations to make sure the email submited is actually a valid email. Don't worry,
|
5
|
+
# if you do have a login or username field, Authlogic will still validate your email field. One less thing you have to
|
6
|
+
# worry about.
|
7
|
+
module Email
|
8
|
+
def self.included(klass)
|
9
|
+
klass.class_eval do
|
10
|
+
extend Config
|
11
|
+
add_acts_as_authentic_module(Methods)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Configuration to modify how Authlogic handles the email field.
|
16
|
+
module Config
|
17
|
+
# The name of the field that stores email addresses.
|
18
|
+
#
|
19
|
+
# * <tt>Default:</tt> :email, if it exists
|
20
|
+
# * <tt>Accepts:</tt> Symbol
|
21
|
+
def email_field(value = nil)
|
22
|
+
rw_config(:email_field, value, first_column_to_exist(nil, :email, :email_address))
|
23
|
+
end
|
24
|
+
alias_method :email_field=, :email_field
|
25
|
+
|
26
|
+
# Toggles validating the email field or not.
|
27
|
+
#
|
28
|
+
# * <tt>Default:</tt> true
|
29
|
+
# * <tt>Accepts:</tt> Boolean
|
30
|
+
def validate_email_field(value = nil)
|
31
|
+
rw_config(:validate_email_field, value, true)
|
32
|
+
end
|
33
|
+
alias_method :validate_email_field=, :validate_email_field
|
34
|
+
|
35
|
+
# A hash of options for the validates_length_of call for the email field. Allows you to change this however you want.
|
36
|
+
#
|
37
|
+
# <b>Keep in mind this is ruby. I wanted to keep this as flexible as possible, so you can completely replace the hash or
|
38
|
+
# merge options into it. Checkout the convenience function merge_validates_length_of_email_field_options to merge
|
39
|
+
# options.</b>
|
40
|
+
#
|
41
|
+
# * <tt>Default:</tt> {:maximum => 100}
|
42
|
+
# * <tt>Accepts:</tt> Hash of options accepted by validates_length_of
|
43
|
+
def validates_length_of_email_field_options(value = nil)
|
44
|
+
rw_config(:validates_length_of_email_field_options, value, {:maximum => 100})
|
45
|
+
end
|
46
|
+
alias_method :validates_length_of_email_field_options=, :validates_length_of_email_field_options
|
47
|
+
|
48
|
+
# A convenience function to merge options into the validates_length_of_email_field_options. So intead of:
|
49
|
+
#
|
50
|
+
# self.validates_length_of_email_field_options = validates_length_of_email_field_options.merge(:my_option => my_value)
|
51
|
+
#
|
52
|
+
# You can do this:
|
53
|
+
#
|
54
|
+
# merge_validates_length_of_email_field_options :my_option => my_value
|
55
|
+
def merge_validates_length_of_email_field_options(options = {})
|
56
|
+
self.validates_length_of_email_field_options = validates_length_of_email_field_options.merge(options)
|
57
|
+
end
|
58
|
+
|
59
|
+
# A hash of options for the validates_format_of call for the email field. Allows you to change this however you want.
|
60
|
+
#
|
61
|
+
# <b>Keep in mind this is ruby. I wanted to keep this as flexible as possible, so you can completely replace the hash or
|
62
|
+
# merge options into it. Checkout the convenience function merge_validates_format_of_email_field_options to merge
|
63
|
+
# options.</b>
|
64
|
+
#
|
65
|
+
# * <tt>Default:</tt> {:with => Authlogic::Regex.email, :message => lambda {I18n.t('error_messages.email_invalid', :default => "should look like an email address.")}}
|
66
|
+
# * <tt>Accepts:</tt> Hash of options accepted by validates_format_of
|
67
|
+
def validates_format_of_email_field_options(value = nil)
|
68
|
+
rw_config(:validates_format_of_email_field_options, value, {:with => Authlogic::Regex.email, :message => Proc.new{I18n.t('error_messages.email_invalid', :default => "should look like an email address.")}})
|
69
|
+
end
|
70
|
+
alias_method :validates_format_of_email_field_options=, :validates_format_of_email_field_options
|
71
|
+
|
72
|
+
# See merge_validates_length_of_email_field_options. The same thing except for validates_format_of_email_field_options.
|
73
|
+
def merge_validates_format_of_email_field_options(options = {})
|
74
|
+
self.validates_format_of_email_field_options = validates_format_of_email_field_options.merge(options)
|
75
|
+
end
|
76
|
+
|
77
|
+
# A hash of options for the validates_uniqueness_of call for the email field. Allows you to change this however you want.
|
78
|
+
#
|
79
|
+
# <b>Keep in mind this is ruby. I wanted to keep this as flexible as possible, so you can completely replace the hash or
|
80
|
+
# merge options into it. Checkout the convenience function merge_validates_uniqueness_of_email_field_options to merge
|
81
|
+
# options.</b>
|
82
|
+
#
|
83
|
+
# * <tt>Default:</tt> {:case_sensitive => false, :scope => validations_scope, :if => "#{email_field}_changed?".to_sym}
|
84
|
+
# * <tt>Accepts:</tt> Hash of options accepted by validates_uniqueness_of
|
85
|
+
def validates_uniqueness_of_email_field_options(value = nil)
|
86
|
+
rw_config(:validates_uniqueness_of_email_field_options, value, {:case_sensitive => false, :scope => validations_scope, :if => "#{email_field}_changed?".to_sym})
|
87
|
+
end
|
88
|
+
alias_method :validates_uniqueness_of_email_field_options=, :validates_uniqueness_of_email_field_options
|
89
|
+
|
90
|
+
# See merge_validates_length_of_email_field_options. The same thing except for validates_uniqueness_of_email_field_options.
|
91
|
+
def merge_validates_uniqueness_of_email_field_options(options = {})
|
92
|
+
self.validates_uniqueness_of_email_field_options = validates_uniqueness_of_email_field_options.merge(options)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# All methods relating to the email field
|
97
|
+
module Methods
|
98
|
+
def self.included(klass)
|
99
|
+
klass.class_eval do
|
100
|
+
if validate_email_field && email_field
|
101
|
+
validates_length_of email_field, validates_length_of_email_field_options
|
102
|
+
validates_format_of email_field, validates_format_of_email_field_options
|
103
|
+
validates_uniqueness_of email_field, validates_uniqueness_of_email_field_options
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Authlogic
|
2
|
+
module ActsAsAuthentic
|
3
|
+
# Since web applications are stateless there is not sure fire way to tell if a user is logged in or not,
|
4
|
+
# from the database perspective. The best way to do this is to provide a "timeout" based on inactivity.
|
5
|
+
# So if that user is inactive for a certain amount of time we assume they are logged out. That's what this
|
6
|
+
# module is all about.
|
7
|
+
module LoggedInStatus
|
8
|
+
def self.included(klass)
|
9
|
+
klass.class_eval do
|
10
|
+
extend Config
|
11
|
+
add_acts_as_authentic_module(Methods)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# All configuration for the logged in status feature set.
|
16
|
+
module Config
|
17
|
+
# The timeout to determine when a user is logged in or not.
|
18
|
+
#
|
19
|
+
# * <tt>Default:</tt> 10.minutes
|
20
|
+
# * <tt>Accepts:</tt> Fixnum
|
21
|
+
def logged_in_timeout(value = nil)
|
22
|
+
rw_config(:logged_in_timeout, (!value.nil? && value.to_i) || value, 10.minutes.to_i)
|
23
|
+
end
|
24
|
+
alias_method :logged_in_timeout=, :logged_in_timeout
|
25
|
+
end
|
26
|
+
|
27
|
+
# All methods for the logged in status feature seat.
|
28
|
+
module Methods
|
29
|
+
def self.included(klass)
|
30
|
+
return if !klass.column_names.include?("last_request_at")
|
31
|
+
|
32
|
+
klass.class_eval do
|
33
|
+
include InstanceMethods
|
34
|
+
scope :logged_in, lambda{ where("last_request_at > ?", logged_in_timeout.seconds.ago) }
|
35
|
+
scope :logged_out, lambda{ where("last_request_at is NULL or last_request_at <= ?", logged_in_timeout.seconds.ago) }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
module InstanceMethods
|
40
|
+
# Returns true if the last_request_at > logged_in_timeout.
|
41
|
+
def logged_in?
|
42
|
+
raise "Can not determine the records login state because there is no last_request_at column" if !respond_to?(:last_request_at)
|
43
|
+
!last_request_at.nil? && last_request_at > logged_in_timeout.seconds.ago
|
44
|
+
end
|
45
|
+
|
46
|
+
# Opposite of logged_in?
|
47
|
+
def logged_out?
|
48
|
+
!logged_in?
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
def logged_in_timeout
|
53
|
+
self.class.logged_in_timeout
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
module Authlogic
|
2
|
+
module ActsAsAuthentic
|
3
|
+
# Handles everything related to the login field.
|
4
|
+
module Login
|
5
|
+
def self.included(klass)
|
6
|
+
klass.class_eval do
|
7
|
+
extend Config
|
8
|
+
add_acts_as_authentic_module(Methods)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# Configuration for the login field.
|
13
|
+
module Config
|
14
|
+
# The name of the login field in the database.
|
15
|
+
#
|
16
|
+
# * <tt>Default:</tt> :login or :username, if they exist
|
17
|
+
# * <tt>Accepts:</tt> Symbol
|
18
|
+
def login_field(value = nil)
|
19
|
+
rw_config(:login_field, value, first_column_to_exist(nil, :login, :username))
|
20
|
+
end
|
21
|
+
alias_method :login_field=, :login_field
|
22
|
+
|
23
|
+
# Whether or not to validate the login field
|
24
|
+
#
|
25
|
+
# * <tt>Default:</tt> true
|
26
|
+
# * <tt>Accepts:</tt> Boolean
|
27
|
+
def validate_login_field(value = nil)
|
28
|
+
rw_config(:validate_login_field, value, true)
|
29
|
+
end
|
30
|
+
alias_method :validate_login_field=, :validate_login_field
|
31
|
+
|
32
|
+
# A hash of options for the validates_length_of call for the login field. Allows you to change this however you want.
|
33
|
+
#
|
34
|
+
# <b>Keep in mind this is ruby. I wanted to keep this as flexible as possible, so you can completely replace the hash or
|
35
|
+
# merge options into it. Checkout the convenience function merge_validates_length_of_login_field_options to merge
|
36
|
+
# options.</b>
|
37
|
+
#
|
38
|
+
# * <tt>Default:</tt> {:within => 3..100}
|
39
|
+
# * <tt>Accepts:</tt> Hash of options accepted by validates_length_of
|
40
|
+
def validates_length_of_login_field_options(value = nil)
|
41
|
+
rw_config(:validates_length_of_login_field_options, value, {:within => 3..100})
|
42
|
+
end
|
43
|
+
alias_method :validates_length_of_login_field_options=, :validates_length_of_login_field_options
|
44
|
+
|
45
|
+
# A convenience function to merge options into the validates_length_of_login_field_options. So instead of:
|
46
|
+
#
|
47
|
+
# self.validates_length_of_login_field_options = validates_length_of_login_field_options.merge(:my_option => my_value)
|
48
|
+
#
|
49
|
+
# You can do this:
|
50
|
+
#
|
51
|
+
# merge_validates_length_of_login_field_options :my_option => my_value
|
52
|
+
def merge_validates_length_of_login_field_options(options = {})
|
53
|
+
self.validates_length_of_login_field_options = validates_length_of_login_field_options.merge(options)
|
54
|
+
end
|
55
|
+
|
56
|
+
# A hash of options for the validates_format_of call for the login field. Allows you to change this however you want.
|
57
|
+
#
|
58
|
+
# <b>Keep in mind this is ruby. I wanted to keep this as flexible as possible, so you can completely replace the hash or
|
59
|
+
# merge options into it. Checkout the convenience function merge_validates_format_of_login_field_options to merge
|
60
|
+
# options.</b>
|
61
|
+
#
|
62
|
+
# * <tt>Default:</tt> {:with => Authlogic::Regex.login, :message => lambda {I18n.t('error_messages.login_invalid', :default => "should use only letters, numbers, spaces, and .-_@ please.")}}
|
63
|
+
# * <tt>Accepts:</tt> Hash of options accepted by validates_format_of
|
64
|
+
def validates_format_of_login_field_options(value = nil)
|
65
|
+
rw_config(:validates_format_of_login_field_options, value, {:with => Authlogic::Regex.login, :message => Proc.new{I18n.t('error_messages.login_invalid', :default => "should use only letters, numbers, spaces, and .-_@ please.")}})
|
66
|
+
end
|
67
|
+
alias_method :validates_format_of_login_field_options=, :validates_format_of_login_field_options
|
68
|
+
|
69
|
+
# See merge_validates_length_of_login_field_options. The same thing, except for validates_format_of_login_field_options
|
70
|
+
def merge_validates_format_of_login_field_options(options = {})
|
71
|
+
self.validates_format_of_login_field_options = validates_format_of_login_field_options.merge(options)
|
72
|
+
end
|
73
|
+
|
74
|
+
# A hash of options for the validates_uniqueness_of call for the login field. Allows you to change this however you want.
|
75
|
+
#
|
76
|
+
# <b>Keep in mind this is ruby. I wanted to keep this as flexible as possible, so you can completely replace the hash or
|
77
|
+
# merge options into it. Checkout the convenience function merge_validates_format_of_login_field_options to merge
|
78
|
+
# options.</b>
|
79
|
+
#
|
80
|
+
# * <tt>Default:</tt> {:case_sensitive => false, :scope => validations_scope, :if => "#{login_field}_changed?".to_sym}
|
81
|
+
# * <tt>Accepts:</tt> Hash of options accepted by validates_uniqueness_of
|
82
|
+
def validates_uniqueness_of_login_field_options(value = nil)
|
83
|
+
rw_config(:validates_uniqueness_of_login_field_options, value, {:case_sensitive => false, :scope => validations_scope, :if => "#{login_field}_changed?".to_sym})
|
84
|
+
end
|
85
|
+
alias_method :validates_uniqueness_of_login_field_options=, :validates_uniqueness_of_login_field_options
|
86
|
+
|
87
|
+
# See merge_validates_length_of_login_field_options. The same thing, except for validates_uniqueness_of_login_field_options
|
88
|
+
def merge_validates_uniqueness_of_login_field_options(options = {})
|
89
|
+
self.validates_uniqueness_of_login_field_options = validates_uniqueness_of_login_field_options.merge(options)
|
90
|
+
end
|
91
|
+
|
92
|
+
# This method allows you to find a record with the given login. If you notice, with Active Record you have the
|
93
|
+
# validates_uniqueness_of validation function. They give you a :case_sensitive option. I handle this in the same
|
94
|
+
# manner that they handle that. If you are using the login field and set false for the :case_sensitive option in
|
95
|
+
# validates_uniqueness_of_login_field_options this method will modify the query to look something like:
|
96
|
+
#
|
97
|
+
# where("#{quoted_table_name}.#{field} LIKE ?", login).first
|
98
|
+
#
|
99
|
+
# If you don't specify this it calls the good old find_by_* method:
|
100
|
+
#
|
101
|
+
# find_by_login(login)
|
102
|
+
#
|
103
|
+
# The above also applies for using email as your login, except that you need to set the :case_sensitive in
|
104
|
+
# validates_uniqueness_of_email_field_options to false.
|
105
|
+
#
|
106
|
+
# The only reason I need to do the above is for Postgres and SQLite since they perform case sensitive searches with the
|
107
|
+
# find_by_* methods.
|
108
|
+
def find_by_smart_case_login_field(login)
|
109
|
+
if login_field
|
110
|
+
find_with_case(login_field, login, validates_uniqueness_of_login_field_options[:case_sensitive] != false)
|
111
|
+
else
|
112
|
+
find_with_case(email_field, login, validates_uniqueness_of_email_field_options[:case_sensitive] != false)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
private
|
117
|
+
def find_with_case(field, value, sensitivity = true)
|
118
|
+
if sensitivity
|
119
|
+
send("find_by_#{field}", value)
|
120
|
+
else
|
121
|
+
like_word = ::ActiveRecord::Base.connection.adapter_name == "PostgreSQL" ? "ILIKE" : "LIKE"
|
122
|
+
where("#{quoted_table_name}.#{field} #{like_word} ?", value.mb_chars).first
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# All methods relating to the login field
|
128
|
+
module Methods
|
129
|
+
# Adds in various validations, modules, etc.
|
130
|
+
def self.included(klass)
|
131
|
+
klass.class_eval do
|
132
|
+
if validate_login_field && login_field
|
133
|
+
validates_length_of login_field, validates_length_of_login_field_options
|
134
|
+
validates_format_of login_field, validates_format_of_login_field_options
|
135
|
+
validates_uniqueness_of login_field, validates_uniqueness_of_login_field_options
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|