devise_token_auth 0.1.1 → 1.3.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 (213) hide show
  1. checksums.yaml +5 -5
  2. data/LICENSE +13 -0
  3. data/README.md +97 -0
  4. data/Rakefile +12 -4
  5. data/app/controllers/devise_token_auth/application_controller.rb +89 -22
  6. data/app/controllers/devise_token_auth/concerns/resource_finder.rb +58 -0
  7. data/app/controllers/devise_token_auth/concerns/set_user_by_token.rb +199 -0
  8. data/app/controllers/devise_token_auth/confirmations_controller.rb +79 -14
  9. data/app/controllers/devise_token_auth/omniauth_callbacks_controller.rb +284 -0
  10. data/app/controllers/devise_token_auth/passwords_controller.rb +196 -35
  11. data/app/controllers/devise_token_auth/registrations_controller.rb +191 -20
  12. data/app/controllers/devise_token_auth/sessions_controller.rb +130 -21
  13. data/app/controllers/devise_token_auth/token_validations_controller.rb +31 -0
  14. data/app/controllers/devise_token_auth/unlocks_controller.rb +94 -0
  15. data/app/models/devise_token_auth/concerns/active_record_support.rb +18 -0
  16. data/app/models/devise_token_auth/concerns/confirmable_support.rb +28 -0
  17. data/app/models/devise_token_auth/concerns/mongoid_support.rb +19 -0
  18. data/app/models/devise_token_auth/concerns/tokens_serialization.rb +31 -0
  19. data/app/models/devise_token_auth/concerns/user.rb +287 -0
  20. data/app/models/devise_token_auth/concerns/user_omniauth_callbacks.rb +35 -0
  21. data/app/validators/devise_token_auth_email_validator.rb +31 -0
  22. data/app/views/devise/mailer/confirmation_instructions.html.erb +5 -0
  23. data/app/views/devise/mailer/reset_password_instructions.html.erb +8 -0
  24. data/app/views/devise/mailer/unlock_instructions.html.erb +7 -0
  25. data/app/views/devise_token_auth/omniauth_external_window.html.erb +38 -0
  26. data/config/locales/da-DK.yml +52 -0
  27. data/config/locales/de.yml +51 -0
  28. data/config/locales/en.yml +60 -0
  29. data/config/locales/es.yml +51 -0
  30. data/config/locales/fa.yml +60 -0
  31. data/config/locales/fr.yml +51 -0
  32. data/config/locales/he.yml +52 -0
  33. data/config/locales/it.yml +48 -0
  34. data/config/locales/ja.yml +60 -0
  35. data/config/locales/ko.yml +51 -0
  36. data/config/locales/nl.yml +32 -0
  37. data/config/locales/pl.yml +51 -0
  38. data/config/locales/pt-BR.yml +48 -0
  39. data/config/locales/pt.yml +51 -0
  40. data/config/locales/ro.yml +48 -0
  41. data/config/locales/ru.yml +52 -0
  42. data/config/locales/sq.yml +48 -0
  43. data/config/locales/sv.yml +52 -0
  44. data/config/locales/uk.yml +61 -0
  45. data/config/locales/vi.yml +52 -0
  46. data/config/locales/zh-CN.yml +48 -0
  47. data/config/locales/zh-HK.yml +50 -0
  48. data/config/locales/zh-TW.yml +50 -0
  49. data/lib/devise_token_auth/blacklist.rb +6 -0
  50. data/lib/devise_token_auth/controllers/helpers.rb +157 -0
  51. data/lib/devise_token_auth/controllers/url_helpers.rb +10 -0
  52. data/lib/devise_token_auth/engine.rb +100 -0
  53. data/lib/devise_token_auth/errors.rb +8 -0
  54. data/lib/devise_token_auth/rails/routes.rb +135 -0
  55. data/lib/devise_token_auth/token_factory.rb +126 -0
  56. data/lib/devise_token_auth/url.rb +44 -0
  57. data/lib/devise_token_auth/version.rb +3 -1
  58. data/lib/devise_token_auth.rb +11 -2
  59. data/lib/generators/devise_token_auth/USAGE +27 -4
  60. data/lib/generators/devise_token_auth/install_generator.rb +91 -0
  61. data/lib/generators/devise_token_auth/install_generator_helpers.rb +98 -0
  62. data/lib/generators/devise_token_auth/install_mongoid_generator.rb +46 -0
  63. data/lib/generators/devise_token_auth/install_views_generator.rb +18 -0
  64. data/lib/generators/devise_token_auth/templates/devise_token_auth.rb +66 -0
  65. data/lib/generators/devise_token_auth/templates/devise_token_auth_create_users.rb.erb +49 -0
  66. data/lib/generators/devise_token_auth/templates/user.rb.erb +9 -0
  67. data/lib/generators/devise_token_auth/templates/user_mongoid.rb.erb +56 -0
  68. data/lib/tasks/devise_token_auth_tasks.rake +2 -0
  69. data/test/controllers/custom/custom_confirmations_controller_test.rb +25 -0
  70. data/test/controllers/custom/custom_omniauth_callbacks_controller_test.rb +33 -0
  71. data/test/controllers/custom/custom_passwords_controller_test.rb +79 -0
  72. data/test/controllers/custom/custom_registrations_controller_test.rb +63 -0
  73. data/test/controllers/custom/custom_sessions_controller_test.rb +39 -0
  74. data/test/controllers/custom/custom_token_validations_controller_test.rb +42 -0
  75. data/test/controllers/demo_group_controller_test.rb +151 -0
  76. data/test/controllers/demo_mang_controller_test.rb +313 -0
  77. data/test/controllers/demo_user_controller_test.rb +658 -0
  78. data/test/controllers/devise_token_auth/confirmations_controller_test.rb +275 -0
  79. data/test/controllers/devise_token_auth/omniauth_callbacks_controller_test.rb +438 -0
  80. data/test/controllers/devise_token_auth/passwords_controller_test.rb +893 -0
  81. data/test/controllers/devise_token_auth/registrations_controller_test.rb +920 -0
  82. data/test/controllers/devise_token_auth/sessions_controller_test.rb +605 -0
  83. data/test/controllers/devise_token_auth/token_validations_controller_test.rb +142 -0
  84. data/test/controllers/devise_token_auth/unlocks_controller_test.rb +235 -0
  85. data/test/controllers/overrides/confirmations_controller_test.rb +47 -0
  86. data/test/controllers/overrides/omniauth_callbacks_controller_test.rb +53 -0
  87. data/test/controllers/overrides/passwords_controller_test.rb +64 -0
  88. data/test/controllers/overrides/registrations_controller_test.rb +46 -0
  89. data/test/controllers/overrides/sessions_controller_test.rb +35 -0
  90. data/test/controllers/overrides/token_validations_controller_test.rb +43 -0
  91. data/test/dummy/app/active_record/confirmable_user.rb +11 -0
  92. data/test/dummy/app/active_record/lockable_user.rb +7 -0
  93. data/test/dummy/app/active_record/mang.rb +5 -0
  94. data/test/dummy/app/active_record/only_email_user.rb +7 -0
  95. data/test/dummy/app/active_record/scoped_user.rb +9 -0
  96. data/test/dummy/app/active_record/unconfirmable_user.rb +9 -0
  97. data/test/dummy/app/active_record/unregisterable_user.rb +9 -0
  98. data/test/dummy/app/active_record/user.rb +6 -0
  99. data/test/dummy/app/controllers/application_controller.rb +12 -3
  100. data/test/dummy/app/controllers/auth_origin_controller.rb +7 -0
  101. data/test/dummy/app/controllers/custom/confirmations_controller.rb +13 -0
  102. data/test/dummy/app/controllers/custom/omniauth_callbacks_controller.rb +13 -0
  103. data/test/dummy/app/controllers/custom/passwords_controller.rb +39 -0
  104. data/test/dummy/app/controllers/custom/registrations_controller.rb +39 -0
  105. data/test/dummy/app/controllers/custom/sessions_controller.rb +29 -0
  106. data/test/dummy/app/controllers/custom/token_validations_controller.rb +19 -0
  107. data/test/dummy/app/controllers/demo_group_controller.rb +15 -0
  108. data/test/dummy/app/controllers/demo_mang_controller.rb +14 -0
  109. data/test/dummy/app/controllers/demo_user_controller.rb +27 -0
  110. data/test/dummy/app/controllers/overrides/confirmations_controller.rb +29 -0
  111. data/test/dummy/app/controllers/overrides/omniauth_callbacks_controller.rb +16 -0
  112. data/test/dummy/app/controllers/overrides/passwords_controller.rb +36 -0
  113. data/test/dummy/app/controllers/overrides/registrations_controller.rb +29 -0
  114. data/test/dummy/app/controllers/overrides/sessions_controller.rb +36 -0
  115. data/test/dummy/app/controllers/overrides/token_validations_controller.rb +23 -0
  116. data/test/dummy/app/helpers/application_helper.rb +1056 -0
  117. data/test/dummy/app/models/concerns/favorite_color.rb +19 -0
  118. data/test/dummy/app/mongoid/confirmable_user.rb +52 -0
  119. data/test/dummy/app/mongoid/lockable_user.rb +38 -0
  120. data/test/dummy/app/mongoid/mang.rb +46 -0
  121. data/test/dummy/app/mongoid/only_email_user.rb +33 -0
  122. data/test/dummy/app/mongoid/scoped_user.rb +50 -0
  123. data/test/dummy/app/mongoid/unconfirmable_user.rb +44 -0
  124. data/test/dummy/app/mongoid/unregisterable_user.rb +47 -0
  125. data/test/dummy/app/mongoid/user.rb +49 -0
  126. data/test/dummy/app/views/layouts/application.html.erb +0 -2
  127. data/test/dummy/config/application.rb +25 -8
  128. data/test/dummy/config/application.yml.bk +0 -0
  129. data/test/dummy/config/boot.rb +8 -2
  130. data/test/dummy/config/environment.rb +3 -1
  131. data/test/dummy/config/environments/development.rb +10 -11
  132. data/test/dummy/config/environments/production.rb +3 -17
  133. data/test/dummy/config/environments/test.rb +25 -3
  134. data/test/dummy/config/initializers/backtrace_silencers.rb +2 -0
  135. data/test/dummy/config/initializers/cookies_serializer.rb +3 -1
  136. data/{config → test/dummy/config}/initializers/devise.rb +63 -31
  137. data/test/dummy/config/initializers/devise_token_auth.rb +55 -0
  138. data/test/dummy/config/initializers/figaro.rb +3 -0
  139. data/test/dummy/config/initializers/filter_parameter_logging.rb +2 -0
  140. data/test/dummy/config/initializers/inflections.rb +2 -0
  141. data/test/dummy/config/initializers/mime_types.rb +2 -0
  142. data/test/dummy/config/initializers/omniauth.rb +7 -1
  143. data/test/dummy/config/initializers/session_store.rb +2 -0
  144. data/test/dummy/config/initializers/wrap_parameters.rb +2 -0
  145. data/test/dummy/config/routes.rb +55 -1
  146. data/test/dummy/config/spring.rb +3 -0
  147. data/test/dummy/config.ru +14 -0
  148. data/test/dummy/db/migrate/20140715061447_devise_token_auth_create_users.rb +58 -0
  149. data/test/dummy/db/migrate/20140715061805_devise_token_auth_create_mangs.rb +57 -0
  150. data/test/dummy/db/migrate/20140829044006_add_operating_thetan_to_user.rb +8 -0
  151. data/test/dummy/db/migrate/20140916224624_add_favorite_color_to_mangs.rb +7 -0
  152. data/test/dummy/db/migrate/20141222035835_devise_token_auth_create_only_email_users.rb +55 -0
  153. data/test/dummy/db/migrate/20141222053502_devise_token_auth_create_unregisterable_users.rb +56 -0
  154. data/test/dummy/db/migrate/20150708104536_devise_token_auth_create_unconfirmable_users.rb +56 -0
  155. data/test/dummy/db/migrate/20160103235141_devise_token_auth_create_scoped_users.rb +56 -0
  156. data/test/dummy/db/migrate/20160629184441_devise_token_auth_create_lockable_users.rb +56 -0
  157. data/test/dummy/db/migrate/20190924101113_devise_token_auth_create_confirmable_users.rb +49 -0
  158. data/test/dummy/db/schema.rb +180 -28
  159. data/test/dummy/lib/migration_database_helper.rb +43 -0
  160. data/test/dummy/tmp/generators/app/models/user.rb +11 -0
  161. data/test/dummy/tmp/generators/config/initializers/devise_token_auth.rb +66 -0
  162. data/{db/migrate/20140628234942_devise_token_auth_create_users.rb → test/dummy/tmp/generators/db/migrate/20240519164408_devise_token_auth_create_users.rb} +16 -23
  163. data/test/factories/users.rb +41 -0
  164. data/test/lib/devise_token_auth/blacklist_test.rb +19 -0
  165. data/test/lib/devise_token_auth/rails/custom_routes_test.rb +30 -0
  166. data/test/lib/devise_token_auth/rails/routes_test.rb +87 -0
  167. data/test/lib/devise_token_auth/token_factory_test.rb +191 -0
  168. data/test/lib/devise_token_auth/url_test.rb +26 -0
  169. data/test/lib/generators/devise_token_auth/install_generator_test.rb +217 -0
  170. data/test/lib/generators/devise_token_auth/install_generator_with_namespace_test.rb +222 -0
  171. data/test/lib/generators/devise_token_auth/install_views_generator_test.rb +25 -0
  172. data/test/models/concerns/mongoid_support_test.rb +31 -0
  173. data/test/models/concerns/tokens_serialization_test.rb +104 -0
  174. data/test/models/confirmable_user_test.rb +35 -0
  175. data/test/models/only_email_user_test.rb +29 -0
  176. data/test/models/user_test.rb +251 -0
  177. data/test/support/controllers/routes.rb +43 -0
  178. data/test/test_helper.rb +136 -10
  179. metadata +368 -80
  180. data/MIT-LICENSE +0 -20
  181. data/README.rdoc +0 -3
  182. data/app/assets/javascripts/devise_token_auth/application.js +0 -13
  183. data/app/assets/stylesheets/devise_token_auth/application.css +0 -15
  184. data/app/controllers/devise_token_auth/auth_controller.rb +0 -62
  185. data/app/helpers/devise_token_auth/application_helper.rb +0 -4
  186. data/app/models/user.rb +0 -6
  187. data/app/views/devise_token_auth/omniauth_success.html.erb +0 -7
  188. data/app/views/layouts/omniauth_response.html.erb +0 -20
  189. data/config/locales/devise.en.yml +0 -59
  190. data/config/routes.rb +0 -14
  191. data/lib/generators/devise_token_auth/devise_token_auth_generator.rb +0 -3
  192. data/test/devise_token_auth_test.rb +0 -7
  193. data/test/dummy/Rakefile +0 -6
  194. data/test/dummy/app/assets/javascripts/application.js +0 -13
  195. data/test/dummy/app/assets/stylesheets/application.css +0 -15
  196. data/test/dummy/bin/bundle +0 -3
  197. data/test/dummy/bin/rails +0 -4
  198. data/test/dummy/bin/rake +0 -4
  199. data/test/dummy/config/application.yml +0 -13
  200. data/test/dummy/config/database.yml +0 -25
  201. data/test/dummy/config/initializers/assets.rb +0 -8
  202. data/test/dummy/config/locales/en.yml +0 -23
  203. data/test/dummy/config/secrets.yml +0 -22
  204. data/test/dummy/db/development.sqlite3 +0 -0
  205. data/test/dummy/db/migrate/20140629011345_devise_token_auth_create_users.devise_token_auth.rb +0 -57
  206. data/test/dummy/db/test.sqlite3 +0 -0
  207. data/test/dummy/log/development.log +0 -3406
  208. data/test/dummy/public/404.html +0 -67
  209. data/test/dummy/public/422.html +0 -67
  210. data/test/dummy/public/500.html +0 -66
  211. data/test/dummy/public/favicon.ico +0 -0
  212. data/test/integration/navigation_test.rb +0 -10
  213. data/test/lib/generators/devise_token_auth/devise_token_auth_generator_test.rb +0 -16
