devise_masquerade 0.6.5 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. checksums.yaml +5 -5
  2. data/.github/FUNDING.yml +1 -0
  3. data/.github/workflows/brakeman-analysis.yml +44 -0
  4. data/.github/workflows/rubocop-analysis.yml +39 -0
  5. data/.gitignore +1 -2
  6. data/.ruby-version +1 -1
  7. data/.travis.yml +2 -7
  8. data/Gemfile +16 -10
  9. data/Gemfile.lock +310 -0
  10. data/Makefile +6 -1
  11. data/README.md +57 -12
  12. data/app/controllers/devise/masquerades_controller.rb +119 -70
  13. data/devise_masquerade.gemspec +5 -4
  14. data/features/back.feature +15 -1
  15. data/features/expires_masquerade.feature +36 -0
  16. data/features/multiple_masquerading_models.feature +17 -0
  17. data/features/step_definitions/auth_steps.rb +8 -0
  18. data/features/step_definitions/back_steps.rb +22 -3
  19. data/features/step_definitions/expires_steps.rb +9 -0
  20. data/features/step_definitions/url_helpers_steps.rb +11 -0
  21. data/features/support/env.rb +23 -4
  22. data/features/url_helpers.feature +14 -0
  23. data/lib/devise_masquerade/controllers/helpers.rb +90 -9
  24. data/lib/devise_masquerade/controllers/url_helpers.rb +16 -2
  25. data/lib/devise_masquerade/models/masqueradable.rb +13 -0
  26. data/lib/devise_masquerade/models.rb +9 -0
  27. data/lib/devise_masquerade/rails.rb +14 -4
  28. data/lib/devise_masquerade/routes.rb +11 -8
  29. data/lib/devise_masquerade/version.rb +1 -1
  30. data/lib/devise_masquerade.rb +23 -9
  31. data/spec/controllers/admin/dashboard_controller_spec.rb +3 -4
  32. data/spec/controllers/dashboard_controller_spec.rb +3 -5
  33. data/spec/controllers/devise/masquerades_controller_spec.rb +80 -38
  34. data/spec/controllers/masquerades_tests_controller_spec.rb +57 -0
  35. data/spec/dummy/app/controllers/admin/dashboard_controller.rb +1 -2
  36. data/spec/dummy/app/controllers/application_controller.rb +2 -0
  37. data/spec/dummy/app/controllers/dashboard_controller.rb +5 -2
  38. data/spec/dummy/app/controllers/masquerades_tests_controller.rb +7 -0
  39. data/spec/dummy/app/controllers/students_controller.rb +8 -0
  40. data/spec/dummy/app/models/admin/user.rb +0 -7
  41. data/spec/dummy/app/models/student.rb +3 -0
  42. data/spec/dummy/app/models/user.rb +1 -10
  43. data/spec/dummy/app/views/admin/dashboard/index.html.erb +0 -2
  44. data/spec/dummy/app/views/dashboard/extra_params.html.erb +7 -0
  45. data/spec/dummy/app/views/dashboard/index.html.erb +0 -2
  46. data/spec/dummy/app/views/layouts/application.html.erb +10 -2
  47. data/spec/dummy/app/views/students/_student.html.erb +6 -0
  48. data/spec/dummy/app/views/students/index.html.erb +1 -0
  49. data/spec/dummy/app/views/users/_user.html.erb +1 -1
  50. data/spec/dummy/config/application.rb +2 -0
  51. data/spec/dummy/config/environment.rb +1 -0
  52. data/spec/dummy/config/routes.rb +9 -5
  53. data/spec/dummy/db/.gitignore +1 -0
  54. data/spec/dummy/db/migrate/20121119085620_devise_create_users.rb +1 -1
  55. data/spec/dummy/db/migrate/20140418160449_create_admin_users.rb +1 -1
  56. data/spec/dummy/db/migrate/20191022100000_create_students.rb +14 -0
  57. data/spec/dummy/db/schema.rb +37 -31
  58. data/spec/models/user_spec.rb +3 -30
  59. data/spec/orm/active_record.rb +5 -2
  60. data/spec/spec_helper.rb +3 -3
  61. data/spec/support/factories.rb +13 -9
  62. metadata +61 -19
  63. data/lib/devise_masquerade/model.rb +0 -42
  64. data/spec/controllers/masquerades_controller_spec.rb +0 -42
  65. data/spec/dummy/app/controllers/masquerades_controller.rb +0 -5
