sorcery 0.6.1 → 0.7.10

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 (205) hide show
  1. data/.travis.yml +2 -0
  2. data/Gemfile +2 -23
  3. data/Gemfile.lock +105 -77
  4. data/README.rdoc +32 -59
  5. data/Rakefile +29 -1
  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 +406 -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 +3 -3
  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 +24 -10
  18. data/lib/sorcery/controller/submodules/brute_force_protection.rb +3 -2
  19. data/lib/sorcery/controller/submodules/external/protocols/certs/ca-bundle.crt +5182 -0
  20. data/lib/sorcery/controller/submodules/external/protocols/oauth2.rb +28 -9
  21. data/lib/sorcery/controller/submodules/external/providers/facebook.rb +12 -4
  22. data/lib/sorcery/controller/submodules/external/providers/github.rb +89 -0
  23. data/lib/sorcery/controller/submodules/external/providers/google.rb +90 -0
  24. data/lib/sorcery/controller/submodules/external/providers/liveid.rb +91 -0
  25. data/lib/sorcery/controller/submodules/external/providers/twitter.rb +8 -2
  26. data/lib/sorcery/controller/submodules/external.rb +17 -4
  27. data/lib/sorcery/controller/submodules/http_basic_auth.rb +1 -1
  28. data/lib/sorcery/controller/submodules/remember_me.rb +26 -15
  29. data/lib/sorcery/controller/submodules/session_timeout.rb +4 -4
  30. data/lib/sorcery/controller.rb +61 -38
  31. data/lib/sorcery/crypto_providers/aes256.rb +7 -3
  32. data/lib/sorcery/engine.rb +1 -0
  33. data/lib/sorcery/model/adapters/active_record.rb +17 -1
  34. data/lib/sorcery/model/adapters/mongo_mapper.rb +54 -0
  35. data/lib/sorcery/model/adapters/mongoid.rb +22 -4
  36. data/lib/sorcery/model/submodules/activity_logging.rb +4 -4
  37. data/lib/sorcery/model/submodules/brute_force_protection.rb +53 -14
  38. data/lib/sorcery/model/submodules/remember_me.rb +10 -3
  39. data/lib/sorcery/model/submodules/reset_password.rb +26 -11
  40. data/lib/sorcery/model/submodules/user_activation.rb +28 -10
  41. data/lib/sorcery/model/temporary_token.rb +8 -1
  42. data/lib/sorcery/model.rb +51 -19
  43. data/lib/sorcery/test_helpers/internal/rails.rb +1 -1
  44. data/lib/sorcery/test_helpers/rails.rb +2 -2
  45. data/lib/sorcery.rb +8 -7
  46. data/sorcery.gemspec +110 -223
  47. data/spec/Gemfile +1 -1
  48. data/spec/Gemfile.lock +26 -26
  49. data/spec/README.md +31 -0
  50. data/spec/rails3/Gemfile +5 -3
  51. data/spec/rails3/Gemfile.lock +74 -48
  52. data/spec/rails3/app/controllers/application_controller.rb +70 -23
  53. data/spec/rails3/app/mailers/sorcery_mailer.rb +7 -0
  54. data/spec/rails3/app/views/application/index.html.erb +17 -0
  55. data/spec/rails3/app/views/sorcery_mailer/send_unlock_token_email.text.erb +1 -0
  56. data/spec/rails3/config/environments/in_memory.rb +35 -0
  57. data/spec/rails3/db/migrate/brute_force_protection/20101224223626_add_brute_force_protection_to_users.rb +2 -0
  58. data/spec/rails3/spec/controller_activity_logging_spec.rb +33 -3
  59. data/spec/rails3/spec/controller_brute_force_protection_spec.rb +25 -3
  60. data/spec/rails3/spec/controller_oauth2_spec.rb +170 -25
  61. data/spec/rails3/spec/controller_remember_me_spec.rb +37 -6
  62. data/spec/rails3/spec/controller_session_timeout_spec.rb +4 -4
  63. data/spec/rails3/spec/controller_spec.rb +60 -2
  64. data/spec/rails3/spec/integration_spec.rb +23 -0
  65. data/spec/rails3/spec/spec_helper.rb +6 -5
  66. data/spec/rails3_mongo_mapper/.gitignore +4 -0
  67. data/spec/rails3_mongo_mapper/.rspec +1 -0
  68. data/spec/{sinatra_modular → rails3_mongo_mapper}/Gemfile +6 -5
  69. data/spec/rails3_mongo_mapper/Gemfile.lock +154 -0
  70. data/spec/{sinatra → rails3_mongo_mapper}/Rakefile +3 -3
  71. data/spec/rails3_mongo_mapper/app/controllers/application_controller.rb +108 -0
  72. data/spec/rails3_mongo_mapper/app/helpers/application_helper.rb +2 -0
  73. data/spec/rails3_mongo_mapper/app/models/authentication.rb +6 -0
  74. data/spec/rails3_mongo_mapper/app/models/user.rb +5 -0
  75. data/spec/rails3_mongo_mapper/app/views/layouts/application.html.erb +14 -0
  76. data/spec/rails3_mongo_mapper/app/views/sorcery_mailer/activation_email.html.erb +17 -0
  77. data/spec/rails3_mongo_mapper/app/views/sorcery_mailer/activation_email.text.erb +9 -0
  78. data/spec/rails3_mongo_mapper/app/views/sorcery_mailer/activation_success_email.html.erb +17 -0
  79. data/spec/rails3_mongo_mapper/app/views/sorcery_mailer/activation_success_email.text.erb +9 -0
  80. data/spec/rails3_mongo_mapper/app/views/sorcery_mailer/reset_password_email.html.erb +16 -0
  81. data/spec/rails3_mongo_mapper/app/views/sorcery_mailer/reset_password_email.text.erb +8 -0
  82. data/spec/rails3_mongo_mapper/config/application.rb +51 -0
  83. data/spec/rails3_mongo_mapper/config/boot.rb +13 -0
  84. data/spec/rails3_mongo_mapper/config/environment.rb +5 -0
  85. data/spec/rails3_mongo_mapper/config/environments/development.rb +30 -0
  86. data/spec/rails3_mongo_mapper/config/environments/in_memory.rb +0 -0
  87. data/spec/rails3_mongo_mapper/config/environments/production.rb +49 -0
  88. data/spec/rails3_mongo_mapper/config/environments/test.rb +35 -0
  89. data/spec/rails3_mongo_mapper/config/initializers/backtrace_silencers.rb +7 -0
  90. data/spec/rails3_mongo_mapper/config/initializers/inflections.rb +10 -0
  91. data/spec/rails3_mongo_mapper/config/initializers/mime_types.rb +5 -0
  92. data/spec/rails3_mongo_mapper/config/initializers/mongo.rb +2 -0
  93. data/spec/rails3_mongo_mapper/config/initializers/secret_token.rb +7 -0
  94. data/spec/rails3_mongo_mapper/config/initializers/session_store.rb +8 -0
  95. data/spec/rails3_mongo_mapper/config/locales/en.yml +5 -0
  96. data/spec/rails3_mongo_mapper/config/routes.rb +59 -0
  97. data/spec/rails3_mongo_mapper/config.ru +4 -0
  98. data/spec/rails3_mongo_mapper/db/schema.rb +23 -0
  99. data/spec/rails3_mongo_mapper/db/seeds.rb +7 -0
  100. data/spec/rails3_mongo_mapper/lib/tasks/.gitkeep +0 -0
  101. data/spec/rails3_mongo_mapper/public/404.html +26 -0
  102. data/spec/rails3_mongo_mapper/public/422.html +26 -0
  103. data/spec/rails3_mongo_mapper/public/500.html +26 -0
  104. data/spec/rails3_mongo_mapper/public/favicon.ico +0 -0
  105. data/spec/rails3_mongo_mapper/public/images/rails.png +0 -0
  106. data/spec/rails3_mongo_mapper/public/javascripts/application.js +2 -0
  107. data/spec/rails3_mongo_mapper/public/javascripts/controls.js +965 -0
  108. data/spec/rails3_mongo_mapper/public/javascripts/dragdrop.js +974 -0
  109. data/spec/rails3_mongo_mapper/public/javascripts/effects.js +1123 -0
  110. data/spec/rails3_mongo_mapper/public/javascripts/prototype.js +6001 -0
  111. data/spec/rails3_mongo_mapper/public/javascripts/rails.js +175 -0
  112. data/spec/rails3_mongo_mapper/public/robots.txt +5 -0
  113. data/spec/rails3_mongo_mapper/public/stylesheets/.gitkeep +0 -0
  114. data/spec/rails3_mongo_mapper/script/rails +6 -0
  115. data/spec/rails3_mongo_mapper/spec/controller_spec.rb +163 -0
  116. data/spec/rails3_mongo_mapper/spec/spec_helper.orig.rb +27 -0
  117. data/spec/rails3_mongo_mapper/spec/spec_helper.rb +55 -0
  118. data/spec/rails3_mongo_mapper/spec/user_activation_spec.rb +9 -0
  119. data/spec/rails3_mongo_mapper/spec/user_activity_logging_spec.rb +8 -0
  120. data/spec/rails3_mongo_mapper/spec/user_brute_force_protection_spec.rb +8 -0
  121. data/spec/rails3_mongo_mapper/spec/user_oauth_spec.rb +8 -0
  122. data/spec/rails3_mongo_mapper/spec/user_remember_me_spec.rb +8 -0
  123. data/spec/rails3_mongo_mapper/spec/user_reset_password_spec.rb +8 -0
  124. data/spec/rails3_mongo_mapper/spec/user_spec.rb +37 -0
  125. data/spec/rails3_mongo_mapper/vendor/plugins/.gitkeep +0 -0
  126. data/spec/rails3_mongoid/Gemfile +2 -1
  127. data/spec/rails3_mongoid/Gemfile.lock +46 -45
  128. data/spec/rails3_mongoid/app/controllers/application_controller.rb +5 -0
  129. data/spec/rails3_mongoid/config/mongoid.yml +1 -1
  130. data/spec/rails3_mongoid/script/rails +0 -0
  131. data/spec/rails3_mongoid/spec/controller_activity_logging_spec.rb +105 -0
  132. data/spec/rails3_mongoid/spec/controller_spec.rb +174 -0
  133. data/spec/rails3_mongoid/spec/user_spec.rb +1 -0
  134. data/spec/shared_examples/user_activation_shared_examples.rb +72 -42
  135. data/spec/shared_examples/user_remember_me_shared_examples.rb +2 -1
  136. data/spec/shared_examples/user_reset_password_shared_examples.rb +81 -28
  137. data/spec/shared_examples/user_shared_examples.rb +36 -8
  138. data/spec/sorcery_crypto_providers_spec.rb +5 -1
  139. metadata +239 -346
  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 -13
  145. data/lib/generators/sorcery_migration/templates/user_activation.rb +0 -17
  146. data/lib/sorcery/controller/adapters/sinatra.rb +0 -104
  147. data/lib/sorcery/initializers/initializer.rb +0 -178
  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/rails3/public/index.html +0 -239
  154. data/spec/sinatra/Gemfile +0 -15
  155. data/spec/sinatra/Gemfile.lock +0 -117
  156. data/spec/sinatra/authentication.rb +0 -3
  157. data/spec/sinatra/db/migrate/activation/20101224223622_add_activation_to_users.rb +0 -17
  158. data/spec/sinatra/db/migrate/activity_logging/20101224223624_add_activity_logging_to_users.rb +0 -17
  159. data/spec/sinatra/db/migrate/brute_force_protection/20101224223626_add_brute_force_protection_to_users.rb +0 -11
  160. data/spec/sinatra/db/migrate/core/20101224223620_create_users.rb +0 -16
  161. data/spec/sinatra/db/migrate/external/20101224223628_create_authentications.rb +0 -14
  162. data/spec/sinatra/db/migrate/remember_me/20101224223623_add_remember_me_token_to_users.rb +0 -15
  163. data/spec/sinatra/db/migrate/reset_password/20101224223622_add_reset_password_to_users.rb +0 -13
  164. data/spec/sinatra/filters.rb +0 -27
  165. data/spec/sinatra/modular.rb +0 -157
  166. data/spec/sinatra/myapp.rb +0 -133
  167. data/spec/sinatra/spec/controller_activity_logging_spec.rb +0 -85
  168. data/spec/sinatra/spec/controller_brute_force_protection_spec.rb +0 -70
  169. data/spec/sinatra/spec/controller_http_basic_auth_spec.rb +0 -53
  170. data/spec/sinatra/spec/controller_oauth2_spec.rb +0 -99
  171. data/spec/sinatra/spec/controller_oauth_spec.rb +0 -100
  172. data/spec/sinatra/spec/controller_remember_me_spec.rb +0 -64
  173. data/spec/sinatra/spec/controller_session_timeout_spec.rb +0 -57
  174. data/spec/sinatra/spec/controller_spec.rb +0 -120
  175. data/spec/sinatra/spec/spec_helper.rb +0 -45
  176. data/spec/sinatra/user.rb +0 -6
  177. data/spec/sinatra/views/test_login.erb +0 -4
  178. data/spec/sinatra_modular/Gemfile.lock +0 -117
  179. data/spec/sinatra_modular/Rakefile +0 -11
  180. data/spec/sinatra_modular/authentication.rb +0 -3
  181. data/spec/sinatra_modular/db/migrate/activation/20101224223622_add_activation_to_users.rb +0 -17
  182. data/spec/sinatra_modular/db/migrate/activity_logging/20101224223624_add_activity_logging_to_users.rb +0 -17
  183. data/spec/sinatra_modular/db/migrate/brute_force_protection/20101224223626_add_brute_force_protection_to_users.rb +0 -11
  184. data/spec/sinatra_modular/db/migrate/core/20101224223620_create_users.rb +0 -16
  185. data/spec/sinatra_modular/db/migrate/external/20101224223628_create_authentications.rb +0 -14
  186. data/spec/sinatra_modular/db/migrate/remember_me/20101224223623_add_remember_me_token_to_users.rb +0 -15
  187. data/spec/sinatra_modular/db/migrate/reset_password/20101224223622_add_reset_password_to_users.rb +0 -13
  188. data/spec/sinatra_modular/filters.rb +0 -27
  189. data/spec/sinatra_modular/modular.rb +0 -157
  190. data/spec/sinatra_modular/myapp.rb +0 -133
  191. data/spec/sinatra_modular/sorcery_mailer.rb +0 -25
  192. data/spec/sinatra_modular/spec_modular/controller_activity_logging_spec.rb +0 -85
  193. data/spec/sinatra_modular/spec_modular/controller_brute_force_protection_spec.rb +0 -70
  194. data/spec/sinatra_modular/spec_modular/controller_http_basic_auth_spec.rb +0 -53
  195. data/spec/sinatra_modular/spec_modular/controller_oauth2_spec.rb +0 -99
  196. data/spec/sinatra_modular/spec_modular/controller_oauth_spec.rb +0 -100
  197. data/spec/sinatra_modular/spec_modular/controller_remember_me_spec.rb +0 -64
  198. data/spec/sinatra_modular/spec_modular/controller_session_timeout_spec.rb +0 -57
  199. data/spec/sinatra_modular/spec_modular/controller_spec.rb +0 -116
  200. data/spec/sinatra_modular/spec_modular/spec.opts +0 -2
  201. data/spec/sinatra_modular/spec_modular/spec_helper.rb +0 -51
  202. data/spec/sinatra_modular/user.rb +0 -6
  203. data/spec/sinatra_modular/views/test_login.erb +0 -4
  204. /data/spec/{sinatra → rails3_mongo_mapper/app/mailers}/sorcery_mailer.rb +0 -0
  205. /data/spec/{sinatra → rails3_mongo_mapper}/spec/spec.opts +0 -0
