Skip to content

Commit 12d13f7

Browse files
jasonvargaclaude
andauthored
[6.x] Stop auto-logging in users after password reset (#14454)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 01395e6 commit 12d13f7

File tree

5 files changed

+177
-5
lines changed

5 files changed

+177
-5
lines changed

resources/js/pages/auth/passwords/Reset.vue

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,6 @@ const submit = () => {
3030
processing.value = true;
3131
errors.value = {};
3232
},
33-
onSuccess: (e) => {
34-
return window.location.href = e.url;
35-
},
3633
onError: () => processing.value = false
3734
});
3835
}

src/Auth/ResetsPasswords.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,6 @@ protected function resetPassword($user, $password)
130130
$user->save();
131131

132132
event(new PasswordReset($user));
133-
134-
$this->guard()->login($user);
135133
}
136134

137135
/**

src/Http/Controllers/CP/Auth/ResetPasswordController.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ public function broker()
2525
return Password::broker($broker);
2626
}
2727

28+
public function redirectPath()
29+
{
30+
return cp_route('login');
31+
}
32+
2833
protected function resetFormAction()
2934
{
3035
return route('statamic.cp.password.reset.action');

src/Http/Middleware/CP/HandleInertiaRequests.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,11 @@ private function toasts(Request $request)
7575
$this->toasts->success($message);
7676
}
7777

78+
// Laravel's built-in auth flows (password reset, etc.) flash to 'status'.
79+
if ($message = $session->get('status')) {
80+
$this->toasts->success($message);
81+
}
82+
7883
if ($message = $session->get('error')) {
7984
$this->toasts->error($message);
8085
}

tests/Auth/ResetPasswordTest.php

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
<?php
2+
3+
namespace Tests\Auth;
4+
5+
use Illuminate\Support\Collection;
6+
use Illuminate\Support\Facades\Hash;
7+
use Illuminate\Support\Facades\Password;
8+
use PHPUnit\Framework\Attributes\DataProvider;
9+
use PHPUnit\Framework\Attributes\Test;
10+
use Statamic\Auth\File\Passkey;
11+
use Statamic\Auth\Passwords\PasswordReset;
12+
use Statamic\Auth\TwoFactor\RecoveryCode;
13+
use Statamic\Contracts\Auth\TwoFactor\TwoFactorAuthenticationProvider;
14+
use Statamic\Facades\User;
15+
use Symfony\Component\Uid\Uuid;
16+
use Tests\PreventSavingStacheItemsToDisk;
17+
use Tests\TestCase;
18+
use Webauthn\PublicKeyCredentialSource;
19+
use Webauthn\TrustPath\EmptyTrustPath;
20+
21+
class ResetPasswordTest extends TestCase
22+
{
23+
use PreventSavingStacheItemsToDisk;
24+
25+
public static function resetPasswordProvider()
26+
{
27+
return [
28+
'cp' => ['cp'],
29+
'web' => ['web'],
30+
];
31+
}
32+
33+
private function resetUrl($type)
34+
{
35+
return match ($type) {
36+
'cp' => cp_route('password.reset.action'),
37+
'web' => route('statamic.password.reset.action'),
38+
};
39+
}
40+
41+
private function defaultRedirectUrl($type)
42+
{
43+
return match ($type) {
44+
'cp' => cp_route('login'),
45+
'web' => route('statamic.site'),
46+
};
47+
}
48+
49+
private function createUser()
50+
{
51+
return tap(User::make()->makeSuper()->email('san@holo.com')->password('secret'))->save();
52+
}
53+
54+
private function enableTwoFactor($user)
55+
{
56+
$user->merge([
57+
'two_factor_confirmed_at' => now()->timestamp,
58+
'two_factor_secret' => encrypt(app(TwoFactorAuthenticationProvider::class)->generateSecretKey()),
59+
'two_factor_recovery_codes' => encrypt(json_encode(Collection::times(8, function () {
60+
return RecoveryCode::generate();
61+
})->all())),
62+
]);
63+
64+
$user->save();
65+
66+
return $user;
67+
}
68+
69+
private function addPasskey($user)
70+
{
71+
$credential = PublicKeyCredentialSource::create(
72+
publicKeyCredentialId: 'test-credential-id',
73+
type: 'public-key',
74+
transports: ['usb'],
75+
attestationType: 'none',
76+
trustPath: new EmptyTrustPath(),
77+
aaguid: Uuid::fromString('00000000-0000-0000-0000-000000000000'),
78+
credentialPublicKey: 'test-public-key',
79+
userHandle: $user->id(),
80+
counter: 0,
81+
);
82+
83+
$passkey = (new Passkey)->setUser($user)->setName('Test Key')->setCredential($credential);
84+
$passkey->save();
85+
86+
return $user->fresh();
87+
}
88+
89+
private function createToken($user, $type)
90+
{
91+
$broker = config('statamic.users.passwords.'.PasswordReset::BROKER_RESETS);
92+
93+
if (is_array($broker)) {
94+
$broker = $broker[$type];
95+
}
96+
97+
return Password::broker($broker)->createToken($user);
98+
}
99+
100+
#[Test]
101+
#[DataProvider('resetPasswordProvider')]
102+
public function it_resets_the_password_and_user_is_not_authenticated($type)
103+
{
104+
$user = $this->createUser();
105+
$token = $this->createToken($user, $type);
106+
107+
$this
108+
->assertGuest()
109+
->post($this->resetUrl($type), [
110+
'token' => $token,
111+
'email' => 'san@holo.com',
112+
'password' => 'newpassword',
113+
'password_confirmation' => 'newpassword',
114+
])
115+
->assertSessionHas('status')
116+
->assertRedirect($this->defaultRedirectUrl($type));
117+
118+
$this->assertGuest();
119+
$this->assertTrue(Hash::check('newpassword', $user->fresh()->password()));
120+
}
121+
122+
#[Test]
123+
#[DataProvider('resetPasswordProvider')]
124+
public function it_resets_password_for_two_factor_user_and_user_is_not_authenticated($type)
125+
{
126+
$user = $this->enableTwoFactor($this->createUser());
127+
$token = $this->createToken($user, $type);
128+
129+
$this
130+
->assertGuest()
131+
->post($this->resetUrl($type), [
132+
'token' => $token,
133+
'email' => 'san@holo.com',
134+
'password' => 'newpassword',
135+
'password_confirmation' => 'newpassword',
136+
])
137+
->assertSessionHas('status')
138+
->assertRedirect($this->defaultRedirectUrl($type));
139+
140+
$this->assertGuest();
141+
$this->assertTrue(Hash::check('newpassword', $user->fresh()->password()));
142+
}
143+
144+
#[Test]
145+
#[DataProvider('resetPasswordProvider')]
146+
public function it_resets_password_for_passkey_user_and_user_is_not_authenticated($type)
147+
{
148+
config(['statamic.webauthn.allow_password_login_with_passkey' => false]);
149+
150+
$user = $this->addPasskey($this->createUser());
151+
$token = $this->createToken($user, $type);
152+
153+
$this
154+
->assertGuest()
155+
->post($this->resetUrl($type), [
156+
'token' => $token,
157+
'email' => 'san@holo.com',
158+
'password' => 'newpassword',
159+
'password_confirmation' => 'newpassword',
160+
])
161+
->assertSessionHas('status')
162+
->assertRedirect($this->defaultRedirectUrl($type));
163+
164+
$this->assertGuest();
165+
$this->assertTrue(Hash::check('newpassword', $user->fresh()->password()));
166+
}
167+
}

0 commit comments

Comments
 (0)