pretender 0.3.1 → 0.4.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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +21 -4
- data/LICENSE.txt +1 -1
- data/README.md +52 -11
- data/lib/pretender/version.rb +1 -1
- data/lib/pretender.rb +29 -12
- metadata +13 -66
- data/.gitignore +0 -17
- data/Gemfile +0 -4
- data/Rakefile +0 -8
- data/pretender.gemspec +0 -26
- data/test/pretender_test.rb +0 -60
- data/test/test_helper.rb +0 -26
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: bfd83e017e14b15a69e02ffe5d25c6be57657f06d84b30fa276fedd61efb6d07
|
4
|
+
data.tar.gz: 55d4d73eb2ab7fa9fe87ba5be1b3da4e6264de02b845cb579612c9e8ae549ae2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7e7d1306ee4466cf4b9419dbfe71c161d633eb4ded28246252b90404954a57c06597081bbfa1fedfa69effce9cbb3988c2b39043e8abd9db5160b0f652987869
|
7
|
+
data.tar.gz: 422366a35f79040ddb0b104f4d3177b637333c590c65124e58bd5934378d13aebcb92987c6c07224ec16d6a5112087c85c2c6401f1517697b0737f66f462b8de
|
data/CHANGELOG.md
CHANGED
@@ -1,17 +1,34 @@
|
|
1
|
-
## 0.
|
1
|
+
## 0.4.0 (2022-01-10)
|
2
|
+
|
3
|
+
- Dropped support for Ruby < 2.6 and Rails < 5.2
|
4
|
+
|
5
|
+
## 0.3.4 (2019-01-31)
|
6
|
+
|
7
|
+
- Fixed error with Action Cable and eager loading
|
8
|
+
|
9
|
+
## 0.3.3 (2018-09-21)
|
10
|
+
|
11
|
+
- Added support for Action Cable
|
12
|
+
|
13
|
+
## 0.3.2 (2018-01-21)
|
14
|
+
|
15
|
+
- Support for Mongoid `BSON::ObjectId` out of the box
|
16
|
+
- Fixed issue with impersonated resource caching
|
17
|
+
|
18
|
+
## 0.3.1 (2017-06-18)
|
2
19
|
|
3
20
|
- Fixed `stack level too deep` error
|
4
21
|
|
5
|
-
## 0.3.0
|
22
|
+
## 0.3.0 (2017-06-11)
|
6
23
|
|
7
24
|
- Fixed compatibility with Clearance
|
8
25
|
- Added support for Rails API
|
9
26
|
- Added support for custom primary key
|
10
27
|
|
11
|
-
## 0.2.1
|
28
|
+
## 0.2.1 (2016-07-07)
|
12
29
|
|
13
30
|
- Better error message
|
14
31
|
|
15
|
-
## 0.2.0
|
32
|
+
## 0.2.0 (2016-07-07)
|
16
33
|
|
17
34
|
- Started changelog
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -1,25 +1,27 @@
|
|
1
1
|
# Pretender
|
2
2
|
|
3
|
-
As an admin, there are times you want to see exactly what another user sees.
|
3
|
+
As an admin, there are times you want to see exactly what another user sees. Meet Pretender.
|
4
4
|
|
5
|
-
- Easily
|
5
|
+
- Easily switch between users
|
6
6
|
- Minimal code changes
|
7
|
-
- Plays nicely with auditing tools
|
7
|
+
- Plays nicely with Action Cable and auditing tools
|
8
8
|
|
9
|
-
:boom: [Rock on](
|
9
|
+
:boom: [Rock on](https://www.youtube.com/watch?v=SBjQ9tuuTJQ)
|
10
10
|
|
11
|
-
Pretender is flexible and lightweight - less than
|
11
|
+
Pretender is flexible and lightweight - less than 100 lines of code :-)
|
12
12
|
|
13
|
-
Works with any authentication system - [Devise](https://github.com/plataformatec/devise), [Authlogic](https://github.com/binarylogic/authlogic), and [Sorcery](https://github.com/
|
13
|
+
Works with any authentication system - [Devise](https://github.com/plataformatec/devise), [Authlogic](https://github.com/binarylogic/authlogic), and [Sorcery](https://github.com/Sorcery/sorcery) to name a few.
|
14
14
|
|
15
15
|
:tangerine: Battle-tested at [Instacart](https://www.instacart.com/opensource)
|
16
16
|
|
17
|
+
[](https://github.com/ankane/pretender/actions)
|
18
|
+
|
17
19
|
## Installation
|
18
20
|
|
19
21
|
Add this line to your application’s Gemfile:
|
20
22
|
|
21
23
|
```ruby
|
22
|
-
gem
|
24
|
+
gem "pretender"
|
23
25
|
```
|
24
26
|
|
25
27
|
And add this to your `ApplicationController`:
|
@@ -58,7 +60,7 @@ Create a controller
|
|
58
60
|
|
59
61
|
```ruby
|
60
62
|
class UsersController < ApplicationController
|
61
|
-
|
63
|
+
before_action :require_admin! # your authorization method
|
62
64
|
|
63
65
|
def index
|
64
66
|
@users = User.order(:id)
|
@@ -113,14 +115,40 @@ If you keep audit logs with a library like [Audited](https://github.com/collecti
|
|
113
115
|
Audited.current_user_method = :true_user
|
114
116
|
```
|
115
117
|
|
118
|
+
## Action Cable
|
119
|
+
|
120
|
+
And add this to your `ApplicationCable::Connection`:
|
121
|
+
|
122
|
+
```ruby
|
123
|
+
module ApplicationCable
|
124
|
+
class Connection < ActionCable::Connection::Base
|
125
|
+
identified_by :current_user, :true_user
|
126
|
+
impersonates :user
|
127
|
+
|
128
|
+
def connect
|
129
|
+
self.current_user = find_verified_user
|
130
|
+
reject_unauthorized_connection unless current_user
|
131
|
+
end
|
132
|
+
|
133
|
+
private
|
134
|
+
|
135
|
+
def find_verified_user
|
136
|
+
env["warden"].user # for Devise
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
```
|
141
|
+
|
142
|
+
The `current_user` method now returns the impersonated user in channels.
|
143
|
+
|
116
144
|
## Configuration
|
117
145
|
|
118
|
-
Pretender is super flexible.
|
146
|
+
Pretender is super flexible. You can change the names of methods and even impersonate multiple roles at the same time. Here’s the default configuration.
|
119
147
|
|
120
148
|
```ruby
|
121
149
|
impersonates :user,
|
122
150
|
method: :current_user,
|
123
|
-
with: ->
|
151
|
+
with: ->(id) { User.find_by(id: id) }
|
124
152
|
```
|
125
153
|
|
126
154
|
Mold it to fit your application.
|
@@ -128,7 +156,7 @@ Mold it to fit your application.
|
|
128
156
|
```ruby
|
129
157
|
impersonates :account,
|
130
158
|
method: :authenticated_account,
|
131
|
-
with: ->
|
159
|
+
with: ->(id) { EnterpriseAccount.find_by(id: id) }
|
132
160
|
```
|
133
161
|
|
134
162
|
This creates three methods:
|
@@ -139,6 +167,10 @@ impersonate_account
|
|
139
167
|
stop_impersonating_account
|
140
168
|
```
|
141
169
|
|
170
|
+
## History
|
171
|
+
|
172
|
+
View the [changelog](https://github.com/ankane/pretender/blob/master/CHANGELOG.md)
|
173
|
+
|
142
174
|
## Contributing
|
143
175
|
|
144
176
|
Everyone is encouraged to help improve this project. Here are a few ways you can help:
|
@@ -147,3 +179,12 @@ Everyone is encouraged to help improve this project. Here are a few ways you can
|
|
147
179
|
- Fix bugs and [submit pull requests](https://github.com/ankane/pretender/pulls)
|
148
180
|
- Write, clarify, or fix documentation
|
149
181
|
- Suggest or add new features
|
182
|
+
|
183
|
+
To get started with development:
|
184
|
+
|
185
|
+
```sh
|
186
|
+
git clone https://github.com/ankane/pretender.git
|
187
|
+
cd pretender
|
188
|
+
bundle install
|
189
|
+
bundle exec rake test
|
190
|
+
```
|
data/lib/pretender/version.rb
CHANGED
data/lib/pretender.rb
CHANGED
@@ -15,6 +15,7 @@ module Pretender
|
|
15
15
|
true_method = :"true_#{scope}"
|
16
16
|
session_key = :"impersonated_#{scope}_id"
|
17
17
|
impersonated_var = :"@impersonated_#{scope}"
|
18
|
+
stop_impersonating_method = :"stop_impersonating_#{scope}"
|
18
19
|
|
19
20
|
# define methods
|
20
21
|
if method_defined?(impersonated_method) || private_method_defined?(impersonated_method)
|
@@ -30,26 +31,39 @@ module Pretender
|
|
30
31
|
helper_method(true_method) if respond_to?(:helper_method)
|
31
32
|
|
32
33
|
define_method impersonated_method do
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
if
|
37
|
-
|
34
|
+
impersonated_resource = instance_variable_get(impersonated_var) if instance_variable_defined?(impersonated_var)
|
35
|
+
|
36
|
+
if !impersonated_resource && request.session[session_key]
|
37
|
+
# only fetch impersonation if user is logged in
|
38
|
+
# this is a safety check (once per request) so
|
39
|
+
# if a user logs out without session being destroyed
|
40
|
+
# or stop_impersonating_user being called,
|
41
|
+
# we can stop the impersonation
|
42
|
+
if send(true_method)
|
43
|
+
impersonated_resource = impersonate_with.call(request.session[session_key])
|
44
|
+
instance_variable_set(impersonated_var, impersonated_resource) if impersonated_resource
|
45
|
+
else
|
46
|
+
# TODO better message
|
47
|
+
warn "[pretender] Stopping impersonation due to safety check"
|
48
|
+
send(stop_impersonating_method)
|
38
49
|
end
|
39
|
-
value = (session[session_key] && impersonate_with.call(session[session_key])) || true_resource
|
40
|
-
instance_variable_set(impersonated_var, value) if value
|
41
50
|
end
|
42
|
-
|
51
|
+
|
52
|
+
impersonated_resource || send(true_method)
|
43
53
|
end
|
44
54
|
|
45
55
|
define_method :"impersonate_#{scope}" do |resource|
|
56
|
+
raise ArgumentError, "No resource to impersonate" unless resource
|
57
|
+
raise Pretender::Error, "Must be logged in to impersonate" unless send(true_method)
|
58
|
+
|
46
59
|
instance_variable_set(impersonated_var, resource)
|
47
|
-
|
60
|
+
# use to_s for Mongoid for BSON::ObjectId
|
61
|
+
request.session[session_key] = resource.id.is_a?(Numeric) ? resource.id : resource.id.to_s
|
48
62
|
end
|
49
63
|
|
50
|
-
define_method
|
51
|
-
|
52
|
-
session
|
64
|
+
define_method stop_impersonating_method do
|
65
|
+
remove_instance_variable(impersonated_var) if instance_variable_defined?(impersonated_var)
|
66
|
+
request.session.delete(session_key)
|
53
67
|
end
|
54
68
|
end
|
55
69
|
end
|
@@ -58,3 +72,6 @@ end
|
|
58
72
|
ActiveSupport.on_load(:action_controller) do
|
59
73
|
extend Pretender::Methods
|
60
74
|
end
|
75
|
+
|
76
|
+
# ActiveSupport.on_load(:action_cable) runs too late with Unicorn
|
77
|
+
ActionCable::Connection::Base.extend(Pretender::Methods) if defined?(ActionCable)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pretender
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kane
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-01-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: actionpack
|
@@ -16,79 +16,30 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '5.2'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
27
|
-
|
28
|
-
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - "~>"
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '1.3'
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - "~>"
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '1.3'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: rake
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - ">="
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - ">="
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: minitest
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - ">="
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - ">="
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '0'
|
69
|
-
description: Simple, powerful user impersonation for Rails
|
70
|
-
email:
|
71
|
-
- andrew@chartkick.com
|
26
|
+
version: '5.2'
|
27
|
+
description:
|
28
|
+
email: andrew@ankane.org
|
72
29
|
executables: []
|
73
30
|
extensions: []
|
74
31
|
extra_rdoc_files: []
|
75
32
|
files:
|
76
|
-
- ".gitignore"
|
77
33
|
- CHANGELOG.md
|
78
|
-
- Gemfile
|
79
34
|
- LICENSE.txt
|
80
35
|
- README.md
|
81
|
-
- Rakefile
|
82
36
|
- lib/pretender.rb
|
83
37
|
- lib/pretender/version.rb
|
84
|
-
- pretender.gemspec
|
85
|
-
- test/pretender_test.rb
|
86
|
-
- test/test_helper.rb
|
87
38
|
homepage: https://github.com/ankane/pretender
|
88
39
|
licenses:
|
89
40
|
- MIT
|
90
41
|
metadata: {}
|
91
|
-
post_install_message:
|
42
|
+
post_install_message:
|
92
43
|
rdoc_options: []
|
93
44
|
require_paths:
|
94
45
|
- lib
|
@@ -96,19 +47,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
96
47
|
requirements:
|
97
48
|
- - ">="
|
98
49
|
- !ruby/object:Gem::Version
|
99
|
-
version: '
|
50
|
+
version: '2.6'
|
100
51
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
52
|
requirements:
|
102
53
|
- - ">="
|
103
54
|
- !ruby/object:Gem::Version
|
104
55
|
version: '0'
|
105
56
|
requirements: []
|
106
|
-
|
107
|
-
|
108
|
-
signing_key:
|
57
|
+
rubygems_version: 3.3.3
|
58
|
+
signing_key:
|
109
59
|
specification_version: 4
|
110
|
-
summary:
|
111
|
-
|
112
|
-
test_files:
|
113
|
-
- test/pretender_test.rb
|
114
|
-
- test/test_helper.rb
|
60
|
+
summary: Log in as another user in Rails
|
61
|
+
test_files: []
|
data/.gitignore
DELETED
data/Gemfile
DELETED
data/Rakefile
DELETED
data/pretender.gemspec
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
lib = File.expand_path("../lib", __FILE__)
|
3
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require "pretender/version"
|
5
|
-
|
6
|
-
Gem::Specification.new do |spec|
|
7
|
-
spec.name = "pretender"
|
8
|
-
spec.version = Pretender::VERSION
|
9
|
-
spec.authors = ["Andrew Kane"]
|
10
|
-
spec.email = ["andrew@chartkick.com"]
|
11
|
-
spec.description = "Simple, powerful user impersonation for Rails"
|
12
|
-
spec.summary = "Easy to switch back and forth between roles, minimal code changes, and plays nicely with auditing tools"
|
13
|
-
spec.homepage = "https://github.com/ankane/pretender"
|
14
|
-
spec.license = "MIT"
|
15
|
-
|
16
|
-
spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
17
|
-
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
-
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
-
spec.require_paths = ["lib"]
|
20
|
-
|
21
|
-
spec.add_dependency "actionpack"
|
22
|
-
|
23
|
-
spec.add_development_dependency "bundler", "~> 1.3"
|
24
|
-
spec.add_development_dependency "rake"
|
25
|
-
spec.add_development_dependency "minitest"
|
26
|
-
end
|
data/test/pretender_test.rb
DELETED
@@ -1,60 +0,0 @@
|
|
1
|
-
require_relative "test_helper"
|
2
|
-
|
3
|
-
module TheTruth
|
4
|
-
def test_original_state
|
5
|
-
@controller.current_user = @impersonator
|
6
|
-
|
7
|
-
assert_equal @impersonator, @controller.true_user
|
8
|
-
assert_equal @impersonator, @controller.current_user
|
9
|
-
end
|
10
|
-
|
11
|
-
def test_impersonates
|
12
|
-
@controller.current_user = @impersonator
|
13
|
-
@controller.impersonate_user @impersonated
|
14
|
-
|
15
|
-
assert_equal @impersonator, @controller.true_user
|
16
|
-
assert_equal @impersonated, @controller.current_user
|
17
|
-
end
|
18
|
-
|
19
|
-
def test_impersonated_state
|
20
|
-
@controller.current_user = @impersonator
|
21
|
-
@controller.session[:impersonated_user_id] = @impersonated.id
|
22
|
-
|
23
|
-
assert_equal @impersonator, @controller.true_user
|
24
|
-
assert_equal @impersonated, @controller.current_user
|
25
|
-
end
|
26
|
-
|
27
|
-
def test_stops_impersonating
|
28
|
-
@controller.current_user = @impersonator
|
29
|
-
@controller.session[:impersonated_user_id] = @impersonated.id
|
30
|
-
@controller.stop_impersonating_user
|
31
|
-
|
32
|
-
assert_equal @impersonator, @controller.true_user
|
33
|
-
assert_equal @impersonator, @controller.current_user
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
class PretenderTest < Minitest::Test
|
38
|
-
include TheTruth
|
39
|
-
|
40
|
-
def setup
|
41
|
-
@impersonator = User.new("impersonator")
|
42
|
-
@impersonated = User.new("impersonated")
|
43
|
-
@controller = ApplicationController.new
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
class SuperPretenderTest < Minitest::Test
|
48
|
-
include TheTruth
|
49
|
-
|
50
|
-
def setup
|
51
|
-
@impersonator = User.new("impersonator")
|
52
|
-
@impersonated = User.new("impersonated")
|
53
|
-
@controller = ApplicationController.new
|
54
|
-
class << @controller
|
55
|
-
def current_user
|
56
|
-
super
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
data/test/test_helper.rb
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
require "bundler/setup"
|
2
|
-
Bundler.require(:default)
|
3
|
-
require "minitest/autorun"
|
4
|
-
require "minitest/pride"
|
5
|
-
require "action_controller"
|
6
|
-
|
7
|
-
User = Struct.new(:id) do
|
8
|
-
def self.where(id: nil)
|
9
|
-
[new(id)]
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
module ActionController
|
14
|
-
class Base
|
15
|
-
attr_reader :session
|
16
|
-
|
17
|
-
def initialize
|
18
|
-
@session = {}
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
class ApplicationController < ActionController::Base
|
24
|
-
attr_accessor :current_user
|
25
|
-
impersonates :user
|
26
|
-
end
|