@@ -0,0 +1,284 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DeviseTokenAuth
4
+ class OmniauthCallbacksController < DeviseTokenAuth::ApplicationController
5
+ attr_reader :auth_params
6
+
7
+ before_action :validate_auth_origin_url_param
8
+
9
+ skip_before_action :set_user_by_token, raise: false
10
+ skip_after_action :update_auth_header
11
+
12
+ # intermediary route for successful omniauth authentication. omniauth does
13
+ # not support multiple models, so we must resort to this terrible hack.
14
+ def redirect_callbacks
15
+
16
+ # derive target redirect route from 'resource_class' param, which was set
17
+ # before authentication.
18
+ devise_mapping = get_devise_mapping
19
+ redirect_route = get_redirect_route(devise_mapping)
20
+
21
+ # preserve omniauth info for success route. ignore 'extra' in twitter
22
+ # auth response to avoid CookieOverflow.
23
+ session['dta.omniauth.auth'] = request.env['omniauth.auth'].except('extra')
24
+ session['dta.omniauth.params'] = request.env['omniauth.params']
25
+
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')
55
+ end
56
+
57
+ def omniauth_success
58
+ get_resource_from_auth_hash
59
+ set_token_on_resource
60
+ create_auth_params
61
+
62
+ if confirmable_enabled?
63
+ # don't send confirmation email!!!
64
+ @resource.skip_confirmation!
65
+ end
66
+
67
+ sign_in(:user, @resource, store: false, bypass: false)
68
+
69
+ @resource.save!
70
+
71
+ yield @resource if block_given?
72
+
73
+ if DeviseTokenAuth.cookie_enabled
74
+ set_token_in_cookie(@resource, @token)
75
+ end
76
+
77
+ render_data_or_redirect('deliverCredentials', @auth_params.as_json, @resource.as_json)
78
+ end
79
+
80
+ def omniauth_failure
81
+ @error = params[:message]
82
+ render_data_or_redirect('authFailure', error: @error)
83
+ end
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
+
90
+ protected
91
+
92
+ # this will be determined differently depending on the action that calls
93
+ # it. redirect_callbacks is called upon returning from successful omniauth
94
+ # authentication, and the target params live in an omniauth-specific
95
+ # request.env variable. this variable is then persisted thru the redirect
96
+ # using our own dta.omniauth.params session var. the omniauth_success
97
+ # method will access that session var and then destroy it immediately
98
+ # after use. In the failure case, finally, the omniauth params
99
+ # are added as query params in our monkey patch to OmniAuth in engine.rb
100
+ def omniauth_params
101
+ unless defined?(@_omniauth_params)
102
+ if request.env['omniauth.params'] && request.env['omniauth.params'].any?
103
+ @_omniauth_params = request.env['omniauth.params']
104
+ elsif session['dta.omniauth.params'] && session['dta.omniauth.params'].any?
105
+ @_omniauth_params ||= session.delete('dta.omniauth.params')
106
+ @_omniauth_params
107
+ elsif params['omniauth_window_type']
108
+ @_omniauth_params = params.slice('omniauth_window_type', 'auth_origin_url', 'resource_class', 'origin')
109
+ else
110
+ @_omniauth_params = {}
111
+ end
112
+ end
113
+ @_omniauth_params
114
+ end
115
+
116
+ # break out provider attribute assignment for easy method extension
117
+ def assign_provider_attrs(user, auth_hash)
118
+ attrs = auth_hash['info'].to_hash
119
+ attrs = attrs.slice(*user.attribute_names)
120
+ user.assign_attributes(attrs)
121
+ end
122
+
123
+ # derive allowed params from the standard devise parameter sanitizer
124
+ def whitelisted_params
125
+ whitelist = params_for_resource(:sign_up)
126
+
127
+ whitelist.inject({}) do |coll, key|
128
+ param = omniauth_params[key.to_s]
129
+ coll[key] = param if param
130
+ coll
131
+ end
132
+ end
133
+
134
+ def resource_class(mapping = nil)
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
142
+ end
143
+
144
+ def resource_name
145
+ resource_class
146
+ end
147
+
148
+ def unsafe_auth_origin_url
149
+ omniauth_params['auth_origin_url'] || omniauth_params['origin']
150
+ end
151
+
152
+
153
+ def auth_origin_url
154
+ if unsafe_auth_origin_url && blacklisted_redirect_url?(unsafe_auth_origin_url)
155
+ return nil
156
+ end
157
+ return unsafe_auth_origin_url
158
+ end
159
+
160
+ # in the success case, omniauth_window_type is in the omniauth_params.
161
+ # in the failure case, it is in a query param. See monkey patch above
162
+ def omniauth_window_type
163
+ omniauth_params.nil? ? params['omniauth_window_type'] : omniauth_params['omniauth_window_type']
164
+ end
165
+
166
+ # this session value is set by the redirect_callbacks method. its purpose
167
+ # is to persist the omniauth auth hash value thru a redirect. the value
168
+ # must be destroyed immediately after it is accessed by omniauth_success
169
+ def auth_hash
170
+ @_auth_hash ||= session.delete('dta.omniauth.auth')
171
+ end
172
+
173
+ # ensure that this controller responds to :devise_controller? conditionals.
174
+ # this is used primarily for access to the parameter sanitizers.
175
+ def assert_is_devise_resource!
176
+ true
177
+ end
178
+
179
+ def set_random_password
180
+ # set crazy password for new oauth users. this is only used to prevent
181
+ # access via email sign-in.
182
+ p = SecureRandom.urlsafe_base64(nil, false)
183
+ @resource.password = p
184
+ @resource.password_confirmation = p
185
+ end
186
+
187
+ def create_auth_params
188
+ @auth_params = {
189
+ auth_token: @token.token,
190
+ client_id: @token.client,
191
+ uid: @resource.uid,
192
+ expiry: @token.expiry,
193
+ config: @config
194
+ }
195
+ @auth_params.merge!(oauth_registration: true) if @oauth_registration
196
+ @auth_params
197
+ end
198
+
199
+ def set_token_on_resource
200
+ @config = omniauth_params['config_name']
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)
207
+ end
208
+
209
+ def render_data(message, data)
210
+ @data = data.merge(message: ActionController::Base.helpers.sanitize(message))
211
+ render layout: nil, template: 'devise_token_auth/omniauth_external_window'
212
+ end
213
+
214
+ def render_data_or_redirect(message, data, user_data = {})
215
+
216
+ # We handle inAppBrowser and newWindow the same, but it is nice
217
+ # to support values in case people need custom implementations for each case
218
+ # (For example, nbrustein does not allow new users to be created if logging in with
219
+ # an inAppBrowser)
220
+ #
221
+ # See app/views/devise_token_auth/omniauth_external_window.html.erb to understand
222
+ # why we can handle these both the same. The view is setup to handle both cases
223
+ # at the same time.
224
+ if ['inAppBrowser', 'newWindow'].include?(omniauth_window_type)
225
+ render_data(message, user_data.merge(data))
226
+
227
+ elsif auth_origin_url # default to same-window implementation, which forwards back to auth_origin_url
228
+
229
+ # build and redirect to destination url
230
+ redirect_to DeviseTokenAuth::Url.generate(auth_origin_url, data.merge(blank: true).merge(redirect_options))
231
+ else
232
+
233
+ # there SHOULD always be an auth_origin_url, but if someone does something silly
234
+ # like coming straight to this url or refreshing the page at the wrong time, there may not be one.
235
+ # In that case, just render in plain text the error message if there is one or otherwise
236
+ # a generic message.
237
+ fallback_render data[:error] || 'An error occurred'
238
+ end
239
+ end
240
+
241
+ def fallback_render(text)
242
+ render inline: %Q(
243
+
244
+ <html>
245
+ <head></head>
246
+ <body>
247
+ #{ActionController::Base.helpers.sanitize(text)}
248
+ </body>
249
+ </html>)
250
+ end
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
+
261
+ def get_resource_from_auth_hash
262
+ # find or create user by provider and provider uid
263
+ @resource = resource_class.where(
264
+ uid: auth_hash['uid'],
265
+ provider: auth_hash['provider']
266
+ ).first_or_initialize
267
+
268
+ if @resource.new_record?
269
+ handle_new_resource
270
+ end
271
+
272
+ # sync user info with provider, update/generate auth token
273
+ assign_provider_attrs(@resource, auth_hash)
274
+
275
+ # assign any additional (whitelisted) attributes
276
+ if assign_whitelisted_params?
277
+ extra_params = whitelisted_params
278
+ @resource.assign_attributes(extra_params) if extra_params
279
+ end
280
+
281
+ @resource
282
+ end
283
+ end
284
+ end
@@ -1,55 +1,216 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DeviseTokenAuth
2
- class PasswordsController < Devise::PasswordsController
3
- include Devise::Controllers::Helpers
4
+ class PasswordsController < DeviseTokenAuth::ApplicationController
5
+ before_action :validate_redirect_url_param, only: [:create, :edit]
6
+ skip_after_action :update_auth_header, only: [:create, :edit]
4
7
 