@@ -1,67 +1,62 @@
1
- class Devise::MasqueradesController < DeviseController
2
- if respond_to?(:prepend_before_action)
3
- prepend_before_action :authenticate_scope!, :masquerade_authorize!
4
- else
5
- prepend_before_filter :authenticate_scope!, :masquerade_authorize!
6
- end
1
+ require 'securerandom'
7
2
 
8
- if respond_to?(:before_action)
9
- before_action :save_masquerade_owner_session, :only => :show
10
- else
11
- before_filter :save_masquerade_owner_session, :only => :show
3
+ class Devise::MasqueradesController < DeviseController
4
+ Devise.mappings.each do |name, _|
5
+ class_eval <<-METHODS, __FILE__, __LINE__ + 1
6
+ skip_before_action :masquerade_#{name}!, raise: false
7
+ METHODS
12
8
  end
9
+ skip_before_action :masquerade!, raise: false
13
10
 
14
- if respond_to?(:after_action)
15
- after_action :cleanup_masquerade_owner_session, :only => :back
16
- else
17
- after_filter :cleanup_masquerade_owner_session, :only => :back
18
- end
11
+ prepend_before_action :authenticate_scope!, only: :show
12
+ prepend_before_action :masquerade_authorize!
19
13
 
20
14
  def show
21
- self.resource = find_resource
15
+ if send("#{masqueraded_resource_name}_masquerade?")
16
+ resource = masquerading_current_user
22
17
 
23
- unless self.resource
24
- flash[:error] = "#{masqueraded_resource_class} not found."
25
- redirect_to(new_user_session_path) and return
26
- end
18
+ go_back(resource, path: after_masquerade_full_path_for(resource))
19
+ else
20
+ masqueradable_resource = find_masqueradable_resource
27
21
 
28
- self.resource.masquerade!
29
- request.env["devise.skip_trackable"] = "1"
22
+ save_masquerade_owner_session(masqueradable_resource)
30
23
 
31
- masquerade_sign_in(self.resource)
24
+ resource = masqueradable_resource
25
+ sign_out(masquerading_current_user)
32
26
 
33
- if Devise.masquerade_routes_back && Rails::VERSION::MAJOR == 5
34
- redirect_back(fallback_location: after_masquerade_full_path_for(resource))
35
- elsif Devise.masquerade_routes_back && request.env['HTTP_REFERER'].present?
36
- redirect_to :back
37
- else
38
- redirect_to(after_masquerade_full_path_for(resource))
27
+ unless resource
28
+ flash[:error] = "#{masqueraded_resource_class} not found."
29
+ redirect_to(send("new_#{masqueraded_resource_name}_session_path")) and return
30
+ end
31
+
32
+ request.env['devise.skip_trackable'] = '1'
33
+
34
+ masquerade_sign_in(resource)
35
+
36
+ go_back(resource, path: after_masquerade_full_path_for(resource))
39
37
  end
40
38
  end
41
39
 
42
40
  def back
43
- user_id = session[session_key]
41
+ unless send("#{masqueraded_resource_name}_masquerade?")
42
+ resource = send("current_#{masqueraded_resource_name}")
43
+ go_back(resource, path: after_back_masquerade_path_for(resource))
44
+ else
45
+ masqueradable_resource = send("current_#{masqueraded_resource_name}")
44
46
 
45
- owner_user = if user_id.present?
46
- masquerading_resource_class.to_adapter.find_first(:id => user_id)
47
- else
48
- send(:"current_#{masquerading_resource_name}")
49
- end
47
+ unless send("#{masqueraded_resource_name}_signed_in?")
48
+ head(401) and return
49
+ end
50
50
 
51
- if masquerading_resource_class != masqueraded_resource_class
51
+ resource = find_owner_resource(masqueradable_resource)
52
52
  sign_out(send("current_#{masqueraded_resource_name}"))
53
- end
54
53
 
55
- masquerade_sign_in(owner_user)
56
- request.env["devise.skip_trackable"] = nil
54
+ sign_in(resource)
55
+ request.env['devise.skip_trackable'] = nil
57
56
 
