devise_masquerade 1.0.0 → 1.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  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/.ruby-version +1 -1
  6. data/.travis.yml +1 -0
  7. data/Gemfile +4 -2
  8. data/Gemfile.lock +31 -18
  9. data/README.md +21 -1
  10. data/app/controllers/devise/masquerades_controller.rb +66 -24
  11. data/devise_masquerade.gemspec +1 -1
  12. data/features/back.feature +0 -1
  13. data/features/multiple_masquerading_models.feature +17 -0
  14. data/features/step_definitions/auth_steps.rb +1 -0
  15. data/features/step_definitions/back_steps.rb +18 -3
  16. data/features/step_definitions/url_helpers_steps.rb +11 -0
  17. data/features/url_helpers.feature +14 -0
  18. data/lib/devise_masquerade.rb +5 -5
  19. data/lib/devise_masquerade/controllers/helpers.rb +27 -6
  20. data/lib/devise_masquerade/controllers/url_helpers.rb +14 -2
  21. data/lib/devise_masquerade/models/masqueradable.rb +2 -27
  22. data/lib/devise_masquerade/rails.rb +5 -7
  23. data/lib/devise_masquerade/routes.rb +3 -2
  24. data/lib/devise_masquerade/version.rb +1 -1
  25. data/spec/controllers/admin/dashboard_controller_spec.rb +3 -4
  26. data/spec/controllers/dashboard_controller_spec.rb +3 -5
  27. data/spec/controllers/devise/masquerades_controller_spec.rb +60 -39
  28. data/spec/controllers/masquerades_tests_controller_spec.rb +41 -0
  29. data/spec/dummy/app/controllers/admin/dashboard_controller.rb +0 -1
  30. data/spec/dummy/app/controllers/application_controller.rb +2 -0
  31. data/spec/dummy/app/controllers/dashboard_controller.rb +4 -1
  32. data/spec/dummy/app/controllers/masquerades_tests_controller.rb +7 -0
  33. data/spec/dummy/app/controllers/students_controller.rb +8 -0
  34. data/spec/dummy/app/models/student.rb +3 -0
  35. data/spec/dummy/app/views/admin/dashboard/index.html.erb +0 -2
  36. data/spec/dummy/app/views/dashboard/extra_params.html.erb +7 -0
  37. data/spec/dummy/app/views/dashboard/index.html.erb +0 -2
  38. data/spec/dummy/app/views/layouts/application.html.erb +8 -2
  39. data/spec/dummy/app/views/students/_student.html.erb +6 -0
  40. data/spec/dummy/app/views/students/index.html.erb +1 -0
  41. data/spec/dummy/app/views/users/_user.html.erb +1 -1
  42. data/spec/dummy/config/routes.rb +9 -5
  43. data/spec/dummy/db/migrate/20191022100000_create_students.rb +14 -0
  44. data/spec/dummy/db/schema.rb +10 -1
  45. data/spec/models/user_spec.rb +3 -30
  46. data/spec/support/factories.rb +8 -4
  47. metadata +34 -13
  48. data/spec/controllers/masquerades_controller_spec.rb +0 -42
  49. data/spec/dummy/app/controllers/masquerades_controller.rb +0 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 53c11df20b59df74e7a1c60c2c895c4174583cfa8211a5922d2eafe4c5b92855
4
- data.tar.gz: 8e39886ffd23cf8dcbe841da11802ffd3db437ba94ed8a38962a82cd29a8e475
3
+ metadata.gz: 7b817222d25ead9ef77e2075ab3d2f86693659fea00373b9cd998c8dfc81becb
4
+ data.tar.gz: 7d95e96a4ed3f3c6addcb54fcab39fe0df54d6eeaf513e0d363035b61d1da46e
5
5
  SHA512:
