sorcery 0.7.0 → 0.8.0

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.
Files changed (204) hide show
  1. data/.travis.yml +3 -0
  2. data/Gemfile +9 -6
  3. data/Gemfile.lock +106 -75
  4. data/README.rdoc +42 -55
  5. data/Rakefile +32 -7
  6. data/VERSION +1 -1
  7. data/lib/generators/sorcery/USAGE +22 -0
  8. data/lib/generators/sorcery/install_generator.rb +77 -0
  9. data/lib/generators/sorcery/templates/initializer.rb +417 -0
  10. data/lib/generators/sorcery/templates/migration/activity_logging.rb +17 -0
  11. data/lib/generators/sorcery/templates/migration/brute_force_protection.rb +13 -0
  12. data/lib/generators/{sorcery_migration/templates → sorcery/templates/migration}/core.rb +2 -2
  13. data/lib/generators/{sorcery_migration/templates → sorcery/templates/migration}/external.rb +1 -1
  14. data/lib/generators/sorcery/templates/migration/remember_me.rb +15 -0
  15. data/lib/generators/sorcery/templates/migration/reset_password.rb +17 -0
  16. data/lib/generators/sorcery/templates/migration/user_activation.rb +17 -0
  17. data/lib/sorcery/controller/submodules/activity_logging.rb +8 -11
  18. data/lib/sorcery/controller/submodules/brute_force_protection.rb +2 -3
  19. data/lib/sorcery/controller/submodules/external/protocols/oauth2.rb +25 -10
  20. data/lib/sorcery/controller/submodules/external/providers/facebook.rb +20 -5
  21. data/lib/sorcery/controller/submodules/external/providers/github.rb +15 -4
  22. data/lib/sorcery/controller/submodules/external/providers/google.rb +90 -0
  23. data/lib/sorcery/controller/submodules/external/providers/linkedin.rb +101 -0
  24. data/lib/sorcery/controller/submodules/external/providers/liveid.rb +91 -0
  25. data/lib/sorcery/controller/submodules/external/providers/twitter.rb +3 -2
  26. data/lib/sorcery/controller/submodules/external/providers/vkontakte.rb +94 -0
  27. data/lib/sorcery/controller/submodules/external.rb +89 -15
  28. data/lib/sorcery/controller/submodules/http_basic_auth.rb +1 -1
  29. data/lib/sorcery/controller/submodules/remember_me.rb +26 -15
  30. data/lib/sorcery/controller/submodules/session_timeout.rb +3 -3
  31. data/lib/sorcery/controller.rb +55 -46
  32. data/lib/sorcery/crypto_providers/bcrypt.rb +1 -0
  33. data/lib/sorcery/model/adapters/active_record.rb +21 -1
  34. data/lib/sorcery/model/adapters/mongo_mapper.rb +56 -0
  35. data/lib/sorcery/model/adapters/mongoid.rb +23 -4
  36. data/lib/sorcery/model/submodules/activity_logging.rb +4 -4
  37. data/lib/sorcery/model/submodules/brute_force_protection.rb +54 -15
  38. data/lib/sorcery/model/submodules/remember_me.rb +12 -7
  39. data/lib/sorcery/model/submodules/reset_password.rb +27 -11
  40. data/lib/sorcery/model/submodules/user_activation.rb +27 -8
  41. data/lib/sorcery/model/temporary_token.rb +4 -2
  42. data/lib/sorcery/model.rb +78 -47
  43. data/lib/sorcery/railties/tasks.rake +2 -0
  44. data/lib/sorcery.rb +10 -8
  45. data/sorcery.gemspec +107 -228
  46. data/spec/Gemfile +1 -1
  47. data/spec/Gemfile.lock +27 -23
  48. data/spec/README.md +12 -7
  49. data/spec/rails3/Gemfile +3 -3
  50. data/spec/rails3/Gemfile.lock +62 -55
  51. data/spec/rails3/app/controllers/application_controller.rb +85 -2
  52. data/spec/rails3/app/mailers/sorcery_mailer.rb +7 -0
  53. data/spec/rails3/app/views/sorcery_mailer/send_unlock_token_email.text.erb +1 -0
  54. data/spec/rails3/config/environments/in_memory.rb +35 -0
  55. data/spec/rails3/db/migrate/brute_force_protection/20101224223626_add_brute_force_protection_to_users.rb +2 -0
  56. data/spec/rails3/spec/controller_activity_logging_spec.rb +16 -6
  57. data/spec/rails3/spec/controller_brute_force_protection_spec.rb +25 -3
  58. data/spec/rails3/spec/controller_oauth2_spec.rb +260 -20
  59. data/spec/rails3/spec/controller_oauth_spec.rb +111 -6
  60. data/spec/rails3/spec/controller_session_timeout_spec.rb +4 -4
  61. data/spec/rails3/spec/controller_spec.rb +37 -2
  62. data/spec/rails3/spec/integration_spec.rb +15 -15
  63. data/spec/rails3/spec/spec_helper.rb +0 -2
  64. data/spec/rails3_mongo_mapper/.gitignore +4 -0
  65. data/spec/rails3_mongo_mapper/.rspec +1 -0
  66. data/spec/{sinatra_modular → rails3_mongo_mapper}/Gemfile +6 -5
  67. data/spec/rails3_mongo_mapper/Gemfile.lock +156 -0
  68. data/spec/{sinatra → rails3_mongo_mapper}/Rakefile +3 -3
  69. data/spec/rails3_mongo_mapper/app/controllers/application_controller.rb +122 -0
  70. data/spec/rails3_mongo_mapper/app/helpers/application_helper.rb +2 -0
  71. data/spec/rails3_mongo_mapper/app/models/authentication.rb +6 -0
  72. data/spec/rails3_mongo_mapper/app/models/user.rb +5 -0
  73. data/spec/rails3_mongo_mapper/app/views/layouts/application.html.erb +14 -0
  74. data/spec/rails3_mongo_mapper/app/views/sorcery_mailer/activation_email.html.erb +17 -0
  75. data/spec/rails3_mongo_mapper/app/views/sorcery_mailer/activation_email.text.erb +9 -0
  76. data/spec/rails3_mongo_mapper/app/views/sorcery_mailer/activation_success_email.html.erb +17 -0
  77. data/spec/rails3_mongo_mapper/app/views/sorcery_mailer/activation_success_email.text.erb +9 -0
  78. data/spec/rails3_mongo_mapper/app/views/sorcery_mailer/reset_password_email.html.erb +16 -0
  79. data/spec/rails3_mongo_mapper/app/views/sorcery_mailer/reset_password_email.text.erb +8 -0
  80. data/spec/rails3_mongo_mapper/config/application.rb +51 -0
  81. data/spec/rails3_mongo_mapper/config/boot.rb +13 -0
  82. data/spec/rails3_mongo_mapper/config/environment.rb +5 -0
  83. data/spec/rails3_mongo_mapper/config/environments/development.rb +30 -0
  84. data/spec/rails3_mongo_mapper/config/environments/in_memory.rb +0 -0
  85. data/spec/rails3_mongo_mapper/config/environments/production.rb +49 -0
  86. data/spec/rails3_mongo_mapper/config/environments/test.rb +35 -0
  87. data/spec/rails3_mongo_mapper/config/initializers/backtrace_silencers.rb +7 -0
  88. data/spec/rails3_mongo_mapper/config/initializers/inflections.rb +10 -0
  89. data/spec/rails3_mongo_mapper/config/initializers/mime_types.rb +5 -0
  90. data/spec/rails3_mongo_mapper/config/initializers/mongo.rb +2 -0
  91. data/spec/rails3_mongo_mapper/config/initializers/secret_token.rb +7 -0
  92. data/spec/rails3_mongo_mapper/config/initializers/session_store.rb +8 -0
  93. data/spec/rails3_mongo_mapper/config/locales/en.yml +5 -0
  94. data/spec/rails3_mongo_mapper/config/routes.rb +59 -0
  95. data/spec/rails3_mongo_mapper/config.ru +4 -0
  96. data/spec/rails3_mongo_mapper/db/schema.rb +23 -0
  97. data/spec/rails3_mongo_mapper/db/seeds.rb +7 -0
  98. data/spec/rails3_mongo_mapper/lib/tasks/.gitkeep +0 -0
  99. data/spec/rails3_mongo_mapper/public/404.html +26 -0
  100. data/spec/rails3_mongo_mapper/public/422.html +26 -0
  101. data/spec/rails3_mongo_mapper/public/500.html +26 -0
  102. data/spec/rails3_mongo_mapper/public/favicon.ico +0 -0
  103. data/spec/rails3_mongo_mapper/public/images/rails.png +0 -0
  104. data/spec/rails3_mongo_mapper/public/javascripts/application.js +2 -0
  105. data/spec/rails3_mongo_mapper/public/javascripts/controls.js +965 -0
  106. data/spec/rails3_mongo_mapper/public/javascripts/dragdrop.js +974 -0
  107. data/spec/rails3_mongo_mapper/public/javascripts/effects.js +1123 -0
  108. data/spec/rails3_mongo_mapper/public/javascripts/prototype.js +6001 -0
  109. data/spec/rails3_mongo_mapper/public/javascripts/rails.js +175 -0
  110. data/spec/rails3_mongo_mapper/public/robots.txt +5 -0
  111. data/spec/rails3_mongo_mapper/public/stylesheets/.gitkeep +0 -0
  112. data/spec/rails3_mongo_mapper/script/rails +6 -0
  113. data/spec/rails3_mongo_mapper/spec/controller_spec.rb +170 -0
  114. data/spec/rails3_mongo_mapper/spec/spec_helper.orig.rb +27 -0
  115. data/spec/rails3_mongo_mapper/spec/spec_helper.rb +55 -0
  116. data/spec/rails3_mongo_mapper/spec/user_activation_spec.rb +9 -0
  117. data/spec/rails3_mongo_mapper/spec/user_activity_logging_spec.rb +8 -0
  118. data/spec/rails3_mongo_mapper/spec/user_brute_force_protection_spec.rb +8 -0
  119. data/spec/rails3_mongo_mapper/spec/user_oauth_spec.rb +8 -0
  120. data/spec/rails3_mongo_mapper/spec/user_remember_me_spec.rb +8 -0
  121. data/spec/rails3_mongo_mapper/spec/user_reset_password_spec.rb +8 -0
  122. data/spec/rails3_mongo_mapper/spec/user_spec.rb +37 -0
  123. data/spec/rails3_mongo_mapper/vendor/plugins/.gitkeep +0 -0
  124. data/spec/rails3_mongoid/Gemfile +2 -1
  125. data/spec/rails3_mongoid/Gemfile.lock +47 -42
  126. data/spec/rails3_mongoid/app/controllers/application_controller.rb +19 -0
  127. data/spec/rails3_mongoid/config/mongoid.yml +1 -1
  128. data/spec/rails3_mongoid/script/rails +0 -0
  129. data/spec/rails3_mongoid/spec/controller_activity_logging_spec.rb +105 -0
  130. data/spec/rails3_mongoid/spec/controller_spec.rb +52 -1
  131. data/spec/rails3_mongoid/spec/user_spec.rb +1 -0
  132. data/spec/shared_examples/controller_oauth2_shared_examples.rb +20 -1
  133. data/spec/shared_examples/controller_oauth_shared_examples.rb +18 -0
  134. data/spec/shared_examples/user_activation_shared_examples.rb +72 -42
  135. data/spec/shared_examples/user_remember_me_shared_examples.rb +1 -1
  136. data/spec/shared_examples/user_reset_password_shared_examples.rb +81 -28
  137. data/spec/shared_examples/user_shared_examples.rb +29 -1
  138. data/spec/sorcery_crypto_providers_spec.rb +14 -1
  139. metadata +111 -229
  140. data/lib/generators/sorcery_migration/sorcery_migration_generator.rb +0 -24
  141. data/lib/generators/sorcery_migration/templates/activity_logging.rb +0 -17
  142. data/lib/generators/sorcery_migration/templates/brute_force_protection.rb +0 -11
  143. data/lib/generators/sorcery_migration/templates/remember_me.rb +0 -15
  144. data/lib/generators/sorcery_migration/templates/reset_password.rb +0 -17
  145. data/lib/generators/sorcery_migration/templates/user_activation.rb +0 -17
  146. data/lib/sorcery/controller/adapters/sinatra.rb +0 -115
  147. data/lib/sorcery/initializers/initializer.rb +0 -199
  148. data/lib/sorcery/sinatra.rb +0 -4
  149. data/lib/sorcery/test_helpers/internal/sinatra.rb +0 -74
  150. data/lib/sorcery/test_helpers/internal/sinatra_modular.rb +0 -74
  151. data/lib/sorcery/test_helpers/sinatra.rb +0 -88
  152. data/spec/rails3/Rakefile.unused +0 -7
  153. data/spec/sinatra/Gemfile +0 -15
  154. data/spec/sinatra/Gemfile.lock +0 -115
  155. data/spec/sinatra/authentication.rb +0 -3
  156. data/spec/sinatra/db/migrate/activation/20101224223622_add_activation_to_users.rb +0 -17
  157. data/spec/sinatra/db/migrate/activity_logging/20101224223624_add_activity_logging_to_users.rb +0 -17
  158. data/spec/sinatra/db/migrate/brute_force_protection/20101224223626_add_brute_force_protection_to_users.rb +0 -11
  159. data/spec/sinatra/db/migrate/core/20101224223620_create_users.rb +0 -16
  160. data/spec/sinatra/db/migrate/external/20101224223628_create_authentications.rb +0 -14
  161. data/spec/sinatra/db/migrate/remember_me/20101224223623_add_remember_me_token_to_users.rb +0 -15
  162. data/spec/sinatra/db/migrate/reset_password/20101224223622_add_reset_password_to_users.rb +0 -13
  163. data/spec/sinatra/filters.rb +0 -27
  164. data/spec/sinatra/modular.rb +0 -157
  165. data/spec/sinatra/myapp.rb +0 -133
  166. data/spec/sinatra/spec/controller_activity_logging_spec.rb +0 -85
  167. data/spec/sinatra/spec/controller_brute_force_protection_spec.rb +0 -70
  168. data/spec/sinatra/spec/controller_http_basic_auth_spec.rb +0 -53
  169. data/spec/sinatra/spec/controller_oauth2_spec.rb +0 -96
  170. data/spec/sinatra/spec/controller_oauth_spec.rb +0 -100
  171. data/spec/sinatra/spec/controller_remember_me_spec.rb +0 -64
  172. data/spec/sinatra/spec/controller_session_timeout_spec.rb +0 -57
  173. data/spec/sinatra/spec/controller_spec.rb +0 -127
  174. data/spec/sinatra/spec/spec_helper.rb +0 -45
  175. data/spec/sinatra/user.rb +0 -6
  176. data/spec/sinatra/views/test_login.erb +0 -4
  177. data/spec/sinatra_modular/Gemfile.lock +0 -115
  178. data/spec/sinatra_modular/Rakefile +0 -11
  179. data/spec/sinatra_modular/authentication.rb +0 -3
  180. data/spec/sinatra_modular/db/migrate/activation/20101224223622_add_activation_to_users.rb +0 -17
  181. data/spec/sinatra_modular/db/migrate/activity_logging/20101224223624_add_activity_logging_to_users.rb +0 -17
  182. data/spec/sinatra_modular/db/migrate/brute_force_protection/20101224223626_add_brute_force_protection_to_users.rb +0 -11
  183. data/spec/sinatra_modular/db/migrate/core/20101224223620_create_users.rb +0 -16
  184. data/spec/sinatra_modular/db/migrate/external/20101224223628_create_authentications.rb +0 -14
  185. data/spec/sinatra_modular/db/migrate/remember_me/20101224223623_add_remember_me_token_to_users.rb +0 -15
  186. data/spec/sinatra_modular/db/migrate/reset_password/20101224223622_add_reset_password_to_users.rb +0 -13
  187. data/spec/sinatra_modular/filters.rb +0 -27
  188. data/spec/sinatra_modular/modular.rb +0 -157
  189. data/spec/sinatra_modular/myapp.rb +0 -133
  190. data/spec/sinatra_modular/sorcery_mailer.rb +0 -25
  191. data/spec/sinatra_modular/spec_modular/controller_activity_logging_spec.rb +0 -85
  192. data/spec/sinatra_modular/spec_modular/controller_brute_force_protection_spec.rb +0 -70
  193. data/spec/sinatra_modular/spec_modular/controller_http_basic_auth_spec.rb +0 -53
  194. data/spec/sinatra_modular/spec_modular/controller_oauth2_spec.rb +0 -96
  195. data/spec/sinatra_modular/spec_modular/controller_oauth_spec.rb +0 -100
  196. data/spec/sinatra_modular/spec_modular/controller_remember_me_spec.rb +0 -64
  197. data/spec/sinatra_modular/spec_modular/controller_session_timeout_spec.rb +0 -57
  198. data/spec/sinatra_modular/spec_modular/controller_spec.rb +0 -116
  199. data/spec/sinatra_modular/spec_modular/spec.opts +0 -2
  200. data/spec/sinatra_modular/spec_modular/spec_helper.rb +0 -51
  201. data/spec/sinatra_modular/user.rb +0 -6
  202. data/spec/sinatra_modular/views/test_login.erb +0 -4
  203. /data/spec/{sinatra → rails3_mongo_mapper/app/mailers}/sorcery_mailer.rb +0 -0
  204. /data/spec/{sinatra → rails3_mongo_mapper}/spec/spec.opts +0 -0
