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.

Files changed (131) hide show
  1. data/CHANGELOG.rdoc +19 -0
  2. data/Manifest.txt +111 -0
  3. data/README.rdoc +116 -389
  4. data/Rakefile +14 -7
  5. data/lib/authlogic.rb +33 -35
  6. data/lib/authlogic/acts_as_authentic/base.rb +91 -0
  7. data/lib/authlogic/acts_as_authentic/email.rb +77 -0
  8. data/lib/authlogic/acts_as_authentic/logged_in_status.rb +54 -0
  9. data/lib/authlogic/acts_as_authentic/login.rb +65 -0
  10. data/lib/authlogic/acts_as_authentic/magic_columns.rb +24 -0
  11. data/lib/authlogic/acts_as_authentic/password.rb +215 -0
  12. data/lib/authlogic/acts_as_authentic/perishable_token.rb +100 -0
  13. data/lib/authlogic/acts_as_authentic/persistence_token.rb +66 -0
  14. data/lib/authlogic/acts_as_authentic/restful_authentication.rb +60 -0
  15. data/lib/authlogic/acts_as_authentic/session_maintenance.rb +127 -0
  16. data/lib/authlogic/acts_as_authentic/single_access_token.rb +58 -0
  17. data/lib/authlogic/acts_as_authentic/validations_scope.rb +32 -0
  18. data/lib/authlogic/{session/authenticates_many_association.rb → authenticates_many/association.rb} +10 -6
  19. data/lib/authlogic/authenticates_many/base.rb +55 -0
  20. data/lib/authlogic/controller_adapters/abstract_adapter.rb +2 -3
  21. data/lib/authlogic/controller_adapters/merb_adapter.rb +0 -4
  22. data/lib/authlogic/controller_adapters/rails_adapter.rb +0 -4
  23. data/lib/authlogic/crypto_providers/aes256.rb +0 -2
  24. data/lib/authlogic/crypto_providers/bcrypt.rb +0 -2
  25. data/lib/authlogic/crypto_providers/md5.rb +34 -0
  26. data/lib/authlogic/crypto_providers/sha1.rb +0 -2
  27. data/lib/authlogic/crypto_providers/sha512.rb +1 -3
  28. data/lib/authlogic/i18n.rb +1 -4
  29. data/lib/authlogic/random.rb +33 -0
  30. data/lib/authlogic/session/activation.rb +56 -0
  31. data/lib/authlogic/session/active_record_trickery.rb +15 -7
  32. data/lib/authlogic/session/base.rb +31 -456
  33. data/lib/authlogic/session/brute_force_protection.rb +50 -27
  34. data/lib/authlogic/session/callbacks.rb +24 -15
  35. data/lib/authlogic/session/cookies.rb +108 -22
  36. data/lib/authlogic/session/existence.rb +89 -0
  37. data/lib/authlogic/session/foundation.rb +63 -0
  38. data/lib/authlogic/session/http_auth.rb +23 -0
  39. data/lib/authlogic/session/id.rb +41 -0
  40. data/lib/authlogic/session/klass.rb +75 -0
  41. data/lib/authlogic/session/magic_columns.rb +75 -0
  42. data/lib/authlogic/session/magic_states.rb +58 -0
  43. data/lib/authlogic/session/params.rb +82 -19
  44. data/lib/authlogic/session/password.rb +156 -0
  45. data/lib/authlogic/session/{perishability.rb → perishable_token.rb} +4 -4
  46. data/lib/authlogic/session/persistence.rb +70 -0
  47. data/lib/authlogic/session/priority_record.rb +34 -0
  48. data/lib/authlogic/session/scopes.rb +57 -53
  49. data/lib/authlogic/session/session.rb +46 -31
  50. data/lib/authlogic/session/timeout.rb +65 -31
  51. data/lib/authlogic/session/unauthorized_record.rb +50 -0
  52. data/lib/authlogic/session/validation.rb +76 -0
  53. data/lib/authlogic/testing/test_unit_helpers.rb +3 -3
  54. data/lib/authlogic/version.rb +3 -3
  55. data/test/acts_as_authentic_test/base_test.rb +12 -0
  56. data/test/acts_as_authentic_test/email_test.rb +79 -0
  57. data/test/acts_as_authentic_test/logged_in_status_test.rb +36 -0
  58. data/test/acts_as_authentic_test/login_test.rb +79 -0
  59. data/test/acts_as_authentic_test/magic_columns_test.rb +27 -0
  60. data/test/acts_as_authentic_test/password_test.rb +212 -0
  61. data/test/acts_as_authentic_test/perishable_token_test.rb +56 -0
  62. data/test/acts_as_authentic_test/persistence_token_test.rb +55 -0
  63. data/test/acts_as_authentic_test/session_maintenance_test.rb +68 -0
  64. data/test/acts_as_authentic_test/single_access_test.rb +39 -0
  65. data/test/authenticates_many_test.rb +16 -0
  66. data/test/{crypto_provider_tests → crypto_provider_test}/aes256_test.rb +1 -1
  67. data/test/{crypto_provider_tests → crypto_provider_test}/bcrypt_test.rb +1 -1
  68. data/test/{crypto_provider_tests → crypto_provider_test}/sha1_test.rb +1 -1
  69. data/test/{crypto_provider_tests → crypto_provider_test}/sha512_test.rb +1 -1
  70. data/test/fixtures/employees.yml +4 -4
  71. data/test/fixtures/users.yml +6 -6
  72. data/test/libs/company.rb +6 -0
  73. data/test/libs/employee.rb +7 -0
  74. data/test/libs/employee_session.rb +2 -0
  75. data/test/libs/project.rb +3 -0
  76. data/test/libs/user_session.rb +2 -0
  77. data/test/random_test.rb +49 -0
  78. data/test/session_test/activation_test.rb +43 -0
  79. data/test/session_test/active_record_trickery_test.rb +26 -0
  80. data/test/session_test/brute_force_protection_test.rb +76 -0
  81. data/test/session_test/callbacks_test.rb +6 -0
  82. data/test/session_test/cookies_test.rb +107 -0
  83. data/test/session_test/credentials_test.rb +0 -0
  84. data/test/session_test/existence_test.rb +64 -0
  85. data/test/session_test/http_auth_test.rb +16 -0
  86. data/test/session_test/id_test.rb +17 -0
  87. data/test/session_test/klass_test.rb +35 -0
  88. data/test/session_test/magic_columns_test.rb +59 -0
  89. data/test/session_test/magic_states_test.rb +60 -0
  90. data/test/session_test/params_test.rb +53 -0
  91. data/test/session_test/password_test.rb +84 -0
  92. data/test/{session_tests → session_test}/perishability_test.rb +1 -1
  93. data/test/session_test/persistence_test.rb +21 -0
  94. data/test/{session_tests → session_test}/scopes_test.rb +2 -3
  95. data/test/session_test/session_test.rb +59 -0
  96. data/test/session_test/timeout_test.rb +43 -0
  97. data/test/session_test/unauthorized_record_test.rb +13 -0
  98. data/test/session_test/validation_test.rb +23 -0
  99. data/test/test_helper.rb +14 -29
  100. metadata +120 -112
  101. data/Manifest +0 -76
  102. data/authlogic.gemspec +0 -38
  103. data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/base.rb +0 -22
  104. data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/config.rb +0 -238
  105. data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/credentials.rb +0 -155
  106. data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/logged_in.rb +0 -51
  107. data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/perishability.rb +0 -71
  108. data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/persistence.rb +0 -94
  109. data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/session_maintenance.rb +0 -87
  110. data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/single_access.rb +0 -61
  111. data/lib/authlogic/orm_adapters/active_record_adapter/authenticates_many.rb +0 -58
  112. data/lib/authlogic/session/config.rb +0 -421
  113. data/lib/authlogic/session/errors.rb +0 -18
  114. data/lib/authlogic/session/record_info.rb +0 -24
  115. data/test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/config_test.rb +0 -154
  116. data/test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/credentials_test.rb +0 -157
  117. data/test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/logged_in_test.rb +0 -24
  118. data/test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/perishability_test.rb +0 -41
  119. data/test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/persistence_test.rb +0 -54
  120. data/test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/session_maintenance_test.rb +0 -62
  121. data/test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/single_access_test.rb +0 -41
  122. data/test/orm_adapters_tests/active_record_adapter_tests/authenticates_many_test.rb +0 -32
  123. data/test/session_tests/active_record_trickery_test.rb +0 -14
  124. data/test/session_tests/authenticates_many_association_test.rb +0 -28
  125. data/test/session_tests/base_test.rb +0 -307
  126. data/test/session_tests/brute_force_protection_test.rb +0 -53
  127. data/test/session_tests/config_test.rb +0 -184
  128. data/test/session_tests/cookies_test.rb +0 -32
  129. data/test/session_tests/params_test.rb +0 -32
  130. data/test/session_tests/session_test.rb +0 -45
  131. data/test/session_tests/timeout_test.rb +0 -71
data/Rakefile CHANGED
@@ -1,13 +1,20 @@
1
- require 'rubygems'
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
- require 'echoe'
4
-
5
- Echoe.new 'authlogic' do |p|
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.dependencies = %w(activesupport echoe)
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
- if defined?(ActiveRecord)
16
- require File.dirname(__FILE__) + "/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/base"
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/session/authenticates_many_association"
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/errors"
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/perishability"
36
- require File.dirname(__FILE__) + "/authlogic/session/record_info"
37
- require File.dirname(__FILE__) + "/authlogic/session/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/base"
41
-
42
- module Authlogic
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