6
- metadata.gz: '0528ff0b74a4008536b5cbaa404d16483bc3a6fe399f00899d3297d2a8dac95bedb945c5b65c920b47c3721799e02d82644cca2152145db19b7026e3a1674e32'
7
- data.tar.gz: 47123c4f6eccfc61ff5171ece7db757cd05bf7fa87f32731d4b4bfe13d1cfe542d3f8a28c251bcd6bb4a6e4de95a7d070b3fb7fee4d2aebdbbd0dfd646d9f039
6
+ metadata.gz: dcec6dae97ed366a03553c6762f4d042a256aed0765aec2fe39c64ea93ecf1f4593eb60e7d57555fc399b0f4ae818f6883e80b11974b0a88c17bdfb18831cc0d
7
+ data.tar.gz: 6814d659d4cb22cb9b88aacd55d0ca3a54c208248919b389174cb220d4bf856682fe6cfd3ce287ec03bdc9554baec3e3556d7b44c92139138daaf3467b44b682
@@ -0,0 +1 @@
1
+ patreon: oivoodoo
@@ -0,0 +1,44 @@
1
+ # This workflow integrates Brakeman with GitHub's Code Scanning feature
2
+ # Brakeman is a static analysis security vulnerability scanner for Ruby on Rails applications
3
+
4
+ name: Brakeman Scan
5
+
6
+ # This section configures the trigger for the workflow. Feel free to customize depending on your convention
7
+ on:
8
+ push:
9
+ branches: [ "master", "main" ]
10
+ pull_request:
11
+ branches: [ "master", "main" ]
12
+
13
+ jobs:
14
+ brakeman-scan:
15
+ name: Brakeman Scan
16
+ runs-on: ubuntu-latest
17
+ steps:
18
+ # Checkout the repository to the GitHub Actions runner
19
+ - name: Checkout
20
+ uses: actions/checkout@v2
21
+
22
+ # Customize the ruby version depending on your needs
23
+ - name: Setup Ruby
24
+ uses: actions/setup-ruby@v1
25
+ with:
26
+ ruby-version: '2.7'
27
+
28
+ - name: Setup Brakeman
29
+ env:
30
+ BRAKEMAN_VERSION: '4.10' # SARIF support is provided in Brakeman version 4.10+
31
+ run: |
32
+ gem install brakeman --version $BRAKEMAN_VERSION
33
+
34
+ # Execute Brakeman CLI and generate a SARIF output with the security issues identified during the analysis
35
+ - name: Scan
36
+ continue-on-error: true
37
+ run: |
38
+ brakeman -f sarif -o output.sarif.json .
39
+
40
+ # Upload the SARIF file generated in the previous step
41
+ - name: Upload SARIF
42
+ uses: github/codeql-action/upload-sarif@v1
43
+ with:
44
+ sarif_file: output.sarif.json
@@ -0,0 +1,39 @@
1
+ name: "Rubocop"
2
+
3
+ on: push
4
+
5
+ jobs:
6
+ rubocop:
7
+ runs-on: ubuntu-latest
8
+ strategy:
9
+ fail-fast: false
10
+
11
+ steps:
12
+ - name: Checkout repository
13
+ uses: actions/checkout@v2
14
+
15
+ # If running on a self-hosted runner, check it meets the requirements
16
+ # listed at https://github.com/ruby/setup-ruby#using-self-hosted-runners
17
+ - name: Set up Ruby
18
+ uses: ruby/setup-ruby@v1
19
+ with:
20
+ ruby-version: 2.6
21
+
22
+ # This step is not necessary if you add the gem to your Gemfile
23
+ - name: Install Code Scanning integration
24
+ run: bundle add code-scanning-rubocop --version 0.3.0 --skip-install
25
+
26
+ - name: Install dependencies
27
+ run: bundle install
28
+
29
+ - name: Rubocop run
30
+ run: |
31
+ bash -c "
32
+ bundle exec rubocop --require code_scanning --format CodeScanning::SarifFormatter -o rubocop.sarif
33
+ [[ $? -ne 2 ]]
34
+ "
35
+
36
+ - name: Upload Sarif output
37
+ uses: github/codeql-action/upload-sarif@v1
38
+ with:
39
+ sarif_file: rubocop.sarif
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.6.0
1
+ 2.7.2
data/.travis.yml CHANGED
@@ -2,6 +2,7 @@ language: ruby
2
2
  rvm:
3
3
  - 2.5.1
4
4
  - 2.6.0
5
+ - 2.7.2
5
6
  gemfile:
6
7
  - Gemfile
7
8
  script: time ./script/travis.sh
data/Gemfile CHANGED
@@ -15,11 +15,11 @@ group :test do
15
15
  gem 'pry-byebug'
16
16
 
17
17
  gem 'guard'
18
- gem 'guard-rspec'
18
+ gem 'guard-rspec', '~> 4.7'
19
19
  gem 'guard-bundler'
20
20
  gem 'guard-cucumber'
21
21
 
22
- gem 'rspec'
22
+ gem 'rspec', github: 'rspec/rspec'
23
23
  gem 'rspec-core', github: 'rspec/rspec-core'
24
24
  gem 'rspec-expectations', github: 'rspec/rspec-expectations'
25
25
  gem 'rspec-mocks', github: 'rspec/rspec-mocks'
@@ -36,4 +36,6 @@ group :test do
36
36
  gem 'selenium-webdriver'
37
37
  gem 'chromedriver-helper'
38
38
  gem 'launchy'
39
+
40
+ gem "nokogiri", ">= 1.10.8"
39
41
  end
data/Gemfile.lock CHANGED
@@ -40,13 +40,22 @@ GIT
40
40
  specs:
41
41
  rspec-support (3.10.0.pre)
42
42
 
43
+ GIT
44
+ remote: https://github.com/rspec/rspec.git
45
+ revision: e1c2c6bd78c849d7956431331f32ba5092951dab
46
+ specs:
47
+ rspec (3.10.0.pre)
48
+ rspec-core (= 3.10.0.pre)
49
+ rspec-expectations (= 3.10.0.pre)
50
+ rspec-mocks (= 3.10.0.pre)
51
+
43
52
  PATH
44
53
  remote: .
45
54
  specs:
46
- devise_masquerade (1.0.0)
55
+ devise_masquerade (1.3.2)
47
56
  devise (>= 4.7.0)
57
+ globalid (>= 0.3.6)
48
58
  railties (>= 5.2.0)
49
- zeitwerk (>= 2.2.0)
50
59
 
51
60
  GEM
52
61
  remote: https://rubygems.org/
@@ -89,7 +98,7 @@ GEM
89
98
  archive-zip (0.12.0)
90
99
  io-like (~> 0.3.0)
91
100
  backports (3.15.0)
92
- bcrypt (3.1.13)
101
+ bcrypt (3.1.16)
93
102
  bson (1.12.5)
94
103
  bson_ext (1.12.5)
95
104
  bson (~> 1.12.5)
@@ -133,7 +142,7 @@ GEM
133
142
  cucumber-tag_expressions (1.1.1)
134
143
  cucumber-wire (0.0.1)
135
144
  database_cleaner (1.0.1)
136
- devise (4.7.1)
145
+ devise (4.7.3)
137
146
  bcrypt (~> 3.0)
138
147
  orm_adapter (~> 0.1)
139
148
  railties (>= 4.1.0)
@@ -169,8 +178,10 @@ GEM
169
178
  cucumber (>= 1.3.0)
170
179
  guard-compat (~> 1.0)
171
180
  nenv (~> 0.1)
172
- guard-rspec (1.2.2)
173
- guard (>= 1.1)
181
+ guard-rspec (4.7.3)
182
+ guard (~> 2.1)
183
+ guard-compat (~> 1.1)
184
+ rspec (>= 2.99.0, < 4.0)
174
185
  i18n (1.7.0)
175
186
  concurrent-ruby (~> 1.0)
176
187
  io-like (0.3.0)
@@ -179,7 +190,7 @@ GEM
179
190
  listen (3.2.0)
180
191
  rb-fsevent (~> 0.10, >= 0.10.3)