@@ -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,7 +14,7 @@ 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?
@@ -22,19 +22,20 @@ module Sorcery
22
22
  def require_login
23
23
  if !logged_in?
24
24
  session[:return_to_url] = request.url if Config.save_return_to_url
25
- self.send(Config.not_authenticated_action)
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
31
  def login(*credentials)
32
+ @current_user = nil
32
33
  user = user_class.authenticate(*credentials)
33
34
  if user
34
35
  return_to_url = session[:return_to_url]
35
36
  reset_session # protect from session fixation attacks
36
37
  session[:return_to_url] = return_to_url
37
- login_user(user)
38
+ auto_login(user)
38
39
  after_login!(user, credentials)
39
40
  current_user
40
41
  else
@@ -42,41 +43,63 @@ module Sorcery
42
43
  nil
43
44
  end
44
45
  end
45
-
46
+
46
47
  # Resets the session and runs hooks before and after.
47
48
  def logout
48
49
  if logged_in?
49
50
  before_logout!(current_user)
50
51
  reset_session
51
52
  after_logout!
53
+ @current_user = nil
52
54
  end
53
55
  end
54
-
56
+
55
57
  def logged_in?
56
58
  !!current_user
57
59
  end
58
-
60
+
59
61
  # attempts to auto-login from the sources defined (session, basic_auth, cookie, etc.)
