Skip to content
This repository has been archived by the owner on Dec 2, 2021. It is now read-only.

Commit

Permalink
Implement authentication form
Browse files Browse the repository at this point in the history
  • Loading branch information
scheb committed Mar 5, 2018
1 parent 201dddf commit 2101590
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 53 deletions.
47 changes: 0 additions & 47 deletions Controller/AuthenticationController.php

This file was deleted.

104 changes: 104 additions & 0 deletions Controller/FormController.php
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;
}
}
6 changes: 6 additions & 0 deletions Resources/config/two_factor.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,11 @@
<service id="scheb_two_factor.firewall_context" class="Scheb\TwoFactorBundle\Security\TwoFactor\TwoFactorFirewallContext" public="true">
<argument type="collection" /> <!-- Firewall configs -->
</service>

<service id="scheb_two_factor.form_controller" class="Scheb\TwoFactorBundle\Controller\FormController" public="true">
<argument type="service" id="security.token_storage" />
<argument type="service" id="scheb_two_factor.provider_registry" />
<argument type="service" id="scheb_two_factor.firewall_context" />
</service>
</services>
</container>
2 changes: 1 addition & 1 deletion Resources/doc/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ authentication code.
2fa_login:
path: /2fa
defaults:
_controller: "SchebTwoFactorBundle:Authentication:form"
_controller: "scheb_two_factor.form_controller:form"

2fa_login_check:
path: /2fa_check
Expand Down
1 change: 1 addition & 0 deletions Resources/translations/messages.de.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
scheb_two_factor:
auth_code: Bestätigungs-Code
choose_provider: Authentifizierungs-Methode wechseln
login: Login
code_invalid: Der Bestätigungs-Code ist nicht korrekt.
trusted: Dies ist ein vertrauenswürdiger Computer
Expand Down
1 change: 1 addition & 0 deletions Resources/translations/messages.en.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
scheb_two_factor:
auth_code: Authentication Code
choose_provider: Switch authentication method
login: Login
code_invalid: The verification code is not valid.
trusted: I'm on a trusted computer
Expand Down
24 changes: 19 additions & 5 deletions Resources/views/Authentication/form.html.twig
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>

0 comments on commit 2101590

Please sign in to comment.