class GALoginHotpValidation in Google Authenticator login 8
HOTP validation class for performing HOTP validation.
Plugin annotation
@TfaValidation(
id = "ga_login_hotp",
label = @Translation("GA Login Hmac-based OTP(HOTP)"),
description = @Translation("GA Login Hotp Validation Plugin"),
setupPluginId = "ga_login_hotp_setup",
)
Hierarchy
- class \Drupal\Component\Plugin\PluginBase implements DerivativeInspectionInterface, PluginInspectionInterface
- class \Drupal\tfa\Plugin\TfaBasePlugin uses DependencySerializationTrait, TfaDataTrait
- class \Drupal\ga_login\Plugin\TfaValidation\GALoginHotpValidation implements ContainerFactoryPluginInterface, TfaValidationInterface uses StringTranslationTrait
- class \Drupal\tfa\Plugin\TfaBasePlugin uses DependencySerializationTrait, TfaDataTrait
Expanded class hierarchy of GALoginHotpValidation
1 file declares its use of GALoginHotpValidation
- GALoginHotpSetup.php in src/
Plugin/ TfaSetup/ GALoginHotpSetup.php
File
- src/
Plugin/ TfaValidation/ GALoginHotpValidation.php, line 31
Namespace
Drupal\ga_login\Plugin\TfaValidationView source
class GALoginHotpValidation extends TfaBasePlugin implements TfaValidationInterface, ContainerFactoryPluginInterface {
use StringTranslationTrait;
/**
* Object containing the external validation library.
*
* @var object
*/
public $auth;
/**
* The counter window in which the validation should be done.
*
* @var int
*/
protected $counterWindow;
/**
* Whether or not the prefix should use the site name.
*
* @var bool
*/
protected $siteNamePrefix;
/**
* Name prefix.
*
* @var string
*/
protected $namePrefix;
/**
* Configurable name of the issuer.
*
* @var string
*/
protected $issuer;
/**
* Whether the code has already been used or not.
*
* @var bool
*/
protected $alreadyAccepted;
/**
* The Datetime service.
*
* @var \Drupal\Component\Datetime\TimeInterface
*/
protected $time;
/**
* {@inheritdoc}
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, UserDataInterface $user_data, EncryptionProfileManagerInterface $encryption_profile_manager, EncryptServiceInterface $encrypt_service, ConfigFactoryInterface $config_factory, TimeInterface $time) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $user_data, $encryption_profile_manager, $encrypt_service);
$this->auth = new \StdClass();
$this->auth->otp = new Otp();
$this->auth->ga = new GoogleAuthenticator();
$plugin_settings = $config_factory
->get('tfa.settings')
->get('validation_plugin_settings');
$settings = isset($plugin_settings['ga_login_hotp']) ? $plugin_settings['ga_login_hotp'] : [];
$settings = array_replace([
'counter_window' => 10,
'site_name_prefix' => TRUE,
'name_prefix' => 'TFA',
'issuer' => 'Drupal',
], $settings);
$this->counterWindow = $settings['counter_window'];
$this->siteNamePrefix = $settings['site_name_prefix'];
$this->namePrefix = $settings['name_prefix'];
$this->issuer = $settings['issuer'];
$this->alreadyAccepted = FALSE;
$this->time = $time;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static($configuration, $plugin_id, $plugin_definition, $container
->get('user.data'), $container
->get('encrypt.encryption_profile.manager'), $container
->get('encryption'), $container
->get('config.factory'), $container
->get('datetime.time'));
}
/**
* {@inheritdoc}
*/
public function ready() {
return $this
->getSeed() !== FALSE;
}
/**
* {@inheritdoc}
*/
public function getForm(array $form, FormStateInterface $form_state) {
$message = $this
->t('Verification code is application generated and @length digits long.', [
'@length' => $this->codeLength,
]);
if ($this
->getUserData('tfa', 'tfa_recovery_code', $this->uid, $this->userData)) {
$message .= '<br/>' . $this
->t("Can't access your account? Use one of your recovery codes.");
}
$form['code'] = [
'#type' => 'textfield',
'#title' => $this
->t('Application verification code'),
'#description' => $message,
'#required' => TRUE,
'#attributes' => [
'autocomplete' => 'off',
],
];
$form['actions']['#type'] = 'actions';
$form['actions']['login'] = [
'#type' => 'submit',
'#button_type' => 'primary',
'#value' => $this
->t('Verify'),
];
return $form;
}
/**
* The configuration form for this validation plugin.
*
* @param \Drupal\Core\Config\Config $config
* Config object for tfa settings.
* @param array $state
* Form state array determines if this form should be shown.
*
* @return array
* Form array specific for this validation plugin.
*/
public function buildConfigurationForm(Config $config, array $state = []) {
$settings_form['counter_window'] = [
'#type' => 'textfield',
'#title' => $this
->t('Counter Window'),
'#default_value' => $this->counterWindow ?: 5,
'#description' => $this
->t('How far ahead from current counter should we check the code.'),
'#size' => 2,
'#states' => $state,
'#required' => TRUE,
];
$settings_form['site_name_prefix'] = [
'#type' => 'checkbox',
'#title' => $this
->t('Use site name as OTP QR code name prefix.'),
'#default_value' => $this->siteNamePrefix,
'#description' => $this
->t('If checked, the site name will be used instead of a static string. This can be useful for multi-site installations.'),
'#states' => $state,
];
// Hide custom name prefix when site name prefix is selected.
$state['visible'] += [
':input[name="validation_plugin_settings[ga_login_hotp][site_name_prefix]"]' => [
'checked' => FALSE,
],
];
$settings_form['name_prefix'] = [
'#type' => 'textfield',
'#title' => $this
->t('OTP QR Code Prefix'),
'#default_value' => $this->namePrefix ?: 'tfa',
'#description' => $this
->t('Prefix for OTP QR code names. Suffix is account username.'),
'#size' => 15,
'#states' => $state,
];
$settings_form['issuer'] = [
'#type' => 'textfield',
'#title' => $this
->t('Issuer'),
'#default_value' => $this->issuer,
'#description' => $this
->t('The provider or service this account is associated with.'),
'#size' => 15,
'#required' => TRUE,
];
return $settings_form;
}
/**
* {@inheritdoc}
*/
public function validateForm(array $form, FormStateInterface $form_state) {
$values = $form_state
->getValues();
if (!$this
->validate($values['code'])) {
$this->errorMessages['code'] = $this
->t('Invalid application code. Please try again.');
if ($this->alreadyAccepted) {
$form_state
->clearErrors();
$this->errorMessages['code'] = $this
->t('Invalid code, it was recently used for a login. Please try a new code.');
}
return FALSE;
}
else {
// Store accepted code to prevent replay attacks.
$this
->storeAcceptedCode($values['code']);
return TRUE;
}
}
/**
* Simple validate for web services.
*
* @param int $code
* OTP Code.
*
* @return bool
* True if validation was successful otherwise false.
*/
public function validateRequest($code) {
if ($this
->validate($code)) {
$this
->storeAcceptedCode($code);
return TRUE;
}
return FALSE;
}
/**
* {@inheritdoc}
*/
protected function validate($code) {
// Strip whitespace.
$code = preg_replace('/\\s+/', '', $code);
if ($this
->alreadyAcceptedCode($code)) {
$this->isValid = FALSE;
}
else {
// Get OTP seed.
$seed = $this
->getSeed();
$counter = $this
->getHotpCounter();
$this->isValid = $seed && ($counter = $this->auth->otp
->checkHotpResync(Encoding::base32DecodeUpper($seed), $counter, $code, $this->counterWindow));
$this
->setUserData('tfa', [
'tfa_hotp_counter' => ++$counter,
], $this->uid, $this->userData);
}
return $this->isValid;
}
/**
* Returns whether code has already been used or not.
*
* @return bool
* True is code already used otherwise false.
*/
public function isAlreadyAccepted() {
return $this->alreadyAccepted;
}
/**
* Get seed for this account.
*
* @return string
* Decrypted account OTP seed or FALSE if none exists.
*/
protected function getSeed() {
// Lookup seed for account and decrypt.
$result = $this
->getUserData('tfa', 'tfa_hotp_seed', $this->uid, $this->userData);
if (!empty($result)) {
$encrypted = base64_decode($result['seed']);
$seed = $this
->decrypt($encrypted);
if (!empty($seed)) {
return $seed;
}
}
return FALSE;
}
/**
* Save seed for account.
*
* @param string $seed
* Un-encrypted seed.
*/
public function storeSeed($seed) {
// Encrypt seed for storage.
$encrypted = $this
->encrypt($seed);
$record = [
'tfa_hotp_seed' => [
'seed' => base64_encode($encrypted),
'created' => $this->time
->getRequestTime(),
],
];
$this
->setUserData('tfa', $record, $this->uid, $this->userData);
}
/**
* Delete the seed of the current validated user.
*/
protected function deleteSeed() {
$this
->deleteUserData('tfa', 'tfa_hotp_seed', $this->uid, $this->userData);
}
/**
* Get the HOTP counter.
*
* @return int
* The current value of the HOTP counter, or 1 if no value was found.
*/
public function getHotpCounter() {
return $this
->getUserData('tfa', 'tfa_hotp_counter', $this->uid, $this->userData) ?: 1;
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
DependencySerializationTrait:: |
protected | property | An array of entity type IDs keyed by the property name of their storages. | |
DependencySerializationTrait:: |
protected | property | An array of service IDs keyed by property name used for serialization. | |
DependencySerializationTrait:: |
public | function | 1 | |
DependencySerializationTrait:: |
public | function | 2 | |
GALoginHotpValidation:: |
protected | property |
Whether the code has already been used or not. Overrides TfaBasePlugin:: |
|
GALoginHotpValidation:: |
public | property | Object containing the external validation library. | |
GALoginHotpValidation:: |
protected | property | The counter window in which the validation should be done. | |
GALoginHotpValidation:: |
protected | property | Configurable name of the issuer. | |
GALoginHotpValidation:: |
protected | property | Name prefix. | |
GALoginHotpValidation:: |
protected | property | Whether or not the prefix should use the site name. | |
GALoginHotpValidation:: |
protected | property | The Datetime service. | |
GALoginHotpValidation:: |
public | function | The configuration form for this validation plugin. | |
GALoginHotpValidation:: |
public static | function |
Creates an instance of the plugin. Overrides ContainerFactoryPluginInterface:: |
|
GALoginHotpValidation:: |
protected | function | Delete the seed of the current validated user. | |
GALoginHotpValidation:: |
public | function |
Get TFA process form from plugin. Overrides TfaValidationInterface:: |
|
GALoginHotpValidation:: |
public | function | Get the HOTP counter. | |
GALoginHotpValidation:: |
protected | function | Get seed for this account. | |
GALoginHotpValidation:: |
public | function | Returns whether code has already been used or not. | |
GALoginHotpValidation:: |
public | function |
Determine if the plugin can run for the current TFA context. Overrides TfaBasePlugin:: |
|
GALoginHotpValidation:: |
public | function | Save seed for account. | |
GALoginHotpValidation:: |
protected | function |
Validate code. Overrides TfaBasePlugin:: |
1 |
GALoginHotpValidation:: |
public | function |
Validate form. Overrides TfaValidationInterface:: |
|
GALoginHotpValidation:: |
public | function | Simple validate for web services. | |
GALoginHotpValidation:: |
public | function |
Constructs a new Tfa plugin object. Overrides TfaBasePlugin:: |
1 |
PluginBase:: |
protected | property | Configuration information passed into the plugin. | 1 |
PluginBase:: |
protected | property | The plugin implementation definition. | 1 |
PluginBase:: |
protected | property | The plugin_id. | |
PluginBase:: |
constant | A string which is used to separate base plugin IDs from the derivative ID. | ||
PluginBase:: |
public | function |
Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface:: |
|
PluginBase:: |
public | function |
Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface:: |
|
PluginBase:: |
public | function |
Gets the definition of the plugin implementation. Overrides PluginInspectionInterface:: |
3 |
PluginBase:: |
public | function |
Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface:: |
|
PluginBase:: |
public | function | Determines if the plugin is configurable. | |
StringTranslationTrait:: |
protected | property | The string translation service. | 1 |
StringTranslationTrait:: |
protected | function | Formats a string containing a count of items. | |
StringTranslationTrait:: |
protected | function | Returns the number of plurals supported by a given language. | |
StringTranslationTrait:: |
protected | function | Gets the string translation service. | |
StringTranslationTrait:: |
public | function | Sets the string translation service to use. | 2 |
StringTranslationTrait:: |
protected | function | Translates a string to the current language or to a given language. | |
TfaBasePlugin:: |
protected | property | The user submitted code to be validated. | |
TfaBasePlugin:: |
protected | property | The allowed code length. | |
TfaBasePlugin:: |
protected | property | Encryption profile. | |
TfaBasePlugin:: |
protected | property | Encryption service. | |
TfaBasePlugin:: |
protected | property | The error for the current validation. | |
TfaBasePlugin:: |
protected | property | Whether the validation succeeded or not. | |
TfaBasePlugin:: |
protected | property | The user id. | |
TfaBasePlugin:: |
protected | property | Provides the user data service object. | |
TfaBasePlugin:: |
protected | function | Whether code has already been used. | |
TfaBasePlugin:: |
protected | function | Decrypt a encrypted string. | |
TfaBasePlugin:: |
protected | function | Encrypt a plaintext string. | |
TfaBasePlugin:: |
public | function | Get error messages suitable for form_set_error(). | |
TfaBasePlugin:: |
public | function | Get the plugin label. | |
TfaBasePlugin:: |
protected | function | Store validated code to prevent replay attack. | |
TfaBasePlugin:: |
public | function | Submit form. | 1 |
TfaDataTrait:: |
protected | function | Deletes data stored for the current validated user account. | |
TfaDataTrait:: |
protected | function | Returns data stored for the current validated user account. | |
TfaDataTrait:: |
protected | function | Store user specific information. | |
TfaDataTrait:: |
protected | function | Get TFA data for an account. | |
TfaDataTrait:: |
public | function | Save TFA data for an account. |