@@ -1,31 +1,40 @@
1
1
  module Sorcery
2
2
  module Controller
3
3
  module Submodules
4
- # The Remember Me submodule takes care of setting the user's cookie so that he will
4
+ # The Remember Me submodule takes care of setting the user's cookie so that he will
5
5
  # be automatically logged in to the site on every visit,
6
6
  # until the cookie expires.
7
7
  # See Sorcery::Model::Submodules::RememberMe for configuration options.
8
8
  module RememberMe
9
9
  def self.included(base)
10
10
  base.send(:include, InstanceMethods)
11
+ Config.module_eval do
12
+ class << self
13
+ attr_accessor :remember_me_httponly
14
+ def merge_remember_me_defaults!
15
+ @defaults.merge!(:@remember_me_httponly => true)
16
+ end
17
+ end
18
+ merge_remember_me_defaults!
19
+ end
11
20
  Config.login_sources << :login_from_cookie
12
21
  Config.after_login << :remember_me_if_asked_to
13
22
  Config.after_logout << :forget_me!
14
23
  end
15
-
24
+
16
25
  module InstanceMethods
17
26
  # This method sets the cookie and calls the user to save the token and the expiration to db.
18
27
  def remember_me!
19
28
  current_user.remember_me!
20
- set_remember_me_cookie!(current_user)
29
+ set_remember_me_cookie!(current_user)
21
30
  end
