sorcery 0.4.1 → 0.5.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 (109) hide show
  1. data/Gemfile +5 -2
  2. data/Gemfile.lock +12 -0
  3. data/README.rdoc +12 -7
  4. data/VERSION +1 -1
  5. data/lib/sorcery/controller/submodules/brute_force_protection.rb +1 -1
  6. data/lib/sorcery/crypto_providers/bcrypt.rb +2 -4
  7. data/lib/sorcery/crypto_providers/common.rb +2 -2
  8. data/lib/sorcery/engine.rb +0 -4
  9. data/lib/sorcery/initializers/initializer.rb +2 -0
  10. data/lib/sorcery/model/adapters/active_record.rb +28 -0
  11. data/lib/sorcery/model/adapters/mongoid.rb +59 -0
  12. data/lib/sorcery/model/submodules/activity_logging.rb +12 -3
  13. data/lib/sorcery/model/submodules/brute_force_protection.rb +6 -1
  14. data/lib/sorcery/model/submodules/external.rb +1 -0
  15. data/lib/sorcery/model/submodules/remember_me.rb +15 -1
  16. data/lib/sorcery/model/submodules/reset_password.rb +10 -3
  17. data/lib/sorcery/model/submodules/user_activation.rb +11 -1
  18. data/lib/sorcery/model/temporary_token.rb +1 -1
  19. data/lib/sorcery/model.rb +34 -6
  20. data/lib/sorcery/sinatra.rb +0 -1
  21. data/lib/sorcery/test_helpers/internal/rails.rb +52 -0
  22. data/lib/sorcery/test_helpers/internal/sinatra.rb +74 -0
  23. data/lib/sorcery/test_helpers/internal.rb +56 -0
  24. data/lib/sorcery/test_helpers/rails.rb +5 -43
  25. data/lib/sorcery/test_helpers/sinatra.rb +62 -102
  26. data/lib/sorcery/test_helpers.rb +0 -47
  27. data/lib/sorcery.rb +29 -1
  28. data/sorcery.gemspec +110 -10
  29. data/spec/Gemfile +1 -1
  30. data/spec/Gemfile.lock +12 -4
  31. data/spec/rails3/Gemfile +1 -1
  32. data/spec/rails3/Gemfile.lock +6 -6
  33. data/spec/rails3/spec/controller_activity_logging_spec.rb +2 -4
  34. data/spec/rails3/spec/controller_oauth_spec.rb +3 -3
  35. data/spec/rails3/spec/controller_session_timeout_spec.rb +20 -19
  36. data/spec/rails3/spec/controller_spec.rb +6 -16
  37. data/spec/rails3/spec/spec_helper.rb +2 -2
  38. data/spec/rails3/spec/user_activation_spec.rb +2 -12
  39. data/spec/rails3/spec/user_brute_force_protection_spec.rb +2 -30
  40. data/spec/rails3/spec/user_remember_me_spec.rb +3 -11
  41. data/spec/rails3/spec/user_reset_password_spec.rb +14 -15
  42. data/spec/rails3/spec/user_spec.rb +18 -3
  43. data/spec/rails3_mongoid/.gitignore +4 -0
  44. data/spec/rails3_mongoid/.rspec +1 -0
  45. data/spec/rails3_mongoid/Gemfile +14 -0
  46. data/spec/rails3_mongoid/Gemfile.lock +146 -0
  47. data/spec/rails3_mongoid/Rakefile +11 -0
  48. data/spec/rails3_mongoid/app/controllers/application_controller.rb +108 -0
  49. data/spec/rails3_mongoid/app/helpers/application_helper.rb +2 -0
  50. data/spec/rails3_mongoid/app/mailers/sorcery_mailer.rb +25 -0
  51. data/spec/rails3_mongoid/app/models/authentication.rb +7 -0
  52. data/spec/rails3_mongoid/app/models/user.rb +5 -0
  53. data/spec/rails3_mongoid/app/views/layouts/application.html.erb +14 -0
  54. data/spec/rails3_mongoid/app/views/sorcery_mailer/activation_email.html.erb +17 -0
  55. data/spec/rails3_mongoid/app/views/sorcery_mailer/activation_email.text.erb +9 -0
  56. data/spec/rails3_mongoid/app/views/sorcery_mailer/activation_success_email.html.erb +17 -0
  57. data/spec/rails3_mongoid/app/views/sorcery_mailer/activation_success_email.text.erb +9 -0
  58. data/spec/rails3_mongoid/app/views/sorcery_mailer/reset_password_email.html.erb +16 -0
  59. data/spec/rails3_mongoid/app/views/sorcery_mailer/reset_password_email.text.erb +8 -0
  60. data/spec/rails3_mongoid/config/application.rb +51 -0
  61. data/spec/rails3_mongoid/config/boot.rb +13 -0
  62. data/spec/rails3_mongoid/config/environment.rb +5 -0
  63. data/spec/rails3_mongoid/config/environments/development.rb +26 -0
  64. data/spec/rails3_mongoid/config/environments/in_memory.rb +0 -0
  65. data/spec/rails3_mongoid/config/environments/production.rb +49 -0
  66. data/spec/rails3_mongoid/config/environments/test.rb +35 -0
  67. data/spec/rails3_mongoid/config/initializers/backtrace_silencers.rb +7 -0
  68. data/spec/rails3_mongoid/config/initializers/inflections.rb +10 -0
  69. data/spec/rails3_mongoid/config/initializers/mime_types.rb +5 -0
  70. data/spec/rails3_mongoid/config/initializers/secret_token.rb +7 -0
  71. data/spec/rails3_mongoid/config/initializers/session_store.rb +8 -0
  72. data/spec/rails3_mongoid/config/locales/en.yml +5 -0
  73. data/spec/rails3_mongoid/config/mongoid.yml +7 -0
  74. data/spec/rails3_mongoid/config/routes.rb +59 -0
  75. data/spec/rails3_mongoid/config.ru +4 -0
  76. data/spec/rails3_mongoid/db/schema.rb +23 -0
  77. data/spec/rails3_mongoid/db/seeds.rb +7 -0
  78. data/spec/rails3_mongoid/lib/tasks/.gitkeep +0 -0
  79. data/spec/rails3_mongoid/public/404.html +26 -0
  80. data/spec/rails3_mongoid/public/422.html +26 -0
  81. data/spec/rails3_mongoid/public/500.html +26 -0
  82. data/spec/rails3_mongoid/public/favicon.ico +0 -0
  83. data/spec/rails3_mongoid/public/images/rails.png +0 -0
  84. data/spec/rails3_mongoid/public/javascripts/application.js +2 -0
  85. data/spec/rails3_mongoid/public/javascripts/controls.js +965 -0
  86. data/spec/rails3_mongoid/public/javascripts/dragdrop.js +974 -0
  87. data/spec/rails3_mongoid/public/javascripts/effects.js +1123 -0
  88. data/spec/rails3_mongoid/public/javascripts/prototype.js +6001 -0
  89. data/spec/rails3_mongoid/public/javascripts/rails.js +175 -0
  90. data/spec/rails3_mongoid/public/robots.txt +5 -0
  91. data/spec/rails3_mongoid/public/stylesheets/.gitkeep +0 -0
  92. data/spec/rails3_mongoid/script/rails +6 -0
  93. data/spec/rails3_mongoid/spec/spec.opts +2 -0
  94. data/spec/rails3_mongoid/spec/spec_helper.orig.rb +27 -0
  95. data/spec/rails3_mongoid/spec/spec_helper.rb +55 -0
  96. data/spec/rails3_mongoid/spec/user_activation_spec.rb +178 -0
  97. data/spec/rails3_mongoid/spec/user_activity_logging_spec.rb +31 -0
  98. data/spec/rails3_mongoid/spec/user_brute_force_protection_spec.rb +41 -0
  99. data/spec/rails3_mongoid/spec/user_oauth_spec.rb +34 -0
  100. data/spec/rails3_mongoid/spec/user_remember_me_spec.rb +51 -0
  101. data/spec/rails3_mongoid/spec/user_reset_password_spec.rb +174 -0
  102. data/spec/rails3_mongoid/spec/user_spec.rb +329 -0
  103. data/spec/rails3_mongoid/vendor/plugins/.gitkeep +0 -0
  104. data/spec/sinatra/Gemfile +1 -1
  105. data/spec/sinatra/Gemfile.lock +6 -6
  106. data/spec/sinatra/spec/controller_session_timeout_spec.rb +23 -22
  107. data/spec/sinatra/spec/spec_helper.rb +2 -2
  108. metadata +153 -37
  109. data/spec/untitled folder +0 -18