181
192
  rb-inotify (~> 0.9, >= 0.9.10)
182
- loofah (2.3.0)
193
+ loofah (2.3.1)
183
194
  crass (~> 1.0.2)
184
195
  nokogiri (>= 1.5.9)
185
196
  lumberjack (1.0.13)
@@ -190,13 +201,14 @@ GEM
190
201
  mime-types-data (~> 3.2015)
191
202
  mime-types-data (3.2019.1009)
192
203
  mini_mime (1.0.2)
193
- mini_portile2 (2.4.0)
204
+ mini_portile2 (2.5.0)
194
205
  minitest (5.12.2)
195
206
  multi_json (1.14.1)
196
207
  multi_test (0.1.2)
197
208
  nenv (0.3.0)
198
- nokogiri (1.10.4)
199
- mini_portile2 (~> 2.4.0)
209
+ nokogiri (1.11.1)
210
+ mini_portile2 (~> 2.5.0)
211
+ racc (~> 1.4)
200
212
  notiffany (0.1.3)
201
213
  nenv (~> 0.1)
202
214
  shellany (~> 0.0)
@@ -209,7 +221,8 @@ GEM
209
221
  byebug (~> 11.0)
210
222
  pry (~> 0.10)
211
223
  public_suffix (4.0.1)
212
- rack (2.0.7)
224
+ racc (1.5.2)
225
+ rack (2.2.3)
213
226
  rack-test (1.1.0)
214
227
  rack (>= 1.0, < 3)
215
228
  rails-dom-testing (2.0.3)
@@ -228,10 +241,9 @@ GEM
228
241
  rb-inotify (0.10.0)
229
242
  ffi (~> 1.0)
230
243
  regexp_parser (1.6.0)
231
- responders (3.0.0)
244
+ responders (3.0.1)
232
245
  actionpack (>= 5.0)
233
246
  railties (>= 5.0)
234
- rspec (1.3.2)
235
247
  rubyzip (2.0.0)
236
248
  selenium-webdriver (3.142.6)
237
249
  childprocess (>= 0.5, < 4.0)
@@ -250,8 +262,8 @@ GEM
250
262
  thread_safe (0.3.6)
251
263
  tzinfo (1.2.5)
252
264
  thread_safe (~> 0.1)
253
- warden (1.2.8)
254
- rack (>= 2.0.6)
265
+ warden (1.2.9)
266
+ rack (>= 2.0.9)
255
267
  xpath (3.2.0)
256
268
  nokogiri (~> 1.8)
257
269
  zeitwerk (2.2.0)
@@ -274,12 +286,13 @@ DEPENDENCIES
274
286
  guard
275
287
  guard-bundler
276
288
  guard-cucumber
277
- guard-rspec
289
+ guard-rspec (~> 4.7)
278
290
  launchy
291
+ nokogiri (>= 1.10.8)
279
292
  pry
280
293
  pry-byebug
281
294
  rb-fsevent
282
- rspec
295
+ rspec!
283
296
  rspec-core!
284
297
  rspec-expectations!
285
298
  rspec-mocks!
@@ -291,4 +304,4 @@ DEPENDENCIES
291
304
  test-unit
292
305
 
293
306
  BUNDLED WITH
294
- 2.0.2
307
+ 2.1.4
data/README.md CHANGED
@@ -33,18 +33,30 @@ In the view you can use url helper for defining link:
33
33
 
34
34
  = link_to "Login As", masquerade_path(user)
35
35
 
36
+ `masquerade_path` would create specific `/masquerade` path with query params `masquerade`(key) and `masqueraded_resource_class` to know
37
+ which model to choose to search and sign in by masquerade key.
38
+
36
39
  In the model you'll need to add the parameter :masqueradable to the existing comma separated values in the devise method:
37
40
 
38
41
  ```ruby
39
42
  devise :invitable, :confirmable, :database_authenticatable, :registerable, :masqueradable
40
43
  ```
41
44
 