8
+ # this action is responsible for generating password reset tokens and sending emails
5
9
  def create
6
- self.resource = resource_class.send_reset_password_instructions(resource_params)
7
- yield resource if block_given?
10
+ return render_create_error_missing_email unless resource_params[:email]
11
+
12
+ @email = get_case_insensitive_field_from_resource_params(:email)
13
+ @resource = find_resource(:uid, @email)
8
14
 
9
- if resource.errors.empty?
10
- render json: {
11
- success: true
12
- }
15
+ if @resource
16
+ yield @resource if block_given?
17
+ @resource.send_reset_password_instructions(
18
+ email: @email,
19
+ provider: 'email',
20
+ redirect_url: @redirect_url,
21
+ client_config: params[:config_name]
22
+ )
23
+
24
+ if @resource.errors.empty?
25
+ return render_create_success
26
+ else
27
+ render_create_error @resource.errors
28
+ end
13
29
  else
14
- render json: {
15
- success: false,
16
- errors: ["Something went wrong. Please contact support@healthbox.com."]
17
- }, status: 401
30
+ render_not_found_error
18
31
  end
19
32
  end
20
33
 
34
+ # this is where users arrive after visiting the password reset confirmation link
35
+ def edit
36
+ # if a user is not found, return nil
37
+ @resource = resource_class.with_reset_password_token(resource_params[:reset_password_token])
38
+
39
+ if @resource && @resource.reset_password_period_valid?
40
+ token = @resource.create_token unless require_client_password_reset_token?
41
+
42
+ # ensure that user is confirmed
43
+ @resource.skip_confirmation! if confirmable_enabled? && !@resource.confirmed_at
44
+ # allow user to change password once without current_password
45
+ @resource.allow_password_change = true if recoverable_enabled?
46
+
47
+ @resource.save!
48
+
49
+ yield @resource if block_given?
50
+
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, reset_password_token: resource_params[:reset_password_token] }
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
67
+ else
68
+ render_edit_error
69
+ end
70
+ end
21
71
 