data/Gemfile CHANGED
@@ -2,13 +2,16 @@ source "http://rubygems.org"
2
2
  # Add dependencies required to use your gem here.
3
3
  # Example:
4
4
  # gem "activesupport", ">= 2.3.5"
5
- gem "rails", ">= 3.0.0"
6
- gem 'json', ">= 1.5.1"
7
5
  gem 'oauth', ">= 0.4.4"
8
6
  gem 'oauth2', ">= 0.1.1"
7
+
9
8
  # Add dependencies to develop your gem here.
10
9
  # Include everything needed to run rake, tests, features, etc.
11
10
  group :development do
11
+ gem "rails", ">= 3.0.0"
12
+ gem 'json', ">= 1.5.1"
13
+ gem "mongoid", "~> 2.0"
14
+ gem "bson_ext", "~> 1.3"
12
15
  gem "rspec", "~> 2.5.0"
13
16
  gem 'rspec-rails', "~> 2.5.0"
14
17
  gem 'ruby-debug19'
data/Gemfile.lock CHANGED
@@ -31,6 +31,8 @@ GEM
31
31
  addressable (2.2.4)
32
32
  archive-tar-minitar (0.5.2)
33
33
  arel (2.0.6)
34
+ bson (1.3.0)
35
+ bson_ext (1.3.0)
34
36
  builder (2.1.2)