60
62
  # returns the logged in user if found, false if not (using old restful-authentication trick, nil != false).
61
63
  def current_user
62
64
  @current_user ||= login_from_session || login_from_other_sources unless @current_user == false
63
65
  end
64
-
65
- # used when a user tries to access a page while logged out, is asked to login,
66
+
67
+ def current_user=(user)
68
+ @current_user = user
69
+ end
70
+
71
+ # used when a user tries to access a page while logged out, is asked to login,
66
72
  # and we want to return him back to the page he originally wanted.
67
73
  def redirect_back_or_to(url, flash_hash = {})
68
74
  redirect_to(session[:return_to_url] || url, :flash => flash_hash)
75
+ session[:return_to_url] = nil
69
76
  end
70
-
77
+
71
78
  # The default action for denying non-authenticated users.
72
79
  # You can override this method in your controllers,
73
80
  # or provide a different method in the configuration.
74
81
  def not_authenticated
75
82
  redirect_to root_path
76
83
  end
77
-
84
+
85
+ # login a user instance
86
+ #
87
+ # @param [<User-Model>] user the user instance.
88
+ # @return - do not depend on the return value.
89
+ def auto_login(user)
90
+ session[:user_id] = user.id
91
+ @current_user = user
92
+ end
93
+
94
+ # Overwrite Rails' handle unverified request
95
+ def handle_unverified_request
96
+ cookies[:remember_me_token] = nil
97
+ @current_user = nil
98
+ super # call the default behaviour which resets the session
99
+ end
100
+
78
101
  protected