58
- if Devise.masquerade_routes_back && Rails::VERSION::MAJOR == 5
59
- # If using the masquerade_routes_back and Rails 5
60
- redirect_back(fallback_location: after_back_masquerade_path_for(owner_user))
61
- elsif Devise.masquerade_routes_back && request.env['HTTP_REFERER'].present?
62
- redirect_to :back
63
- else
64
- redirect_to after_back_masquerade_path_for(owner_user)
57
+ go_back(resource, path: after_back_masquerade_path_for(resource))
58
+
59
+ cleanup_masquerade_owner_session(masqueradable_resource)
65
60
  end
66
61
  end
67
62
 
@@ -75,22 +70,54 @@ class Devise::MasqueradesController < DeviseController
75
70
  true
76
71
  end
77
72
 
78
- def find_resource
79
- masqueraded_resource_class.to_adapter.find_first(:id => params[:id])
73
+ def find_masqueradable_resource
74
+ GlobalID::Locator.locate_signed(params[Devise.masquerade_param], for: 'masquerade')
80
75
  end
81
76
 
82
- private
77
+ def find_owner_resource(masqueradable_resource)
78
+ skey = session_key(masqueradable_resource, masquerading_guid)
79
+
80
+ if Devise.masquerade_storage_method_session?
81
+ resource_id = session[skey]
83
82
 
84
- def masqueraded_resource_class
85
- Devise.masqueraded_resource_class || resource_class
83
+ masquerading_resource_class.find(resource_id)
84
+ else
85
+ data = Rails.cache.read(skey)
86
+
87
+ GlobalID::Locator.locate_signed(data, for: 'masquerade')
88
+ end
89
+ end
90
+
91
+ def go_back(user, path:)
92
+ if Devise.masquerade_routes_back
93
+ redirect_back(fallback_location: path)
94
+ else
95
+ redirect_to path
96
+ end
86
97
  end
87
98
 
99
+ private
100
+
88
101
  def masqueraded_resource_name
89
102
  Devise.masqueraded_resource_name || masqueraded_resource_class.model_name.param_key
90
103
  end
91
104
 
92
105
  def masquerading_resource_class
93
- Devise.masquerading_resource_class || resource_class
106
+ @masquerading_resource_class ||= begin
107
+ unless params[:masquerading_resource_class].blank?
108
+ params[:masquerading_resource_class].constantize
109
+ else
110
+ unless session[session_key_masquerading_resource_class].blank?
111
+ session[session_key_masquerading_resource_class].constantize
112
+ else
113
+ if Devise.masquerading_resource_class_name.present?
114
+ Devise.masquerading_resource_class_name.constantize
115
+ else
116
+ Devise.masquerading_resource_class || resource_class
117
+ end
118
+ end
119
+ end
120
+ end
94
121
  end
95
122
 
96
123
  def masquerading_resource_name
@@ -98,40 +125,62 @@ class Devise::MasqueradesController < DeviseController
98
125
  end
99
126
 
100
127
  def authenticate_scope!
101
- send(:"authenticate_#{masquerading_resource_name}!", :force => true)
128
+ send(:"authenticate_#{masquerading_resource_name}!", force: true)
102
129
  end
103
130
 
104
131
  def after_masquerade_path_for(resource)
105
- "/"
132
+ '/'
106
133
  end
107
134
 
108
135
  def after_masquerade_full_path_for(resource)
109
- if after_masquerade_path_for(resource) =~ /\?/
110
- "#{after_masquerade_path_for(resource)}&#{after_masquerade_param_for(resource)}"
111
- else
112
- "#{after_masquerade_path_for(resource)}?#{after_masquerade_param_for(resource)}"
113
- end
114
- end
115
-
116
- def after_masquerade_param_for(resource)
117
- "#{Devise.masquerade_param}=#{resource.masquerade_key}"
136
+ after_masquerade_path_for(resource)
118
137
  end
119
138
 
120
139
  def after_back_masquerade_path_for(resource)
121
140
  '/'
122
141
  end
123
142
 
124
- def save_masquerade_owner_session
125
- unless session.key?(session_key)
126
- session[session_key] = send("current_#{masquerading_resource_name}").id
143
+ def save_masquerade_owner_session(masqueradable_resource)
144
+ guid = SecureRandom.uuid
145
+
146
+ skey = session_key(masqueradable_resource, guid)
147
+
148
+ resource_obj = send("current_#{masquerading_resource_name}")
149
+
150
+ if Devise.masquerade_storage_method_session?
151
+ session[skey] = resource_obj.id
152
+ else
153
+ # skip sharing owner id via session
154
+ Rails.cache.write(skey, resource_obj.to_sgid(for: 'masquerade'))
155
+
156
+ session[skey] = true
127
157
  end