35
37
  columnize (0.3.2)
36
38
  diff-lcs (1.1.2)
@@ -55,6 +57,13 @@ GEM
55
57
  mime-types (~> 1.16)
56
58
  treetop (~> 1.4.8)
57
59
  mime-types (1.16)
60
+ mongo (1.3.0)
61
+ bson (>= 1.3.0)
62
+ mongoid (2.0.1)
63
+ activemodel (~> 3.0)
64
+ mongo (~> 1.3)
65
+ tzinfo (~> 0.3.22)
66
+ will_paginate (~> 3.0.pre)
58
67
  multi_json (0.0.5)
59
68
  multipart-post (1.1.0)
60
69
  oauth (0.4.4)
@@ -113,15 +122,18 @@ GEM
113
122
  treetop (1.4.9)
114
123
  polyglot (>= 0.3.1)
115
124
  tzinfo (0.3.23)
125
+ will_paginate (3.0.pre2)
116
126
  yard (0.6.4)
117
127
 
118
128
  PLATFORMS
119
129
  ruby
120
130
 
121
131
  DEPENDENCIES
132
+ bson_ext (~> 1.3)
122
133
  bundler (~> 1.0.0)
123
134
  jeweler (~> 1.5.2)
124
135
  json (>= 1.5.1)
136
+ mongoid (~> 2.0)
125
137
  oauth (>= 0.4.4)
126
138
  oauth2 (>= 0.1.1)
127
139
  rails (>= 3.0.0)
data/README.rdoc CHANGED
@@ -1,5 +1,6 @@
1
1
  = sorcery
2
2
  Magical Authentication for Rails 3 and Sinatra.
3
+ Supports ActiveRecord and Mongoid.
3
4
 
4
5
  Inspired by restful_authentication, Authlogic and Devise.
5
6
  Crypto code taken almost unchanged from Authlogic.
@@ -15,7 +16,7 @@ It was built with a few goals in mind:
15
16
  * Less is more - less than 20 public methods to remember for the entire feature-set make the lib easy to 'get'.
16
17
  * No built-in or generated code - use the library's methods inside *your own* MVC structures, and don't fight to fix someone else's.
17
18
  * Magic yes, Voodoo no - the lib should be easy to hack for most developers.
18
- * Configuration over Confusion - Simple & short configuration as possible, not drowning in syntactic sugar.
19
+ * Configuration over Confusion - Centralized (1 file), Simple & short configuration as possible, not drowning in syntactic sugar.
19
20
  * Keep MVC cleanly separated - DB is for models, sessions are for controllers. Models stay unaware of sessions.
20
21
 
21
22
  Hopefully, I've achieved this. If not, let me know.
@@ -28,7 +29,7 @@ Example Rails 3 app using sorcery: https://github.com/NoamB/sorcery-example-app
28
29
 
29
30
  Example Sinatra app using sorcery: https://github.com/NoamB/sorcery-example-app-sinatra
30
31
 
31
- Documentation: http://rubydoc.info/gems/sorcery/0.4.1/frames
32
+ Documentation: http://rubydoc.info/gems/sorcery/0.5.0/frames
32
33
 
33
34
  Check out the tutorials in the github wiki!
34
35
 
@@ -66,7 +67,7 @@ Below is a summary of the library methods. Most method names are self explaining
66
67
  # reset password
67
68
  User.load_from_reset_password_token(token)
68
69
  @user.deliver_reset_password_instructions!
69
- @user.reset_password!(params)
70
+ @user.change_password!(new_password)
70
71
 