22
72
  def update
23
- self.resource = resource_class.reset_password_by_token(resource_params)
24
- yield resource if block_given?
25
-
26
- if resource.errors.empty?
27
- resource.unlock_access! if unlockable?(resource)
28
- sign_in(resource_name, resource)
29
-
30
- user_data = resource.as_json(methods: :can_score)
31
- user_data[:permissions] = resource.all_permissions
32
- user_data[:scoring_admin] = resource.scoring_admin
33
-
34
- render json: {
35
- success: true,
36
- data: {
37
- user: user_data,
38
- auth_token: resource.authentication_token
39
- }
40
- }
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 && @resource.reset_password_period_valid?
77
+
78
+ @token = @resource.create_token
41
79
  else
42
- render json: {
43
- success: false,
44
- errors: ["Something went wrong. Please contact support@healthbox.com."]
45
- }, status: 401
80
+ @resource = set_user_by_token
81
+ end
82
+
83
+ return render_update_error_unauthorized unless @resource
84
+
85
+ # make sure account doesn't use oauth2 provider
86
+ unless @resource.provider == 'email'
87
+ return render_update_error_password_not_required
88
+ end
89
+
90
+ # ensure that password params were sent
91
+ unless password_resource_params[:password] && password_resource_params[:password_confirmation]
92
+ return render_update_error_missing_password
93
+ end
94
+
95
+ if @resource.send(resource_update_method, password_resource_params)
96
+ @resource.allow_password_change = false if recoverable_enabled?
97
+ @resource.save!
98
+
99
+ yield @resource if block_given?
100
+ return render_update_success
101
+ else
102
+ return render_update_error
46
103
  end