79
-
102
+
80
103
  # Tries all available sources (methods) until one doesn't return false.
81
104
  def login_from_other_sources
82
105
  result = nil
@@ -85,52 +108,51 @@ module Sorcery
85
108
  end
86
109
  result || false
87
110
  end
88
-
89
- def login_user(user)
90
- session[:user_id] = user.id
91
- end
92
-
111
+
93
112
  def login_from_session
94
113
  @current_user = (user_class.find_by_id(session[:user_id]) if session[:user_id]) || false
95
114
  end
96
-
115
+
97
116
  def after_login!(user, credentials)
98
117
  Config.after_login.each {|c| self.send(c, user, credentials)}
99
118
  end
100
-
119
+
101
120
  def after_failed_login!(credentials)
102
121
  Config.after_failed_login.each {|c| self.send(c, credentials)}
103
122
  end
104
-
123
+
105
124
  def before_logout!(user)
106
125
  Config.before_logout.each {|c| self.send(c, user)}
107
126
  end
108
-
127
+
109
128
  def after_logout!
110
129
  Config.after_logout.each {|c| self.send(c)}
111
130
  end
112
-
131
+
113
132
  def user_class
114
133
  @user_class ||= Config.user_class.to_s.constantize
115
134
  end
135
+
116
136
  end