71
72
  # user activation
72
73
  User.load_from_activation_token(token)
@@ -193,19 +194,23 @@ External (see lib/sorcery/controller/submodules/external.rb):
193
194
  == Next Planned Features:
194
195
 
195
196
 
196
- I've got many plans which include (by priority):
197
+ I've got some thoughts which include (unordered):
198
+ * Passing a block to encrypt, allowing the developer to define his own mix of salting and encrypting
197
199
  * Forgot username, maybe as part of the reset_password module
198
200
  * Scoping logins (to a subdomain or another arbitrary field)
199
- * Mongoid support
201
+ * Allowing storing the salt and crypted password in the same DB field for extra security
200
202
  * Other reset password strategies (security questions?)
201
203
  * Other brute force protection strategies (captcha)
202
- * Have an idea? Let me know, and it might get into the gem!
204
+
205
+
206
+ Have an idea? Let me know, and it might get into the gem!
207
+
203
208
 
204
209
  Other stuff:
205
210
  * Improve specs speed
206
211
  * Provide an easy way to run specs after install
207
212
  * Improve documentation
208
- * Tty to reduce the number of library methods, and find better names to some
213
+ * Try to reduce the number of library methods, and find better names to some
209
214
 
210
215
 
211
216
  == Backward compatibility
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.1
1
+ 0.5.0
@@ -19,7 +19,7 @@ module Sorcery
19
19
  # Increments the failed logins counter on every failed login.
20
20
  # Runs as a hook after a failed login.
21
21
  def update_failed_logins_count!(credentials)
22
- user = Config.user_class.where("#{Config.user_class.sorcery_config.username_attribute_name} = ?", credentials[0]).first
22
+ user = Config.user_class.find_by_credentials(credentials)
23
23
  user.register_failed_login! if user
24
24
  end
25
25
 
@@ -30,11 +30,9 @@ module Sorcery
30
30
  #
31
31
  # gem install bcrypt-ruby
32
32
  #
33
- # Tell activate_sorcery! to use it:
33
+ # Update your initializer to use it:
34
34
  #
35
- # activate_sorcery! do |c|
36
- # c.encryption_algorithm = :bcrypt
37
- # end
35
+ # config.encryption_algorithm = :bcrypt
38
36
  #
39
37
  # You are good to go!
40
38
  class BCrypt
@@ -13,14 +13,14 @@ module Sorcery
13
13
  attr_writer :stretches
14
14
 
15
15
  def encrypt(*tokens)
16
- digest = tokens.flatten.join(join_token)
16
+ digest = tokens.flatten.compact.join(join_token)
17
17
  stretches.times { digest = secure_digest(digest) }
18
18
  digest
19
19
  end
20
20
 
21
21
  # Does the crypted password match the tokens? Uses the same tokens that were used to encrypt.
22
22
  def matches?(crypted, *tokens)
23
- encrypt(*tokens) == crypted
23
+ encrypt(*tokens.compact) == crypted
24
24
  end
25
25
 
26
26
  def reset!
@@ -7,10 +7,6 @@ module Sorcery
7
7
  class Engine < Rails::Engine
8
8
  config.sorcery = ::Sorcery::Controller::Config
9
9
 
10
- initializer "extend Model with sorcery" do |app|
11
- ActiveRecord::Base.send(:include, Sorcery::Model) if defined?(ActiveRecord)
12
- end
13
-
14
10
  initializer "extend Controller with sorcery" do |app|
15
11
  ActionController::Base.send(:include, Sorcery::Controller)
16
12
  ActionController::Base.helper_method :current_user
@@ -9,6 +9,7 @@ Rails.application.config.sorcery.configure do |config|
9
9
  # config.not_authenticated_action = :not_authenticated # what controller action to call for non-authenticated users. You can also override 'not_authenticated' instead.
10
10
  # config.save_return_to_url = true # when a non logged in user tries to enter a page that requires login, save the URL he wanted to reach,
11
11
  # and send him there after login, using 'redirect_back_or_to'.
12
+ # subclasses_inherit_config = false # make this configuration inheritable for subclasses. Useful for ActiveRecord's STI.
12
13
 
13
14
  # -- session timeout --
14
15
  # config.session_timeout = 3600 # how long in seconds to keep the session alive.
@@ -44,6 +45,7 @@ Rails.application.config.sorcery.configure do |config|
44
45
  # user.encryption_key = nil # encryption key used to encrypt reversible encryptions such as AES256.
45
46
  # user.custom_encryption_provider = nil # use an external encryption class.