42
- Add into your application_controller.rb:
45
+ Add into your `application_controller.rb` if you want to have custom way on sign in by using masquerade token otherwise you can still
46
+ use only `masquerade_path` in your view to generate temporary token and link to make `Login As`:
43
47
 
44
48
  ```ruby
45
49
  before_action :masquerade_user!
46
50
  ```
47
51
 
52
+ or
53
+
54
+ ```ruby
55
+ before_action :masquerade!
56
+ ```
57
+
58
+ `masquerade!` is generic way in case if you want to support multiple models on masquerade.
59
+
48
60
  Instead of user you can use your resource name admin, student or another names.
49
61
 
50
62
  If you want to back to the owner of masquerade action user you could use
@@ -167,6 +179,14 @@ in `routes.rb`:
167
179
  And check http://localhost:3000/, use for login user1@example.com and
168
180
  'password'
169
181
 
182
+ ## Troubleshooting
183
+
184
+ Are you working in development mode and wondering why masquerade attempts result in a [Receiving "You are already signed in" flash[:error]](https://github.com/oivoodoo/devise_masquerade/issues/58) message? `Filter chain halted as :require_no_authentication rendered or redirected` showing up in your logfile? Chances are that you need to enable caching:
185
+
186
+ rails dev:cache
187
+
188
+ This is a one-time operation, so you can set it and forget it. Should you ever need to disable caching in development, you can re-run the command as required.
189
+
170
190
  ## Test project
171
191
 
172
192
  make test
@@ -1,5 +1,13 @@
1
1
  class Devise::MasqueradesController < DeviseController
2
- prepend_before_action :authenticate_scope!, :masquerade_authorize!
2
+ Devise.mappings.each do |name, _|
3
+ class_eval <<-METHODS, __FILE__, __LINE__ + 1
4
+ skip_before_action :masquerade_#{name}!, raise: false
5
+ METHODS
6
+ end
7
+ skip_before_action :masquerade!, raise: false
8
+
9
+ prepend_before_action :authenticate_scope!, only: :show
10
+ prepend_before_action :masquerade_authorize!
3
11
 
4
12
  before_action :save_masquerade_owner_session, only: :show
5
13
 
@@ -8,13 +16,16 @@ class Devise::MasqueradesController < DeviseController
8
16
  def show
9
17
  self.resource = find_resource
10
18
 
19
+ if resource.class != masquerading_resource_class
20
+ sign_out(send("current_#{masquerading_resource_name}"))
21
+ end
22
+
11
23
  unless resource
12
24
  flash[:error] = "#{masqueraded_resource_class} not found."
13
25
  redirect_to(new_user_session_path) and return
14
26
  end
15
27
 
16
- resource.masquerade!
17
- request.env["devise.skip_trackable"] = "1"
28
+ request.env['devise.skip_trackable'] = '1'
18
29
 
19
30
  masquerade_sign_in(resource)
20
31
 
@@ -22,15 +33,13 @@ class Devise::MasqueradesController < DeviseController
22
33
  end
23
34
 
24
35
  def back
25
- user_id = session[session_key]
26
-
27
- resource = if user_id.present?
28
- masquerading_resource_class.to_adapter.find_first(:id => user_id)
29
- else
30
- send(:"current_#{masquerading_resource_name}")
36
+ unless send("#{masqueraded_resource_name}_signed_in?")
37
+ head(401) and return
31
38
  end
32
39
 
33
- if masquerading_resource_class != masqueraded_resource_class
40
+ self.resource = find_owner_resource
41
+
42
+ if resource.class != masqueraded_resource_class
34
43
  sign_out(send("current_#{masqueraded_resource_name}"))
35
44
  end
36
45
 
@@ -51,7 +60,11 @@ class Devise::MasqueradesController < DeviseController
51
60
  end
52
61
 
53
62
  def find_resource
54
- masqueraded_resource_class.to_adapter.find_first(id: params[:id])
63
+ GlobalID::Locator.locate_signed params[Devise.masquerade_param], for: 'masquerade'
64
+ end
65
+
66
+ def find_owner_resource
67
+ GlobalID::Locator.locate_signed(Rails.cache.read(session_key), for: 'masquerade')
55
68
  end
56
69
 
57
70
  def go_back(user, path:)
@@ -65,7 +78,17 @@ class Devise::MasqueradesController < DeviseController
65
78
  private
66
79
 
67
80
  def masqueraded_resource_class
68
- Devise.masqueraded_resource_class || resource_class
81
+ @masqueraded_resource_class ||= begin
82
+ unless params[:masqueraded_resource_class].blank?
83
+ params[:masqueraded_resource_class].constantize
84
+ else
85
+ unless session[session_key_masqueraded_resource_class].blank?
86
+ session[session_key_masquerading_resource_class].constantize
87
+ else
88
+ Devise.masqueraded_resource_class || resource_class
89
+ end
90
+ end
91
+ end
69
92
  end
70
93
 
71
94
  def masqueraded_resource_name
@@ -73,7 +96,17 @@ class Devise::MasqueradesController < DeviseController
73
96
  end
74
97
 
75
98
  def masquerading_resource_class
76
- Devise.masquerading_resource_class || resource_class
99
+ @masquerading_resource_class ||= begin
100
+ unless params[:masquerading_resource_class].blank?
101
+ params[:masquerading_resource_class].constantize
102
+ else
103
+ unless session[session_key_masquerading_resource_class].blank?
104
+ session[session_key_masquerading_resource_class].constantize
105
+ else
106
+ Devise.masquerading_resource_class || resource_class
107
+ end
108
+ end
109
+ end
77
110
  end
78
111
 
79
112
  def masquerading_resource_name
@@ -89,15 +122,7 @@ class Devise::MasqueradesController < DeviseController
89
122
  end
90
123
 
91
124
  def after_masquerade_full_path_for(resource)
92
- if after_masquerade_path_for(resource) =~ /\?/
93
- "#{after_masquerade_path_for(resource)}&#{after_masquerade_param_for(resource)}"
94
- else
95
- "#{after_masquerade_path_for(resource)}?#{after_masquerade_param_for(resource)}"
96
- end
97
- end
98
-
99
- def after_masquerade_param_for(resource)
100
- "#{Devise.masquerade_param}=#{resource.masquerade_key}"
125
+ after_masquerade_path_for(resource)
101
126
  end
102
127
 
103
128
  def after_back_masquerade_path_for(resource)
@@ -105,16 +130,33 @@ class Devise::MasqueradesController < DeviseController
105
130
  end
106
131
 
107
132
  def save_masquerade_owner_session
133
+ resource_gid = send("current_#{masquerading_resource_name}").to_sgid(
134
+ expires_in: Devise.masquerade_expires_in, for: 'masquerade')
135
+ # skip sharing owner id via session
136
+ Rails.cache.write(session_key, resource_gid, expires_in: Devise.masquerade_expires_in)
137
+
108
138
  unless session.key?(session_key)
109
- session[session_key] = send("current_#{masquerading_resource_name}").id
139
+ session[session_key_masquerading_resource_class] = masquerading_resource_class.name
140
+ session[session_key_masqueraded_resource_class] = masqueraded_resource_class.name
110
141
  end
111
142
  end
112
143
 
113
144
  def cleanup_masquerade_owner_session
114
- session.delete(session_key)
145
+ Rails.cache.delete(session_key)
146
+
147
+ session.delete(session_key_masqueraded_resource_class)
148
+ session.delete(session_key_masquerading_resource_class)
115
149
  end
116
150
 
117
151
  def session_key
118
152
  "devise_masquerade_#{masqueraded_resource_name}".to_sym
119
153
  end
154
+
155
+ def session_key_masqueraded_resource_class
156
+ "devise_masquerade_masqueraded_resource_class"
157
+ end
158
+
159
+ def session_key_masquerading_resource_class
160
+ "devise_masquerade_masquerading_resource_class"
161
+ end
120
162
  end