117
-
137
+
118
138
  module Config
119
139
  class << self
120
140
  attr_accessor :submodules,
121
- :user_class, # what class to use as the user class.
141
+ :user_class, # what class to use as the user class.
122
142
  :not_authenticated_action, # what controller action to call for non-authenticated users.
123
-
143
+
124
144
  :save_return_to_url, # when a non logged in user tries to enter a page that requires
125
- # login, save the URL he wanted to reach,
145
+ # login, save the URL he wanted to reach,
126
146
  # and send him there after login.
127
-
147
+
148
+ :cookie_domain, # set domain option for cookies
149
+
128
150
  :login_sources,
129
151
  :after_login,
130
152
  :after_failed_login,
131
153
  :before_logout,
132
- :after_logout
133
-
154
+ :after_logout
155
+
134
156
  def init!
135
157
  @defaults = {
136
158
  :@user_class => nil,
@@ -141,31 +163,32 @@ module Sorcery
141
163
  :@after_failed_login => [],
142
164
  :@before_logout => [],
143
165
  :@after_logout => [],
144
- :@save_return_to_url => true
166
+ :@save_return_to_url => true,
167
+ :@cookie_domain => nil
145
168
  }
146
169
  end
147
-
170
+
148
171
  # Resets all configuration options to their default values.
149
172
  def reset!
150
173
  @defaults.each do |k,v|
151
174
  instance_variable_set(k,v)
152
- end
175
+ end
153
176
  end
154
-
177
+
155
178
  def update!
156
179
  @defaults.each do |k,v|
157
180
  instance_variable_set(k,v) if !instance_variable_defined?(k)
158
181
  end
159
182
  end
160
-
183
+
161
184
  def user_config(&blk)
162
185
  block_given? ? @user_config = blk : @user_config
163
186
  end
164
-
187
+
165
188
  def configure(&blk)
166
189
  @configure_blk = blk
167
190
  end
168
-
191
+
169
192
  def configure!
170
193
  @configure_blk.call(self) if @configure_blk
171
194
  end
@@ -174,4 +197,4 @@ module Sorcery
174
197
  reset!
175
198
  end
176
199
  end
177
- end
200
+ end
@@ -28,12 +28,16 @@ module Sorcery
28
28
  end
29
29
 
30
30
  def matches?(crypted, *tokens)
31
- aes.decrypt
32
- aes.key = @key
33
- (aes.update(crypted.unpack("m").first) + aes.final) == tokens.join
31
+ decrypt(crypted) == tokens.join
34
32
  rescue OpenSSL::CipherError
35
33
  false
36
34
  end
35
+
36
+ def decrypt(crypted)
37
+ aes.decrypt
38
+ aes.key = @key
39
+ (aes.update(crypted.unpack("m").first) + aes.final)
40
+ end
37
41
 
38
42
  private
39
43
 
@@ -10,6 +10,7 @@ module Sorcery
10
10
  initializer "extend Controller with sorcery" do |app|
11
11
  ActionController::Base.send(:include, Sorcery::Controller)
12
12
  ActionController::Base.helper_method :current_user
13
+ ActionController::Base.helper_method :logged_in?
13
14
  end
14
15
 
15
16
  rake_tasks do
@@ -4,11 +4,27 @@ 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_single_attribute(name, value)
12
+ self.send(:"#{name}=", value)
13
+
14
+ primary_key = self.class.primary_key
15
+ self.class.where(:"#{primary_key}" => self.send(:"#{primary_key}")).update_all(name => value)
16
+ end
17
+ end
18
+
9
19
  module ClassMethods
20
+ def column_name(attribute)
21
+ return "LOWER(#{attribute})" if (@sorcery_config.downcase_username_before_authenticating)
22
+ return "#{attribute}"
23
+ end
24
+
10
25
  def find_by_credentials(credentials)
11
- where("#{@sorcery_config.username_attribute_name} = ?", credentials[0]).first
26
+ sql = @sorcery_config.username_attribute_names.map{|attribute| column_name(attribute) + " = :login"}
27
+ where(sql.join(' OR '), :login => credentials[0]).first
12
28
  end
