devise_token_auth 0.1.43 → 1.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.
Files changed (183) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +42 -895
  3. data/Rakefile +11 -4
  4. data/app/controllers/devise_token_auth/application_controller.rb +19 -8
  5. data/app/controllers/devise_token_auth/concerns/resource_finder.rb +26 -12
  6. data/app/controllers/devise_token_auth/concerns/set_user_by_token.rb +106 -85
  7. data/app/controllers/devise_token_auth/confirmations_controller.rb +73 -17
  8. data/app/controllers/devise_token_auth/omniauth_callbacks_controller.rb +95 -51
  9. data/app/controllers/devise_token_auth/passwords_controller.rb +65 -57
  10. data/app/controllers/devise_token_auth/registrations_controller.rb +61 -61
  11. data/app/controllers/devise_token_auth/sessions_controller.rb +22 -18
  12. data/app/controllers/devise_token_auth/token_validations_controller.rb +5 -3
  13. data/app/controllers/devise_token_auth/unlocks_controller.rb +20 -16
  14. data/app/models/devise_token_auth/concerns/active_record_support.rb +14 -0
  15. data/app/models/devise_token_auth/concerns/confirmable_support.rb +28 -0
  16. data/app/models/devise_token_auth/concerns/mongoid_support.rb +19 -0
  17. data/app/models/devise_token_auth/concerns/tokens_serialization.rb +31 -0
  18. data/app/models/devise_token_auth/concerns/user.rb +92 -100
  19. data/app/models/devise_token_auth/concerns/user_omniauth_callbacks.rb +8 -3
  20. data/app/validators/{email_validator.rb → devise_token_auth_email_validator.rb} +5 -3
  21. data/app/views/devise_token_auth/omniauth_external_window.html.erb +1 -1
  22. data/config/locales/da-DK.yml +11 -9
  23. data/config/locales/de.yml +2 -0
  24. data/config/locales/en.yml +10 -0
  25. data/config/locales/es.yml +2 -0
  26. data/config/locales/fr.yml +2 -0
  27. data/config/locales/he.yml +52 -0
  28. data/config/locales/it.yml +2 -0
  29. data/config/locales/ja.yml +4 -2
  30. data/config/locales/ko.yml +51 -0
  31. data/config/locales/nl.yml +2 -0
  32. data/config/locales/pl.yml +6 -3
  33. data/config/locales/pt-BR.yml +2 -0
  34. data/config/locales/pt.yml +6 -3
  35. data/config/locales/ro.yml +2 -0
  36. data/config/locales/ru.yml +2 -0
  37. data/config/locales/sq.yml +2 -0
  38. data/config/locales/sv.yml +52 -0
  39. data/config/locales/uk.yml +2 -0
  40. data/config/locales/vi.yml +2 -0
  41. data/config/locales/zh-CN.yml +2 -0
  42. data/config/locales/zh-HK.yml +2 -0
  43. data/config/locales/zh-TW.yml +2 -0
  44. data/lib/devise_token_auth/blacklist.rb +6 -0
  45. data/lib/devise_token_auth/controllers/helpers.rb +21 -13
  46. data/lib/devise_token_auth/controllers/url_helpers.rb +2 -0
  47. data/lib/devise_token_auth/engine.rb +26 -14
  48. data/lib/devise_token_auth/errors.rb +8 -0
  49. data/lib/devise_token_auth/rails/routes.rb +37 -30
  50. data/lib/devise_token_auth/token_factory.rb +126 -0
  51. data/lib/devise_token_auth/url.rb +11 -4
  52. data/lib/devise_token_auth/version.rb +3 -1
  53. data/lib/devise_token_auth.rb +11 -5
  54. data/lib/generators/devise_token_auth/USAGE +2 -2
  55. data/lib/generators/devise_token_auth/install_generator.rb +36 -105
  56. data/lib/generators/devise_token_auth/install_generator_helpers.rb +98 -0
  57. data/lib/generators/devise_token_auth/install_mongoid_generator.rb +46 -0
  58. data/lib/generators/devise_token_auth/install_views_generator.rb +7 -5
  59. data/lib/generators/devise_token_auth/templates/devise_token_auth.rb +12 -0
  60. data/lib/generators/devise_token_auth/templates/devise_token_auth_create_users.rb.erb +8 -14
  61. data/lib/generators/devise_token_auth/templates/user.rb.erb +9 -0
  62. data/lib/generators/devise_token_auth/templates/user_mongoid.rb.erb +56 -0
  63. data/lib/tasks/devise_token_auth_tasks.rake +2 -0
  64. data/test/controllers/custom/custom_confirmations_controller_test.rb +5 -1
  65. data/test/controllers/custom/custom_omniauth_callbacks_controller_test.rb +4 -0
  66. data/test/controllers/custom/custom_passwords_controller_test.rb +6 -2
  67. data/test/controllers/custom/custom_registrations_controller_test.rb +17 -8
  68. data/test/controllers/custom/custom_sessions_controller_test.rb +7 -5
  69. data/test/controllers/custom/custom_token_validations_controller_test.rb +5 -3
  70. data/test/controllers/demo_group_controller_test.rb +4 -6
  71. data/test/controllers/demo_mang_controller_test.rb +3 -3
  72. data/test/controllers/demo_user_controller_test.rb +53 -25
  73. data/test/controllers/devise_token_auth/confirmations_controller_test.rb +159 -25
  74. data/test/controllers/devise_token_auth/omniauth_callbacks_controller_test.rb +117 -47
  75. data/test/controllers/devise_token_auth/passwords_controller_test.rb +309 -126
  76. data/test/controllers/devise_token_auth/registrations_controller_test.rb +65 -23
  77. data/test/controllers/devise_token_auth/sessions_controller_test.rb +93 -61
  78. data/test/controllers/devise_token_auth/token_validations_controller_test.rb +18 -6
  79. data/test/controllers/devise_token_auth/unlocks_controller_test.rb +24 -5
  80. data/test/controllers/overrides/confirmations_controller_test.rb +6 -2
  81. data/test/controllers/overrides/omniauth_callbacks_controller_test.rb +5 -1
  82. data/test/controllers/overrides/passwords_controller_test.rb +27 -29
  83. data/test/controllers/overrides/registrations_controller_test.rb +33 -27
  84. data/test/controllers/overrides/sessions_controller_test.rb +6 -4
  85. data/test/controllers/overrides/token_validations_controller_test.rb +5 -3
  86. data/test/dummy/app/active_record/confirmable_user.rb +11 -0
  87. data/test/dummy/app/{models → active_record}/lockable_user.rb +2 -0
  88. data/test/dummy/app/{models → active_record}/mang.rb +2 -0
  89. data/test/dummy/app/{models → active_record}/only_email_user.rb +2 -0
  90. data/test/dummy/app/{models → active_record}/scoped_user.rb +4 -2
  91. data/test/dummy/app/{models → active_record}/unconfirmable_user.rb +3 -2
  92. data/test/dummy/app/active_record/unregisterable_user.rb +9 -0
  93. data/test/dummy/app/active_record/user.rb +6 -0
  94. data/test/dummy/app/controllers/application_controller.rb +2 -0
  95. data/test/dummy/app/controllers/auth_origin_controller.rb +2 -0
  96. data/test/dummy/app/controllers/custom/confirmations_controller.rb +2 -2
  97. data/test/dummy/app/controllers/custom/omniauth_callbacks_controller.rb +2 -0
  98. data/test/dummy/app/controllers/custom/passwords_controller.rb +3 -4
  99. data/test/dummy/app/controllers/custom/registrations_controller.rb +3 -3
  100. data/test/dummy/app/controllers/custom/sessions_controller.rb +3 -3
  101. data/test/dummy/app/controllers/custom/token_validations_controller.rb +3 -3
  102. data/test/dummy/app/controllers/demo_group_controller.rb +2 -0
  103. data/test/dummy/app/controllers/demo_mang_controller.rb +2 -0
  104. data/test/dummy/app/controllers/demo_user_controller.rb +2 -0
  105. data/test/dummy/app/controllers/overrides/confirmations_controller.rb +8 -6
  106. data/test/dummy/app/controllers/overrides/omniauth_callbacks_controller.rb +5 -3
  107. data/test/dummy/app/controllers/overrides/passwords_controller.rb +10 -8
  108. data/test/dummy/app/controllers/overrides/registrations_controller.rb +5 -3
  109. data/test/dummy/app/controllers/overrides/sessions_controller.rb +12 -12
  110. data/test/dummy/app/controllers/overrides/token_validations_controller.rb +5 -5
  111. data/test/dummy/app/helpers/application_helper.rb +1029 -1036
  112. data/test/dummy/app/models/{user.rb → concerns/favorite_color.rb} +8 -7
  113. data/test/dummy/app/mongoid/confirmable_user.rb +52 -0
  114. data/test/dummy/app/mongoid/lockable_user.rb +38 -0
  115. data/test/dummy/app/mongoid/mang.rb +46 -0
  116. data/test/dummy/app/mongoid/only_email_user.rb +33 -0
  117. data/test/dummy/app/mongoid/scoped_user.rb +50 -0
  118. data/test/dummy/app/mongoid/unconfirmable_user.rb +44 -0
  119. data/test/dummy/app/mongoid/unregisterable_user.rb +47 -0
  120. data/test/dummy/app/mongoid/user.rb +49 -0
  121. data/test/dummy/app/views/layouts/application.html.erb +0 -2
  122. data/test/dummy/config/application.rb +26 -3
  123. data/test/dummy/config/boot.rb +8 -2
  124. data/test/dummy/config/environment.rb +3 -1
  125. data/test/dummy/config/environments/development.rb +5 -13
  126. data/test/dummy/config/environments/production.rb +2 -16
  127. data/test/dummy/config/environments/test.rb +3 -1
  128. data/test/dummy/config/initializers/backtrace_silencers.rb +2 -0
  129. data/test/dummy/config/initializers/cookies_serializer.rb +3 -1
  130. data/test/dummy/config/initializers/devise.rb +287 -0
  131. data/test/dummy/config/initializers/devise_token_auth.rb +37 -4
  132. data/test/dummy/config/initializers/figaro.rb +3 -1
  133. data/test/dummy/config/initializers/filter_parameter_logging.rb +2 -0
  134. data/test/dummy/config/initializers/inflections.rb +2 -0
  135. data/test/dummy/config/initializers/mime_types.rb +2 -0
  136. data/test/dummy/config/initializers/omniauth.rb +5 -2
  137. data/test/dummy/config/initializers/session_store.rb +2 -0
  138. data/test/dummy/config/initializers/wrap_parameters.rb +2 -0
  139. data/test/dummy/config/routes.rb +14 -29
  140. data/test/dummy/config/spring.rb +2 -0
  141. data/test/dummy/config.ru +5 -3
  142. data/test/dummy/db/migrate/20140715061447_devise_token_auth_create_users.rb +9 -14
  143. data/test/dummy/db/migrate/20140715061805_devise_token_auth_create_mangs.rb +8 -13
  144. data/test/dummy/db/migrate/20140829044006_add_operating_thetan_to_user.rb +2 -0
  145. data/test/dummy/db/migrate/20140916224624_add_favorite_color_to_mangs.rb +2 -0
  146. data/test/dummy/db/migrate/20141222035835_devise_token_auth_create_only_email_users.rb +6 -11
  147. data/test/dummy/db/migrate/20141222053502_devise_token_auth_create_unregisterable_users.rb +8 -13
  148. data/test/dummy/db/migrate/20150708104536_devise_token_auth_create_unconfirmable_users.rb +8 -13
  149. data/test/dummy/db/migrate/20160103235141_devise_token_auth_create_scoped_users.rb +8 -13
  150. data/test/dummy/db/migrate/20160629184441_devise_token_auth_create_lockable_users.rb +8 -13
  151. data/test/dummy/{tmp/generators/db/migrate/20171014052631_devise_token_auth_create_users.rb → db/migrate/20190924101113_devise_token_auth_create_confirmable_users.rb} +8 -14
  152. data/test/dummy/db/schema.rb +11 -71
  153. data/test/dummy/lib/migration_database_helper.rb +15 -1
  154. data/test/dummy/tmp/generators/app/controllers/application_controller.rb +6 -0
  155. data/test/dummy/tmp/generators/app/models/azpire/v1/human_resource/user.rb +56 -0
  156. data/test/dummy/tmp/generators/config/initializers/devise_token_auth.rb +12 -0
  157. data/test/factories/users.rb +41 -0
  158. data/test/lib/devise_token_auth/blacklist_test.rb +19 -0
  159. data/test/lib/devise_token_auth/rails/custom_routes_test.rb +29 -0
  160. data/test/lib/devise_token_auth/rails/routes_test.rb +87 -0
  161. data/test/lib/devise_token_auth/token_factory_test.rb +191 -0
  162. data/test/lib/devise_token_auth/url_test.rb +9 -7
  163. data/test/lib/generators/devise_token_auth/install_generator_test.rb +67 -37
  164. data/test/lib/generators/devise_token_auth/install_generator_with_namespace_test.rb +222 -0
  165. data/test/lib/generators/devise_token_auth/install_views_generator_test.rb +3 -1
  166. data/test/models/concerns/mongoid_support_test.rb +31 -0
  167. data/test/models/concerns/tokens_serialization_test.rb +104 -0
  168. data/test/models/confirmable_user_test.rb +35 -0
  169. data/test/models/only_email_user_test.rb +2 -8
  170. data/test/models/user_test.rb +18 -79
  171. data/test/support/controllers/routes.rb +43 -0
  172. data/test/test_helper.rb +83 -26
  173. metadata +153 -44
  174. data/config/initializers/devise.rb +0 -196
  175. data/lib/generators/devise_token_auth/templates/user.rb +0 -7
  176. data/test/dummy/app/models/evil_user.rb +0 -3
  177. data/test/dummy/app/models/nice_user.rb +0 -7
  178. data/test/dummy/app/models/unregisterable_user.rb +0 -7
  179. data/test/dummy/config/initializers/assets.rb +0 -8
  180. data/test/dummy/db/migrate/20140928231203_devise_token_auth_create_evil_users.rb +0 -64
  181. data/test/dummy/db/migrate/20150409095712_devise_token_auth_create_nice_users.rb +0 -61
  182. data/test/dummy/tmp/generators/app/models/user.rb +0 -11
  183. data/test/integration/navigation_test.rb +0 -10