46
47
  # user.encryption_algorithm = :bcrypt # encryption algorithm name. See 'encryption_algorithm=' for available options.
48
+ # user.subclasses_inherit_config = false # make this configuration inheritable for subclasses. Useful for ActiveRecord's STI.
47
49
 
48
50
  # -- user_activation --
49
51
  # user.activation_state_attribute_name = :activation_state # the attribute name to hold activation state (active/pending).
@@ -0,0 +1,28 @@
1
+ module Sorcery
2
+ module Model
3
+ module Adapters
4
+ module ActiveRecord
5
+ def self.included(klass)
6
+ klass.extend ClassMethods
7
+ end
8
+
9
+ module ClassMethods
10
+ def find_by_credentials(credentials)
11
+ where("#{@sorcery_config.username_attribute_name} = ?", credentials[0]).first
12
+ end
13
+
14
+ def find_by_token(token_attr_name, token)
15
+ where("#{token_attr_name} = ?", token).first
16
+ end
17
+
18
+ def get_current_users
19
+ config = sorcery_config
20
+ where("#{config.last_activity_at_attribute_name} IS NOT NULL") \
21
+ .where("#{config.last_logout_at_attribute_name} IS NULL OR #{config.last_activity_at_attribute_name} > #{config.last_logout_at_attribute_name}") \
22
+ .where("#{config.last_activity_at_attribute_name} > ? ", config.activity_timeout.seconds.ago.utc.to_s(:db))
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,59 @@
1
+ module Sorcery
2
+ module Model
3
+ module Adapters
4
+ module Mongoid
5
+ def self.included(klass)
6
+ klass.extend ClassMethods
7
+ klass.send(:include, InstanceMethods)
8
+ end
9
+
10
+ module InstanceMethods
11
+ def increment(attr)
12
+ self.inc(attr,1)
13
+ end
14
+ end
15
+
16
+ module ClassMethods
17
+ def find_by_credentials(credentials)
18
+ where(@sorcery_config.username_attribute_name => credentials[0]).first
19
+ end
20
+
21
+ def find_by_provider_and_uid(provider, uid)
22
+ where(:provider => provider, :uid => uid).first
23
+ end
24
+
25
+ def find_by_id(id)
26
+ find(id)
27
+ end
28
+
29
+ def find_by_activation_token(token)
30
+ where(:activation_token => token).first
31
+ end
32
+
33
+ def find_by_remember_me_token(token)
34
+ where(:remember_me_token => token).first
35
+ end
36
+
37
+ def find_by_username(username)
38
+ where(:username => username).first
39
+ end
40
+
41
+ def transaction(&blk)
42
+ tap(&blk)
43
+ end
44
+
45
+ def find_by_token(token_attr_name, token)
46
+ where(token_attr_name => token).first
47
+ end
48
+
49
+ def get_current_users
50
+ config = sorcery_config
51
+ where(config.last_activity_at_attribute_name.ne => nil) \
52
+ .any_of({config.last_logout_at_attribute_name => nil},{config.last_activity_at_attribute_name.gt => config.last_logout_at_attribute_name}) \
53
+ .and(config.last_activity_at_attribute_name.gt => config.activity_timeout.seconds.ago.utc.to_s(:db)).order_by([:_id,:asc])
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -9,6 +9,7 @@ module Sorcery
9
9
  module ActivityLogging
10
10
  def self.included(base)
11
11
  base.extend(ClassMethods)
12
+
12
13
  base.sorcery_config.class_eval do
13
14
  attr_accessor :last_login_at_attribute_name, # last login attribute name.
14
15
  :last_logout_at_attribute_name, # last logout attribute name.
@@ -23,15 +24,23 @@ module Sorcery
23
24
  :@activity_timeout => 10 * 60)
24
25
  reset!
25
26
  end
27
+
28
+ base.sorcery_config.after_config << :define_activity_logging_mongoid_fields if defined?(Mongoid) and base.ancestors.include?(Mongoid::Document)
26
29
  end
27
30
 
28
31
  module ClassMethods
29
32
  # get all users with last_activity within timeout
30
33
  def current_users
31
34
  config = sorcery_config