158
+
159
+ session[session_key_masquerading_resource_class] = masquerading_resource_class.name
160
+ session[session_key_masqueraded_resource_class] = masqueraded_resource_class.name
161
+ session[session_key_masquerading_resource_guid] = guid
128
162
  end
129
163
 
130
- def cleanup_masquerade_owner_session
131
- session.delete(session_key)
164
+ def cleanup_masquerade_owner_session(masqueradable_resource)
165
+ skey = session_key(masqueradable_resource, masquerading_guid)
166
+
167
+ Rails.cache.delete(skey) if Devise.masquerade_storage_method_cache?
168
+
169
+ session.delete(session_key_masqueraded_resource_class)
170
+ session.delete(session_key_masquerading_resource_class)
171
+ session.delete(session_key_masquerading_resource_guid)
132
172
  end
133
173
 
134
- def session_key
135
- "devise_masquerade_#{masqueraded_resource_name}".to_sym
174
+ def session_key(masqueradable_resource, guid)
175
+ "devise_masquerade_#{masqueraded_resource_name}_#{masqueradable_resource.id}_#{guid}".to_sym
176
+ end
177
+
178
+ def masquerading_current_user
179
+ send("current_#{masquerading_resource_name}")
180
+ end
181
+
182
+ def masquerading_guid
183
+ session[session_key_masquerading_resource_guid]
136
184
  end
137
185
  end
186
+
@@ -11,7 +11,7 @@ Gem::Specification.new do |gem|
11
11
  gem.email = ['alex.korsak@gmail.com']
12
12
  gem.description = 'devise masquerade library'
13
13
  gem.summary = 'use for login as functionallity on your admin users pages'
14
- gem.homepage = 'http://github.com/oivoodoo/devise_masquerade/'
14
+ gem.homepage = 'http://github.com/oivoodoo/devise_masquerade'
15
15
 
16
16
  gem.files = `git ls-files`.split($/)
17
17
  gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
@@ -20,8 +20,9 @@ Gem::Specification.new do |gem|
20
20
 
21
21
  gem.license = 'MIT'
22
22
 
23
- gem.add_development_dependency('bundler', '>= 1.1.0')
23
+ gem.add_development_dependency('bundler', '>= 2.0.0')
24
24
 
25
- gem.add_runtime_dependency('railties', '>= 3.0')
26
- gem.add_runtime_dependency('devise', '>= 2.1.0')
25
+ gem.add_runtime_dependency('railties', '>= 5.2.0')
26
+ gem.add_runtime_dependency('devise', '>= 4.7.0')
27
+ gem.add_runtime_dependency('globalid', '>= 0.3.6')
27
28
  end
@@ -3,14 +3,28 @@ Feature: Use back button for returning to the owner of the masquerade action.
3
3
  As an masquerade user
4
4
  I want to be able to press a simple button on the page
5
5
 
6
- Scenario: Use back button
6
+ Scenario: Use back button with cache
7
7
  Given I logged in
8
+ And devise masquerade configured to use cache
8
9
  And I have a user for masquerade
9
10
 
10
11
  When I am on the users page
11
12
  And I login as one user
12
13
  Then I should be login as this user
14
+ And I should be masqueraded by owner user
13
15
 
14
16
  When I press back masquerade button
15
17
  Then I should be login as owner user
16
18
 
