sorcery 0.9.1 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of sorcery might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.travis.yml +29 -104
- data/CHANGELOG.md +13 -1
- data/Gemfile +2 -16
- data/README.md +124 -272
- data/Rakefile +2 -2
- data/gemfiles/{mongoid-rails40.gemfile → active_record-rails42.gemfile} +1 -3
- data/lib/generators/sorcery/helpers.rb +4 -4
- data/lib/generators/sorcery/install_generator.rb +25 -19
- data/lib/generators/sorcery/templates/initializer.rb +27 -52
- data/lib/generators/sorcery/templates/migration/activity_logging.rb +2 -2
- data/lib/generators/sorcery/templates/migration/brute_force_protection.rb +1 -1
- data/lib/generators/sorcery/templates/migration/core.rb +3 -3
- data/lib/generators/sorcery/templates/migration/external.rb +2 -2
- data/lib/generators/sorcery/templates/migration/remember_me.rb +2 -2
- data/lib/generators/sorcery/templates/migration/reset_password.rb +2 -2
- data/lib/generators/sorcery/templates/migration/user_activation.rb +2 -2
- data/lib/sorcery.rb +0 -28
- data/lib/sorcery/adapters/active_record_adapter.rb +7 -18
- data/lib/sorcery/controller.rb +19 -21
- data/lib/sorcery/controller/config.rb +20 -18
- data/lib/sorcery/controller/submodules/activity_logging.rb +7 -15
- data/lib/sorcery/controller/submodules/brute_force_protection.rb +1 -2
- data/lib/sorcery/controller/submodules/external.rb +22 -14
- data/lib/sorcery/controller/submodules/http_basic_auth.rb +16 -19
- data/lib/sorcery/controller/submodules/remember_me.rb +15 -10
- data/lib/sorcery/controller/submodules/session_timeout.rb +7 -8
- data/lib/sorcery/crypto_providers/aes256.rb +15 -15
- data/lib/sorcery/crypto_providers/bcrypt.rb +19 -21
- data/lib/sorcery/crypto_providers/common.rb +1 -1
- data/lib/sorcery/crypto_providers/md5.rb +5 -5
- data/lib/sorcery/crypto_providers/sha1.rb +5 -5
- data/lib/sorcery/crypto_providers/sha256.rb +2 -2
- data/lib/sorcery/crypto_providers/sha512.rb +3 -3
- data/lib/sorcery/engine.rb +3 -8
- data/lib/sorcery/model.rb +24 -32
- data/lib/sorcery/model/config.rb +64 -49
- data/lib/sorcery/model/submodules/activity_logging.rb +31 -12
- data/lib/sorcery/model/submodules/brute_force_protection.rb +23 -23
- data/lib/sorcery/model/submodules/external.rb +3 -7
- data/lib/sorcery/model/submodules/remember_me.rb +19 -7
- data/lib/sorcery/model/submodules/reset_password.rb +32 -36
- data/lib/sorcery/model/submodules/user_activation.rb +38 -50
- data/lib/sorcery/model/temporary_token.rb +2 -2
- data/lib/sorcery/protocols/oauth.rb +3 -9
- data/lib/sorcery/protocols/oauth2.rb +0 -2
- data/lib/sorcery/providers/base.rb +4 -4
- data/lib/sorcery/providers/facebook.rb +5 -8
- data/lib/sorcery/providers/github.rb +5 -7
- data/lib/sorcery/providers/google.rb +3 -5
- data/lib/sorcery/providers/heroku.rb +6 -8
- data/lib/sorcery/providers/jira.rb +12 -17
- data/lib/sorcery/providers/linkedin.rb +6 -8
- data/lib/sorcery/providers/liveid.rb +4 -7
- data/lib/sorcery/providers/paypal.rb +60 -0
- data/lib/sorcery/providers/salesforce.rb +3 -5
- data/lib/sorcery/providers/slack.rb +45 -0
- data/lib/sorcery/providers/twitter.rb +4 -6
- data/lib/sorcery/providers/vk.rb +3 -5
- data/lib/sorcery/providers/wechat.rb +79 -0
- data/lib/sorcery/providers/xing.rb +7 -10
- data/lib/sorcery/test_helpers/internal.rb +10 -10
- data/lib/sorcery/test_helpers/internal/rails.rb +16 -8
- data/lib/sorcery/test_helpers/rails/controller.rb +1 -1
- data/lib/sorcery/test_helpers/rails/integration.rb +5 -6
- data/lib/sorcery/version.rb +1 -1
- data/sorcery.gemspec +25 -27
- data/spec/active_record/user_activation_spec.rb +2 -3
- data/spec/active_record/user_activity_logging_spec.rb +2 -4
- data/spec/active_record/user_brute_force_protection_spec.rb +3 -4
- data/spec/active_record/user_oauth_spec.rb +3 -4
- data/spec/active_record/user_remember_me_spec.rb +3 -4
- data/spec/active_record/user_reset_password_spec.rb +2 -3
- data/spec/active_record/user_spec.rb +7 -7
- data/spec/controllers/controller_activity_logging_spec.rb +13 -24
- data/spec/controllers/controller_brute_force_protection_spec.rb +6 -8
- data/spec/controllers/controller_http_basic_auth_spec.rb +19 -20
- data/spec/controllers/controller_oauth2_spec.rb +125 -100
- data/spec/controllers/controller_oauth_spec.rb +86 -66
- data/spec/controllers/controller_remember_me_spec.rb +35 -30
- data/spec/controllers/controller_session_timeout_spec.rb +14 -15
- data/spec/controllers/controller_spec.rb +77 -111
- data/spec/orm/active_record.rb +1 -1
- data/spec/rails_app/app/active_record/authentication.rb +1 -1
- data/spec/rails_app/app/active_record/user.rb +2 -2
- data/spec/rails_app/app/controllers/sorcery_controller.rb +89 -24
- data/spec/rails_app/app/mailers/sorcery_mailer.rb +16 -17
- data/spec/rails_app/config.ru +1 -1
- data/spec/rails_app/config/application.rb +7 -7
- data/spec/rails_app/config/boot.rb +1 -1
- data/spec/rails_app/config/environments/test.rb +1 -1
- data/spec/rails_app/config/initializers/compatible_legacy_migration.rb +11 -0
- data/spec/rails_app/config/initializers/session_store.rb +3 -3
- data/spec/rails_app/config/routes.rb +11 -1
- data/spec/rails_app/db/migrate/activation/20101224223622_add_activation_to_users.rb +4 -4
- data/spec/rails_app/db/migrate/activity_logging/20101224223624_add_activity_logging_to_users.rb +8 -8
- data/spec/rails_app/db/migrate/brute_force_protection/20101224223626_add_brute_force_protection_to_users.rb +5 -5
- data/spec/rails_app/db/migrate/core/20101224223620_create_users.rb +5 -5
- data/spec/rails_app/db/migrate/external/20101224223628_create_authentications_and_user_providers.rb +3 -3
- data/spec/rails_app/db/migrate/remember_me/20101224223623_add_remember_me_token_to_users.rb +6 -6
- data/spec/rails_app/db/migrate/reset_password/20101224223622_add_reset_password_to_users.rb +5 -5
- data/spec/shared_examples/user_activation_shared_examples.rb +99 -58
- data/spec/shared_examples/user_activity_logging_shared_examples.rb +47 -41
- data/spec/shared_examples/user_brute_force_protection_shared_examples.rb +19 -24
- data/spec/shared_examples/user_oauth_shared_examples.rb +7 -10
- data/spec/shared_examples/user_remember_me_shared_examples.rb +90 -21
- data/spec/shared_examples/user_reset_password_shared_examples.rb +52 -54
- data/spec/shared_examples/user_shared_examples.rb +215 -118
- data/spec/sorcery_crypto_providers_spec.rb +63 -76
- data/spec/spec_helper.rb +17 -13
- metadata +28 -83
- data/gemfiles/mongo_mapper-rails40.gemfile +0 -9
- data/gemfiles/mongo_mapper-rails41.gemfile +0 -9
- data/gemfiles/mongoid-rails41.gemfile +0 -9
- data/gemfiles/mongoid3-rails32.gemfile +0 -9
- data/lib/sorcery/adapters/data_mapper_adapter.rb +0 -176
- data/lib/sorcery/adapters/mongo_mapper_adapter.rb +0 -110
- data/lib/sorcery/adapters/mongoid_adapter.rb +0 -97
- data/lib/sorcery/railties/tasks.rake +0 -6
- data/spec/data_mapper/user_activation_spec.rb +0 -10
- data/spec/data_mapper/user_activity_logging_spec.rb +0 -14
- data/spec/data_mapper/user_brute_force_protection_spec.rb +0 -9
- data/spec/data_mapper/user_oauth_spec.rb +0 -9
- data/spec/data_mapper/user_remember_me_spec.rb +0 -8
- data/spec/data_mapper/user_reset_password_spec.rb +0 -8
- data/spec/data_mapper/user_spec.rb +0 -27
- data/spec/mongo_mapper/user_activation_spec.rb +0 -9
- data/spec/mongo_mapper/user_activity_logging_spec.rb +0 -8
- data/spec/mongo_mapper/user_brute_force_protection_spec.rb +0 -8
- data/spec/mongo_mapper/user_oauth_spec.rb +0 -8
- data/spec/mongo_mapper/user_remember_me_spec.rb +0 -8
- data/spec/mongo_mapper/user_reset_password_spec.rb +0 -8
- data/spec/mongo_mapper/user_spec.rb +0 -37
- data/spec/mongoid/user_activation_spec.rb +0 -9
- data/spec/mongoid/user_activity_logging_spec.rb +0 -8
- data/spec/mongoid/user_brute_force_protection_spec.rb +0 -8
- data/spec/mongoid/user_oauth_spec.rb +0 -8
- data/spec/mongoid/user_remember_me_spec.rb +0 -8
- data/spec/mongoid/user_reset_password_spec.rb +0 -8
- data/spec/mongoid/user_spec.rb +0 -51
- data/spec/orm/data_mapper.rb +0 -48
- data/spec/orm/mongo_mapper.rb +0 -10
- data/spec/orm/mongoid.rb +0 -22
- data/spec/rails_app/app/data_mapper/authentication.rb +0 -8
- data/spec/rails_app/app/data_mapper/user.rb +0 -7
- data/spec/rails_app/app/mongo_mapper/authentication.rb +0 -6
- data/spec/rails_app/app/mongo_mapper/user.rb +0 -7
- data/spec/rails_app/app/mongoid/authentication.rb +0 -7
- data/spec/rails_app/app/mongoid/user.rb +0 -7
@@ -2,46 +2,45 @@ module Sorcery
|
|
2
2
|
module Controller
|
3
3
|
module Submodules
|
4
4
|
# This submodule integrates HTTP Basic authentication into sorcery.
|
5
|
-
# You are provided with a before
|
5
|
+
# You are provided with a before action, require_login_from_http_basic,
|
6
6
|
# which requests the browser for authentication.
|
7
|
-
# Then the rest of the submodule takes care of logging the user in
|
7
|
+
# Then the rest of the submodule takes care of logging the user in
|
8
8
|
# into the session, so that the next requests will keep him logged in.
|
9
9
|
module HttpBasicAuth
|
10
10
|
def self.included(base)
|
11
11
|
base.send(:include, InstanceMethods)
|
12
12
|
Config.module_eval do
|
13
13
|
class << self
|
14
|
-
attr_accessor :controller_to_realm_map
|
15
|
-
|
14
|
+
attr_accessor :controller_to_realm_map # What realm to display for which controller name.
|
15
|
+
|
16
16
|
def merge_http_basic_auth_defaults!
|
17
|
-
@defaults.merge!(:@controller_to_realm_map
|
17
|
+
@defaults.merge!(:@controller_to_realm_map => { 'application' => 'Application' })
|
18
18
|
end
|
19
19
|
end
|
20
20
|
merge_http_basic_auth_defaults!
|
21
21
|
end
|
22
22
|
Config.login_sources << :login_from_basic_auth
|
23
23
|
end
|
24
|
-
|
25
|
-
module InstanceMethods
|
26
24
|
|
25
|
+
module InstanceMethods
|
27
26
|
protected
|
28
|
-
|
29
|
-
# to be used as a
|
27
|
+
|
28
|
+
# to be used as a before_action.
|
30
29
|
# The method sets a session when requesting the user's credentials.
|
31
30
|
# This is a trick to overcome the way HTTP authentication works (explained below):
|
32
31
|
#
|
33
|
-
# Once the user fills the credentials once, the browser will always send it to the
|
32
|
+
# Once the user fills the credentials once, the browser will always send it to the
|
34
33
|
# server when visiting the website, until the browser is closed.
|
35
|
-
# This causes wierd behaviour if the user logs out. The session is reset, yet the
|
36
|
-
# user is re-logged in by the
|
34
|
+
# This causes wierd behaviour if the user logs out. The session is reset, yet the
|
35
|
+
# user is re-logged in by the before_action calling 'login_from_basic_auth'.
|
37
36
|
# To overcome this, we set a session when requesting the password, which logout will
|
38
37
|
# reset, and that's how we know if we need to request for HTTP auth again.
|
39
38
|
def require_login_from_http_basic
|
40
|
-
(request_http_basic_authentication(realm_name_by_controller)
|
39
|
+
(request_http_basic_authentication(realm_name_by_controller) && (session[:http_authentication_used] = true) && return) if request.authorization.nil? || session[:http_authentication_used].nil?
|
41
40
|
require_login
|
42
41
|
session[:http_authentication_used] = nil unless logged_in?
|
43
42
|
end
|
44
|
-
|
43
|
+
|
45
44
|
# given to main controller module as a login source callback
|
46
45
|
def login_from_basic_auth
|
47
46
|
authenticate_with_http_basic do |username, password|
|
@@ -50,7 +49,7 @@ module Sorcery
|
|
50
49
|
@current_user
|
51
50
|
end
|
52
51
|
end
|
53
|
-
|
52
|
+
|
54
53
|
# Sets the realm name by searching the controller name in the hash given at configuration time.
|
55
54
|
def realm_name_by_controller
|
56
55
|
if defined?(ActionController::Base)
|
@@ -62,13 +61,11 @@ module Sorcery
|
|
62
61
|
end
|
63
62
|
nil
|
64
63
|
else
|
65
|
-
Config.controller_to_realm_map[
|
64
|
+
Config.controller_to_realm_map['application']
|
66
65
|
end
|
67
66
|
end
|
68
|
-
|
69
67
|
end
|
70
|
-
|
71
68
|
end
|
72
69
|
end
|
73
70
|
end
|
74
|
-
end
|
71
|
+
end
|
@@ -19,7 +19,7 @@ module Sorcery
|
|
19
19
|
end
|
20
20
|
Config.login_sources << :login_from_cookie
|
21
21
|
Config.after_login << :remember_me_if_asked_to
|
22
|
-
Config.
|
22
|
+
Config.before_logout << :forget_me!
|
23
23
|
end
|
24
24
|
|
25
25
|
module InstanceMethods
|
@@ -29,10 +29,16 @@ module Sorcery
|
|
29
29
|
set_remember_me_cookie!(current_user)
|
30
30
|
end
|
31
31
|
|
32
|
-
# Clears the cookie and
|
32
|
+
# Clears the cookie, and depending on the value of remember_me_token_persist_globally, may clear the token value.
|
33
33
|
def forget_me!
|
34
34
|
current_user.forget_me!
|
35
|
-
cookies.delete(:remember_me_token, :
|
35
|
+
cookies.delete(:remember_me_token, domain: Config.cookie_domain)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Clears the cookie, and clears the token value.
|
39
|
+
def force_forget_me!
|
40
|
+
current_user.force_forget_me!
|
41
|
+
cookies.delete(:remember_me_token, domain: Config.cookie_domain)
|
36
42
|
end
|
37
43
|
|
38
44
|
# Override.
|
@@ -47,8 +53,8 @@ module Sorcery
|
|
47
53
|
|
48
54
|
# calls remember_me! if a third credential was passed to the login method.
|
49
55
|
# Runs as a hook after login.
|
50
|
-
def remember_me_if_asked_to(
|
51
|
-
remember_me! if
|
56
|
+
def remember_me_if_asked_to(_user, credentials)
|
57
|
+
remember_me! if credentials.size == 3 && credentials[2] && credentials[2] != '0'
|
52
58
|
end
|
53
59
|
|
54
60
|
# Checks the cookie for a remember me token, tried to find a user with that token
|
@@ -67,14 +73,13 @@ module Sorcery
|
|
67
73
|
|
68
74
|
def set_remember_me_cookie!(user)
|
69
75
|
cookies.signed[:remember_me_token] = {
|
70
|
-
:
|
71
|
-
:
|
72
|
-
:
|
73
|
-
:
|
76
|
+
value: user.send(user.sorcery_config.remember_me_token_attribute_name),
|
77
|
+
expires: user.send(user.sorcery_config.remember_me_token_expires_at_attribute_name),
|
78
|
+
httponly: Config.remember_me_httponly,
|
79
|
+
domain: Config.cookie_domain
|
74
80
|
}
|
75
81
|
end
|
76
82
|
end
|
77
|
-
|
78
83
|
end
|
79
84
|
end
|
80
85
|
end
|
@@ -8,10 +8,10 @@ module Sorcery
|
|
8
8
|
base.send(:include, InstanceMethods)
|
9
9
|
Config.module_eval do
|
10
10
|
class << self
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
# how long in seconds to keep the session alive.
|
12
|
+
attr_accessor :session_timeout
|
13
|
+
# use the last action as the beginning of session timeout.
|
14
|
+
attr_accessor :session_timeout_from_last_action
|
15
15
|
|
16
16
|
def merge_session_timeout_defaults!
|
17
17
|
@defaults.merge!(:@session_timeout => 3600, # 1.hour
|
@@ -21,7 +21,7 @@ module Sorcery
|
|
21
21
|
merge_session_timeout_defaults!
|
22
22
|
end
|
23
23
|
Config.after_login << :register_login_time
|
24
|
-
base.
|
24
|
+
base.prepend_before_action :validate_session
|
25
25
|
end
|
26
26
|
|
27
27
|
module InstanceMethods
|
@@ -29,12 +29,12 @@ module Sorcery
|
|
29
29
|
|
30
30
|
# Registers last login to be used as the timeout starting point.
|
31
31
|
# Runs as a hook after a successful login.
|
32
|
-
def register_login_time(
|
32
|
+
def register_login_time(_user, _credentials)
|
33
33
|
session[:login_time] = session[:last_action_time] = Time.now.in_time_zone
|
34
34
|
end
|
35
35
|
|
36
36
|
# Checks if session timeout was reached and expires the current session if so.
|
37
|
-
# To be used as a
|
37
|
+
# To be used as a before_action, before require_login
|
38
38
|
def validate_session
|
39
39
|
session_to_use = Config.session_timeout_from_last_action ? session[:last_action_time] : session[:login_time]
|
40
40
|
if session_to_use && sorcery_session_expired?(session_to_use.to_time)
|
@@ -48,7 +48,6 @@ module Sorcery
|
|
48
48
|
def sorcery_session_expired?(time)
|
49
49
|
Time.now.in_time_zone - time > Config.session_timeout
|
50
50
|
end
|
51
|
-
|
52
51
|
end
|
53
52
|
end
|
54
53
|
end
|
@@ -1,51 +1,51 @@
|
|
1
|
-
require
|
1
|
+
require 'openssl'
|
2
2
|
|
3
3
|
module Sorcery
|
4
4
|
module CryptoProviders
|
5
|
-
# This encryption method is reversible if you have the supplied key.
|
5
|
+
# This encryption method is reversible if you have the supplied key.
|
6
6
|
# So in order to use this encryption method you must supply it with a key first.
|
7
7
|
# In an initializer, or before your application initializes, you should do the following:
|
8
8
|
#
|
9
9
|
# Sorcery::Model::ConfigAES256.key = "my 32 bytes long key"
|
10
10
|
#
|
11
|
-
# My final comment is that this is a strong encryption method,
|
11
|
+
# My final comment is that this is a strong encryption method,
|
12
12
|
# but its main weakness is that its reversible. If you do not need to reverse the hash
|
13
13
|
# then you should consider Sha512 or BCrypt instead.
|
14
14
|
#
|
15
15
|
# Keep your key in a safe place, some even say the key should be stored on a separate server.
|
16
|
-
# This won't hurt performance because the only time it will try and access the key on the
|
16
|
+
# This won't hurt performance because the only time it will try and access the key on the
|
17
17
|
# separate server is during initialization, which only
|
18
|
-
# happens once. The reasoning behind this is if someone does compromise your server they
|
18
|
+
# happens once. The reasoning behind this is if someone does compromise your server they
|
19
19
|
# won't have the key also. Basically, you don't want to store the key with the lock.
|
20
20
|
class AES256
|
21
21
|
class << self
|
22
22
|
attr_writer :key
|
23
|
-
|
23
|
+
|
24
24
|
def encrypt(*tokens)
|
25
25
|
aes.encrypt
|
26
26
|
aes.key = @key
|
27
|
-
[aes.update(tokens.join) + aes.final].pack(
|
27
|
+
[aes.update(tokens.join) + aes.final].pack('m').chomp
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
30
|
def matches?(crypted, *tokens)
|
31
31
|
decrypt(crypted) == tokens.join
|
32
32
|
rescue OpenSSL::CipherError
|
33
33
|
false
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
36
|
def decrypt(crypted)
|
37
37
|
aes.decrypt
|
38
38
|
aes.key = @key
|
39
|
-
(aes.update(crypted.unpack(
|
39
|
+
(aes.update(crypted.unpack('m').first) + aes.final)
|
40
40
|
end
|
41
|
-
|
41
|
+
|
42
42
|
private
|
43
|
-
|
43
|
+
|
44
44
|
def aes
|
45
|
-
raise ArgumentError
|
46
|
-
@aes ||= OpenSSL::Cipher
|
45
|
+
raise ArgumentError, "#{name} expects a 32 bytes long key. Please use Sorcery::Model::Config.encryption_key to set it." if @key.nil? || @key == ''
|
46
|
+
@aes ||= OpenSSL::Cipher.new('AES-256-ECB')
|
47
47
|
end
|
48
48
|
end
|
49
49
|
end
|
50
50
|
end
|
51
|
-
end
|
51
|
+
end
|
@@ -2,9 +2,9 @@ require 'bcrypt'
|
|
2
2
|
|
3
3
|
module Sorcery
|
4
4
|
module CryptoProviders
|
5
|
-
# For most apps Sha512 is plenty secure, but if you are building an app that stores nuclear
|
5
|
+
# For most apps Sha512 is plenty secure, but if you are building an app that stores nuclear
|
6
6
|
# launch codes you might want to consier BCrypt. This is an extremely
|
7
|
-
# secure hashing algorithm, mainly because it is slow.
|
7
|
+
# secure hashing algorithm, mainly because it is slow.
|
8
8
|
# A brute force attack on a BCrypt encrypted password would take much longer than a brute force attack on a
|
9
9
|
# password encrypted with a Sha algorithm. Keep in mind you are sacrificing performance by using this,
|
10
10
|
# generating a password takes exponentially longer than any
|
@@ -40,30 +40,30 @@ module Sorcery
|
|
40
40
|
# You are good to go!
|
41
41
|
class BCrypt
|
42
42
|
class << self
|
43
|
-
# This is the :cost option for the BCrpyt library.
|
43
|
+
# This is the :cost option for the BCrpyt library.
|
44
44
|
# The higher the cost the more secure it is and the longer is take the generate a hash. By default this is 10.
|
45
|
-
# Set this to whatever you want, play around with it to get that perfect balance between
|
45
|
+
# Set this to whatever you want, play around with it to get that perfect balance between
|
46
46
|
# security and performance.
|
47
47
|
def cost
|
48
48
|
@cost ||= 10
|
49
49
|
end
|
50
50
|
attr_writer :cost
|
51
|
-
alias
|
52
|
-
alias
|
53
|
-
|
51
|
+
alias stretches cost
|
52
|
+
alias stretches= cost=
|
53
|
+
|
54
54
|
# Creates a BCrypt hash for the password passed.
|
55
55
|
def encrypt(*tokens)
|
56
|
-
::BCrypt::Password.create(join_tokens(tokens), :
|
56
|
+
::BCrypt::Password.create(join_tokens(tokens), cost: cost)
|
57
57
|
end
|
58
|
-
|
58
|
+
|
59
59
|
# Does the hash match the tokens? Uses the same tokens that were used to encrypt.
|
60
60
|
def matches?(hash, *tokens)
|
61
61
|
hash = new_from_hash(hash)
|
62
62
|
return false if hash.nil? || hash == {}
|
63
63
|
hash == join_tokens(tokens)
|
64
64
|
end
|
65
|
-
|
66
|
-
# This method is used as a flag to tell Sorcery to "resave" the password
|
65
|
+
|
66
|
+
# This method is used as a flag to tell Sorcery to "resave" the password
|
67
67
|
# upon a successful login, using the new cost
|
68
68
|
def cost_matches?(hash)
|
69
69
|
hash = new_from_hash(hash)
|
@@ -73,25 +73,23 @@ module Sorcery
|
|
73
73
|
hash.cost == cost
|
74
74
|
end
|
75
75
|
end
|
76
|
-
|
76
|
+
|
77
77
|
def reset!
|
78
78
|
@cost = 10
|
79
79
|
end
|
80
|
-
|
80
|
+
|
81
81
|
private
|
82
|
-
|
82
|
+
|
83
83
|
def join_tokens(tokens)
|
84
84
|
tokens.flatten.join
|
85
85
|
end
|
86
|
-
|
86
|
+
|
87
87
|
def new_from_hash(hash)
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
return nil
|
92
|
-
end
|
88
|
+
::BCrypt::Password.new(hash)
|
89
|
+
rescue ::BCrypt::Errors::InvalidHash
|
90
|
+
return nil
|
93
91
|
end
|
94
92
|
end
|
95
93
|
end
|
96
94
|
end
|
97
|
-
end
|
95
|
+
end
|
@@ -1,9 +1,9 @@
|
|
1
|
-
require
|
2
|
-
|
1
|
+
require 'digest/md5'
|
2
|
+
|
3
3
|
module Sorcery
|
4
4
|
module CryptoProviders
|
5
|
-
# This class was made for the users transitioning from md5 based systems.
|
6
|
-
# I highly discourage using this crypto provider as it superbly inferior
|
5
|
+
# This class was made for the users transitioning from md5 based systems.
|
6
|
+
# I highly discourage using this crypto provider as it superbly inferior
|
7
7
|
# to your other options.
|
8
8
|
#
|
9
9
|
# Please use any other provider offered by Sorcery.
|
@@ -16,4 +16,4 @@ module Sorcery
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|
19
|
-
end
|
19
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require 'digest/sha1'
|
2
2
|
|
3
3
|
module Sorcery
|
4
4
|
module CryptoProviders
|
@@ -8,9 +8,9 @@ module Sorcery
|
|
8
8
|
include Common
|
9
9
|
class << self
|
10
10
|
def join_token
|
11
|
-
@join_token ||=
|
11
|
+
@join_token ||= '--'
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
# Turns your raw password into a Sha1 hash.
|
15
15
|
def encrypt(*tokens)
|
16
16
|
tokens = tokens.flatten
|
@@ -18,11 +18,11 @@ module Sorcery
|
|
18
18
|
stretches.times { digest = secure_digest([digest, *tokens].join(join_token)) }
|
19
19
|
digest
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
def secure_digest(digest)
|
23
23
|
Digest::SHA1.hexdigest(digest)
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
28
|
-
end
|
28
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
|
-
require
|
1
|
+
require 'digest/sha2'
|
2
2
|
|
3
3
|
module Sorcery
|
4
|
-
# The activate_sorcery method has a custom_crypto_provider configuration option.
|
4
|
+
# The activate_sorcery method has a custom_crypto_provider configuration option.
|
5
5
|
# This allows you to use any type of encryption you like.
|
6
6
|
# Just create a class with a class level encrypt and matches? method. See example below.
|
7
7
|
#
|
@@ -1,7 +1,7 @@
|
|
1
|
-
require
|
1
|
+
require 'digest/sha2'
|
2
2
|
|
3
3
|
module Sorcery
|
4
|
-
# The activate_sorcery method has a custom_crypto_provider configuration option.
|
4
|
+
# The activate_sorcery method has a custom_crypto_provider configuration option.
|
5
5
|
# This allows you to use any type of encryption you like.
|
6
6
|
# Just create a class with a class level encrypt and matches? method. See example below.
|
7
7
|
#
|
@@ -33,4 +33,4 @@ module Sorcery
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
end
|
36
|
-
end
|
36
|
+
end
|
data/lib/sorcery/engine.rb
CHANGED
@@ -6,16 +6,11 @@ module Sorcery
|
|
6
6
|
# With the plugin logic.
|
7
7
|
class Engine < Rails::Engine
|
8
8
|
config.sorcery = ::Sorcery::Controller::Config
|
9
|
-
|
10
|
-
initializer
|
9
|
+
|
10
|
+
initializer 'extend Controller with sorcery' do
|
11
11
|
ActionController::Base.send(:include, Sorcery::Controller)
|
12
12
|
ActionController::Base.helper_method :current_user
|
13
13
|
ActionController::Base.helper_method :logged_in?
|
14
14
|
end
|
15
|
-
|
16
|
-
rake_tasks do
|
17
|
-
load "sorcery/railties/tasks.rake"
|
18
|
-
end
|
19
|
-
|
20
15
|
end
|
21
|
-
end
|
16
|
+
end
|
data/lib/sorcery/model.rb
CHANGED
@@ -17,7 +17,7 @@ module Sorcery
|
|
17
17
|
include_required_submodules!
|
18
18
|
|
19
19
|
# This runs the options block set in the initializer on the model class.
|
20
|
-
::Sorcery::Controller::Config.user_config.tap{|blk| blk.call(@sorcery_config) if blk}
|
20
|
+
::Sorcery::Controller::Config.user_config.tap { |blk| blk.call(@sorcery_config) if blk }
|
21
21
|
|
22
22
|
define_base_fields
|
23
23
|
init_orm_hooks!
|
@@ -29,7 +29,7 @@ module Sorcery
|
|
29
29
|
private
|
30
30
|
|
31
31
|
def define_base_fields
|
32
|
-
|
32
|
+
class_eval do
|
33
33
|
sorcery_config.username_attribute_names.each do |username|
|
34
34
|
sorcery_adapter.define_field username, String, length: 255
|
35
35
|
end
|
@@ -39,17 +39,16 @@ module Sorcery
|
|
39
39
|
sorcery_adapter.define_field sorcery_config.crypted_password_attribute_name, String, length: 255
|
40
40
|
sorcery_adapter.define_field sorcery_config.salt_attribute_name, String, length: 255
|
41
41
|
end
|
42
|
-
|
43
42
|
end
|
44
43
|
|
45
44
|
# includes required submodules into the model class,
|
46
45
|
# which usually is called User.
|
47
46
|
def include_required_submodules!
|
48
|
-
|
47
|
+
class_eval do
|
49
48
|
@sorcery_config.submodules = ::Sorcery::Controller::Config.submodules
|
50
49
|
@sorcery_config.submodules.each do |mod|
|
51
50
|
begin
|
52
|
-
include Submodules.const_get(mod.to_s.split('_').map
|
51
|
+
include Submodules.const_get(mod.to_s.split('_').map(&:capitalize).join)
|
53
52
|
rescue NameError
|
54
53
|
# don't stop on a missing submodule. Needed because some submodules are only defined
|
55
54
|
# in the controller side.
|
@@ -60,11 +59,11 @@ module Sorcery
|
|
60
59
|
|
61
60
|
# add virtual password accessor and ORM callbacks.
|
62
61
|
def init_orm_hooks!
|
63
|
-
sorcery_adapter.define_callback :before, :validation, :encrypt_password, if:
|
62
|
+
sorcery_adapter.define_callback :before, :validation, :encrypt_password, if: proc { |record|
|
64
63
|
record.send(sorcery_config.password_attribute_name).present?
|
65
64
|
}
|
66
65
|
|
67
|
-
sorcery_adapter.define_callback :after, :save, :clear_virtual_password, if:
|
66
|
+
sorcery_adapter.define_callback :after, :save, :clear_virtual_password, if: proc { |record|
|
68
67
|
record.send(sorcery_config.password_attribute_name).present?
|
69
68
|
}
|
70
69
|
|
@@ -82,7 +81,7 @@ module Sorcery
|
|
82
81
|
# Finds the user by the username and compares the user's password to the one supplied to the method.
|
83
82
|
# returns the user if success, nil otherwise.
|
84
83
|
def authenticate(*credentials)
|
85
|
-
raise ArgumentError,
|
84
|
+
raise ArgumentError, 'at least 2 arguments required' if credentials.size < 2
|
86
85
|
|
87
86
|
return false if credentials[0].blank?
|
88
87
|
|
@@ -93,19 +92,19 @@ module Sorcery
|
|
93
92
|
user = sorcery_adapter.find_by_credentials(credentials)
|
94
93
|
|
95
94
|
if user.respond_to?(:active_for_authentication?)
|
96
|
-
return nil
|
95
|
+
return nil unless user.active_for_authentication?
|
97
96
|
end
|
98
97
|
|
99
98
|
set_encryption_attributes
|
100
99
|
|
101
|
-
user if user && @sorcery_config.before_authenticate.all? {|c| user.send(c)} && user.valid_password?(credentials[1])
|
100
|
+
user if user && @sorcery_config.before_authenticate.all? { |c| user.send(c) } && user.valid_password?(credentials[1])
|
102
101
|
end
|
103
102
|
|
104
103
|
# encrypt tokens using current encryption_provider.
|
105
104
|
def encrypt(*tokens)
|
106
105
|
return tokens.first if @sorcery_config.encryption_provider.nil?
|
107
106
|
|
108
|
-
set_encryption_attributes
|
107
|
+
set_encryption_attributes
|
109
108
|
|
110
109
|
CryptoProviders::AES256.key = @sorcery_config.encryption_key
|
111
110
|
@sorcery_config.encryption_provider.encrypt(*tokens)
|
@@ -113,13 +112,13 @@ module Sorcery
|
|
113
112
|
|
114
113
|
protected
|
115
114
|
|
116
|
-
def set_encryption_attributes
|
115
|
+
def set_encryption_attributes
|
117
116
|
@sorcery_config.encryption_provider.stretches = @sorcery_config.stretches if @sorcery_config.encryption_provider.respond_to?(:stretches) && @sorcery_config.stretches
|
118
117
|
@sorcery_config.encryption_provider.join_token = @sorcery_config.salt_join_token if @sorcery_config.encryption_provider.respond_to?(:join_token) && @sorcery_config.salt_join_token
|
119
118
|
end
|
120
|
-
|
119
|
+
|
121
120
|
def add_config_inheritance
|
122
|
-
|
121
|
+
class_eval do
|
123
122
|
def self.inherited(subclass)
|
124
123
|
subclass.class_eval do
|
125
124
|
class << self
|
@@ -131,7 +130,6 @@ module Sorcery
|
|
131
130
|
end
|
132
131
|
end
|
133
132
|
end
|
134
|
-
|
135
133
|
end
|
136
134
|
|
137
135
|
module InstanceMethods
|
@@ -148,12 +146,12 @@ module Sorcery
|
|
148
146
|
|
149
147
|
# Calls the configured encryption provider to compare the supplied password with the encrypted one.
|
150
148
|
def valid_password?(pass)
|
151
|
-
|
152
|
-
return
|
149
|
+
crypted = send(sorcery_config.crypted_password_attribute_name)
|
150
|
+
return crypted == pass if sorcery_config.encryption_provider.nil?
|
153
151
|
|
154
|
-
|
152
|
+
salt = send(sorcery_config.salt_attribute_name) unless sorcery_config.salt_attribute_name.nil?
|
155
153
|
|
156
|
-
sorcery_config.encryption_provider.matches?(
|
154
|
+
sorcery_config.encryption_provider.matches?(crypted, pass, salt)
|
157
155
|
end
|
158
156
|
|
159
157
|
protected
|
@@ -162,16 +160,16 @@ module Sorcery
|
|
162
160
|
# encrypts password with salt and saves it.
|
163
161
|
def encrypt_password
|
164
162
|
config = sorcery_config
|
165
|
-
|
166
|
-
|
163
|
+
send(:"#{config.salt_attribute_name}=", new_salt = TemporaryToken.generate_random_token) unless config.salt_attribute_name.nil?
|
164
|
+
send(:"#{config.crypted_password_attribute_name}=", self.class.encrypt(send(config.password_attribute_name), new_salt))
|
167
165
|
end
|
168
166
|
|
169
167
|
def clear_virtual_password
|
170
168
|
config = sorcery_config
|
171
|
-
|
169
|
+
send(:"#{config.password_attribute_name}=", nil)
|
172
170
|
|
173
171
|
if respond_to?(:"#{config.password_attribute_name}_confirmation=")
|
174
|
-
|
172
|
+
send(:"#{config.password_attribute_name}_confirmation=", nil)
|
175
173
|
end
|
176
174
|
end
|
177
175
|
|
@@ -179,17 +177,11 @@ module Sorcery
|
|
179
177
|
# supports both the ActionMailer 3 way of calling, and the plain old Ruby object way.
|
180
178
|
def generic_send_email(method, mailer)
|
181
179
|
config = sorcery_config
|
182
|
-
mail = config.send(mailer).send(config.send(method),self)
|
183
|
-
if defined?(ActionMailer)
|
184
|
-
|
185
|
-
if mail.respond_to?(:deliver_now)
|
186
|
-
mail.deliver_now
|
187
|
-
else
|
188
|
-
mail.deliver
|
189
|
-
end
|
180
|
+
mail = config.send(mailer).send(config.send(method), self)
|
181
|
+
if defined?(ActionMailer) && config.send(mailer).is_a?(Class) && config.send(mailer) < ActionMailer::Base
|
182
|
+
mail.send(config.email_delivery_method)
|
190
183
|
end
|
191
184
|
end
|
192
185
|
end
|
193
|
-
|
194
186
|
end
|
195
187
|
end
|