@@ -1,7 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DeviseTokenAuth
2
4
  class OmniauthCallbacksController < DeviseTokenAuth::ApplicationController
3
-
4
5
  attr_reader :auth_params
6
+
7
+ before_action :validate_auth_origin_url_param
8
+
5
9
  skip_before_action :set_user_by_token, raise: false
6
10
  skip_after_action :update_auth_header
7
11
 
@@ -11,11 +15,8 @@ module DeviseTokenAuth
11
15
 
12
16
  # derive target redirect route from 'resource_class' param, which was set
13
17
  # before authentication.
14
- devise_mapping = [request.env['omniauth.params']['namespace_name'],
15
- request.env['omniauth.params']['resource_class'].underscore.gsub('/', '_')].compact.join('_')
16
- path = "#{Devise.mappings[devise_mapping.to_sym].fullpath}/#{params[:provider]}/callback"
17
- klass = request.scheme == 'https' ? URI::HTTPS : URI::HTTP
18
- 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)
19
20
 
20
21
  # preserve omniauth info for success route. ignore 'extra' in twitter
21
22
  # auth response to avoid CookieOverflow.
@@ -25,6 +26,34 @@ module DeviseTokenAuth
25
26
  redirect_to redirect_route
26
27
  end
27
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')
55
+ end
56
+
28
57
  def omniauth_success
