devise_token_auth 1.0.0 → 1.1.5

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 (126) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +4 -2
  3. data/app/controllers/devise_token_auth/application_controller.rb +2 -3
  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 +41 -57
  6. data/app/controllers/devise_token_auth/confirmations_controller.rb +63 -20
  7. data/app/controllers/devise_token_auth/omniauth_callbacks_controller.rb +77 -29
  8. data/app/controllers/devise_token_auth/passwords_controller.rb +44 -30
  9. data/app/controllers/devise_token_auth/registrations_controller.rb +33 -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 +14 -0
  13. data/app/models/devise_token_auth/concerns/confirmable_support.rb +28 -0
  14. data/app/models/devise_token_auth/concerns/mongoid_support.rb +19 -0
  15. data/app/models/devise_token_auth/concerns/tokens_serialization.rb +31 -0
  16. data/app/models/devise_token_auth/concerns/user.rb +51 -70
  17. data/app/models/devise_token_auth/concerns/user_omniauth_callbacks.rb +6 -3
  18. data/app/validators/{email_validator.rb → devise_token_auth_email_validator.rb} +2 -2
  19. data/config/locales/da-DK.yml +2 -0
  20. data/config/locales/de.yml +2 -0
  21. data/config/locales/en.yml +7 -0
  22. data/config/locales/es.yml +2 -0
  23. data/config/locales/fr.yml +2 -0
  24. data/config/locales/he.yml +52 -0
  25. data/config/locales/it.yml +2 -0
  26. data/config/locales/ja.yml +4 -2
  27. data/config/locales/ko.yml +51 -0
  28. data/config/locales/nl.yml +2 -0
  29. data/config/locales/pl.yml +6 -3
  30. data/config/locales/pt-BR.yml +2 -0
  31. data/config/locales/pt.yml +6 -3
  32. data/config/locales/ro.yml +2 -0
  33. data/config/locales/ru.yml +2 -0
  34. data/config/locales/sq.yml +2 -0
  35. data/config/locales/sv.yml +2 -0
  36. data/config/locales/uk.yml +2 -0
  37. data/config/locales/vi.yml +2 -0
  38. data/config/locales/zh-CN.yml +2 -0
  39. data/config/locales/zh-HK.yml +2 -0
  40. data/config/locales/zh-TW.yml +2 -0
  41. data/lib/devise_token_auth/blacklist.rb +2 -0
  42. data/lib/devise_token_auth/controllers/helpers.rb +5 -9
  43. data/lib/devise_token_auth/engine.rb +7 -1
  44. data/lib/devise_token_auth/rails/routes.rb +16 -11
  45. data/lib/devise_token_auth/token_factory.rb +126 -0
  46. data/lib/devise_token_auth/url.rb +3 -0
  47. data/lib/devise_token_auth/version.rb +1 -1
  48. data/lib/devise_token_auth.rb +6 -3
  49. data/lib/generators/devise_token_auth/USAGE +1 -1
  50. data/lib/generators/devise_token_auth/install_generator.rb +7 -91
  51. data/lib/generators/devise_token_auth/install_generator_helpers.rb +98 -0
  52. data/lib/generators/devise_token_auth/install_mongoid_generator.rb +46 -0
  53. data/lib/generators/devise_token_auth/templates/devise_token_auth.rb +10 -0
  54. data/lib/generators/devise_token_auth/templates/devise_token_auth_create_users.rb.erb +1 -8
  55. data/lib/generators/devise_token_auth/templates/user.rb.erb +2 -2
  56. data/lib/generators/devise_token_auth/templates/user_mongoid.rb.erb +56 -0
  57. data/test/controllers/custom/custom_confirmations_controller_test.rb +1 -1
  58. data/test/controllers/demo_user_controller_test.rb +2 -2
  59. data/test/controllers/devise_token_auth/confirmations_controller_test.rb +83 -19
  60. data/test/controllers/devise_token_auth/omniauth_callbacks_controller_test.rb +109 -42
  61. data/test/controllers/devise_token_auth/passwords_controller_test.rb +227 -102
  62. data/test/controllers/devise_token_auth/registrations_controller_test.rb +34 -7
  63. data/test/controllers/devise_token_auth/sessions_controller_test.rb +0 -38
  64. data/test/controllers/devise_token_auth/token_validations_controller_test.rb +2 -1
  65. data/test/dummy/app/active_record/confirmable_user.rb +11 -0
  66. data/test/dummy/app/{models → active_record}/scoped_user.rb +2 -2
  67. data/test/dummy/app/{models → active_record}/unconfirmable_user.rb +1 -2
  68. data/test/dummy/app/{models → active_record}/unregisterable_user.rb +3 -3
  69. data/test/dummy/app/active_record/user.rb +6 -0
  70. data/test/dummy/app/controllers/overrides/confirmations_controller.rb +3 -3
  71. data/test/dummy/app/controllers/overrides/passwords_controller.rb +3 -3
  72. data/test/dummy/app/controllers/overrides/registrations_controller.rb +1 -1
  73. data/test/dummy/app/controllers/overrides/sessions_controller.rb +2 -2
  74. data/test/dummy/app/models/{user.rb → concerns/favorite_color.rb} +7 -8
  75. data/test/dummy/app/mongoid/confirmable_user.rb +52 -0
  76. data/test/dummy/app/mongoid/lockable_user.rb +38 -0
  77. data/test/dummy/app/mongoid/mang.rb +46 -0
  78. data/test/dummy/app/mongoid/only_email_user.rb +33 -0
  79. data/test/dummy/app/mongoid/scoped_user.rb +50 -0
  80. data/test/dummy/app/mongoid/unconfirmable_user.rb +44 -0
  81. data/test/dummy/app/mongoid/unregisterable_user.rb +47 -0
  82. data/test/dummy/app/mongoid/user.rb +49 -0
  83. data/test/dummy/app/views/layouts/application.html.erb +0 -2
  84. data/test/dummy/config/application.rb +22 -1
  85. data/test/dummy/config/boot.rb +4 -0
  86. data/test/dummy/config/environments/development.rb +0 -10
  87. data/test/dummy/config/environments/production.rb +0 -16
  88. data/test/dummy/config/initializers/devise.rb +285 -0
  89. data/test/dummy/config/initializers/devise_token_auth.rb +35 -4
  90. data/test/dummy/config/initializers/figaro.rb +1 -1
  91. data/test/dummy/config/initializers/omniauth.rb +1 -0
  92. data/test/dummy/config/routes.rb +2 -0
  93. data/test/dummy/db/migrate/20140715061447_devise_token_auth_create_users.rb +0 -7
  94. data/test/dummy/db/migrate/20140715061805_devise_token_auth_create_mangs.rb +0 -7
  95. data/test/dummy/db/migrate/20141222035835_devise_token_auth_create_only_email_users.rb +0 -7
  96. data/test/dummy/db/migrate/20141222053502_devise_token_auth_create_unregisterable_users.rb +0 -7
  97. data/test/dummy/db/migrate/20150708104536_devise_token_auth_create_unconfirmable_users.rb +0 -7
  98. data/test/dummy/db/migrate/20160103235141_devise_token_auth_create_scoped_users.rb +0 -7
  99. data/test/dummy/db/migrate/20160629184441_devise_token_auth_create_lockable_users.rb +0 -7
  100. data/test/dummy/db/migrate/20190924101113_devise_token_auth_create_confirmable_users.rb +49 -0
  101. data/test/dummy/db/schema.rb +26 -28
  102. data/test/dummy/tmp/generators/app/models/azpire/v1/human_resource/user.rb +9 -0
  103. data/test/dummy/tmp/generators/config/initializers/devise_token_auth.rb +60 -0
  104. data/test/dummy/tmp/generators/db/migrate/20210126004321_devise_token_auth_create_azpire_v1_human_resource_users.rb +49 -0
  105. data/test/factories/users.rb +3 -2
  106. data/test/lib/devise_token_auth/blacklist_test.rb +11 -0
  107. data/test/lib/devise_token_auth/rails/custom_routes_test.rb +29 -0
  108. data/test/lib/devise_token_auth/rails/routes_test.rb +87 -0
  109. data/test/lib/devise_token_auth/token_factory_test.rb +191 -0
  110. data/test/lib/devise_token_auth/url_test.rb +2 -2
  111. data/test/lib/generators/devise_token_auth/install_generator_test.rb +51 -31
  112. data/test/lib/generators/devise_token_auth/install_generator_with_namespace_test.rb +51 -31
  113. data/test/models/concerns/mongoid_support_test.rb +31 -0
  114. data/test/models/concerns/tokens_serialization_test.rb +104 -0
  115. data/test/models/confirmable_user_test.rb +35 -0
  116. data/test/models/only_email_user_test.rb +0 -8
  117. data/test/models/user_test.rb +1 -33
  118. data/test/test_helper.rb +13 -3
  119. metadata +125 -32
  120. data/config/initializers/devise.rb +0 -198
  121. data/test/dummy/config/initializers/assets.rb +0 -10
  122. data/test/dummy/tmp/generators/app/views/devise/mailer/confirmation_instructions.html.erb +0 -5
  123. data/test/dummy/tmp/generators/app/views/devise/mailer/reset_password_instructions.html.erb +0 -8
  124. /data/test/dummy/app/{models → active_record}/lockable_user.rb +0 -0
  125. /data/test/dummy/app/{models → active_record}/mang.rb +0 -0
  126. /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: 7a64d8fc927471b28cec59b5191e06ef4d2fd7152dadcc9f49b5c512611ba4e6
