[CORE][SECURITY] Replicate 'next' form submission feature on login form
This commit is contained in:
parent
46c91a4b39
commit
9a0c74cb0c
@ -22,9 +22,11 @@ declare(strict_types = 1);
|
||||
namespace App\Security;
|
||||
|
||||
use function App\Core\I18n\_m;
|
||||
use App\Core\Log;
|
||||
use App\Core\Router\Router;
|
||||
use App\Entity\LocalUser;
|
||||
use App\Util\Common;
|
||||
use App\Util\Exception\ClientException;
|
||||
use App\Util\Exception\NoSuchActorException;
|
||||
use App\Util\Exception\NotFoundException;
|
||||
use App\Util\Exception\ServerException;
|
||||
@ -32,6 +34,7 @@ use App\Util\Nickname;
|
||||
use Stringable;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
|
||||
use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
|
||||
@ -158,9 +161,23 @@ class Authenticator extends AbstractFormLoginAuthenticator implements Authentica
|
||||
|
||||
if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {
|
||||
return new RedirectResponse($targetPath);
|
||||
} elseif (!\is_null($next = $request->request->get('_next') ?? $request->query->get('next'))) {
|
||||
try {
|
||||
if ($pos = mb_strrpos($next, '#')) {
|
||||
$fragment = mb_substr($next, $pos);
|
||||
$next = mb_substr($next, 0, $pos);
|
||||
}
|
||||
Router::match($next);
|
||||
return new RedirectResponse(url: $next . ($fragment ?? ''));
|
||||
} catch (ResourceNotFoundException $e) {
|
||||
$user = Common::user();
|
||||
$user_id = !\is_null($user) ? $user->getId() : '(not logged in)';
|
||||
Log::warning("Suspicious activity: User with ID {$user_id} submitted a form where the `_next` parameter is not a valid local URL ({$next})");
|
||||
throw new ClientException(_m('Invalid form submission'), $e);
|
||||
}
|
||||
} else {
|
||||
return new RedirectResponse(url: Router::url('root'));
|
||||
}
|
||||
|
||||
return new RedirectResponse(Router::url('root'));
|
||||
}
|
||||
|
||||
public function authenticate(Request $request): PassportInterface
|
||||
|
@ -151,7 +151,7 @@ abstract class Common
|
||||
public static function ensureLoggedIn(): LocalUser
|
||||
{
|
||||
if (($user = self::user()) == null) {
|
||||
throw new NoLoggedInUser();
|
||||
throw new NoLoggedInUser(self::getRequest());
|
||||
// TODO Maybe redirect to login page and back
|
||||
} else {
|
||||
return $user;
|
||||
|
@ -21,6 +21,8 @@ declare(strict_types = 1);
|
||||
|
||||
namespace App\Util\Exception;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* No user logged in
|
||||
*
|
||||
@ -31,6 +33,10 @@ namespace App\Util\Exception;
|
||||
* @copyright 2020-2021 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
||||
*/
|
||||
class NoLoggedInUser extends ClientException
|
||||
class NoLoggedInUser extends RedirectException
|
||||
{
|
||||
public function __construct(Request $request)
|
||||
{
|
||||
parent::__construct('security_login', ['next' => $request->getRequestUri()]);
|
||||
}
|
||||
}
|
||||
|
@ -41,6 +41,9 @@
|
||||
<input type="checkbox" name="_remember_me" id="inputRememberMe">
|
||||
</span>
|
||||
|
||||
{% if app.request.query.has('next') %}
|
||||
<input type="hidden" name="_next" value="{{ app.request.query.get('next') }}">
|
||||
{% endif %}
|
||||
<input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}">
|
||||
<div>
|
||||
<button id="signIn" class="btn btn-lg btn-primary" type="submit">Sign in</button>
|
||||
|
Loading…
Reference in New Issue
Block a user