devise_token_auth 1.0.0 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of devise_token_auth might be problematic. Click here for more details.

Files changed (83) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +4 -2
  3. data/app/controllers/devise_token_auth/application_controller.rb +0 -1
  4. data/app/controllers/devise_token_auth/concerns/resource_finder.rb +11 -12
  5. data/app/controllers/devise_token_auth/concerns/set_user_by_token.rb +39 -55
  6. data/app/controllers/devise_token_auth/confirmations_controller.rb +62 -20
  7. data/app/controllers/devise_token_auth/omniauth_callbacks_controller.rb +51 -26
  8. data/app/controllers/devise_token_auth/passwords_controller.rb +19 -23
  9. data/app/controllers/devise_token_auth/registrations_controller.rb +32 -40
  10. data/app/controllers/devise_token_auth/sessions_controller.rb +5 -5
  11. data/app/controllers/devise_token_auth/unlocks_controller.rb +4 -4
  12. data/app/models/devise_token_auth/concerns/active_record_support.rb +16 -0
  13. data/app/models/devise_token_auth/concerns/mongoid_support.rb +19 -0
  14. data/app/models/devise_token_auth/concerns/tokens_serialization.rb +19 -0
  15. data/app/models/devise_token_auth/concerns/user.rb +44 -67
  16. data/app/models/devise_token_auth/concerns/user_omniauth_callbacks.rb +2 -2
  17. data/app/validators/{email_validator.rb → devise_token_auth_email_validator.rb} +1 -1
  18. data/config/locales/en.yml +5 -0
  19. data/config/locales/he.yml +50 -0
  20. data/config/locales/ja.yml +1 -1
  21. data/lib/devise_token_auth/blacklist.rb +2 -0
  22. data/lib/devise_token_auth/engine.rb +2 -0
  23. data/lib/devise_token_auth/rails/routes.rb +1 -1
  24. data/lib/devise_token_auth/token_factory.rb +126 -0
  25. data/lib/devise_token_auth/version.rb +1 -1
  26. data/lib/devise_token_auth.rb +6 -3
  27. data/lib/generators/devise_token_auth/install_generator.rb +3 -87
  28. data/lib/generators/devise_token_auth/install_generator_helpers.rb +98 -0
  29. data/lib/generators/devise_token_auth/install_mongoid_generator.rb +46 -0
  30. data/lib/generators/devise_token_auth/templates/devise_token_auth.rb +5 -0
  31. data/lib/generators/devise_token_auth/templates/devise_token_auth_create_users.rb.erb +0 -7
  32. data/lib/generators/devise_token_auth/templates/user_mongoid.rb.erb +56 -0
  33. data/test/controllers/custom/custom_confirmations_controller_test.rb +1 -1
  34. data/test/controllers/demo_user_controller_test.rb +2 -2
  35. data/test/controllers/devise_token_auth/confirmations_controller_test.rb +79 -19
  36. data/test/controllers/devise_token_auth/omniauth_callbacks_controller_test.rb +2 -0
  37. data/test/controllers/devise_token_auth/passwords_controller_test.rb +115 -94
  38. data/test/controllers/devise_token_auth/registrations_controller_test.rb +31 -4
  39. data/test/controllers/devise_token_auth/sessions_controller_test.rb +0 -38
  40. data/test/controllers/devise_token_auth/token_validations_controller_test.rb +2 -1
  41. data/test/dummy/app/{models → active_record}/scoped_user.rb +2 -2
  42. data/test/dummy/app/{models → active_record}/unconfirmable_user.rb +1 -2
  43. data/test/dummy/app/{models → active_record}/unregisterable_user.rb +3 -3
  44. data/test/dummy/app/active_record/user.rb +6 -0
  45. data/test/dummy/app/controllers/overrides/confirmations_controller.rb +3 -3
  46. data/test/dummy/app/controllers/overrides/passwords_controller.rb +3 -3
  47. data/test/dummy/app/controllers/overrides/registrations_controller.rb +1 -1
  48. data/test/dummy/app/controllers/overrides/sessions_controller.rb +2 -2
  49. data/test/dummy/app/models/{user.rb → concerns/favorite_color.rb} +7 -8
  50. data/test/dummy/app/mongoid/lockable_user.rb +38 -0
  51. data/test/dummy/app/mongoid/mang.rb +46 -0
  52. data/test/dummy/app/mongoid/only_email_user.rb +33 -0
  53. data/test/dummy/app/mongoid/scoped_user.rb +50 -0
  54. data/test/dummy/app/mongoid/unconfirmable_user.rb +44 -0
  55. data/test/dummy/app/mongoid/unregisterable_user.rb +47 -0
  56. data/test/dummy/app/mongoid/user.rb +49 -0
  57. data/test/dummy/config/application.rb +23 -1
  58. data/test/dummy/config/boot.rb +4 -0
  59. data/test/dummy/config/initializers/devise.rb +285 -0
  60. data/test/dummy/config/initializers/devise_token_auth.rb +35 -4
  61. data/test/dummy/db/migrate/20140715061447_devise_token_auth_create_users.rb +0 -7
  62. data/test/dummy/db/migrate/20140715061805_devise_token_auth_create_mangs.rb +0 -7
  63. data/test/dummy/db/migrate/20141222035835_devise_token_auth_create_only_email_users.rb +0 -7
  64. data/test/dummy/db/migrate/20141222053502_devise_token_auth_create_unregisterable_users.rb +0 -7
  65. data/test/dummy/db/migrate/20150708104536_devise_token_auth_create_unconfirmable_users.rb +0 -7
  66. data/test/dummy/db/migrate/20160103235141_devise_token_auth_create_scoped_users.rb +0 -7
  67. data/test/dummy/db/migrate/20160629184441_devise_token_auth_create_lockable_users.rb +0 -7
  68. data/test/dummy/db/schema.rb +1 -28
  69. data/test/factories/users.rb +1 -1
  70. data/test/lib/devise_token_auth/blacklist_test.rb +11 -0
  71. data/test/lib/devise_token_auth/token_factory_test.rb +191 -0
  72. data/test/lib/generators/devise_token_auth/install_generator_test.rb +51 -31
  73. data/test/lib/generators/devise_token_auth/install_generator_with_namespace_test.rb +51 -31
  74. data/test/models/concerns/mongoid_support_test.rb +31 -0
  75. data/test/models/concerns/tokens_serialization_test.rb +70 -0
  76. data/test/models/only_email_user_test.rb +0 -8
  77. data/test/models/user_test.rb +1 -33
  78. data/test/test_helper.rb +12 -2
  79. metadata +105 -25
  80. data/config/initializers/devise.rb +0 -198
  81. /data/test/dummy/app/{models → active_record}/lockable_user.rb +0 -0
  82. /data/test/dummy/app/{models → active_record}/mang.rb +0 -0
  83. /data/test/dummy/app/{models → active_record}/only_email_user.rb +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 916c84285bb6b805d3a70a5adc8e86d83efb348e