13
29
 
14
30
  def find_by_sorcery_token(token_attr_name, token)
@@ -0,0 +1,54 @@
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
+ module InstanceMethods
12
+ def increment(attr)
13
+ self.class.increment(id, attr => 1)
14
+ end
15
+
16
+ def save!(options = {})
17
+ save(options)
18
+ end
19
+ end
20
+
21
+ module ClassMethods
22
+ def credential_regex(credential)
23
+ return { :$regex => /^#{credential}$/i } if (@sorcery_config.downcase_username_before_authenticating)
24
+ return credential
25
+ end
26
+
27
+ def find_by_credentials(credentials)
28
+ @sorcery_config.username_attribute_names.each do |attribute|
29
+ @user = where(attribute => credential_regex(credentials[0])).first
30
+ break if @user
31
+ end
32
+ @user
33
+ end
34
+
35
+ def find_by_id(id)
36
+ find(id)
37
+ end
38
+
39
+ def find_by_activation_token(token)
40
+ where(sorcery_config.activation_token_attribute_name => token).first
41
+ end
42
+
43
+ def transaction(&blk)
44
+ tap(&blk)
45
+ end
46
+
47
+ def find_by_sorcery_token(token_attr_name, token)
48
+ where(token_attr_name => token).first
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -11,11 +11,26 @@ module Sorcery
11
11
  def increment(attr)
12
12
  self.inc(attr,1)
13
13
  end
14
+
15
+ def update_single_attribute(name, value)
16
+ value = value.utc if value.is_a?(ActiveSupport::TimeWithZone)
17
+ self.send(:"#{name}=", value)
18
+ self.class.where(:_id => self.id).update_all(name => value)
19
+ end
14
20
  end
15
21
 
16
22
  module ClassMethods
23
+ def credential_regex(credential)
24
+ return { :$regex => /^#{credential}$/i } if (@sorcery_config.downcase_username_before_authenticating)
25
+ return credential
26
+ end
27
+
17
28
  def find_by_credentials(credentials)
18
- where(sorcery_config.username_attribute_name => credentials[0]).first
29
+ @sorcery_config.username_attribute_names.each do |attribute|
30
+ @user = where(attribute => credential_regex(credentials[0])).first
31
+ break if @user
32
+ end
33
+ @user
19
34
  end
20
35
 
21
36
  def find_by_provider_and_uid(provider, uid)
@@ -25,6 +40,8 @@ module Sorcery
25
40
 
26
41
  def find_by_id(id)
27
42
  find(id)
43
+ rescue ::Mongoid::Errors::DocumentNotFound
44
+ nil
28
45
  end
29
46
 
30
47
  def find_by_activation_token(token)
@@ -36,7 +53,8 @@ module Sorcery
36
53
  end
37
54
 
38
55
  def find_by_username(username)
39
- where(sorcery_config.username_attribute_name => username).first
56
+ query = sorcery_config.username_attribute_names.map {|name| {name => username}}
57
+ any_of(*query).first
40
58
  end
41
59
 
42
60
  def transaction(&blk)
@@ -54,8 +72,8 @@ module Sorcery
54
72
  def get_current_users
55
73
  config = sorcery_config
56
74
  where(config.last_activity_at_attribute_name.ne => nil) \
57
- .any_of({config.last_logout_at_attribute_name => nil},{config.last_activity_at_attribute_name.gt => config.last_logout_at_attribute_name}) \
58
- .and(config.last_activity_at_attribute_name.gt => config.activity_timeout.seconds.ago.utc.to_s(:db)).order_by([:_id,:asc])
75
+ .where("this.#{config.last_logout_at_attribute_name} == null || this.#{config.last_activity_at_attribute_name} > this.#{config.last_logout_at_attribute_name}") \
76
+ .where(config.last_activity_at_attribute_name.gt => config.activity_timeout.seconds.ago.utc).order_by([:_id,:asc])
59
77
  end
60
78
  end
61
79
  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,58 @@ 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)
44
+
45
+ base.class_eval do
46
+ after_update :send_unlock_token_email!, :if => Proc.new { |user| user.send(sorcery_config.unlock_token_attribute_name).present? }
47
+ end
31
48
  end
32
49
 
33
50
  module ClassMethods
51
+ def load_from_unlock_token(token)
52
+ return nil if token.blank?
53
+ user = find_by_sorcery_token(sorcery_config.unlock_token_attribute_name,token)
54
+ user
55
+ end
56
+
34
57
  protected
35
58
 
36
59
  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
60
+ field sorcery_config.failed_logins_count_attribute_name, :type => Integer, :default => 0
61
+ field sorcery_config.lock_expires_at_attribute_name, :type => Time
62
+ end
63
+
64
+ def define_brute_force_protection_mongo_mapper_fields
65
+ key sorcery_config.failed_logins_count_attribute_name, Integer, :default => 0
66
+ key sorcery_config.lock_expires_at_attribute_name, Time
39
67
  end
40
68
  end
41
69
 
@@ -46,34 +74,45 @@ module Sorcery
46
74
  config = sorcery_config
47
75
  return if !unlocked?
48
76
  self.increment(config.failed_logins_count_attribute_name)
49
- save!
77
+ self.save!(:validate => false)
50
78
  self.lock! if self.send(config.failed_logins_count_attribute_name) >= config.consecutive_login_retries_amount_limit
51
79
  end
52
80
 
53
- protected
54
-
55
- def lock!
81
+ # /!\
82
+ # Moved out of protected for use like activate! in controller
83
+ # /!\
84
+ def unlock!
56
85
  config = sorcery_config
57
- self.update_attributes!(config.lock_expires_at_attribute_name => Time.now.utc + config.login_lock_time_period)
86
+ self.send(:"#{config.lock_expires_at_attribute_name}=", nil)
87
+ self.send(:"#{config.failed_logins_count_attribute_name}=", 0)
88
+ self.send(:"#{config.unlock_token_attribute_name}=", nil) unless config.unlock_token_mailer_disabled or config.unlock_token_mailer.nil?
89
+ self.save!(:validate => false)
58
90
  end
59
91
 
60
- def unlock!
92
+ protected
93
+
94
+ def lock!
61
95
  config = sorcery_config
62
- self.update_attributes!(config.lock_expires_at_attribute_name => nil,
63
- config.failed_logins_count_attribute_name => 0)
96
+ self.send(:"#{config.lock_expires_at_attribute_name}=", Time.now.in_time_zone + config.login_lock_time_period)
97
+ self.send(:"#{config.unlock_token_attribute_name}=", TemporaryToken.generate_random_token) unless config.unlock_token_mailer_disabled or config.unlock_token_mailer.nil?
98
+ self.save!(:validate => false)
64
99
  end
65
100
 
66
101
  def unlocked?
67
102
  config = sorcery_config
68
103
  self.send(config.lock_expires_at_attribute_name).nil?
69
104
  end
105
+
106
+ def send_unlock_token_email!
107
+ 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
108
+ end
70
109
 
71
110
  # Prevents a locked user from logging in, and unlocks users that expired their lock time.
72
111
  # Runs as a hook before authenticate.
73
112
  def prevent_locked_user_login
74
113
  config = sorcery_config
75
114
  if !self.unlocked? && config.login_lock_time_period != 0
76
- self.unlock! if self.send(config.lock_expires_at_attribute_name) <= Time.now.utc
115
+ self.unlock! if self.send(config.lock_expires_at_attribute_name) <= Time.now.in_time_zone
77
116
  end
78
117
  unlocked?
79
118
  end
@@ -81,4 +120,4 @@ module Sorcery
81
120
  end
82
121
  end
83
122
  end
84
- end
123
+ end
@@ -24,7 +24,10 @@ module Sorcery
24
24
  base.send(:include, InstanceMethods)
25
25
 
26
26
  base.sorcery_config.after_config << :define_remember_me_mongoid_fields if defined?(Mongoid) and base.ancestors.include?(Mongoid::Document)
27
-
27
+ if defined?(MongoMapper) and base.ancestors.include?(MongoMapper::Document)
28
+ base.sorcery_config.after_config << :define_remember_me_mongo_mapper_fields
29
+ end
30
+
28
31
  base.extend(ClassMethods)
29
32
  end
30
33
 
@@ -36,14 +39,18 @@ module Sorcery
36
39
  field sorcery_config.remember_me_token_expires_at_attribute_name, :type => Time
37
40
  end
38
41
 
42
+ def define_remember_me_mongo_mapper_fields
43
+ key sorcery_config.remember_me_token_attribute_name, String
44
+ key sorcery_config.remember_me_token_expires_at_attribute_name, Time
45
+ end
39
46
  end
40
47
 
41
48
  module InstanceMethods
42
49
  # You shouldn't really use this one yourself - it's called by the controller's 'remember_me!' method.
43
50
  def remember_me!
44
51
  config = sorcery_config
45
- self.send(:"#{config.remember_me_token_attribute_name}=", generate_random_token)
46
- self.send(:"#{config.remember_me_token_expires_at_attribute_name}=", Time.now + config.remember_me_for)
52
+ self.send(:"#{config.remember_me_token_attribute_name}=", TemporaryToken.generate_random_token)
53
+ self.send(:"#{config.remember_me_token_expires_at_attribute_name}=", Time.now.in_time_zone + config.remember_me_for)
47
54
  self.save!(:validate => false)
48
55
  end
49
56
 
@@ -18,6 +18,11 @@ module Sorcery
18
18
  # protection.
19
19
 
20
20
  :reset_password_mailer, # mailer class. Needed.
21
+
22
+ :reset_password_mailer_disabled, # when true sorcery will not automatically
23
+ # email password reset details and allow you to
24
+ # manually handle how and when email is sent
25
+
21
26
  :reset_password_email_method_name, # reset password email method on your
22
27
  # mailer class.
23
28
 
@@ -34,6 +39,7 @@ module Sorcery
34
39
  :@reset_password_token_expires_at_attribute_name => :reset_password_token_expires_at,
35
40
  :@reset_password_email_sent_at_attribute_name => :reset_password_email_sent_at,
36
41
  :@reset_password_mailer => nil,
42
+ :@reset_password_mailer_disabled => false,
37
43
  :@reset_password_email_method_name => :reset_password_email,
38
44
  :@reset_password_expiration_period => nil,
39
45
  :@reset_password_time_between_emails => 5 * 60 )
