devise_masquerade 1.0.0 → 1.3.2
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.
- checksums.yaml +4 -4
- data/.github/FUNDING.yml +1 -0
- data/.github/workflows/brakeman-analysis.yml +44 -0
- data/.github/workflows/rubocop-analysis.yml +39 -0
- data/.ruby-version +1 -1
- data/.travis.yml +1 -0
- data/Gemfile +4 -2
- data/Gemfile.lock +31 -18
- data/README.md +21 -1
- data/app/controllers/devise/masquerades_controller.rb +66 -24
- data/devise_masquerade.gemspec +1 -1
- data/features/back.feature +0 -1
- data/features/multiple_masquerading_models.feature +17 -0
- data/features/step_definitions/auth_steps.rb +1 -0
- data/features/step_definitions/back_steps.rb +18 -3
- data/features/step_definitions/url_helpers_steps.rb +11 -0
- data/features/url_helpers.feature +14 -0
- data/lib/devise_masquerade.rb +5 -5
- data/lib/devise_masquerade/controllers/helpers.rb +27 -6
- data/lib/devise_masquerade/controllers/url_helpers.rb +14 -2
- data/lib/devise_masquerade/models/masqueradable.rb +2 -27
- data/lib/devise_masquerade/rails.rb +5 -7
- data/lib/devise_masquerade/routes.rb +3 -2
- data/lib/devise_masquerade/version.rb +1 -1
- data/spec/controllers/admin/dashboard_controller_spec.rb +3 -4
- data/spec/controllers/dashboard_controller_spec.rb +3 -5
- data/spec/controllers/devise/masquerades_controller_spec.rb +60 -39
- data/spec/controllers/masquerades_tests_controller_spec.rb +41 -0
- data/spec/dummy/app/controllers/admin/dashboard_controller.rb +0 -1
- data/spec/dummy/app/controllers/application_controller.rb +2 -0
- data/spec/dummy/app/controllers/dashboard_controller.rb +4 -1
- data/spec/dummy/app/controllers/masquerades_tests_controller.rb +7 -0
- data/spec/dummy/app/controllers/students_controller.rb +8 -0
- data/spec/dummy/app/models/student.rb +3 -0
- data/spec/dummy/app/views/admin/dashboard/index.html.erb +0 -2
- data/spec/dummy/app/views/dashboard/extra_params.html.erb +7 -0
- data/spec/dummy/app/views/dashboard/index.html.erb +0 -2
- data/spec/dummy/app/views/layouts/application.html.erb +8 -2
- data/spec/dummy/app/views/students/_student.html.erb +6 -0
- data/spec/dummy/app/views/students/index.html.erb +1 -0
- data/spec/dummy/app/views/users/_user.html.erb +1 -1
- data/spec/dummy/config/routes.rb +9 -5
- data/spec/dummy/db/migrate/20191022100000_create_students.rb +14 -0
- data/spec/dummy/db/schema.rb +10 -1
- data/spec/models/user_spec.rb +3 -30
- data/spec/support/factories.rb +8 -4
- metadata +34 -13
- data/spec/controllers/masquerades_controller_spec.rb +0 -42
- data/spec/dummy/app/controllers/masquerades_controller.rb +0 -5
data/devise_masquerade.gemspec
CHANGED
data/features/back.feature
CHANGED
@@ -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
|
@@ -1,5 +1,5 @@
|
|
1
1
|
Given /^I have a user for masquerade$/ do
|
2
|
-
@
|
2
|
+
@user_mask = create(:user)
|
3
3
|
end
|
4
4
|
|
5
5
|
When /^I am on the users page$/ do
|
@@ -7,11 +7,11 @@ When /^I am on the users page$/ do
|
|
7
7
|
end
|
8
8
|
|
9
9
|
When /^I login as one user$/ do
|
10
|
-
|
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(@
|
14
|
+
find('.current_user').should have_content(@user_mask.email)
|
15
15
|
end
|
16
16
|
|
17
17
|
When /^I press back masquerade button$/ do
|
@@ -22,3 +22,18 @@ Then /^I should be login as owner user$/ do
|
|
22
22
|
find('.current_user').should have_content(@user.email)
|
23
23
|
end
|
24
24
|
|
25
|
+
Given /^I have a student for masquerade$/ do
|
26
|
+
@student_mask = create(:student)
|
27
|
+
end
|
28
|
+
|
29
|
+
When /^I am on the students page$/ do
|
30
|
+
visit '/students'
|
31
|
+
end
|
32
|
+
|
33
|
+
When /^I login as one student$/ do
|
34
|
+
find('.login_as').click
|
35
|
+
end
|
36
|
+
|
37
|
+
Then /^I should be login as this student$/ do
|
38
|
+
find('.current_student').should have_content(@student_mask.email)
|
39
|
+
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&masquerade=')
|
11
|
+
end
|
@@ -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
|
data/lib/devise_masquerade.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
require 'zeitwerk'
|
2
|
-
loader = Zeitwerk::Loader.for_gem
|
3
|
-
loader.setup # ready!
|
4
|
-
|
5
1
|
require 'devise'
|
2
|
+
require 'devise_masquerade/version'
|
3
|
+
require 'devise_masquerade/routes'
|
4
|
+
require 'devise_masquerade/controllers/helpers'
|
5
|
+
require 'devise_masquerade/controllers/url_helpers'
|
6
6
|
require 'devise_masquerade/rails'
|
7
7
|
|
8
8
|
module Devise
|
@@ -10,7 +10,7 @@ module Devise
|
|
10
10
|
@@masquerade_param = 'masquerade'
|
11
11
|
|
12
12
|
mattr_accessor :masquerade_expires_in
|
13
|
-
@@masquerade_expires_in =
|
13
|
+
@@masquerade_expires_in = 1.minute
|
14
14
|
|
15
15
|
mattr_accessor :masquerade_key_size
|
16
16
|
@@masquerade_key_size = 16
|
@@ -6,23 +6,44 @@ 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
|
16
|
+
Devise.masqueraded_resource_class
|
17
|
+
elsif defined?(User)
|
18
|
+
User
|
19
|
+
end
|
20
|
+
end
|
21
|
+
return unless klass
|
22
|
+
|
23
|
+
resource = GlobalID::Locator.locate_signed params[Devise.masquerade_param], for: 'masquerade'
|
24
|
+
|
25
|
+
if resource
|
26
|
+
masquerade_sign_in(resource)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
9
30
|
def masquerade_#{name}!
|
10
31
|
return if params["#{Devise.masquerade_param}"].blank?
|
11
32
|
|
12
|
-
|
33
|
+
resource = GlobalID::Locator.locate_signed params[Devise.masquerade_param], for: 'masquerade'
|
13
34
|
|
14
|
-
if
|
15
|
-
masquerade_sign_in(
|
35
|
+
if resource
|
36
|
+
masquerade_sign_in(resource)
|
16
37
|
end
|
17
38
|
end
|
18
39
|
|
19
40
|
def #{name}_masquerade?
|
20
|
-
|
41
|
+
::Rails.cache.exist?(:"devise_masquerade_#{name}").present?
|
21
42
|
end
|
22
43
|
|
23
44
|
def #{name}_masquerade_owner
|
24
45
|
return nil unless send(:#{name}_masquerade?)
|
25
|
-
|
46
|
+
GlobalID::Locator.locate_signed(Rails.cache.read(:"devise_masquerade_#{name}"), for: 'masquerade')
|
26
47
|
end
|
27
48
|
|
28
49
|
private
|
@@ -32,7 +53,7 @@ module DeviseMasquerade
|
|
32
53
|
if respond_to?(:bypass_sign_in)
|
33
54
|
bypass_sign_in(resource)
|
34
55
|
else
|
35
|
-
sign_in(resource, :
|
56
|
+
sign_in(resource, bypass: true)
|
36
57
|
end
|
37
58
|
else
|
38
59
|
sign_in(resource)
|
@@ -1,15 +1,27 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
1
3
|
module DeviseMasquerade
|
2
4
|
module Controllers
|
3
5
|
|
4
6
|
module UrlHelpers
|
5
7
|
def masquerade_path(resource, *args)
|
6
8
|
scope = Devise::Mapping.find_scope!(resource)
|
7
|
-
|
9
|
+
|
10
|
+
opts = args.shift || {}
|
11
|
+
opts.merge!(masqueraded_resource_class: resource.class.name)
|
12
|
+
|
13
|
+
opts.merge!(Devise.masquerade_param => resource.masquerade_key)
|
14
|
+
|
15
|
+
send("#{scope}_masquerade_index_path", opts, *args)
|
8
16
|
end
|
9
17
|
|
10
18
|
def back_masquerade_path(resource, *args)
|
11
19
|
scope = Devise::Mapping.find_scope!(resource)
|
12
|
-
|
20
|
+
|
21
|
+
opts = args.first || {}
|
22
|
+
opts.merge!(masqueraded_resource_class: resource.class.name)
|
23
|
+
|
24
|
+
send("back_#{scope}_masquerade_index_path", opts, *args)
|
13
25
|
end
|
14
26
|
end
|
15
27
|
|
@@ -4,35 +4,10 @@ module DeviseMasquerade
|
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
6
|
included do
|
7
|
-
|
8
|
-
|
9
|
-
def masquerade!
|
10
|
-
@masquerade_key = SecureRandom.urlsafe_base64(
|
11
|
-
Devise.masquerade_key_size)
|
12
|
-
cache_key = self.class.cache_masquerade_key_by(@masquerade_key)
|
13
|
-
::Rails.cache.write(
|
14
|
-
cache_key, id, expires_in: Devise.masquerade_expires_in)
|
7
|
+
def masquerade_key
|
8
|
+
to_sgid(expires_in: Devise.masquerade_expires_in, for: 'masquerade')
|
15
9
|
end
|
16
10
|
end
|
17
|
-
|
18
|
-
module ClassMethods
|
19
|
-
def cache_masquerade_key_by(key)
|
20
|
-
"#{self.name.pluralize.underscore}:#{key}:masquerade"
|
21
|
-
end
|
22
|
-
|
23
|
-
def remove_masquerade_key!(key)
|
24
|
-
::Rails.cache.delete(cache_masquerade_key_by(key))
|
25
|
-
end
|
26
|
-
|
27
|
-
def find_by_masquerade_key(key)
|
28
|
-
id = ::Rails.cache.read(cache_masquerade_key_by(key))
|
29
|
-
|
30
|
-
# clean up the cached masquerade key value
|
31
|
-
remove_masquerade_key!(key)
|
32
|
-
|
33
|
-
where(id: id).first
|
34
|
-
end
|
35
|
-
end # ClassMethods
|
36
11
|
end
|
37
12
|
end
|
38
13
|
end
|
@@ -1,17 +1,15 @@
|
|
1
|
-
|
2
|
-
require 'devise_masquerade/models'
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
4
3
|
module DeviseMasquerade
|
5
4
|
module Rails
|
6
5
|
|
7
6
|
class Engine < ::Rails::Engine
|
8
|
-
|
9
|
-
|
10
|
-
include DeviseMasquerade::Controllers::UrlHelpers
|
7
|
+
initializer "devise.url_helpers" do
|
8
|
+
Devise.include_helpers(DeviseMasquerade::Controllers)
|
11
9
|
end
|
12
10
|
|
13
|
-
ActiveSupport.on_load(:
|
14
|
-
include DeviseMasquerade::Controllers::
|
11
|
+
ActiveSupport.on_load(:action_controller) do
|
12
|
+
include DeviseMasquerade::Controllers::Helpers
|
15
13
|
end
|
16
14
|
end
|
17
15
|
|
@@ -3,11 +3,12 @@ module DeviseMasquerade
|
|
3
3
|
|
4
4
|
def devise_masquerade(mapping, controllers)
|
5
5
|
resources :masquerade,
|
6
|
-
only: :show,
|
7
6
|
path: mapping.path_names[:masquerade],
|
8
|
-
controller: controllers[:masquerades]
|
7
|
+
controller: controllers[:masquerades],
|
8
|
+
only: [] do
|
9
9
|
|
10
10
|
collection do
|
11
|
+
get :show
|
11
12
|
get :back
|
12
13
|
end
|
13
14
|
end
|
@@ -5,14 +5,13 @@ describe Admin::DashboardController, type: :controller do
|
|
5
5
|
before { admin_logged_in }
|
6
6
|
|
7
7
|
context 'and admin masquerade by user' do
|
8
|
-
let!(:
|
8
|
+
let!(:mask) { create(:admin_user) }
|
9
9
|
|
10
10
|
before do
|
11
|
-
|
12
|
-
get :index, params: { masquerade: user.masquerade_key }
|
11
|
+
get :index, params: { masquerade: mask.masquerade_key, masqueraded_resource_class: 'Admin::User' }
|
13
12
|
end
|
14
13
|
|
15
|
-
it { expect(current_admin_user.reload).to eq(
|
14
|
+
it { expect(current_admin_user.reload).to eq(mask) }
|
16
15
|
end
|
17
16
|
end
|
18
17
|
end
|
@@ -5,15 +5,13 @@ describe DashboardController, type: :controller do
|
|
5
5
|
before { logged_in }
|
6
6
|
|
7
7
|
context 'and admin masquerade by user' do
|
8
|
-
let!(:
|
8
|
+
let!(:mask) { create(:user) }
|
9
9
|
|
10
10
|
before do
|
11
|
-
|
12
|
-
|
13
|
-
get :index, params: { masquerade: user.masquerade_key }
|
11
|
+
get :index, params: { masquerade: mask.masquerade_key }
|
14
12
|
end
|
15
13
|
|
16
|
-
it { expect(current_user.reload).to eq(
|
14
|
+
it { expect(current_user.reload).to eq(mask) }
|
17
15
|
end
|
18
16
|
end
|
19
17
|
end
|
@@ -7,72 +7,93 @@ describe Devise::MasqueradesController, type: :controller do
|
|
7
7
|
context 'when logged in' do
|
8
8
|
before { logged_in }
|
9
9
|
|
10
|
+
context 'with masqueradable_class param' do
|
11
|
+
let(:mask) { create(:student) }
|
12
|
+
|
13
|
+
before do
|
14
|
+
get :show, params: { id: mask.to_param, masqueraded_resource_class: mask.class.name, masquerade: mask.masquerade_key }
|
15
|
+
end
|
16
|
+
|
17
|
+
it { expect(Rails.cache.read('devise_masquerade_student')).to be }
|
18
|
+
|
19
|
+
it 'should have warden keys defined' do
|
20
|
+
expect(session["warden.user.student.key"].first.first).to eq(mask.id)
|
21
|
+
end
|
22
|
+
|
23
|
+
it { should redirect_to('/') }
|
24
|
+
end
|
25
|
+
|
10
26
|
describe '#masquerade user' do
|
11
27
|
let(:mask) { create(:user) }
|
12
28
|
|
13
29
|
before do
|
14
|
-
|
15
|
-
get :show, params: { id: mask.to_param }
|
30
|
+
get :show, params: { id: mask.to_param, masquerade: mask.masquerade_key }
|
16
31
|
end
|
17
32
|
|
18
|
-
it { expect(
|
33
|
+
it { expect(Rails.cache.read('devise_masquerade_user')).to be }
|
19
34
|
it { expect(session["warden.user.user.key"].first.first).to eq(mask.id) }
|
20
|
-
it { should redirect_to(
|
35
|
+
it { should redirect_to('/') }
|
21
36
|
|
22
37
|
context 'and back' do
|
23
38
|
before { get :back }
|
24
39
|
|
25
40
|
it { should redirect_to(masquerade_page) }
|
26
41
|
it { expect(current_user.reload).to eq(@user) }
|
27
|
-
it { expect(
|
42
|
+
it { expect(Rails.cache.read('devise_masquerade_user')).not_to be }
|
28
43
|
end
|
44
|
+
end
|
29
45
|
|
30
|
-
|
31
|
-
|
32
|
-
|
46
|
+
# Configure masquerade_routes_back setting
|
47
|
+
describe 'config#masquerade_routes_back' do
|
48
|
+
let(:mask) { create(:user) }
|
33
49
|
|
34
|
-
|
50
|
+
before { Devise.setup { |c| c.masquerade_routes_back = true } }
|
35
51
|
|
36
|
-
|
37
|
-
before { expect(SecureRandom).to receive(:urlsafe_base64) { "secure_key" } }
|
52
|
+
after { Devise.masquerade_routes_back = false }
|
38
53
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
54
|
+
context 'show' do
|
55
|
+
context 'with http referrer' do
|
56
|
+
before do
|
57
|
+
@request.env['HTTP_REFERER'] = 'previous_location'
|
58
|
+
get :show, params: { id: mask.to_param, masquerade: mask.masquerade_key }
|
59
|
+
end # before
|
44
60
|
|
45
|
-
|
46
|
-
|
61
|
+
it { should redirect_to('previous_location') }
|
62
|
+
end # context
|
47
63
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
64
|
+
context 'no http referrer' do
|
65
|
+
before do
|
66
|
+
allow_any_instance_of(described_class).to(
|
67
|
+
receive(:after_masquerade_path_for).and_return("/dashboard?color=red"))
|
68
|
+
end
|
53
69
|
|
54
|
-
|
70
|
+
before { get :show, params: { id: mask.to_param, masquerade: mask.masquerade_key } }
|
55
71
|
|
56
|
-
|
57
|
-
end # context
|
72
|
+
it { should redirect_to("/dashboard?color=red") }
|
58
73
|
end # context
|
74
|
+
end # context
|
59
75
|
|
60
|
-
|
61
|
-
|
76
|
+
context 'and back' do
|
77
|
+
before do
|
78
|
+
get :show, params: { id: mask.to_param, masquerade: mask.masquerade_key }
|
62
79
|
|
63
|
-
|
64
|
-
end
|
80
|
+
get :back
|
81
|
+
end
|
65
82
|
|
66
|
-
|
67
|
-
|
68
|
-
@request.env['HTTP_REFERER'] = 'previous_location'
|
69
|
-
get :back
|
70
|
-
end
|
83
|
+
it { should redirect_to(masquerade_page) }
|
84
|
+
end # context
|
71
85
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
86
|
+
context 'and back fallback if http_referer not present' do
|
87
|
+
before do
|
88
|
+
get :show, params: { id: mask.to_param, masquerade: mask.masquerade_key }
|
89
|
+
|
90
|
+
@request.env['HTTP_REFERER'] = 'previous_location'
|
91
|
+
get :back
|
92
|
+
end
|
93
|
+
|
94
|
+
it { should redirect_to('previous_location') }
|
95
|
+
end # context
|
96
|
+
end # describe
|
76
97
|
end
|
77
98
|
|
78
99
|
context 'when not logged in' do
|