4
- data.tar.gz: 38deed793c1466de04cd75ab4861627a5eb18447
2
+ SHA256:
3
+ metadata.gz: 25a0c261827b5f9e1f7dccc40b782a5321d34c50a730fac7bdf9f2c281c397d9
4
+ data.tar.gz: dfee96bd1789d025ea52a83573d90d0ae784e4c63723d2ea864d17eea8fdbaf3
5
5
  SHA512:
6
- metadata.gz: 4b631710faf5afc08a2f0f0fc89a96e63c7fe07d0c7a985a19d3b5c0a18801401afe67525aa6e0a078195ca4d24c58b6a6651da667c2a7a7f40723d4974dc850
7
- data.tar.gz: 8707ad62656749fc88de275533456b93c17545f854e40f03920365c2ba9a11c170af44787118c4d8bc59ef593c5535ce8e09c512338c0de8af860c7e2500746f
6
+ metadata.gz: e68ff8599b70eebdfb2eceab3f76fce22a5cac1976234f485a58363c3821815e541982523f8ff08cd35677e794b507a10c5239c718dd033dc799f5594de0877a
7
+ data.tar.gz: d48ee0ebfa6a9117f1dbcb96180c4a6d06436ba3b555b75899da653115332fa2e69090cdb11ae8d1df3617f799a3e04547ac12bb45e0d148a49a52ac63b6c072
data/README.md CHANGED
@@ -19,7 +19,7 @@ Also, it maintains a session for each client/device, so you can have as many ses
19
19
 
