sorcery 0.1.4 → 0.2.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.

Potentially problematic release.


This version of sorcery might be problematic. Click here for more details.

Files changed (65) hide show
  1. data/Gemfile +4 -2
  2. data/Gemfile.lock +16 -13
  3. data/README.rdoc +28 -27
  4. data/Rakefile +5 -0
  5. data/VERSION +1 -1
  6. data/lib/sorcery.rb +12 -0
  7. data/lib/sorcery/controller.rb +29 -17
  8. data/lib/sorcery/controller/submodules/activity_logging.rb +20 -7
  9. data/lib/sorcery/controller/submodules/brute_force_protection.rb +9 -2
  10. data/lib/sorcery/controller/submodules/http_basic_auth.rb +8 -3
  11. data/lib/sorcery/controller/submodules/oauth.rb +95 -0
  12. data/lib/sorcery/controller/submodules/oauth/oauth1.rb +25 -0
  13. data/lib/sorcery/controller/submodules/oauth/oauth2.rb +23 -0
  14. data/lib/sorcery/controller/submodules/oauth/providers/facebook.rb +64 -0
  15. data/lib/sorcery/controller/submodules/oauth/providers/twitter.rb +61 -0
  16. data/lib/sorcery/controller/submodules/remember_me.rb +14 -5
  17. data/lib/sorcery/controller/submodules/session_timeout.rb +6 -1
  18. data/lib/sorcery/engine.rb +9 -2
  19. data/lib/sorcery/model.rb +10 -3
  20. data/lib/sorcery/model/submodules/activity_logging.rb +12 -7
  21. data/lib/sorcery/model/submodules/brute_force_protection.rb +11 -4
  22. data/lib/sorcery/model/submodules/oauth.rb +53 -0
  23. data/lib/sorcery/model/submodules/remember_me.rb +5 -3
  24. data/lib/sorcery/model/submodules/reset_password.rb +16 -13
  25. data/lib/sorcery/model/submodules/user_activation.rb +38 -19
  26. data/lib/sorcery/model/temporary_token.rb +22 -0
  27. data/lib/sorcery/test_helpers.rb +84 -0
  28. data/sorcery.gemspec +69 -40
  29. data/spec/Gemfile +3 -2
  30. data/spec/Gemfile.lock +15 -2
  31. data/spec/rails3/app_root/.rspec +1 -0
  32. data/spec/rails3/{Gemfile → app_root/Gemfile} +5 -3
  33. data/spec/rails3/{Gemfile.lock → app_root/Gemfile.lock} +25 -2
  34. data/spec/rails3/{Rakefile → app_root/Rakefile} +0 -0
  35. data/spec/rails3/app_root/app/controllers/application_controller.rb +42 -1
  36. data/spec/rails3/app_root/app/models/authentication.rb +3 -0
  37. data/spec/rails3/app_root/app/models/user.rb +4 -1
  38. data/spec/rails3/app_root/config/application.rb +1 -3
  39. data/spec/rails3/app_root/config/routes.rb +1 -10
  40. data/spec/rails3/app_root/db/migrate/activation/20101224223622_add_activation_to_users.rb +6 -4
  41. data/spec/rails3/app_root/db/migrate/core/20101224223620_create_users.rb +4 -4
  42. data/spec/rails3/app_root/db/migrate/oauth/20101224223628_create_authentications.rb +14 -0
  43. data/spec/rails3/{controller_activity_logging_spec.rb → app_root/spec/controller_activity_logging_spec.rb} +13 -13
  44. data/spec/rails3/{controller_brute_force_protection_spec.rb → app_root/spec/controller_brute_force_protection_spec.rb} +16 -6
  45. data/spec/rails3/{controller_http_basic_auth_spec.rb → app_root/spec/controller_http_basic_auth_spec.rb} +3 -3
  46. data/spec/rails3/app_root/spec/controller_oauth2_spec.rb +117 -0
  47. data/spec/rails3/app_root/spec/controller_oauth_spec.rb +117 -0
  48. data/spec/rails3/{controller_remember_me_spec.rb → app_root/spec/controller_remember_me_spec.rb} +4 -4
  49. data/spec/rails3/{controller_session_timeout_spec.rb → app_root/spec/controller_session_timeout_spec.rb} +4 -4
  50. data/spec/rails3/{controller_spec.rb → app_root/spec/controller_spec.rb} +20 -13
  51. data/spec/rails3/app_root/spec/spec_helper.orig.rb +27 -0
  52. data/spec/rails3/app_root/spec/spec_helper.rb +61 -0
  53. data/spec/rails3/{user_activation_spec.rb → app_root/spec/user_activation_spec.rb} +60 -20
  54. data/spec/rails3/{user_activity_logging_spec.rb → app_root/spec/user_activity_logging_spec.rb} +4 -4
  55. data/spec/rails3/{user_brute_force_protection_spec.rb → app_root/spec/user_brute_force_protection_spec.rb} +7 -7
  56. data/spec/rails3/app_root/spec/user_oauth_spec.rb +39 -0
  57. data/spec/rails3/{user_remember_me_spec.rb → app_root/spec/user_remember_me_spec.rb} +4 -4
  58. data/spec/rails3/{user_reset_password_spec.rb → app_root/spec/user_reset_password_spec.rb} +21 -41
  59. data/spec/rails3/{user_spec.rb → app_root/spec/user_spec.rb} +68 -38
  60. metadata +127 -58
  61. data/spec/rails3/app_root/test/fixtures/users.yml +0 -9
  62. data/spec/rails3/app_root/test/performance/browsing_test.rb +0 -9
  63. data/spec/rails3/app_root/test/test_helper.rb +0 -13
  64. data/spec/rails3/app_root/test/unit/user_test.rb +0 -8
  65. data/spec/rails3/spec_helper.rb +0 -135