4
+ data.tar.gz: 3ac708a845da1df134975f293a7db9e8977cd116c0d8dbdc7650e249bb99df82
5
5
  SHA512:
6
- metadata.gz: 4b631710faf5afc08a2f0f0fc89a96e63c7fe07d0c7a985a19d3b5c0a18801401afe67525aa6e0a078195ca4d24c58b6a6651da667c2a7a7f40723d4974dc850
7
- data.tar.gz: 8707ad62656749fc88de275533456b93c17545f854e40f03920365c2ba9a11c170af44787118c4d8bc59ef593c5535ce8e09c512338c0de8af860c7e2500746f
6
+ metadata.gz: 51a73c32d0debfc772ff7f7b8b5a524a67fde1676bb66a1d77d243c451a3ca5b375c593287bfb1be2abff7ff881947e39470a6d46421c73f112d4a5b1d774858
7
+ data.tar.gz: a79f4e32938818a92fddbcb88eb918da3c53afe8bf304769fa9d02f1841ed67093ab0bf7b004263094737da15d3dae222b785c70ef233e1b6f43a07a7f49f2b5
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
@@ -17,8 +16,8 @@ module DeviseTokenAuth
17
16
 
18
17
  protected
19
18
 
20
- def blacklisted_redirect_url?
21
- DeviseTokenAuth.redirect_whitelist && !DeviseTokenAuth::Url.whitelisted?(@redirect_url)
19
+ def blacklisted_redirect_url?(redirect_url)
20
+ DeviseTokenAuth.redirect_whitelist && !DeviseTokenAuth::Url.whitelisted?(redirect_url)
22
21
  end
