forked from GNUsocial/gnu-social
[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;
|
namespace App\Security;
|
||||||
|
|
||||||
use function App\Core\I18n\_m;
|
use function App\Core\I18n\_m;
|
||||||
|
use App\Core\Log;
|
||||||
use App\Core\Router\Router;
|
use App\Core\Router\Router;
|
||||||
use App\Entity\LocalUser;
|
use App\Entity\LocalUser;
|
||||||
use App\Util\Common;
|
use App\Util\Common;
|
||||||
|
use App\Util\Exception\ClientException;
|
||||||
use App\Util\Exception\NoSuchActorException;
|
use App\Util\Exception\NoSuchActorException;
|
||||||
use App\Util\Exception\NotFoundException;
|
use App\Util\Exception\NotFoundException;
|
||||||
use App\Util\Exception\ServerException;
|
use App\Util\Exception\ServerException;
|
||||||
@ -32,6 +34,7 @@ use App\Util\Nickname;
|
|||||||
use Stringable;
|
use Stringable;
|
||||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
|
||||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||||
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
|
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
|
||||||
use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
|
use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
|
||||||
@ -158,9 +161,23 @@ class Authenticator extends AbstractFormLoginAuthenticator implements Authentica
|
|||||||
|
|
||||||
if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {
|
if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {
|
||||||
return new RedirectResponse($targetPath);
|
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
|
public function authenticate(Request $request): PassportInterface
|
||||||
|
@ -151,7 +151,7 @@ abstract class Common
|
|||||||
public static function ensureLoggedIn(): LocalUser
|
public static function ensureLoggedIn(): LocalUser
|
||||||
{
|
{
|
||||||
if (($user = self::user()) == null) {
|
if (($user = self::user()) == null) {
|
||||||
throw new NoLoggedInUser();
|
throw new NoLoggedInUser(self::getRequest());
|
||||||
// TODO Maybe redirect to login page and back
|
// TODO Maybe redirect to login page and back
|
||||||
} else {
|
} else {
|
||||||
return $user;
|
return $user;
|
||||||
|
@ -21,6 +21,8 @@ declare(strict_types = 1);
|
|||||||
|
|
||||||
namespace App\Util\Exception;
|
namespace App\Util\Exception;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* No user logged in
|
* No user logged in
|
||||||
*
|
*
|
||||||
@ -31,6 +33,10 @@ namespace App\Util\Exception;
|
|||||||
* @copyright 2020-2021 Free Software Foundation, Inc http://www.fsf.org
|
* @copyright 2020-2021 Free Software Foundation, Inc http://www.fsf.org
|
||||||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
* @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">
|
<input type="checkbox" name="_remember_me" id="inputRememberMe">
|
||||||
</span>
|
</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') }}">
|
<input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}">
|
||||||
<div>
|
<div>
|
||||||
<button id="signIn" class="btn btn-lg btn-primary" type="submit">Sign in</button>
|
<button id="signIn" class="btn btn-lg btn-primary" type="submit">Sign in</button>
|
||||||
|
Loading…
Reference in New Issue
Block a user