devise_token_auth_multitenancy 1.1.3.alpha1

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 (175) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +13 -0
  3. data/README.md +103 -0
  4. data/Rakefile +42 -0
  5. data/app/controllers/devise_token_auth/application_controller.rb +79 -0
  6. data/app/controllers/devise_token_auth/concerns/resource_finder.rb +44 -0
  7. data/app/controllers/devise_token_auth/concerns/set_user_by_token.rb +162 -0
  8. data/app/controllers/devise_token_auth/confirmations_controller.rb +82 -0
  9. data/app/controllers/devise_token_auth/omniauth_callbacks_controller.rb +287 -0
  10. data/app/controllers/devise_token_auth/passwords_controller.rb +206 -0
  11. data/app/controllers/devise_token_auth/registrations_controller.rb +205 -0
  12. data/app/controllers/devise_token_auth/sessions_controller.rb +131 -0
  13. data/app/controllers/devise_token_auth/token_validations_controller.rb +31 -0
  14. data/app/controllers/devise_token_auth/unlocks_controller.rb +89 -0
  15. data/app/models/devise_token_auth/concerns/active_record_support.rb +16 -0
  16. data/app/models/devise_token_auth/concerns/confirmable_support.rb +27 -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 +19 -0
  19. data/app/models/devise_token_auth/concerns/user.rb +257 -0
  20. data/app/models/devise_token_auth/concerns/user_omniauth_callbacks.rb +28 -0
  21. data/app/validators/devise_token_auth_email_validator.rb +23 -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 +57 -0
  29. data/config/locales/es.yml +51 -0
  30. data/config/locales/fr.yml +51 -0
  31. data/config/locales/he.yml +52 -0
  32. data/config/locales/it.yml +48 -0
  33. data/config/locales/ja.yml +48 -0
  34. data/config/locales/ko.yml +51 -0
  35. data/config/locales/nl.yml +32 -0
  36. data/config/locales/pl.yml +51 -0
  37. data/config/locales/pt-BR.yml +48 -0
  38. data/config/locales/pt.yml +51 -0
  39. data/config/locales/ro.yml +48 -0
  40. data/config/locales/ru.yml +52 -0
  41. data/config/locales/sq.yml +48 -0
  42. data/config/locales/sv.yml +52 -0
  43. data/config/locales/uk.yml +61 -0
  44. data/config/locales/vi.yml +52 -0
  45. data/config/locales/zh-CN.yml +48 -0
  46. data/config/locales/zh-HK.yml +50 -0
  47. data/config/locales/zh-TW.yml +50 -0
  48. data/lib/devise_token_auth/blacklist.rb +2 -0
  49. data/lib/devise_token_auth/controllers/helpers.rb +161 -0
  50. data/lib/devise_token_auth/controllers/url_helpers.rb +10 -0
  51. data/lib/devise_token_auth/engine.rb +96 -0
  52. data/lib/devise_token_auth/errors.rb +8 -0
  53. data/lib/devise_token_auth/rails/routes.rb +116 -0
  54. data/lib/devise_token_auth/token_factory.rb +126 -0
  55. data/lib/devise_token_auth/url.rb +44 -0
  56. data/lib/devise_token_auth/version.rb +5 -0
  57. data/lib/devise_token_auth.rb +14 -0
  58. data/lib/generators/devise_token_auth/USAGE +31 -0
  59. data/lib/generators/devise_token_auth/install_generator.rb +91 -0
  60. data/lib/generators/devise_token_auth/install_generator_helpers.rb +98 -0
  61. data/lib/generators/devise_token_auth/install_mongoid_generator.rb +46 -0
  62. data/lib/generators/devise_token_auth/install_views_generator.rb +18 -0
  63. data/lib/generators/devise_token_auth/templates/devise_token_auth.rb +60 -0
  64. data/lib/generators/devise_token_auth/templates/devise_token_auth_create_users.rb.erb +49 -0
  65. data/lib/generators/devise_token_auth/templates/user.rb.erb +9 -0
  66. data/lib/generators/devise_token_auth/templates/user_mongoid.rb.erb +56 -0
  67. data/lib/tasks/devise_token_auth_tasks.rake +6 -0
  68. data/test/controllers/custom/custom_confirmations_controller_test.rb +25 -0
  69. data/test/controllers/custom/custom_omniauth_callbacks_controller_test.rb +33 -0
  70. data/test/controllers/custom/custom_passwords_controller_test.rb +79 -0
  71. data/test/controllers/custom/custom_registrations_controller_test.rb +63 -0
  72. data/test/controllers/custom/custom_sessions_controller_test.rb +39 -0
  73. data/test/controllers/custom/custom_token_validations_controller_test.rb +42 -0
  74. data/test/controllers/demo_group_controller_test.rb +151 -0
  75. data/test/controllers/demo_mang_controller_test.rb +284 -0
  76. data/test/controllers/demo_user_controller_test.rb +629 -0
  77. data/test/controllers/devise_token_auth/confirmations_controller_test.rb +191 -0
  78. data/test/controllers/devise_token_auth/omniauth_callbacks_controller_test.rb +441 -0
  79. data/test/controllers/devise_token_auth/passwords_controller_test.rb +780 -0
  80. data/test/controllers/devise_token_auth/registrations_controller_test.rb +907 -0
  81. data/test/controllers/devise_token_auth/sessions_controller_test.rb +503 -0
  82. data/test/controllers/devise_token_auth/token_validations_controller_test.rb +102 -0
  83. data/test/controllers/devise_token_auth/unlocks_controller_test.rb +196 -0
  84. data/test/controllers/overrides/confirmations_controller_test.rb +47 -0
  85. data/test/controllers/overrides/omniauth_callbacks_controller_test.rb +53 -0
  86. data/test/controllers/overrides/passwords_controller_test.rb +64 -0
  87. data/test/controllers/overrides/registrations_controller_test.rb +46 -0
  88. data/test/controllers/overrides/sessions_controller_test.rb +35 -0
  89. data/test/controllers/overrides/token_validations_controller_test.rb +43 -0
  90. data/test/dummy/README.rdoc +28 -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 +18 -0
  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 +28 -0
  111. data/test/dummy/app/controllers/overrides/omniauth_callbacks_controller.rb +16 -0
  112. data/test/dummy/app/controllers/overrides/passwords_controller.rb +35 -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 +1058 -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 +14 -0
  127. data/test/dummy/config/application.rb +48 -0
  128. data/test/dummy/config/application.yml.bk +0 -0
  129. data/test/dummy/config/boot.rb +11 -0
  130. data/test/dummy/config/environment.rb +7 -0
  131. data/test/dummy/config/environments/development.rb +46 -0
  132. data/test/dummy/config/environments/production.rb +84 -0
  133. data/test/dummy/config/environments/test.rb +50 -0
  134. data/test/dummy/config/initializers/assets.rb +10 -0
  135. data/test/dummy/config/initializers/backtrace_silencers.rb +9 -0
  136. data/test/dummy/config/initializers/cookies_serializer.rb +5 -0
  137. data/test/dummy/config/initializers/devise.rb +290 -0
  138. data/test/dummy/config/initializers/devise_token_auth.rb +55 -0
  139. data/test/dummy/config/initializers/figaro.rb +3 -0
  140. data/test/dummy/config/initializers/filter_parameter_logging.rb +6 -0
  141. data/test/dummy/config/initializers/inflections.rb +18 -0
  142. data/test/dummy/config/initializers/mime_types.rb +6 -0
  143. data/test/dummy/config/initializers/omniauth.rb +11 -0
  144. data/test/dummy/config/initializers/session_store.rb +5 -0
  145. data/test/dummy/config/initializers/wrap_parameters.rb +16 -0
  146. data/test/dummy/config/routes.rb +57 -0
  147. data/test/dummy/config/spring.rb +3 -0
  148. data/test/dummy/config.ru +18 -0
  149. data/test/dummy/db/migrate/20140715061447_devise_token_auth_create_users.rb +58 -0
  150. data/test/dummy/db/migrate/20140715061805_devise_token_auth_create_mangs.rb +57 -0
  151. data/test/dummy/db/migrate/20140829044006_add_operating_thetan_to_user.rb +8 -0
  152. data/test/dummy/db/migrate/20140916224624_add_favorite_color_to_mangs.rb +7 -0
  153. data/test/dummy/db/migrate/20141222035835_devise_token_auth_create_only_email_users.rb +55 -0
  154. data/test/dummy/db/migrate/20141222053502_devise_token_auth_create_unregisterable_users.rb +56 -0
  155. data/test/dummy/db/migrate/20150708104536_devise_token_auth_create_unconfirmable_users.rb +56 -0
  156. data/test/dummy/db/migrate/20160103235141_devise_token_auth_create_scoped_users.rb +56 -0
  157. data/test/dummy/db/migrate/20160629184441_devise_token_auth_create_lockable_users.rb +56 -0
  158. data/test/dummy/db/migrate/20190924101113_devise_token_auth_create_confirmable_users.rb +49 -0
  159. data/test/dummy/db/schema.rb +198 -0
  160. data/test/dummy/lib/migration_database_helper.rb +43 -0
  161. data/test/factories/users.rb +41 -0
  162. data/test/lib/devise_token_auth/blacklist_test.rb +11 -0
  163. data/test/lib/devise_token_auth/token_factory_test.rb +191 -0
  164. data/test/lib/devise_token_auth/url_test.rb +26 -0
  165. data/test/lib/generators/devise_token_auth/install_generator_test.rb +217 -0
  166. data/test/lib/generators/devise_token_auth/install_generator_with_namespace_test.rb +222 -0
  167. data/test/lib/generators/devise_token_auth/install_views_generator_test.rb +25 -0
  168. data/test/models/concerns/mongoid_support_test.rb +31 -0
  169. data/test/models/concerns/tokens_serialization_test.rb +70 -0
  170. data/test/models/confirmable_user_test.rb +35 -0
  171. data/test/models/only_email_user_test.rb +29 -0
  172. data/test/models/user_test.rb +108 -0
  173. data/test/support/controllers/routes.rb +43 -0
  174. data/test/test_helper.rb +103 -0
  175. metadata +483 -0