19
+ Scenario: Use back button with session
20
+ Given I logged in
21
+ And devise masquerade configured to use session
22
+ And I have a user for masquerade
23
+
24
+ When I am on the users page
25
+ And I login as one user
26
+ Then I should be login as this user
27
+ And I should be masqueraded by owner user
28
+
29
+ When I press back masquerade button
30
+ Then I should be login as owner user
@@ -0,0 +1,36 @@
1
+ Feature: Use back button for returning to the owner despite on expiration time.
2
+ In order to back to the owner user
3
+ As an masquerade user
4
+ I want to be able to press a simple button on the page
5
+
6
+ Scenario: Use back button with cache
7
+ Given I logged in
8
+ And devise masquerade configured to use cache
9
+ And I have a user for masquerade
10
+
11
+ When I have devise masquerade expiration time in 1 second
12
+
13
+ When I am on the users page
14
+ And I login as one user
15
+ Then I should be login as this user
16
+ And I should be masqueraded by owner user
17
+ And I waited for 2 seconds
18
+
19
+ When I press back masquerade button
20
+ Then I should be login as owner user
21
+
22
+ Scenario: Use back button with session
23
+ Given I logged in
24
+ And devise masquerade configured to use session
25
+ And I have a user for masquerade
26
+
27
+ When I have devise masquerade expiration time in 1 second
28
+
29
+ When I am on the users page
30
+ And I login as one user
31
+ Then I should be login as this user
32
+ And I should be masqueraded by owner user
33
+ And I waited for 2 seconds
34
+
35
+ When I press back masquerade button
36
+ Then I should be login as owner user
@@ -0,0 +1,17 @@
1
+ Feature: Use various models for masquerading
2
+ In order to use various models for masquerading
3
+ As an masquerade user
4
+ I want to be able to press press masquerade as link for different models
5
+
6
+ Scenario: Use masquerade button on student and user models
7
+ Given I logged in
8
+ And I have a user for masquerade
9
+ And I have a student for masquerade
10
+
11
+ When I am on the users page
12
+ And I login as one user
13
+ Then I should be login as this user
14
+
15
+ When I am on the students page
16
+ And I login as one student
17
+ Then I should be login as this student
@@ -8,3 +8,11 @@ Given /^I logged in$/ do
8
8
 
9
9
  click_on 'Log in'
10
10
  end
11
+
12
+ Given("devise masquerade configured to use cache") do
13
+ Devise.masquerade_storage_method = :cache
14
+ end
15
+
16
+ Given("devise masquerade configured to use session") do
17
+ Devise.masquerade_storage_method = :session
18
+ end
@@ -1,5 +1,5 @@
1
1
  Given /^I have a user for masquerade$/ do
2
- @mask = create(:user)
2
+ @user_mask = create(:user)
3
3
  end
4
4
 
5
5
  When /^I am on the users page$/ do
@@ -7,11 +7,15 @@ When /^I am on the users page$/ do
7
7
  end
8
8
 
9
9
  When /^I login as one user$/ do
10
- click_on "Login as"
10
+ find('.login_as').click
11
11
  end
12
12
 
13
13
  Then /^I should be login as this user$/ do
14
- find('.current_user').should have_content(@mask.email)
14
+ find('.current_user').should have_content(@user_mask.email)
15
+ end
16
+
17
+ Then /^I should be masqueraded by owner user$/ do
18
+ find('.owner_user').should have_content(@user.email)
15
19
  end
16
20
 
17
21
  When /^I press back masquerade button$/ do
@@ -22,3 +26,18 @@ Then /^I should be login as owner user$/ do
22
26
  find('.current_user').should have_content(@user.email)
23
27
  end
24
28
 
29
+ Given /^I have a student for masquerade$/ do
30
+ @student_mask = create(:student)
31
+ end
32
+
33
+ When /^I am on the students page$/ do
34
+ visit '/students'
35
+ end
36
+
37
+ When /^I login as one student$/ do
38
+ find('.login_as').click
39
+ end
40
+
41
+ Then /^I should be login as this student$/ do
42
+ find('.current_student').should have_content(@student_mask.email)
43
+ end
@@ -0,0 +1,9 @@
1
+ When("I have devise masquerade expiration time in {int} second") do |seconds|
2
+ Devise.masquerade_expires_in = seconds.second
3
+ end
4
+
5
+ Then("I waited for {int} seconds") do |seconds|
6
+ sleep(seconds)
7
+
8
+ Devise.masquerade_expires_in = 5.minutes
9
+ end
@@ -0,0 +1,11 @@
1
+ Then("I should see maquerade url") do
2
+ page.html.should include('href="/users/masquerade?masquerade=')
3
+ end
4
+
5
+ When("I am on the users page with extra params") do
6
+ visit '/extra_params'
7
+ end
8
+
9
+ Then("I should see maquerade url with extra params") do
10
+ page.html.should include('href="/users/masquerade?key1=value1&amp;masquerade=')
11
+ end
@@ -1,5 +1,5 @@
1
1
  require 'cucumber/rails'
2
- require 'factory_girl'
2
+ require 'factory_bot'
3
3
  require 'database_cleaner'
4
4
  require 'cucumber/rspec/doubles'
5
5
 
@@ -9,9 +9,11 @@ ENV["RAILS_ENV"] = "test"
9
9
 