29
58
  get_resource_from_auth_hash
30
59
  set_token_on_resource
@@ -46,9 +75,14 @@ module DeviseTokenAuth
46
75
 
47
76
  def omniauth_failure
48
77
  @error = params[:message]
49
- render_data_or_redirect('authFailure', {error: @error})
78
+ render_data_or_redirect('authFailure', error: @error)
50
79
  end
51
80
 
81
+ def validate_auth_origin_url_param
82
+ return render_error_not_allowed_auth_origin_url if auth_origin_url && blacklisted_redirect_url?(auth_origin_url)
83
+ end
84
+
85
+
52
86
  protected
53
87
 
54
88
  # this will be determined differently depending on the action that calls
@@ -60,7 +94,7 @@ module DeviseTokenAuth
60
94
  # after use. In the failure case, finally, the omniauth params
61
95
  # are added as query params in our monkey patch to OmniAuth in engine.rb
62
96
  def omniauth_params
63
- if !defined?(@_omniauth_params)
97
+ unless defined?(@_omniauth_params)
64
98
  if request.env['omniauth.params'] && request.env['omniauth.params'].any?
65
99
  @_omniauth_params = request.env['omniauth.params']
66
100
  elsif session['dta.omniauth.params'] && session['dta.omniauth.params'].any?