32
- where("#{config.last_activity_at_attribute_name} IS NOT NULL") \
33
- .where("#{config.last_logout_at_attribute_name} IS NULL OR #{config.last_activity_at_attribute_name} > #{config.last_logout_at_attribute_name}") \
34
- .where("#{config.last_activity_at_attribute_name} > ? ", config.activity_timeout.seconds.ago.utc.to_s(:db))
35
+ get_current_users
36
+ end
37
+
38
+ protected
39
+
40
+ def define_activity_logging_mongoid_fields
41
+ field sorcery_config.last_login_at_attribute_name, type: DateTime
42
+ field sorcery_config.last_logout_at_attribute_name, type: DateTime
43
+ field sorcery_config.last_activity_at_attribute_name, type: DateTime
35
44
  end
36
45
  end
37
46
  end
@@ -21,13 +21,18 @@ module Sorcery
21
21
  end
22
22
 
23
23
  base.sorcery_config.before_authenticate << :prevent_locked_user_login
24
+ base.sorcery_config.after_config << :define_brute_force_protection_mongoid_fields if defined?(Mongoid) and base.ancestors.include?(Mongoid::Document)
24
25
  base.extend(ClassMethods)
25
26
  base.send(:include, InstanceMethods)
26
27
  end
27
28
 
28
29
  module ClassMethods
29
30
  protected
30
-
31
+
32
+ def define_brute_force_protection_mongoid_fields
33
+ field sorcery_config.failed_logins_count_attribute_name, type: Integer
34
+ field sorcery_config.lock_expires_at_attribute_name, type: DateTime
35
+ end
31
36
  end
32
37
 
33
38
  module InstanceMethods
@@ -32,6 +32,7 @@ module Sorcery
32
32
 
33
33
  base.send(:include, InstanceMethods)
34
34
  base.extend(ClassMethods)
35
+
35
36
  end
36
37
 
37
38
  module ClassMethods
@@ -21,8 +21,22 @@ module Sorcery
21
21
  end
22
22
 
23
23
  base.send(:include, InstanceMethods)
24
+
25
+ base.sorcery_config.after_config << :define_remember_me_mongoid_fields if defined?(Mongoid) and base.ancestors.include?(Mongoid::Document)
26
+
27
+ base.extend(ClassMethods)
28
+ end
29
+
30
+ module ClassMethods
31
+ protected
32
+
33
+ def define_remember_me_mongoid_fields
34
+ field sorcery_config.remember_me_token_attribute_name, type: String
35
+ field sorcery_config.remember_me_token_expires_at_attribute_name, type: DateTime
36
+ end
37
+
24
38
  end
25
-
39
+
26
40
  module InstanceMethods
27
41
  # You shouldn't really use this one yourself - it's called by the controller's 'remember_me!' method.
28
42
  def remember_me!
@@ -34,10 +34,12 @@ module Sorcery
34
34
  end
35
35
 
36
36
  base.sorcery_config.after_config << :validate_mailer_defined
37
-
37
+ base.sorcery_config.after_config << :define_reset_password_mongoid_fields if defined?(Mongoid) and base.ancestors.include?(Mongoid::Document)
38
+
38
39
  base.extend(ClassMethods)
39
40
  base.send(:include, TemporaryToken)
40
41
  base.send(:include, InstanceMethods)
42
+
41
43
  end
42
44
 
43
45
  module ClassMethods
@@ -57,6 +59,11 @@ module Sorcery
57
59
  raise ArgumentError, msg if @sorcery_config.reset_password_mailer == nil
58
60
  end
59
61
 
62
+ def define_reset_password_mongoid_fields
63
+ field sorcery_config.reset_password_token_attribute_name, type: String
64
+ field sorcery_config.reset_password_token_expires_at_attribute_name, type: DateTime
65
+ field sorcery_config.reset_password_email_sent_at_attribute_name, type: DateTime
66
+ end
60
67
  end
61
68
 
62
69
  module InstanceMethods
@@ -75,9 +82,9 @@ module Sorcery
75
82
  end
76
83
 
77
84
  # Clears token and tries to update the new password for the user.
78
- def reset_password!(params)
85
+ def change_password!(new_password)
79
86
  clear_reset_password_token
80
- update_attributes(params)
87
+ update_attributes(sorcery_config.password_attribute_name => new_password)
81
88
  end
82
89
 
83
90
  protected
@@ -38,12 +38,14 @@ module Sorcery
38
38
  end
39
39
 
40
40
  base.sorcery_config.after_config << :validate_mailer_defined
41
-
41
+ base.sorcery_config.after_config << :define_user_activation_mongoid_fields if defined?(Mongoid) and base.ancestors.include?(Mongoid::Document)
42
42
  base.sorcery_config.before_authenticate << :prevent_non_active_login
43
43
 
44
44
  base.extend(ClassMethods)
45
45
  base.send(:include, TemporaryToken)
