Allow 2FA for SAML and LDAP users (#4000)
* inline totp image as data uri to prevent caching issues * allow 2fa for ldap and saml users * allow 2FA access for super admin to all profiles
This commit is contained in:
@@ -367,23 +367,34 @@ final class ProfileController extends AbstractController
|
||||
return $this->redirectToRoute('user_profile_2fa', ['username' => $profile->getUserIdentifier()]);
|
||||
}
|
||||
|
||||
$qrCodeContent = $totpAuthenticator->getQRContent($profile);
|
||||
|
||||
$result = Builder::create()
|
||||
->writer(new PngWriter())
|
||||
->writerOptions([])
|
||||
->data($qrCodeContent)
|
||||
->encoding(new Encoding('UTF-8'))
|
||||
->errorCorrectionLevel(new ErrorCorrectionLevelHigh())
|
||||
->size(200)
|
||||
->margin(0)
|
||||
->roundBlockSizeMode(new RoundBlockSizeModeMargin())
|
||||
->build();
|
||||
|
||||
return $this->render('user/2fa.html.twig', [
|
||||
'tab' => '2fa',
|
||||
'user' => $profile,
|
||||
'form' => $form->createView(),
|
||||
'deactivate' => $this->getTwoFactorDeactivationForm($profile)->createView(),
|
||||
'qr_code' => $result,
|
||||
]);
|
||||
}
|
||||
|
||||
private function getTwoFactorDeactivationForm(User $user): FormInterface
|
||||
{
|
||||
return $this->createFormBuilder(
|
||||
[],
|
||||
[
|
||||
'action' => $this->generateUrl('user_profile_2fa_deactivate', ['username' => $user->getUserIdentifier()]),
|
||||
'method' => 'POST'
|
||||
]
|
||||
)->getForm();
|
||||
return $this->createFormBuilder([], [
|
||||
'action' => $this->generateUrl('user_profile_2fa_deactivate', ['username' => $user->getUserIdentifier()]),
|
||||
'method' => 'POST'
|
||||
])->getForm();
|
||||
}
|
||||
|
||||
#[Route(path: '/{username}/2fa_deactivate', name: 'user_profile_2fa_deactivate', methods: ['POST'])]
|
||||
@@ -405,28 +416,4 @@ final class ProfileController extends AbstractController
|
||||
|
||||
return $this->redirectToRoute('user_profile_2fa', ['username' => $profile->getUserIdentifier()]);
|
||||
}
|
||||
|
||||
#[Route(path: '/{username}/totp-qr-code', name: 'user_profile_2fa_image', methods: ['GET'])]
|
||||
#[IsGranted('2fa', 'profile')]
|
||||
public function displayTotpQrCode(User $profile, TotpAuthenticatorInterface $totpAuthenticator): Response
|
||||
{
|
||||
if (!$profile->hasTotpSecret()) {
|
||||
throw $this->createNotFoundException('User has no TOTP secret.');
|
||||
}
|
||||
|
||||
$qrCodeContent = $totpAuthenticator->getQRContent($profile);
|
||||
|
||||
$result = Builder::create()
|
||||
->writer(new PngWriter())
|
||||
->writerOptions([])
|
||||
->data($qrCodeContent)
|
||||
->encoding(new Encoding('UTF-8'))
|
||||
->errorCorrectionLevel(new ErrorCorrectionLevelHigh())
|
||||
->size(200)
|
||||
->margin(0)
|
||||
->roundBlockSizeMode(new RoundBlockSizeModeMargin())
|
||||
->build();
|
||||
|
||||
return new Response($result->getString(), 200, ['Content-Type' => 'image/png']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,11 +25,6 @@ final class TwoFactorCondition implements TwoFactorConditionInterface
|
||||
/** @var User $user */
|
||||
$user = $context->getUser();
|
||||
|
||||
// only internal users support 2FA currently
|
||||
if (!$user->isInternalUser()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// never require 2FA on API calls
|
||||
if (str_starts_with($context->getRequest()->getRequestUri(), '/api/')) {
|
||||
return false;
|
||||
|
||||
@@ -83,9 +83,8 @@ final class UserVoter extends Voter
|
||||
}
|
||||
|
||||
if ($attribute === '2fa') {
|
||||
// two factor only works for internal users and
|
||||
// can only be activated by the logged-in user for himself
|
||||
return $subject->isInternalUser() && $subject->getId() === $user->getId();
|
||||
// can only be activated by the logged-in user for himself or by a super-admin
|
||||
return $subject->getId() === $user->getId() || $user->isSuperAdmin();
|
||||
}
|
||||
|
||||
$permission = $attribute;
|
||||
|
||||
Reference in New Issue
Block a user