23
22
 
24
23
  def build_redirect_headers(access_token, client, redirect_header_options = {})
@@ -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
- devise_warden_user = warden.user(rc.to_s.underscore.to_sym)
62
- if devise_warden_user && devise_warden_user.tokens[@client_id].nil?
49
+ devise_warden_user = warden.user(mapping)
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,53 +59,51 @@ 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)
117
103
 
118
104
  else
119
105
  unless @resource.reload.valid?
120
- @resource = resource_class.find(@resource.to_param) # errors remain after reload
106
+ @resource = @resource.class.find(@resource.to_param) # errors remain after reload
121
107
  # if we left the model in a bad state, something is wrong in our app
122
108
  unless @resource.valid?
123
109
  raise DeviseTokenAuth::Errors::InvalidModel, "Cannot set auth token in invalid model. Errors: #{@resource.errors.full_messages}"
@@ -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,81 @@
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
16
+ signed_in_resource.save!
28
17
 
29
- # fall back to default value if provided
30
- @redirect_url ||= DeviseTokenAuth.default_confirm_success_url
18
+ redirect_headers = build_redirect_headers(token.token,
19
+ token.client,
20
+ redirect_header_options)
31
21
 
22
+ redirect_to_link = signed_in_resource.build_auth_url(redirect_url, redirect_headers)
23
+ else
24
+ redirect_to_link = DeviseTokenAuth::Url.generate(redirect_url, redirect_header_options)
25
+ end
32
26
 