46
46
  base.send(:include, InstanceMethods)
47
+
48
+
47
49
  end
48
50
 
49
51
  module ClassMethods
@@ -62,6 +64,14 @@ module Sorcery
62
64
  msg = "To use user_activation submodule, you must define a mailer (config.user_activation_mailer = YourMailerClass)."
63
65
  raise ArgumentError, msg if @sorcery_config.user_activation_mailer == nil
64
66
  end
67
+
68
+ def define_user_activation_mongoid_fields
69
+ self.class_eval do
70
+ field sorcery_config.activation_state_attribute_name, type: String
71
+ field sorcery_config.activation_token_attribute_name, type: String
72
+ field sorcery_config.activation_token_expires_at_attribute_name, type: DateTime
73
+ end
74
+ end
65
75
  end
66
76
 
67
77
  module InstanceMethods
@@ -10,7 +10,7 @@ module Sorcery
10
10
  module ClassMethods
11
11
  def load_from_token(token, token_attr_name, token_expiration_date_attr)
12
12
  return nil if token.blank?
13
- user = where("#{token_attr_name} = ?", token).first
13
+ user = find_by_token(token_attr_name,token)
14
14
  if !user.blank? && !user.send(token_expiration_date_attr).nil?
15
15
  return Time.now.utc < user.send(token_expiration_date_attr) ? user : nil
16
16
  end
data/lib/sorcery/model.rb CHANGED
@@ -22,19 +22,31 @@ module Sorcery
22
22
  begin
23
23
  include Submodules.const_get(mod.to_s.split("_").map {|p| p.capitalize}.join(""))
24
24
  rescue NameError
25
- # don't stop on a missing submodule.
25
+ # don't stop on a missing submodule. Needed because some submodules are only defined in the controller side.
26
26
  end
27
27
  end
28
28
  end
29
-
29
+
30
+ # This runs the options block set in the initializer on the model class.
30
31
  ::Sorcery::Controller::Config.user_config.tap{|blk| blk.call(@sorcery_config) if blk}
31
-
32
+
33
+ self.class_eval do
34
+ field sorcery_config.username_attribute_name, type: String
35
+ field sorcery_config.password_attribute_name, type: String
36
+ field sorcery_config.email_attribute_name, type: String unless sorcery_config.username_attribute_name == sorcery_config.email_attribute_name
37
+ field sorcery_config.crypted_password_attribute_name, type: String
38
+ field sorcery_config.salt_attribute_name, type: String
39
+ end if defined?(Mongoid) and self.ancestors.include?(Mongoid::Document)
40
+
41
+ # add virtual password accessor and ORM callbacks
32
42
  self.class_eval do
33
43
  attr_accessor @sorcery_config.password_attribute_name
34
44
  attr_protected @sorcery_config.crypted_password_attribute_name, @sorcery_config.salt_attribute_name
35
45
  before_save :encrypt_password, :if => Proc.new { |record| record.send(sorcery_config.password_attribute_name).present? }
36
46
  after_save :clear_virtual_password, :if => Proc.new { |record| record.send(sorcery_config.password_attribute_name).present? }
37
47
  end
48
+
49
+ @sorcery_config.after_config << :add_config_inheritance if @sorcery_config.subclasses_inherit_config
38
50
  @sorcery_config.after_config.each { |c| send(c) }
39
51
  end
40
52
  end
@@ -53,7 +65,7 @@ module Sorcery
53
65
  # returns the user if success, nil otherwise.
54
66
  def authenticate(*credentials)
55
67
  raise ArgumentError, "at least 2 arguments required" if credentials.size < 2
56
- user = where("#{@sorcery_config.username_attribute_name} = ?", credentials[0]).first
68
+ user = find_by_credentials(credentials)
57
69
  _salt = user.send(@sorcery_config.salt_attribute_name) if user && !@sorcery_config.salt_attribute_name.nil? && !@sorcery_config.encryption_provider.nil?
58
70
  user if user && @sorcery_config.before_authenticate.all? {|c| user.send(c)} && credentials_match?(user.send(@sorcery_config.crypted_password_attribute_name),credentials[1],_salt)
59
71
  end
@@ -76,6 +88,20 @@ module Sorcery
76
88
  @sorcery_config.encryption_provider.matches?(crypted, *tokens)
77
89
  end
78
90
 
91
+ def add_config_inheritance
92
+ self.class_eval do
93
+ def self.inherited(subclass)
94
+ subclass.class_eval do
95
+ class << self
96
+ attr_accessor :sorcery_config
97
+ end
98
+ end
99
+ subclass.sorcery_config = sorcery_config
100
+ super
101
+ end
102
+ end
103
+ end
104
+
79
105
  end
