sorcery 0.9.0 → 0.10.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.
- checksums.yaml +4 -4
- data/.travis.yml +29 -104
- data/CHANGELOG.md +22 -1
- data/Gemfile +2 -16
- data/README.md +124 -271
- 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 +29 -53
- 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 +3 -3
- 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/adapters/active_record_adapter.rb +7 -18
- 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 +23 -15
- 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/controller.rb +19 -21
- 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/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/model.rb +27 -31
- 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 +17 -9
- data/lib/sorcery/providers/github.rb +12 -5
- 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 +8 -11
- data/lib/sorcery/test_helpers/internal/rails.rb +16 -8
- data/lib/sorcery/test_helpers/internal.rb +10 -10
- 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/lib/sorcery.rb +0 -28
- 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 +142 -102
- 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/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/config.ru +1 -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 +226 -116
- data/spec/sorcery_crypto_providers_spec.rb +63 -76
- data/spec/spec_helper.rb +17 -13
- metadata +28 -82
- 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
- data/spec/rails_app/log/development.log +0 -1791
|
@@ -19,6 +19,9 @@ module Sorcery
|
|
|
19
19
|
require 'sorcery/providers/google'
|
|
20
20
|
require 'sorcery/providers/jira'
|
|
21
21
|
require 'sorcery/providers/salesforce'
|
|
22
|
+
require 'sorcery/providers/paypal'
|
|
23
|
+
require 'sorcery/providers/slack'
|
|
24
|
+
require 'sorcery/providers/wechat'
|
|
22
25
|
|
|
23
26
|
Config.module_eval do
|
|
24
27
|
class << self
|
|
@@ -61,7 +64,7 @@ module Sorcery
|
|
|
61
64
|
@provider = sorcery_get_provider provider_name
|
|
62
65
|
sorcery_fixup_callback_url @provider
|
|
63
66
|
if @provider.respond_to?(:login_url) && @provider.has_callback?
|
|
64
|
-
@provider.state = args[:state]
|
|
67
|
+
@provider.state = args[:state]
|
|
65
68
|
return @provider.login_url(params, session)
|
|
66
69
|
else
|
|
67
70
|
return nil
|
|
@@ -87,19 +90,18 @@ module Sorcery
|
|
|
87
90
|
end
|
|
88
91
|
|
|
89
92
|
# for backwards compatibility
|
|
90
|
-
def access_token(*
|
|
93
|
+
def access_token(*_args)
|
|
91
94
|
@access_token
|
|
92
95
|
end
|
|
93
96
|
|
|
94
|
-
|
|
95
97
|
# this method should be somewhere else. It only does something once per application per provider.
|
|
96
98
|
def sorcery_fixup_callback_url(provider)
|
|
97
99
|
provider.original_callback_url ||= provider.callback_url
|
|
98
100
|
if provider.original_callback_url.present? && provider.original_callback_url[0] == '/'
|
|
99
|
-
uri = URI.parse(request.url.gsub(/\?.*$/,''))
|
|
101
|
+
uri = URI.parse(request.url.gsub(/\?.*$/, ''))
|
|
100
102
|
uri.path = ''
|
|
101
103
|
uri.query = nil
|
|
102
|
-
uri.scheme = 'https' if
|
|
104
|
+
uri.scheme = 'https' if request.env['HTTP_X_FORWARDED_PROTO'] == 'https'
|
|
103
105
|
host = uri.to_s
|
|
104
106
|
provider.callback_url = "#{host}#{@provider.original_callback_url}"
|
|
105
107
|
end
|
|
@@ -139,7 +141,7 @@ module Sorcery
|
|
|
139
141
|
current_user.add_provider_to_user(provider_name.to_s, @user_hash[:uid].to_s)
|
|
140
142
|
end
|
|
141
143
|
|
|
142
|
-
#
|
|
144
|
+
# Initialize new user from provider informations.
|
|
143
145
|
# If a provider doesn't give required informations or username/email is already taken,
|
|
144
146
|
# we store provider/user infos into a session and can be rendered into registration form
|
|
145
147
|
def create_and_validate_from(provider_name)
|
|
@@ -150,12 +152,14 @@ module Sorcery
|
|
|
150
152
|
|
|
151
153
|
user, saved = user_class.create_and_validate_from_provider(provider_name, @user_hash[:uid], attrs)
|
|
152
154
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
155
|
+
unless saved
|
|
156
|
+
session[:incomplete_user] = {
|
|
157
|
+
provider: { config.provider_uid_attribute_name => @user_hash[:uid], config.provider_attribute_name => provider_name },
|
|
158
|
+
user_hash: attrs
|
|
159
|
+
}
|
|
160
|
+
end
|
|
157
161
|
|
|
158
|
-
|
|
162
|
+
user
|
|
159
163
|
end
|
|
160
164
|
|
|
161
165
|
# this method automatically creates a new user from the data in the external user hash.
|
|
@@ -184,15 +188,19 @@ module Sorcery
|
|
|
184
188
|
|
|
185
189
|
def user_attrs(user_info_mapping, user_hash)
|
|
186
190
|
attrs = {}
|
|
187
|
-
user_info_mapping.each do |k,v|
|
|
188
|
-
if (varr = v.split(
|
|
189
|
-
attribute_value =
|
|
191
|
+
user_info_mapping.each do |k, v|
|
|
192
|
+
if (varr = v.split('/')).size > 1
|
|
193
|
+
attribute_value = begin
|
|
194
|
+
varr.inject(user_hash[:user_info]) { |hash, value| hash[value] }
|
|
195
|
+
rescue
|
|
196
|
+
nil
|
|
197
|
+
end
|
|
190
198
|
attribute_value.nil? ? attrs : attrs.merge!(k => attribute_value)
|
|
191
199
|
else
|
|
192
200
|
attrs.merge!(k => user_hash[:user_info][v])
|
|
193
201
|
end
|
|
194
202
|
end
|
|
195
|
-
|
|
203
|
+
attrs
|
|
196
204
|
end
|
|
197
205
|
end
|
|
198
206
|
end
|
|
@@ -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
|
data/lib/sorcery/controller.rb
CHANGED
|
@@ -5,7 +5,7 @@ module Sorcery
|
|
|
5
5
|
include InstanceMethods
|
|
6
6
|
Config.submodules.each do |mod|
|
|
7
7
|
begin
|
|
8
|
-
include Submodules.const_get(mod.to_s.split('_').map
|
|
8
|
+
include Submodules.const_get(mod.to_s.split('_').map(&:capitalize).join)
|
|
9
9
|
rescue NameError
|
|
10
10
|
# don't stop on a missing submodule.
|
|
11
11
|
end
|
|
@@ -16,13 +16,13 @@ module Sorcery
|
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
module InstanceMethods
|
|
19
|
-
# To be used as
|
|
19
|
+
# To be used as before_action.
|
|
20
20
|
# Will trigger auto-login attempts via the call to logged_in?
|
|
21
21
|
# If all attempts to auto-login fail, the failure callback will be called.
|
|
22
22
|
def require_login
|
|
23
|
-
|
|
24
|
-
session[:return_to_url] = request.url if Config.save_return_to_url && request.get?
|
|
25
|
-
|
|
23
|
+
unless logged_in?
|
|
24
|
+
session[:return_to_url] = request.url if Config.save_return_to_url && request.get? && !request.xhr?
|
|
25
|
+
send(Config.not_authenticated_action)
|
|
26
26
|
end
|
|
27
27
|
end
|
|
28
28
|
|
|
@@ -34,7 +34,7 @@ module Sorcery
|
|
|
34
34
|
if user
|
|
35
35
|
old_session = session.dup.to_hash
|
|
36
36
|
reset_sorcery_session
|
|
37
|
-
old_session.each_pair do |k,v|
|
|
37
|
+
old_session.each_pair do |k, v|
|
|
38
38
|
session[k.to_sym] = v
|
|
39
39
|
end
|
|
40
40
|
form_authenticity_token
|
|
@@ -59,11 +59,11 @@ module Sorcery
|
|
|
59
59
|
# Resets the session and runs hooks before and after.
|
|
60
60
|
def logout
|
|
61
61
|
if logged_in?
|
|
62
|
-
|
|
63
|
-
before_logout!
|
|
64
|
-
reset_sorcery_session
|
|
65
|
-
after_logout!
|
|
62
|
+
user = current_user
|
|
63
|
+
before_logout!
|
|
66
64
|
@current_user = nil
|
|
65
|
+
reset_sorcery_session
|
|
66
|
+
after_logout!(user)
|
|
67
67
|
end
|
|
68
68
|
end
|
|
69
69
|
|
|
@@ -87,7 +87,7 @@ module Sorcery
|
|
|
87
87
|
# used when a user tries to access a page while logged out, is asked to login,
|
|
88
88
|
# and we want to return him back to the page he originally wanted.
|
|
89
89
|
def redirect_back_or_to(url, flash_hash = {})
|
|
90
|
-
redirect_to(session[:return_to_url] || url, :
|
|
90
|
+
redirect_to(session[:return_to_url] || url, flash: flash_hash)
|
|
91
91
|
session[:return_to_url] = nil
|
|
92
92
|
end
|
|
93
93
|
|
|
@@ -102,7 +102,7 @@ module Sorcery
|
|
|
102
102
|
#
|
|
103
103
|
# @param [<User-Model>] user the user instance.
|
|
104
104
|
# @return - do not depend on the return value.
|
|
105
|
-
def auto_login(user,
|
|
105
|
+
def auto_login(user, _should_remember = false)
|
|
106
106
|
session[:user_id] = user.id.to_s
|
|
107
107
|
@current_user = user
|
|
108
108
|
end
|
|
@@ -132,26 +132,24 @@ module Sorcery
|
|
|
132
132
|
end
|
|
133
133
|
|
|
134
134
|
def after_login!(user, credentials = [])
|
|
135
|
-
Config.after_login.each {|c|
|
|
135
|
+
Config.after_login.each { |c| send(c, user, credentials) }
|
|
136
136
|
end
|
|
137
137
|
|
|
138
138
|
def after_failed_login!(credentials)
|
|
139
|
-
Config.after_failed_login.each {|c|
|
|
139
|
+
Config.after_failed_login.each { |c| send(c, credentials) }
|
|
140
140
|
end
|
|
141
141
|
|
|
142
|
-
def before_logout!
|
|
143
|
-
Config.before_logout.each {|c|
|
|
142
|
+
def before_logout!
|
|
143
|
+
Config.before_logout.each { |c| send(c) }
|
|
144
144
|
end
|
|
145
145
|
|
|
146
|
-
def after_logout!
|
|
147
|
-
Config.after_logout.each {|c|
|
|
146
|
+
def after_logout!(user)
|
|
147
|
+
Config.after_logout.each { |c| send(c, user) }
|
|
148
148
|
end
|
|
149
149
|
|
|
150
150
|
def user_class
|
|
151
151
|
@user_class ||= Config.user_class.to_s.constantize
|
|
152
152
|
end
|
|
153
|
-
|
|
154
153
|
end
|
|
155
|
-
|
|
156
|
-
end
|
|
154
|
+
end
|
|
157
155
|
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
|