diff --git a/config/packages/scheb_2fa.yaml b/config/packages/scheb_2fa.yaml index 355dd78e..d1de5164 100644 --- a/config/packages/scheb_2fa.yaml +++ b/config/packages/scheb_2fa.yaml @@ -3,12 +3,14 @@ scheb_two_factor: security_tokens: - Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken - Symfony\Component\Security\Http\Authenticator\Token\PostAuthenticationToken + - App\Saml\SamlToken + totp: enabled: true template: security/2fa.html.twig # Overwritten template window: 1 # How many codes before/after the current one would be accepted as valid -# server_name: Server Name # Server name used in QR code issuer: Kimai # Issuer name used in QR code -# parameters: # Additional parameters added in the QR code -# image: 'https://my-service/img/logo.png' + two_factor_condition: App\Security\TwoFactorCondition + + # FIXME add backup codes - https://symfony.com/bundles/SchebTwoFactorBundle/current/backup_codes.html diff --git a/src/Controller/ProfileController.php b/src/Controller/ProfileController.php index f970d66d..a72d061c 100644 --- a/src/Controller/ProfileController.php +++ b/src/Controller/ProfileController.php @@ -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']); - } } diff --git a/src/Security/TwoFactorCondition.php b/src/Security/TwoFactorCondition.php index 20c2443a..c9f6c5a3 100644 --- a/src/Security/TwoFactorCondition.php +++ b/src/Security/TwoFactorCondition.php @@ -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; diff --git a/src/Voter/UserVoter.php b/src/Voter/UserVoter.php index ba311920..46c46a12 100644 --- a/src/Voter/UserVoter.php +++ b/src/Voter/UserVoter.php @@ -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; diff --git a/templates/user/2fa.html.twig b/templates/user/2fa.html.twig index c4158e71..ddec3f0a 100644 --- a/templates/user/2fa.html.twig +++ b/templates/user/2fa.html.twig @@ -8,7 +8,7 @@ {{ 'profile.2fa_intro'|trans }}
-
+