@@ -78,7 +112,8 @@ module DeviseTokenAuth
78
112
 
79
113
  # break out provider attribute assignment for easy method extension
80
114
  def assign_provider_attrs(user, auth_hash)
81
- attrs = auth_hash['info'].slice(*user.attributes.keys)
115
+ attrs = auth_hash['info'].to_hash
116
+ attrs = attrs.slice(*user.attribute_names)
82
117
  user.assign_attributes(attrs)
83
118
  end
84
119
 
@@ -86,13 +121,11 @@ module DeviseTokenAuth
86
121
  def whitelisted_params
87
122
  whitelist = params_for_resource(:sign_up)
88
123
 
89
- whitelist.inject({}){|coll, key|
124
+ whitelist.inject({}) do |coll, key|
90
125
  param = omniauth_params[key.to_s]
91
- if param
92
- coll[key] = param
93
- end
126
+ coll[key] = param if param
94
127
  coll
95
- }
128
+ end
96
129
  end
97
130
 
98
131
  def resource_class(mapping = nil)
@@ -101,7 +134,7 @@ module DeviseTokenAuth
101
134
  elsif params['resource_class']
102
135
  params['resource_class'].constantize
103
136
  else
104
- raise "No resource_class found"
137
+ raise 'No resource_class found'
105
138
  end