80
106
 
81
107
  module InstanceMethods
@@ -93,7 +119,7 @@ module Sorcery
93
119
  protected
94
120
 
95
121
  # creates new salt and saves it.
96
- # encrypts password with salt and save it.
122
+ # encrypts password with salt and saves it.
97
123
  def encrypt_password
98
124
  config = sorcery_config
99
125
  new_salt = self.send(:"#{config.salt_attribute_name}=", generate_random_token) if !config.salt_attribute_name.nil?
@@ -117,7 +143,7 @@ module Sorcery
117
143
 
118
144
  # Random code, used for salt and temporary tokens.
119
145
  def generate_random_token
120
- return Digest::SHA1.hexdigest( Time.now.to_s.split(//).sort_by {rand}.join )
146
+ Digest::SHA1.hexdigest( Time.now.to_s.split(//).sort_by {rand}.join )
121
147
  end
122
148
  end
123
149
 
@@ -133,6 +159,7 @@ module Sorcery
133
159
  :salt_attribute_name, # change default salt attribute.
134
160
  :stretches, # how many times to apply encryption to the password.
135
161
  :encryption_key, # encryption key used to encrypt reversible encryptions such as AES256.
162
+ :subclasses_inherit_config, # make this configuration inheritable for subclasses. Useful for ActiveRecord's STI.
136
163
 
137
164
  :submodules, # configured in config/application.rb
138
165
  :before_authenticate, # an array of method names to call before authentication completes. used internally.
@@ -156,6 +183,7 @@ module Sorcery
156
183
  :@salt_join_token => "",
157
184
  :@salt_attribute_name => :salt,
158
185
  :@stretches => nil,
186
+ :@subclasses_inherit_config => false,
159
187
  :@before_authenticate => [],
160
188
  :@after_config => []
161
189
  }
@@ -1,4 +1,3 @@
1
- ActiveRecord::Base.send(:include, Sorcery::Model) if defined?(ActiveRecord)
2
1
  if defined?(Sinatra::Base)
3
2
  Sinatra::Base.send(:include, Sorcery::Controller::Adapters::Sinatra)
4
3
  Sinatra::Base.send(:include, Sorcery::Controller)
@@ -0,0 +1,52 @@
1
+ module Sorcery
2
+ module TestHelpers
3
+ module Internal
4
+ module Rails
5
+ include ::Sorcery::TestHelpers::Rails
6
+
7
+ SUBMODUELS_AUTO_ADDED_CONTROLLER_FILTERS = [:register_last_activity_time_to_db, :deny_banned_user, :validate_session]
8
+
9
+ def sorcery_reload!(submodules = [], options = {})
10
+ reload_user_class
11
+
12
+ # return to no-module configuration
13
+ ::Sorcery::Controller::Config.init!
14
+ ::Sorcery::Controller::Config.reset!
15
+
16
+ # remove all plugin before_filters so they won't fail other tests.
17
+ # I don't like this way, but I didn't find another.
18
+ # hopefully it won't break until Rails 4.
19
+ ApplicationController._process_action_callbacks.delete_if {|c| SUBMODUELS_AUTO_ADDED_CONTROLLER_FILTERS.include?(c.filter) }
20
+
21
+ # configure
22
+ ::Sorcery::Controller::Config.submodules = submodules
23
+ ::Sorcery::Controller::Config.user_class = nil
24
+ ActionController::Base.send(:include,::Sorcery::Controller)
25
+
26
+ ::Sorcery::Controller::Config.user_config do |user|
27
+ options.each do |property,value|
28
+ user.send(:"#{property}=", value)
29
+ end
30
+ end
31
+ User.authenticates_with_sorcery!
32
+ end
33
+
34
+ def sorcery_controller_property_set(property, value)
35
+ ::Sorcery::Controller::Config.send(:"#{property}=", value)
36
+ end
37
+
38
+ def sorcery_controller_external_property_set(provider, property, value)
39
+ ::Sorcery::Controller::Config.send(provider).send(:"#{property}=", value)
40
+ end
41
+
42
+ # This helper is used to fake multiple users signing in in tests.
43
+ # It does so by clearing @current_user, thus allowing a new user to login,
44
+ # all this without calling the :logout action explicitly.
45
+ # A dirty dirty hack.
46
+ def clear_user_without_logout
47
+ subject.instance_variable_set(:@current_user,nil)
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end