@@ -1,20 +1,25 @@
1
1
  module Sorcery
2
2
  module Model
3
3
  module Submodules
4
+ # This submodule keeps track of events such as login, logout, and last activity time, per user.
5
+ # It helps in estimating which users are active now in the site.
6
+ # This cannot be determined absolutely because a user might be reading a page without clicking anything for a while.
7
+
8
+ # This is the model part of the submodule, which provides configuration options.
4
9
  module ActivityLogging
5
10
  def self.included(base)
6
11
  base.extend(ClassMethods)
7
12
  base.sorcery_config.class_eval do
8
- attr_accessor :last_login_at_attribute_name, # last login attribute name.
9
- :last_logout_at_attribute_name, # last logout attribute name.
10
- :last_activity_at_attribute_name, # last activity attribute name.
13
+ attr_accessor :last_login_at_attribute_name, # last login attribute name.
14
+ :last_logout_at_attribute_name, # last logout attribute name.
15
+ :last_activity_at_attribute_name, # last activity attribute name.
11
16
  :activity_timeout # how long since last activity is the user defined logged out?
12
17
  end
13
18
 
14
19
  base.sorcery_config.instance_eval do
15
- @defaults.merge!(:@last_login_at_attribute_name => :last_login_at,
16
- :@last_logout_at_attribute_name => :last_logout_at,
17
- :@last_activity_at_attribute_name => :last_activity_at,
20
+ @defaults.merge!(:@last_login_at_attribute_name => :last_login_at,
21
+ :@last_logout_at_attribute_name => :last_logout_at,
22
+ :@last_activity_at_attribute_name => :last_activity_at,
18
23
  :@activity_timeout => 10.minutes)
19
24
  reset!
20
25
  end
@@ -22,7 +27,7 @@ module Sorcery
22
27
 
23
28
  module ClassMethods
24
29
  # get all users with last_activity within timeout
25
- def logged_in_users
30
+ def current_users
26
31
  config = sorcery_config
27
32
  where("#{config.last_activity_at_attribute_name} IS NOT NULL") \
28
33
  .where("#{config.last_logout_at_attribute_name} IS NULL OR #{config.last_activity_at_attribute_name} > #{config.last_logout_at_attribute_name}") \
@@ -1,19 +1,21 @@
1
1
  module Sorcery
2
2
  module Model
3
3
  module Submodules
4
+ # This module helps protect user accounts by locking them down after too many failed attemps to login were detected.
5
+ # This is the model part of the submodule which provides configuration options and methods for locking and unlocking the user.
4
6
  module BruteForceProtection
5
7
  def self.included(base)
6
8
  base.sorcery_config.class_eval do
7
9
  attr_accessor :failed_logins_count_attribute_name, # failed logins attribute name.
8
10
  :lock_expires_at_attribute_name, # this field indicates whether user is banned and when it will be active again.
9
- :consecutive_login_retries_amount_allowed, # how many failed logins allowed.
11
+ :consecutive_login_retries_amount_limit, # how many failed logins allowed.
10
12
  :login_lock_time_period # how long the user should be banned. in seconds. 0 for permanent.
11
13
  end
12
14
 
13
15
  base.sorcery_config.instance_eval do
14
16
  @defaults.merge!(:@failed_logins_count_attribute_name => :failed_logins_count,
15
17
  :@lock_expires_at_attribute_name => :lock_expires_at,
16
- :@consecutive_login_retries_amount_allowed => 50,
18
+ :@consecutive_login_retries_amount_limit => 50,
17
19
  :@login_lock_time_period => 3600)
18
20
  reset!
19
21
  end
@@ -33,11 +35,14 @@ module Sorcery
33
35
  end
34
36
 
35
37
  module InstanceMethods
38
+ # Called by the controller to increment the failed logins counter.
39
+ # Calls 'lock!' if login retries limit was reached.
36
40
  def register_failed_login!
37
41
  config = sorcery_config
42
+ return if !unlocked?
38
43
  self.increment(config.failed_logins_count_attribute_name)
39
44
  save!
40
- self.lock! if self.send(config.failed_logins_count_attribute_name) >= config.consecutive_login_retries_amount_allowed
45
+ self.lock! if self.send(config.failed_logins_count_attribute_name) >= config.consecutive_login_retries_amount_limit
41
46
  end
42
47
 
43
48
  protected
@@ -58,9 +63,11 @@ module Sorcery
58
63
  self.send(config.lock_expires_at_attribute_name).nil?
59
64
  end
60
65
 
66
+ # Prevents a locked user from logging in, and unlocks users that expired their lock time.
67
+ # Runs as a hook before authenticate.
61
68
  def prevent_locked_user_login
62
69
  config = sorcery_config
63
- if !self.unlocked?
70
+ if !self.unlocked? && config.login_lock_time_period != 0
64
71
  self.unlock! if self.send(config.lock_expires_at_attribute_name) <= Time.now.utc
65
72
  end
66
73
  unlocked?
@@ -0,0 +1,53 @@
1
+ module Sorcery
2
+ module Model
3
+ module Submodules
4
+ # This submodule helps you login users from OAuth providers such as Twitter.
5
+ # This is the model part which handles finding the user using access tokens.
6
+ # For the controller options see Sorcery::Controller::Oauth.
7
+ #
8
+ # Socery assumes (read: requires) you will create external users in the same table where you keep your regular users,
9
+ # but that you will have a separate table for keeping their external authentication data,
10
+ # and that that separate table has a few rows for each user, facebook and twitter for example (a one-to-many relationship).
11
+ #
12
+ # External users will have a null crypted_password field, since we do not hold their password.
13
+ # They will not be sent activation emails on creation.
14
+ module Oauth
15
+ def self.included(base)
16
+ base.sorcery_config.class_eval do
17
+ attr_accessor :authentications_class,
18
+ :authentications_user_id_attribute_name,
19
+ :provider_attribute_name,
20
+ :provider_uid_attribute_name
21
+
22
+ end
23
+
24
+ base.sorcery_config.instance_eval do
25
+ @defaults.merge!(:@authentications_class => Sorcery::Controller::Config.authentications_class,
26
+ :@authentications_user_id_attribute_name => :user_id,
27
+ :@provider_attribute_name => :provider,
28
+ :@provider_uid_attribute_name => :uid)
29
+
30
+ reset!
31
+ end
32
+
33
+ base.send(:include, InstanceMethods)
34
+ base.extend(ClassMethods)
35
+ end
36
+
37
+ module ClassMethods
38
+ # takes a provider and uid and finds a user by them.
39
+ def load_from_provider(provider,uid)
40
+ config = sorcery_config
41
+ authentication = config.authentications_class.find_by_provider_and_uid(provider, uid)
42
+ user = find(authentication.send(config.authentications_user_id_attribute_name)) if authentication
43
+ end
44
+ end
45
+
46
+ module InstanceMethods
47
+
48
+ end
49
+
50
+ end
51
+ end
52
+ end
53
+ end
@@ -1,6 +1,8 @@
1
1
  module Sorcery
2
2
  module Model
3
3
  module Submodules
4
+ # The Remember Me submodule takes care of setting the user's cookie so that he will be automatically logged in to the site on every visit,
5
+ # until the cookie expires.
4
6
  module RememberMe
5
7
  def self.included(base)
6
8
  base.sorcery_config.class_eval do
@@ -22,15 +24,15 @@ module Sorcery
22
24
  end
23
25
 
24
26
  module InstanceMethods
25
- # You shouldn't really use this one - it's called by the controller's 'remember_me!' method.
27
+ # You shouldn't really use this one yourself - it's called by the controller's 'remember_me!' method.
26
28
  def remember_me!
27
29
  config = sorcery_config
28
- self.send(:"#{config.remember_me_token_attribute_name}=", generate_random_code)
30
+ self.send(:"#{config.remember_me_token_attribute_name}=", generate_random_token)
29
31
  self.send(:"#{config.remember_me_token_expires_at_attribute_name}=", Time.now + config.remember_me_for)
30
32
  self.save!(:validate => false)
31
33
  end
32
34
 
33
- # You shouldn't really use this one - it's called by the controller's 'forget_me!' method.
35
+ # You shouldn't really use this one yourself - it's called by the controller's 'forget_me!' method.
34
36
  def forget_me!
35
37
  config = sorcery_config
36
38
  self.send(:"#{config.remember_me_token_attribute_name}=", nil)
@@ -2,6 +2,12 @@ module Sorcery
2
2
  module Model
3
3
  module Submodules
4
4
  # This submodule adds the ability to reset password via email confirmation.
5
+ # When the user requests an email is sent to him with a url.
6
+ # The url includes a token, which is also saved with the user's record in the db.
7
+ # The token has configurable expiration.
8
+ # When the user clicks the url in the email, providing the token has not yet expired, he will be able to reset his password via a form.
9
+ #
10
+ # When using this submodule, supplying a mailer is mandatory.
5
11
  module ResetPassword
6
12
  def self.included(base)
7
13
  base.sorcery_config.class_eval do
@@ -30,22 +36,22 @@ module Sorcery
30
36
  base.sorcery_config.after_config << :validate_mailer_defined
31
37
 
32
38
  base.extend(ClassMethods)
39
+ base.send(:include, TemporaryToken)
33
40
  base.send(:include, InstanceMethods)
34
41
  end
35
42
 
36
43
  module ClassMethods
37
-
44
+ # Find user by token, also checks for expiration.
45
+ # Returns the user if token found and is valid.
38
46
  def load_from_reset_password_token(token)
39
- return nil if token.blank?
40
- user = where("#{@sorcery_config.reset_password_token_attribute_name} = ?", token).first
41
- if !user.blank? && !@sorcery_config.reset_password_expiration_period.nil?
42
- return user.reset_password_token_valid? ? user : nil
43
- end
44
- user
47
+ token_attr_name = @sorcery_config.reset_password_token_attribute_name
48
+ token_expiration_date_attr = @sorcery_config.reset_password_token_expires_at_attribute_name
49
+ load_from_token(token, token_attr_name, token_expiration_date_attr)
45
50
  end
46
51
 
47
52
  protected
48
53
 
54
+ # This submodule requires the developer to define his own mailer class to be used by it.
49
55
  def validate_mailer_defined
50
56
  msg = "To use reset_password submodule, you must define a mailer (config.reset_password_mailer = YourMailerClass)."
51
57
  raise ArgumentError, msg if @sorcery_config.reset_password_mailer == nil
@@ -59,7 +65,7 @@ module Sorcery
59
65
  config = sorcery_config
60
66
  # hammering protection
61
67
  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
62
- self.send(:"#{config.reset_password_token_attribute_name}=", generate_random_code)
68
+ self.send(:"#{config.reset_password_token_attribute_name}=", generate_random_token)
63
69
  self.send(:"#{config.reset_password_token_expires_at_attribute_name}=", Time.now.utc + config.reset_password_expiration_period) if config.reset_password_expiration_period
64
70
  self.send(:"#{config.reset_password_email_sent_at_attribute_name}=", Time.now.utc)
65
71
  self.class.transaction do
@@ -68,18 +74,15 @@ module Sorcery
68
74
  end
69
75
  end
70
76
 
77
+ # Clears token and tries to update the new password for the user.
71
78
  def reset_password!(params)
72
79
  clear_reset_password_token
73
80
  update_attributes(params)
74
81
  end
75
-
76
- def reset_password_token_valid?
77
- config = sorcery_config
78
- config.reset_password_expiration_period ? Time.now.utc < self.send(config.reset_password_token_expires_at_attribute_name) : true
79
- end
80
82
 
81
83
  protected
82
84
 
85
+ # Clears the token.
83
86
  def clear_reset_password_token
84
87
  config = sorcery_config
85
88
  self.send(:"#{config.reset_password_token_attribute_name}=", nil)
@@ -8,27 +8,33 @@ module Sorcery
8
8
  module UserActivation
9
9
  def self.included(base)
10
10
  base.sorcery_config.class_eval do
11
- attr_accessor :activation_state_attribute_name, # the attribute name to hold activation state (active/pending).
12
- :activation_code_attribute_name, # the attribute name to hold activation code (sent by email).
13
- :user_activation_mailer, # your mailer class. Needed.
14
- :activation_needed_email_method_name, # activation needed email method on your mailer class.
15
- :activation_success_email_method_name, # activation success email method on your mailer class.
16
- :prevent_non_active_users_to_login # do you want to prevent or allow users that did not activate by email to login?
11
+ attr_accessor :activation_state_attribute_name, # the attribute name to hold activation state (active/pending).
12
+ :activation_token_attribute_name, # the attribute name to hold activation code (sent by email).
13
+ :activation_token_expires_at_attribute_name, # the attribute name to hold activation code expiration date.
14
+ :activation_token_expiration_period, # how many seconds before the activation code expires. nil for never expires.
15
+ :user_activation_mailer, # your mailer class. Required.
16
+ :activation_needed_email_method_name, # activation needed email method on your mailer class.
17
+ :activation_success_email_method_name, # activation success email method on your mailer class.
18
+ :prevent_non_active_users_to_login # do you want to prevent or allow users that did not activate by email to login?
17
19
  end
18
20
 
19
21
  base.sorcery_config.instance_eval do
20
- @defaults.merge!(:@activation_state_attribute_name => :activation_state,
21
- :@activation_code_attribute_name => :activation_code,
22
- :@user_activation_mailer => nil,
23
- :@activation_needed_email_method_name => :activation_needed_email,
24
- :@activation_success_email_method_name => :activation_success_email,
25
- :@prevent_non_active_users_to_login => true)
22
+ @defaults.merge!(:@activation_state_attribute_name => :activation_state,
23
+ :@activation_token_attribute_name => :activation_token,
24
+ :@activation_token_expires_at_attribute_name => :activation_token_expires_at,
25
+ :@activation_token_expiration_period => nil,
26
+ :@user_activation_mailer => nil,
27
+ :@activation_needed_email_method_name => :activation_needed_email,
28
+ :@activation_success_email_method_name => :activation_success_email,
29
+ :@prevent_non_active_users_to_login => true)
26
30
  reset!
27
31
  end
28
32
 
29
33
  base.class_eval do
30
- before_create :setup_activation
31
- after_create :send_activation_needed_email!
34
+ # don't setup activation if no password supplied - this user is created automatically
35
+ before_create :setup_activation, :if => Proc.new { |user| user.send(sorcery_config.password_attribute_name).present? }
36
+ # don't send activation needed email if no crypted password created - this user is external (OAuth etc.)
37
+ after_create :send_activation_needed_email!, :if => Proc.new { |user| !user.external?}
32
38
  end
33
39
 
34
40
  base.sorcery_config.after_config << :validate_mailer_defined
@@ -36,12 +42,22 @@ module Sorcery
36
42
  base.sorcery_config.before_authenticate << :prevent_non_active_login
37
43
 
38
44
  base.extend(ClassMethods)
45
+ base.send(:include, TemporaryToken)
39
46
  base.send(:include, InstanceMethods)
40
47
  end
41
48
 
42
49
  module ClassMethods
50
+ # Find user by token, also checks for expiration.
51
+ # Returns the user if token found and is valid.
52
+ def load_from_activation_token(token)
53
+ token_attr_name = @sorcery_config.activation_token_attribute_name
54
+ token_expiration_date_attr = @sorcery_config.activation_token_expires_at_attribute_name
55
+ load_from_token(token, token_attr_name, token_expiration_date_attr)
56
+ end
57
+
43
58
  protected
44
59
 
60
+ # This submodule requires the developer to define his own mailer class to be used by it.
45
61
  def validate_mailer_defined
46
62
  msg = "To use user_activation submodule, you must define a mailer (config.user_activation_mailer = YourMailerClass)."
47
63
  raise ArgumentError, msg if @sorcery_config.user_activation_mailer == nil
@@ -49,23 +65,26 @@ module Sorcery
49
65
  end
50
66
 
51
67
  module InstanceMethods
68
+ # clears activation code, sets the user as 'active' and optionaly sends a success email.
52
69
  def activate!
53
70
  config = sorcery_config
54
- self.send(:"#{config.activation_code_attribute_name}=", nil)
71
+ self.send(:"#{config.activation_token_attribute_name}=", nil)
55
72
  self.send(:"#{config.activation_state_attribute_name}=", "active")
56
- send_activation_success_email!
73
+ send_activation_success_email! unless self.external?
57
74
  save!(:validate => false) # don't run validations
58
75
  end
59
-
76
+
60
77
  protected
61
78
 
62
79
  def setup_activation
63
80
  config = sorcery_config
64
- generated_activation_code = CryptoProviders::SHA1.encrypt( Time.now.to_s.split(//).sort_by {rand}.join )
65
- self.send(:"#{config.activation_code_attribute_name}=", generated_activation_code)
81
+ generated_activation_token = generate_random_token
82
+ self.send(:"#{config.activation_token_attribute_name}=", generated_activation_token)
66
83
  self.send(:"#{config.activation_state_attribute_name}=", "pending")
84
+ self.send(:"#{config.activation_token_expires_at_attribute_name}=", Time.now.utc + config.activation_token_expiration_period) if config.activation_token_expiration_period
67
85
  end
68
86
 
87
+ # called automatically after user initial creation.
69
88
  def send_activation_needed_email!
70
89
  generic_send_email(:activation_needed_email_method_name, :user_activation_mailer) unless sorcery_config.activation_needed_email_method_name.nil?
71
90
  end
@@ -0,0 +1,22 @@
1
+ module Sorcery
2
+ module Model
3
+ # This module encapsulates the logic for temporary token.
4
+ # A temporary token is created to identify a user in scenarios such as reseting password and activating the user by email.
5
+ module TemporaryToken
6
+ def self.included(base)
7
+ base.extend(ClassMethods)
8
+ end
9
+
10
+ module ClassMethods
11
+ def load_from_token(token, token_attr_name, token_expiration_date_attr)
12
+ return nil if token.blank?
13
+ user = where("#{token_attr_name} = ?", token).first
14
+ if !user.blank? && !user.send(token_expiration_date_attr).nil?
15
+ return Time.now.utc < user.send(token_expiration_date_attr) ? user : nil
16
+ end
17
+ user
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,84 @@
1
+ module Sorcery
2
+ module TestHelpers
3
+ SUBMODUELS_AUTO_ADDED_CONTROLLER_FILTERS = [:register_last_activity_time_to_db, :deny_banned_user, :validate_session]
4
+
5
+ def create_new_user(attributes_hash = nil)
6
+ user_attributes_hash = attributes_hash || {:username => 'gizmo', :email => "bla@bla.com", :password => 'secret'}
7
+ @user = User.new(user_attributes_hash)
8
+ @user.save!
9
+ @user
10
+ end
11
+
12
+ def create_new_external_user(provider, attributes_hash = nil)
13
+ user_attributes_hash = attributes_hash || {:username => 'gizmo', :authentications_attributes => [{:provider => provider, :uid => 123}]}
14
+ @user = User.new(user_attributes_hash)
15
+ @user.save!
16
+ @user
17
+ end
18
+
19
+ def login_user(user = nil)
20
+ user ||= @user
21
+ subject.send(:login_user,user)
22
+ subject.send(:after_login!,user,[user.username,'secret'])
23
+ end
24
+
25
+ def logout_user
26
+ subject.send(:logout)
27
+ end
28
+
29
+ def clear_user_without_logout
30
+ subject.instance_variable_set(:@current_user,nil)
31
+ end
32
+
33
+ def sorcery_reload!(submodules = [], options = {})
34
+ reload_user_class
35
+
36
+ # return to no-module configuration
37
+ ::Sorcery::Controller::Config.init!
38
+ ::Sorcery::Controller::Config.reset!
39
+
40
+ # remove all plugin before_filters so they won't fail other tests.
41
+ # I don't like this way, but I didn't find another.
42
+ # hopefully it won't break until Rails 4.
43
+ ApplicationController._process_action_callbacks.delete_if {|c| SUBMODUELS_AUTO_ADDED_CONTROLLER_FILTERS.include?(c.filter) }
44
+
45
+ # configure
46
+ ::Sorcery::Controller::Config.submodules = submodules
47
+ ::Sorcery::Controller::Config.user_class = nil
48
+ ActionController::Base.send(:include,::Sorcery::Controller)
49
+
50
+ User.activate_sorcery! do |config|
51
+ options.each do |property,value|
52
+ config.send(:"#{property}=", value)
53
+ end
54
+ end
55
+ end
56
+
57
+ def sorcery_model_property_set(property, *values)
58
+ User.class_eval do
59
+ sorcery_config.send(:"#{property}=", *values)
60
+ end
61
+ end
62
+
63
+ def sorcery_controller_property_set(property, value)
64
+ ApplicationController.activate_sorcery! do |config|
65
+ config.send(:"#{property}=", value)
66
+ end
67
+ end
68
+
69
+ def sorcery_controller_oauth_property_set(provider, property, value)
70
+ ApplicationController.activate_sorcery! do |config|
71
+ config.send(provider).send(:"#{property}=", value)
72
+ end
73
+ end
74
+
75
+ private
76
+
77
+ # reload user class between specs
78
+ # so it will be possible to test the different submodules in isolation
79
+ def reload_user_class
80
+ Object.send(:remove_const,:User)
81
+ load 'user.rb'
82
+ end
83
+ end
84
+ end