booth 0.0.10 → 0.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -1
- data/config/locales/de.yml +9 -0
- data/config/locales/en.yml +9 -0
- data/lib/booth/adminland/incognitos/consume_token.rb +108 -0
- data/lib/booth/adminland/incognitos/generate_secret_key.rb +78 -0
- data/lib/booth/adminland/incognitos/stop_incognito.rb +88 -0
- data/lib/booth/adminland.rb +10 -2
- data/lib/booth/models/audit.rb +3 -0
- data/lib/booth/version.rb +1 -1
- data/lib/generators/booth/migration/templates/create_booth_tables.erb +2 -0
- metadata +4 -2
- data/lib/booth/adminland/incognitos/start.rb +0 -106
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 825454f7f3a05334b3fa0ae5dffa808debf032381a9eca3ecc33c328cd686d30
|
|
4
|
+
data.tar.gz: 961e43f55afaa1a41ac5234f56a8848016e89a0d3d5f2a4a3f4a992434894bad
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dfd4cfc102db64fcc7d5c5654565928c095d0075ca743a8bc2ac1ade00e347b4342580a00d4e755ca082f9762f921de3f8405ed55dc8eaa5e86ff85214094207
|
|
7
|
+
data.tar.gz: ca078c52a93db8f77d6c46e48c81cee5ca34228606ed72bdad3b0156dc677df5979d367fb47b9f17796cb441449541c49494dff193f0217418861c25a982e4d3
|
data/CHANGELOG.md
CHANGED
|
@@ -2,7 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
# 0.0.10
|
|
4
4
|
|
|
5
|
-
-
|
|
5
|
+
- Schema: add `booth_sessions.incognito_secret_key` (string, unique) and `booth_sessions.impersonator_session_id` (uuid, FK to self)
|
|
6
|
+
|
|
7
|
+
### Upgrading: Add new columns via migration
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
class AddIncognitoColumnsToBoothSessions < ActiveRecord::Migration[8.1]
|
|
11
|
+
def change
|
|
12
|
+
add_column :booth_sessions, :incognito_secret_key, :string
|
|
13
|
+
add_index :booth_sessions, :incognito_secret_key, unique: true
|
|
14
|
+
|
|
15
|
+
add_reference :booth_sessions, :impersonator_session,
|
|
16
|
+
foreign_key: { to_table: :booth_sessions, on_delete: :nullify },
|
|
17
|
+
type: :uuid, index: true
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
```
|
|
6
21
|
|
|
7
22
|
# 0.0.9
|
|
8
23
|
|
data/config/locales/de.yml
CHANGED
|
@@ -22,6 +22,15 @@ de:
|
|
|
22
22
|
email_too_long: The provided email is too long. It must be less at most %{maximum} characters long.
|
|
23
23
|
email_too_short: The provided email is too short. It should be at least %{minimum} characters long.
|
|
24
24
|
incognito_started: Sie sind jetzt im Namen eines anderen Kontos angemeldet.
|
|
25
|
+
incognito_token_issued: Der Inkognito-Schlüssel wurde ausgestellt.
|
|
26
|
+
incognito_token_expired: Der Inkognito-Schlüssel ist abgelaufen. Bitte stellen Sie einen neuen aus.
|
|
27
|
+
incognito_session_not_found: Der Inkognito-Schlüssel ist ungültig.
|
|
28
|
+
incognito_stopped: Sie sind nicht länger im Namen eines anderen Kontos angemeldet.
|
|
29
|
+
already_logged_in_on_scope: Sie sind bereits angemeldet. Bitte melden Sie sich zuerst ab.
|
|
30
|
+
scope_mismatch: Der angegebene Bereich stimmt nicht mit dem Zielkonto überein.
|
|
31
|
+
not_logged_in: Sie müssen angemeldet sein, um diese Aktion auszuführen.
|
|
32
|
+
session_not_found: Ihre Sitzung konnte nicht gefunden werden.
|
|
33
|
+
impersonator_session_not_found: Die ursprüngliche Sitzung konnte nicht wiederhergestellt werden.
|
|
25
34
|
incompatible_webauth_device: Sorry, this device cannot be used. Please try another webauth device.
|
|
26
35
|
invalid_domain: Die Domain "%{domain}" ist keine gültige Domain.
|
|
27
36
|
invalid_email_characters: The provided email address contains invalid characters.
|
data/config/locales/en.yml
CHANGED
|
@@ -22,6 +22,15 @@ en:
|
|
|
22
22
|
email_too_long: The provided email is too long. It must be less at most %{maximum} characters long.
|
|
23
23
|
email_too_short: The provided email is too short. It should be at least %{minimum} characters long.
|
|
24
24
|
incognito_started: You are now acting on behalf of another account.
|
|
25
|
+
incognito_token_issued: The incognito token has been issued.
|
|
26
|
+
incognito_token_expired: The incognito token has expired. Please issue a new one.
|
|
27
|
+
incognito_session_not_found: The incognito token is invalid.
|
|
28
|
+
incognito_stopped: You are no longer acting on behalf of another account.
|
|
29
|
+
already_logged_in_on_scope: You are already logged in. Please log out first.
|
|
30
|
+
scope_mismatch: The provided scope does not match the target account.
|
|
31
|
+
not_logged_in: You must be logged in to perform this action.
|
|
32
|
+
session_not_found: Your session could not be found.
|
|
33
|
+
impersonator_session_not_found: The original session could not be restored.
|
|
25
34
|
incompatible_webauth_device: Sorry, this device cannot be used. Please try another webauth device.
|
|
26
35
|
invalid_domain: The Domain "%{domain}" is not a valid domain name.
|
|
27
36
|
invalid_email_characters: The provided email address contains invalid characters.
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Booth
|
|
4
|
+
module Adminland
|
|
5
|
+
module Incognitos
|
|
6
|
+
class ConsumeToken
|
|
7
|
+
include Calls
|
|
8
|
+
include ::Booth::Logging
|
|
9
|
+
|
|
10
|
+
option :scope, ::Booth::Coercers::Scope
|
|
11
|
+
option :request, ::Booth::Coercers::Request
|
|
12
|
+
option :secret_key
|
|
13
|
+
|
|
14
|
+
def call
|
|
15
|
+
do_find_session
|
|
16
|
+
.on_success { do_check_expiry }
|
|
17
|
+
.on_success { do_check_not_already_logged_in_as_someone_else }
|
|
18
|
+
.on_success { do_compare_scope }
|
|
19
|
+
.on_success { do_atomic_updates }
|
|
20
|
+
.on_success { do_audit }
|
|
21
|
+
.on_success { do_login }
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
attr_accessor :session
|
|
27
|
+
|
|
28
|
+
def do_find_session
|
|
29
|
+
self.session = ::Booth::Models::Session.find_by(incognito_secret_key: secret_key)
|
|
30
|
+
|
|
31
|
+
return Tron.failure(:incognito_session_not_found,
|
|
32
|
+
public_message: I18n.t('booth.incognito_session_not_found')) unless session
|
|
33
|
+
|
|
34
|
+
log { "Found session ##{session.id}" }
|
|
35
|
+
Tron.success :session_found
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def do_check_expiry
|
|
39
|
+
return Tron.failure(:incognito_token_expired,
|
|
40
|
+
public_message: I18n.t('booth.incognito_token_expired')) unless session.created_at > 60.seconds.ago
|
|
41
|
+
|
|
42
|
+
Tron.success :session_within_expiry
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def do_check_not_already_logged_in_as_someone_else
|
|
46
|
+
if request.authentication.logged_in? &&
|
|
47
|
+
request.authentication.credential_id != session.incognito_credential_id
|
|
48
|
+
log { 'Someone else is logged in on this scope' }
|
|
49
|
+
return Tron.failure :already_logged_in_on_scope,
|
|
50
|
+
public_message: I18n.t('booth.already_logged_in_on_scope')
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
Tron.success :not_logged_in_or_is_impersonator
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def do_compare_scope
|
|
57
|
+
return Tron.failure(:scope_mismatch,
|
|
58
|
+
public_message: I18n.t('booth.scope_mismatch')) unless session.credential.scope == scope.to_s
|
|
59
|
+
|
|
60
|
+
Tron.success :scope_matches
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def do_atomic_updates
|
|
64
|
+
::Booth::Models::Session.transaction do
|
|
65
|
+
session.update!(incognito_secret_key: nil)
|
|
66
|
+
log { 'Cleared incognito_secret_key' }
|
|
67
|
+
revoke_impersonator_if_same_scope
|
|
68
|
+
session.update!(agent: request.agent, most_recent_ip: request.ip)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
Tron.success :atomic_updates_done
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def do_audit
|
|
75
|
+
::Booth::Models::Audit.create!(
|
|
76
|
+
credential_id: session.incognito_credential_id,
|
|
77
|
+
ip: request.ip,
|
|
78
|
+
agent: request.agent,
|
|
79
|
+
event: :incognito_consumed,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
Tron.success :audited
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def do_login
|
|
86
|
+
request.authentication.login(session:)
|
|
87
|
+
Tron.success :incognito_started,
|
|
88
|
+
public_message: I18n.t('booth.incognito_started')
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def revoke_impersonator_if_same_scope
|
|
92
|
+
return unless request.authentication.logged_in? &&
|
|
93
|
+
request.authentication.credential_id == session.incognito_credential_id
|
|
94
|
+
|
|
95
|
+
impersonator_session = ::Booth::Models::Session.find_by(
|
|
96
|
+
id: request.authentication.session_id,
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
return unless impersonator_session
|
|
100
|
+
|
|
101
|
+
log { "Revoking impersonator session ##{impersonator_session.id}" }
|
|
102
|
+
impersonator_session.update!(revoked_at: Time.current, revoke_reason: :impersonation)
|
|
103
|
+
session.update!(impersonator_session_id: impersonator_session.id)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Booth
|
|
4
|
+
module Adminland
|
|
5
|
+
module Incognitos
|
|
6
|
+
class GenerateSecretKey
|
|
7
|
+
include Calls
|
|
8
|
+
include ::Booth::Logging
|
|
9
|
+
|
|
10
|
+
option :scope, ::Booth::Coercers::Scope
|
|
11
|
+
option :request, ::Booth::Coercers::Request
|
|
12
|
+
option :target_credential_id
|
|
13
|
+
|
|
14
|
+
def call
|
|
15
|
+
do_check_impersonator_logged_in
|
|
16
|
+
.on_success { do_find_target_credential }
|
|
17
|
+
.on_success { do_create_session }
|
|
18
|
+
.on_success { do_audit }
|
|
19
|
+
.on_success { do_return_key }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
attr_accessor :impersonator_credential_id, :target_credential, :session, :secret_key
|
|
25
|
+
|
|
26
|
+
def do_check_impersonator_logged_in
|
|
27
|
+
return Tron.failure(:not_logged_in_as_impersonator,
|
|
28
|
+
public_message: I18n.t('booth.not_logged_in_as_impersonator')) unless request.authentication.logged_in?
|
|
29
|
+
|
|
30
|
+
self.impersonator_credential_id = request.authentication.credential_id
|
|
31
|
+
log { "Impersonator credential_id=#{impersonator_credential_id}" }
|
|
32
|
+
Tron.success :impersonator_captured
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def do_find_target_credential
|
|
36
|
+
self.target_credential = ::Booth::Models::Credential.find_by(id: target_credential_id)
|
|
37
|
+
|
|
38
|
+
return Tron.failure(:target_credential_not_found,
|
|
39
|
+
public_message: I18n.t('booth.target_credential_not_found')) unless target_credential
|
|
40
|
+
|
|
41
|
+
log { "Target credential ##{target_credential.id} found" }
|
|
42
|
+
Tron.success :target_credential_found
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def do_create_session
|
|
46
|
+
self.secret_key = SecureRandom.hex(32)
|
|
47
|
+
|
|
48
|
+
self.session = ::Booth::Models::Session.create!(
|
|
49
|
+
credential: target_credential,
|
|
50
|
+
incognito_credential_id: impersonator_credential_id,
|
|
51
|
+
incognito_secret_key: secret_key,
|
|
52
|
+
most_recent_ip: request.ip,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
log { "Created incognito session ##{session.id}" }
|
|
56
|
+
Tron.success :session_created
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def do_audit
|
|
60
|
+
::Booth::Models::Audit.create!(
|
|
61
|
+
credential_id: impersonator_credential_id,
|
|
62
|
+
ip: request.ip,
|
|
63
|
+
agent: request.agent,
|
|
64
|
+
event: :incognito_token_issued,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
Tron.success :audited
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def do_return_key
|
|
71
|
+
Tron.success :incognito_token_issued,
|
|
72
|
+
secret_key:,
|
|
73
|
+
public_message: I18n.t('booth.incognito_token_issued')
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Booth
|
|
4
|
+
module Adminland
|
|
5
|
+
module Incognitos
|
|
6
|
+
class StopIncognito
|
|
7
|
+
include Calls
|
|
8
|
+
include ::Booth::Logging
|
|
9
|
+
|
|
10
|
+
option :scope, ::Booth::Coercers::Scope
|
|
11
|
+
option :request, ::Booth::Coercers::Request
|
|
12
|
+
|
|
13
|
+
def call
|
|
14
|
+
do_check_logged_in
|
|
15
|
+
.on_success { do_find_current_session }
|
|
16
|
+
.on_success { do_find_impersonator_session }
|
|
17
|
+
.on_success { do_revoke_incognito }
|
|
18
|
+
.on_success { do_audit }
|
|
19
|
+
.on_success { impersonator_session ? do_restore_impersonator : do_logout }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
attr_accessor :current_session, :impersonator_session
|
|
25
|
+
|
|
26
|
+
def do_check_logged_in
|
|
27
|
+
return Tron.failure(:not_logged_in,
|
|
28
|
+
public_message: I18n.t('booth.not_logged_in')) unless request.authentication.logged_in?
|
|
29
|
+
|
|
30
|
+
Tron.success :logged_in
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def do_find_current_session
|
|
34
|
+
self.current_session = ::Booth::Models::Session.find_by(
|
|
35
|
+
id: request.authentication.session_id,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
return Tron.failure(:session_not_found,
|
|
39
|
+
public_message: I18n.t('booth.session_not_found')) unless current_session
|
|
40
|
+
|
|
41
|
+
Tron.success :current_session_found
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def do_find_impersonator_session
|
|
45
|
+
return Tron.success(:no_impersonator_session) unless current_session.impersonator_session_id
|
|
46
|
+
|
|
47
|
+
self.impersonator_session = ::Booth::Models::Session.find_by(
|
|
48
|
+
id: current_session.impersonator_session_id,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
return Tron.failure(:impersonator_session_not_found,
|
|
52
|
+
public_message: I18n.t('booth.impersonator_session_not_found')) unless impersonator_session
|
|
53
|
+
|
|
54
|
+
Tron.success :impersonator_session_found
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def do_revoke_incognito
|
|
58
|
+
current_session.update!(revoked_at: Time.current, revoke_reason: :incognito_stopped)
|
|
59
|
+
Tron.success :incognito_revoked
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def do_audit
|
|
63
|
+
::Booth::Models::Audit.create!(
|
|
64
|
+
credential_id: current_session.incognito_credential_id,
|
|
65
|
+
ip: request.ip,
|
|
66
|
+
agent: request.agent,
|
|
67
|
+
event: :incognito_stopped,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
Tron.success :audited
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def do_restore_impersonator
|
|
74
|
+
impersonator_session.update!(revoked_at: nil, revoke_reason: nil)
|
|
75
|
+
request.authentication.login(session: impersonator_session)
|
|
76
|
+
Tron.success :incognito_stopped,
|
|
77
|
+
public_message: I18n.t('booth.incognito_stopped')
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def do_logout
|
|
81
|
+
request.authentication.logout
|
|
82
|
+
Tron.success :incognito_stopped,
|
|
83
|
+
public_message: I18n.t('booth.incognito_stopped')
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
data/lib/booth/adminland.rb
CHANGED
|
@@ -48,8 +48,16 @@ module Booth
|
|
|
48
48
|
# Incognito Helpers
|
|
49
49
|
# -----------------
|
|
50
50
|
|
|
51
|
-
def self.
|
|
52
|
-
::Booth::Adminland::Incognitos::
|
|
51
|
+
def self.generate_incognito_secret_key(...)
|
|
52
|
+
::Booth::Adminland::Incognitos::GenerateSecretKey.call(...)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def self.consume_incognito_token(...)
|
|
56
|
+
::Booth::Adminland::Incognitos::ConsumeToken.call(...)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def self.stop_incognito(...)
|
|
60
|
+
::Booth::Adminland::Incognitos::StopIncognito.call(...)
|
|
53
61
|
end
|
|
54
62
|
|
|
55
63
|
# ----------------
|
data/lib/booth/models/audit.rb
CHANGED
data/lib/booth/version.rb
CHANGED
|
@@ -74,6 +74,8 @@ class CreateBoothTables < ActiveRecord::Migration[<%= ActiveRecord::Migration.cu
|
|
|
74
74
|
t.string :agent
|
|
75
75
|
t.string :location
|
|
76
76
|
t.hstore :historical_locations, null: false, default: {}
|
|
77
|
+
t.string :incognito_secret_key, index: { unique: true }
|
|
78
|
+
t.references :impersonator_session, foreign_key: { to_table: :booth_sessions, on_delete: :nullify }, type: :uuid, index: true
|
|
77
79
|
t.timestamps
|
|
78
80
|
end
|
|
79
81
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: booth
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0
|
|
4
|
+
version: 0.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- halo
|
|
@@ -230,7 +230,9 @@ files:
|
|
|
230
230
|
- lib/booth/adminland/authenticators/exist.rb
|
|
231
231
|
- lib/booth/adminland/credentials/create.rb
|
|
232
232
|
- lib/booth/adminland/credentials/index.rb
|
|
233
|
-
- lib/booth/adminland/incognitos/
|
|
233
|
+
- lib/booth/adminland/incognitos/consume_token.rb
|
|
234
|
+
- lib/booth/adminland/incognitos/generate_secret_key.rb
|
|
235
|
+
- lib/booth/adminland/incognitos/stop_incognito.rb
|
|
234
236
|
- lib/booth/adminland/onboardings/create.rb
|
|
235
237
|
- lib/booth/adminland/onboardings/destroy.rb
|
|
236
238
|
- lib/booth/adminland/onboardings/find.rb
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Booth
|
|
4
|
-
module Adminland
|
|
5
|
-
module Incognitos
|
|
6
|
-
# The admin (impersonator) specifies their own +scope+ and a +target_scope+.
|
|
7
|
-
# +request+ is coerced with the impersonator's +scope+ (+request.authentication+ checks the
|
|
8
|
-
# impersonator's scope). We create a new session for the target credential and store the
|
|
9
|
-
# impersonator's credential_id as +incognito_credential_id+. If +target_scope+ matches the
|
|
10
|
-
# impersonator's scope, we revoke the impersonator's session before logging in as the target.
|
|
11
|
-
class Start
|
|
12
|
-
include Calls
|
|
13
|
-
include ::Booth::Logging
|
|
14
|
-
|
|
15
|
-
option :scope, ::Booth::Coercers::Scope
|
|
16
|
-
option :request, ::Booth::Coercers::Request
|
|
17
|
-
option :target_credential_id
|
|
18
|
-
option :target_scope
|
|
19
|
-
|
|
20
|
-
def call
|
|
21
|
-
do_check_impersonator_logged_in
|
|
22
|
-
.on_success { do_find_target_credential }
|
|
23
|
-
.on_success { do_compare_scope }
|
|
24
|
-
.on_success { do_create_session }
|
|
25
|
-
.on_success { do_revoke_impersonator_if_same_scope }
|
|
26
|
-
.on_success { do_login }
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
private
|
|
30
|
-
|
|
31
|
-
attr_accessor :impersonator_credential_id, :target_credential, :session
|
|
32
|
-
|
|
33
|
-
def do_check_impersonator_logged_in
|
|
34
|
-
unless request.authentication.logged_in?
|
|
35
|
-
log { 'No impersonator logged in' }
|
|
36
|
-
return Tron.failure :not_logged_in_as_impersonator,
|
|
37
|
-
public_message: I18n.t('booth.not_logged_in_as_impersonator')
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
self.impersonator_credential_id = request.authentication.credential_id
|
|
41
|
-
log { "Impersonator credential_id=#{impersonator_credential_id}" }
|
|
42
|
-
Tron.success :impersonator_captured
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def do_find_target_credential
|
|
46
|
-
self.target_credential = ::Booth::Models::Credential.find_by(id: target_credential_id)
|
|
47
|
-
|
|
48
|
-
if target_credential
|
|
49
|
-
log { "Target credential ##{target_credential.id} found" }
|
|
50
|
-
Tron.success :target_credential_found
|
|
51
|
-
else
|
|
52
|
-
Tron.failure :target_credential_not_found,
|
|
53
|
-
public_message: I18n.t('booth.target_credential_not_found')
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def do_compare_scope
|
|
58
|
-
::Booth::Comparisons::Scope.call(
|
|
59
|
-
expected: target_credential.scope,
|
|
60
|
-
actual: target_scope,
|
|
61
|
-
)
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def do_create_session
|
|
65
|
-
self.session = ::Booth::Models::Session.create!(
|
|
66
|
-
credential: target_credential,
|
|
67
|
-
incognito_credential_id: impersonator_credential_id,
|
|
68
|
-
agent: request.agent,
|
|
69
|
-
most_recent_ip: request.ip,
|
|
70
|
-
)
|
|
71
|
-
log { "Created incognito session ##{session.id}" }
|
|
72
|
-
Tron.success :session_created
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def do_revoke_impersonator_if_same_scope
|
|
76
|
-
return Tron.success(:no_revoke_needed) unless same_scope?
|
|
77
|
-
|
|
78
|
-
impersonator_session = ::Booth::Models::Session.find_by(
|
|
79
|
-
id: request.authentication.session_id,
|
|
80
|
-
)
|
|
81
|
-
return Tron.failure(:impersonator_session_not_found) unless impersonator_session
|
|
82
|
-
|
|
83
|
-
log { "Revoking impersonator session ##{impersonator_session.id}" }
|
|
84
|
-
impersonator_session.update!(revoked_at: Time.current, revoke_reason: :impersonation)
|
|
85
|
-
|
|
86
|
-
Tron.success :impersonator_session_revoked
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
def do_login
|
|
90
|
-
target_auth.login(session:)
|
|
91
|
-
log { "Incognito started: #{target_credential.username}" }
|
|
92
|
-
Tron.success :incognito_started,
|
|
93
|
-
public_message: I18n.t('booth.incognito_started')
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
def same_scope?
|
|
97
|
-
target_scope == request.scope
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
def target_auth
|
|
101
|
-
@target_auth ||= request.authentication(scope: target_scope)
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
end
|
|
105
|
-
end
|
|
106
|
-
end
|