33
- redirect_to(@resource.build_auth_url(@redirect_url, redirect_headers))
27
+ redirect_to(redirect_to_link)
34
28
  else
35
29
  raise ActionController::RoutingError, 'Not Found'
36
30
  end
37
31
  end
32
+
33
+ def create
34
+ return render_create_error_missing_email if resource_params[:email].blank?
35
+
36
+ @email = get_case_insensitive_field_from_resource_params(:email)
37
+
38
+ @resource = resource_class.dta_find_by(uid: @email, provider: provider)
39
+
40
+ return render_not_found_error unless @resource
41
+
42
+ @resource.send_confirmation_instructions({
43
+ redirect_url: redirect_url,
44
+ client_config: resource_params[:config_name]
45
+ })
46
+
47
+ return render_create_success
48
+ end
49
+
50
+ protected
51
+
52
+ def render_create_error_missing_email
53
+ render_error(401, I18n.t('devise_token_auth.confirmations.missing_email'))
54
+ end
55
+
56
+ def render_create_success
57
+ render json: {
58
+ success: true,
59
+ message: I18n.t('devise_token_auth.confirmations.sended', email: @email)
60
+ }
61
+ end
62
+
63
+ def render_not_found_error
64
+ render_error(404, I18n.t('devise_token_auth.confirmations.user_not_found', email: @email))
65
+ end
66
+
67
+ private
68
+
69
+ def resource_params
70
+ params.permit(:email, :confirmation_token, :config_name)
71
+ end
72
+
73
+ # give redirect value from params priority or fall back to default value if provided
74
+ def redirect_url
75
+ params.fetch(
76
+ :redirect_url,
77
+ DeviseTokenAuth.default_confirm_success_url
78
+ )
79
+ end
80
+
38
81
  end
39
82
  end
@@ -3,6 +3,9 @@
3
3
  module DeviseTokenAuth
4
4
  class OmniauthCallbacksController < DeviseTokenAuth::ApplicationController
5
5
  attr_reader :auth_params
6
+
7
+ before_action :validate_auth_origin_url_param
8
+
6
9
  skip_before_action :set_user_by_token, raise: false
7
10
  skip_after_action :update_auth_header
8
11
 
@@ -12,11 +15,8 @@ module DeviseTokenAuth
12
15
 
13
16
  # derive target redirect route from 'resource_class' param, which was set
14
17
  # 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
18
+ devise_mapping = get_devise_mapping
19
+ redirect_route = get_redirect_route(devise_mapping)
20
20
 
21
21
  # preserve omniauth info for success route. ignore 'extra' in twitter
22
22
  # auth response to avoid CookieOverflow.
@@ -26,6 +26,34 @@ module DeviseTokenAuth
26
26
  redirect_to redirect_route
27
27
  end
28
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
+
29
57
  def omniauth_success
30
58
  get_resource_from_auth_hash
31
59
  set_token_on_resource