10
10
  Capybara.default_selector = :css
11
11
 
12
- ActionController::Base.allow_rescue = false
12
+ ActiveSupport.on_load(:action_controller) do
13
+ self.allow_rescue = false
14
+ end
13
15
 
14
- World(FactoryGirl::Syntax::Methods)
16
+ World(FactoryBot::Syntax::Methods)
15
17
 
16
18
  begin
17
19
  DatabaseCleaner.strategy = :transaction
@@ -20,7 +22,24 @@ rescue NameError
20
22
  end
21
23
 
22
24
  Cucumber::Rails::Database.javascript_strategy = :truncation
23
- Capybara.javascript_driver = :webkit
25
+
26
+ Capybara.register_driver :chrome do |app|
27
+ Capybara::Selenium::Driver.new(app, browser: :chrome)
28
+ end
29
+
30
+ Capybara.register_driver :headless_chrome do |app|
31
+ caps = Selenium::WebDriver::Remote::Capabilities.chrome(loggingPrefs: { browser: 'ALL' })
32
+ opts = Selenium::WebDriver::Chrome::Options.new
33
+
34
+ chrome_args = %w[--headless --window-size=1920,1080 --no-sandbox --disable-dev-shm-usage]
35
+ chrome_args.each { |arg| opts.add_argument(arg) }
36
+ Capybara::Selenium::Driver.new(app, browser: :chrome, options: opts, desired_capabilities: caps)
37
+ end
38
+
39
+ Capybara.configure do |config|
40
+ # change this to :chrome to observe tests in a real browser
41
+ config.javascript_driver = :headless_chrome
42
+ end
24
43
 
25
44
  Before do
26
45
  allow_any_instance_of(DeviseController).to receive(:devise_mapping) { Devise.mappings[:user] }
@@ -0,0 +1,14 @@
1
+ Feature: Use masquerade path to generate routes on page
2
+ In order to have the way to render masquerade path
3
+ As an user
4
+ I want to be able to see the url and use it
5
+
6
+ Scenario: Use masquerade path helper
7
+ Given I logged in
8
+ And I have a user for masquerade
9
+
10
+ When I am on the users page
11
+ Then I should see maquerade url
12
+
13
+ When I am on the users page with extra params
14
+ Then I should see maquerade url with extra params
@@ -6,49 +6,130 @@ module DeviseMasquerade
6
6
  class_name = mapping.class_name
7
7
 
8
8
  class_eval <<-METHODS, __FILE__, __LINE__ + 1
9
+ def masquerade!
10
+ return if params["#{Devise.masquerade_param}"].blank?
11
+
12
+ klass = unless params[:masqueraded_resource_class].blank?
13
+ params[:masqueraded_resource_class].constantize
14
+ else
15
+ if Devise.masqueraded_resource_class_name.present?
16
+ Devise.masqueraded_resource_class_name.constantize
17
+ elsif Devise.masqueraded_resource_class
18
+ Devise.masqueraded_resource_class
19
+ elsif defined?(User)
20
+ User
21
+ end
22
+ end
23
+ return unless klass
24
+
25
+ resource = GlobalID::Locator.locate_signed params[Devise.masquerade_param], for: 'masquerade'
26
+
27
+ if resource
28
+ masquerade_sign_in(resource)
29
+ end
30
+ end
31
+
9
32
  def masquerade_#{name}!
10
33
  return if params["#{Devise.masquerade_param}"].blank?
11
34
 
12
- #{name} = ::#{class_name}.find_by_masquerade_key(params["#{Devise.masquerade_param}"])
35
+ resource = GlobalID::Locator.locate_signed params[Devise.masquerade_param], for: 'masquerade'
13
36
 
