devise-tokens 1.0.0 → 1.0.1

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 (64) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/devise_tokens/application_controller.rb +77 -0
  3. data/app/controllers/devise_tokens/concerns/resource_finder.rb +42 -0
  4. data/app/controllers/devise_tokens/concerns/set_user_by_token.rb +160 -0
  5. data/app/controllers/devise_tokens/confirmations_controller.rb +79 -0
  6. data/app/controllers/devise_tokens/omniauth_callbacks_controller.rb +284 -0
  7. data/app/controllers/devise_tokens/passwords_controller.rb +204 -0
  8. data/app/controllers/devise_tokens/registrations_controller.rb +203 -0
  9. data/app/controllers/devise_tokens/sessions_controller.rb +128 -0
  10. data/app/controllers/devise_tokens/token_validations_controller.rb +29 -0
  11. data/app/controllers/devise_tokens/unlocks_controller.rb +87 -0
  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 +253 -0
  16. data/app/models/devise_token_auth/concerns/user_omniauth_callbacks.rb +28 -0
  17. data/app/validators/devise_token_auth_email_validator.rb +23 -0
  18. data/app/views/devise/mailer/confirmation_instructions.html.erb +5 -0
  19. data/app/views/devise/mailer/reset_password_instructions.html.erb +8 -0
  20. data/app/views/devise/mailer/unlock_instructions.html.erb +7 -0
  21. data/app/views/devise_token_auth/omniauth_external_window.html.erb +38 -0
  22. data/config/locales/da-DK.yml +52 -0
  23. data/config/locales/de.yml +51 -0
  24. data/config/locales/en.yml +57 -0
  25. data/config/locales/es.yml +51 -0
  26. data/config/locales/fr.yml +51 -0
  27. data/config/locales/he.yml +52 -0
  28. data/config/locales/it.yml +48 -0
  29. data/config/locales/ja.yml +48 -0
  30. data/config/locales/nl.yml +32 -0
  31. data/config/locales/pl.yml +50 -0
  32. data/config/locales/pt-BR.yml +48 -0
  33. data/config/locales/pt.yml +50 -0
  34. data/config/locales/ro.yml +48 -0
  35. data/config/locales/ru.yml +52 -0
  36. data/config/locales/sq.yml +48 -0
  37. data/config/locales/sv.yml +52 -0
  38. data/config/locales/uk.yml +61 -0
  39. data/config/locales/vi.yml +52 -0
  40. data/config/locales/zh-CN.yml +48 -0
  41. data/config/locales/zh-HK.yml +50 -0
  42. data/config/locales/zh-TW.yml +50 -0
  43. data/lib/devise_tokens.rb +14 -0
  44. data/lib/devise_tokens/blacklist.rb +2 -0
  45. data/lib/devise_tokens/controllers/helpers.rb +161 -0
  46. data/lib/devise_tokens/controllers/url_helpers.rb +10 -0
  47. data/lib/devise_tokens/engine.rb +92 -0
  48. data/lib/devise_tokens/errors.rb +6 -0
  49. data/lib/devise_tokens/rails/routes.rb +116 -0
  50. data/lib/devise_tokens/token_factory.rb +126 -0
  51. data/lib/devise_tokens/url.rb +39 -0
  52. data/lib/devise_tokens/version.rb +3 -0
  53. data/lib/generators/devise_tokens/USAGE +31 -0
  54. data/lib/generators/devise_tokens/install_generator.rb +91 -0
  55. data/lib/generators/devise_tokens/install_generator_helpers.rb +98 -0
  56. data/lib/generators/devise_tokens/install_mongoid_generator.rb +46 -0
  57. data/lib/generators/devise_tokens/install_views_generator.rb +18 -0
  58. data/lib/generators/devise_tokens/templates/devise_tokens.rb +55 -0
  59. data/lib/generators/devise_tokens/templates/devise_tokens_create_users.rb.erb +49 -0
  60. data/lib/generators/devise_tokens/templates/user.rb.erb +9 -0
  61. data/lib/generators/devise_tokens/templates/user_mongoid.rb.erb +56 -0
  62. data/lib/tasks/devise_tokens_tasks.rake +6 -0
  63. metadata +208 -4
  64. data/lib/devise-tokens.rb +0 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 78cd95c506477bf946903658700208508bf7eba1fde5bfba02b6068281550e34
