authlogic 1.4.3 → 2.0.0
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 +19 -0
- data/Manifest.txt +111 -0
- data/README.rdoc +116 -389
- data/Rakefile +14 -7
- data/lib/authlogic.rb +33 -35
- data/lib/authlogic/acts_as_authentic/base.rb +91 -0
- data/lib/authlogic/acts_as_authentic/email.rb +77 -0
- data/lib/authlogic/acts_as_authentic/logged_in_status.rb +54 -0
- data/lib/authlogic/acts_as_authentic/login.rb +65 -0
- data/lib/authlogic/acts_as_authentic/magic_columns.rb +24 -0
- data/lib/authlogic/acts_as_authentic/password.rb +215 -0
- data/lib/authlogic/acts_as_authentic/perishable_token.rb +100 -0
- data/lib/authlogic/acts_as_authentic/persistence_token.rb +66 -0
- data/lib/authlogic/acts_as_authentic/restful_authentication.rb +60 -0
- data/lib/authlogic/acts_as_authentic/session_maintenance.rb +127 -0
- data/lib/authlogic/acts_as_authentic/single_access_token.rb +58 -0
- data/lib/authlogic/acts_as_authentic/validations_scope.rb +32 -0
- data/lib/authlogic/{session/authenticates_many_association.rb → authenticates_many/association.rb} +10 -6
- data/lib/authlogic/authenticates_many/base.rb +55 -0
- data/lib/authlogic/controller_adapters/abstract_adapter.rb +2 -3
- data/lib/authlogic/controller_adapters/merb_adapter.rb +0 -4
- data/lib/authlogic/controller_adapters/rails_adapter.rb +0 -4
- data/lib/authlogic/crypto_providers/aes256.rb +0 -2
- data/lib/authlogic/crypto_providers/bcrypt.rb +0 -2
- data/lib/authlogic/crypto_providers/md5.rb +34 -0
- data/lib/authlogic/crypto_providers/sha1.rb +0 -2
- data/lib/authlogic/crypto_providers/sha512.rb +1 -3
- data/lib/authlogic/i18n.rb +1 -4
- data/lib/authlogic/random.rb +33 -0
- data/lib/authlogic/session/activation.rb +56 -0
- data/lib/authlogic/session/active_record_trickery.rb +15 -7
- data/lib/authlogic/session/base.rb +31 -456
- data/lib/authlogic/session/brute_force_protection.rb +50 -27
- data/lib/authlogic/session/callbacks.rb +24 -15
- data/lib/authlogic/session/cookies.rb +108 -22
- data/lib/authlogic/session/existence.rb +89 -0
- data/lib/authlogic/session/foundation.rb +63 -0
- data/lib/authlogic/session/http_auth.rb +23 -0
- data/lib/authlogic/session/id.rb +41 -0
- data/lib/authlogic/session/klass.rb +75 -0
- data/lib/authlogic/session/magic_columns.rb +75 -0
- data/lib/authlogic/session/magic_states.rb +58 -0
- data/lib/authlogic/session/params.rb +82 -19
- data/lib/authlogic/session/password.rb +156 -0
- data/lib/authlogic/session/{perishability.rb → perishable_token.rb} +4 -4
- data/lib/authlogic/session/persistence.rb +70 -0
- data/lib/authlogic/session/priority_record.rb +34 -0
- data/lib/authlogic/session/scopes.rb +57 -53
- data/lib/authlogic/session/session.rb +46 -31
- data/lib/authlogic/session/timeout.rb +65 -31
- data/lib/authlogic/session/unauthorized_record.rb +50 -0
- data/lib/authlogic/session/validation.rb +76 -0
- data/lib/authlogic/testing/test_unit_helpers.rb +3 -3
- data/lib/authlogic/version.rb +3 -3
- data/test/acts_as_authentic_test/base_test.rb +12 -0
- data/test/acts_as_authentic_test/email_test.rb +79 -0
- data/test/acts_as_authentic_test/logged_in_status_test.rb +36 -0
- data/test/acts_as_authentic_test/login_test.rb +79 -0
- data/test/acts_as_authentic_test/magic_columns_test.rb +27 -0
- data/test/acts_as_authentic_test/password_test.rb +212 -0
- data/test/acts_as_authentic_test/perishable_token_test.rb +56 -0
- data/test/acts_as_authentic_test/persistence_token_test.rb +55 -0
- data/test/acts_as_authentic_test/session_maintenance_test.rb +68 -0
- data/test/acts_as_authentic_test/single_access_test.rb +39 -0
- data/test/authenticates_many_test.rb +16 -0
- data/test/{crypto_provider_tests → crypto_provider_test}/aes256_test.rb +1 -1
- data/test/{crypto_provider_tests → crypto_provider_test}/bcrypt_test.rb +1 -1
- data/test/{crypto_provider_tests → crypto_provider_test}/sha1_test.rb +1 -1
- data/test/{crypto_provider_tests → crypto_provider_test}/sha512_test.rb +1 -1
- data/test/fixtures/employees.yml +4 -4
- data/test/fixtures/users.yml +6 -6
- 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/project.rb +3 -0
- data/test/libs/user_session.rb +2 -0
- data/test/random_test.rb +49 -0
- data/test/session_test/activation_test.rb +43 -0
- data/test/session_test/active_record_trickery_test.rb +26 -0
- data/test/session_test/brute_force_protection_test.rb +76 -0
- data/test/session_test/callbacks_test.rb +6 -0
- data/test/session_test/cookies_test.rb +107 -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 +16 -0
- data/test/session_test/id_test.rb +17 -0
- data/test/session_test/klass_test.rb +35 -0
- data/test/session_test/magic_columns_test.rb +59 -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 +84 -0
- data/test/{session_tests → session_test}/perishability_test.rb +1 -1
- data/test/session_test/persistence_test.rb +21 -0
- data/test/{session_tests → session_test}/scopes_test.rb +2 -3
- data/test/session_test/session_test.rb +59 -0
- data/test/session_test/timeout_test.rb +43 -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 +14 -29
- metadata +120 -112
- data/Manifest +0 -76
- data/authlogic.gemspec +0 -38
- data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/base.rb +0 -22
- data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/config.rb +0 -238
- data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/credentials.rb +0 -155
- data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/logged_in.rb +0 -51
- data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/perishability.rb +0 -71
- data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/persistence.rb +0 -94
- data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/session_maintenance.rb +0 -87
- data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/single_access.rb +0 -61
- data/lib/authlogic/orm_adapters/active_record_adapter/authenticates_many.rb +0 -58
- data/lib/authlogic/session/config.rb +0 -421
- data/lib/authlogic/session/errors.rb +0 -18
- data/lib/authlogic/session/record_info.rb +0 -24
- data/test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/config_test.rb +0 -154
- data/test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/credentials_test.rb +0 -157
- data/test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/logged_in_test.rb +0 -24
- data/test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/perishability_test.rb +0 -41
- data/test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/persistence_test.rb +0 -54
- data/test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/session_maintenance_test.rb +0 -62
- data/test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/single_access_test.rb +0 -41
- data/test/orm_adapters_tests/active_record_adapter_tests/authenticates_many_test.rb +0 -32
- data/test/session_tests/active_record_trickery_test.rb +0 -14
- data/test/session_tests/authenticates_many_association_test.rb +0 -28
- data/test/session_tests/base_test.rb +0 -307
- data/test/session_tests/brute_force_protection_test.rb +0 -53
- data/test/session_tests/config_test.rb +0 -184
- data/test/session_tests/cookies_test.rb +0 -32
- data/test/session_tests/params_test.rb +0 -32
- data/test/session_tests/session_test.rb +0 -45
- data/test/session_tests/timeout_test.rb +0 -71
data/Rakefile
CHANGED
@@ -1,13 +1,20 @@
|
|
1
|
-
|
1
|
+
ENV['RDOCOPT'] = "-S -f html -T hanna"
|
2
|
+
|
3
|
+
require "rubygems"
|
4
|
+
require "hoe"
|
2
5
|
require File.dirname(__FILE__) << "/lib/authlogic/version"
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
p.version = Authlogic::Version::STRING
|
6
|
+
|
7
|
+
Hoe.new("Authlogic", Authlogic::Version::STRING) do |p|
|
8
|
+
p.name = "authlogic"
|
7
9
|
p.author = "Ben Johnson of Binary Logic"
|
8
10
|
p.email = 'bjohnson@binarylogic.com'
|
9
|
-
p.project = 'authlogic'
|
10
11
|
p.summary = "A clean, simple, and unobtrusive ruby authentication solution."
|
12
|
+
p.description = "A clean, simple, and unobtrusive ruby authentication solution."
|
11
13
|
p.url = "http://github.com/binarylogic/authlogic"
|
12
|
-
p.
|
14
|
+
p.history_file = "CHANGELOG.rdoc"
|
15
|
+
p.readme_file = "README.rdoc"
|
16
|
+
p.extra_rdoc_files = ["CHANGELOG.rdoc", "README.rdoc"]
|
17
|
+
p.test_globs = ["test/*/test_*.rb", "test/*/*_test.rb"]
|
18
|
+
p.extra_deps = %w(activesupport)
|
19
|
+
p.post_install_message = "Version 2.0 introduces some changes that break backwards compatibility. The big change is how acts_as_authentic accepts configuration options. Instead of a hash, it now accepts a block: acts_as_authentic { |c| c.my_config_option = my_value}. See the docs for more details."
|
13
20
|
end
|
data/lib/authlogic.rb
CHANGED
@@ -2,56 +2,54 @@ require "active_support"
|
|
2
2
|
|
3
3
|
require File.dirname(__FILE__) + "/authlogic/version"
|
4
4
|
require File.dirname(__FILE__) + "/authlogic/i18n"
|
5
|
+
require File.dirname(__FILE__) + "/authlogic/random"
|
5
6
|
|
6
7
|
require File.dirname(__FILE__) + "/authlogic/controller_adapters/abstract_adapter"
|
7
8
|
require File.dirname(__FILE__) + "/authlogic/controller_adapters/rails_adapter" if defined?(Rails)
|
8
9
|
require File.dirname(__FILE__) + "/authlogic/controller_adapters/merb_adapter" if defined?(Merb)
|
9
10
|
|
11
|
+
require File.dirname(__FILE__) + "/authlogic/crypto_providers/md5"
|
10
12
|
require File.dirname(__FILE__) + "/authlogic/crypto_providers/sha1"
|
11
13
|
require File.dirname(__FILE__) + "/authlogic/crypto_providers/sha512"
|
12
14
|
require File.dirname(__FILE__) + "/authlogic/crypto_providers/bcrypt"
|
13
15
|
require File.dirname(__FILE__) + "/authlogic/crypto_providers/aes256"
|
14
16
|
|
15
|
-
|
16
|
-
|
17
|
-
require File.dirname(__FILE__) + "/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/credentials"
|
18
|
-
require File.dirname(__FILE__) + "/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/logged_in"
|
19
|
-
require File.dirname(__FILE__) + "/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/perishability"
|
20
|
-
require File.dirname(__FILE__) + "/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/persistence"
|
21
|
-
require File.dirname(__FILE__) + "/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/session_maintenance"
|
22
|
-
require File.dirname(__FILE__) + "/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/single_access"
|
23
|
-
require File.dirname(__FILE__) + "/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/config" # call this last so the configuration options are passed down the chain
|
24
|
-
require File.dirname(__FILE__) + "/authlogic/orm_adapters/active_record_adapter/authenticates_many"
|
25
|
-
end
|
17
|
+
require File.dirname(__FILE__) + "/authlogic/authenticates_many/base"
|
18
|
+
require File.dirname(__FILE__) + "/authlogic/authenticates_many/association"
|
26
19
|
|
27
|
-
require File.dirname(__FILE__) + "/authlogic/
|
20
|
+
require File.dirname(__FILE__) + "/authlogic/acts_as_authentic/email"
|
21
|
+
require File.dirname(__FILE__) + "/authlogic/acts_as_authentic/logged_in_status"
|
22
|
+
require File.dirname(__FILE__) + "/authlogic/acts_as_authentic/login"
|
23
|
+
require File.dirname(__FILE__) + "/authlogic/acts_as_authentic/magic_columns"
|
24
|
+
require File.dirname(__FILE__) + "/authlogic/acts_as_authentic/password"
|
25
|
+
require File.dirname(__FILE__) + "/authlogic/acts_as_authentic/perishable_token"
|
26
|
+
require File.dirname(__FILE__) + "/authlogic/acts_as_authentic/persistence_token"
|
27
|
+
require File.dirname(__FILE__) + "/authlogic/acts_as_authentic/restful_authentication"
|
28
|
+
require File.dirname(__FILE__) + "/authlogic/acts_as_authentic/session_maintenance"
|
29
|
+
require File.dirname(__FILE__) + "/authlogic/acts_as_authentic/single_access_token"
|
30
|
+
require File.dirname(__FILE__) + "/authlogic/acts_as_authentic/validations_scope"
|
31
|
+
require File.dirname(__FILE__) + "/authlogic/acts_as_authentic/base"
|
32
|
+
|
33
|
+
require File.dirname(__FILE__) + "/authlogic/session/activation"
|
28
34
|
require File.dirname(__FILE__) + "/authlogic/session/active_record_trickery"
|
29
35
|
require File.dirname(__FILE__) + "/authlogic/session/brute_force_protection"
|
30
36
|
require File.dirname(__FILE__) + "/authlogic/session/callbacks"
|
31
|
-
require File.dirname(__FILE__) + "/authlogic/session/config"
|
32
37
|
require File.dirname(__FILE__) + "/authlogic/session/cookies"
|
33
|
-
require File.dirname(__FILE__) + "/authlogic/session/
|
38
|
+
require File.dirname(__FILE__) + "/authlogic/session/existence"
|
39
|
+
require File.dirname(__FILE__) + "/authlogic/session/foundation"
|
40
|
+
require File.dirname(__FILE__) + "/authlogic/session/http_auth"
|
41
|
+
require File.dirname(__FILE__) + "/authlogic/session/id"
|
42
|
+
require File.dirname(__FILE__) + "/authlogic/session/klass"
|
43
|
+
require File.dirname(__FILE__) + "/authlogic/session/magic_columns"
|
44
|
+
require File.dirname(__FILE__) + "/authlogic/session/magic_states"
|
34
45
|
require File.dirname(__FILE__) + "/authlogic/session/params"
|
35
|
-
require File.dirname(__FILE__) + "/authlogic/session/
|
36
|
-
require File.dirname(__FILE__) + "/authlogic/session/
|
37
|
-
require File.dirname(__FILE__) + "/authlogic/session/
|
46
|
+
require File.dirname(__FILE__) + "/authlogic/session/password"
|
47
|
+
require File.dirname(__FILE__) + "/authlogic/session/perishable_token"
|
48
|
+
require File.dirname(__FILE__) + "/authlogic/session/persistence"
|
49
|
+
require File.dirname(__FILE__) + "/authlogic/session/priority_record"
|
38
50
|
require File.dirname(__FILE__) + "/authlogic/session/scopes"
|
51
|
+
require File.dirname(__FILE__) + "/authlogic/session/session"
|
39
52
|
require File.dirname(__FILE__) + "/authlogic/session/timeout"
|
40
|
-
require File.dirname(__FILE__) + "/authlogic/session/
|
41
|
-
|
42
|
-
|
43
|
-
module Session
|
44
|
-
class Base
|
45
|
-
include ActiveRecordTrickery
|
46
|
-
include Callbacks
|
47
|
-
include BruteForceProtection
|
48
|
-
include Cookies
|
49
|
-
include Params
|
50
|
-
include Perishability
|
51
|
-
include RecordInfo
|
52
|
-
include Session
|
53
|
-
include Scopes
|
54
|
-
include Timeout
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
53
|
+
require File.dirname(__FILE__) + "/authlogic/session/unauthorized_record"
|
54
|
+
require File.dirname(__FILE__) + "/authlogic/session/validation"
|
55
|
+
require File.dirname(__FILE__) + "/authlogic/session/base"
|
@@ -0,0 +1,91 @@
|
|
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
|
+
extend Config
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
module Config
|
12
|
+
# This includes a lot of helpful methods for authenticating records which The Authlogic::Session module relies on.
|
13
|
+
# To use it just do:
|
14
|
+
#
|
15
|
+
# class User < ActiveRecord::Base
|
16
|
+
# acts_as_authentic
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# Configuration is easy:
|
20
|
+
#
|
21
|
+
# acts_as_authentic do |c|
|
22
|
+
# c.my_configuration_option = my_value
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# See the various sub modules for the configuration they provide.
|
26
|
+
def acts_as_authentic(&block)
|
27
|
+
yield self if block_given?
|
28
|
+
acts_as_authentic_modules.each { |mod| include mod }
|
29
|
+
end
|
30
|
+
|
31
|
+
# Since this part of Authlogic deals with another class, ActiveRecord, we can't just start including things
|
32
|
+
# in ActiveRecord itself. A lot of these module includes need to be triggered by the acts_as_authentic method
|
33
|
+
# call. For example, you don't want to start adding in email validations and what not into a model that has
|
34
|
+
# nothing to do with Authlogic.
|
35
|
+
#
|
36
|
+
# That being said, this is your tool for extending Authlogic and "hooking" into the acts_as_authentic call.
|
37
|
+
def add_acts_as_authentic_module(mod)
|
38
|
+
modules = acts_as_authentic_modules
|
39
|
+
modules << mod
|
40
|
+
modules.uniq!
|
41
|
+
write_inheritable_attribute(:acts_as_authentic_modules, modules)
|
42
|
+
end
|
43
|
+
|
44
|
+
# This is the same as add_acts_as_authentic_module, except that it removes the module from the list.
|
45
|
+
def remove_acts_as_authentic_module(mod)
|
46
|
+
acts_as_authentic_modules.delete(mod)
|
47
|
+
acts_as_authentic_modules
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
def acts_as_authentic_modules
|
52
|
+
key = :acts_as_authentic_modules
|
53
|
+
inheritable_attributes.include?(key) ? read_inheritable_attribute(key) : []
|
54
|
+
end
|
55
|
+
|
56
|
+
def config(key, value, default_value = nil, read_value = nil)
|
57
|
+
if value == read_value
|
58
|
+
return read_inheritable_attribute(key) if inheritable_attributes.include?(key)
|
59
|
+
write_inheritable_attribute(key, default_value)
|
60
|
+
else
|
61
|
+
write_inheritable_attribute(key, value)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def first_column_to_exist(*columns_to_check) # :nodoc:
|
66
|
+
columns_to_check.each { |column_name| return column_name.to_sym if column_names.include?(column_name.to_s) }
|
67
|
+
columns_to_check.first ? columns_to_check.first.to_sym : nil
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
if defined?(::ActiveRecord)
|
75
|
+
module ::ActiveRecord
|
76
|
+
class Base
|
77
|
+
include Authlogic::ActsAsAuthentic::Base
|
78
|
+
include Authlogic::ActsAsAuthentic::Email
|
79
|
+
include Authlogic::ActsAsAuthentic::LoggedInStatus
|
80
|
+
include Authlogic::ActsAsAuthentic::Login
|
81
|
+
include Authlogic::ActsAsAuthentic::MagicColumns
|
82
|
+
include Authlogic::ActsAsAuthentic::Password
|
83
|
+
include Authlogic::ActsAsAuthentic::PerishableToken
|
84
|
+
include Authlogic::ActsAsAuthentic::PersistenceToken
|
85
|
+
include Authlogic::ActsAsAuthentic::RestfulAuthentication
|
86
|
+
include Authlogic::ActsAsAuthentic::SessionMaintenance
|
87
|
+
include Authlogic::ActsAsAuthentic::SingleAccessToken
|
88
|
+
include Authlogic::ActsAsAuthentic::ValidationsScope
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,77 @@
|
|
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
|
+
config(:email_field, value, first_column_to_exist(nil, :email))
|
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
|
+
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
|
+
# * <tt>Default:</tt> {:within => 6..100}
|
38
|
+
# * <tt>Accepts:</tt> Hash of options accepted by validates_length_of
|
39
|
+
def validates_length_of_email_field_options(value = nil)
|
40
|
+
config(:validates_length_of_email_field_options, value, {:within => 6..100})
|
41
|
+
end
|
42
|
+
alias_method :validates_length_of_email_field_options=, :validates_length_of_email_field_options
|
43
|
+
|
44
|
+
# A hash of options for the validates_format_of call for the email field. Allows you to change this however you want.
|
45
|
+
#
|
46
|
+
# * <tt>Default:</tt> {:with => email_regex, :message => I18n.t('error_messages.email_invalid', :default => "should look like an email address.")}
|
47
|
+
# * <tt>Accepts:</tt> Hash of options accepted by validates_format_of
|
48
|
+
def validates_format_of_email_field_options(value = nil)
|
49
|
+
config(:validates_format_of_email_field_options, value, {:with => email_regex, :message => I18n.t('error_messages.email_invalid', :default => "should look like an email address.")})
|
50
|
+
end
|
51
|
+
alias_method :validates_format_of_email_field_options=, :validates_format_of_email_field_options
|
52
|
+
|
53
|
+
private
|
54
|
+
def email_regex
|
55
|
+
return @email_regex if @email_regex
|
56
|
+
email_name_regex = '[\w\.%\+\-]+'
|
57
|
+
domain_head_regex = '(?:[A-Z0-9\-]+\.)+'
|
58
|
+
domain_tld_regex = '(?:[A-Z]{2}|aero|ag|asia|at|be|biz|ca|cc|cn|com|de|edu|eu|fm|gov|gs|jobs|jp|in|info|me|mil|mobi|museum|ms|name|net|nu|nz|org|tc|tw|tv|uk|us|vg|ws)'
|
59
|
+
@email_regex = /\A#{email_name_regex}@#{domain_head_regex}#{domain_tld_regex}\z/i
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# All methods relating to the email field
|
64
|
+
module Methods
|
65
|
+
def self.included(klass)
|
66
|
+
klass.class_eval do
|
67
|
+
if validate_email_field && email_field
|
68
|
+
validates_length_of email_field, validates_length_of_email_field_options
|
69
|
+
validates_format_of email_field, validates_format_of_email_field_options
|
70
|
+
validates_uniqueness_of email_field, :scope => validations_scope, :if => "#{email_field}_changed?".to_sym
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,54 @@
|
|
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
|
+
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
|
+
klass.class_eval do
|
31
|
+
named_scope :logged_in, lambda { {:conditions => ["last_request_at > ?", logged_in_timeout.seconds.ago]} }
|
32
|
+
named_scope :logged_out, lambda { {:conditions => ["last_request_at is NULL or last_request_at <= ?", logged_in_timeout.seconds.ago]} }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Returns true if the last_request_at > logged_in_timeout.
|
37
|
+
def logged_in?
|
38
|
+
raise "Can not determine the records login state because there is no last_request_at column" if !respond_to?(:last_request_at)
|
39
|
+
!last_request_at.nil? && last_request_at > logged_in_timeout.seconds.ago
|
40
|
+
end
|
41
|
+
|
42
|
+
# Opposite of logged_in?
|
43
|
+
def logged_out?
|
44
|
+
!logged_in?
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
def logged_in_timeout
|
49
|
+
self.class.logged_in_timeout
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,65 @@
|
|
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
|
+
# Confguration 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
|
+
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 the validate the login field
|
24
|
+
#
|
25
|
+
# * <tt>Default:</tt> true
|
26
|
+
# * <tt>Accepts:</tt> Boolean
|
27
|
+
def validate_login_field(value = nil)
|
28
|
+
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
|
+
# * <tt>Default:</tt> {:within => 6..100}
|
35
|
+
# * <tt>Accepts:</tt> Hash of options accepted by validates_length_of
|
36
|
+
def validates_length_of_login_field_options(value = nil)
|
37
|
+
config(:validates_length_of_login_field_options, value, {:within => 3..100})
|
38
|
+
end
|
39
|
+
alias_method :validates_length_of_login_field_options=, :validates_length_of_login_field_options
|
40
|
+
|
41
|
+
# A hash of options for the validates_format_of call for the email field. Allows you to change this however you want.
|
42
|
+
#
|
43
|
+
# * <tt>Default:</tt> {:with => /\A\w[\w\.\-_@ ]+\z/, :message => I18n.t('error_messages.login_invalid', :default => "should use only letters, numbers, spaces, and .-_@ please.")}
|
44
|
+
# * <tt>Accepts:</tt> Hash of options accepted by validates_format_of
|
45
|
+
def validates_format_of_login_field_options(value = nil)
|
46
|
+
config(:validates_format_of_login_field_options, value, {:with => /\A\w[\w\.\-_@ ]+\z/, :message => I18n.t('error_messages.login_invalid', :default => "should use only letters, numbers, spaces, and .-_@ please.")})
|
47
|
+
end
|
48
|
+
alias_method :validates_format_of_login_field_options=, :validates_format_of_login_field_options
|
49
|
+
end
|
50
|
+
|
51
|
+
# All methods relating to the login field
|
52
|
+
module Methods
|
53
|
+
def self.included(klass)
|
54
|
+
klass.class_eval do
|
55
|
+
if validate_login_field && login_field
|
56
|
+
validates_length_of login_field, validates_length_of_login_field_options
|
57
|
+
validates_format_of login_field, validates_format_of_login_field_options
|
58
|
+
validates_uniqueness_of login_field, :scope => validations_scope, :if => "#{login_field}_changed?".to_sym
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Authlogic
|
2
|
+
module ActsAsAuthentic
|
3
|
+
# Magic columns are like ActiveRecord's created_at and updated_at columns. They are "magically" maintained for
|
4
|
+
# you. Authlogic has the same thing, but these are maintained on the session side. Please see Authlogic::Session::MagicColumns
|
5
|
+
# for more details. This module merely adds validations for the magic columns if they exist.
|
6
|
+
module MagicColumns
|
7
|
+
def self.included(klass)
|
8
|
+
klass.class_eval do
|
9
|
+
add_acts_as_authentic_module(Methods)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# Methods relating to the magic columns
|
14
|
+
module Methods
|
15
|
+
def self.included(klass)
|
16
|
+
klass.class_eval do
|
17
|
+
validates_numericality_of :login_count, :only_integer => :true, :greater_than_or_equal_to => 0, :allow_nil => true if column_names.include?("login_count")
|
18
|
+
validates_numericality_of :failed_login_count, :only_integer => :true, :greater_than_or_equal_to => 0, :allow_nil => true if column_names.include?("failed_login_count")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,215 @@
|
|
1
|
+
module Authlogic
|
2
|
+
module ActsAsAuthentic
|
3
|
+
# This module has a lot of neat functionality. It is responsible for encrypting your password, salting it, and verifying it.
|
4
|
+
# It can also help you transition to a new encryption algorithm. See the Config sub module for configuration options.
|
5
|
+
module Password
|
6
|
+
def self.included(klass)
|
7
|
+
klass.class_eval do
|
8
|
+
extend Config
|
9
|
+
add_acts_as_authentic_module(Callbacks)
|
10
|
+
add_acts_as_authentic_module(Methods)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# All configuration for the password aspect of acts_as_authentic.
|
15
|
+
module Config
|
16
|
+
# The name of the crypted_password field in the database.
|
17
|
+
#
|
18
|
+
# * <tt>Default:</tt> :crypted_password, :encrypted_password, :password_hash, or :pw_hash
|
19
|
+
# * <tt>Accepts:</tt> Symbol
|
20
|
+
def crypted_password_field(value = nil)
|
21
|
+
config(:crypted_password_field, value, first_column_to_exist(:crypted_password, :encrypted_password, :password_hash, :pw_hash))
|
22
|
+
end
|
23
|
+
alias_method :crypted_password_field=, :crypted_password_field
|
24
|
+
|
25
|
+
# The name of the password_salt field in the database.
|
26
|
+
#
|
27
|
+
# * <tt>Default:</tt> :password_salt, :pw_salt, :salt, nil if none exist
|
28
|
+
# * <tt>Accepts:</tt> Symbol
|
29
|
+
def password_salt_field(value = nil)
|
30
|
+
config(:password_salt_field, value, first_column_to_exist(nil, :password_salt, :pw_salt, :salt))
|
31
|
+
end
|
32
|
+
alias_method :password_salt_field=, :password_salt_field
|
33
|
+
|
34
|
+
# Whether or not to validate the password field.
|
35
|
+
#
|
36
|
+
# * <tt>Default:</tt> true
|
37
|
+
# * <tt>Accepts:</tt> Boolean
|
38
|
+
def validate_password_field(value = nil)
|
39
|
+
config(:validate_password_field, value, true)
|
40
|
+
end
|
41
|
+
alias_method :validate_password_field=, :validate_password_field
|
42
|
+
|
43
|
+
# A hash of options for the validates_confirmation_of call for the password field. Allows you to change this however you want.
|
44
|
+
#
|
45
|
+
# * <tt>Default:</tt> {:minimum => 4, :if => "#{password_salt_field}_changed?".to_sym}
|
46
|
+
# * <tt>Accepts:</tt> Hash of options accepted by validates_confirmation_of
|
47
|
+
def validates_confirmation_of_password_field_options(value = nil)
|
48
|
+
config(:validates_confirmation_of_password_field_options, value, {:minimum => 4, :if => (password_salt_field ? "#{password_salt_field}_changed?".to_sym : nil)})
|
49
|
+
end
|
50
|
+
alias_method :validates_confirmation_of_password_field_options=, :validates_confirmation_of_password_field_options
|
51
|
+
|
52
|
+
# A hash of options for the validates_length_of call for the password_confirmation field. Allows you to change this however you want.
|
53
|
+
#
|
54
|
+
# * <tt>Default:</tt> {:minimum => 4, :if => :require_password_confirmation?}
|
55
|
+
# * <tt>Accepts:</tt> Hash of options accepted by validates_length_of
|
56
|
+
def validates_length_of_password_confirmation_field_options(value = nil)
|
57
|
+
config(:validates_length_of_password_confirmation_field_options, value, {:minimum => 4, :if => :require_password_confirmation?})
|
58
|
+
end
|
59
|
+
alias_method :validates_length_of_password_confirmation_field_options=, :validates_length_of_password_confirmation_field_options
|
60
|
+
|
61
|
+
# The class you want to use to encrypt and verify your encrypted passwords. See the Authlogic::CryptoProviders module for more info
|
62
|
+
# on the available methods and how to create your own.
|
63
|
+
#
|
64
|
+
# * <tt>Default:</tt> CryptoProviders::Sha512
|
65
|
+
# * <tt>Accepts:</tt> Class
|
66
|
+
def crypto_provider(value = nil)
|
67
|
+
config(:crypto_provider, value, CryptoProviders::Sha512)
|
68
|
+
end
|
69
|
+
alias_method :crypto_provider=, :crypto_provider
|
70
|
+
|
71
|
+
# Let's say you originally encrypted your passwords with Sha1. Sha1 is starting to join the party with MD5 and you want to switch
|
72
|
+
# to something stronger. No problem, just specify your new and improved algorithm with the crypt_provider option and then let
|
73
|
+
# Authlogic know you are transitioning from Sha1 using this option. Authlogic will take care of everything, including transitioning
|
74
|
+
# your users to the new algorithm. The next time a user logs in, they will be granted access using the old algorithm and their
|
75
|
+
# password will be resaved with the new algorithm. All new users will obviously use the new algorithm as well.
|
76
|
+
#
|
77
|
+
# Lastly, if you want to transition again, you can pass an array of crypto providers. So you can transition from as many algorithms
|
78
|
+
# as you want.
|
79
|
+
#
|
80
|
+
# * <tt>Default:</tt> nil
|
81
|
+
# * <tt>Accepts:</tt> Class or Array
|
82
|
+
def transition_from_crypto_providers(value = nil)
|
83
|
+
config(:transition_from_crypto_providers, (!value.nil? && [value].flatten.compact) || value, [])
|
84
|
+
end
|
85
|
+
alias_method :transition_from_crypto_providers=, :transition_from_crypto_providers
|
86
|
+
end
|
87
|
+
|
88
|
+
# Callbacks / hooks to allow other modules to modify the behavior of this module.
|
89
|
+
module Callbacks
|
90
|
+
METHODS = [
|
91
|
+
"before_password_set", "after_password_set",
|
92
|
+
"before_password_verification", "after_password_verification"
|
93
|
+
]
|
94
|
+
|
95
|
+
def self.included(klass)
|
96
|
+
klass.define_callbacks *METHODS
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
METHODS.each do |method|
|
101
|
+
class_eval <<-"end_eval", __FILE__, __LINE__
|
102
|
+
def #{method}
|
103
|
+
run_callbacks(:#{method}) { |result, object| result == false }
|
104
|
+
end
|
105
|
+
end_eval
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# The methods related to the password field.
|
110
|
+
module Methods
|
111
|
+
def self.included(klass)
|
112
|
+
klass.class_eval do
|
113
|
+
if validate_password_field
|
114
|
+
validates_confirmation_of :password, validates_confirmation_of_password_field_options
|
115
|
+
validates_length_of :password_confirmation, validates_length_of_password_confirmation_field_options
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# The password
|
121
|
+
def password
|
122
|
+
@password
|
123
|
+
end
|
124
|
+
|
125
|
+
# This is a virtual method. Once a password is passed to it, it will create new password salt as well as encrypt
|
126
|
+
# the password.
|
127
|
+
def password=(pass)
|
128
|
+
return if pass.blank?
|
129
|
+
before_password_set
|
130
|
+
@password = pass
|
131
|
+
send("#{password_salt_field}=", Authlogic::Random.friendly_token) if password_salt_field
|
132
|
+
send("#{crypted_password_field}=", crypto_provider.encrypt(*encrypt_arguments(@password, act_like_restful_authentication? ? :restful_authentication : nil)))
|
133
|
+
after_password_set
|
134
|
+
end
|
135
|
+
|
136
|
+
# Accepts a raw password to determine if it is the correct password or not.
|
137
|
+
def valid_password?(attempted_password)
|
138
|
+
return false if attempted_password.blank? || send(crypted_password_field).blank?
|
139
|
+
|
140
|
+
before_password_verification
|
141
|
+
|
142
|
+
crypto_providers = [crypto_provider] + transition_from_crypto_providers
|
143
|
+
crypto_providers.each_with_index do |encryptor, index|
|
144
|
+
# The arguments_type of for the transitioning from restful_authentication
|
145
|
+
arguments_type = (act_like_restful_authentication? && index == 0) ||
|
146
|
+
(transition_from_restful_authentication? && index > 0 && encryptor == Authlogic::CryptoProviders::Sha1) ?
|
147
|
+
:restful_authentication : nil
|
148
|
+
|
149
|
+
if encryptor.matches?(send(crypted_password_field), *encrypt_arguments(attempted_password, arguments_type))
|
150
|
+
# If we are transitioning from an older encryption algorithm and the password is still using the old algorithm
|
151
|
+
# then let's reset the password using the new algorithm. If the algorithm has a cost (BCrypt) and the cost has changed, update the password with
|
152
|
+
# the new cost.
|
153
|
+
if index > 0 || (encryptor.respond_to?(:cost_matches?) && !encryptor.cost_matches?(send(crypted_password_field)))
|
154
|
+
self.password = attempted_password
|
155
|
+
save(false)
|
156
|
+
end
|
157
|
+
|
158
|
+
after_password_verification
|
159
|
+
|
160
|
+
return true
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
false
|
165
|
+
end
|
166
|
+
|
167
|
+
# Resets the password to a random friendly token.
|
168
|
+
def reset_password
|
169
|
+
friendly_token = Authlogic::Random.friendly_token
|
170
|
+
self.password = friendly_token
|
171
|
+
self.password_confirmation = friendly_token
|
172
|
+
end
|
173
|
+
alias_method :randomize_password, :reset_password
|
174
|
+
|
175
|
+
# Resets the password to a random friendly token and then saves the record.
|
176
|
+
def reset_password!
|
177
|
+
reset_password
|
178
|
+
save_without_session_maintenance(false)
|
179
|
+
end
|
180
|
+
alias_method :randomize_password!, :reset_password!
|
181
|
+
|
182
|
+
private
|
183
|
+
def encrypt_arguments(raw_password, arguments_type = nil)
|
184
|
+
salt = password_salt_field ? send(password_salt_field) : nil
|
185
|
+
case arguments_type
|
186
|
+
when :restful_authentication
|
187
|
+
[REST_AUTH_SITE_KEY, salt, raw_password, REST_AUTH_SITE_KEY].compact
|
188
|
+
else
|
189
|
+
[raw_password, salt].compact
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def require_password_confirmation?
|
194
|
+
new_record? || (password_salt_field && send("#{password_salt_field}_changed?")) || send(crypted_password_field).blank?
|
195
|
+
end
|
196
|
+
|
197
|
+
def crypted_password_field
|
198
|
+
self.class.crypted_password_field
|
199
|
+
end
|
200
|
+
|
201
|
+
def password_salt_field
|
202
|
+
self.class.password_salt_field
|
203
|
+
end
|
204
|
+
|
205
|
+
def crypto_provider
|
206
|
+
self.class.crypto_provider
|
207
|
+
end
|
208
|
+
|
209
|
+
def transition_from_crypto_providers
|
210
|
+
self.class.transition_from_crypto_providers
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|