14
- if #{name}
15
- masquerade_sign_in(#{name})
37
+ if resource
38
+ masquerade_sign_in(resource)
16
39
  end
17
40
  end
18
41
 
19
42
  def #{name}_masquerade?
20
- session[:"devise_masquerade_#{name}"].present?
43
+ return false if current_#{name}.blank?
44
+ return false if session[#{name}_helper_session_key].blank?
45
+
46
+ if Devise.masquerade_storage_method_session?
47
+ session[#{name}_helper_session_key].present?
48
+ else
49
+ ::Rails.cache.exist?(#{name}_helper_session_key).present?
50
+ end
21
51
  end
22
52
 
23
53
  def #{name}_masquerade_owner
24
- return nil unless send(:#{name}_masquerade?)
25
- ::#{class_name}.to_adapter.find_first(:id => session[:"devise_masquerade_#{name}"])
54
+ return unless send(:#{name}_masquerade?)
55
+
56
+ if Devise.masquerade_storage_method_session?
57
+ resource_id = session[#{name}_helper_session_key]
58
+
59
+ masqueraded_resource_class.find(resource_id)
60
+ else
61
+ sgid = ::Rails.cache.read(#{name}_helper_session_key)
62
+
63
+ GlobalID::Locator.locate_signed(sgid, for: 'masquerade')
64
+ end
26
65
  end
27
66
 
28
67
  private
29
68
 
69
+ def #{name}_helper_session_key
70
+ ["devise_masquerade_#{name}", current_#{name}.id, #{name}_helper_masquerading_resource_guid].join("_")
71
+ end
72
+
73
+ def #{name}_helper_masquerading_resource_guid
74
+ session["devise_masquerade_masquerading_resource_guid"].to_s
75
+ end
76
+
30
77
  def masquerade_sign_in(resource)
31
78
  if Devise.masquerade_bypass_warden_callback
32
79
  if respond_to?(:bypass_sign_in)
33
80
  bypass_sign_in(resource)
34
81
  else
35
- sign_in(resource, :bypass => true)
82
+ sign_in(resource, bypass: true)
36
83
  end
37
84
  else
38
85
  sign_in(resource)
39
86
  end
40
87
  end
88
+
89
+ def masqueraded_resource_class
90
+ @masqueraded_resource_class ||= begin
91
+ unless params[:masqueraded_resource_class].blank?
92
+ params[:masqueraded_resource_class].constantize
93
+ else
94
+ unless session[session_key_masqueraded_resource_class].blank?
95
+ session[session_key_masquerading_resource_class].constantize
96
+ else
97
+ if Devise.masqueraded_resource_class_name.present?
98
+ Devise.masqueraded_resource_class_name.constantize
99
+ else
100
+ Devise.masqueraded_resource_class || resource_class
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
106
+
107
+ def session_key_masqueraded_resource_class
108
+ "devise_masquerade_masqueraded_resource_class"
109
+ end
110
+
111
+ def session_key_masquerading_resource_class
112
+ "devise_masquerade_masquerading_resource_class"
113
+ end
114
+
115
+ def session_key_masquerading_resource_guid
116
+ "devise_masquerade_masquerading_resource_guid"
117
+ end
118
+
41
119
  METHODS
42
120
 
43
121
  ActiveSupport.on_load(:action_controller) do
44
122
  if respond_to?(:helper_method)
45
123
  helper_method "#{name}_masquerade?"
46
124
  helper_method "#{name}_masquerade_owner"
125
+
126
+ helper_method :masqueraded_resource_class
127
+ helper_method :session_key_masqueraded_resource_class
128
+ helper_method :session_key_masquerading_resource_class
129
+ helper_method :session_key_masquerading_resource_guid
47
130
  end
48
131
  end
49
132
  end
50
133
  end
51
134
  end
52
135
  end
53
-
54
- ActionController::Base.send(:include, DeviseMasquerade::Controllers::Helpers)
@@ -1,16 +1,30 @@
1
+ require 'securerandom'
2
+
1
3
  module DeviseMasquerade
2
4
  module Controllers
5
+
3
6
  module UrlHelpers
4
7
  def masquerade_path(resource, *args)
5
8
  scope = Devise::Mapping.find_scope!(resource)
6
- send("#{scope}_masquerade_path", resource, *args)
9
+
10
+ opts = args.shift || {}
11
+ opts[:masqueraded_resource_class] = resource.class.name
12
+
13
+ opts[Devise.masquerade_param] = resource.masquerade_key
14
+
15
+ send("#{scope}_masquerade_index_path", opts, *args)
7
16
  end
8
17
 
9
18
  def back_masquerade_path(resource, *args)
10
19
  scope = Devise::Mapping.find_scope!(resource)
11
- send("back_#{scope}_masquerade_index_path", *args)
20
+
21
+ opts = args.first || {}
22
+ opts[:masqueraded_resource_class] = resource.class.name
23
+
24
+ send("back_#{scope}_masquerade_index_path", opts, *args)
12
25
  end
13
26
  end
27
+
14
28
  end
15
29
  end
16
30