20
20
  * Seamless integration with:
21
21
  * [ng-token-auth](https://github.com/lynndylanhurley/ng-token-auth) for [AngularJS](https://github.com/angular/angular.js)
22
- * [Angular2-Token](https://github.com/neroniaky/angular2-token) for [Angular2](https://github.com/angular/angular)
22
+ * [Angular-Token](https://github.com/neroniaky/angular-token) for [Angular](https://github.com/angular/angular)
23
23
  * [redux-token-auth](https://github.com/kylecorbelli/redux-token-auth) for [React with Redux](https://github.com/reactjs/react-redux)
24
24
  * [jToker](https://github.com/lynndylanhurley/j-toker) for [jQuery](https://jquery.com/)
25
25
  * Oauth2 authentication using [OmniAuth](https://github.com/intridea/omniauth).
@@ -65,11 +65,13 @@ Please read the [issue template](https://github.com/lynndylanhurley/devise_token
65
65
 
66
66
  See our [Contribution Guidelines](https://github.com/lynndylanhurley/devise_token_auth/blob/master/.github/CONTRIBUTING.md). Feel free to submit pull requests, review pull requests, or review open issues. If you'd like to get in contact, [Zach Feldman](https://github.com/zachfeldman) has been wrangling this effort, you can reach him with his name @gmail. Further discussion of this in [this issue](https://github.com/lynndylanhurley/devise_token_auth/issues/969).
67
67
 
68
+ We have some bounties for some issues, [check them out](https://github.com/lynndylanhurley/devise_token_auth/issues?q=is%3Aopen+is%3Aissue+label%3Abounty)!
69
+
68
70
  ## Live Demos
69
71
 
70
72
  [Here is a demo](http://ng-token-auth-demo.herokuapp.com/) of this app running with the [ng-token-auth](https://github.com/lynndylanhurley/ng-token-auth) module and [AngularJS](https://github.com/angular/angular.js).
71
73
 
72
- [Here is a demo](https://angular2-token.herokuapp.com) of this app running with the [Angular2-Token](https://github.com/neroniaky/angular2-token) service and [Angular2](https://github.com/angular/angular).
74
+ [Here is a demo](https://stackblitz.com/github/neroniaky/angular-token) of this app running with the [Angular-Token](https://github.com/neroniaky/angular-token) service and [Angular](https://github.com/angular/angular).
73
75
 
74
76
  [Here is a demo](https://j-toker-demo.herokuapp.com/) of this app using the [jToker](https://github.com/lynndylanhurley/j-toker) plugin and [React](http://facebook.github.io/react/).
75
77
 
@@ -3,7 +3,6 @@
3
3
  module DeviseTokenAuth
4
4
  class ApplicationController < DeviseController
5
5
  include DeviseTokenAuth::Concerns::SetUserByToken
6
- include DeviseTokenAuth::Concerns::ResourceFinder
7
6
 
8
7
  def resource_data(opts = {})
9
8
  response_data = opts[:resource_json] || @resource.as_json
@@ -20,21 +20,20 @@ module DeviseTokenAuth::Concerns::ResourceFinder
20
20
  end
21
21
 
22
22
  def find_resource(field, value)
23
- # fix for mysql default case insensitivity
24
- q = "#{field.to_s} = ? AND provider='#{provider.to_s}'"
25
- if ActiveRecord::Base.connection.adapter_name.downcase.starts_with? 'mysql'
26
- q = 'BINARY ' + q
27
- end
28
-
29
- @resource = resource_class.where(q, value).first
23
+ @resource = if resource_class.try(:connection_config).try(:[], :adapter).try(:include?, 'mysql')
24
+ # fix for mysql default case insensitivity
25
+ resource_class.where("BINARY #{field} = ? AND provider= ?", value, provider).first
26
+ else
27
+ resource_class.dta_find_by(field => value, 'provider' => provider)
28
+ end
30
29
  end
31
30
 
32
31
  def resource_class(m = nil)
33
- if m
34
- mapping = Devise.mappings[m]
35
- else
36
- mapping = Devise.mappings[resource_name] || Devise.mappings.values.first
37
- end
32
+ mapping = if m
33
+ Devise.mappings[m]
34
+ else
35
+ Devise.mappings[resource_name] || Devise.mappings.values.first
36
+ end
38
37
 
39
38
  mapping.to
40
39
  end
@@ -17,24 +17,11 @@ module DeviseTokenAuth::Concerns::SetUserByToken
17
17
  @used_auth_by_token = true
18
18
 
19
19
  # initialize instance variables
20
- @client_id ||= nil
20
+ @token = DeviseTokenAuth::TokenFactory.new
21
21
  @resource ||= nil
22
- @token ||= nil
23
22
  @is_batch_request ||= nil
24
23
  end
25
24
 
26
- def ensure_pristine_resource
27
- if @resource.changed?
28
- # Stash pending changes in the resource before reloading.
29
- changes = @resource.changes
30
- @resource.reload
31
- end
32
- yield
33
- ensure
34
- # Reapply pending changes
35
- @resource.assign_attributes(changes) if changes
36
- end
37
-
38
25
  # user auth
39
26
  def set_user_by_token(mapping = nil)
40
27
  # determine target authentication class
@@ -49,17 +36,18 @@ module DeviseTokenAuth::Concerns::SetUserByToken
49
36
  client_name = DeviseTokenAuth.headers_names[:'client']
50
37
 
51
38
  # parse header for values necessary for authentication
52
- uid = request.headers[uid_name] || params[uid_name]
53
- @token ||= request.headers[access_token_name] || params[access_token_name]
54
- @client_id ||= request.headers[client_name] || params[client_name]
39
+ uid = request.headers[uid_name] || params[uid_name]
40
+ @token = DeviseTokenAuth::TokenFactory.new unless @token
41
+ @token.token ||= request.headers[access_token_name] || params[access_token_name]
42
+ @token.client ||= request.headers[client_name] || params[client_name]
55
43
 
56
- # client_id isn't required, set to 'default' if absent
57
- @client_id ||= 'default'
44
+ # client isn't required, set to 'default' if absent
45
+ @token.client ||= 'default'
58
46
 
59
47
  # check for an existing user, authenticated via warden/devise, if enabled
60
48
  if DeviseTokenAuth.enable_standard_devise_support
61
49
  devise_warden_user = warden.user(rc.to_s.underscore.to_sym)
62
- if devise_warden_user && devise_warden_user.tokens[@client_id].nil?
50
+ if devise_warden_user && devise_warden_user.tokens[@token.client].nil?
63
51
  @used_auth_by_token = false
64
52
  @resource = devise_warden_user
65
53
  # REVIEW: The following line _should_ be safe to remove;
@@ -71,46 +59,44 @@ module DeviseTokenAuth::Concerns::SetUserByToken
71
59
  # user has already been found and authenticated
72
60
  return @resource if @resource && @resource.is_a?(rc)
73
61
 
74
- # ensure we clear the client_id
75
- unless @token
76
- @client_id = nil
62
+ # ensure we clear the client
63
+ unless @token.present?
64
+ @token.client = nil
77
65
  return
78
66
  end
79
67
 
80
- return false unless @token
81
-
82
68
  # mitigate timing attacks by finding by uid instead of auth token
83
- user = uid && rc.find_by(uid: uid)
69
+ user = uid && rc.dta_find_by(uid: uid)
70
+ scope = rc.to_s.underscore.to_sym
84
71
 
85
- if user && user.valid_token?(@token, @client_id)
72
+ if user && user.valid_token?(@token.token, @token.client)
86
73
  # sign_in with bypass: true will be deprecated in the next version of Devise
87
74
  if respond_to?(:bypass_sign_in) && DeviseTokenAuth.bypass_sign_in
88
- bypass_sign_in(user, scope: :user)
75
+ bypass_sign_in(user, scope: scope)
89
76
  else
90
- sign_in(:user, user, store: false, event: :fetch, bypass: DeviseTokenAuth.bypass_sign_in)
77
+ sign_in(scope, user, store: false, event: :fetch, bypass: DeviseTokenAuth.bypass_sign_in)
91
78
  end
92
79
  return @resource = user
93
80
  else
94
81
  # zero all values previously set values
95
- @client_id = nil
82
+ @token.client = nil
96
83
  return @resource = nil
97
84
  end
98
85
  end
99
86
 
100
87
  def update_auth_header
101
88
  # cannot save object if model has invalid params
89
+ return unless @resource && @token.client
102
90
 
103
- return unless @resource && @client_id
104
-
105
- # Generate new client_id with existing authentication
106
- @client_id = nil unless @used_auth_by_token
91
+ # Generate new client with existing authentication
92
+ @token.client = nil unless @used_auth_by_token
107
93
 
108
94
  if @used_auth_by_token && !DeviseTokenAuth.change_headers_on_each_request
109
95
  # should not append auth header if @resource related token was
110
96
  # cleared by sign out in the meantime
111
- return if @resource.reload.tokens[@client_id].nil?
97
+ return if @resource.reload.tokens[@token.client].nil?
112
98
 
113
- auth_header = @resource.build_auth_header(@token, @client_id)
99
+ auth_header = @resource.build_auth_header(@token.token, @token.client)
114
100
 
115
101
  # update the response header
116
102
  response.headers.merge!(auth_header)
@@ -130,37 +116,35 @@ module DeviseTokenAuth::Concerns::SetUserByToken
130
116
  private
131
117
 
132
118
  def refresh_headers
133
- ensure_pristine_resource do
134
- # Lock the user record during any auth_header updates to ensure
135
- # we don't have write contention from multiple threads
136
- @resource.with_lock do
137
- # should not append auth header if @resource related token was
138
- # cleared by sign out in the meantime
139
- return if @used_auth_by_token && @resource.tokens[@client_id].nil?
140
-
141
- # update the response header
142
- response.headers.merge!(auth_header_from_batch_request)
143
- end # end lock
144
- end # end ensure_pristine_resource
119
+ # Lock the user record during any auth_header updates to ensure
120
+ # we don't have write contention from multiple threads
121
+ @resource.with_lock do
122
+ # should not append auth header if @resource related token was
123
+ # cleared by sign out in the meantime
124
+ return if @used_auth_by_token && @resource.tokens[@token.client].nil?
125
+
126
+ # update the response header
127
+ response.headers.merge!(auth_header_from_batch_request)
128
+ end # end lock
145
129
  end
146
130
 
147
- def is_batch_request?(user, client_id)
131
+ def is_batch_request?(user, client)
148
132
  !params[:unbatch] &&
149
- user.tokens[client_id] &&
150
- user.tokens[client_id]['updated_at'] &&
151
- Time.parse(user.tokens[client_id]['updated_at']) > @request_started_at - DeviseTokenAuth.batch_request_buffer_throttle
133
+ user.tokens[client] &&
134
+ user.tokens[client]['updated_at'] &&
135
+ user.tokens[client]['updated_at'].to_time > @request_started_at - DeviseTokenAuth.batch_request_buffer_throttle
152
136
  end
153
137
 
154
138
  def auth_header_from_batch_request
155
139
  # determine batch request status after request processing, in case
156
140
  # another processes has updated it during that processing
157
- @is_batch_request = is_batch_request?(@resource, @client_id)
141
+ @is_batch_request = is_batch_request?(@resource, @token.client)
158
142
 
159
143
  auth_header = {}
160
144
  # extend expiration of batch buffer to account for the duration of
161
145
  # this request
162
146
  if @is_batch_request
163
- auth_header = @resource.extend_batch_buffer(@token, @client_id)
147
+ auth_header = @resource.extend_batch_buffer(@token.token, @token.client)
164
148
 
165
149
  # Do not return token for batch requests to avoid invalidated
166
150
  # tokens returned to the client in case of race conditions.
@@ -171,7 +155,7 @@ module DeviseTokenAuth::Concerns::SetUserByToken
171
155
  auth_header[DeviseTokenAuth.headers_names[:"expiry"]] = ' '
172
156
  else
173
157
  # update Authorization response header with new token
174
- auth_header = @resource.create_new_auth_token(@client_id)
158
+ auth_header = @resource.create_new_auth_token(@token.client)
175
159
  end
176
160
  auth_header
177
161
  end
@@ -2,38 +2,80 @@
2
2
 
3
3
  module DeviseTokenAuth
4
4
  class ConfirmationsController < DeviseTokenAuth::ApplicationController
5
- def show
6
- @resource = resource_class.confirm_by_token(params[:confirmation_token])
7
-
8
- if @resource && @resource.id
9
- expiry = nil
10
- if defined?(@resource.sign_in_count) && @resource.sign_in_count > 0
11
- expiry = (Time.zone.now + 1.second).to_i
12
- end
13
-
14
- client_id, token = @resource.create_token expiry: expiry
15
5
 
16
- sign_in(@resource)
17
- @resource.save!
6
+ def show
7
+ @resource = resource_class.confirm_by_token(resource_params[:confirmation_token])
18
8
 
9
+ if @resource.errors.empty?
19
10
  yield @resource if block_given?
20
11
 
21
12
  redirect_header_options = { account_confirmation_success: true }
22
- redirect_headers = build_redirect_headers(token,
23
- client_id,
24
- redirect_header_options)
25
13
 
26
- # give redirect value from params priority
27
- @redirect_url = params[:redirect_url]
14
+ if signed_in?(resource_name)
15
+ token = signed_in_resource.create_token
28
16
 
29
- # fall back to default value if provided
30
- @redirect_url ||= DeviseTokenAuth.default_confirm_success_url
17
+ redirect_headers = build_redirect_headers(token.token,
18
+ token.client,
19
+ redirect_header_options)
31
20
 
21
+ redirect_to_link = signed_in_resource.build_auth_url(redirect_url, redirect_headers)
22
+ else
23
+ redirect_to_link = DeviseTokenAuth::Url.generate(redirect_url, redirect_header_options)
24
+ end
32
25
 
33
- redirect_to(@resource.build_auth_url(@redirect_url, redirect_headers))
26
+ redirect_to(redirect_to_link)
34
27
  else
35
28
  raise ActionController::RoutingError, 'Not Found'
36
29
  end
37
30
  end
31
+
32
+ def create
33
+ return render_create_error_missing_email if resource_params[:email].blank?
34
+
35
+ @email = get_case_insensitive_field_from_resource_params(:email)
36
+
37
+ @resource = resource_class.dta_find_by(uid: @email, provider: provider)
38
+
39
+ return render_not_found_error unless @resource
40
+
41
+ @resource.send_confirmation_instructions({
42
+ redirect_url: redirect_url,
43
+ client_config: resource_params[:config_name]
44
+ })
45
+
46
+ return render_create_success
47
+ end
48
+
49
+ protected
50
+
51
+ def render_create_error_missing_email
52
+ render_error(401, I18n.t('devise_token_auth.confirmations.missing_email'))
53
+ end
54
+
55
+ def render_create_success
56
+ render json: {
57
+ success: true,
58
+ message: I18n.t('devise_token_auth.confirmations.sended', email: @email)
59
+ }
60
+ end
61
+
62
+ def render_not_found_error
63
+ render_error(404, I18n.t('devise_token_auth.confirmations.user_not_found', email: @email))
64
+ end
65
+
66
+ private
67
+
68
+ def resource_params
69
+ params.permit(:email, :confirmation_token, :config_name)
70
+ end
71
+
72
+ # give redirect value from params priority or fall back to default value if provided
73
+ def redirect_url
74
+ params.fetch(
75
+ :redirect_url,
76
+ DeviseTokenAuth.default_confirm_success_url
77
+ )
78
+ end
79
+
38
80
  end
39
81
  end
@@ -12,11 +12,8 @@ module DeviseTokenAuth
12
12
 
13
13
  # derive target redirect route from 'resource_class' param, which was set
14
14
  # before authentication.
15
- devise_mapping = [request.env['omniauth.params']['namespace_name'],
16
- request.env['omniauth.params']['resource_class'].underscore.gsub('/', '_')].compact.join('_')
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
15
+ devise_mapping = get_devise_mapping
16
+ redirect_route = get_redirect_route(devise_mapping)
20
17
 
21
18
  # preserve omniauth info for success route. ignore 'extra' in twitter
22
19
  # auth response to avoid CookieOverflow.
@@ -26,6 +23,34 @@ module DeviseTokenAuth
26
23
  redirect_to redirect_route
27
24
  end
28
25
 
26
+ def get_redirect_route(devise_mapping)
27
+ path = "#{Devise.mappings[devise_mapping.to_sym].fullpath}/#{params[:provider]}/callback"
28
+ klass = request.scheme == 'https' ? URI::HTTPS : URI::HTTP
29
+ redirect_route = klass.build(host: request.host, port: request.port, path: path).to_s
30
+ end
31
+
32
+ def get_devise_mapping
33
+ # derive target redirect route from 'resource_class' param, which was set
34
+ # before authentication.
35
+ devise_mapping = [request.env['omniauth.params']['namespace_name'],
36
+ request.env['omniauth.params']['resource_class'].underscore.gsub('/', '_')].compact.join('_')
37
+ rescue NoMethodError => err
38
+ default_devise_mapping
39
+ end
40
+
41
+ # This method will only be called if `get_devise_mapping` cannot
42
+ # find the mapping in `omniauth.params`.
43
+ #
44
+ # One example use-case here is for IDP-initiated SAML login. In that
45
+ # case, there will have been no initial request in which to save
46
+ # the devise mapping. If you are in a situation like that, and
47
+ # your app allows for you to determine somehow what the devise
48
+ # mapping should be (because, for example, it is always the same),
49
+ # then you can handle it by overriding this method.
50
+ def default_devise_mapping
51
+ raise NotImplementedError.new('no default_devise_mapping set')
52
+ end
53
+
29
54
  def omniauth_success
30
55
  get_resource_from_auth_hash
31
56
  set_token_on_resource
@@ -79,7 +104,7 @@ module DeviseTokenAuth
79
104
 
80
105
  # break out provider attribute assignment for easy method extension
81
106
  def assign_provider_attrs(user, auth_hash)
82
- attrs = auth_hash['info'].slice(*user.attributes.keys)
107
+ attrs = auth_hash['info'].slice(*user.attribute_names)
83
108
  user.assign_attributes(attrs)
84
109
  end
85
110
 
@@ -136,16 +161,6 @@ module DeviseTokenAuth
136
161
  true
137
162
  end
138
163
 
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
164
  def set_random_password
150
165
  # set crazy password for new oauth users. this is only used to prevent
151
166
  # access via email sign-in.
@@ -156,11 +171,11 @@ module DeviseTokenAuth
156
171
 
157
172
  def create_auth_params
158
173
  @auth_params = {
159
- auth_token: @token,
160
- client_id: @client_id,
161
- uid: @resource.uid,
162
- expiry: @expiry,
163
- config: @config
174
+ auth_token: @token.token,
175
+ client_id: @token.client,
176
+ uid: @resource.uid,
177
+ expiry: @token.expiry,
178
+ config: @config
164
179
  }
165
180
  @auth_params.merge!(oauth_registration: true) if @oauth_registration
166
181
  @auth_params
@@ -168,7 +183,7 @@ module DeviseTokenAuth
168
183
 
169
184
  def set_token_on_resource
170
185
  @config = omniauth_params['config_name']
171
- @client_id, @token, @expiry = @resource.create_token
186
+ @token = @resource.create_token
172
187
  end
173
188
 
174
189
  def render_data(message, data)
@@ -214,6 +229,15 @@ module DeviseTokenAuth
214
229
  </html>)
215
230
  end
216
231
 
232
+ def handle_new_resource
233
+ @oauth_registration = true
234
+ set_random_password
235
+ end
236
+
237
+ def assign_whitelisted_params?
238
+ true
239
+ end
240
+
217
241
  def get_resource_from_auth_hash
218
242
  # find or create user by provider and provider uid
219
243
  @resource = resource_class.where(
@@ -222,16 +246,17 @@ module DeviseTokenAuth
222
246
  ).first_or_initialize
223
247
 
224
248
  if @resource.new_record?
225
- @oauth_registration = true
226
- set_random_password
249
+ handle_new_resource
227
250
  end
228
251
 
229
252
  # sync user info with provider, update/generate auth token
230
253
  assign_provider_attrs(@resource, auth_hash)
231
254
 
232
255
  # assign any additional (whitelisted) attributes
233
- extra_params = whitelisted_params
234
- @resource.assign_attributes(extra_params) if extra_params
256
+ if assign_whitelisted_params?
257
+ extra_params = whitelisted_params
258
+ @resource.assign_attributes(extra_params) if extra_params
259
+ end
235
260
 
236
261
  @resource
237
262
  end
@@ -3,6 +3,7 @@
3
3
  module DeviseTokenAuth
4
4
  class PasswordsController < DeviseTokenAuth::ApplicationController
5
5
  before_action :set_user_by_token, only: [:update]
6
+ before_action :validate_redirect_url_param, only: [:create, :edit]
6
7
  skip_after_action :update_auth_header, only: [:create, :edit]
7
8
 
8
9
  # this action is responsible for generating password reset tokens and
@@ -10,15 +11,6 @@ module DeviseTokenAuth
10
11
  def create
11
12
  return render_create_error_missing_email unless resource_params[:email]
12
13
 
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
14
  @email = get_case_insensitive_field_from_resource_params(:email)
23
15
  @resource = find_resource(:uid, @email)
24
16
 
@@ -44,10 +36,10 @@ module DeviseTokenAuth
44
36
  # this is where users arrive after visiting the password reset confirmation link
45
37
  def edit
46
38
  # if a user is not found, return nil
47
- @resource = with_reset_password_token(resource_params[:reset_password_token])
39
+ @resource = resource_class.with_reset_password_token(resource_params[:reset_password_token])
48
40
 
49
41
  if @resource && @resource.reset_password_period_valid?
50
- client_id, token = @resource.create_token
42
+ token = @resource.create_token
51
43
 
52
44
  # ensure that user is confirmed
53
45
  @resource.skip_confirmation! if confirmable_enabled? && !@resource.confirmed_at
@@ -60,10 +52,10 @@ module DeviseTokenAuth
60
52
  yield @resource if block_given?
61
53
 
62
54
  redirect_header_options = { reset_password: true }
63
- redirect_headers = build_redirect_headers(token,
64
- client_id,
55
+ redirect_headers = build_redirect_headers(token.token,
56
+ token.client,
65
57
  redirect_header_options)
66
- redirect_to(@resource.build_auth_url(params[:redirect_url],
58
+ redirect_to(@resource.build_auth_url(@redirect_url,
67
59
  redirect_headers))
68
60
  else
69
61
  render_edit_error
@@ -100,7 +92,7 @@ module DeviseTokenAuth
100
92
  def resource_update_method
101
93
  allow_password_change = recoverable_enabled? && @resource.allow_password_change == true
102
94
  if DeviseTokenAuth.check_current_password_before_update == false || allow_password_change
103
- 'update_attributes'
95
+ 'update'
104
96
  else
105
97
  'update_with_password'
106
98
  end
@@ -114,7 +106,7 @@ module DeviseTokenAuth
114
106
  render_error(401, I18n.t('devise_token_auth.passwords.missing_redirect_url'))
115
107
  end
116
108
 
117
- def render_create_error_not_allowed_redirect_url
109
+ def render_error_not_allowed_redirect_url
118
110
  response = {
119
111
  status: 'error',
120
112
  data: resource_data
@@ -178,15 +170,19 @@ module DeviseTokenAuth
178
170
  params.permit(*params_for_resource(:account_update))
179
171
  end
180
172
 
181
- def with_reset_password_token token
182
- recoverable = resource_class.with_reset_password_token(token)
183
-
184
- recoverable.reset_password_token = token if recoverable && recoverable.reset_password_token.present?
185
- recoverable
186
- end
187
-
188
173
  def render_not_found_error
189
174
  render_error(404, I18n.t('devise_token_auth.passwords.user_not_found', email: @email))
190
175
  end
176
+
177
+ def validate_redirect_url_param
178
+ # give redirect value from params priority
179
+ @redirect_url = params.fetch(
180
+ :redirect_url,
181
+ DeviseTokenAuth.default_password_reset_url
182
+ )
183
+
184
+ return render_create_error_missing_redirect_url unless @redirect_url
185
+ return render_error_not_allowed_redirect_url if blacklisted_redirect_url?
186
+ end
191
187
  end
192
188
  end