106
139
  end
107
140
 
@@ -113,10 +146,18 @@ module DeviseTokenAuth
113
146
  omniauth_params['omniauth_window_type']
114
147
  end
115
148
 
116
- def auth_origin_url
149
+ def unsafe_auth_origin_url
117
150
  omniauth_params['auth_origin_url'] || omniauth_params['origin']
118
151
  end
119
152
 
153
+
154
+ def auth_origin_url
155
+ if unsafe_auth_origin_url && blacklisted_redirect_url?(unsafe_auth_origin_url)
156
+ return nil
157
+ end
158
+ return unsafe_auth_origin_url
159
+ end
160
+
120
161
  # in the success case, omniauth_window_type is in the omniauth_params.
121
162
  # in the failure case, it is in a query param. See monkey patch above
122
163
  def omniauth_window_type
@@ -137,31 +178,21 @@ module DeviseTokenAuth
137
178
  true
138
179
  end
139
180
 
140
- # necessary for access to devise_parameter_sanitizers
141
- def devise_mapping
142
- if omniauth_params
143
- Devise.mappings[[omniauth_params['namespace_name'],
144
- omniauth_params['resource_class'].underscore].compact.join('_').to_sym]
145
- else
146
- request.env['devise.mapping']
147
- end
148
- end
149
-
150
181
  def set_random_password
151
182
  # set crazy password for new oauth users. this is only used to prevent
152
- # access via email sign-in.
153
- p = SecureRandom.urlsafe_base64(nil, false)
154
- @resource.password = p
155
- @resource.password_confirmation = p
183
+ # access via email sign-in.
184
+ p = SecureRandom.urlsafe_base64(nil, false)
185
+ @resource.password = p
186
+ @resource.password_confirmation = p
156
187
  end
157
188
 
158
189
  def create_auth_params
159
190
  @auth_params = {
160
- auth_token: @token,
161
- client_id: @client_id,
162
- uid: @resource.uid,
163
- expiry: @expiry,
164
- config: @config
191
+ auth_token: @token.token,
192
+ client_id: @token.client,
193
+ uid: @resource.uid,
194
+ expiry: @token.expiry,
195
+ config: @config
165
196
  }
166
197
  @auth_params.merge!(oauth_registration: true) if @oauth_registration
