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:
Kevin Papst
2023-05-01 08:28:35 +02:00
committed by GitHub
parent 01e26dca9e
commit 7112e932a2
6 changed files with 51 additions and 77 deletions

View File

@@ -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']);
}
}

View File

@@ -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;

View File

@@ -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;