@@ -50,6 +78,11 @@ module DeviseTokenAuth
50
78
  render_data_or_redirect('authFailure', error: @error)
51
79
  end
52
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
+
53
86
  protected
54
87
 
55
88
  # this will be determined differently depending on the action that calls
@@ -79,7 +112,8 @@ module DeviseTokenAuth
79
112
 
80
113
  # break out provider attribute assignment for easy method extension
81
114
  def assign_provider_attrs(user, auth_hash)
82
- attrs = auth_hash['info'].slice(*user.attributes.keys)
115
+ attrs = auth_hash['info'].to_hash
116
+ attrs = attrs.slice(*user.attribute_names)
83
117
  user.assign_attributes(attrs)
84
118
  end
85
119
 
@@ -112,10 +146,18 @@ module DeviseTokenAuth
112
146
  omniauth_params['omniauth_window_type']
113
147
  end
114
148
 
115
- def auth_origin_url
149
+ def unsafe_auth_origin_url
116
150
  omniauth_params['auth_origin_url'] || omniauth_params['origin']
117
151
  end
118
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
+
119
161
  # in the success case, omniauth_window_type is in the omniauth_params.
120
162
  # in the failure case, it is in a query param. See monkey patch above
121
163
  def omniauth_window_type
@@ -136,16 +178,6 @@ module DeviseTokenAuth
136
178
  true
137
179
  end
138
180
 
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
181
  def set_random_password
150
182
  # set crazy password for new oauth users. this is only used to prevent
151
183
  # access via email sign-in.
@@ -156,11 +188,11 @@ module DeviseTokenAuth
156
188
 
157
189
  def create_auth_params
158
190
  @auth_params = {
159
- auth_token: @token,
160
- client_id: @client_id,
161
- uid: @resource.uid,
162
- expiry: @expiry,
163
- config: @config
191
+ auth_token: @token.token,
192
+ client_id: @token.client,
193
+ uid: @resource.uid,
194
+ expiry: @token.expiry,
195
+ config: @config
164
196
  }
165
197
  @auth_params.merge!(oauth_registration: true) if @oauth_registration
166
198
  @auth_params
@@ -168,11 +200,16 @@ module DeviseTokenAuth
168
200
 
169
201
  def set_token_on_resource
170
202
  @config = omniauth_params['config_name']
171
- @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)
172
209
  end
173
210
 
174
211
  def render_data(message, data)
175
- @data = data.merge(message: message)
212
+ @data = data.merge(message: ActionController::Base.helpers.sanitize(message))
176
213
  render layout: nil, template: 'devise_token_auth/omniauth_external_window'
177
214
  end
178
215
 
@@ -209,11 +246,20 @@ module DeviseTokenAuth
209
246
  <html>
210
247
  <head></head>
211
248
  <body>
212
- #{text}
249
+ #{ActionController::Base.helpers.sanitize(text)}
213
250
  </body>
214
251
  </html>)
215
252
  end
216
253
 
254
+ def handle_new_resource
255
+ @oauth_registration = true
256
+ set_random_password
257
+ end
258
+
259
+ def assign_whitelisted_params?
260
+ true
261
+ end
262
+
217
263
  def get_resource_from_auth_hash
218
264
  # find or create user by provider and provider uid
219
265
  @resource = resource_class.where(
@@ -222,18 +268,20 @@ module DeviseTokenAuth
222
268
  ).first_or_initialize
223
269
 
224
270
  if @resource.new_record?
225
- @oauth_registration = true
226
- set_random_password
271
+ handle_new_resource
227
272
  end
228
273
 
229
274
  # sync user info with provider, update/generate auth token
230
275
  assign_provider_attrs(@resource, auth_hash)
231
276
 
232
277
  # assign any additional (whitelisted) attributes
233
- extra_params = whitelisted_params
234
- @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
235
282
 
236
283
  @resource
237
284
  end
238
285
  end
286
+
239
287
  end