mirror of
https://github.com/projectsend/projectsend.git
synced 2026-09-23 03:53:21 +00:00
3a3fd5358d
The confirm-password screen hid its field from every account that was not Local, and told it to set a password instead. That is right for an account a provider created, which has no password anybody has seen. It is wrong for a directory account: its password is the directory's, PasswordVerification accepts it, and /settings/password refuses to let it set another. So an LDAP account could not get past the confirmation at all, and everything behind it, turning on two-factor included, was out of reach. The new dialog copied the same question. Both now ask whether the account came from a provider, and the prop is called has_password, which is what it means. The dialog also clears the typed password when it closes or once it has been used, instead of keeping it in component state.
76 lines
2.8 KiB
PHP
76 lines
2.8 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Auth;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Modules\Identity\AuthSource;
|
|
use App\Modules\Identity\PasswordVerification;
|
|
use Illuminate\Http\RedirectResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Http\Response as HttpResponse;
|
|
use Illuminate\Validation\ValidationException;
|
|
use Inertia\Inertia;
|
|
use Inertia\Response;
|
|
|
|
class ConfirmablePasswordController extends Controller
|
|
{
|
|
/**
|
|
* Show the confirm password page.
|
|
*/
|
|
public function show(Request $request): Response
|
|
{
|
|
$user = $request->user();
|
|
assert($user !== null);
|
|
|
|
return Inertia::render('auth/confirm-password', [
|
|
// An account provisioned by a provider has no password to
|
|
// confirm with — its stored hash is a generated string nobody
|
|
// has seen. The screen offers to set one instead of asking for
|
|
// it, which is the only way past this for those accounts, and
|
|
// this screen stands in front of two-factor enrolment.
|
|
//
|
|
// Social, not "anything but Local": a directory account has a
|
|
// password -- the directory's -- and store() accepts it. Asking
|
|
// whether the account was Local told those accounts to set one
|
|
// here instead, which /settings/password refuses them, and left
|
|
// them no way past this screen at all.
|
|
'has_password' => $user->auth_source !== AuthSource::Social,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Confirm the user's password.
|
|
*
|
|
* Through PasswordVerification, so this asks the same question the
|
|
* sign-in form asks: is this the account's password, from wherever
|
|
* that account's password lives. Checking only the local hash refused
|
|
* every directory-provisioned account the password it actually has --
|
|
* their local hash is a Str::password(64) nobody has ever seen -- and
|
|
* this screen stands in front of enrolling in two-factor, so those
|
|
* accounts could not enrol at all.
|
|
*
|
|
* Asked for JSON, it answers with a bare 204: that is the password
|
|
* dialog (RequirePasswordConfirmation), which stays on the page and
|
|
* sends the refused request again itself, so there is nowhere to go.
|
|
*/
|
|
public function store(Request $request, PasswordVerification $passwords): RedirectResponse|HttpResponse
|
|
{
|
|
$user = $request->user();
|
|
assert($user !== null);
|
|
|
|
if (! $passwords->verify($user, (string) $request->string('password'))) {
|
|
throw ValidationException::withMessages([
|
|
'password' => __('auth.password'),
|
|
]);
|
|
}
|
|
|
|
$request->session()->put('auth.password_confirmed_at', time());
|
|
|
|
if ($request->expectsJson()) {
|
|
return response()->noContent();
|
|
}
|
|
|
|
return redirect()->intended(route('dashboard', absolute: false));
|
|
}
|
|
}
|