diff --git a/CHANGELOG.md b/CHANGELOG.md index 94a90280d4a..48bebdef91c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -103,6 +103,7 @@ - Fixed a bug where typing an option’s exact label or value into a combobox that accepts free text could make two options look selected. Exact matches are now listed first. - Fixed a bug where rich selects’ menus could extend off-screen when an option had a long label or hint, and a long option could stretch the select itself past its container. - Fixed a bug where permission trees, such as user group permissions and the public MCP settings, used the browser’s native checkboxes instead of the control panel’s checkbox styling. +- Fixed a bug where logging in from the control panel’s login page could redirect to the front end instead of the control panel, when a front-end login path was also configured. - Fixed a bug where element edit pages could have a few pixels of vertical scroll after the window was resized, even though their content fit within it. ([#20028](https://github.com/craftcms/cms/pull/20028)) - Fixed a bug where control panel pages and details panes shifted sideways when a scrollbar appeared. ([#20030](https://github.com/craftcms/cms/pull/20030)) diff --git a/routes/cp.php b/routes/cp.php index 037194fe3d2..df9eecaab04 100644 --- a/routes/cp.php +++ b/routes/cp.php @@ -109,7 +109,7 @@ Route::allowDuringMaintenance()->middleware(RunQueue::class)->group(function () { Route::get(CpAuthPath::Login->value, [LoginController::class, 'showLogin']); - Route::post(CpAuthPath::Login->value, [LoginController::class, 'attemptLogin'])->middleware('throttle:'.LoginRateLimiter::NAME); + Route::post(CpAuthPath::Login->value, [LoginController::class, 'attemptLogin'])->middleware('throttle:'.LoginRateLimiter::NAME)->name('login.attempt'); Route::match(['get', 'post'], CpAuthPath::Logout->value, [LoginController::class, 'logout'])->name('logout'); Route::get(CpAuthPath::TwoFactorChallenge->value, [TwoFactorAuthenticationController::class, 'showForm'])->middleware(EnsureTwoFactorChallengeIsRecent::class); Route::get(CpAuthPath::SetPassword->value, [SetPasswordController::class, 'show']); diff --git a/src/Http/Controllers/Auth/LoginController.php b/src/Http/Controllers/Auth/LoginController.php index 12adda1bc1b..68b3e9157e9 100644 --- a/src/Http/Controllers/Auth/LoginController.php +++ b/src/Http/Controllers/Auth/LoginController.php @@ -65,10 +65,10 @@ public function showLogin(Request $request, GeneralConfig $generalConfig, AuthMe inertiaProps: [ 'username' => $generalConfig->rememberUsernameDuration ? $authMethods->getRememberedUsername() : '', 'oauthLoginButtons' => $oauthLoginButtons, - 'action' => $request->isCpRequest() ? action([self::class, 'attemptLogin']) : action_url('users/login'), + 'action' => $request->isCpRequest() ? route('craft.cp.login.attempt') : action_url('users/login'), ], data: [ - 'action' => action([self::class, 'attemptLogin']), + 'action' => $request->isCpRequest() ? route('craft.cp.login.attempt') : action([self::class, 'attemptLogin']), 'oauthLoginButtons' => $oauthLoginButtons, ], ); @@ -103,7 +103,7 @@ public function showLoginModal(Request $request, Impersonation $impersonation, H } $html = template('_special/login-modal', [ - 'action' => action([LoginController::class, 'attemptLogin']), + 'action' => route('craft.cp.login.attempt'), 'staticEmail' => $staticEmail, 'forElevatedSession' => $forElevatedSession, ], templateMode: TemplateMode::Cp); diff --git a/src/Http/Controllers/Auth/SessionInfoController.php b/src/Http/Controllers/Auth/SessionInfoController.php index 9ecb88e15ab..6856ef710fa 100644 --- a/src/Http/Controllers/Auth/SessionInfoController.php +++ b/src/Http/Controllers/Auth/SessionInfoController.php @@ -88,7 +88,7 @@ public function confirmPassword( $loginName = (string) ($user->email ?? $user->username); $context = [ ...$templateGlobals->resolve(), - 'action' => action([LoginController::class, 'attemptLogin']), + 'action' => route('craft.cp.login.attempt'), 'forElevatedSession' => true, 'generalConfig' => $generalConfig, 'staticEmail' => $loginName, diff --git a/tests/Feature/Http/Controllers/Auth/LoginControllerTest.php b/tests/Feature/Http/Controllers/Auth/LoginControllerTest.php index 2577400f219..39a9ab8c24b 100644 --- a/tests/Feature/Http/Controllers/Auth/LoginControllerTest.php +++ b/tests/Feature/Http/Controllers/Auth/LoginControllerTest.php @@ -170,6 +170,21 @@ expect(Auth::id())->toBe($user->id); }); +test('control panel logins post to the control panel and redirect to the post-CP-login redirect', function () { + // A front-end login path is another route to the same action, so URLs generated from the action could point there. + Route::post('logmein', [LoginController::class, 'attemptLogin']); + Route::getRoutes()->refreshActionLookups(); + Cms::config()->postCpLoginRedirect = 'entries'; + + get(cp_url(CpAuthPath::Login->value)) + ->assertInertia(fn (AssertableInertia $page) => $page->where('action', cp_url(CpAuthPath::Login->value))); + + post(cp_url(CpAuthPath::Login->value), [ + 'loginName' => User::findOne()->email, + 'password' => 'craftcms2018!!', + ])->assertRedirect(cp_url('entries')); +}); + test('modal login requires refreshing the token before resubmitting a form', function (bool $authenticated) { // Laravel skips CSRF verification in the testing environment. $this->app->instance('env', 'local');