22
31
 
23
32
  # Clears the cookie and clears the token from the db.
24
33
  def forget_me!
25
- current_user.forget_me!
26
- cookies[:remember_me_token] = nil
34
+ @current_user.forget_me!
35
+ cookies.delete(:remember_me_token, :domain => Config.cookie_domain)
27
36
  end
28
-
37
+
29
38
  # Override.
30
39
  # logins a user instance, and optionally remembers him.
31
40
  def auto_login(user, should_remember = false)
@@ -33,33 +42,35 @@ module Sorcery
33
42
  @current_user = user
34
43
  remember_me! if should_remember
35
44
  end
36
-
45
+
37
46
  protected
38
-
47
+
39
48
  # calls remember_me! if a third credential was passed to the login method.
40
49
  # Runs as a hook after login.
41
50
  def remember_me_if_asked_to(user, credentials)
42
51
  remember_me! if ( credentials.size == 3 && credentials[2] && credentials[2] != "0" )
43
52
  end
44
-
45
- # Checks the cookie for a remember me token, tried to find a user with that token
53
+
54
+ # Checks the cookie for a remember me token, tried to find a user with that token
46
55
  # and logs the user in if found.
47
56
  # Runs as a login source. See 'current_user' method for how it is used.
48
57
  def login_from_cookie
