pretender 0.0.1
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.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +132 -0
- data/Rakefile +1 -0
- data/lib/pretender.rb +38 -0
- data/lib/pretender/version.rb +3 -0
- data/pretender.gemspec +23 -0
- metadata +88 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Andrew Kane
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
# Pretender
|
2
|
+
|
3
|
+
As an admin, there are times you want to see exactly what another user sees or take action on behalf of a user. Pretender provides the ability to login as another user **the right way**.
|
4
|
+
|
5
|
+
What is the right way?
|
6
|
+
|
7
|
+
- Easy to switch back and forth between roles
|
8
|
+
- Minimal code changes
|
9
|
+
- Plays nicely with auditing tools
|
10
|
+
|
11
|
+
[Rock on](http://www.youtube.com/watch?v=SBjQ9tuuTJQ) :boom:
|
12
|
+
|
13
|
+
Pretender is also flexible and lightweight - less than 40 lines of code :-)
|
14
|
+
|
15
|
+
Pretender works with Rails 2.3 and above.
|
16
|
+
|
17
|
+
## Get started
|
18
|
+
|
19
|
+
Add this line to your application's Gemfile:
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
# Gemfile
|
23
|
+
gem 'pretender'
|
24
|
+
```
|
25
|
+
|
26
|
+
And add this line to your ApplicationController:
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
# app/controllers/application_controller.rb
|
30
|
+
class ApplicationController < ActionController::Base
|
31
|
+
impersonates :user
|
32
|
+
end
|
33
|
+
```
|
34
|
+
|
35
|
+
This adds three methods to your controllers:
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
true_user
|
39
|
+
# returns authenticated user
|
40
|
+
|
41
|
+
impersonate_user(user)
|
42
|
+
# allows you to login as another user
|
43
|
+
|
44
|
+
stop_impersonating_user
|
45
|
+
# become yourself again
|
46
|
+
```
|
47
|
+
|
48
|
+
And changes the behavior of another:
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
current_user
|
52
|
+
# now returns:
|
53
|
+
# - if impersonating, the impersonated user
|
54
|
+
# - otherwise, the true user
|
55
|
+
```
|
56
|
+
|
57
|
+
**Note:** the name of this method is configurable (details at the end)
|
58
|
+
|
59
|
+
Now we need to setup a way to login as another user. **Pretender makes no assumptions about how you want to do this**. I like to add this to my admin dashboard.
|
60
|
+
|
61
|
+
#### Sample Implementation
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
class Admin::UsersController < ApplicationController
|
65
|
+
before_filter :require_admin, :except => [:stop_impersonating]
|
66
|
+
|
67
|
+
def impersonate
|
68
|
+
user = User.find(params[:id])
|
69
|
+
impersonate_user(user)
|
70
|
+
redirect_to root_path
|
71
|
+
end
|
72
|
+
|
73
|
+
# do not require admin for this method if access control
|
74
|
+
# is performed on the current_user instead of true_user
|
75
|
+
def stop_impersonating
|
76
|
+
stop_impersonating_user
|
77
|
+
redirect_to admin_path
|
78
|
+
end
|
79
|
+
end
|
80
|
+
```
|
81
|
+
|
82
|
+
You may want to make it obvious to an admin when he / she is logged in as another user. I like to add this to the application layout.
|
83
|
+
|
84
|
+
#### Haml / Slim
|
85
|
+
|
86
|
+
```haml
|
87
|
+
- # app/views/layouts/application.haml
|
88
|
+
- if current_user != true_user
|
89
|
+
.alert
|
90
|
+
You (#{true_user.name}) are logged in as #{current_user.name}
|
91
|
+
= link_to "Back to admin", stop_impersonating_user_path
|
92
|
+
```
|
93
|
+
|
94
|
+
### Audits
|
95
|
+
|
96
|
+
If you keep audit logs with a library like [audited](https://github.com/collectiveidea/audited), make sure it uses the **true user**.
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
Audited.current_user_method = :true_user
|
100
|
+
```
|
101
|
+
|
102
|
+
### Configuration
|
103
|
+
|
104
|
+
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.
|
105
|
+
|
106
|
+
```ruby
|
107
|
+
# app/controllers/application_controller.rb
|
108
|
+
impersonates :user,
|
109
|
+
:method => :current_user,
|
110
|
+
:with => proc{|id| User.where(:id => id).first }
|
111
|
+
```
|
112
|
+
|
113
|
+
Mold it to fit your application.
|
114
|
+
|
115
|
+
```ruby
|
116
|
+
# app/controllers/application_controller.rb
|
117
|
+
impersonates :account,
|
118
|
+
:method => :authenticated_account,
|
119
|
+
:with => proc{|id| EnterpriseAccount.where(:id => id).first }
|
120
|
+
```
|
121
|
+
|
122
|
+
This creates three methods:
|
123
|
+
|
124
|
+
```ruby
|
125
|
+
true_account
|
126
|
+
impersonate_account
|
127
|
+
stop_impersonating_account
|
128
|
+
```
|
129
|
+
|
130
|
+
Also, authenticated_account is overridden with `EnterpriseAccount.where(:id => id).first`
|
131
|
+
|
132
|
+
### That's all folks!
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/lib/pretender.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require "pretender/version"
|
2
|
+
|
3
|
+
module Pretender
|
4
|
+
|
5
|
+
def impersonates(scope = :user, opts = {})
|
6
|
+
impersonated_method = opts[:method] || :"current_#{scope}"
|
7
|
+
impersonate_with = opts[:with] || proc{|id| scope.to_s.classify.constantize.where(:id => id).first }
|
8
|
+
true_method = :"true_#{scope}"
|
9
|
+
session_key = :"impersonated_#{scope}_id"
|
10
|
+
impersonated_var = :"@impersonated_#{scope}"
|
11
|
+
|
12
|
+
# define methods
|
13
|
+
alias_method true_method, impersonated_method
|
14
|
+
helper_method true_method
|
15
|
+
|
16
|
+
define_method impersonated_method do
|
17
|
+
# only try to fetch impersonation if impersonation_id exists
|
18
|
+
if !instance_variable_get(impersonated_var)
|
19
|
+
value = (session[session_key] && impersonate_with.call(session[session_key])) || send(true_method)
|
20
|
+
instance_variable_set(impersonated_var, value) if value
|
21
|
+
end
|
22
|
+
instance_variable_get(impersonated_var)
|
23
|
+
end
|
24
|
+
|
25
|
+
define_method :"impersonate_#{scope}" do |resource|
|
26
|
+
instance_variable_set(impersonated_var, resource)
|
27
|
+
session[session_key] = resource.id
|
28
|
+
end
|
29
|
+
|
30
|
+
define_method :"stop_impersonating_#{scope}" do
|
31
|
+
instance_variable_set(impersonated_var, nil)
|
32
|
+
session[session_key] = nil
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
ActionController::Base.send(:extend, Pretender) if defined?(ActionController::Base)
|
data/pretender.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
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 = ["acekane1@gmail.com"]
|
11
|
+
spec.description = %q{The right way to login as another user}
|
12
|
+
spec.summary = %q{What is the right way? 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($/)
|
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_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
end
|
metadata
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pretender
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Andrew Kane
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-03-05 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bundler
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.3'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.3'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
description: The right way to login as another user
|
47
|
+
email:
|
48
|
+
- acekane1@gmail.com
|
49
|
+
executables: []
|
50
|
+
extensions: []
|
51
|
+
extra_rdoc_files: []
|
52
|
+
files:
|
53
|
+
- .gitignore
|
54
|
+
- Gemfile
|
55
|
+
- LICENSE.txt
|
56
|
+
- README.md
|
57
|
+
- Rakefile
|
58
|
+
- lib/pretender.rb
|
59
|
+
- lib/pretender/version.rb
|
60
|
+
- pretender.gemspec
|
61
|
+
homepage: https://github.com/ankane/pretender
|
62
|
+
licenses:
|
63
|
+
- MIT
|
64
|
+
post_install_message:
|
65
|
+
rdoc_options: []
|
66
|
+
require_paths:
|
67
|
+
- lib
|
68
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - ! '>='
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ! '>='
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
requirements: []
|
81
|
+
rubyforge_project:
|
82
|
+
rubygems_version: 1.8.23
|
83
|
+
signing_key:
|
84
|
+
specification_version: 3
|
85
|
+
summary: What is the right way? Easy to switch back and forth between roles, minimal
|
86
|
+
code changes, and plays nicely with auditing tools
|
87
|
+
test_files: []
|
88
|
+
has_rdoc:
|