diff --git a/src/ChurchCRM/Authentication/AuthenticationManager.php b/src/ChurchCRM/Authentication/AuthenticationManager.php index e5ea1bdce0..3ea27810c1 100644 --- a/src/ChurchCRM/Authentication/AuthenticationManager.php +++ b/src/ChurchCRM/Authentication/AuthenticationManager.php @@ -127,7 +127,11 @@ public static function authenticate(AuthenticationRequest $AuthenticationRequest } if ($result->isAuthenticated && !$result->preventRedirect) { - $redirectLocation = $_SESSION['location'] ?? 'v2/dashboard'; + $redirectLocation = null; + if ($AuthenticationRequest instanceof LocalUsernamePasswordRequest) { + $redirectLocation = $AuthenticationRequest->redirectPath; + } + $redirectLocation ??= $_SESSION['location'] ?? 'v2/dashboard'; NotificationService::updateNotifications(); $logger->debug( 'Authentication Successful; redirecting to: ' . $redirectLocation @@ -171,11 +175,12 @@ public static function ensureAuthentication(): void 'Session not authenticated. Redirecting to login page' ); - $queryParams = http_build_query([ - 'location' => $_SERVER['REQUEST_URI'], - ]); + $redirectPath = $_GET['location'] ?? $_SESSION['location'] ?? null; $loginUrl = self::getSessionBeginURL(); - if (!str_contains(self::getSessionBeginURL(), $_SERVER['REQUEST_URI'])) { + if (!empty($redirectPath)) { + $queryParams = http_build_query([ + 'location' => $redirectPath, + ]); $loginUrl .= '?' . $queryParams; } RedirectUtils::redirect($loginUrl); @@ -183,6 +188,13 @@ public static function ensureAuthentication(): void LoggerUtils::getAuthLogger()->debug( 'Session authenticated, but redirect requested by authentication provider.' ); + $redirectPath = $_GET['location'] ?? $_SESSION['location'] ?? null; + if (!empty($redirectPath)) { + $queryParams = http_build_query([ + 'location' => $redirectPath, + ]); + $result->nextStepURL .= '?' . $queryParams; + } RedirectUtils::redirect($result->nextStepURL); } LoggerUtils::getAuthLogger()->debug('Session valid'); @@ -195,16 +207,21 @@ public static function ensureAuthentication(): void } } - public static function getSessionBeginURL(): string + public static function getSessionBeginURL(?string $redirectPath = null): string { - return SystemURLs::getRootPath() . '/session/begin'; + $url = SystemURLs::getRootPath() . '/session/begin'; + if (!empty($redirectPath)) { + $url .= '?location=' . urlencode($redirectPath); + } + + return $url; } public static function getForgotPasswordURL(): string { // this assumes we're using local authentication // TODO: when we implement other authentication providers (SAML/etc) - // this URL will need to be configuable by the system administrator + // this URL will need to be configurable by the system administrator // since they likely will not want users attempting to reset ChurchCRM passwords // but rather redirect users to some other password reset mechanism. return SystemURLs::getRootPath() . '/session/forgot-password/reset-request'; diff --git a/src/ChurchCRM/Authentication/AuthenticationResult.php b/src/ChurchCRM/Authentication/AuthenticationResult.php index 4f0818702e..82ae6e31b0 100644 --- a/src/ChurchCRM/Authentication/AuthenticationResult.php +++ b/src/ChurchCRM/Authentication/AuthenticationResult.php @@ -4,8 +4,8 @@ class AuthenticationResult { - public $isAuthenticated; - public $nextStepURL; - public $message; - public $preventRedirect; + public bool $isAuthenticated = false; + public ?string $nextStepURL = null; + public string $message; + public bool $preventRedirect = false; } diff --git a/src/ChurchCRM/Authentication/Requests/APITokenAuthenticationRequest.php b/src/ChurchCRM/Authentication/Requests/APITokenAuthenticationRequest.php index dedef7bbfe..e433896e69 100644 --- a/src/ChurchCRM/Authentication/Requests/APITokenAuthenticationRequest.php +++ b/src/ChurchCRM/Authentication/Requests/APITokenAuthenticationRequest.php @@ -4,9 +4,10 @@ class APITokenAuthenticationRequest extends AuthenticationRequest { - public function __construct($APIToken) + public string $APIToken; + + public function __construct(string $APIToken) { $this->APIToken = $APIToken; } - public $APIToken; } diff --git a/src/ChurchCRM/Authentication/Requests/LocalTwoFactorTokenRequest.php b/src/ChurchCRM/Authentication/Requests/LocalTwoFactorTokenRequest.php index 9bade8329a..14fa67ea3c 100644 --- a/src/ChurchCRM/Authentication/Requests/LocalTwoFactorTokenRequest.php +++ b/src/ChurchCRM/Authentication/Requests/LocalTwoFactorTokenRequest.php @@ -4,9 +4,9 @@ class LocalTwoFactorTokenRequest extends AuthenticationRequest { - public $TwoFACode; + public string $TwoFACode; - public function __construct($TwoFACode) + public function __construct(string $TwoFACode) { $this->TwoFACode = $TwoFACode; } diff --git a/src/ChurchCRM/Authentication/Requests/LocalUsernamePasswordRequest.php b/src/ChurchCRM/Authentication/Requests/LocalUsernamePasswordRequest.php index 223e0c9d36..3e53908b79 100644 --- a/src/ChurchCRM/Authentication/Requests/LocalUsernamePasswordRequest.php +++ b/src/ChurchCRM/Authentication/Requests/LocalUsernamePasswordRequest.php @@ -4,12 +4,14 @@ class LocalUsernamePasswordRequest extends AuthenticationRequest { - public $username; - public $password; + public string $username; + public string $password; + public ?string $redirectPath = null; - public function __construct($username, $password) + public function __construct(string $username, string $password, ?string $redirectPath = null) { $this->username = $username; $this->password = $password; + $this->redirectPath = $redirectPath; } } diff --git a/src/session/index.php b/src/session/index.php index fd46b88e12..4049693403 100644 --- a/src/session/index.php +++ b/src/session/index.php @@ -63,28 +63,27 @@ function endSession(Request $request, Response $response, array $args): void function beginSession(Request $request, Response $response, array $args): Response { + $queryParams = $request->getQueryParams(); + $redirectPath = isset($queryParams['location']) ? urldecode($queryParams['location']) : null; $pageArgs = [ 'sRootPath' => SystemURLs::getRootPath(), - 'localAuthNextStepURL' => AuthenticationManager::getSessionBeginURL(), + 'localAuthNextStepURL' => AuthenticationManager::getSessionBeginURL($redirectPath), 'forgotPasswordURL' => AuthenticationManager::getForgotPasswordURL(), ]; - if ($request->getMethod() == 'POST') { + if ($request->getMethod() === 'POST') { $loginRequestBody = $request->getParsedBody(); - $request = new LocalUsernamePasswordRequest($loginRequestBody['User'], $loginRequestBody['Password']); + $request = new LocalUsernamePasswordRequest($loginRequestBody['User'], $loginRequestBody['Password'], $redirectPath); $authenticationResult = AuthenticationManager::authenticate($request); $pageArgs['sErrorText'] = $authenticationResult->message; } $renderer = new PhpRenderer('templates/'); - $pageArgs['prefilledUserName'] = ''; // Determine if appropriate to pre-fill the username field - if (isset($_GET['username'])) { - $pageArgs['prefilledUserName'] = $_GET['username']; - } elseif (isset($_SESSION['username'])) { - $pageArgs['prefilledUserName'] = $_SESSION['username']; - } + $pageArgs['prefilledUserName'] = $request->getQueryParams()['username'] ?? + $request->getServerParams()['username'] ?? + ''; return $renderer->render($response, 'begin-session.php', $pageArgs); }