49
58
  user = cookies.signed[:remember_me_token] && user_class.find_by_remember_me_token(cookies.signed[:remember_me_token])
50
59
  if user && user.remember_me_token?
51
60
  set_remember_me_cookie!(user)
61
+ session[:user_id] = user.id
52
62
  @current_user = user
53
63
  else
54
64
  @current_user = false
55
65
  end
56
66
  end
57
-
67
+
58
68
  def set_remember_me_cookie!(user)
59
- cookies.signed[:remember_me_token] = {
60
- :value => user.send(user.sorcery_config.remember_me_token_attribute_name),
69
+ cookies.signed[:remember_me_token] = {
70
+ :value => user.send(user.sorcery_config.remember_me_token_attribute_name),
61
71
  :expires => user.send(user.sorcery_config.remember_me_token_expires_at_attribute_name),
62
- :httponly => true
72
+ :httponly => Config.remember_me_httponly,
73
+ :domain => Config.cookie_domain
63
74
  }
64
75
  end
65
76
  end
@@ -67,4 +78,4 @@ module Sorcery
67
78
  end
68
79
  end
69
80
  end
70
- end
81
+ end
@@ -30,18 +30,18 @@ module Sorcery
30
30
  # Registers last login to be used as the timeout starting point.
31
31
  # Runs as a hook after a successful login.
32
32
  def register_login_time(user, credentials)
33
- session[:login_time] = session[:last_action_time] = Time.now.utc
33
+ session[:login_time] = session[:last_action_time] = Time.now.in_time_zone
34
34
  end
35
35
 
36
36
  # Checks if session timeout was reached and expires the current session if so.
37
37
  # To be used as a before_filter, before require_login
38
38
  def validate_session
39
39
  session_to_use = Config.session_timeout_from_last_action ? session[:last_action_time] : session[:login_time]
40
- if session_to_use && (Time.now.utc - session_to_use > Config.session_timeout)
40
+ if session_to_use && (Time.now.in_time_zone - session_to_use > Config.session_timeout)
41
41
  reset_session
42
42
  @current_user = nil
43
43
  else
44
- session[:last_action_time] = Time.now.utc
44
+ session[:last_action_time] = Time.now.in_time_zone
45
45
  end
46
46
  end
47
47
 
@@ -5,7 +5,7 @@ module Sorcery
5
5
  include InstanceMethods
6
6
  Config.submodules.each do |mod|
7
7
  begin
8
- include Submodules.const_get(mod.to_s.split("_").map {|p| p.capitalize}.join(""))
8
+ include Submodules.const_get(mod.to_s.split("_").map {|p| p.capitalize}.join(""))
9
9
  rescue NameError
10
10
  # don't stop on a missing submodule.
11
11
  end
@@ -14,26 +14,29 @@ module Sorcery
14
14
  Config.update!
15
15
  Config.configure!
16
16
  end
17
-
17
+
18
18
  module InstanceMethods
19
19
  # To be used as before_filter.
20
20
  # Will trigger auto-login attempts via the call to logged_in?
21
21
  # If all attempts to auto-login fail, the failure callback will be called.
22
22
  def require_login
23
23
  if !logged_in?
24
- session[:return_to_url] = request.url if Config.save_return_to_url
25
- self.send(Config.not_authenticated_action)
24
+ session[:return_to_url] = request.url if Config.save_return_to_url && request.get?
25
+ self.send(Config.not_authenticated_action)
26
26
  end
27
27
  end
28
-
28
+
29
29
  # Takes credentials and returns a user on successful authentication.
30
30
  # Runs hooks after login or failed login.
31
- def login(*credentials)
31
+ def login(*credentials)
32
+ @current_user = nil
32
33
  user = user_class.authenticate(*credentials)
33
34
  if user
34
- return_to_url = session[:return_to_url]
35
+ old_session = session.dup
35
36
  reset_session # protect from session fixation attacks
36
- session[:return_to_url] = return_to_url
37
+ old_session.to_hash.each_pair do |k,v|
38
+ session[k.to_sym] = v
39
+ end
37
40
  auto_login(user)
38
41
  after_login!(user, credentials)
39
42
  current_user
@@ -42,43 +45,45 @@ module Sorcery
42
45
  nil
43
46
  end
44
47
  end
45
-
48
+
46
49
  # Resets the session and runs hooks before and after.
47
50
  def logout
48
51
  if logged_in?
49
52
  before_logout!(current_user)
50
53
  reset_session
51
54
  after_logout!
55
+ @current_user = nil
52
56
  end
53
57
  end
54
-
58
+
55
59
  def logged_in?
56
60
  !!current_user
57
61
  end
58
-
62
+
59
63
  # attempts to auto-login from the sources defined (session, basic_auth, cookie, etc.)
60
64
  # returns the logged in user if found, false if not (using old restful-authentication trick, nil != false).
61
65
  def current_user
62
66
  @current_user ||= login_from_session || login_from_other_sources unless @current_user == false
63
67
  end
64
-
68
+
65
69
  def current_user=(user)
66
70
  @current_user = user
67
71
  end
68
-
69
- # used when a user tries to access a page while logged out, is asked to login,
72
+
73
+ # used when a user tries to access a page while logged out, is asked to login,
70
74
  # and we want to return him back to the page he originally wanted.
71
75
  def redirect_back_or_to(url, flash_hash = {})
72
76
  redirect_to(session[:return_to_url] || url, :flash => flash_hash)
77
+ session[:return_to_url] = nil
73
78
  end
74
-
79
+
75
80
  # The default action for denying non-authenticated users.
76
81
  # You can override this method in your controllers,
77
82
  # or provide a different method in the configuration.
78
83
  def not_authenticated
79
84
  redirect_to root_path
80
85
  end
81
-
86
+
82
87
  # login a user instance
83
88
  #
84
89
  # @param [<User-Model>] user the user instance.
@@ -87,16 +92,16 @@ module Sorcery
87
92
  session[:user_id] = user.id
88
93
  @current_user = user
89
94
  end
90
-
95
+
91
96
  # Overwrite Rails' handle unverified request
92
97
  def handle_unverified_request
93
98
  cookies[:remember_me_token] = nil
94
99
  @current_user = nil
95
100
  super # call the default behaviour which resets the session
96
101
  end
97
-
102
+
98
103
  protected
99
-
104
+
100
105
  # Tries all available sources (methods) until one doesn't return false.
101
106
  def login_from_other_sources
102
107
  result = nil
@@ -105,51 +110,55 @@ module Sorcery
105
110
  end
106
111
  result || false
107
112
  end
108
-
113
+
109
114
  def login_from_session
110
- @current_user = (user_class.find_by_id(session[:user_id]) if session[:user_id]) || false
111
- end
112
-
113
- def after_login!(user, credentials)
115
+ @current_user = (user_class.find(session[:user_id]) if session[:user_id]) || false
116
+ rescue => exception
117
+ return false if defined?(Mongoid) and exception.is_a?(Mongoid::Errors::DocumentNotFound)
118
+ return false if defined?(ActiveRecord) and exception.is_a?(ActiveRecord::RecordNotFound)
119
+ raise exception
120
+ end
121
+
122
+ def after_login!(user, credentials = [])
114
123
  Config.after_login.each {|c| self.send(c, user, credentials)}
115
124
  end
116
-
125
+
117
126
  def after_failed_login!(credentials)
118
127
  Config.after_failed_login.each {|c| self.send(c, credentials)}
119
128
  end
120
-
129
+
121
130
  def before_logout!(user)
122
131
  Config.before_logout.each {|c| self.send(c, user)}
123
132
  end
124
-
133
+
125
134
  def after_logout!
126
135
  Config.after_logout.each {|c| self.send(c)}
127
136
  end
128
-
137
+
129
138
  def user_class
130
139
  @user_class ||= Config.user_class.to_s.constantize
131
140
  end
132
-
141
+
133
142
  end
134
-
143
+
135
144
  module Config
136
145
  class << self
137
146
  attr_accessor :submodules,
138
- :user_class, # what class to use as the user class.
147
+ :user_class, # what class to use as the user class.
139
148
  :not_authenticated_action, # what controller action to call for non-authenticated users.
140
-
149
+
141
150
  :save_return_to_url, # when a non logged in user tries to enter a page that requires
142
- # login, save the URL he wanted to reach,
151
+ # login, save the URL he wanted to reach,
143
152
  # and send him there after login.
144
-
145
- :sinatra_cookie_secret, # used to sign cookies in Sinatra.
146
-
153
+
154
+ :cookie_domain, # set domain option for cookies
155
+
147
156
  :login_sources,
148
157
  :after_login,
149
158
  :after_failed_login,
150
159
  :before_logout,
151
- :after_logout
152
-
160
+ :after_logout
161
+
153
162
  def init!
154
163
  @defaults = {
155
164
  :@user_class => nil,
@@ -161,31 +170,31 @@ module Sorcery
161
170
  :@before_logout => [],
162
171
  :@after_logout => [],
163
172
  :@save_return_to_url => true,
164
- :@sinatra_cookie_secret => 'ch4ng3M3plz'
173
+ :@cookie_domain => nil
165
174
  }
166
175
  end
167
-
176
+
168
177
  # Resets all configuration options to their default values.
169
178
  def reset!
170
179
  @defaults.each do |k,v|
171
180
  instance_variable_set(k,v)
172
- end
181
+ end
173
182
  end
174
-
183
+
175
184
  def update!
176
185
  @defaults.each do |k,v|
177
186
  instance_variable_set(k,v) if !instance_variable_defined?(k)
178
187
  end
179
188
  end
180
-
189
+
181
190
  def user_config(&blk)
182
191
  block_given? ? @user_config = blk : @user_config
183
192
  end
184
-
193
+
185
194
  def configure(&blk)
186
195
  @configure_blk = blk
187
196
  end
188
-
197
+
189
198
  def configure!
190
199
  @configure_blk.call(self) if @configure_blk
191
200
  end
@@ -194,4 +203,4 @@ module Sorcery
194
203
  reset!
195
204
  end
196
205
  end
197
- end
206
+ end
@@ -48,6 +48,7 @@ module Sorcery
48
48
  @cost ||= 10
49
49
  end
50
50
  attr_writer :cost
51
+ alias :stretches :cost
51
52
  alias :stretches= :cost=
52
53
 
53
54
  # Creates a BCrypt hash for the password passed.
@@ -4,11 +4,31 @@ module Sorcery
4
4
  module ActiveRecord
5
5
  def self.included(klass)
6
6
  klass.extend ClassMethods
7
+ klass.send(:include, InstanceMethods)
7
8
  end
8
9
 
10
+ module InstanceMethods
11
+ def update_many_attributes(attrs)
12
+ attrs.each do |name, value|
13
+ self.send(:"#{name}=", value)
14
+ end
15
+ primary_key = self.class.primary_key
16
+ self.class.where(:"#{primary_key}" => self.send(:"#{primary_key}")).update_all(attrs)
17
+ end
18
+
19
+ def update_single_attribute(name, value)
20
+ update_many_attributes(name => value)
21
+ end
22
+ end
23
+
9
24
  module ClassMethods
25
+ def column_name(attribute)
26
+ return "LOWER(#{attribute})" if (@sorcery_config.downcase_username_before_authenticating)
27
+ return "#{attribute}"
28
+ end
29
+
10
30
  def find_by_credentials(credentials)
11
- sql = @sorcery_config.username_attribute_names.map{|attribute| "#{attribute} = :login"}
31
+ sql = @sorcery_config.username_attribute_names.map{|attribute| column_name(attribute) + " = :login"}
12
32
  where(sql.join(' OR '), :login => credentials[0]).first
13
33
  end
14
34
 
@@ -0,0 +1,56 @@
1
+ module Sorcery
2
+ module Model
3
+ module Adapters
4
+ module MongoMapper
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ include Sorcery::Model
9
+ end
10
+
11
+ def increment(attr)
12
+ self.class.increment(id, attr => 1)
13
+ end
14
+
15
+ def save!(options = {})
16
+ save(options)
17
+ end
18
+
19
+ def update_many_attributes(attrs)
20
+ update_attributes(attrs)
21
+ end
22
+
23
+ module ClassMethods
24
+ def credential_regex(credential)
25
+ return { :$regex => /^#{credential}$/i } if (@sorcery_config.downcase_username_before_authenticating)
26
+ return credential
27
+ end
28
+
29
+ def find_by_credentials(credentials)
30
+ @sorcery_config.username_attribute_names.each do |attribute|
31
+ @user = where(attribute => credential_regex(credentials[0])).first
32
+ break if @user
33
+ end
34
+ @user
35
+ end
36
+
37
+ def find_by_id(id)
38
+ find(id)
39
+ end
40
+
41
+ def find_by_activation_token(token)
42
+ where(sorcery_config.activation_token_attribute_name => token).first
43
+ end
44
+
45
+ def transaction(&blk)
46
+ tap(&blk)
47
+ end
48
+
49
+ def find_by_sorcery_token(token_attr_name, token)
50
+ where(token_attr_name => token).first
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -11,12 +11,29 @@ module Sorcery
11
11
  def increment(attr)
12
12
  self.inc(attr,1)
13
13
  end
14
+
15
+ def update_many_attributes(attrs)
16
+ attrs.each do |name, value|
17
+ attrs[name] = value.utc if value.is_a?(ActiveSupport::TimeWithZone)
18
+ self.send(:"#{name}=", value)
19
+ end
20
+ self.class.where(:_id => self.id).update_all(attrs)
21
+ end
22
+
23
+ def update_single_attribute(name, value)
24
+ update_many_attributes(name => value)
25
+ end
14
26
  end
15
27
 
16
28
  module ClassMethods
29
+ def credential_regex(credential)
30
+ return { :$regex => /^#{credential}$/i } if (@sorcery_config.downcase_username_before_authenticating)
31
+ return credential
32
+ end
33
+
17
34
  def find_by_credentials(credentials)
18
35
  @sorcery_config.username_attribute_names.each do |attribute|
19
- @user = where(attribute => credentials[0]).first
36
+ @user = where(attribute => credential_regex(credentials[0])).first
20
37
  break if @user
21
38
  end
22
39
  @user
@@ -29,6 +46,8 @@ module Sorcery
29
46
 
30
47
  def find_by_id(id)
31
48
  find(id)
49
+ rescue ::Mongoid::Errors::DocumentNotFound
50
+ nil
32
51
  end
33
52
 
34
53
  def find_by_activation_token(token)
@@ -41,7 +60,7 @@ module Sorcery
41
60
 
42
61
  def find_by_username(username)
43
62
  query = sorcery_config.username_attribute_names.map {|name| {name => username}}
44
- where(query).first
63
+ any_of(*query).first
45
64
  end
46
65
 
47
66
  def transaction(&blk)
@@ -59,8 +78,8 @@ module Sorcery
59
78
  def get_current_users
60
79
  config = sorcery_config
61
80
  where(config.last_activity_at_attribute_name.ne => nil) \
62
- .any_of({config.last_logout_at_attribute_name => nil},{config.last_activity_at_attribute_name.gt => config.last_logout_at_attribute_name}) \
63
- .and(config.last_activity_at_attribute_name.gt => config.activity_timeout.seconds.ago.utc.to_s(:db)).order_by([:_id,:asc])
81
+ .where("this.#{config.last_logout_at_attribute_name} == null || this.#{config.last_activity_at_attribute_name} > this.#{config.last_logout_at_attribute_name}") \
82
+ .where(config.last_activity_at_attribute_name.gt => config.activity_timeout.seconds.ago.utc).order_by([:_id,:asc])
64
83
  end
65
84
  end
66
85
  end
@@ -39,12 +39,12 @@ module Sorcery
39
39
  protected
40
40
 
41
41
  def define_activity_logging_mongoid_fields
42
- field sorcery_config.last_login_at_attribute_name, :type => DateTime
43
- field sorcery_config.last_logout_at_attribute_name, :type => DateTime
44
- field sorcery_config.last_activity_at_attribute_name, :type => DateTime
42
+ field sorcery_config.last_login_at_attribute_name, :type => Time
43
+ field sorcery_config.last_logout_at_attribute_name, :type => Time
44
+ field sorcery_config.last_activity_at_attribute_name, :type => Time
45
45
  end
46
46
  end
47
47
  end
48
48
  end
49
49
  end
50
- end
50
+ end
@@ -12,30 +12,56 @@ module Sorcery
12
12
  :lock_expires_at_attribute_name, # this field indicates whether user
13
13
  # is banned and when it will be active again.
14
14
  :consecutive_login_retries_amount_limit, # how many failed logins allowed.
15
- :login_lock_time_period # how long the user should be banned.
15
+ :login_lock_time_period, # how long the user should be banned.
16
16
  # in seconds. 0 for permanent.
17
+
18
+ :unlock_token_attribute_name, # Unlock token attribute name
19
+ :unlock_token_email_method_name, # Mailer method name
20
+ :unlock_token_mailer_disabled, # When true, dont send unlock token via email
21
+ :unlock_token_mailer # Mailer class
17
22
  end
18
23
 
19
24
  base.sorcery_config.instance_eval do
20
25
  @defaults.merge!(:@failed_logins_count_attribute_name => :failed_logins_count,
21
26
  :@lock_expires_at_attribute_name => :lock_expires_at,
22
27
  :@consecutive_login_retries_amount_limit => 50,
23
- :@login_lock_time_period => 60 * 60)
28
+ :@login_lock_time_period => 60 * 60,
29
+
30
+ :@unlock_token_attribute_name => :unlock_token,
31
+ :@unlock_token_email_method_name => :send_unlock_token_email,
32
+ :@unlock_token_mailer_disabled => false,
33
+ :@unlock_token_mailer => nil)
24
34
  reset!
25
35
  end
26
36
 
27
37
  base.sorcery_config.before_authenticate << :prevent_locked_user_login
28
38
  base.sorcery_config.after_config << :define_brute_force_protection_mongoid_fields if defined?(Mongoid) and base.ancestors.include?(Mongoid::Document)
39
+ if defined?(MongoMapper) and base.ancestors.include?(MongoMapper::Document)
40
+ base.sorcery_config.after_config << :define_brute_force_protection_mongo_mapper_fields
41
+ end
29
42
  base.extend(ClassMethods)
30
43
  base.send(:include, InstanceMethods)
31
44
  end
32
45
 
33
46
  module ClassMethods
47
+ def load_from_unlock_token(token)
48
+ return nil if token.blank?
49
+ user = find_by_sorcery_token(sorcery_config.unlock_token_attribute_name,token)
50
+ user
51
+ end
52
+
34
53
  protected
35
54
 
36
55
  def define_brute_force_protection_mongoid_fields
37
- field sorcery_config.failed_logins_count_attribute_name, :type => Integer
38
- field sorcery_config.lock_expires_at_attribute_name, :type => DateTime
56
+ field sorcery_config.failed_logins_count_attribute_name, :type => Integer, :default => 0
57
+ field sorcery_config.lock_expires_at_attribute_name, :type => Time
58
+ field sorcery_config.unlock_token_attribute_name, :type => String
59
+ end
60
+
61
+ def define_brute_force_protection_mongo_mapper_fields
62
+ key sorcery_config.failed_logins_count_attribute_name, Integer, :default => 0
63
+ key sorcery_config.lock_expires_at_attribute_name, Time
64
+ key sorcery_config.unlock_token_attribute_name, String
39
65
  end
40
66
  end
41
67
 
@@ -46,36 +72,49 @@ module Sorcery
46
72
  config = sorcery_config
47
73
  return if !unlocked?
48
74
  self.increment(config.failed_logins_count_attribute_name)
49
- save!
75
+ self.update_many_attributes(config.failed_logins_count_attribute_name => self.send(config.failed_logins_count_attribute_name))
50
76
  self.lock! if self.send(config.failed_logins_count_attribute_name) >= config.consecutive_login_retries_amount_limit
51
77
  end
52
78
 
79
+ # /!\
80
+ # Moved out of protected for use like activate! in controller
81
+ # /!\
82
+ def unlock!
83
+ config = sorcery_config
84
+ attributes = {config.lock_expires_at_attribute_name => nil,
85
+ config.failed_logins_count_attribute_name => 0}
86
+ attributes[config.unlock_token_attribute_name] = nil unless config.unlock_token_mailer_disabled or config.unlock_token_mailer.nil?
87
+ self.update_many_attributes(attributes)
88
+ end
89
+
53
90
  protected
54
91
 
55
92
  def lock!
56
93
  config = sorcery_config
57
- self.send(:"#{config.lock_expires_at_attribute_name}=", Time.now.utc + config.login_lock_time_period)
58
- self.save!
59
- end
94
+ attributes = {config.lock_expires_at_attribute_name => Time.now.in_time_zone + config.login_lock_time_period}
60
95
 
61
- def unlock!
62
- config = sorcery_config
63
- self.send(:"#{config.lock_expires_at_attribute_name}=", nil)
64
- self.send(:"#{config.failed_logins_count_attribute_name}=", 0)
65
- self.save!
96
+ unless config.unlock_token_mailer_disabled || config.unlock_token_mailer.nil?
97
+ attributes[config.unlock_token_attribute_name] = TemporaryToken.generate_random_token
98
+ send_unlock_token_email!
99
+ end
100
+ self.update_many_attributes(attributes)
66
101
  end
67
102
 
68
103
  def unlocked?
69
104
  config = sorcery_config
70
105
  self.send(config.lock_expires_at_attribute_name).nil?
71
106
  end
107
+
108
+ def send_unlock_token_email!
109
+ generic_send_email(:unlock_token_email_method_name, :unlock_token_mailer) unless sorcery_config.unlock_token_email_method_name.nil? or sorcery_config.unlock_token_mailer_disabled == true
110
+ end
72
111
 
73
112
  # Prevents a locked user from logging in, and unlocks users that expired their lock time.
74
113
  # Runs as a hook before authenticate.
75
114
  def prevent_locked_user_login
76
115
  config = sorcery_config
77
116
  if !self.unlocked? && config.login_lock_time_period != 0
78
- self.unlock! if self.send(config.lock_expires_at_attribute_name) <= Time.now.utc
117
+ self.unlock! if self.send(config.lock_expires_at_attribute_name) <= Time.now.in_time_zone
79
118
  end
80
119
  unlocked?
81
120
  end
@@ -83,4 +122,4 @@ module Sorcery
83
122
  end
84
123
  end
85
124
  end
86
- end
125
+ end