167
198
  @auth_params
@@ -169,14 +200,17 @@ module DeviseTokenAuth
169
200
 
170
201
  def set_token_on_resource
171
202
  @config = omniauth_params['config_name']
172
- @client_id, @token, @expiry = @resource.create_token
203
+ @token = @resource.create_token
204
+ end
205
+
206
+ def render_error_not_allowed_auth_origin_url
207
+ message = I18n.t('devise_token_auth.omniauth.not_allowed_redirect_url', redirect_url: unsafe_auth_origin_url)
208
+ render_data_or_redirect('authFailure', error: message)
173
209
  end
174
210
 
175
211
  def render_data(message, data)
176
- @data = data.merge({
177
- message: message
178
- })
179
- render :layout => nil, :template => "devise_token_auth/omniauth_external_window"
212
+ @data = data.merge(message: ActionController::Base.helpers.sanitize(message))
213
+ render layout: nil, template: 'devise_token_auth/omniauth_external_window'
180
214
  end
181
215
 
182
216
  def render_data_or_redirect(message, data, user_data = {})
@@ -207,37 +241,47 @@ module DeviseTokenAuth
207
241
  end
208
242
 
209
243
  def fallback_render(text)
210
- render inline: %Q|
244
+ render inline: %Q(
211
245
 
212
246
  <html>
213
247
  <head></head>
214
248
  <body>
215
- #{text}
249
+ #{ActionController::Base.helpers.sanitize(text)}
216
250
  </body>
217
- </html>|
251
+ </html>)
252
+ end
253
+
254
+ def handle_new_resource
255
+ @oauth_registration = true
256
+ set_random_password
257
+ end
258
+
259
+ def assign_whitelisted_params?
260
+ true
218
261
  end
219
262
 
220
263
  def get_resource_from_auth_hash
221
264
  # find or create user by provider and provider uid
222
- @resource = resource_class.where({
223
- uid: auth_hash['uid'],
265
+ @resource = resource_class.where(
266
+ uid: auth_hash['uid'],
224
267
  provider: auth_hash['provider']
225
- }).first_or_initialize
268
+ ).first_or_initialize
226
269
 
227
270
  if @resource.new_record?
228
- @oauth_registration = true
229
- set_random_password
271
+ handle_new_resource
230
272
  end
231
273
 
232
274
  # sync user info with provider, update/generate auth token
233
275
  assign_provider_attrs(@resource, auth_hash)
234
276
 
235
277
  # assign any additional (whitelisted) attributes
236
- extra_params = whitelisted_params
237
- @resource.assign_attributes(extra_params) if extra_params
278
+ if assign_whitelisted_params?
279
+ extra_params = whitelisted_params
280
+ @resource.assign_attributes(extra_params) if extra_params
281
+ end
238
282
 
239
283
  @resource
240
284
  end
241
-
242
285
  end
286
+
243
287
  end
@@ -1,43 +1,25 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DeviseTokenAuth
2
4
  class PasswordsController < DeviseTokenAuth::ApplicationController
3
- before_action :set_user_by_token, :only => [:update]
4
- skip_after_action :update_auth_header, :only => [:create, :edit]
5
+ before_action :validate_redirect_url_param, only: [:create, :edit]
6
+ skip_after_action :update_auth_header, only: [:create, :edit]
5
7
 
6
- # this action is responsible for generating password reset tokens and
7
- # sending emails
8
+ # this action is responsible for generating password reset tokens and sending emails
8
9
  def create
9
- unless resource_params[:email]
10
- return render_create_error_missing_email
11
- end
12
-
13
- # give redirect value from params priority
14
- @redirect_url = params[:redirect_url]
15
-
16
- # fall back to default value if provided
17
- @redirect_url ||= DeviseTokenAuth.default_password_reset_url
18
-
19
- unless @redirect_url
20
- return render_create_error_missing_redirect_url
21
- end
22
-
23
- # if whitelist is set, validate redirect_url against whitelist
24
- if DeviseTokenAuth.redirect_whitelist
25
- unless DeviseTokenAuth::Url.whitelisted?(@redirect_url)
26
- return render_create_error_not_allowed_redirect_url
27
- end
28
- end
10
+ return render_create_error_missing_email unless resource_params[:email]
29
11
 
