sorcery 0.1.0 → 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.
- data/Gemfile +4 -3
- data/Gemfile.lock +16 -13
- data/LICENSE.txt +1 -1
- data/README.rdoc +77 -63
- data/Rakefile +7 -12
- data/VERSION +1 -1
- data/lib/sorcery/controller/submodules/activity_logging.rb +58 -0
- data/lib/sorcery/controller/submodules/brute_force_protection.rb +15 -69
- data/lib/sorcery/controller/submodules/http_basic_auth.rb +65 -0
- data/lib/sorcery/controller/submodules/oauth/oauth1.rb +25 -0
- data/lib/sorcery/controller/submodules/oauth/oauth2.rb +23 -0
- data/lib/sorcery/controller/submodules/oauth/providers/facebook.rb +64 -0
- data/lib/sorcery/controller/submodules/oauth/providers/twitter.rb +61 -0
- data/lib/sorcery/controller/submodules/oauth.rb +95 -0
- data/lib/sorcery/controller/submodules/remember_me.rb +14 -5
- data/lib/sorcery/controller/submodules/session_timeout.rb +10 -2
- data/lib/sorcery/controller.rb +40 -22
- data/lib/sorcery/crypto_providers/bcrypt.rb +2 -6
- data/lib/sorcery/engine.rb +9 -2
- data/lib/sorcery/model/submodules/activity_logging.rb +40 -0
- data/lib/sorcery/model/submodules/brute_force_protection.rb +79 -0
- data/lib/sorcery/model/submodules/oauth.rb +53 -0
- data/lib/sorcery/model/submodules/remember_me.rb +6 -2
- data/lib/sorcery/model/submodules/reset_password.rb +96 -0
- data/lib/sorcery/model/submodules/user_activation.rb +44 -23
- data/lib/sorcery/model/temporary_token.rb +22 -0
- data/lib/sorcery/model.rb +22 -9
- data/lib/sorcery/test_helpers.rb +84 -0
- data/lib/sorcery.rb +17 -1
- data/sorcery.gemspec +250 -0
- data/spec/Gemfile +3 -2
- data/spec/Gemfile.lock +15 -2
- data/spec/rails3/app_root/.rspec +1 -0
- data/spec/rails3/{Gemfile → app_root/Gemfile} +6 -3
- data/spec/rails3/{Gemfile.lock → app_root/Gemfile.lock} +27 -2
- data/spec/rails3/app_root/app/controllers/application_controller.rb +48 -2
- data/spec/rails3/app_root/app/models/authentication.rb +3 -0
- data/spec/rails3/app_root/app/models/user.rb +4 -1
- data/spec/rails3/app_root/config/application.rb +1 -3
- data/spec/rails3/app_root/config/routes.rb +1 -9
- data/spec/rails3/app_root/db/migrate/activation/20101224223622_add_activation_to_users.rb +6 -4
- data/spec/rails3/app_root/db/migrate/activity_logging/20101224223624_add_activity_logging_to_users.rb +17 -0
- data/spec/rails3/app_root/db/migrate/brute_force_protection/20101224223626_add_brute_force_protection_to_users.rb +11 -0
- data/spec/rails3/app_root/db/migrate/core/20101224223620_create_users.rb +4 -4
- data/spec/rails3/app_root/db/migrate/oauth/20101224223628_create_authentications.rb +14 -0
- data/spec/rails3/app_root/db/migrate/reset_password/20101224223622_add_reset_password_to_users.rb +13 -0
- data/spec/rails3/app_root/spec/controller_activity_logging_spec.rb +84 -0
- data/spec/rails3/app_root/spec/controller_brute_force_protection_spec.rb +65 -0
- data/spec/rails3/app_root/spec/controller_http_basic_auth_spec.rb +50 -0
- data/spec/rails3/app_root/spec/controller_oauth2_spec.rb +117 -0
- data/spec/rails3/app_root/spec/controller_oauth_spec.rb +117 -0
- data/spec/rails3/{controller_remember_me_spec.rb → app_root/spec/controller_remember_me_spec.rb} +4 -4
- data/spec/rails3/{controller_session_timeout_spec.rb → app_root/spec/controller_session_timeout_spec.rb} +5 -4
- data/spec/rails3/{controller_spec.rb → app_root/spec/controller_spec.rb} +23 -16
- data/spec/rails3/app_root/spec/spec_helper.orig.rb +27 -0
- data/spec/rails3/app_root/spec/spec_helper.rb +61 -0
- data/spec/rails3/{user_activation_spec.rb → app_root/spec/user_activation_spec.rb} +62 -22
- data/spec/rails3/app_root/spec/user_activity_logging_spec.rb +36 -0
- data/spec/rails3/app_root/spec/user_brute_force_protection_spec.rb +76 -0
- data/spec/rails3/app_root/spec/user_oauth_spec.rb +39 -0
- data/spec/rails3/{user_remember_me_spec.rb → app_root/spec/user_remember_me_spec.rb} +4 -4
- data/spec/rails3/app_root/spec/user_reset_password_spec.rb +178 -0
- data/spec/rails3/{user_spec.rb → app_root/spec/user_spec.rb} +75 -41
- metadata +147 -102
- data/features/support/env.rb +0 -13
- data/lib/sorcery/model/submodules/password_reset.rb +0 -64
- data/spec/rails3/app_root/db/migrate/password_reset/20101224223622_add_password_reset_to_users.rb +0 -9
- data/spec/rails3/app_root/test/fixtures/users.yml +0 -9
- data/spec/rails3/app_root/test/performance/browsing_test.rb +0 -9
- data/spec/rails3/app_root/test/test_helper.rb +0 -13
- data/spec/rails3/app_root/test/unit/user_test.rb +0 -8
- data/spec/rails3/controller_brute_force_protection_spec.rb +0 -72
- data/spec/rails3/spec_helper.rb +0 -115
- data/spec/rails3/user_password_reset_spec.rb +0 -76
- /data/spec/rails3/{Rakefile → app_root/Rakefile} +0 -0
|
@@ -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,13 +24,15 @@ module Sorcery
|
|
|
22
24
|
end
|
|
23
25
|
|
|
24
26
|
module InstanceMethods
|
|
27
|
+
# You shouldn't really use this one yourself - it's called by the controller's 'remember_me!' method.
|
|
25
28
|
def remember_me!
|
|
26
29
|
config = sorcery_config
|
|
27
|
-
self.send(:"#{config.remember_me_token_attribute_name}=",
|
|
30
|
+
self.send(:"#{config.remember_me_token_attribute_name}=", generate_random_token)
|
|
28
31
|
self.send(:"#{config.remember_me_token_expires_at_attribute_name}=", Time.now + config.remember_me_for)
|
|
29
32
|
self.save!(:validate => false)
|
|
30
33
|
end
|
|
31
|
-
|
|
34
|
+
|
|
35
|
+
# You shouldn't really use this one yourself - it's called by the controller's 'forget_me!' method.
|
|
32
36
|
def forget_me!
|
|
33
37
|
config = sorcery_config
|
|
34
38
|
self.send(:"#{config.remember_me_token_attribute_name}=", nil)
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
module Sorcery
|
|
2
|
+
module Model
|
|
3
|
+
module Submodules
|
|
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.
|
|
11
|
+
module ResetPassword
|
|
12
|
+
def self.included(base)
|
|
13
|
+
base.sorcery_config.class_eval do
|
|
14
|
+
attr_accessor :reset_password_token_attribute_name, # reset password code attribute name.
|
|
15
|
+
:reset_password_token_expires_at_attribute_name, # expires at attribute name.
|
|
16
|
+
:reset_password_email_sent_at_attribute_name, # when was email sent, used for hammering protection.
|
|
17
|
+
:reset_password_mailer, # mailer class. Needed.
|
|
18
|
+
:reset_password_email_method_name, # reset password email method on your mailer class.
|
|
19
|
+
:reset_password_expiration_period, # how many seconds before the reset request expires. nil for never expires.
|
|
20
|
+
:reset_password_time_between_emails # hammering protection, how long to wait before allowing another email to be sent.
|
|
21
|
+
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
base.sorcery_config.instance_eval do
|
|
25
|
+
@defaults.merge!(:@reset_password_token_attribute_name => :reset_password_token,
|
|
26
|
+
:@reset_password_token_expires_at_attribute_name => :reset_password_token_expires_at,
|
|
27
|
+
:@reset_password_email_sent_at_attribute_name => :reset_password_email_sent_at,
|
|
28
|
+
:@reset_password_mailer => nil,
|
|
29
|
+
:@reset_password_email_method_name => :reset_password_email,
|
|
30
|
+
:@reset_password_expiration_period => nil,
|
|
31
|
+
:@reset_password_time_between_emails => 5.minutes )
|
|
32
|
+
|
|
33
|
+
reset!
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
base.sorcery_config.after_config << :validate_mailer_defined
|
|
37
|
+
|
|
38
|
+
base.extend(ClassMethods)
|
|
39
|
+
base.send(:include, TemporaryToken)
|
|
40
|
+
base.send(:include, InstanceMethods)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
module ClassMethods
|
|
44
|
+
# Find user by token, also checks for expiration.
|
|
45
|
+
# Returns the user if token found and is valid.
|
|
46
|
+
def load_from_reset_password_token(token)
|
|
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)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
protected
|
|
53
|
+
|
|
54
|
+
# This submodule requires the developer to define his own mailer class to be used by it.
|
|
55
|
+
def validate_mailer_defined
|
|
56
|
+
msg = "To use reset_password submodule, you must define a mailer (config.reset_password_mailer = YourMailerClass)."
|
|
57
|
+
raise ArgumentError, msg if @sorcery_config.reset_password_mailer == nil
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
module InstanceMethods
|
|
63
|
+
# generates a reset code with expiration and sends an email to the user.
|
|
64
|
+
def deliver_reset_password_instructions!
|
|
65
|
+
config = sorcery_config
|
|
66
|
+
# hammering protection
|
|
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
|
|
68
|
+
self.send(:"#{config.reset_password_token_attribute_name}=", generate_random_token)
|
|
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
|
|
70
|
+
self.send(:"#{config.reset_password_email_sent_at_attribute_name}=", Time.now.utc)
|
|
71
|
+
self.class.transaction do
|
|
72
|
+
self.save!(:validate => false)
|
|
73
|
+
generic_send_email(:reset_password_email_method_name, :reset_password_mailer)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Clears token and tries to update the new password for the user.
|
|
78
|
+
def reset_password!(params)
|
|
79
|
+
clear_reset_password_token
|
|
80
|
+
update_attributes(params)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
protected
|
|
84
|
+
|
|
85
|
+
# Clears the token.
|
|
86
|
+
def clear_reset_password_token
|
|
87
|
+
config = sorcery_config
|
|
88
|
+
self.send(:"#{config.reset_password_token_attribute_name}=", nil)
|
|
89
|
+
self.send(:"#{config.reset_password_token_expires_at_attribute_name}=", nil) if config.reset_password_expiration_period
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
@@ -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,
|
|
12
|
-
:
|
|
13
|
-
:
|
|
14
|
-
:
|
|
15
|
-
:
|
|
16
|
-
:
|
|
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
|
|
21
|
-
:@
|
|
22
|
-
:@
|
|
23
|
-
:@
|
|
24
|
-
:@
|
|
25
|
-
:@
|
|
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
|
-
|
|
31
|
-
|
|
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,40 +42,55 @@ 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
|
+
|
|
58
|
+
protected
|
|
59
|
+
|
|
60
|
+
# This submodule requires the developer to define his own mailer class to be used by it.
|
|
43
61
|
def validate_mailer_defined
|
|
44
|
-
msg = "To use user_activation submodule, you must define a mailer (config.
|
|
45
|
-
raise ArgumentError, msg if @sorcery_config.
|
|
62
|
+
msg = "To use user_activation submodule, you must define a mailer (config.user_activation_mailer = YourMailerClass)."
|
|
63
|
+
raise ArgumentError, msg if @sorcery_config.user_activation_mailer == nil
|
|
46
64
|
end
|
|
47
65
|
end
|
|
48
66
|
|
|
49
67
|
module InstanceMethods
|
|
68
|
+
# clears activation code, sets the user as 'active' and optionaly sends a success email.
|
|
50
69
|
def activate!
|
|
51
70
|
config = sorcery_config
|
|
52
|
-
self.send(:"#{config.
|
|
71
|
+
self.send(:"#{config.activation_token_attribute_name}=", nil)
|
|
53
72
|
self.send(:"#{config.activation_state_attribute_name}=", "active")
|
|
54
|
-
send_activation_success_email!
|
|
73
|
+
send_activation_success_email! unless self.external?
|
|
55
74
|
save!(:validate => false) # don't run validations
|
|
56
75
|
end
|
|
57
|
-
|
|
76
|
+
|
|
58
77
|
protected
|
|
59
78
|
|
|
60
79
|
def setup_activation
|
|
61
80
|
config = sorcery_config
|
|
62
|
-
|
|
63
|
-
self.send(:"#{config.
|
|
81
|
+
generated_activation_token = generate_random_token
|
|
82
|
+
self.send(:"#{config.activation_token_attribute_name}=", generated_activation_token)
|
|
64
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
|
|
65
85
|
end
|
|
66
86
|
|
|
87
|
+
# called automatically after user initial creation.
|
|
67
88
|
def send_activation_needed_email!
|
|
68
|
-
generic_send_email(:activation_needed_email_method_name) unless sorcery_config.activation_needed_email_method_name.nil?
|
|
89
|
+
generic_send_email(:activation_needed_email_method_name, :user_activation_mailer) unless sorcery_config.activation_needed_email_method_name.nil?
|
|
69
90
|
end
|
|
70
91
|
|
|
71
92
|
def send_activation_success_email!
|
|
72
|
-
generic_send_email(:activation_success_email_method_name) unless sorcery_config.activation_success_email_method_name.nil?
|
|
93
|
+
generic_send_email(:activation_success_email_method_name, :user_activation_mailer) unless sorcery_config.activation_success_email_method_name.nil?
|
|
73
94
|
end
|
|
74
95
|
|
|
75
96
|
def prevent_non_active_login
|
|
@@ -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
|
data/lib/sorcery/model.rb
CHANGED
|
@@ -52,10 +52,17 @@ module Sorcery
|
|
|
52
52
|
def authenticate(*credentials)
|
|
53
53
|
raise ArgumentError, "at least 2 arguments required" if credentials.size < 2
|
|
54
54
|
user = where("#{@sorcery_config.username_attribute_name} = ?", credentials[0]).first
|
|
55
|
-
|
|
56
|
-
user if user && @sorcery_config.before_authenticate.all? {|c| user.send(c)} && (user.send(@sorcery_config.crypted_password_attribute_name)
|
|
55
|
+
_salt = user.send(@sorcery_config.salt_attribute_name) if user && !@sorcery_config.salt_attribute_name.nil? && !@sorcery_config.encryption_provider.nil?
|
|
56
|
+
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)
|
|
57
57
|
end
|
|
58
58
|
|
|
59
|
+
# Calls the configured encryption provider to compare the supplied password with the encrypted one.
|
|
60
|
+
def credentials_match?(crypted, *tokens)
|
|
61
|
+
return crypted == tokens.join if @sorcery_config.encryption_provider.nil?
|
|
62
|
+
@sorcery_config.encryption_provider.matches?(crypted, *tokens)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# encrypt tokens using current encryption_provider.
|
|
59
66
|
def encrypt(*tokens)
|
|
60
67
|
return tokens.first if @sorcery_config.encryption_provider.nil?
|
|
61
68
|
|
|
@@ -72,14 +79,20 @@ module Sorcery
|
|
|
72
79
|
self.class.sorcery_config
|
|
73
80
|
end
|
|
74
81
|
|
|
82
|
+
# identifies whether this user is regular, i.e. we hold his credentials in our db,
|
|
83
|
+
# or that he is external, and his credentials are saved elsewhere (twitter/facebook etc.).
|
|
84
|
+
def external?
|
|
85
|
+
send(sorcery_config.crypted_password_attribute_name).nil?
|
|
86
|
+
end
|
|
87
|
+
|
|
75
88
|
protected
|
|
76
89
|
|
|
77
90
|
# creates new salt and saves it.
|
|
78
91
|
# encrypts password with salt and save it.
|
|
79
92
|
def encrypt_password
|
|
80
93
|
config = sorcery_config
|
|
81
|
-
self.send(:"#{config.salt_attribute_name}=",
|
|
82
|
-
self.send(:"#{config.crypted_password_attribute_name}=", self.class.encrypt(self.send(config.password_attribute_name),
|
|
94
|
+
new_salt = self.send(:"#{config.salt_attribute_name}=", generate_random_token) if !config.salt_attribute_name.nil?
|
|
95
|
+
self.send(:"#{config.crypted_password_attribute_name}=", self.class.encrypt(self.send(config.password_attribute_name),new_salt))
|
|
83
96
|
end
|
|
84
97
|
|
|
85
98
|
def clear_virtual_password
|
|
@@ -89,16 +102,16 @@ module Sorcery
|
|
|
89
102
|
|
|
90
103
|
# calls the requested email method on the configured mailer
|
|
91
104
|
# supports both the ActionMailer 3 way of calling, and the plain old Ruby object way.
|
|
92
|
-
def generic_send_email(method)
|
|
105
|
+
def generic_send_email(method, mailer)
|
|
93
106
|
config = sorcery_config
|
|
94
|
-
mail = config.
|
|
95
|
-
if defined?(ActionMailer) and config.
|
|
107
|
+
mail = config.send(mailer).send(config.send(method),self)
|
|
108
|
+
if defined?(ActionMailer) and config.send(mailer).superclass == ActionMailer::Base
|
|
96
109
|
mail.deliver
|
|
97
110
|
end
|
|
98
111
|
end
|
|
99
112
|
|
|
100
113
|
# Random code, used for salt and temporary tokens.
|
|
101
|
-
def
|
|
114
|
+
def generate_random_token
|
|
102
115
|
return Digest::SHA1.hexdigest( Time.now.to_s.split(//).sort_by {rand}.join )
|
|
103
116
|
end
|
|
104
117
|
end
|
|
@@ -131,7 +144,7 @@ module Sorcery
|
|
|
131
144
|
:@password_attribute_name => :password,
|
|
132
145
|
:@email_attribute_name => :email,
|
|
133
146
|
:@crypted_password_attribute_name => :crypted_password,
|
|
134
|
-
:@encryption_algorithm => :
|
|
147
|
+
:@encryption_algorithm => :bcrypt,
|
|
135
148
|
:@encryption_provider => CryptoProviders::BCrypt,
|
|
136
149
|
:@custom_encryption_provider => nil,
|
|
137
150
|
:@encryption_key => nil,
|
|
@@ -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
|
data/lib/sorcery.rb
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
module Sorcery
|
|
2
2
|
autoload :Model, 'sorcery/model'
|
|
3
3
|
module Model
|
|
4
|
+
autoload :TemporaryToken, 'sorcery/model/temporary_token'
|
|
4
5
|
module Submodules
|
|
5
6
|
autoload :UserActivation, 'sorcery/model/submodules/user_activation'
|
|
6
|
-
autoload :
|
|
7
|
+
autoload :ResetPassword, 'sorcery/model/submodules/reset_password'
|
|
7
8
|
autoload :RememberMe, 'sorcery/model/submodules/remember_me'
|
|
9
|
+
autoload :ActivityLogging, 'sorcery/model/submodules/activity_logging'
|
|
10
|
+
autoload :BruteForceProtection, 'sorcery/model/submodules/brute_force_protection'
|
|
11
|
+
autoload :Oauth, 'sorcery/model/submodules/oauth'
|
|
8
12
|
end
|
|
9
13
|
end
|
|
10
14
|
autoload :Controller, 'sorcery/controller'
|
|
@@ -13,6 +17,17 @@ module Sorcery
|
|
|
13
17
|
autoload :RememberMe, 'sorcery/controller/submodules/remember_me'
|
|
14
18
|
autoload :SessionTimeout, 'sorcery/controller/submodules/session_timeout'
|
|
15
19
|
autoload :BruteForceProtection, 'sorcery/controller/submodules/brute_force_protection'
|
|
20
|
+
autoload :HttpBasicAuth, 'sorcery/controller/submodules/http_basic_auth'
|
|
21
|
+
autoload :ActivityLogging, 'sorcery/controller/submodules/activity_logging'
|
|
22
|
+
autoload :Oauth, 'sorcery/controller/submodules/oauth'
|
|
23
|
+
module Oauth
|
|
24
|
+
autoload :Oauth1, 'sorcery/controller/submodules/oauth/oauth1'
|
|
25
|
+
autoload :Oauth2, 'sorcery/controller/submodules/oauth/oauth2'
|
|
26
|
+
module Providers
|
|
27
|
+
autoload :Twitter, 'sorcery/controller/submodules/oauth/providers/twitter'
|
|
28
|
+
autoload :Facebook, 'sorcery/controller/submodules/oauth/providers/facebook'
|
|
29
|
+
end
|
|
30
|
+
end
|
|
16
31
|
end
|
|
17
32
|
end
|
|
18
33
|
module CryptoProviders
|
|
@@ -23,6 +38,7 @@ module Sorcery
|
|
|
23
38
|
autoload :SHA256, 'sorcery/crypto_providers/sha256'
|
|
24
39
|
autoload :SHA512, 'sorcery/crypto_providers/sha512'
|
|
25
40
|
end
|
|
41
|
+
autoload :TestHelpers, 'sorcery/test_helpers'
|
|
26
42
|
|
|
27
43
|
require 'sorcery/engine' if defined?(Rails) && Rails::VERSION::MAJOR == 3
|
|
28
44
|
end
|