Skip to content
Draft
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
33 changes: 23 additions & 10 deletions src/Auth/UserTags.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,23 @@ public function index()

// No user found? Get the current one.
if (! $user) {
if (! $user = User::current()) {
if (! $user = $this->currentUser()) {
return $this->parseNoResults();
}
}

return $this->aliasedResult($user);
}

private function currentUser()
{
if (! $guard = $this->params->get('guard')) {
return User::current();
}

return User::fromUser(auth($guard)->user());
}

/**
* Alias of the {{ user }} tag.
*
Expand Down Expand Up @@ -420,6 +429,10 @@ public function logoutUrl()
$queryParams['redirect'] = $redirect;
}

if ($guard = $this->params->get('guard')) {
$queryParams['guard'] = $guard;
}

return route('statamic.logout', $queryParams);
}

Expand All @@ -430,7 +443,7 @@ public function logoutUrl()
*/
public function logout()
{
auth()->logout();
auth($this->params->get('guard'))->logout();

abort(redirect($this->params->get('redirect', '/'), $this->params->get('response', 302)));
}
Expand Down Expand Up @@ -575,12 +588,12 @@ public function resetPasswordForm()
*/
public function can()
{
if (! $user = User::current()) {
if (! $user = $this->currentUser()) {
return $this->parser ? null : false;
}

$permissions = Arr::wrap($this->params->explode(['permission', 'do']));
$arguments = $this->params->except(['permission', 'do'])->all();
$arguments = $this->params->except(['permission', 'do', 'guard'])->all();

foreach ($permissions as $permission) {
if ($user->can($permission, $arguments)) {
Expand All @@ -600,12 +613,12 @@ public function can()
*/
public function cant()
{
if (! $user = User::current()) {
if (! $user = $this->currentUser()) {
return $this->parser ? $this->parse() : true;
}

$permissions = Arr::wrap($this->params->explode(['permission', 'do']));
$arguments = $this->params->except(['permission', 'do'])->all();
$arguments = $this->params->except(['permission', 'do', 'guard'])->all();

$can = false;

Expand All @@ -632,7 +645,7 @@ public function cant()
*/
public function is()
{
if (! $user = User::current()) {
if (! $user = $this->currentUser()) {
return $this->parser ? null : false;
}

Expand Down Expand Up @@ -660,7 +673,7 @@ public function is()
*/
public function isnt()
{
if (! $user = User::current()) {
if (! $user = $this->currentUser()) {
return $this->parser ? $this->parse() : true;
}

Expand Down Expand Up @@ -695,7 +708,7 @@ public function isnt()
*/
public function in()
{
if (! $user = User::current()) {
if (! $user = $this->currentUser()) {
return $this->parser ? null : false;
}

Expand All @@ -719,7 +732,7 @@ public function in()
*/
public function notIn()
{
if (! $user = User::current()) {
if (! $user = $this->currentUser()) {
return $this->parser ? $this->parse() : true;
}

Expand Down
22 changes: 21 additions & 1 deletion src/Http/Controllers/User/LoginController.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Statamic\Http\Controllers\User;

use Illuminate\Auth\Events\Failed;
use Illuminate\Contracts\Auth\StatefulGuard;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
Expand Down Expand Up @@ -108,7 +109,7 @@ protected function fireFailedEvent($request, $user = null)

public function logout()
{
Auth::logout();
Auth::guard($this->requestedGuard())->logout();

$redirect = request()->get('redirect');

Expand All @@ -119,6 +120,25 @@ public function logout()
return redirect($url);
}

private function requestedGuard(): ?string
{
$guard = request()->query('guard');

if (! $guard) {
return null;
}

abort_unless(is_string($guard) && $this->isStatefulGuard($guard), 404);

return $guard;
}

private function isStatefulGuard(string $guard): bool
{
return array_key_exists($guard, config('auth.guards'))
&& Auth::guard($guard) instanceof StatefulGuard;
}

protected function username()
{
return 'email';
Expand Down
64 changes: 64 additions & 0 deletions tests/Tags/User/LogoutTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Tests\Tags\User;

use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use Statamic\Facades\User;
use Tests\PreventSavingStacheItemsToDisk;
Expand Down Expand Up @@ -44,6 +45,69 @@ public function it_does_not_redirect_to_external_url()
$this->assertGuest();
}

#[Test]
public function it_can_logout_a_specific_guard()
{
config()->set('auth.guards.statamic', config('auth.guards.web'));

$this
->actingAs($this->createUser(), 'statamic')
->actingAs(User::make()->id('web-user')->email('web@example.com')->save(), 'web')
->get(route('statamic.logout', ['guard' => 'statamic']))
->assertRedirect('/');

$this->assertGuest('statamic');
$this->assertAuthenticated('web');
}

#[Test]
#[DataProvider('invalidGuardProvider')]
public function it_does_not_logout_an_invalid_guard(string $guard)
{
config()->set('auth.guards.api', ['driver' => 'token', 'provider' => 'users']);

$this
->actingAs($this->createUser())
->get(route('statamic.logout', ['guard' => $guard]))
->assertNotFound();

$this->assertAuthenticated();
}

public static function invalidGuardProvider(): array
{
return [
'unknown guard' => ['nope'],
'non-session guard' => ['api'],
];
}

#[Test]
public function it_does_not_logout_an_array_of_guards()
{
$this
->actingAs($this->createUser())
->get(route('statamic.logout', ['guard' => ['web']]))
->assertNotFound();

$this->assertAuthenticated();
}

#[Test]
public function it_ignores_the_guard_param_on_the_cp_logout_route()
{
config()->set('auth.guards.statamic', config('auth.guards.web'));

$this
->actingAs($this->createUser(), 'statamic')
->actingAs(User::make()->id('web-user')->email('web@example.com')->save(), 'web')
->get(cp_route('logout', ['guard' => 'statamic']))
->assertRedirect('/');

$this->assertAuthenticated('statamic');
$this->assertGuest('web');
}

private function createUser()
{
return tap(User::make()->id('test-user')->email('test@example.com')->password('secret'))->save();
Expand Down
44 changes: 44 additions & 0 deletions tests/Tags/User/UserTagsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,30 @@ public function it_renders_user_in_tag_content()
$this->assertEquals('', $this->tag('{{ user:not_in group="favourite|non_favourite" }}yes{{ /user:not_in }}'));
}

#[Test]
#[DataProvider('guardProvider')]
public function it_renders_tag_content_for_a_specific_guard($tag, $expected)
{
config()->set('auth.guards.statamic', config('auth.guards.web'));
$this->setTestRoles(['admin' => ['configure collections']]);
$this->setTestUserGroups(['favourite' => ['admin']]);

auth('statamic')->login(User::make()->email('admin@example.com')->assignRole('admin')->addToGroup('favourite')->save());

$this->assertEquals('', $this->tag(sprintf($tag, '')));
$this->assertEquals($expected, $this->tag(sprintf($tag, ' guard="statamic"')));
}

public static function guardProvider()
{
return [
'user' => ['{{ user%s }}{{ email }}{{ /user }}', 'admin@example.com'],
'can' => ['{{ user:can%s do="configure collections" }}yes{{ /user:can }}', 'yes'],
'is' => ['{{ user:is%s role="admin" }}yes{{ /user:is }}', 'yes'],
'in' => ['{{ user:in%s group="favourite" }}yes{{ /user:in }}', 'yes'],
];
}

#[Test]
public function it_can_logout_user()
{
Expand Down Expand Up @@ -167,12 +191,32 @@ public function it_can_logout_user_with_custom_redirect()
$this->assertEquals(url('home'), $exception->getResponse()->getTargetUrl());
}

#[Test]
public function it_can_logout_user_from_a_specific_guard()
{
config()->set('auth.guards.statamic', config('auth.guards.web'));

auth('statamic')->login(User::make()->save());
auth('web')->login(User::make()->save());

try {
$this->tag('{{ user:logout guard="statamic" }}');
} catch (HttpResponseException $exception) {
//
}

$this->assertFalse(auth('statamic')->check());
$this->assertTrue(auth('web')->check());
}

#[Test]
public function it_can_render_logout_url()
{
$this->assertEquals(route('statamic.logout'), $this->tag('{{ user:logout_url }}'));

$this->assertEquals(route('statamic.logout', ['redirect' => 'home']), $this->tag('{{ user:logout_url redirect="home" }}'));

$this->assertEquals(route('statamic.logout', ['guard' => 'statamic']), $this->tag('{{ user:logout_url guard="statamic" }}'));
}

#[Test]
Expand Down
Loading