@@ -45,8 +51,10 @@ module Sorcery
45
51
 
46
52
  base.sorcery_config.after_config << :validate_mailer_defined
47
53
  base.sorcery_config.after_config << :define_reset_password_mongoid_fields if defined?(Mongoid) and base.ancestors.include?(Mongoid::Document)
54
+ if defined?(MongoMapper) and base.ancestors.include?(MongoMapper::Document)
55
+ base.sorcery_config.after_config << :define_reset_password_mongo_mapper_fields
56
+ end
48
57
 
49
- base.send(:include, TemporaryToken)
50
58
  base.send(:include, InstanceMethods)
51
59
 
52
60
  end
@@ -62,16 +70,23 @@ module Sorcery
62
70
 
63
71
  protected
64
72
 
65
- # This submodule requires the developer to define his own mailer class to be used by it.
73
+ # This submodule requires the developer to define his own mailer class to be used by it
74
+ # when reset_password_mailer_disabled is false
66
75
  def validate_mailer_defined
67
76
  msg = "To use reset_password submodule, you must define a mailer (config.reset_password_mailer = YourMailerClass)."
68
- raise ArgumentError, msg if @sorcery_config.reset_password_mailer == nil
77
+ raise ArgumentError, msg if @sorcery_config.reset_password_mailer == nil and @sorcery_config.reset_password_mailer_disabled == false
69
78
  end
