devise_token_auth 1.0.0 → 1.2.2
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 +5 -5
- data/README.md +6 -3
- data/app/controllers/devise_token_auth/application_controller.rb +23 -3
- data/app/controllers/devise_token_auth/concerns/resource_finder.rb +24 -11
- data/app/controllers/devise_token_auth/concerns/set_user_by_token.rb +78 -57
- data/app/controllers/devise_token_auth/confirmations_controller.rb +69 -19
- data/app/controllers/devise_token_auth/omniauth_callbacks_controller.rb +89 -44
- data/app/controllers/devise_token_auth/passwords_controller.rb +55 -31
- data/app/controllers/devise_token_auth/registrations_controller.rb +33 -40
- data/app/controllers/devise_token_auth/sessions_controller.rb +36 -14
- data/app/controllers/devise_token_auth/unlocks_controller.rb +12 -7
- data/app/models/devise_token_auth/concerns/active_record_support.rb +14 -0
- data/app/models/devise_token_auth/concerns/confirmable_support.rb +28 -0
- data/app/models/devise_token_auth/concerns/mongoid_support.rb +19 -0
- data/app/models/devise_token_auth/concerns/tokens_serialization.rb +31 -0
- data/app/models/devise_token_auth/concerns/user.rb +79 -80
- data/app/models/devise_token_auth/concerns/user_omniauth_callbacks.rb +12 -5
- data/app/validators/{email_validator.rb → devise_token_auth_email_validator.rb} +11 -3
- data/app/views/devise_token_auth/omniauth_external_window.html.erb +1 -1
- data/config/locales/da-DK.yml +2 -0
- data/config/locales/de.yml +2 -0
- data/config/locales/en.yml +10 -0
- data/config/locales/es.yml +2 -0
- data/config/locales/fr.yml +2 -0
- data/config/locales/he.yml +52 -0
- data/config/locales/it.yml +2 -0
- data/config/locales/ja.yml +16 -2
- data/config/locales/ko.yml +51 -0
- data/config/locales/nl.yml +2 -0
- data/config/locales/pl.yml +6 -3
- data/config/locales/pt-BR.yml +2 -0
- data/config/locales/pt.yml +6 -3
- data/config/locales/ro.yml +2 -0
- data/config/locales/ru.yml +2 -0
- data/config/locales/sq.yml +2 -0
- data/config/locales/sv.yml +2 -0
- data/config/locales/uk.yml +2 -0
- data/config/locales/vi.yml +2 -0
- data/config/locales/zh-CN.yml +2 -0
- data/config/locales/zh-HK.yml +2 -0
- data/config/locales/zh-TW.yml +2 -0
- data/lib/devise_token_auth/blacklist.rb +6 -0
- data/lib/devise_token_auth/controllers/helpers.rb +5 -9
- data/lib/devise_token_auth/engine.rb +17 -2
- data/lib/devise_token_auth/rails/routes.rb +22 -16
- data/lib/devise_token_auth/token_factory.rb +126 -0
- data/lib/devise_token_auth/url.rb +3 -0
- data/lib/devise_token_auth/version.rb +1 -1
- data/lib/devise_token_auth.rb +6 -3
- data/lib/generators/devise_token_auth/USAGE +1 -1
- data/lib/generators/devise_token_auth/install_generator.rb +7 -91
- data/lib/generators/devise_token_auth/install_generator_helpers.rb +98 -0
- data/lib/generators/devise_token_auth/install_mongoid_generator.rb +46 -0
- data/lib/generators/devise_token_auth/templates/devise_token_auth.rb +21 -5
- data/lib/generators/devise_token_auth/templates/devise_token_auth_create_users.rb.erb +1 -8
- data/lib/generators/devise_token_auth/templates/user.rb.erb +2 -2
- data/lib/generators/devise_token_auth/templates/user_mongoid.rb.erb +56 -0
- 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/demo_mang_controller_test.rb +37 -8
- data/test/controllers/demo_user_controller_test.rb +39 -10
- data/test/controllers/devise_token_auth/confirmations_controller_test.rb +170 -22
- data/test/controllers/devise_token_auth/omniauth_callbacks_controller_test.rb +117 -53
- data/test/controllers/devise_token_auth/passwords_controller_test.rb +299 -122
- data/test/controllers/devise_token_auth/registrations_controller_test.rb +56 -16
- data/test/controllers/devise_token_auth/sessions_controller_test.rb +139 -75
- data/test/controllers/devise_token_auth/token_validations_controller_test.rb +43 -2
- data/test/controllers/devise_token_auth/unlocks_controller_test.rb +44 -5
- data/test/controllers/overrides/confirmations_controller_test.rb +1 -1
- data/test/controllers/overrides/omniauth_callbacks_controller_test.rb +1 -1
- data/test/dummy/app/active_record/confirmable_user.rb +11 -0
- data/test/dummy/app/{models → active_record}/scoped_user.rb +2 -2
- data/test/dummy/app/{models → active_record}/unconfirmable_user.rb +1 -2
- data/test/dummy/app/{models → active_record}/unregisterable_user.rb +3 -3
- data/test/dummy/app/active_record/user.rb +6 -0
- data/test/dummy/app/controllers/application_controller.rb +2 -6
- data/test/dummy/app/controllers/overrides/confirmations_controller.rb +5 -4
- data/test/dummy/app/controllers/overrides/passwords_controller.rb +5 -4
- data/test/dummy/app/controllers/overrides/registrations_controller.rb +1 -1
- data/test/dummy/app/controllers/overrides/sessions_controller.rb +2 -2
- data/test/dummy/app/models/{user.rb → concerns/favorite_color.rb} +7 -8
- data/test/dummy/app/mongoid/confirmable_user.rb +52 -0
- data/test/dummy/app/mongoid/lockable_user.rb +38 -0
- data/test/dummy/app/mongoid/mang.rb +46 -0
- data/test/dummy/app/mongoid/only_email_user.rb +33 -0
- data/test/dummy/app/mongoid/scoped_user.rb +50 -0
- data/test/dummy/app/mongoid/unconfirmable_user.rb +44 -0
- data/test/dummy/app/mongoid/unregisterable_user.rb +47 -0
- data/test/dummy/app/mongoid/user.rb +49 -0
- data/test/dummy/app/views/layouts/application.html.erb +0 -2
- data/test/dummy/config/application.rb +22 -1
- data/test/dummy/config/boot.rb +4 -0
- data/test/dummy/config/environments/development.rb +0 -10
- data/test/dummy/config/environments/production.rb +0 -16
- data/test/dummy/config/environments/test.rb +6 -2
- data/test/dummy/config/initializers/devise.rb +285 -0
- data/test/dummy/config/initializers/devise_token_auth.rb +35 -4
- data/test/dummy/config/initializers/figaro.rb +1 -1
- data/test/dummy/config/initializers/omniauth.rb +1 -0
- data/test/dummy/config/routes.rb +2 -0
- data/test/dummy/db/migrate/20140715061447_devise_token_auth_create_users.rb +0 -7
- data/test/dummy/db/migrate/20140715061805_devise_token_auth_create_mangs.rb +0 -7
- data/test/dummy/db/migrate/20141222035835_devise_token_auth_create_only_email_users.rb +0 -7
- data/test/dummy/db/migrate/20141222053502_devise_token_auth_create_unregisterable_users.rb +0 -7
- data/test/dummy/db/migrate/20150708104536_devise_token_auth_create_unconfirmable_users.rb +0 -7
- data/test/dummy/db/migrate/20160103235141_devise_token_auth_create_scoped_users.rb +0 -7
- data/test/dummy/db/migrate/20160629184441_devise_token_auth_create_lockable_users.rb +0 -7
- data/test/dummy/db/migrate/20190924101113_devise_token_auth_create_confirmable_users.rb +49 -0
- data/test/dummy/db/schema.rb +31 -33
- data/test/dummy/tmp/generators/app/models/user.rb +9 -0
- data/test/dummy/tmp/generators/config/initializers/devise_token_auth.rb +66 -0
- data/test/dummy/tmp/generators/db/migrate/20230415183419_devise_token_auth_create_users.rb +49 -0
- data/test/factories/users.rb +3 -2
- data/test/lib/devise_token_auth/blacklist_test.rb +19 -0
- data/test/lib/devise_token_auth/rails/custom_routes_test.rb +29 -0
- data/test/lib/devise_token_auth/rails/routes_test.rb +87 -0
- data/test/lib/devise_token_auth/token_factory_test.rb +191 -0
- data/test/lib/devise_token_auth/url_test.rb +2 -2
- data/test/lib/generators/devise_token_auth/install_generator_test.rb +51 -31
- data/test/lib/generators/devise_token_auth/install_generator_with_namespace_test.rb +51 -31
- data/test/models/concerns/mongoid_support_test.rb +31 -0
- data/test/models/concerns/tokens_serialization_test.rb +104 -0
- data/test/models/confirmable_user_test.rb +35 -0
- data/test/models/only_email_user_test.rb +0 -8
- data/test/models/user_test.rb +13 -23
- data/test/test_helper.rb +45 -4
- metadata +190 -97
- data/config/initializers/devise.rb +0 -198
- data/test/dummy/config/initializers/assets.rb +0 -10
- data/test/dummy/tmp/generators/app/views/devise/mailer/confirmation_instructions.html.erb +0 -5
- data/test/dummy/tmp/generators/app/views/devise/mailer/reset_password_instructions.html.erb +0 -8
- /data/test/dummy/app/{models → active_record}/lockable_user.rb +0 -0
- /data/test/dummy/app/{models → active_record}/mang.rb +0 -0
- /data/test/dummy/app/{models → active_record}/only_email_user.rb +0 -0
@@ -3,6 +3,9 @@
|
|
3
3
|
module DeviseTokenAuth
|
4
4
|
class OmniauthCallbacksController < DeviseTokenAuth::ApplicationController
|
5
5
|
attr_reader :auth_params
|
6
|
+
|
7
|
+
before_action :validate_auth_origin_url_param
|
8
|
+
|
6
9
|
skip_before_action :set_user_by_token, raise: false
|
7
10
|
skip_after_action :update_auth_header
|
8
11
|
|
@@ -12,18 +15,43 @@ module DeviseTokenAuth
|
|
12
15
|
|
13
16
|
# derive target redirect route from 'resource_class' param, which was set
|
14
17
|
# before authentication.
|
15
|
-
devise_mapping =
|
16
|
-
|
17
|
-
path = "#{Devise.mappings[devise_mapping.to_sym].fullpath}/#{params[:provider]}/callback"
|
18
|
-
klass = request.scheme == 'https' ? URI::HTTPS : URI::HTTP
|
19
|
-
redirect_route = klass.build(host: request.host, port: request.port, path: path).to_s
|
18
|
+
devise_mapping = get_devise_mapping
|
19
|
+
redirect_route = get_redirect_route(devise_mapping)
|
20
20
|
|
21
21
|
# preserve omniauth info for success route. ignore 'extra' in twitter
|
22
22
|
# auth response to avoid CookieOverflow.
|
23
23
|
session['dta.omniauth.auth'] = request.env['omniauth.auth'].except('extra')
|
24
24
|
session['dta.omniauth.params'] = request.env['omniauth.params']
|
25
25
|
|
26
|
-
redirect_to redirect_route
|
26
|
+
redirect_to redirect_route, {status: 307}.merge(redirect_options)
|
27
|
+
end
|
28
|
+
|
29
|
+
def get_redirect_route(devise_mapping)
|
30
|
+
path = "#{Devise.mappings[devise_mapping.to_sym].fullpath}/#{params[:provider]}/callback"
|
31
|
+
klass = request.scheme == 'https' ? URI::HTTPS : URI::HTTP
|
32
|
+
redirect_route = klass.build(host: request.host, port: request.port, path: path).to_s
|
33
|
+
end
|
34
|
+
|
35
|
+
def get_devise_mapping
|
36
|
+
# derive target redirect route from 'resource_class' param, which was set
|
37
|
+
# before authentication.
|
38
|
+
devise_mapping = [request.env['omniauth.params']['namespace_name'],
|
39
|
+
request.env['omniauth.params']['resource_class'].underscore.gsub('/', '_')].compact.join('_')
|
40
|
+
rescue NoMethodError => err
|
41
|
+
default_devise_mapping
|
42
|
+
end
|
43
|
+
|
44
|
+
# This method will only be called if `get_devise_mapping` cannot
|
45
|
+
# find the mapping in `omniauth.params`.
|
46
|
+
#
|
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
|
49
|
+
# the devise mapping. If you are in a situation like that, and
|
50
|
+
# your app allows for you to determine somehow what the devise
|
51
|
+
# mapping should be (because, for example, it is always the same),
|
52
|
+
# then you can handle it by overriding this method.
|
53
|
+
def default_devise_mapping
|
54
|
+
raise NotImplementedError.new('no default_devise_mapping set')
|
27
55
|
end
|
28
56
|
|
29
57
|
def omniauth_success
|
@@ -42,6 +70,10 @@ module DeviseTokenAuth
|
|
42
70
|
|
43
71
|
yield @resource if block_given?
|
44
72
|
|
73
|
+
if DeviseTokenAuth.cookie_enabled
|
74
|
+
set_token_in_cookie(@resource, @token)
|
75
|
+
end
|
76
|
+
|
45
77
|
render_data_or_redirect('deliverCredentials', @auth_params.as_json, @resource.as_json)
|
46
78
|
end
|
47
79
|
|
@@ -50,6 +82,11 @@ module DeviseTokenAuth
|
|
50
82
|
render_data_or_redirect('authFailure', error: @error)
|
51
83
|
end
|
52
84
|
|
85
|
+
def validate_auth_origin_url_param
|
86
|
+
return render_error_not_allowed_auth_origin_url if auth_origin_url && blacklisted_redirect_url?(auth_origin_url)
|
87
|
+
end
|
88
|
+
|
89
|
+
|
53
90
|
protected
|
54
91
|
|
55
92
|
# this will be determined differently depending on the action that calls
|
@@ -74,12 +111,12 @@ module DeviseTokenAuth
|
|
74
111
|
end
|
75
112
|
end
|
76
113
|
@_omniauth_params
|
77
|
-
|
78
114
|
end
|
79
115
|
|
80
116
|
# break out provider attribute assignment for easy method extension
|
81
117
|
def assign_provider_attrs(user, auth_hash)
|
82
|
-
attrs = auth_hash['info'].
|
118
|
+
attrs = auth_hash['info'].to_hash
|
119
|
+
attrs = attrs.slice(*user.attribute_names)
|
83
120
|
user.assign_attributes(attrs)
|
84
121
|
end
|
85
122
|
|
@@ -95,25 +132,29 @@ module DeviseTokenAuth
|
|
95
132
|
end
|
96
133
|
|
97
134
|
def resource_class(mapping = nil)
|
98
|
-
if
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
135
|
+
return @resource_class if defined?(@resource_class)
|
136
|
+
|
137
|
+
constant_name = omniauth_params['resource_class'].presence || params['resource_class'].presence
|
138
|
+
@resource_class = ObjectSpace.each_object(Class).detect { |cls| cls.to_s == constant_name && cls.pretty_print_inspect.starts_with?(constant_name) }
|
139
|
+
raise 'No resource_class found' if @resource_class.nil?
|
140
|
+
|
141
|
+
@resource_class
|
105
142
|
end
|
106
143
|
|
107
144
|
def resource_name
|
108
145
|
resource_class
|
109
146
|
end
|
110
147
|
|
111
|
-
def
|
112
|
-
omniauth_params['
|
148
|
+
def unsafe_auth_origin_url
|
149
|
+
omniauth_params['auth_origin_url'] || omniauth_params['origin']
|
113
150
|
end
|
114
151
|
|
152
|
+
|
115
153
|
def auth_origin_url
|
116
|
-
|
154
|
+
if unsafe_auth_origin_url && blacklisted_redirect_url?(unsafe_auth_origin_url)
|
155
|
+
return nil
|
156
|
+
end
|
157
|
+
return unsafe_auth_origin_url
|
117
158
|
end
|
118
159
|
|
119
160
|
# in the success case, omniauth_window_type is in the omniauth_params.
|
@@ -122,12 +163,11 @@ module DeviseTokenAuth
|
|
122
163
|
omniauth_params.nil? ? params['omniauth_window_type'] : omniauth_params['omniauth_window_type']
|
123
164
|
end
|
124
165
|
|
125
|
-
# this
|
166
|
+
# this session value is set by the redirect_callbacks method. its purpose
|
126
167
|
# is to persist the omniauth auth hash value thru a redirect. the value
|
127
|
-
# must be destroyed
|
168
|
+
# must be destroyed immediately after it is accessed by omniauth_success
|
128
169
|
def auth_hash
|
129
170
|
@_auth_hash ||= session.delete('dta.omniauth.auth')
|
130
|
-
@_auth_hash
|
131
171
|
end
|
132
172
|
|
133
173
|
# ensure that this controller responds to :devise_controller? conditionals.
|
@@ -136,16 +176,6 @@ module DeviseTokenAuth
|
|
136
176
|
true
|
137
177
|
end
|
138
178
|
|
139
|
-
# necessary for access to devise_parameter_sanitizers
|
140
|
-
def devise_mapping
|
141
|
-
if omniauth_params
|
142
|
-
Devise.mappings[[omniauth_params['namespace_name'],
|
143
|
-
omniauth_params['resource_class'].underscore].compact.join('_').to_sym]
|
144
|
-
else
|
145
|
-
request.env['devise.mapping']
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
179
|
def set_random_password
|
150
180
|
# set crazy password for new oauth users. this is only used to prevent
|
151
181
|
# access via email sign-in.
|
@@ -156,11 +186,11 @@ module DeviseTokenAuth
|
|
156
186
|
|
157
187
|
def create_auth_params
|
158
188
|
@auth_params = {
|
159
|
-
auth_token:
|
160
|
-
client_id:
|
161
|
-
uid:
|
162
|
-
expiry:
|
163
|
-
config:
|
189
|
+
auth_token: @token.token,
|
190
|
+
client_id: @token.client,
|
191
|
+
uid: @resource.uid,
|
192
|
+
expiry: @token.expiry,
|
193
|
+
config: @config
|
164
194
|
}
|
165
195
|
@auth_params.merge!(oauth_registration: true) if @oauth_registration
|
166
196
|
@auth_params
|
@@ -168,11 +198,16 @@ module DeviseTokenAuth
|
|
168
198
|
|
169
199
|
def set_token_on_resource
|
170
200
|
@config = omniauth_params['config_name']
|
171
|
-
@
|
201
|
+
@token = @resource.create_token
|
202
|
+
end
|
203
|
+
|
204
|
+
def render_error_not_allowed_auth_origin_url
|
205
|
+
message = I18n.t('devise_token_auth.omniauth.not_allowed_redirect_url', redirect_url: unsafe_auth_origin_url)
|
206
|
+
render_data_or_redirect('authFailure', error: message)
|
172
207
|
end
|
173
208
|
|
174
209
|
def render_data(message, data)
|
175
|
-
@data = data.merge(message: message)
|
210
|
+
@data = data.merge(message: ActionController::Base.helpers.sanitize(message))
|
176
211
|
render layout: nil, template: 'devise_token_auth/omniauth_external_window'
|
177
212
|
end
|
178
213
|
|
@@ -192,7 +227,7 @@ module DeviseTokenAuth
|
|
192
227
|
elsif auth_origin_url # default to same-window implementation, which forwards back to auth_origin_url
|
193
228
|
|
194
229
|
# build and redirect to destination url
|
195
|
-
redirect_to DeviseTokenAuth::Url.generate(auth_origin_url, data.merge(blank: true))
|
230
|
+
redirect_to DeviseTokenAuth::Url.generate(auth_origin_url, data.merge(blank: true).merge(redirect_options))
|
196
231
|
else
|
197
232
|
|
198
233
|
# there SHOULD always be an auth_origin_url, but if someone does something silly
|
@@ -209,11 +244,20 @@ module DeviseTokenAuth
|
|
209
244
|
<html>
|
210
245
|
<head></head>
|
211
246
|
<body>
|
212
|
-
#{text}
|
247
|
+
#{ActionController::Base.helpers.sanitize(text)}
|
213
248
|
</body>
|
214
249
|
</html>)
|
215
250
|
end
|
216
251
|
|
252
|
+
def handle_new_resource
|
253
|
+
@oauth_registration = true
|
254
|
+
set_random_password
|
255
|
+
end
|
256
|
+
|
257
|
+
def assign_whitelisted_params?
|
258
|
+
true
|
259
|
+
end
|
260
|
+
|
217
261
|
def get_resource_from_auth_hash
|
218
262
|
# find or create user by provider and provider uid
|
219
263
|
@resource = resource_class.where(
|
@@ -222,16 +266,17 @@ module DeviseTokenAuth
|
|
222
266
|
).first_or_initialize
|
223
267
|
|
224
268
|
if @resource.new_record?
|
225
|
-
|
226
|
-
set_random_password
|
269
|
+
handle_new_resource
|
227
270
|
end
|
228
271
|
|
229
272
|
# sync user info with provider, update/generate auth token
|
230
273
|
assign_provider_attrs(@resource, auth_hash)
|
231
274
|
|
232
275
|
# assign any additional (whitelisted) attributes
|
233
|
-
|
234
|
-
|
276
|
+
if assign_whitelisted_params?
|
277
|
+
extra_params = whitelisted_params
|
278
|
+
@resource.assign_attributes(extra_params) if extra_params
|
279
|
+
end
|
235
280
|
|
236
281
|
@resource
|
237
282
|
end
|
@@ -2,23 +2,13 @@
|
|
2
2
|
|
3
3
|
module DeviseTokenAuth
|
4
4
|
class PasswordsController < DeviseTokenAuth::ApplicationController
|
5
|
-
before_action :
|
5
|
+
before_action :validate_redirect_url_param, only: [:create, :edit]
|
6
6
|
skip_after_action :update_auth_header, only: [:create, :edit]
|
7
7
|
|
8
|
-
# this action is responsible for generating password reset tokens and
|
9
|
-
# sending emails
|
8
|
+
# this action is responsible for generating password reset tokens and sending emails
|
10
9
|
def create
|
11
10
|
return render_create_error_missing_email unless resource_params[:email]
|
12
11
|
|
13
|
-
# give redirect value from params priority
|
14
|
-
@redirect_url = params.fetch(
|
15
|
-
:redirect_url,
|
16
|
-
DeviseTokenAuth.default_password_reset_url
|
17
|
-
)
|
18
|
-
|
19
|
-
return render_create_error_missing_redirect_url unless @redirect_url
|
20
|
-
return render_create_error_not_allowed_redirect_url if blacklisted_redirect_url?
|
21
|
-
|
22
12
|
@email = get_case_insensitive_field_from_resource_params(:email)
|
23
13
|
@resource = find_resource(:uid, @email)
|
24
14
|
|
@@ -44,14 +34,13 @@ module DeviseTokenAuth
|
|
44
34
|
# this is where users arrive after visiting the password reset confirmation link
|
45
35
|
def edit
|
46
36
|
# if a user is not found, return nil
|
47
|
-
@resource = with_reset_password_token(resource_params[:reset_password_token])
|
37
|
+
@resource = resource_class.with_reset_password_token(resource_params[:reset_password_token])
|
48
38
|
|
49
39
|
if @resource && @resource.reset_password_period_valid?
|
50
|
-
|
40
|
+
token = @resource.create_token unless require_client_password_reset_token?
|
51
41
|
|
52
42
|
# ensure that user is confirmed
|
53
43
|
@resource.skip_confirmation! if confirmable_enabled? && !@resource.confirmed_at
|
54
|
-
|
55
44
|
# allow user to change password once without current_password
|
56
45
|
@resource.allow_password_change = true if recoverable_enabled?
|
57
46
|
|
@@ -59,12 +48,22 @@ module DeviseTokenAuth
|
|
59
48
|
|
60
49
|
yield @resource if block_given?
|
61
50
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
51
|
+
if require_client_password_reset_token?
|
52
|
+
redirect_to DeviseTokenAuth::Url.generate(@redirect_url, reset_password_token: resource_params[:reset_password_token]),
|
53
|
+
redirect_options
|
54
|
+
else
|
55
|
+
if DeviseTokenAuth.cookie_enabled
|
56
|
+
set_token_in_cookie(@resource, token)
|
57
|
+
end
|
58
|
+
|
59
|
+
redirect_header_options = { reset_password: true }
|
60
|
+
redirect_headers = build_redirect_headers(token.token,
|
61
|
+
token.client,
|
62
|
+
redirect_header_options)
|
63
|
+
redirect_to(@resource.build_auth_url(@redirect_url,
|
64
|
+
redirect_headers),
|
65
|
+
redirect_options)
|
66
|
+
end
|
68
67
|
else
|
69
68
|
render_edit_error
|
70
69
|
end
|
@@ -72,6 +71,15 @@ module DeviseTokenAuth
|
|
72
71
|
|
73
72
|
def update
|
74
73
|
# make sure user is authorized
|
74
|
+
if require_client_password_reset_token? && resource_params[:reset_password_token]
|
75
|
+
@resource = resource_class.with_reset_password_token(resource_params[:reset_password_token])
|
76
|
+
return render_update_error_unauthorized unless @resource
|
77
|
+
|
78
|
+
@token = @resource.create_token
|
79
|
+
else
|
80
|
+
@resource = set_user_by_token
|
81
|
+
end
|
82
|
+
|
75
83
|
return render_update_error_unauthorized unless @resource
|
76
84
|
|
77
85
|
# make sure account doesn't use oauth2 provider
|
@@ -98,9 +106,9 @@ module DeviseTokenAuth
|
|
98
106
|
protected
|
99
107
|
|
100
108
|
def resource_update_method
|
101
|
-
allow_password_change = recoverable_enabled? && @resource.allow_password_change == true
|
109
|
+
allow_password_change = recoverable_enabled? && @resource.allow_password_change == true || require_client_password_reset_token?
|
102
110
|
if DeviseTokenAuth.check_current_password_before_update == false || allow_password_change
|
103
|
-
'
|
111
|
+
'update'
|
104
112
|
else
|
105
113
|
'update_with_password'
|
106
114
|
end
|
@@ -114,7 +122,7 @@ module DeviseTokenAuth
|
|
114
122
|
render_error(401, I18n.t('devise_token_auth.passwords.missing_redirect_url'))
|
115
123
|
end
|
116
124
|
|
117
|
-
def
|
125
|
+
def render_error_not_allowed_redirect_url
|
118
126
|
response = {
|
119
127
|
status: 'error',
|
120
128
|
data: resource_data
|
@@ -126,7 +134,7 @@ module DeviseTokenAuth
|
|
126
134
|
def render_create_success
|
127
135
|
render json: {
|
128
136
|
success: true,
|
129
|
-
message:
|
137
|
+
message: success_message('passwords', @email)
|
130
138
|
}
|
131
139
|
end
|
132
140
|
|
@@ -178,15 +186,31 @@ module DeviseTokenAuth
|
|
178
186
|
params.permit(*params_for_resource(:account_update))
|
179
187
|
end
|
180
188
|
|
181
|
-
def
|
182
|
-
|
189
|
+
def render_not_found_error
|
190
|
+
if Devise.paranoid
|
191
|
+
render_create_success
|
192
|
+
else
|
193
|
+
render_error(404, I18n.t('devise_token_auth.passwords.user_not_found', email: @email))
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def validate_redirect_url_param
|
198
|
+
# give redirect value from params priority
|
199
|
+
@redirect_url = params.fetch(
|
200
|
+
:redirect_url,
|
201
|
+
DeviseTokenAuth.default_password_reset_url
|
202
|
+
)
|
183
203
|
|
184
|
-
|
185
|
-
|
204
|
+
return render_create_error_missing_redirect_url unless @redirect_url
|
205
|
+
return render_error_not_allowed_redirect_url if blacklisted_redirect_url?(@redirect_url)
|
186
206
|
end
|
187
207
|
|
188
|
-
def
|
189
|
-
|
208
|
+
def reset_password_token_as_raw?(recoverable)
|
209
|
+
recoverable && recoverable.reset_password_token.present? && !require_client_password_reset_token?
|
210
|
+
end
|
211
|
+
|
212
|
+
def require_client_password_reset_token?
|
213
|
+
DeviseTokenAuth.require_client_password_reset_token
|
190
214
|
end
|
191
215
|
end
|
192
216
|
end
|
@@ -28,42 +28,40 @@ module DeviseTokenAuth
|
|
28
28
|
end
|
29
29
|
|
30
30
|
# if whitelist is set, validate redirect_url against whitelist
|
31
|
-
return render_create_error_redirect_url_not_allowed if blacklisted_redirect_url?
|
31
|
+
return render_create_error_redirect_url_not_allowed if blacklisted_redirect_url?(@redirect_url)
|
32
32
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
33
|
+
# override email confirmation, must be sent manually from ctrl
|
34
|
+
callback_name = defined?(ActiveRecord) && resource_class < ActiveRecord::Base ? :commit : :create
|
35
|
+
resource_class.set_callback(callback_name, :after, :send_on_create_confirmation_instructions)
|
36
|
+
resource_class.skip_callback(callback_name, :after, :send_on_create_confirmation_instructions)
|
37
37
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
38
|
+
if @resource.respond_to? :skip_confirmation_notification!
|
39
|
+
# Fix duplicate e-mails by disabling Devise confirmation e-mail
|
40
|
+
@resource.skip_confirmation_notification!
|
41
|
+
end
|
42
42
|
|
43
|
-
|
44
|
-
|
43
|
+
if @resource.save
|
44
|
+
yield @resource if block_given?
|
45
45
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
# user will require email authentication
|
53
|
-
@resource.send_confirmation_instructions(
|
54
|
-
client_config: params[:config_name],
|
55
|
-
redirect_url: @redirect_url
|
56
|
-
)
|
57
|
-
end
|
58
|
-
|
59
|
-
render_create_success
|
60
|
-
else
|
61
|
-
clean_up_passwords @resource
|
62
|
-
render_create_error
|
46
|
+
unless @resource.confirmed?
|
47
|
+
# user will require email authentication
|
48
|
+
@resource.send_confirmation_instructions({
|
49
|
+
client_config: params[:config_name],
|
50
|
+
redirect_url: @redirect_url
|
51
|
+
})
|
63
52
|
end
|
64
|
-
|
53
|
+
|
54
|
+
if active_for_authentication?
|
55
|
+
# email auth has been bypassed, authenticate user
|
56
|
+
@token = @resource.create_token
|
57
|
+
@resource.save!
|
58
|
+
update_auth_header
|
59
|
+
end
|
60
|
+
|
61
|
+
render_create_success
|
62
|
+
else
|
65
63
|
clean_up_passwords @resource
|
66
|
-
|
64
|
+
render_create_error
|
67
65
|
end
|
68
66
|
end
|
69
67
|
|
@@ -145,15 +143,6 @@ module DeviseTokenAuth
|
|
145
143
|
}, status: 422
|
146
144
|
end
|
147
145
|
|
148
|
-
def render_create_error_email_already_exists
|
149
|
-
response = {
|
150
|
-
status: 'error',
|
151
|
-
data: resource_data
|
152
|
-
}
|
153
|
-
message = I18n.t('devise_token_auth.registrations.email_already_exists', email: @resource.email)
|
154
|
-
render_error(422, message, response)
|
155
|
-
end
|
156
|
-
|
157
146
|
def render_update_success
|
158
147
|
render json: {
|
159
148
|
status: 'success',
|
@@ -193,7 +182,7 @@ module DeviseTokenAuth
|
|
193
182
|
elsif account_update_params.key?(:current_password)
|
194
183
|
'update_with_password'
|
195
184
|
else
|
196
|
-
'
|
185
|
+
'update'
|
197
186
|
end
|
198
187
|
end
|
199
188
|
|
@@ -208,5 +197,9 @@ module DeviseTokenAuth
|
|
208
197
|
def validate_post_data which, message
|
209
198
|
render_error(:unprocessable_entity, message, status: 'error') if which.empty?
|
210
199
|
end
|
200
|
+
|
201
|
+
def active_for_authentication?
|
202
|
+
!@resource.respond_to?(:active_for_authentication?) || @resource.active_for_authentication?
|
203
|
+
end
|
211
204
|
end
|
212
205
|
end
|
@@ -11,11 +11,7 @@ module DeviseTokenAuth
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def create
|
14
|
-
|
15
|
-
field = (resource_params.keys.map(&:to_sym) & resource_class.authentication_keys).first
|
16
|
-
|
17
|
-
@resource = nil
|
18
|
-
if field
|
14
|
+
if field = (resource_params.keys.map(&:to_sym) & resource_class.authentication_keys).first
|
19
15
|
q_value = get_case_insensitive_field_from_resource_params(field)
|
20
16
|
|
21
17
|
@resource = find_resource(field, q_value)
|
@@ -26,21 +22,22 @@ module DeviseTokenAuth
|
|
26
22
|
if (@resource.respond_to?(:valid_for_authentication?) && !@resource.valid_for_authentication? { valid_password }) || !valid_password
|
27
23
|
return render_create_error_bad_credentials
|
28
24
|
end
|
29
|
-
@client_id, @token = @resource.create_token
|
30
|
-
@resource.save
|
31
25
|
|
32
|
-
|
26
|
+
create_and_assign_token
|
27
|
+
|
28
|
+
sign_in(@resource, scope: :user, store: false, bypass: false)
|
33
29
|
|
34
30
|
yield @resource if block_given?
|
35
31
|
|
36
32
|
render_create_success
|
37
|
-
elsif @resource && !(!@resource.respond_to?(:active_for_authentication?) || @resource.active_for_authentication?)
|
33
|
+
elsif @resource && !Devise.paranoid && !(!@resource.respond_to?(:active_for_authentication?) || @resource.active_for_authentication?)
|
38
34
|
if @resource.respond_to?(:locked_at) && @resource.locked_at
|
39
35
|
render_create_error_account_locked
|
40
36
|
else
|
41
37
|
render_create_error_not_confirmed
|
42
38
|
end
|
43
39
|
else
|
40
|
+
hash_password_in_paranoid_mode
|
44
41
|
render_create_error_bad_credentials
|
45
42
|
end
|
46
43
|
end
|
@@ -48,13 +45,19 @@ module DeviseTokenAuth
|
|
48
45
|
def destroy
|
49
46
|
# remove auth instance variables so that after_action does not run
|
50
47
|
user = remove_instance_variable(:@resource) if @resource
|
51
|
-
|
52
|
-
|
48
|
+
client = @token.client
|
49
|
+
@token.clear!
|
53
50
|
|
54
|
-
if user &&
|
55
|
-
user.tokens.delete(
|
51
|
+
if user && client && user.tokens[client]
|
52
|
+
user.tokens.delete(client)
|
56
53
|
user.save!
|
57
54
|
|
55
|
+
if DeviseTokenAuth.cookie_enabled
|
56
|
+
# If a cookie is set with a domain specified then it must be deleted with that domain specified
|
57
|
+
# See https://api.rubyonrails.org/classes/ActionDispatch/Cookies.html
|
58
|
+
cookies.delete(DeviseTokenAuth.cookie_name, domain: DeviseTokenAuth.cookie_attributes[:domain])
|
59
|
+
end
|
60
|
+
|
58
61
|
yield user if block_given?
|
59
62
|
|
60
63
|
render_destroy_success
|
@@ -72,7 +75,6 @@ module DeviseTokenAuth
|
|
72
75
|
def get_auth_params
|
73
76
|
auth_key = nil
|
74
77
|
auth_val = nil
|
75
|
-
|
76
78
|
# iterate thru allowed auth keys, use first found
|
77
79
|
resource_class.authentication_keys.each do |k|
|
78
80
|
if resource_params[k]
|
@@ -127,5 +129,25 @@ module DeviseTokenAuth
|
|
127
129
|
def resource_params
|
128
130
|
params.permit(*params_for_resource(:sign_in))
|
129
131
|
end
|
132
|
+
|
133
|
+
def create_and_assign_token
|
134
|
+
if @resource.respond_to?(:with_lock)
|
135
|
+
@resource.with_lock do
|
136
|
+
@token = @resource.create_token
|
137
|
+
@resource.save!
|
138
|
+
end
|
139
|
+
else
|
140
|
+
@token = @resource.create_token
|
141
|
+
@resource.save!
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def hash_password_in_paranoid_mode
|
146
|
+
# In order to avoid timing attacks in paranoid mode, we want the password hash to be
|
147
|
+
# calculated even if no resource has been found. Devise's DatabaseAuthenticatable warden
|
148
|
+
# strategy handles this case similarly:
|
149
|
+
# https://github.com/heartcombo/devise/blob/main/lib/devise/strategies/database_authenticatable.rb
|
150
|
+
resource_class.new.password = resource_params[:password] if Devise.paranoid
|
151
|
+
end
|
130
152
|
end
|
131
153
|
end
|
@@ -34,17 +34,18 @@ module DeviseTokenAuth
|
|
34
34
|
def show
|
35
35
|
@resource = resource_class.unlock_access_by_token(params[:unlock_token])
|
36
36
|
|
37
|
-
if @resource
|
38
|
-
|
37
|
+
if @resource.persisted?
|
38
|
+
token = @resource.create_token
|
39
39
|
@resource.save!
|
40
40
|
yield @resource if block_given?
|
41
41
|
|
42
42
|
redirect_header_options = { unlock: true }
|
43
|
-
redirect_headers = build_redirect_headers(token,
|
44
|
-
|
43
|
+
redirect_headers = build_redirect_headers(token.token,
|
44
|
+
token.client,
|
45
45
|
redirect_header_options)
|
46
46
|
redirect_to(@resource.build_auth_url(after_unlock_path_for(@resource),
|
47
|
-
redirect_headers)
|
47
|
+
redirect_headers),
|
48
|
+
redirect_options)
|
48
49
|
else
|
49
50
|
render_show_error
|
50
51
|
end
|
@@ -63,7 +64,7 @@ module DeviseTokenAuth
|
|
63
64
|
def render_create_success
|
64
65
|
render json: {
|
65
66
|
success: true,
|
66
|
-
message:
|
67
|
+
message: success_message('unlocks', @email)
|
67
68
|
}
|
68
69
|
end
|
69
70
|
|
@@ -79,7 +80,11 @@ module DeviseTokenAuth
|
|
79
80
|
end
|
80
81
|
|
81
82
|
def render_not_found_error
|
82
|
-
|
83
|
+
if Devise.paranoid
|
84
|
+
render_create_success
|
85
|
+
else
|
86
|
+
render_error(404, I18n.t('devise_token_auth.unlocks.user_not_found', email: @email))
|
87
|
+
end
|
83
88
|
end
|
84
89
|
|
85
90
|
def resource_params
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module DeviseTokenAuth::Concerns::ActiveRecordSupport
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
included do
|
5
|
+
serialize :tokens, DeviseTokenAuth::Concerns::TokensSerialization
|
6
|
+
end
|
7
|
+
|
8
|
+
class_methods do
|
9
|
+
# It's abstract replacement .find_by
|
10
|
+
def dta_find_by(attrs = {})
|
11
|
+
find_by(attrs)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|