Как убрать токен аутентификации "ролей" для реализации системы MFA? - PullRequest
1 голос
/ 19 сентября 2019

Я хочу интегрировать вторичную меру аутентификации для подмножества пользователей после их входа в систему:

public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
    $user = $token->getUser();

    if ($user->getOrganization()->getMfa() {

        //$token->setAuthenticated(false);
        $token->setRoles(null);

        return new RedirectResponse($this->router->generate('mfa'));
    }

    return new RedirectResponse($this->router->generate('home'));
}

Затем я хотел бы проверить код безопасности в другом контроллере:

if((int)$session->get('authCode') === (int)$request->get('auth_code')) {

    //$token->setAuthenticated(true);
    $token->setRoles($user->getRoles());

    return new RedirectResponse($this->router->generate('home'));
}

Проблема с setAutheticated(false) заключается в том, что я теряю доступ к объекту $user после завершения метода.

Я думаю об удалении ролей, предоставленных пользователю;но я не могу понять, как удалить роли из существующего токена.

1 Ответ

1 голос
/ 19 сентября 2019

Вы не можете установить свойства role токена.Как вы видели, TokenInterface не включает в себя установщик для ролей.

И вы не можете setAuthenticated(false), потому что тогда вы очистите первую аутентификацию factor ,и возвращаемся к нулю.

Но я полагаю, что вы подходите к проблеме неправильно.

Оставьте токен как есть, и используйте слушатель для onAuthenticationSuccess, чтобы проверить User::organization::getMfa()чтобы решить, нужно ли вам:

  • отправить пользователю дополнительный код аутентификации,
  • сохранить где-то, что вы не завершили аутентификацию (например, в сеансе, в БД впользовательское свойство, отдельное хранилище для этого и т. д.).

(Лично я бы сделал требование MFA другой ролью, чтобы ее можно было хранить на токене, и вам не нужно было быпроверьте дополнительные вещи для этого).

Затем создайте подписчика на события для каждого запроса.

На этом слушателе вы добавите use Symfony\Component\Security\Core\Securityполучить доступ к пользователю и посмотреть, если User::organization::getMfa() === true;и все, что означает, чтобы проверить, если аутентификация не завершена (например, если вы сохранили в сеансе, или проверить пользовательский объект непосредственно и т. д.).

  • Если у вас нет токена, вы return, это представление без аутентификации, и это не проблема слушателей.

  • Если пользователю не требуется MFA, вы просто return;тут делать нечего.

  • Если пользователю требуется MFA, но он не находится в процессе аутентификации, вы return.Это означает, что пользователь уже полностью прошел аутентификацию и может продолжить.

  • Если пользователю требуется MFA и он находится в середине процесса аутентификации, вы отображаете любые средства для его завершения.,Обычно это форма.

  • Если пользователю требуется MFA, и он находится в процессе аутентификации , и они отправляют вам средства для проверки этой аутентификации (например,POST-запрос с соответствующими полями), вы проверяете, что аутентификация в порядке.

  • Проверка правильна?Вы очищаете бит «аутентификация в процессе» и возвращаетесь.Дальнейшие запросы не будут перехвачены.

  • Проверка плоха?Вы либо позволяете им проверять снова, повторно отправлять проверочные коды, полностью выходить из системы, чтобы они снова начали ... Что именно будет очень зависеть от ваших требований.

ПолныйРеализация кода будет зависеть от вас, поскольку невозможно охватить все возможные сценарии.

Но для начала ваш подписчик может быть чем-то вроде этого (обратите внимание, что есть также пара нереализованных методов).

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Security\Core\Security;

class MfaSubscriber implements EventSubscriberInterface
{

    private $security;

    public function __construct(Security $security)
    {
        $this->security = $security;
    }

    public function onRequest(RequestEvent $event)
    {

        if ($event->getRequestType() === HttpKernelInterface::SUB_REQUEST) {
            return;
        }

        $request = $event->getRequest();

        if ( null == $token = $this->security->getToken()) {
            return;
        }

        if ( ! in_array('ROLE_NEEDS_MFA', $token->getRoleNames(), true)) {
            return;
        }

        if ( ! $request->hasPreviousSession() || ! $request->getSession()->get('AUTHENTICATION_IN_PROCESS')) {
            return;
        }

        if (
            $request->getMethod() === Request::METHOD_POST
            && $request->get('verification_code')
            && $this->verifyCode($request->get('verification_code')) // verify code needs to be implemented
        ) {
            $request->getSession()->set('AUTHENTICATION_IN_PROCESS', null);

            return;
        }

        $event->setResponse($this->displayMfaVerificationMethod($request, $token));

    }

    public static function getSubscribedEvents(): array
    {
        return [
            KernelEvents::REQUEST => 'onRequest',
        ];
    }
}

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...