@@ -0,0 +1,161 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DeviseTokenAuth
4
+ module Controllers
5
+ module Helpers
6
+ extend ActiveSupport::Concern
7
+
8
+ module ClassMethods
9
+ # Define authentication filters and accessor helpers for a group of mappings.
10
+ # These methods are useful when you are working with multiple mappings that
11
+ # share some functionality. They are pretty much the same as the ones
12
+ # defined for normal mappings.
13
+ #
14
+ # Example:
15
+ #
16
+ # inside BlogsController (or any other controller, it doesn't matter which):
17
+ # devise_group :blogger, contains: [:user, :admin]
18
+ #
19
+ # Generated methods:
20
+ # authenticate_blogger! # Redirects unless user or admin are signed in
21
+ # blogger_signed_in? # Checks whether there is either a user or an admin signed in
22
+ # current_blogger # Currently signed in user or admin
23
+ # current_bloggers # Currently signed in user and admin
24
+ # render_authenticate_error # Render error unless user or admin are signed in
25
+ #
26
+ # Use:
27
+ # before_action :authenticate_blogger! # Redirects unless either a user or an admin are authenticated
28
+ # before_action ->{ authenticate_blogger! :admin } # Redirects to the admin login page
29
+ # current_blogger :user # Preferably returns a User if one is signed in
30
+ #
31
+ def devise_token_auth_group(group_name, opts = {})
32
+ mappings = "[#{opts[:contains].map { |m| ":#{m}" }.join(',')}]"
33
+
34
+ class_eval <<-METHODS, __FILE__, __LINE__ + 1
35
+ def authenticate_#{group_name}!(favourite=nil, opts={})
36
+ unless #{group_name}_signed_in?
37
+ mappings = #{mappings}
38
+ mappings.unshift mappings.delete(favourite.to_sym) if favourite
39
+ mappings.each do |mapping|
40
+ set_user_by_token(mapping)
41
+ end
42
+
43
+ unless current_#{group_name}
44
+ render_authenticate_error
45
+ end
46
+ end
47
+ end
48
+
49
+ def #{group_name}_signed_in?
50
+ #{mappings}.any? do |mapping|
51
+ set_user_by_token(mapping)
52
+ end
53
+ end
54
+
55
+ def current_#{group_name}(favourite=nil)
56
+ mappings = #{mappings}
57
+ mappings.unshift mappings.delete(favourite.to_sym) if favourite
58
+ mappings.each do |mapping|
59
+ current = set_user_by_token(mapping)
60
+ return current if current
61
+ end
62
+ nil
63
+ end
64
+
65
+ def current_#{group_name.to_s.pluralize}
66
+ #{mappings}.map do |mapping|
67
+ set_user_by_token(mapping)
68
+ end.compact
69
+ end
70
+
71
+ def render_authenticate_error
72
+ return render json: {
73
+ errors: [I18n.t('devise.failure.unauthenticated')]
74
+ }, status: 401
75
+ end
76
+
77
+ if respond_to?(:helper_method)
78
+ helper_method(
79
+ "current_#{group_name}",
80
+ "current_#{group_name.to_s.pluralize}",
81
+ "#{group_name}_signed_in?",
82
+ "render_authenticate_error"
83
+ )
84
+ end
85
+ METHODS
86
+ end
87
+
88
+ def log_process_action(payload)
89
+ payload[:status] ||= 401 unless payload[:exception]
90
+ super
91
+ end
92
+ end
93
+
94
+ # Define authentication filters and accessor helpers based on mappings.
95
+ # These filters should be used inside the controllers as before_actions,
96
+ # so you can control the scope of the user who should be signed in to
97
+ # access that specific controller/action.
98
+ # Example:
99
+ #
100
+ # Roles:
101
+ # User
102
+ # Admin
103
+ #
104
+ # Generated methods:
105
+ # authenticate_user! # Signs user in or 401
106
+ # authenticate_admin! # Signs admin in or 401
107
+ # user_signed_in? # Checks whether there is a user signed in or not
108
+ # admin_signed_in? # Checks whether there is an admin signed in or not
109
+ # current_user # Current signed in user
110
+ # current_admin # Current signed in admin
111
+ # user_session # Session data available only to the user scope
112
+ # admin_session # Session data available only to the admin scope
113
+ # render_authenticate_error # Render error unless user or admin is signed in
114
+ #
115
+ # Use:
116
+ # before_action :authenticate_user! # Tell devise to use :user map
117
+ # before_action :authenticate_admin! # Tell devise to use :admin map
118
+ #
119
+ def self.define_helpers(mapping) #:nodoc:
120
+ mapping = mapping.name
121
+
122
+ class_eval <<-METHODS, __FILE__, __LINE__ + 1
123
+ def authenticate_#{mapping}!(opts={})
124
+ unless current_#{mapping}
125
+ render_authenticate_error
126
+ end
127
+ end
128
+
129
+ def #{mapping}_signed_in?
130
+ !!current_#{mapping}
131
+ end
132
+
133
+ def current_#{mapping}
134
+ @current_#{mapping} ||= set_user_by_token(:#{mapping})
135
+ end
136
+
137
+ def #{mapping}_session
138
+ current_#{mapping} && warden.session(:#{mapping})
139
+ end
140
+
141
+ def render_authenticate_error
142
+ return render json: {
143
+ errors: [I18n.t('devise.failure.unauthenticated')]
144
+ }, status: 401
145
+ end
146
+ METHODS
147
+
148
+ ActiveSupport.on_load(:action_controller) do
149
+ if respond_to?(:helper_method)
150
+ helper_method(
151
+ "current_#{mapping}",
152
+ "#{mapping}_signed_in?",
153
+ "#{mapping}_session",
154
+ 'render_authenticate_error'
155
+ )
156
+ end
157
+ end
158
+ end
159
+ end
160
+ end
161
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DeviseTokenAuth
4
+ module Controllers
5
+ module UrlHelpers
6
+ def self.define_helpers(mapping)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'devise_token_auth/rails/routes'
4
+
5
+ module DeviseTokenAuth
6
+ class Engine < ::Rails::Engine
7
+ isolate_namespace DeviseTokenAuth
8
+
9
+ initializer 'devise_token_auth.url_helpers' do
10
+ Devise.helpers << DeviseTokenAuth::Controllers::Helpers
11
+ end
12
+ end
13
+
14
+ mattr_accessor :change_headers_on_each_request,
15
+ :max_number_of_devices,
16
+ :token_lifespan,
17
+ :token_cost,
18
+ :batch_request_buffer_throttle,
19
+ :omniauth_prefix,
20
+ :default_confirm_success_url,
21
+ :default_password_reset_url,
22
+ :redirect_whitelist,
23
+ :check_current_password_before_update,
24
+ :enable_standard_devise_support,
25
+ :remove_tokens_after_password_reset,
26
+ :default_callbacks,
27
+ :headers_names,
28
+ :bypass_sign_in,
29
+ :send_confirmation_email,
30
+ :require_client_password_reset_token
31
+
32
+ self.change_headers_on_each_request = true
33
+ self.max_number_of_devices = 10
34
+ self.token_lifespan = 2.weeks
35
+ self.token_cost = 10
36
+ self.batch_request_buffer_throttle = 5.seconds
37
+ self.omniauth_prefix = '/omniauth'
38
+ self.default_confirm_success_url = nil
39
+ self.default_password_reset_url = nil
40
+ self.redirect_whitelist = nil
41
+ self.check_current_password_before_update = false
42
+ self.enable_standard_devise_support = false
43
+ self.remove_tokens_after_password_reset = false
44
+ self.default_callbacks = true
45
+ self.headers_names = { 'access-token': 'access-token',
46
+ 'client': 'client',
47
+ 'expiry': 'expiry',
48
+ 'uid': 'uid',
49
+ 'token-type': 'token-type' }
50
+ self.bypass_sign_in = true
51
+ self.send_confirmation_email = false
52
+ self.require_client_password_reset_token = false
53
+
54
+ def self.setup(&block)
55
+ yield self
56
+
57
+ Rails.application.config.after_initialize do
58
+ if defined?(::OmniAuth)
59
+ ::OmniAuth::config.path_prefix = Devise.omniauth_path_prefix = omniauth_prefix
60
+
61
+ # Omniauth currently does not pass along omniauth.params upon failure redirect
62
+ # see also: https://github.com/intridea/omniauth/issues/626
63
+ OmniAuth::FailureEndpoint.class_eval do
64
+ def redirect_to_failure
65
+ message_key = env['omniauth.error.type']
66
+ origin_query_param = env['omniauth.origin'] ? "&origin=#{CGI.escape(env['omniauth.origin'])}" : ''
67
+ strategy_name_query_param = env['omniauth.error.strategy'] ? "&strategy=#{env['omniauth.error.strategy'].name}" : ''
68
+ extra_params = env['omniauth.params'] ? "&#{env['omniauth.params'].to_query}" : ''
69
+ new_path = "#{env['SCRIPT_NAME']}#{OmniAuth.config.path_prefix}/failure?message=#{message_key}#{origin_query_param}#{strategy_name_query_param}#{extra_params}"
70
+ Rack::Response.new(['302 Moved'], 302, 'Location' => new_path).finish
71
+ end
72
+ end
73
+
74
+ # Omniauth currently removes omniauth.params during mocked requests
75
+ # see also: https://github.com/intridea/omniauth/pull/812
76
+ OmniAuth::Strategy.class_eval do
77
+ def mock_callback_call
78
+ setup_phase
79
+ @env['omniauth.origin'] = session.delete('omniauth.origin')
80
+ @env['omniauth.origin'] = nil if env['omniauth.origin'] == ''
81
+ @env['omniauth.params'] = session.delete('omniauth.params') || {}
82
+ mocked_auth = OmniAuth.mock_auth_for(name.to_s)
83
+ if mocked_auth.is_a?(Symbol)
84
+ fail!(mocked_auth)
85
+ else
86
+ @env['omniauth.auth'] = mocked_auth
87
+ OmniAuth.config.before_callback_phase.call(@env) if OmniAuth.config.before_callback_phase
88
+ call_app!
89
+ end
90
+ end
91
+ end
92
+
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DeviseTokenAuth
4
+ module Errors
5
+ class NoResourceDefinedError < StandardError; end
6
+ class InvalidModel < StandardError; end
7
+ end
8
+ end
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionDispatch::Routing
4
+ class Mapper
5
+ def mount_devise_token_auth_for(resource, opts)
6
+ # ensure objects exist to simplify attr checks
7
+ opts[:controllers] ||= {}
8
+ opts[:skip] ||= []
9
+
10
+ # check for ctrl overrides, fall back to defaults
11
+ sessions_ctrl = opts[:controllers][:sessions] || 'devise_token_auth/sessions'
12
+ registrations_ctrl = opts[:controllers][:registrations] || 'devise_token_auth/registrations'
13
+ passwords_ctrl = opts[:controllers][:passwords] || 'devise_token_auth/passwords'
14
+ confirmations_ctrl = opts[:controllers][:confirmations] || 'devise_token_auth/confirmations'
15
+ token_validations_ctrl = opts[:controllers][:token_validations] || 'devise_token_auth/token_validations'
16
+ omniauth_ctrl = opts[:controllers][:omniauth_callbacks] || 'devise_token_auth/omniauth_callbacks'
17
+ unlocks_ctrl = opts[:controllers][:unlocks] || 'devise_token_auth/unlocks'
18
+
19
+ # define devise controller mappings
20
+ controllers = { sessions: sessions_ctrl,
21
+ registrations: registrations_ctrl,
22
+ passwords: passwords_ctrl,
23
+ confirmations: confirmations_ctrl }
24
+
25
+ controllers[:unlocks] = unlocks_ctrl if unlocks_ctrl
26
+
27
+ # remove any unwanted devise modules
28
+ opts[:skip].each{ |item| controllers.delete(item) }
29
+
30
+ devise_for resource.pluralize.underscore.gsub('/', '_').to_sym,
31
+ class_name: resource,
32
+ module: :devise,
33
+ path: opts[:at].to_s,
34
+ controllers: controllers,
35
+ skip: opts[:skip] + [:omniauth_callbacks]
36
+
37
+ unnest_namespace do
38
+ # get full url path as if it were namespaced
39
+ full_path = "#{@scope[:path]}/#{opts[:at]}"
40
+
41
+ # get namespace name
42
+ namespace_name = @scope[:as]
43
+
44
+ # clear scope so controller routes aren't namespaced
45
+ @scope = ActionDispatch::Routing::Mapper::Scope.new(
46
+ path: '',
47
+ shallow_path: '',
48
+ constraints: {},
49
+ defaults: {},
50
+ options: {},
51
+ parent: nil
52
+ )
53
+
54
+ mapping_name = resource.underscore.gsub('/', '_')
55
+ mapping_name = "#{namespace_name}_#{mapping_name}" if namespace_name
56
+
57
+ devise_scope mapping_name.to_sym do
58
+ # path to verify token validity
59
+ get "#{full_path}/validate_token", controller: token_validations_ctrl.to_s, action: 'validate_token' if !opts[:skip].include?(:token_validations)
60
+
61
+ # omniauth routes. only define if omniauth is installed and not skipped.
62
+ if defined?(::OmniAuth) && !opts[:skip].include?(:omniauth_callbacks)
63
+ match "#{full_path}/failure", controller: omniauth_ctrl, action: 'omniauth_failure', via: [:get]
64
+ match "#{full_path}/:provider/callback", controller: omniauth_ctrl, action: 'omniauth_success', via: [:get]
65
+
66
+ match "#{DeviseTokenAuth.omniauth_prefix}/:provider/callback", controller: omniauth_ctrl, action: 'redirect_callbacks', via: [:get, :post]
67
+ match "#{DeviseTokenAuth.omniauth_prefix}/failure", controller: omniauth_ctrl, action: 'omniauth_failure', via: [:get, :post]
68
+
69
+ # preserve the resource class thru oauth authentication by setting name of
70
+ # resource as "resource_class" param
71
+ match "#{full_path}/:provider", to: redirect{ |params, request|
72
+ # get the current querystring
73
+ qs = CGI::parse(request.env['QUERY_STRING'])
74
+
75
+ # append name of current resource
76
+ qs['resource_class'] = [resource]
77
+ qs['namespace_name'] = [namespace_name] if namespace_name
78
+
79
+ set_omniauth_path_prefix!(DeviseTokenAuth.omniauth_prefix)
80
+
81
+ redirect_params = {}.tap { |hash| qs.each{ |k, v| hash[k] = v.first } }
82
+
83
+ if DeviseTokenAuth.redirect_whitelist
84
+ redirect_url = request.params['auth_origin_url']
85
+ unless DeviseTokenAuth::Url.whitelisted?(redirect_url)
86
+ message = I18n.t(
87
+ 'devise_token_auth.registrations.redirect_url_not_allowed',
88
+ redirect_url: redirect_url
89
+ )
90
+ redirect_params['message'] = message
91
+ next "#{::OmniAuth.config.path_prefix}/failure?#{redirect_params.to_param}"
92
+ end
93
+ end
94
+
95
+ # re-construct the path for omniauth
96
+ "#{::OmniAuth.config.path_prefix}/#{params[:provider]}?#{redirect_params.to_param}"
97
+ }, via: [:get]
98
+ end
99
+ end
100
+ end
101
+ end
102
+
103
+ # this allows us to use namespaced paths without namespacing the routes
104
+ def unnest_namespace
105
+ current_scope = @scope.dup
106
+ yield
107
+ ensure
108
+ @scope = current_scope
109
+ end
110
+
111
+ # ignore error about omniauth/multiple model support
112
+ def set_omniauth_path_prefix!(path_prefix)
113
+ ::OmniAuth.config.path_prefix = path_prefix
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,126 @@
1
+ require 'bcrypt'
2
+
3
+ module DeviseTokenAuth
4
+ # A token management factory which allow generate token objects and check them.
5
+ module TokenFactory
6
+ # For BCrypt::Password class see:
7
+ # https://github.com/codahale/bcrypt-ruby/blob/master/lib/bcrypt/password.rb
8
+
9
+ # Creates a token instance. Takes an optional client, lifespan and cost options.
10
+ # Example:
11
+ # DeviseTokenAuth::TokenFactory.create
12
+ # => #<struct DeviseTokenAuth::TokenFactory::Token client="tElcgkdZ7f9XEa0unZhrYQ", token="rAMcWOs0-mGHFMnIgJD2cA", token_hash="$2a$10$wrsdlHVRGlYW11wfImxU..jr0Ux3bHo/qbXcSfgp8zmvVUNHosita", expiry=1518982690>
13
+ #
14
+ # DeviseTokenAuth::TokenFactory.create(lifespan: 10, cost: 4)
15
+ # => #<struct DeviseTokenAuth::TokenFactory::Token client="5qleT7_t9JPVcX9xmxkVYA", token="RBXX43u4xXNSO-fr2N_4pA", token_hash="$2a$04$9gpCaoFbu2dUKxU3qiTgluHX7jj9UzS.jq1QW0EkQmoaxARo1WxTy", expiry=1517773268>
16
+ def self.create(client: nil, lifespan: nil, cost: nil)
17
+ # obj_client = client.nil? ? client() : client
18
+ obj_client = client || client()
19
+ obj_token = token
20
+ obj_token_hash = token_hash(obj_token, cost)
21
+ obj_expiry = expiry(lifespan)
22
+
23
+ Token.new(obj_client, obj_token, obj_token_hash, obj_expiry)
24
+ end
25
+
26
+ # Generates a random URL-safe client.
27
+ # Example:
28
+ # DeviseTokenAuth::TokenFactory.client
29
+ # => "zNf0pNP5iGfuBItZJGCseQ"
30
+ def self.client
31
+ secure_string
32
+ end
33
+
34
+ # Generates a random URL-safe token.
35
+ # Example:
36
+ # DeviseTokenAuth::TokenFactory.token
37
+ # => "6Bqs4K9x8ChLmZogvruF3A"
38
+ def self.token
39
+ secure_string
40
+ end
41
+
42
+ # Returns token hash for a token with given cost. If no cost value is specified,
43
+ # the default value is used. The possible cost value is within range from 4 to 31.
44
+ # It is recommended to not use a value more than 10.
45
+ # Example:
46
+ # DeviseTokenAuth::TokenFactory.token_hash("_qxAxmc-biQLiYRHsmwd5Q")
47
+ # => "$2a$10$6/cTAtQ3CBLfpkeHW7dlt.PD2aVCbFRN5vDDJUUhGsZ6pzYFlh4Me"
48
+ #
49
+ # DeviseTokenAuth::TokenFactory.token_hash("_qxAxmc-biQLiYRHsmwd5Q", 4)
50
+ # => "$2a$04$RkIrosbdRtuet2eUk3si8eS4ufeNpiPc/rSSsfpniRK8ogM5YFOWS"
51
+ def self.token_hash(token, cost = nil)
52
+ cost ||= DeviseTokenAuth.token_cost
53
+ BCrypt::Password.create(token, cost: cost)
54
+ end
55
+
56
+ # Returns the value of time as an integer number of seconds. Takes one argument.
57
+ # Example:
58
+ # DeviseTokenAuth::TokenFactory.expiry
59
+ # => 1518983359
60
+ # DeviseTokenAuth::TokenFactory.expiry(10)
61
+ # => 1517773781
62
+ def self.expiry(lifespan = nil)
63
+ lifespan ||= DeviseTokenAuth.token_lifespan
64
+ (Time.zone.now + lifespan).to_i
65
+ end
66
+
67
+ # Generates a random URL-safe string.
68
+ # Example:
69
+ # DeviseTokenAuth::TokenFactory.secure_string
70
+ # => "ADBoIaqXsEDnxIpOuumrTA"
71
+ def self.secure_string
72
+ # https://ruby-doc.org/stdlib-2.5.0/libdoc/securerandom/rdoc/Random/Formatter.html#method-i-urlsafe_base64
73
+ SecureRandom.urlsafe_base64
74
+ end
75
+
76
+ # Returns true if token hash is a valid token hash.
77
+ # Example:
78
+ # token_hash = "$2a$10$ArjX0tskRIa5Z/Tmapy59OCiAXLStfhrCiaDz.8fCb6hnX1gJ0p/2"
79
+ # DeviseTokenAuth::TokenFactory.valid_token_hash?(token_hash)
80
+ # => true
81
+ def self.valid_token_hash?(token_hash)
82
+ !!BCrypt::Password.valid_hash?(token_hash)
83
+ end
84
+
85
+ # Compares a potential token against the token hash. Returns true if the token is the original token, false otherwise.
86
+ # Example:
87
+ # token = "4wZ9gcc900rMQD1McpcSNA"
88
+ # token_hash = "$2a$10$ArjX0tskRIa5Z/Tmapy59OCiAXLStfhrCiaDz.8fCb6hnX1gJ0p/2"
89
+ # DeviseTokenAuth::TokenFactory.token_hash_is_token?(token_hash, token)
90
+ # => true
91
+ def self.token_hash_is_token?(token_hash, token)
92
+ BCrypt::Password.new(token_hash).is_password?(token)
93
+ rescue StandardError
94
+ false
95
+ end
96
+
97
+ # Creates a token instance with instance variables equal nil.
98
+ # Example:
99
+ # DeviseTokenAuth::TokenFactory.new
100
+ # => #<struct DeviseTokenAuth::TokenFactory::Token client=nil, token=nil, token_hash=nil, expiry=nil>
101
+ def self.new
102
+ Token.new
103
+ end
104
+
105
+ Token = Struct.new(:client, :token, :token_hash, :expiry) do
106
+ # Sets all instance variables of the token to nil. It is faster than creating new empty token.
107
+ # Example:
108
+ # token.clear!
109
+ # => true
110
+ # token
111
+ # => #<struct DeviseTokenAuth::TokenFactory::Token client=nil, token=nil, token_hash=nil, expiry=nil>
112
+ def clear!
113
+ size.times { |i| self[i] = nil }
114
+ true
115
+ end
116
+
117
+ # Checks token attribute presence
118
+ # Example:
119
+ # token.present?
120
+ # => true
121
+ def present?
122
+ token.present?
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DeviseTokenAuth::Url
4
+
5
+ def self.generate(url, params = {})
6
+ uri = URI(url)
7
+
8
+ res = "#{uri.scheme}://#{uri.host}"
9
+ res += ":#{uri.port}" if (uri.port && uri.port != 80 && uri.port != 443)
10
+ res += uri.path.to_s if uri.path
11
+ query = [uri.query, params.to_query].reject(&:blank?).join('&')
12
+ res += "?#{query}"
13
+ res += "##{uri.fragment}" if uri.fragment
14
+ # repeat any query params after the fragment to deal with Angular eating any pre fragment query params, used
15
+ # in the reset password redirect url
16
+ res += "?#{query}" if uri.fragment
17
+
18
+ res
19
+ end
20
+
21
+ def self.whitelisted?(url)
22
+ url.nil? || \
23
+ !!DeviseTokenAuth.redirect_whitelist.find do |pattern|
24
+ !!Wildcat.new(pattern).match(url)
25
+ end
26
+ end
27
+
28
+ # wildcard convenience class
29
+ class Wildcat
30
+ def self.parse_to_regex(str)
31
+ escaped = Regexp.escape(str).gsub('\*','.*?')
32
+ Regexp.new("^#{escaped}$", Regexp::IGNORECASE)
33
+ end
34
+
35
+ def initialize(str)
36
+ @regex = self.class.parse_to_regex(str)
37
+ end
38
+
39
+ def match(str)
40
+ !!@regex.match(str)
41
+ end
42
+ end
43
+
44
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DeviseTokenAuth
4
+ VERSION = '1.1.3.alpha1'.freeze
5
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'devise'
4
+
5
+ module DeviseTokenAuth
6
+ end
7
+
8
+ require 'devise_token_auth/engine'
9
+ require 'devise_token_auth/controllers/helpers'
10
+ require 'devise_token_auth/controllers/url_helpers'
11
+ require 'devise_token_auth/url'
12
+ require 'devise_token_auth/errors'
13
+ require 'devise_token_auth/blacklist'
14
+ require 'devise_token_auth/token_factory'
@@ -0,0 +1,31 @@
1
+ Description:
2
+ This generator will install all the necessary configuration and migration
3
+ files for the devise_token_auth gem. See
4
+ https://github.com/lynndylanhurley/devise_token_auth for more information.
5
+
6
+ Arguments:
7
+ USER_CLASS # The name of the class to use for user authentication. Default is
8
+ # 'User'
9
+ MOUNT_PATH # The path at which to mount the authentication routes. Default is
10
+ # 'auth'. More detail documentation is here:
11
+ # https://devise-token-auth.gitbook.io/devise-token-auth/usage
12
+
13
+ Example:
14
+ rails generate devise_token_auth:install User auth
15
+
16
+ This will create:
17
+ config/initializers/devise_token_auth.rb
18
+ db/migrate/<%= Time.zone.now.utc.strftime("%Y%m%d%H%M%S") %>_create_devise_token_auth_create_users.rb
19
+ app/models/user.rb
20
+
21
+ If 'app/models/user.rb' already exists, the following line will be inserted
22
+ after the class definition:
23
+ include DeviseTokenAuth::Concerns::User
24
+
25
+ The following line will be inserted into your application controller at
26
+ app/controllers/application_controller.rb:
27
+ include DeviseTokenAuth::Concerns::SetUserByToken
28
+
29
+ The following line will be inserted at the top of 'config/routes.rb' if it
30
+ does not already exist:
31
+ mount_devise_token_auth_for "User", at: 'auth'