47
104
  end
48
105
 
106
+ protected
107
+
108
+ def resource_update_method
109
+ allow_password_change = recoverable_enabled? && @resource.allow_password_change == true || require_client_password_reset_token?
110
+ if DeviseTokenAuth.check_current_password_before_update == false || allow_password_change
111
+ 'update'
112
+ else
113
+ 'update_with_password'
114
+ end
115
+ end
116
+
117
+ def render_create_error_missing_email
118
+ render_error(401, I18n.t('devise_token_auth.passwords.missing_email'))
119
+ end
120
+
121
+ def render_create_error_missing_redirect_url
122
+ render_error(401, I18n.t('devise_token_auth.passwords.missing_redirect_url'))
123
+ end
124
+
125
+ def render_error_not_allowed_redirect_url
126
+ response = {
127
+ status: 'error',
128
+ data: resource_data
129
+ }
130
+ message = I18n.t('devise_token_auth.passwords.not_allowed_redirect_url', redirect_url: @redirect_url)
131
+ render_error(422, message, response)
132
+ end
133
+
134
+ def render_create_success
135
+ render json: {
136
+ success: true,
137
+ message: success_message('passwords', @email)
138
+ }
139
+ end
140
+
141
+ def render_create_error(errors)
142
+ render json: {
143
+ success: false,
144
+ errors: errors
145
+ }, status: 400
146
+ end
147
+
148
+ def render_edit_error
149
+ raise ActionController::RoutingError, 'Not Found'
150
+ end
151
+
152
+ def render_update_error_unauthorized
153
+ render_error(401, 'Unauthorized')
154
+ end
155
+
156
+ def render_update_error_password_not_required
157
+ render_error(422, I18n.t('devise_token_auth.passwords.password_not_required', provider: @resource.provider.humanize))
158
+ end
159
+
160
+ def render_update_error_missing_password
161
+ render_error(422, I18n.t('devise_token_auth.passwords.missing_passwords'))
162
+ end
163
+
164
+ def render_update_success
165
+ render json: {
166
+ success: true,
167
+ data: resource_data,
168
+ message: I18n.t('devise_token_auth.passwords.successfully_updated')
169
+ }
170
+ end
171
+
172
+ def render_update_error
173
+ render json: {
174
+ success: false,
175
+ errors: resource_errors
176
+ }, status: 422
177
+ end
178
+
179
+ private
49
180
 
50
181
  def resource_params
51
- params.permit(:email, :password, :password_confirmation, :reset_password_token)
182
+ params.permit(:email, :reset_password_token)
183
+ end
184
+
185
+ def password_resource_params
186
+ params.permit(*params_for_resource(:account_update))
52
187
  end
53
188
 
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
+ )
203
+
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)
206
+ end
207
+
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
214
+ end
54
215
  end
55
216
  end