devise_jwt_auth 0.1.4 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/app/controllers/devise_jwt_auth/application_controller.rb +11 -22
- data/app/controllers/devise_jwt_auth/concerns/resource_finder.rb +3 -7
- data/app/controllers/devise_jwt_auth/concerns/set_user_by_token.rb +22 -18
- data/app/controllers/devise_jwt_auth/confirmations_controller.rb +10 -19
- data/app/controllers/devise_jwt_auth/omniauth_callbacks_controller.rb +38 -46
- data/app/controllers/devise_jwt_auth/passwords_controller.rb +34 -36
- data/app/controllers/devise_jwt_auth/refresh_token_controller.rb +4 -1
- data/app/controllers/devise_jwt_auth/registrations_controller.rb +40 -21
- data/app/controllers/devise_jwt_auth/sessions_controller.rb +21 -21
- data/app/controllers/devise_jwt_auth/unlocks_controller.rb +5 -4
- data/app/models/devise_jwt_auth/concerns/active_record_support.rb +3 -0
- data/app/models/devise_jwt_auth/concerns/confirmable_support.rb +7 -14
- data/app/models/devise_jwt_auth/concerns/mongoid_support.rb +3 -0
- data/app/models/devise_jwt_auth/concerns/tokens_serialization.rb +4 -1
- data/app/models/devise_jwt_auth/concerns/user.rb +18 -11
- data/app/models/devise_jwt_auth/concerns/user_omniauth_callbacks.rb +11 -3
- data/app/validators/devise_jwt_auth_email_validator.rb +12 -2
- data/app/views/devise/mailer/reset_password_instructions.html.erb +1 -1
- data/lib/devise_jwt_auth/blacklist.rb +3 -1
- data/lib/devise_jwt_auth/controllers/url_helpers.rb +1 -2
- data/lib/devise_jwt_auth/engine.rb +4 -4
- data/lib/devise_jwt_auth/rails/routes.rb +35 -24
- data/lib/devise_jwt_auth/token_factory.rb +3 -2
- data/lib/devise_jwt_auth/url.rb +2 -4
- data/lib/devise_jwt_auth/version.rb +1 -1
- data/lib/generators/devise_jwt_auth/USAGE +1 -1
- data/lib/generators/devise_jwt_auth/install_generator.rb +7 -6
- data/lib/generators/devise_jwt_auth/install_generator_helpers.rb +27 -6
- data/lib/generators/devise_jwt_auth/install_mongoid_generator.rb +3 -2
- data/lib/generators/devise_jwt_auth/templates/devise_jwt_auth.rb +6 -7
- data/lib/generators/devise_jwt_auth/templates/devise_jwt_auth_create_users.rb.erb +15 -11
- data/lib/generators/devise_jwt_auth/templates/user.rb.erb +2 -2
- data/test/controllers/custom/custom_confirmations_controller_test.rb +2 -2
- data/test/controllers/custom/custom_omniauth_callbacks_controller_test.rb +1 -1
- data/test/controllers/custom/custom_passwords_controller_test.rb +8 -8
- data/test/controllers/custom/custom_refresh_token_controller_test.rb +2 -3
- data/test/controllers/custom/custom_registrations_controller_test.rb +2 -2
- data/test/controllers/demo_group_controller_test.rb +0 -24
- data/test/controllers/demo_mang_controller_test.rb +4 -224
- data/test/controllers/demo_user_controller_test.rb +6 -432
- data/test/controllers/devise_jwt_auth/confirmations_controller_test.rb +5 -5
- data/test/controllers/devise_jwt_auth/omniauth_callbacks_controller_test.rb +9 -10
- data/test/controllers/devise_jwt_auth/passwords_controller_test.rb +34 -35
- data/test/controllers/devise_jwt_auth/refresh_token_controller_test.rb +8 -12
- data/test/controllers/devise_jwt_auth/registrations_controller_test.rb +12 -26
- data/test/controllers/devise_jwt_auth/sessions_controller_test.rb +32 -34
- data/test/controllers/devise_jwt_auth/unlocks_controller_test.rb +2 -2
- data/test/controllers/overrides/confirmations_controller_test.rb +1 -1
- data/test/controllers/overrides/passwords_controller_test.rb +1 -6
- data/test/controllers/overrides/refresh_token_controller_test.rb +1 -2
- data/test/controllers/overrides/registrations_controller_test.rb +1 -1
- data/test/dummy/app/controllers/custom/refresh_token_controller.rb +2 -1
- data/test/dummy/app/controllers/custom/registrations_controller.rb +1 -1
- data/test/dummy/app/controllers/overrides/confirmations_controller.rb +3 -16
- data/test/dummy/app/controllers/overrides/omniauth_callbacks_controller.rb +4 -4
- data/test/dummy/app/controllers/overrides/passwords_controller.rb +4 -16
- data/test/dummy/app/controllers/overrides/refresh_token_controller.rb +1 -1
- data/test/dummy/app/controllers/overrides/registrations_controller.rb +2 -2
- data/test/dummy/app/controllers/overrides/sessions_controller.rb +2 -2
- data/test/dummy/app/models/concerns/favorite_color.rb +11 -9
- data/test/dummy/config/application.rb +1 -0
- data/test/dummy/config/boot.rb +1 -1
- data/test/dummy/config/environments/development.rb +2 -2
- data/test/dummy/config/environments/test.rb +11 -7
- data/test/dummy/config/initializers/devise_jwt_auth.rb +1 -0
- data/test/dummy/config/initializers/figaro.rb +1 -1
- data/test/dummy/config/initializers/omniauth.rb +2 -2
- data/test/dummy/config/routes.rb +10 -8
- data/test/dummy/config.ru +2 -2
- data/test/dummy/db/migrate/20141222035835_devise_jwt_auth_create_only_email_users.rb +9 -9
- data/test/dummy/db/migrate/20190924101113_devise_jwt_auth_create_confirmable_users.rb +6 -5
- data/test/dummy/db/schema.rb +170 -170
- data/test/dummy/tmp/generators/app/models/user.rb +8 -0
- data/test/dummy/tmp/generators/config/initializers/devise_jwt_auth.rb +6 -7
- data/test/dummy/tmp/generators/db/migrate/{20200210193225_devise_jwt_auth_create_azpire_v1_human_resource_users.rb → 20220123023137_devise_jwt_auth_create_users.rb} +20 -17
- data/test/factories/users.rb +5 -3
- data/test/lib/devise_jwt_auth/blacklist_test.rb +2 -2
- data/test/lib/devise_jwt_auth/token_factory_test.rb +7 -7
- data/test/lib/generators/devise_jwt_auth/install_generator_test.rb +3 -20
- data/test/lib/generators/devise_jwt_auth/install_generator_with_namespace_test.rb +4 -21
- data/test/models/concerns/tokens_serialization_test.rb +68 -68
- data/test/models/user_test.rb +0 -38
- data/test/support/controllers/routes.rb +7 -5
- data/test/test_helper.rb +1 -1
- metadata +45 -71
- data/test/dummy/tmp/generators/app/models/azpire/v1/human_resource/user.rb +0 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f4dbb49ae0d62dcc2e5b23374e972178509d1e936c1246d85828631ceb07b65a
|
4
|
+
data.tar.gz: d4d15235f408dce8fd1c2107007ea4fbf2e48e0ab01315cba67b9f4451fffd92
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a46230b6210496f7ee97b54a357aaf6c36625a7083f33440cf02371914a11bb44329da3516df8b0d6d1bd4524b474715577fc430431d001ef9b6b1bf3b70035e
|
7
|
+
data.tar.gz: bbea37a5d6460fefb600d084d387045d9fefbc14196bdfd23d31d0ae2d8cdb89538d1250781d7a69a379b86a3255397e913610a0d18d30e193220b77ebd6e791
|
data/README.md
CHANGED
@@ -57,7 +57,7 @@ See our [Contribution Guidelines](https://github.com/aarona/devise_jwt_auth/blob
|
|
57
57
|
|
58
58
|
## Live Demos
|
59
59
|
|
60
|
-
Live demos will hopefully be added in the future.
|
60
|
+
Live demos will hopefully be added in the future. Currently, I have a [repository](https://github.com/aarona/dja_example) available that is a proof of concept for DJA that uses React as the client. However, the example application only supports sigining up, sigining in and singing out. It doesn't provide a way to reset a user's password for example and other things that DJA supports. Those will be added in the near future.
|
61
61
|
|
62
62
|
## License
|
63
63
|
|
@@ -20,20 +20,6 @@ module DeviseJwtAuth
|
|
20
20
|
DeviseJwtAuth.redirect_whitelist && !DeviseJwtAuth::Url.whitelisted?(redirect_url)
|
21
21
|
end
|
22
22
|
|
23
|
-
def build_redirect_headers(access_token, client, redirect_header_options = {})
|
24
|
-
{
|
25
|
-
# DeviseJwtAuth.headers_names[:"access-token"] => access_token,
|
26
|
-
# DeviseJwtAuth.headers_names[:"client"] => client,
|
27
|
-
:config => params[:config],
|
28
|
-
|
29
|
-
# Legacy parameters which may be removed in a future release.
|
30
|
-
# Consider using "client" and "access-token" in client code.
|
31
|
-
# See: github.com/lynndylanhurley/devise_jwt_auth/issues/993
|
32
|
-
# :client_id => client,
|
33
|
-
:token => access_token
|
34
|
-
}.merge(redirect_header_options)
|
35
|
-
end
|
36
|
-
|
37
23
|
def params_for_resource(resource)
|
38
24
|
devise_parameter_sanitizer.instance_values['permitted'][resource].each do |type|
|
39
25
|
params[type.to_s] ||= request.headers[type.to_s] unless request.headers[type.to_s].nil?
|
@@ -42,20 +28,23 @@ module DeviseJwtAuth
|
|
42
28
|
end
|
43
29
|
|
44
30
|
def resource_class(m = nil)
|
45
|
-
if m
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
31
|
+
mapping = if m
|
32
|
+
Devise.mappings[m]
|
33
|
+
else
|
34
|
+
Devise.mappings[resource_name] || Devise.mappings.values.first
|
35
|
+
end
|
50
36
|
|
51
37
|
mapping.to
|
52
38
|
end
|
53
39
|
|
54
40
|
def json_api?
|
55
41
|
return false unless defined?(ActiveModel::Serializer)
|
56
|
-
|
57
|
-
|
58
|
-
|
42
|
+
|
43
|
+
if ActiveModel::Serializer.respond_to?(:setup)
|
44
|
+
return ActiveModel::Serializer.setup do |config|
|
45
|
+
config.adapter == :json_api
|
46
|
+
end
|
47
|
+
end
|
59
48
|
ActiveModelSerializers.config.adapter == :json_api
|
60
49
|
end
|
61
50
|
|
@@ -8,19 +8,15 @@ module DeviseJwtAuth::Concerns::ResourceFinder
|
|
8
8
|
# honor Devise configuration for case_insensitive keys
|
9
9
|
q_value = resource_params[field.to_sym]
|
10
10
|
|
11
|
-
if resource_class.case_insensitive_keys.include?(field.to_sym)
|
12
|
-
q_value.downcase!
|
13
|
-
end
|
11
|
+
q_value.downcase! if resource_class.case_insensitive_keys.include?(field.to_sym)
|
14
12
|
|
15
|
-
if resource_class.strip_whitespace_keys.include?(field.to_sym)
|
16
|
-
q_value.strip!
|
17
|
-
end
|
13
|
+
q_value.strip! if resource_class.strip_whitespace_keys.include?(field.to_sym)
|
18
14
|
|
19
15
|
q_value
|
20
16
|
end
|
21
17
|
|
22
18
|
def find_resource(field, value)
|
23
|
-
@resource = if resource_class.try(:
|
19
|
+
@resource = if resource_class.try(:connection_db_config).try(:[], :adapter).try(:include?, 'mysql')
|
24
20
|
# fix for mysql default case insensitivity
|
25
21
|
resource_class.where("BINARY #{field} = ? AND provider= ?", value, provider).first
|
26
22
|
else
|
@@ -5,7 +5,6 @@ module DeviseJwtAuth::Concerns::SetUserByToken
|
|
5
5
|
include DeviseJwtAuth::Concerns::ResourceFinder
|
6
6
|
|
7
7
|
included do
|
8
|
-
|
9
8
|
end
|
10
9
|
|
11
10
|
protected
|
@@ -22,10 +21,10 @@ module DeviseJwtAuth::Concerns::SetUserByToken
|
|
22
21
|
devise_warden_user = warden.user(rc.to_s.underscore.to_sym)
|
23
22
|
@resource = devise_warden_user if devise_warden_user
|
24
23
|
end
|
25
|
-
|
24
|
+
|
26
25
|
# user has already been found and authenticated
|
27
|
-
return @resource if @resource
|
28
|
-
|
26
|
+
return @resource if @resource.is_a?(rc)
|
27
|
+
|
29
28
|
# TODO: Look for the access token in an 'Authentication' header
|
30
29
|
token = request.headers[DeviseJwtAuth.access_token_name]
|
31
30
|
return unless token
|
@@ -33,8 +32,9 @@ module DeviseJwtAuth::Concerns::SetUserByToken
|
|
33
32
|
payload = DeviseJwtAuth::TokenFactory.decode_access_token(token)
|
34
33
|
return if payload.empty?
|
35
34
|
return if payload && payload['sub'].blank?
|
35
|
+
|
36
36
|
uid = payload['sub']
|
37
|
-
|
37
|
+
|
38
38
|
# mitigate timing attacks by finding by uid instead of auth token
|
39
39
|
user = uid && rc.dta_find_by(uid: uid)
|
40
40
|
scope = rc.to_s.underscore.to_sym
|
@@ -46,10 +46,10 @@ module DeviseJwtAuth::Concerns::SetUserByToken
|
|
46
46
|
else
|
47
47
|
sign_in(scope, user, store: false, event: :fetch, bypass: DeviseJwtAuth.bypass_sign_in)
|
48
48
|
end
|
49
|
-
|
49
|
+
@resource = user
|
50
50
|
else
|
51
51
|
# zero all values previously set values
|
52
|
-
|
52
|
+
@resource = nil
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
@@ -65,10 +65,10 @@ module DeviseJwtAuth::Concerns::SetUserByToken
|
|
65
65
|
devise_warden_user = warden.user(rc.to_s.underscore.to_sym)
|
66
66
|
@resource = devise_warden_user if devise_warden_user
|
67
67
|
end
|
68
|
-
|
68
|
+
|
69
69
|
# user has already been found and authenticated
|
70
|
-
return @resource if @resource
|
71
|
-
|
70
|
+
return @resource if @resource.is_a?(rc)
|
71
|
+
|
72
72
|
token = request.cookies[DeviseJwtAuth.refresh_token_name]
|
73
73
|
|
74
74
|
return unless token
|
@@ -76,6 +76,7 @@ module DeviseJwtAuth::Concerns::SetUserByToken
|
|
76
76
|
payload = DeviseJwtAuth::TokenFactory.decode_refresh_token(token)
|
77
77
|
return if payload.empty?
|
78
78
|
return if payload && payload['sub'].blank?
|
79
|
+
|
79
80
|
uid = payload['sub']
|
80
81
|
|
81
82
|
# mitigate timing attacks by finding by uid instead of auth token
|
@@ -89,13 +90,12 @@ module DeviseJwtAuth::Concerns::SetUserByToken
|
|
89
90
|
else
|
90
91
|
sign_in(scope, user, store: false, event: :fetch, bypass: DeviseJwtAuth.bypass_sign_in)
|
91
92
|
end
|
92
|
-
|
93
|
+
@resource = user
|
93
94
|
else
|
94
95
|
# zero all values previously set values
|
95
|
-
|
96
|
+
@resource = nil
|
96
97
|
end
|
97
98
|
end
|
98
|
-
|
99
99
|
|
100
100
|
def update_refresh_token_cookie
|
101
101
|
response.set_cookie(DeviseJwtAuth.refresh_token_name,
|
@@ -103,9 +103,13 @@ module DeviseJwtAuth::Concerns::SetUserByToken
|
|
103
103
|
path: '/auth/refresh_token', # TODO: Use configured auth path
|
104
104
|
expires: Time.zone.now + DeviseJwtAuth.refresh_token_lifespan,
|
105
105
|
httponly: true,
|
106
|
-
secure: Rails.env.production?
|
107
|
-
|
106
|
+
secure: Rails.env.production?)
|
107
|
+
end
|
108
|
+
|
109
|
+
def clear_refresh_token_cookie
|
110
|
+
response.set_cookie(DeviseJwtAuth.refresh_token_name,
|
111
|
+
value: '',
|
112
|
+
path: '/auth/refresh_token', # TODO: Use configured auth path
|
113
|
+
expires: Time.zone.now)
|
108
114
|
end
|
109
|
-
|
110
|
-
|
111
|
-
end
|
115
|
+
end
|
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
module DeviseJwtAuth
|
4
4
|
class ConfirmationsController < DeviseJwtAuth::ApplicationController
|
5
|
-
|
6
5
|
def show
|
7
6
|
@resource = resource_class.confirm_by_token(resource_params[:confirmation_token])
|
8
7
|
|
@@ -12,19 +11,12 @@ module DeviseJwtAuth
|
|
12
11
|
redirect_header_options = { account_confirmation_success: true }
|
13
12
|
|
14
13
|
if signed_in?(resource_name)
|
15
|
-
|
16
|
-
|
17
|
-
# redirect_headers = build_redirect_headers(token.token,
|
18
|
-
# token.client,
|
19
|
-
# redirect_header_options)
|
20
|
-
|
21
|
-
redirect_headers = signed_in_resource.create_named_token_pair.
|
22
|
-
merge(redirect_header_options)
|
14
|
+
redirect_headers = signed_in_resource.create_named_token_pair
|
15
|
+
.merge(redirect_header_options)
|
23
16
|
|
24
|
-
# TODO: add a refresh token cookie in the response.
|
25
17
|
update_refresh_token_cookie
|
26
|
-
|
27
|
-
#redirect_to_link = signed_in_resource.build_auth_url(redirect_url, redirect_headers)
|
18
|
+
|
19
|
+
# redirect_to_link = signed_in_resource.build_auth_url(redirect_url, redirect_headers)
|
28
20
|
redirect_to_link = DeviseJwtAuth::Url.generate(redirect_url, redirect_headers)
|
29
21
|
else
|
30
22
|
redirect_to_link = DeviseJwtAuth::Url.generate(redirect_url, redirect_header_options)
|
@@ -46,11 +38,11 @@ module DeviseJwtAuth
|
|
46
38
|
return render_not_found_error unless @resource
|
47
39
|
|
48
40
|
@resource.send_confirmation_instructions({
|
49
|
-
|
50
|
-
|
51
|
-
|
41
|
+
redirect_url: redirect_url,
|
42
|
+
client_config: resource_params[:config_name]
|
43
|
+
})
|
52
44
|
|
53
|
-
|
45
|
+
render_create_success
|
54
46
|
end
|
55
47
|
|
56
48
|
protected
|
@@ -61,8 +53,8 @@ module DeviseJwtAuth
|
|
61
53
|
|
62
54
|
def render_create_success
|
63
55
|
render json: {
|
64
|
-
|
65
|
-
|
56
|
+
success: true,
|
57
|
+
message: I18n.t('devise_jwt_auth.confirmations.sended', email: @email)
|
66
58
|
}
|
67
59
|
end
|
68
60
|
|
@@ -83,6 +75,5 @@ module DeviseJwtAuth
|
|
83
75
|
DeviseJwtAuth.default_confirm_success_url
|
84
76
|
)
|
85
77
|
end
|
86
|
-
|
87
78
|
end
|
88
79
|
end
|
@@ -7,12 +7,10 @@ module DeviseJwtAuth
|
|
7
7
|
before_action :validate_auth_origin_url_param
|
8
8
|
|
9
9
|
skip_before_action :set_user_by_jwt_token, raise: false
|
10
|
-
# skip_after_action :update_auth_header
|
11
10
|
|
12
11
|
# intermediary route for successful omniauth authentication. omniauth does
|
13
12
|
# not support multiple models, so we must resort to this terrible hack.
|
14
13
|
def redirect_callbacks
|
15
|
-
|
16
14
|
# derive target redirect route from 'resource_class' param, which was set
|
17
15
|
# before authentication.
|
18
16
|
devise_mapping = get_devise_mapping
|
@@ -20,8 +18,8 @@ module DeviseJwtAuth
|
|
20
18
|
|
21
19
|
# preserve omniauth info for success route. ignore 'extra' in twitter
|
22
20
|
# auth response to avoid CookieOverflow.
|
23
|
-
session['
|
24
|
-
session['
|
21
|
+
session['dja.omniauth.auth'] = request.env['omniauth.auth'].except('extra')
|
22
|
+
session['dja.omniauth.params'] = request.env['omniauth.params']
|
25
23
|
|
26
24
|
redirect_to redirect_route
|
27
25
|
end
|
@@ -29,15 +27,17 @@ module DeviseJwtAuth
|
|
29
27
|
def get_redirect_route(devise_mapping)
|
30
28
|
path = "#{Devise.mappings[devise_mapping.to_sym].fullpath}/#{params[:provider]}/callback"
|
31
29
|
klass = request.scheme == 'https' ? URI::HTTPS : URI::HTTP
|
32
|
-
|
30
|
+
klass.build(host: request.host, port: request.port, path: path).to_s
|
33
31
|
end
|
34
32
|
|
35
33
|
def get_devise_mapping
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
34
|
+
# derive target redirect route from 'resource_class' param, which was set
|
35
|
+
# before authentication.
|
36
|
+
[
|
37
|
+
request.env['omniauth.params']['namespace_name'],
|
38
|
+
request.env['omniauth.params']['resource_class'].underscore.gsub('/', '_')
|
39
|
+
].compact.join('_')
|
40
|
+
rescue NoMethodError
|
41
41
|
default_devise_mapping
|
42
42
|
end
|
43
43
|
|
@@ -45,13 +45,13 @@ module DeviseJwtAuth
|
|
45
45
|
# find the mapping in `omniauth.params`.
|
46
46
|
#
|
47
47
|
# One example use-case here is for IDP-initiated SAML login. In that
|
48
|
-
# case, there will have been no initial request in which to save
|
48
|
+
# case, there will have been no initial request in which to save
|
49
49
|
# the devise mapping. If you are in a situation like that, and
|
50
50
|
# your app allows for you to determine somehow what the devise
|
51
51
|
# mapping should be (because, for example, it is always the same),
|
52
52
|
# then you can handle it by overriding this method.
|
53
53
|
def default_devise_mapping
|
54
|
-
raise NotImplementedError
|
54
|
+
raise NotImplementedError, 'no default_devise_mapping set'
|
55
55
|
end
|
56
56
|
|
57
57
|
def omniauth_success
|
@@ -78,10 +78,11 @@ module DeviseJwtAuth
|
|
78
78
|
render_data_or_redirect('authFailure', error: @error)
|
79
79
|
end
|
80
80
|
|
81
|
-
def validate_auth_origin_url_param
|
82
|
-
return
|
81
|
+
def validate_auth_origin_url_param
|
82
|
+
return unless auth_origin_url && blacklisted_redirect_url?(auth_origin_url)
|
83
|
+
|
84
|
+
render_error_not_allowed_auth_origin_url
|
83
85
|
end
|
84
|
-
|
85
86
|
|
86
87
|
protected
|
87
88
|
|
@@ -89,25 +90,25 @@ module DeviseJwtAuth
|
|
89
90
|
# it. redirect_callbacks is called upon returning from successful omniauth
|
90
91
|
# authentication, and the target params live in an omniauth-specific
|
91
92
|
# request.env variable. this variable is then persisted thru the redirect
|
92
|
-
# using our own
|
93
|
+
# using our own dja.omniauth.params session var. the omniauth_success
|
93
94
|
# method will access that session var and then destroy it immediately
|
94
95
|
# after use. In the failure case, finally, the omniauth params
|
95
96
|
# are added as query params in our monkey patch to OmniAuth in engine.rb
|
96
97
|
def omniauth_params
|
97
98
|
unless defined?(@_omniauth_params)
|
98
|
-
if request.env['omniauth.params']
|
99
|
+
if request.env['omniauth.params']&.any?
|
99
100
|
@_omniauth_params = request.env['omniauth.params']
|
100
|
-
elsif session['
|
101
|
-
@_omniauth_params ||= session.delete('
|
101
|
+
elsif session['dja.omniauth.params']&.any?
|
102
|
+
@_omniauth_params ||= session.delete('dja.omniauth.params')
|
102
103
|
@_omniauth_params
|
103
104
|
elsif params['omniauth_window_type']
|
104
|
-
@_omniauth_params =
|
105
|
+
@_omniauth_params =
|
106
|
+
params.slice('omniauth_window_type', 'auth_origin_url', 'resource_class', 'origin')
|
105
107
|
else
|
106
108
|
@_omniauth_params = {}
|
107
109
|
end
|
108
110
|
end
|
109
111
|
@_omniauth_params
|
110
|
-
|
111
112
|
end
|
112
113
|
|
113
114
|
# break out provider attribute assignment for easy method extension
|
@@ -120,14 +121,13 @@ module DeviseJwtAuth
|
|
120
121
|
def whitelisted_params
|
121
122
|
whitelist = params_for_resource(:sign_up)
|
122
123
|
|
123
|
-
whitelist.
|
124
|
+
whitelist.each_with_object({}) do |key, coll|
|
124
125
|
param = omniauth_params[key.to_s]
|
125
126
|
coll[key] = param if param
|
126
|
-
coll
|
127
127
|
end
|
128
128
|
end
|
129
129
|
|
130
|
-
def resource_class(
|
130
|
+
def resource_class(_mapping = nil)
|
131
131
|
if omniauth_params['resource_class']
|
132
132
|
omniauth_params['resource_class'].constantize
|
133
133
|
elsif params['resource_class']
|
@@ -149,25 +149,25 @@ module DeviseJwtAuth
|
|
149
149
|
omniauth_params['auth_origin_url'] || omniauth_params['origin']
|
150
150
|
end
|
151
151
|
|
152
|
-
|
153
152
|
def auth_origin_url
|
154
|
-
if unsafe_auth_origin_url && blacklisted_redirect_url?(unsafe_auth_origin_url)
|
155
|
-
|
156
|
-
|
157
|
-
return unsafe_auth_origin_url
|
153
|
+
return nil if unsafe_auth_origin_url && blacklisted_redirect_url?(unsafe_auth_origin_url)
|
154
|
+
|
155
|
+
unsafe_auth_origin_url
|
158
156
|
end
|
159
157
|
|
160
158
|
# in the success case, omniauth_window_type is in the omniauth_params.
|
161
159
|
# in the failure case, it is in a query param. See monkey patch above
|
162
160
|
def omniauth_window_type
|
163
|
-
|
161
|
+
return params['omniauth_window_type'] if omniauth_params.nil?
|
162
|
+
|
163
|
+
omniauth_params['omniauth_window_type']
|
164
164
|
end
|
165
165
|
|
166
|
-
# this
|
166
|
+
# this session value is set by the redirect_callbacks method. its purpose
|
167
167
|
# is to persist the omniauth auth hash value thru a redirect. the value
|
168
168
|
# must be destroyed immediatly after it is accessed by omniauth_success
|
169
169
|
def auth_hash
|
170
|
-
@_auth_hash ||= session.delete('
|
170
|
+
@_auth_hash ||= session.delete('dja.omniauth.auth')
|
171
171
|
@_auth_hash
|
172
172
|
end
|
173
173
|
|
@@ -190,13 +190,6 @@ module DeviseJwtAuth
|
|
190
190
|
config: @config,
|
191
191
|
uid: @resource.uid
|
192
192
|
)
|
193
|
-
# @auth_params = {
|
194
|
-
# auth_token: @token.token,
|
195
|
-
# client_id: @token.client,
|
196
|
-
# uid: @resource.uid,
|
197
|
-
# expiry: @token.expiry,
|
198
|
-
# config: @config
|
199
|
-
# }
|
200
193
|
@auth_params.merge!(oauth_registration: true) if @oauth_registration
|
201
194
|
@auth_params
|
202
195
|
end
|
@@ -208,7 +201,10 @@ module DeviseJwtAuth
|
|
208
201
|
end
|
209
202
|
|
210
203
|
def render_error_not_allowed_auth_origin_url
|
211
|
-
message =
|
204
|
+
message =
|
205
|
+
I18n.t('devise_jwt_auth.omniauth.not_allowed_redirect_url',
|
206
|
+
redirect_url: unsafe_auth_origin_url)
|
207
|
+
|
212
208
|
render_data_or_redirect('authFailure', error: message)
|
213
209
|
end
|
214
210
|
|
@@ -218,7 +214,6 @@ module DeviseJwtAuth
|
|
218
214
|
end
|
219
215
|
|
220
216
|
def render_data_or_redirect(message, data, user_data = {})
|
221
|
-
|
222
217
|
# We handle inAppBrowser and newWindow the same, but it is nice
|
223
218
|
# to support values in case people need custom implementations for each case
|
224
219
|
# (For example, nbrustein does not allow new users to be created if logging in with
|
@@ -245,7 +240,7 @@ module DeviseJwtAuth
|
|
245
240
|
end
|
246
241
|
|
247
242
|
def fallback_render(text)
|
248
|
-
|
243
|
+
render inline: %(
|
249
244
|
|
250
245
|
<html>
|
251
246
|
<head></head>
|
@@ -271,9 +266,7 @@ module DeviseJwtAuth
|
|
271
266
|
provider: auth_hash['provider']
|
272
267
|
).first_or_initialize
|
273
268
|
|
274
|
-
if @resource.new_record?
|
275
|
-
handle_new_resource
|
276
|
-
end
|
269
|
+
handle_new_resource if @resource.new_record?
|
277
270
|
|
278
271
|
# sync user info with provider, update/generate auth token
|
279
272
|
assign_provider_attrs(@resource, auth_hash)
|
@@ -287,5 +280,4 @@ module DeviseJwtAuth
|
|
287
280
|
@resource
|
288
281
|
end
|
289
282
|
end
|
290
|
-
|
291
283
|
end
|
@@ -3,9 +3,8 @@
|
|
3
3
|
module DeviseJwtAuth
|
4
4
|
class PasswordsController < DeviseJwtAuth::ApplicationController
|
5
5
|
before_action :validate_redirect_url_param, only: [:create, :edit]
|
6
|
-
# skip_after_action :update_auth_header, only: [:create, :edit]
|
7
6
|
|
8
|
-
#
|
7
|
+
# This action is responsible for generating password reset tokens and sending emails
|
9
8
|
def create
|
10
9
|
return render_create_error_missing_email unless resource_params[:email]
|
11
10
|
|
@@ -17,12 +16,11 @@ module DeviseJwtAuth
|
|
17
16
|
@resource.send_reset_password_instructions(
|
18
17
|
email: @email,
|
19
18
|
provider: 'email',
|
20
|
-
redirect_url: @redirect_url
|
21
|
-
client_config: params[:config_name]
|
19
|
+
redirect_url: @redirect_url
|
22
20
|
)
|
23
21
|
|
24
22
|
if @resource.errors.empty?
|
25
|
-
|
23
|
+
render_create_success
|
26
24
|
else
|
27
25
|
render_create_error @resource.errors
|
28
26
|
end
|
@@ -31,17 +29,14 @@ module DeviseJwtAuth
|
|
31
29
|
end
|
32
30
|
end
|
33
31
|
|
34
|
-
#
|
32
|
+
# This is where users arrive after visiting the password reset confirmation link.
|
35
33
|
def edit
|
36
|
-
# if a user is not found, return nil
|
37
34
|
@resource = resource_class.with_reset_password_token(resource_params[:reset_password_token])
|
38
35
|
|
39
|
-
if @resource
|
40
|
-
# TODO: add a token invalidator
|
41
|
-
# token = @resource.create_token unless require_client_password_reset_token?
|
42
|
-
|
36
|
+
if @resource&.reset_password_period_valid?
|
43
37
|
# ensure that user is confirmed
|
44
38
|
@resource.skip_confirmation! if confirmable_enabled? && !@resource.confirmed_at
|
39
|
+
|
45
40
|
# allow user to change password once without current_password
|
46
41
|
@resource.allow_password_change = true if recoverable_enabled?
|
47
42
|
@resource.save!
|
@@ -49,19 +44,16 @@ module DeviseJwtAuth
|
|
49
44
|
yield @resource if block_given?
|
50
45
|
|
51
46
|
if require_client_password_reset_token?
|
52
|
-
|
53
|
-
else
|
54
|
-
redirect_header_options = { reset_password: true }
|
55
|
-
redirect_headers = @resource.create_named_token_pair.
|
56
|
-
merge(redirect_header_options)
|
47
|
+
clear_refresh_token_cookie
|
57
48
|
|
49
|
+
redirect_to DeviseJwtAuth::Url.generate(
|
50
|
+
@redirect_url,
|
51
|
+
reset_password_token: resource_params[:reset_password_token]
|
52
|
+
)
|
53
|
+
else
|
58
54
|
# TODO: do we put the refresh token here?
|
59
|
-
# we do if token exists (see line 41)
|
60
55
|
update_refresh_token_cookie
|
61
|
-
|
62
|
-
redirect_to_link = DeviseJwtAuth::Url.generate(@redirect_url, redirect_headers)
|
63
|
-
|
64
|
-
redirect_to redirect_to_link
|
56
|
+
redirect_to @redirect_url
|
65
57
|
end
|
66
58
|
else
|
67
59
|
render_edit_error
|
@@ -69,12 +61,11 @@ module DeviseJwtAuth
|
|
69
61
|
end
|
70
62
|
|
71
63
|
def update
|
72
|
-
#
|
64
|
+
# Make sure user is authorized. Either by a reset_password_token or a valid access token.
|
73
65
|
if require_client_password_reset_token? && resource_params[:reset_password_token]
|
74
66
|
@resource = resource_class.with_reset_password_token(resource_params[:reset_password_token])
|
75
|
-
return render_update_error_unauthorized unless @resource
|
76
67
|
|
77
|
-
|
68
|
+
return render_update_error_unauthorized unless @resource
|
78
69
|
else
|
79
70
|
@resource = set_user_by_token
|
80
71
|
end
|
@@ -82,9 +73,7 @@ module DeviseJwtAuth
|
|
82
73
|
return render_update_error_unauthorized unless @resource
|
83
74
|
|
84
75
|
# make sure account doesn't use oauth2 provider
|
85
|
-
unless @resource.provider == 'email'
|
86
|
-
return render_update_error_password_not_required
|
87
|
-
end
|
76
|
+
return render_update_error_password_not_required unless @resource.provider == 'email'
|
88
77
|
|
89
78
|
# ensure that password params were sent
|
90
79
|
unless password_resource_params[:password] && password_resource_params[:password_confirmation]
|
@@ -100,16 +89,20 @@ module DeviseJwtAuth
|
|
100
89
|
# send refresh cookie
|
101
90
|
# send access token
|
102
91
|
update_refresh_token_cookie
|
103
|
-
|
92
|
+
render_update_success
|
104
93
|
else
|
105
|
-
|
94
|
+
render_update_error
|
106
95
|
end
|
107
96
|
end
|
108
97
|
|
109
98
|
protected
|
110
99
|
|
111
100
|
def resource_update_method
|
112
|
-
allow_password_change =
|
101
|
+
allow_password_change =
|
102
|
+
recoverable_enabled? &&
|
103
|
+
@resource.allow_password_change == true ||
|
104
|
+
require_client_password_reset_token?
|
105
|
+
|
113
106
|
if DeviseJwtAuth.check_current_password_before_update == false || allow_password_change
|
114
107
|
'update'
|
115
108
|
else
|
@@ -128,9 +121,10 @@ module DeviseJwtAuth
|
|
128
121
|
def render_error_not_allowed_redirect_url
|
129
122
|
response = {
|
130
123
|
status: 'error',
|
131
|
-
data:
|
124
|
+
data: resource_data
|
132
125
|
}
|
133
|
-
message = I18n.t('devise_jwt_auth.passwords.not_allowed_redirect_url',
|
126
|
+
message = I18n.t('devise_jwt_auth.passwords.not_allowed_redirect_url',
|
127
|
+
redirect_url: @redirect_url)
|
134
128
|
render_error(422, message, response)
|
135
129
|
end
|
136
130
|
|
@@ -157,7 +151,8 @@ module DeviseJwtAuth
|
|
157
151
|
end
|
158
152
|
|
159
153
|
def render_update_error_password_not_required
|
160
|
-
render_error(422, I18n.t('devise_jwt_auth.passwords.password_not_required',
|
154
|
+
render_error(422, I18n.t('devise_jwt_auth.passwords.password_not_required',
|
155
|
+
provider: @resource.provider.humanize))
|
161
156
|
end
|
162
157
|
|
163
158
|
def render_update_error_missing_password
|
@@ -170,7 +165,7 @@ module DeviseJwtAuth
|
|
170
165
|
data: resource_data,
|
171
166
|
message: I18n.t('devise_jwt_auth.passwords.successfully_updated')
|
172
167
|
}.merge!(@resource.create_named_token_pair)
|
173
|
-
|
168
|
+
|
174
169
|
render json: response_body
|
175
170
|
end
|
176
171
|
|
@@ -203,11 +198,14 @@ module DeviseJwtAuth
|
|
203
198
|
)
|
204
199
|
|
205
200
|
return render_create_error_missing_redirect_url unless @redirect_url
|
206
|
-
|
201
|
+
|
202
|
+
render_error_not_allowed_redirect_url if blacklisted_redirect_url?(@redirect_url)
|
207
203
|
end
|
208
204
|
|
209
205
|
def reset_password_token_as_raw?(recoverable)
|
210
|
-
recoverable &&
|
206
|
+
recoverable &&
|
207
|
+
recoverable.reset_password_token.present? &&
|
208
|
+
!require_client_password_reset_token?
|
211
209
|
end
|
212
210
|
|
213
211
|
def require_client_password_reset_token?
|