30
12
  @email = get_case_insensitive_field_from_resource_params(:email)
31
13
  @resource = find_resource(:uid, @email)
32
14
 
33
15
  if @resource
34
16
  yield @resource if block_given?
35
- @resource.send_reset_password_instructions({
17
+ @resource.send_reset_password_instructions(
36
18
  email: @email,
37
19
  provider: 'email',
38
20
  redirect_url: @redirect_url,
39
21
  client_config: params[:config_name]
40
- })
22
+ )
41
23
 
42
24
  if @resource.errors.empty?
43
25
  return render_create_success
@@ -52,14 +34,13 @@ module DeviseTokenAuth
52
34
  # this is where users arrive after visiting the password reset confirmation link
53
35
  def edit
54
36
  # if a user is not found, return nil
55
- @resource = with_reset_password_token(resource_params[:reset_password_token])
37
+ @resource = resource_class.with_reset_password_token(resource_params[:reset_password_token])
56
38
 
57
39
  if @resource && @resource.reset_password_period_valid?
58
- client_id, token = @resource.create_token
40
+ token = @resource.create_token unless require_client_password_reset_token?
59
41
 
60
42
  # ensure that user is confirmed
61
43
  @resource.skip_confirmation! if confirmable_enabled? && !@resource.confirmed_at
62
-
63
44
  # allow user to change password once without current_password
64
45
  @resource.allow_password_change = true if recoverable_enabled?
65
46
 
@@ -67,12 +48,16 @@ module DeviseTokenAuth
67
48
 
68
49
  yield @resource if block_given?
69
50
 
70
- redirect_header_options = {reset_password: true}
71
- redirect_headers = build_redirect_headers(token,
72
- client_id,
73
- redirect_header_options)
74
- redirect_to(@resource.build_auth_url(params[:redirect_url],
75
- redirect_headers))
51
+ if require_client_password_reset_token?
52
+ redirect_to DeviseTokenAuth::Url.generate(@redirect_url, reset_password_token: resource_params[:reset_password_token])
53
+ else
54
+ redirect_header_options = { reset_password: true }
55
+ redirect_headers = build_redirect_headers(token.token,
56
+ token.client,
57
+ redirect_header_options)
58
+ redirect_to(@resource.build_auth_url(@redirect_url,
59
+ redirect_headers))
60
+ end
76
61
  else
77
62
  render_edit_error
78
63
  end
@@ -80,10 +65,17 @@ module DeviseTokenAuth
80
65
 
81
66
  def update
82
67
  # make sure user is authorized
83
- unless @resource
84
- return render_update_error_unauthorized
68
+ if require_client_password_reset_token? && resource_params[:reset_password_token]
69
+ @resource = resource_class.with_reset_password_token(resource_params[:reset_password_token])
70
+ return render_update_error_unauthorized unless @resource
71
+
72
+ @token = @resource.create_token
73
+ else
74
+ @resource = set_user_by_token
85
75
  end
86
76
 
77
+ return render_update_error_unauthorized unless @resource
78
+
87
79
  # make sure account doesn't use oauth2 provider
88
80
  unless @resource.provider == 'email'
89
81
  return render_update_error_password_not_required
@@ -108,47 +100,47 @@ module DeviseTokenAuth
108
100
  protected
109
101
 
110
102
  def resource_update_method
111
- allow_password_change = recoverable_enabled? && @resource.allow_password_change == true
103
+ allow_password_change = recoverable_enabled? && @resource.allow_password_change == true || require_client_password_reset_token?
112
104
  if DeviseTokenAuth.check_current_password_before_update == false || allow_password_change
113
- "update_attributes"
105
+ 'update'
114
106
  else
115
- "update_with_password"
107
+ 'update_with_password'
116
108
  end
117
109
  end
118
110
 
119
111
  def render_create_error_missing_email
120
- render_error(401, I18n.t("devise_token_auth.passwords.missing_email"))
112
+ render_error(401, I18n.t('devise_token_auth.passwords.missing_email'))
121
113
  end
122
114
 
123
115
  def render_create_error_missing_redirect_url
