This repository has been archived by the owner on Dec 2, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 111
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
132 additions
and
53 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
<?php | ||
|
||
namespace Scheb\TwoFactorBundle\Controller; | ||
|
||
use Scheb\TwoFactorBundle\Security\Authentication\Token\TwoFactorToken; | ||
use Scheb\TwoFactorBundle\Security\TwoFactor\Provider\Exception\UnknownTwoFactorProviderException; | ||
use Scheb\TwoFactorBundle\Security\TwoFactor\Provider\TwoFactorProviderRegistry; | ||
use Scheb\TwoFactorBundle\Security\TwoFactor\TwoFactorFirewallContext; | ||
use Symfony\Component\HttpFoundation\Request; | ||
use Symfony\Component\HttpFoundation\Response; | ||
use Symfony\Component\HttpFoundation\Session\SessionInterface; | ||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; | ||
use Symfony\Component\Security\Core\Exception\AccessDeniedException; | ||
use Symfony\Component\Security\Core\Exception\AuthenticationException; | ||
use Symfony\Component\Security\Core\Security; | ||
|
||
class FormController | ||
{ | ||
/** | ||
* @var TokenStorageInterface | ||
*/ | ||
private $tokenStorage; | ||
|
||
/** | ||
* @var TwoFactorProviderRegistry | ||
*/ | ||
private $providerRegistry; | ||
|
||
/** | ||
* @var TwoFactorFirewallContext | ||
*/ | ||
private $twoFactorFirewallContext; | ||
|
||
public function __construct( | ||
TokenStorageInterface $tokenStorage, | ||
TwoFactorProviderRegistry $providerRegistry, | ||
TwoFactorFirewallContext $twoFactorFirewallContext | ||
) { | ||
$this->tokenStorage = $tokenStorage; | ||
$this->providerRegistry = $providerRegistry; | ||
$this->twoFactorFirewallContext = $twoFactorFirewallContext; | ||
} | ||
|
||
public function form(Request $request): Response | ||
{ | ||
$token = $this->getTwoFactorToken(); | ||
$this->setPreferredProvider($request, $token); | ||
|
||
$providerName = $token->getCurrentTwoFactorProvider(); | ||
$renderer = $this->providerRegistry->getProvider($providerName)->getFormRenderer(); | ||
$templateVars = $this->getTemplateVars($request, $token); | ||
|
||
return $renderer->renderForm($request, $templateVars); | ||
} | ||
|
||
protected function getTwoFactorToken(): TwoFactorToken | ||
{ | ||
$token = $this->tokenStorage->getToken(); | ||
if (!($token instanceof TwoFactorToken)) { | ||
throw new AccessDeniedException('User is not in a two-factor authentication process.'); | ||
} | ||
|
||
return $token; | ||
} | ||
|
||
protected function setPreferredProvider(Request $request, TwoFactorToken $token): void | ||
{ | ||
$preferredProvider = $request->get('preferProvider'); | ||
if ($preferredProvider) { | ||
try { | ||
$token->preferTwoFactorProvider($preferredProvider); | ||
} catch (UnknownTwoFactorProviderException $e) { | ||
} | ||
} | ||
} | ||
|
||
protected function getTemplateVars(Request $request, TwoFactorToken $token): array | ||
{ | ||
$config = $this->twoFactorFirewallContext->getFirewallConfig($token->getProviderKey()); | ||
$pendingTwoFactorProviders = $token->getTwoFactorProviders(); | ||
$displayTrustedOption = !$config->isMultiFactor() || 1 === count($pendingTwoFactorProviders); | ||
|
||
return [ | ||
'twoFactorProvider' => $token->getCurrentTwoFactorProvider(), | ||
'availableTwoFactorProviders' => $pendingTwoFactorProviders, | ||
'authError' => $this->getLastAuthenticationError($request->getSession()), | ||
'displayTrustedOption' => $displayTrustedOption, | ||
'authCodeParameterName' => $config->getAuthCodeParameterName(), | ||
'trustedParameterName' => $config->getTrustedParameterName(), | ||
]; | ||
} | ||
|
||
protected function getLastAuthenticationError(SessionInterface $session): ?string | ||
{ | ||
$authException = $session->get(Security::AUTHENTICATION_ERROR); | ||
if (!($authException instanceof AuthenticationException)) { | ||
return null; // The value does not come from the security component. | ||
} | ||
|
||
$session->remove(Security::AUTHENTICATION_ERROR); | ||
|
||
return $authException->getMessage() ?? null; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,27 @@ | ||
{# This is a demo template for the authentication form. Please consider overwriting this with your own implementation #} | ||
|
||
{# Authentication errors #} | ||
{% if authError %} | ||
<p>{{ authError }}</p> | ||
{% endif %} | ||
|
||
{# Let the user select the authentication method #} | ||
<p>{{ "scheb_two_factor.choose_provider"|trans }}: | ||
{% for provider in availableTwoFactorProviders %} | ||
<a href="{{ path("2fa_login", {"preferProvider": provider}) }}">{{ provider }}</a> | ||
{% endfor %} | ||
</p> | ||
|
||
{# Display current two-factor provider #} | ||
<p class="label"><label for="_auth_code">{{ "scheb_two_factor.auth_code"|trans }} {{ twoFactorProvider }}:</label></p> | ||
|
||
<form class="form" action="{{ path("2fa_login_check") }}" method="post"> | ||
<p class="label"><label for="_auth_code">{{ "scheb_two_factor.auth_code"|trans }}</label></p> | ||
<p class="widget"><input id="_auth_code" type="text" autocomplete="off" name="_auth_code" /></p> | ||
{% if useTrustedOption %}<p class="widget"><label for="_trusted"><input id="_trusted" type="checkbox" name="_trusted" /> {{ "scheb_two_factor.trusted"|trans }}</label></p>{% endif %} | ||
<p class="submit"><input type="submit" value="{{ "scheb_two_factor.login"|trans }}" /></p> | ||
<p class="widget"><input id="_auth_code" type="text" autocomplete="off" name="{{ authCodeParameterName }}" /></p> | ||
{% if displayTrustedOption %} | ||
<p class="widget"><label for="_trusted"><input id="_trusted" type="checkbox" name="{{ trustedParameterName }}" /> {{ "scheb_two_factor.trusted"|trans }}</label></p> | ||
{% endif %} | ||
<p class="submit"><input type="submit" value="{{ "scheb_two_factor.login"|trans }}" /></p> | ||
</form> | ||
|
||
{# The logout link gives the user a way out if they can't complete the second step #} | ||
{# The logout link gives the user a way out if they can't complete two-factor authentication #} | ||
<p class="cancel"><a href="{{ path("_security_logout") }}">{{ "scheb_two_factor.cancel"|trans }}</a></p> |