4
- data.tar.gz: bffd925f0488dc99af39d2c892031a7f4b7878f1cbf57fb96a0f4b05be404571
3
+ metadata.gz: 7dafc9b9c1d7eb65cf8162acc3a06dacbd5151dfbea76da7c801564538bd275f
4
+ data.tar.gz: b798b1450394f2d804bd59efdd273fce5dad770eecf73d017248329314063d41
5
5
  SHA512:
6
- metadata.gz: f4266ac42be750d396ce6c3ea1878ea269de258326fde4af3fc298ed836f8c9c19070fd6330985268ed996624afa574bff3368d3dffb51956d70d8d746961dfb
7
- data.tar.gz: 5f779487e2966857b9e9b4d637699f8bf1b8497247e4eccae02e0cba9c6eb8a7a60c0b03129e6509e0bb805ace2548f1121403b892f2f070d95fecbaa6729e4a
6
+ metadata.gz: da07c4adec6ea1aea9f9343f0b508f5125e2922b1c5adff00f2d3a56ffaec3189c4aaa93f6357abd4999a75298bc9227a6a46049a9d0a1e68d4ff0379af89f11
7
+ data.tar.gz: 6da368d8796a98de5a218a4cf0eaa44b59f0e7466864db2a820b7228f678ec9834b9697cd2c08345018d7110a4d545bccc1fcc0cf190e2f88f0eb25fec07fc39
@@ -0,0 +1,77 @@
1
+ module DeviseTokens
2
+ class ApplicationController < DeviseController
3
+ include DeviseTokens::Concerns::SetUserByToken
4
+
5
+ def resource_data(opts = {})
6
+ response_data = opts[:resource_json] || @resource.as_json
7
+ response_data['type'] = @resource.class.name.parameterize if json_api?
8
+ response_data
9
+ end
10
+
11
+ def resource_errors
12
+ @resource.errors.to_hash.merge(full_messages: @resource.errors.full_messages)
13
+ end
14
+
15
+ protected
16
+
17
+ def blacklisted_redirect_url?(redirect_url)
18
+ DeviseTokens.redirect_whitelist && !DeviseTokens::Url.whitelisted?(redirect_url)
19
+ end
20
+
21
+ def build_redirect_headers(access_token, client, redirect_header_options = {})
22
+ {
23
+ DeviseTokens.headers_names[:"access-token"] => access_token,
24
+ DeviseTokens.headers_names[:"client"] => client,
25
+ :config => params[:config],
26
+
27
+ # Legacy parameters which may be removed in a future release.
28
+ # Consider using "client" and "access-token" in client code.
29
+ # See: github.com/lynndylanhurley/devise_tokens/issues/993
30
+ :client_id => client,
31
+ :token => access_token
32
+ }.merge(redirect_header_options)
33
+ end
34
+
35
+ def params_for_resource(resource)
36
+ devise_parameter_sanitizer.instance_values['permitted'][resource].each do |type|
37
+ params[type.to_s] ||= request.headers[type.to_s] unless request.headers[type.to_s].nil?
38
+ end
39
+ devise_parameter_sanitizer.instance_values['permitted'][resource]
40
+ end
41
+
42
+ def resource_class(m = nil)
43
+ if m
44
+ mapping = Devise.mappings[m]
45
+ else
46
+ mapping = Devise.mappings[resource_name] || Devise.mappings.values.first
47
+ end
48
+
49
+ mapping.to
50
+ end
51
+
52
+ def json_api?
53
+ return false unless defined?(ActiveModel::Serializer)
54
+ return ActiveModel::Serializer.setup do |config|
55
+ config.adapter == :json_api
56
+ end if ActiveModel::Serializer.respond_to?(:setup)
57
+ ActiveModelSerializers.config.adapter == :json_api
58
+ end
59
+
60
+ def recoverable_enabled?
61
+ resource_class.devise_modules.include?(:recoverable)
62
+ end
63
+
64
+ def confirmable_enabled?
65
+ resource_class.devise_modules.include?(:confirmable)
66
+ end
67
+
68
+ def render_error(status, message, data = nil)
69
+ response = {
70
+ success: false,
71
+ errors: [message]
72
+ }
73
+ response = response.merge(data) if data
74
+ render json: response, status: status
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,42 @@
1
+ module DeviseTokens::Concerns::ResourceFinder
2
+ extend ActiveSupport::Concern
3
+ include DeviseTokens::Controllers::Helpers
4
+
5
+ def get_case_insensitive_field_from_resource_params(field)
6
+ # honor Devise configuration for case_insensitive keys
7
+ q_value = resource_params[field.to_sym]
8
+
9
+ if resource_class.case_insensitive_keys.include?(field.to_sym)
10
+ q_value.downcase!
11
+ end
12
+
13
+ if resource_class.strip_whitespace_keys.include?(field.to_sym)
14
+ q_value.strip!
15
+ end
16
+
17
+ q_value
18
+ end
19
+
20
+ def find_resource(field, value)
21
+ @resource = if resource_class.try(:connection_config).try(:[], :adapter).try(:include?, 'mysql')
22
+ # fix for mysql default case insensitivity
23
+ resource_class.where("BINARY #{field} = ? AND provider= ?", value, provider).first
24
+ else
25
+ resource_class.dta_find_by(field => value, 'provider' => provider)
26
+ end
27
+ end
28
+
29
+ def resource_class(m = nil)
30
+ mapping = if m
31
+ Devise.mappings[m]
32
+ else
33
+ Devise.mappings[resource_name] || Devise.mappings.values.first
34
+ end
35
+
36
+ mapping.to
37
+ end
38
+
39
+ def provider
40
+ 'email'
41
+ end
42
+ end
@@ -0,0 +1,160 @@
1
+ module DeviseTokens::Concerns::SetUserByToken
2
+ extend ActiveSupport::Concern
3
+ include DeviseTokens::Concerns::ResourceFinder
4
+
5
+ included do
6
+ before_action :set_request_start
7
+ after_action :update_auth_header
8
+ end
9
+
10
+ protected
11
+
12
+ # keep track of request duration
13
+ def set_request_start
14
+ @request_started_at = Time.zone.now
15
+ @used_auth_by_token = true
16
+
17
+ # initialize instance variables
18
+ @token = DeviseTokens::TokenFactory.new
19
+ @resource ||= nil
20
+ @is_batch_request ||= nil
21
+ end
22
+
23
+ # user auth
24
+ def set_user_by_token(mapping = nil)
25
+ # determine target authentication class
26
+ rc = resource_class(mapping)
27
+
28
+ # no default user defined
29
+ return unless rc
30
+
31
+ # gets the headers names, which was set in the initialize file
32
+ uid_name = DeviseTokens.headers_names[:'uid']
33
+ access_token_name = DeviseTokens.headers_names[:'access-token']
34
+ client_name = DeviseTokens.headers_names[:'client']
35
+
36
+ # parse header for values necessary for authentication
37
+ uid = request.headers[uid_name] || params[uid_name]
38
+ @token = DeviseTokens::TokenFactory.new unless @token
39
+ @token.token ||= request.headers[access_token_name] || params[access_token_name]
40
+ @token.client ||= request.headers[client_name] || params[client_name]
41
+
42
+ # client isn't required, set to 'default' if absent
43
+ @token.client ||= 'default'
44
+
45
+ # check for an existing user, authenticated via warden/devise, if enabled
46
+ if DeviseTokens.enable_standard_devise_support
47
+ devise_warden_user = warden.user(rc.to_s.underscore.to_sym)
48
+ if devise_warden_user && devise_warden_user.tokens[@token.client].nil?
49
+ @used_auth_by_token = false
50
+ @resource = devise_warden_user
51
+ # REVIEW: The following line _should_ be safe to remove;
52
+ # the generated token does not get used anywhere.
53
+ # @resource.create_new_auth_token
54
+ end
55
+ end
56
+
57
+ # user has already been found and authenticated
58
+ return @resource if @resource && @resource.is_a?(rc)
59
+
60
+ # ensure we clear the client
61
+ unless @token.present?
62
+ @token.client = nil
63
+ return
64
+ end
65
+
66
+ # mitigate timing attacks by finding by uid instead of auth token
67
+ user = uid && rc.dta_find_by(uid: uid)
68
+ scope = rc.to_s.underscore.to_sym
69
+
70
+ if user && user.valid_token?(@token.token, @token.client)
71
+ # sign_in with bypass: true will be deprecated in the next version of Devise
72
+ if respond_to?(:bypass_sign_in) && DeviseTokens.bypass_sign_in
73
+ bypass_sign_in(user, scope: scope)
74
+ else
75
+ sign_in(scope, user, store: false, event: :fetch, bypass: DeviseTokens.bypass_sign_in)
76
+ end
77
+ return @resource = user
78
+ else
79
+ # zero all values previously set values
80
+ @token.client = nil
81
+ return @resource = nil
82
+ end
83
+ end
84
+
85
+ def update_auth_header
86
+ # cannot save object if model has invalid params
87
+ return unless @resource && @token.client
88
+
89
+ # Generate new client with existing authentication
90
+ @token.client = nil unless @used_auth_by_token
91
+
92
+ if @used_auth_by_token && !DeviseTokens.change_headers_on_each_request
93
+ # should not append auth header if @resource related token was
94
+ # cleared by sign out in the meantime
95
+ return if @resource.reload.tokens[@token.client].nil?
96
+
97
+ auth_header = @resource.build_auth_header(@token.token, @token.client)
98
+
99
+ # update the response header
100
+ response.headers.merge!(auth_header)
101
+
102
+ else
103
+ unless @resource.reload.valid?
104
+ @resource = resource_class.find(@resource.to_param) # errors remain after reload
105
+ # if we left the model in a bad state, something is wrong in our app
106
+ unless @resource.valid?
107
+ raise DeviseTokens::Errors::InvalidModel, "Cannot set auth token in invalid model. Errors: #{@resource.errors.full_messages}"
108
+ end
109
+ end
110
+ refresh_headers
111
+ end
112
+ end
113
+
114
+ private
115
+
116
+ def refresh_headers
117
+ # Lock the user record during any auth_header updates to ensure
118
+ # we don't have write contention from multiple threads
119
+ @resource.with_lock do
120
+ # should not append auth header if @resource related token was
121
+ # cleared by sign out in the meantime
122
+ return if @used_auth_by_token && @resource.tokens[@token.client].nil?
123
+
124
+ # update the response header
125
+ response.headers.merge!(auth_header_from_batch_request)
126
+ end # end lock
127
+ end
128
+
129
+ def is_batch_request?(user, client)
130
+ !params[:unbatch] &&
131
+ user.tokens[client] &&
132
+ user.tokens[client]['updated_at'] &&
133
+ user.tokens[client]['updated_at'].to_time > @request_started_at - DeviseTokens.batch_request_buffer_throttle
134
+ end
135
+
136
+ def auth_header_from_batch_request
137
+ # determine batch request status after request processing, in case
138
+ # another processes has updated it during that processing
139
+ @is_batch_request = is_batch_request?(@resource, @token.client)
140
+
141
+ auth_header = {}
142
+ # extend expiration of batch buffer to account for the duration of
143
+ # this request
144
+ if @is_batch_request
145
+ auth_header = @resource.extend_batch_buffer(@token.token, @token.client)
146
+
147
+ # Do not return token for batch requests to avoid invalidated
148
+ # tokens returned to the client in case of race conditions.
149
+ # Use a blank string for the header to still be present and
150
+ # being passed in a XHR response in case of
151
+ # 304 Not Modified responses.
152
+ auth_header[DeviseTokens.headers_names[:"access-token"]] = ' '
153
+ auth_header[DeviseTokens.headers_names[:"expiry"]] = ' '
154
+ else
155
+ # update Authorization response header with new token
156
+ auth_header = @resource.create_new_auth_token(@token.client)
157
+ end
158
+ auth_header
159
+ end
160
+ end
@@ -0,0 +1,79 @@
1
+ module DeviseTokens
2
+ class ConfirmationsController < DeviseTokens::ApplicationController
3
+
4
+ def show
5
+ @resource = resource_class.confirm_by_token(resource_params[:confirmation_token])
6
+
7
+ if @resource.errors.empty?
8
+ yield @resource if block_given?
9
+
10
+ redirect_header_options = { account_confirmation_success: true }
11
+
12
+ if signed_in?(resource_name)
13
+ token = signed_in_resource.create_token
14
+
15
+ redirect_headers = build_redirect_headers(token.token,
16
+ token.client,
17
+ redirect_header_options)
18
+
19
+ redirect_to_link = signed_in_resource.build_auth_url(redirect_url, redirect_headers)
20
+ else
21
+ redirect_to_link = DeviseTokens::Url.generate(redirect_url, redirect_header_options)
22
+ end
23
+
24
+ redirect_to(redirect_to_link)
25
+ else
26
+ raise ActionController::RoutingError, 'Not Found'
27
+ end
28
+ end
29
+
30
+ def create
31
+ return render_create_error_missing_email if resource_params[:email].blank?
32
+
33
+ @email = get_case_insensitive_field_from_resource_params(:email)
34
+
35
+ @resource = resource_class.dta_find_by(uid: @email, provider: provider)
36
+
37
+ return render_not_found_error unless @resource
38
+
39
+ @resource.send_confirmation_instructions({
40
+ redirect_url: redirect_url,
41
+ client_config: resource_params[:config_name]
42
+ })
43
+
44
+ return render_create_success
45
+ end
46
+
47
+ protected
48
+
49
+ def render_create_error_missing_email
50
+ render_error(401, I18n.t('devise_tokens.confirmations.missing_email'))
51
+ end
52
+
53
+ def render_create_success
54
+ render json: {
55
+ success: true,
56
+ message: I18n.t('devise_tokens.confirmations.sended', email: @email)
57
+ }
58
+ end
59
+
60
+ def render_not_found_error
61
+ render_error(404, I18n.t('devise_tokens.confirmations.user_not_found', email: @email))
62
+ end
63
+
64
+ private
65
+
66
+ def resource_params
67
+ params.permit(:email, :confirmation_token, :config_name)
68
+ end
69
+
70
+ # give redirect value from params priority or fall back to default value if provided
71
+ def redirect_url
72
+ params.fetch(
73
+ :redirect_url,
74
+ DeviseTokens.default_confirm_success_url
75
+ )
76
+ end
77
+
78
+ end
79
+ end
@@ -0,0 +1,284 @@
1
+ module DeviseTokens
2
+ class OmniauthCallbacksController < DeviseTokens::ApplicationController
3
+ attr_reader :auth_params
4
+
5
+ before_action :validate_auth_origin_url_param
6
+
7
+ skip_before_action :set_user_by_token, raise: false
8
+ skip_after_action :update_auth_header
9
+
10
+ # intermediary route for successful omniauth authentication. omniauth does
11
+ # not support multiple models, so we must resort to this terrible hack.
12
+ def redirect_callbacks
13
+
14
+ # derive target redirect route from 'resource_class' param, which was set
15
+ # before authentication.
16
+ devise_mapping = get_devise_mapping
17
+ redirect_route = get_redirect_route(devise_mapping)
18
+
19
+ # preserve omniauth info for success route. ignore 'extra' in twitter
20
+ # auth response to avoid CookieOverflow.
21
+ session['dta.omniauth.auth'] = request.env['omniauth.auth'].except('extra')
22
+ session['dta.omniauth.params'] = request.env['omniauth.params']
23
+
24
+ redirect_to redirect_route
25
+ end
26
+
27
+ def get_redirect_route(devise_mapping)
28
+ path = "#{Devise.mappings[devise_mapping.to_sym].fullpath}/#{params[:provider]}/callback"
29
+ klass = request.scheme == 'https' ? URI::HTTPS : URI::HTTP
30
+ redirect_route = klass.build(host: request.host, port: request.port, path: path).to_s
31
+ end
32
+
33
+ def get_devise_mapping
34
+ # derive target redirect route from 'resource_class' param, which was set
35
+ # before authentication.
36
+ devise_mapping = [request.env['omniauth.params']['namespace_name'],
37
+ request.env['omniauth.params']['resource_class'].underscore.gsub('/', '_')].compact.join('_')
38
+ rescue NoMethodError => err
39
+ default_devise_mapping
40
+ end
41
+
42
+ # This method will only be called if `get_devise_mapping` cannot
43
+ # find the mapping in `omniauth.params`.
44
+ #
45
+ # One example use-case here is for IDP-initiated SAML login. In that
46
+ # case, there will have been no initial request in which to save
47
+ # the devise mapping. If you are in a situation like that, and
48
+ # your app allows for you to determine somehow what the devise
49
+ # mapping should be (because, for example, it is always the same),
50
+ # then you can handle it by overriding this method.
51
+ def default_devise_mapping
52
+ raise NotImplementedError.new('no default_devise_mapping set')
53
+ end
54
+
55
+ def omniauth_success
56
+ get_resource_from_auth_hash
57
+ set_token_on_resource
58
+ create_auth_params
59
+
60
+ if confirmable_enabled?
61
+ # don't send confirmation email!!!
62
+ @resource.skip_confirmation!
63
+ end
64
+
65
+ sign_in(:user, @resource, store: false, bypass: false)
66
+
67
+ @resource.save!
68
+
69
+ yield @resource if block_given?
70
+
71
+ render_data_or_redirect('deliverCredentials', @auth_params.as_json, @resource.as_json)
72
+ end
73
+
74
+ def omniauth_failure
75
+ @error = params[:message]
76
+ render_data_or_redirect('authFailure', error: @error)
77
+ end
78
+
79
+ def validate_auth_origin_url_param
80
+ return render_error_not_allowed_auth_origin_url if auth_origin_url && blacklisted_redirect_url?(auth_origin_url)
81
+ end
82
+
83
+
84
+ protected
85
+
86
+ # this will be determined differently depending on the action that calls
87
+ # it. redirect_callbacks is called upon returning from successful omniauth
88
+ # authentication, and the target params live in an omniauth-specific
89
+ # request.env variable. this variable is then persisted thru the redirect
90
+ # using our own dta.omniauth.params session var. the omniauth_success
91
+ # method will access that session var and then destroy it immediately
92
+ # after use. In the failure case, finally, the omniauth params
93
+ # are added as query params in our monkey patch to OmniAuth in engine.rb
94
+ def omniauth_params
95
+ unless defined?(@_omniauth_params)
96
+ if request.env['omniauth.params'] && request.env['omniauth.params'].any?
97
+ @_omniauth_params = request.env['omniauth.params']
98
+ elsif session['dta.omniauth.params'] && session['dta.omniauth.params'].any?
99
+ @_omniauth_params ||= session.delete('dta.omniauth.params')
100
+ @_omniauth_params
101
+ elsif params['omniauth_window_type']
102
+ @_omniauth_params = params.slice('omniauth_window_type', 'auth_origin_url', 'resource_class', 'origin')
103
+ else
104
+ @_omniauth_params = {}
105
+ end
106
+ end
107
+ @_omniauth_params
108
+
109
+ end
110
+
111
+ # break out provider attribute assignment for easy method extension
112
+ def assign_provider_attrs(user, auth_hash)
113
+ attrs = auth_hash['info'].slice(*user.attribute_names)
114
+ user.assign_attributes(attrs)
115
+ end
116
+
117
+ # derive allowed params from the standard devise parameter sanitizer
118
+ def whitelisted_params
119
+ whitelist = params_for_resource(:sign_up)
120
+
121
+ whitelist.inject({}) do |coll, key|
122
+ param = omniauth_params[key.to_s]
123
+ coll[key] = param if param
124
+ coll
125
+ end
126
+ end
127
+
128
+ def resource_class(mapping = nil)
129
+ if omniauth_params['resource_class']
130
+ omniauth_params['resource_class'].constantize
131
+ elsif params['resource_class']
132
+ params['resource_class'].constantize
133
+ else
134
+ raise 'No resource_class found'
135
+ end
136
+ end
137
+
138
+ def resource_name
139
+ resource_class
140
+ end
141
+
142
+ def omniauth_window_type
143
+ omniauth_params['omniauth_window_type']
144
+ end
145
+
146
+ def unsafe_auth_origin_url
147
+ omniauth_params['auth_origin_url'] || omniauth_params['origin']
148
+ end
149
+
150
+
151
+ def auth_origin_url
152
+ if unsafe_auth_origin_url && blacklisted_redirect_url?(unsafe_auth_origin_url)
153
+ return nil
154
+ end
155
+ return unsafe_auth_origin_url
156
+ end
157
+
158
+ # in the success case, omniauth_window_type is in the omniauth_params.
159
+ # in the failure case, it is in a query param. See monkey patch above
160
+ def omniauth_window_type
161
+ omniauth_params.nil? ? params['omniauth_window_type'] : omniauth_params['omniauth_window_type']
162
+ end
163
+
164
+ # this sesison value is set by the redirect_callbacks method. its purpose
165
+ # is to persist the omniauth auth hash value thru a redirect. the value
166
+ # must be destroyed immediatly after it is accessed by omniauth_success
167
+ def auth_hash
168
+ @_auth_hash ||= session.delete('dta.omniauth.auth')
169
+ @_auth_hash
170
+ end
171
+
172
+ # ensure that this controller responds to :devise_controller? conditionals.
173
+ # this is used primarily for access to the parameter sanitizers.
174
+ def assert_is_devise_resource!
175
+ true
176
+ end
177
+
178
+ def set_random_password
179
+ # set crazy password for new oauth users. this is only used to prevent
180
+ # access via email sign-in.
181
+ p = SecureRandom.urlsafe_base64(nil, false)
182
+ @resource.password = p
183
+ @resource.password_confirmation = p
184
+ end
185
+
186
+ def create_auth_params
187
+ @auth_params = {
188
+ auth_token: @token.token,
189
+ client_id: @token.client,
190
+ uid: @resource.uid,
191
+ expiry: @token.expiry,
192
+ config: @config
193
+ }
194
+ @auth_params.merge!(oauth_registration: true) if @oauth_registration
195
+ @auth_params
196
+ end
197
+
198
+ def set_token_on_resource
199
+ @config = omniauth_params['config_name']
200
+ @token = @resource.create_token
201
+ end
202
+
203
+ def render_error_not_allowed_auth_origin_url
204
+ message = I18n.t('devise_tokens.omniauth.not_allowed_redirect_url', redirect_url: unsafe_auth_origin_url)
205
+ render_data_or_redirect('authFailure', error: message)
206
+ end
207
+
208
+ def render_data(message, data)
209
+ @data = data.merge(message: ActionController::Base.helpers.sanitize(message))
210
+ render layout: nil, template: 'devise_tokens/omniauth_external_window'
211
+ end
212
+
213
+ def render_data_or_redirect(message, data, user_data = {})
214
+
215
+ # We handle inAppBrowser and newWindow the same, but it is nice
216
+ # to support values in case people need custom implementations for each case
217
+ # (For example, nbrustein does not allow new users to be created if logging in with
218
+ # an inAppBrowser)
219
+ #
220
+ # See app/views/devise_tokens/omniauth_external_window.html.erb to understand
221
+ # why we can handle these both the same. The view is setup to handle both cases
222
+ # at the same time.
223
+ if ['inAppBrowser', 'newWindow'].include?(omniauth_window_type)
224
+ render_data(message, user_data.merge(data))
225
+
226
+ elsif auth_origin_url # default to same-window implementation, which forwards back to auth_origin_url
227
+
228
+ # build and redirect to destination url
229
+ redirect_to DeviseTokens::Url.generate(auth_origin_url, data.merge(blank: true))
230
+ else
231
+
232
+ # there SHOULD always be an auth_origin_url, but if someone does something silly
233
+ # like coming straight to this url or refreshing the page at the wrong time, there may not be one.
234
+ # In that case, just render in plain text the error message if there is one or otherwise
235
+ # a generic message.
236
+ fallback_render data[:error] || 'An error occurred'
237
+ end
238
+ end
239
+
240
+ def fallback_render(text)
241
+ render inline: %Q(
242
+
243
+ <html>
244
+ <head></head>
245
+ <body>
246
+ #{ActionController::Base.helpers.sanitize(text)}
247
+ </body>
248
+ </html>)
249
+ end
250
+
251
+ def handle_new_resource
252
+ @oauth_registration = true
253
+ set_random_password
254
+ end
255
+
256
+ def assign_whitelisted_params?
257
+ true
258
+ end
259
+
260
+ def get_resource_from_auth_hash
261
+ # find or create user by provider and provider uid
262
+ @resource = resource_class.where(
263
+ uid: auth_hash['uid'],
264
+ provider: auth_hash['provider']
265
+ ).first_or_initialize
266
+
267
+ if @resource.new_record?
268
+ handle_new_resource
269
+ end
270
+
271
+ # sync user info with provider, update/generate auth token
272
+ assign_provider_attrs(@resource, auth_hash)
273
+
274
+ # assign any additional (whitelisted) attributes
275
+ if assign_whitelisted_params?
276
+ extra_params = whitelisted_params
277
+ @resource.assign_attributes(extra_params) if extra_params
278
+ end
279
+
280
+ @resource
281
+ end
282
+ end
283
+
284
+ end