124
- render_error(401, I18n.t("devise_token_auth.passwords.missing_redirect_url"))
116
+ render_error(401, I18n.t('devise_token_auth.passwords.missing_redirect_url'))
125
117
  end
126
118
 
127
- def render_create_error_not_allowed_redirect_url
119
+ def render_error_not_allowed_redirect_url
128
120
  response = {
129
121
  status: 'error',
130
122
  data: resource_data
131
123
  }
132
- message = I18n.t("devise_token_auth.passwords.not_allowed_redirect_url", redirect_url: @redirect_url)
124
+ message = I18n.t('devise_token_auth.passwords.not_allowed_redirect_url', redirect_url: @redirect_url)
133
125
  render_error(422, message, response)
134
126
  end
135
127
 
136
128
  def render_create_success
137
129
  render json: {
138
130
  success: true,
139
- message: I18n.t("devise_token_auth.passwords.sended", email: @email)
131
+ message: success_message('passwords', @email)
140
132
  }
141
133
  end
142
134
 
143
135
  def render_create_error(errors)
144
136
  render json: {
145
137
  success: false,
146
- errors: errors,
138
+ errors: errors
147
139
  }, status: 400
148
140
  end
149
141
 
150
142
  def render_edit_error
151
- raise ActionController::RoutingError.new('Not Found')
143
+ raise ActionController::RoutingError, 'Not Found'
152
144
  end
153
145
 
154
146
  def render_update_error_unauthorized
@@ -156,23 +148,23 @@ module DeviseTokenAuth
156
148
  end
157
149
 
158
150
  def render_update_error_password_not_required
159
- render_error(422, I18n.t("devise_token_auth.passwords.password_not_required", provider: @resource.provider.humanize))
151
+ render_error(422, I18n.t('devise_token_auth.passwords.password_not_required', provider: @resource.provider.humanize))
160
152
  end
161
153
 
162
154
  def render_update_error_missing_password
163
- render_error(422, I18n.t("devise_token_auth.passwords.missing_passwords"))
155
+ render_error(422, I18n.t('devise_token_auth.passwords.missing_passwords'))
164
156
  end
165
157
 
166
158
  def render_update_success
167
159
  render json: {
168
160
  success: true,
169
161
  data: resource_data,
170
- message: I18n.t("devise_token_auth.passwords.successfully_updated")
162
+ message: I18n.t('devise_token_auth.passwords.successfully_updated')
171
163
  }
172
164
  end
173
165
 
174
166
  def render_update_error
175
- return render json: {
167
+ render json: {
176
168
  success: false,
177
169
  errors: resource_errors
178
170
  }, status: 422
@@ -188,15 +180,31 @@ module DeviseTokenAuth
188
180
  params.permit(*params_for_resource(:account_update))
189
181
  end
190
182
 
191
- def with_reset_password_token token
192
- recoverable = resource_class.with_reset_password_token(token)
183
+ def render_not_found_error
184
+ if Devise.paranoid
185
+ render_error(404, I18n.t('devise_token_auth.passwords.sended_paranoid'))
186
+ else
187
+ render_error(404, I18n.t('devise_token_auth.passwords.user_not_found', email: @email))
188
+ end
189
+ end
190
+
191
+ def validate_redirect_url_param
192
+ # give redirect value from params priority
193
+ @redirect_url = params.fetch(
194
+ :redirect_url,
195
+ DeviseTokenAuth.default_password_reset_url
196
+ )
193
197
 
194
- recoverable.reset_password_token = token if recoverable && recoverable.reset_password_token.present?
195
- recoverable
198
+ return render_create_error_missing_redirect_url unless @redirect_url
199
+ return render_error_not_allowed_redirect_url if blacklisted_redirect_url?(@redirect_url)
196
200
  end
197
201
 
198
- def render_not_found_error
199
- render_error(404, I18n.t("devise_token_auth.passwords.user_not_found", email: @email))
202
+ def reset_password_token_as_raw?(recoverable)
203
+ recoverable && recoverable.reset_password_token.present? && !require_client_password_reset_token?
204
+ end
205
+
206
+ def require_client_password_reset_token?
207
+ DeviseTokenAuth.require_client_password_reset_token
200
208
  end
201
209
  end
202
210
  end