70
79
 
71
80
  def define_reset_password_mongoid_fields
72
81
  field sorcery_config.reset_password_token_attribute_name, :type => String
73
- field sorcery_config.reset_password_token_expires_at_attribute_name, :type => DateTime
74
- field sorcery_config.reset_password_email_sent_at_attribute_name, :type => DateTime
82
+ field sorcery_config.reset_password_token_expires_at_attribute_name, :type => Time
83
+ field sorcery_config.reset_password_email_sent_at_attribute_name, :type => Time
84
+ end
85
+
86
+ def define_reset_password_mongo_mapper_fields
87
+ key sorcery_config.reset_password_token_attribute_name, String
88
+ key sorcery_config.reset_password_token_expires_at_attribute_name, Time
89
+ key sorcery_config.reset_password_email_sent_at_attribute_name, Time
75
90
  end
76
91
  end
77
92
 
@@ -80,13 +95,13 @@ module Sorcery
80
95
  def deliver_reset_password_instructions!
81
96
  config = sorcery_config
82
97
  # hammering protection
83
- return if config.reset_password_time_between_emails && self.send(config.reset_password_email_sent_at_attribute_name) && self.send(config.reset_password_email_sent_at_attribute_name) > config.reset_password_time_between_emails.ago.utc
84
- self.send(:"#{config.reset_password_token_attribute_name}=", generate_random_token)
85
- self.send(:"#{config.reset_password_token_expires_at_attribute_name}=", Time.now.utc + config.reset_password_expiration_period) if config.reset_password_expiration_period
86
- self.send(:"#{config.reset_password_email_sent_at_attribute_name}=", Time.now.utc)
98
+ return false if config.reset_password_time_between_emails && self.send(config.reset_password_email_sent_at_attribute_name) && self.send(config.reset_password_email_sent_at_attribute_name) > config.reset_password_time_between_emails.ago.utc
99
+ self.send(:"#{config.reset_password_token_attribute_name}=", TemporaryToken.generate_random_token)
100
+ self.send(:"#{config.reset_password_token_expires_at_attribute_name}=", Time.now.in_time_zone + config.reset_password_expiration_period) if config.reset_password_expiration_period
101
+ self.send(:"#{config.reset_password_email_sent_at_attribute_name}=", Time.now.in_time_zone)
87
102
  self.class.transaction do
88
103
  self.save!(:validate => false)
89
- generic_send_email(:reset_password_email_method_name, :reset_password_mailer)
104
+ generic_send_email(:reset_password_email_method_name, :reset_password_mailer) unless config.reset_password_mailer_disabled
90
105
  end
91
106
  end
92
107
 
@@ -110,4 +125,4 @@ module Sorcery
110
125
  end
111
126
  end
112
127
  end
113
- end
128
+ end