Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions src/Features/UserImpersonation.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ public static function makeResponse(#[\SensitiveParameter] string|Model $token,

Auth::guard($token->auth_guard)->loginUsingId($token->user_id, $token->remember);

$token->delete();
session()->put('tenancy_impersonation_guard', $token->auth_guard);

session()->put('tenancy_impersonating', true);
$token->delete();

return redirect($token->redirect_url);
}
Expand All @@ -76,16 +76,20 @@ public static function modelClass(): string

public static function isImpersonating(): bool
{
return session()->has('tenancy_impersonating');
return session()->has('tenancy_impersonation_guard');
}

/**
* Logout from the current domain and forget impersonation session.
*/
public static function stopImpersonating(): void
public static function stopImpersonating(bool $logout = true): void
{
auth()->logout();
if ($logout) {
$guard = session()->get('tenancy_impersonation_guard');

auth($guard)->logout();
}

session()->forget('tenancy_impersonating');
session()->forget('tenancy_impersonation_guard');
}
}
51 changes: 47 additions & 4 deletions tests/TenantUserImpersonationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,14 @@
->assertSee('You are logged in as Joe');

expect(UserImpersonation::isImpersonating())->toBeTrue();
expect(session('tenancy_impersonating'))->toBeTrue();
expect(session('tenancy_impersonation_guard'))->toBe('web');
expect($token->auth_guard)->toBe('web');

// Leave impersonation
UserImpersonation::stopImpersonating();

expect(UserImpersonation::isImpersonating())->toBeFalse();
expect(session('tenancy_impersonating'))->toBeNull();
expect(session('tenancy_impersonation_guard'))->toBeNull();

// Assert can't access the tenant dashboard
pest()->get('http://foo.localhost/dashboard')
Expand Down Expand Up @@ -135,19 +136,61 @@
->assertSee('You are logged in as Joe');

expect(UserImpersonation::isImpersonating())->toBeTrue();
expect(session('tenancy_impersonating'))->toBeTrue();
expect(session('tenancy_impersonation_guard'))->toBe('web');
expect($token->auth_guard)->toBe('web');

// Leave impersonation
UserImpersonation::stopImpersonating();

expect(UserImpersonation::isImpersonating())->toBeFalse();
expect(session('tenancy_impersonating'))->toBeNull();
expect(session('tenancy_impersonation_guard'))->toBeNull();

// Assert can't access the tenant dashboard
pest()->get('/acme/dashboard')
->assertRedirect('/login');
});

test('stopImpersonating can keep the user authenticated', function() {
makeLoginRoute();

Route::middleware(InitializeTenancyByPath::class)->prefix('/{tenant}')->group(getRoutes(false));

$tenant = Tenant::create([
'id' => 'acme',
'tenancy_db_name' => 'db' . Str::random(16),
]);

migrateTenants();

$user = $tenant->run(function () {
return ImpersonationUser::create([
'name' => 'Joe',
'email' => 'joe@local',
'password' => bcrypt('secret'),
]);
});

// Impersonate the user
$token = tenancy()->impersonate($tenant, $user->id, '/acme/dashboard');

pest()->get('/acme/impersonate/' . $token->token)
->assertRedirect('/acme/dashboard');

expect(UserImpersonation::isImpersonating())->toBeTrue();

// Stop impersonating without logging out
UserImpersonation::stopImpersonating(false);

// The impersonation session key should be cleared
expect(UserImpersonation::isImpersonating())->toBeFalse();
expect(session('tenancy_impersonation_guard'))->toBeNull();

// The user should still be authenticated
pest()->get('/acme/dashboard')
->assertSuccessful()
->assertSee('You are logged in as Joe');
});

test('tokens have a limited ttl', function () {
Route::middleware(InitializeTenancyByDomain::class)->group(getRoutes());

Expand Down
Loading