
Partager:
Douglas is a full stack software engineer with a keen interest to marketing, customer growth and data analytics. When he’s not coding, he’s probably watching way too many TV shows.
Ajouter l'authentification à 2 facteurs à WordPress avec Nexmo Verify API
Temps de lecture : 9 minutes
Introduction
Avec l'augmentation des failles de sécurité, la protection de votre site web et de ses utilisateurs n'a jamais été aussi importante qu'aujourd'hui. Dans ce tutoriel, vous allez configurer 2FA (authentification à deux facteurs) sur WordPress en utilisant l'API Verify de Nexmo. Avec cette configuration, chaque fois qu'un utilisateur essaie de se connecter, il recevra un SMS ou un appel sur le numéro de téléphone mobile enregistré dans son profil avec un code unique, et en entrant le code valide, il sera connecté.
A la fin de ce tutoriel, vous aurez appris les bases de la construction d'un plugin WordPress et aurez une bonne compréhension de l'intégration de l'API Nexmo avec WordPress en utilisant la bibliothèque PHP Nexmo. Alors, commençons !
À propos de l'API Verify de Nexmo
L'API Verify est la solution plug and play de Nexmo pour l'authentification à deux facteurs sur n'importe quel système. Le processus est simple ; vous appelez l'API Envoyer la vérification en transmettant un numéro de mobile, Nexmo enverra au numéro de mobile un code unique par SMS/appel et renverra un ID de demande. Avec le code de l'utilisateur, vous appelez le point de terminaison Vérifier la vérification avec l'ID de la demande pour vérifier le code, et Nexmo renvoie un statut selon que le code est valide ou non. C'est assez simple, non ?
J'apprécie particulièrement Nexmo Verify en raison de ce que l'on appelle les flux de travail. Avec les flux de travail, vous pouvez configurer plusieurs options de repli au cas où un utilisateur ne reçoit pas le code par SMS à temps. Vous pouvez configurer une option de repli pour un appel vocal après une certaine durée et bien plus encore.Vous pouvez lire à propos des workflows ici.
Ce dont vous avez besoin pour commencer :
Auto-hébergé WordPress site web
Vonage API Account
To complete this tutorial, you will need a Vonage API account. If you don’t have one already, you can sign up today and start building with free credit. Once you have an account, you can find your API Key and API Secret at the top of the Vonage API Dashboard.
Création de votre plugin WordPress
Bien que vous puissiez créer un plugin WordPress en ajoutant simplement un nouveau dossier dans le dossier WordPress plugins, une méthode vraiment efficace consiste à utiliser un boilerplate léger pour commencer. Les boilerplates sont utiles pour configurer tous les fichiers et les classes de manière standard. Dans ce tutoriel, vous utiliserez le modèle wppb Il vous suffit de remplir les détails sur le site web et de cliquer sur le bouton "build plugin" pour télécharger le boilerplate de votre plugin.
Wordpress Plugin Boilerplate Generator
Une fois que vous l'avez, extrayez le fichier zip et placez-le dans votre dossier de plugins WordPress. Ensuite, allez dans votre administration WordPress, naviguez jusqu'à la page des plugins installés et activez votre plugin.
Plugins
Histoires d'utilisateurs
Notre objectif étant de mettre en place 2FA sur WordPress, nous allons décomposer l'idée en histoires d'utilisateurs/étapes actionnables et les mettre en œuvre de haut en bas :
Dans les paramètres du profil de l'utilisateur WordPress, vous aurez besoin de champs personnalisés pour le numéro de téléphone mobile 2FA de l'utilisateur et pour indiquer s'il est activé pour le 2FA.
Vous enverrez un code au numéro de téléphone portable de l'utilisateur lorsqu'il se connectera.
Vous disposerez d'un formulaire permettant à l'utilisateur de saisir le code qu'il a reçu et de le vérifier
Comprendre les actions et les filtres de WordPress
La plupart des modifications que vous ferez sur WordPress consisteront à relier vos fonctions aux actions et aux filtres existants de WordPress ; Les actions sont des fonctions exécutées lorsqu'un certain événement se produit dans WordPress. Par conséquent, si vous voulez que votre fonction s'exécute lorsqu'un événement spécifique se produit, par exemple lorsqu'un utilisateur se connecte, vous accrocherez votre fonction à l'action liée à la connexion. De l'autre côté, filtres modifient certaines fonctions ; vous pouvez utiliser un filtre pour manipuler le résultat d'une fonction.
Vous accrochez votre fonction à une action existante comme ceci :
add_action( 'action_name', 'name_of_your_function' );
Vous reliez votre fonction à un filtre de la manière suivante :
add_filter( 'filter_name', 'name_of_your_function' );
Champs personnalisés de l'utilisateur
Pour la concision de ce billet, voici le lien vers le code qui ajoute les champs numéro de mobile et case à cocher 2FA enabled aux paramètres du profil utilisateur de WordPress. Avec cette configuration, votre page de paramètres utilisateur ressemblerait à ceci :
Nexmo 2FA
Ajout de la bibliothèque PHP Nexmo à l'ensemble du système
Nexmo vous recommande d'installer leur bibliothèque PHP via Composer ; vous devez avoir installé Composer sur votre serveur/système local. Si vous n'avez pas installé Composer, voici deux guides recommandés par Nexmo pour vous aider : GetComposer.org ou Scotch.io
Une fois Composer installé, ouvrez votre terminal, naviguez jusqu'au dossier racine de votre plugin, et exécutez :
Il créera un nouveau dossier appelé vendor qui contient un certain nombre d'autres bibliothèques, dont la bibliothèque PHP de Numbers. Pour inclure la bibliothèque dans votre plugin, ajoutez simplement cette ligne au fichier PHP racine de votre plugin.
require_once plugin_dir_path( __FILE__ ) . 'vendor/autoload.php';
Initialisation de la classe Nexmo
Avant de pouvoir effectuer un appel avec la bibliothèque PHP de Nexmo, vous devez initialiser la classe Nexmo et utiliser l'objet client pour effectuer vos requêtes ultérieures.
$basic = new \Nexmo\Client\Credentials\Basic(NEXMO_API_KEY, NEXMO_API_SECRET);
$client = new \Nexmo\Client(new \Nexmo\Client\Credentials\Container($basic));Si vous utilisez le modèle de base, vous pouvez effectuer les modifications suivantes dans le fichier fichier public Class dans le dossier /public de votre plugin. Vous initialiserez la bibliothèque Nexmo dans la construction et définirez l'objet client comme une variable protégée afin que les autres méthodes de notre classe publique puissent y accéder.
<?php
class Two_Factor_Auth_Nexmo_Public {
protected $nexmo_client;
public function __construct( $plugin_name, $version ) {
$this->nexmo_client = new Nexmo\Client(new Nexmo\Client\Credentials\Basic(TWO_FACTOR_AUTH_NEXMO_KEY, TWO_FACTOR_AUTH_NEXMO_SECRET));
}
} Envoi de la demande de vérification
Sur la base de notre histoire d'utilisateur, nous voulons intercepter le login de l'utilisateur, vérifier si l'utilisateur est activé pour 2FA, et si c'est le cas, initier un Envoyer une vérification à son numéro de téléphone mobile. Pour ce faire, vous allez accrocher l'action authenticate car c'est l'action déclenchée lorsqu'un utilisateur se connecte avec succès.
<?php
class Two_Factor_Auth_Nexmo_Public {
protected $nexmo_client;
public function __construct( $plugin_name, $version ) {
$this->nexmo_client = new Nexmo\Client(new Nexmo\Client\Credentials\Basic(TWO_FACTOR_AUTH_NEXMO_KEY, TWO_FACTOR_AUTH_NEXMO_SECRET));
add_action( 'authenticate', array( $this, 'intercept_login_with_two_factor_auth' ), 10, 3 );
}
public function intercept_login_with_two_factor_auth( $user, $username, $password ) {
$errors = array();
$redirect_to = isset( $_POST['redirect_to'] ) ? $_POST['redirect_to'] : admin_url();
$remember_me = ( isset( $_POST['rememberme'] ) && $_POST['rememberme'] === 'forever' ) ? true : false;
$_user = get_user_by( 'login', $username );
if ( $_user ) {
$this->verify_user( $_user, $redirect_to, $remember_me );
}
return $user;
}En insérant notre fonction dans l'action authenticate nous permet de travailler avec trois variables : $user, $username, et $password, la variable $user est généralement nulle, mais ce n'est pas grave. Ce dont vous avez besoin, c'est de la variable $usernameAvec cela, vous pouvez appeler la fonction WordPress pour obtenir l'objet utilisateur. Vous avez besoin de l'objet utilisateur pour obtenir d'autres propriétés de l'utilisateur, comme son numéro de téléphone portable et s'il est autorisé à utiliser le 2FA.
$_user = get_user_by( 'login', $username );// Function to get the user objectPour obtenir la valeur des champs personnalisés d'un utilisateur, vous utilisez la fonction WordPress get_user_metaen indiquant l'identifiant de l'utilisateur et le nom du champ personnalisé. Comme défini dans le code des paramètres du profil de l'utilisateur, les noms des champs sont two_factor_auth_nexmo_enabled et two_factor_auth_nexmo_mobile.
private function verify_user( $user, $redirect_to, $remember_me, $errors = array() ) {
$enabled_2fa = get_user_meta($user->ID, 'two_factor_auth_nexmo_enabled', true );
$mobile = get_user_meta($user->ID, 'two_factor_auth_nexmo_mobile', true );
if ( ! $mobile || ! $enabled_2fa) {
return;
}
try {
$verification = new \Nexmo\Verify\Verification($mobile, TWO_FACTOR_AUTH_NEXMO_SENDER_NAME);
$this->nexmo_client->verify()->start($verification);
}
catch(Exception $e) {
$errors = array( "Error sending verification request" );
}
$request_id = $verification->getRequestId();
update_user_meta( $user->ID, 'two_factor_auth_nexmo_request_id', $request_id);
wp_logout();
}Si toutes les variables requises sont définies (numéro de mobile et 2FA activée pour l'utilisateur), vous appelez la fonction pour lancer un Envoyer une vérification Nexmo envoie le code unique à l'utilisateur et renvoie un ID de demande. Il est important de stocker l'ID de la demande afin de pouvoir l'utiliser pour appeler la fonction Valider le code à l'étape suivante. Une façon simple de le faire est d'utiliser la fonction WordPress update_user_meta avec l'identifiant clé de la variable (dans notre cas two_factor_auth_nexmo_request_id) et la variable $request_id.
Enfin, appelez la fonction logout . Vous vous demandez peut-être pourquoi vous faites cela ? Parce que, comme indiqué initialement, l'action d'authentification est déclenchée lorsque l'utilisateur s'est connecté avec succès. En réalité, tout ce code s'exécute lorsque l'utilisateur est connecté, mais ce n'est pas ce que vous voulez, du moins pas encore. Vous voulez que l'utilisateur ne soit connecté qu'après avoir validé le code. Par conséquent, déconnectez l'utilisateur après avoir envoyé le code, ce qui nous amène à notre dernière étape, la validation du code et la connexion de l'utilisateur.
Validation du code
Vous avez envoyé le code à l'utilisateur dans la section ci-dessus, il ne reste plus qu'à lui montrer un formulaire pour qu'il saisisse le code qu'il a reçu et à le valider par rapport à son profil pour qu'il se connecte.
En vous appuyant sur la fonction verify_user que vous avez créée précédemment, vous allez ajouter le formulaire de validation du code.
private function verify_user( $user, $redirect_to, $remember_me, $errors = array() ) {
$enabled_2fa = get_user_meta($user->ID, 'two_factor_auth_nexmo_enabled', true );
$mobile = get_user_meta($user->ID, 'two_factor_auth_nexmo_mobile', true );
if ( ! $mobile || ! $enabled_2fa) {
return;
}
try {
$verification = new \Nexmo\Verify\Verification($mobile, TWO_FACTOR_AUTH_NEXMO_SENDER_NAME);
$this->nexmo_client->verify()->start($verification);
}
catch(Exception $e) {
$errors = array( "Error sending verification request" );
}
$request_id = $verification->getRequestId();
update_user_meta( $user->ID, 'two_factor_auth_nexmo_request_id', $request_id);
wp_logout();
nocache_headers();
header('Content-Type: ' . get_bloginfo( 'html_type' ) . '; charset=' . get_bloginfo( 'charset' ) );
login_header('Nexmo Two-Factor Authentication', '<p class="message">' . sprintf( 'Enter the PIN code sent to your mobile number ending in <strong>%1$s</strong>' , substr($mobile, -5) ) . '</p>');
if(!empty($errors)) {
?>
<div id="login_error"><?php echo implode( '<br />', $errors ) ?></div>
<?php } ?>
<form name="loginform" id="loginform" action="<?php echo esc_url( site_url( 'wp-login.php', 'login_post' ) ) ?>" method="post" autocomplete="off">
<p>
<label for="two_factor_auth_nexmo_pin_code">Code
<br />
<input type="number" name="two_factor_auth_nexmo_pin_code" id="two_factor_auth_nexmo_pin_code" class="input" value="" size="6" />
</label>
</p>
<p class="submit">
<input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large" value="Verify" />
<input type="hidden" name="log" value="<?php echo esc_attr( $user->user_login ) ?>" />
<input type="hidden" name="two_factor_auth_nexmo_request_id" value="<?php echo esc_attr( $request_id ) ?>" />
<input type="hidden" name="redirect_to" value="<?php echo esc_attr( $redirect_to ) ?>" />
<?php if ( $remember_me ) : ?>
<input type="hidden" name="rememberme" value="forever" />
<?php endif; ?>
</p>
</form>
<?php
login_footer( 'two_factor_auth_nexmo_pin_code' );
exit;
}NB: J'ai placé mon HTML dans la méthode Class ici, mais vous pouvez toujours placer le vôtre dans un fichier séparé et l'inclure.
Avec le code ci-dessus, vous devriez avoir une page qui ressemble à ceci lorsque vous essayez de vous connecter à un compte activé pour 2FA.
Wordpress Pin
La fonction login_header ajoute une petite section au-dessus du formulaire qui affiche les 5 derniers chiffres du numéro de téléphone mobile de l'utilisateur.
Le formulaire <form> dans cette vue est une réplique du formulaire de connexion de WordPress avec juste quelques changements. Si vous inspectez votre formulaire de connexion WordPress via votre navigateur, vous remarquerez que le champ de saisie du nom d'utilisateur a un attribut de nom appelé "<strong>log</strong>". Conservez cet attribut car c'est ainsi que WordPress obtient la variable nom d'utilisateur ; cependant, dans ce cas, vous transmettrez le nom d'utilisateur à partir de votre objet utilisateur. Pour conserver l'expérience des redirections et de la préférence remember me de la session de connexion initiale, conservez ces variables dans leurs noms de champs de saisie respectifs, mais cette fois-ci, elles seront cachées. Enfin, transmettez l'ID de la demande d'envoi de la vérification dans un champ de saisie caché, ainsi que la valeur du code saisi par l'utilisateur - tous ces éléments seront utilisés pour valider le code.
Les paramètres du formulaire sont les suivants
log: Nom d'utilisateur de l'utilisateurtwo_factor_auth_nexmo_pin_code: Code saisi par l'utilisateurtwo_factor_auth_nexmo_request_id: ID de la demande initialerememberme: Statut "Remember me" (se souvenir de moi) à partir de la connexion initialeredirect_to: Redirection vers l'URL si l'utilisateur a essayé d'accéder à une page particulière avant le formulaire de connexion.
Remarque importante : L'URL d'action du formulaire est toujours l'URL de connexion de WordPress.
<?php echo esc_url( site_url( 'wp-login.php', 'login_post' ) ) ?>Verify, Ce qui est intéressant, c'est que notre fonction d'interception est liée à l'action d'authentification, lorsque vous cliquez sur le bouton de vérification du formulaire de vérification du code, votre fonction d'interception s'exécute toujours, et c'est là que vous ajoutez l'extrait de code pour valider le code que l'utilisateur a saisi.
public function intercept_login_with_two_factor_auth( $user, $username, $password ) {
$errors = array();
$redirect_to = isset( $_POST['redirect_to'] ) ? $_POST['redirect_to'] : admin_url();
$remember_me = ( isset( $_POST['rememberme'] ) && $_POST['rememberme'] === 'forever' ) ? true : false;
$_user = get_user_by( 'login', $username );
// New addition
$saved_request_id = ($_user) ? get_user_meta($_user->ID, 'two_factor_auth_nexmo_request_id', true ) : null;
$nexmo_pin_code = isset( $_POST['two_factor_auth_nexmo_pin_code'] ) ? $_POST['two_factor_auth_nexmo_pin_code'] : false;
$nexmo_request_id = isset( $_POST['two_factor_auth_nexmo_request_id'] ) ? $_POST['two_factor_auth_nexmo_request_id'] : false;
if ( $nexmo_request_id && $nexmo_pin_code && $saved_request_id == $nexmo_request_id ) {
$verification = new \Nexmo\Verify\Verification($nexmo_request_id);
try {
$result = $this->nexmo_client->verify()->check($verification, $nexmo_pin_code);
$response = $result->getResponseData();
if ($response['status'] == "0") {
wp_set_auth_cookie( $_user->ID, $remember_me );
wp_safe_redirect( $redirect_to );
exit;
}
}
catch(Exception $e) {
// handle invalid code
if ($e->getCode() == 16){
$errors = array( "Invalid PIN code" );
}
$this->verify_user( $_user, $redirect_to, $remember_me,$errors );
}
}
// End of addition
if ( $_user ) {
$this->verify_user( $_user, $redirect_to, $remember_me );
}
return $user;
}Dans l'ajout ci-dessus, vous vérifiez les données POST de la demande de connexion pour voir si les éléments 'two_factor_auth_nexmo_pin_code' et 'two_factor_auth_nexmo_request_id' sont définies. Si c'est le cas, il s'agit d'une demande de validation d'un code. Pour vous assurer que vous validez le code pour le bon utilisateur, vous comparez également l'ID de la requête provenant des données POST avec l'ID de la requête enregistrée dans le profil de l'utilisateur ; s'ils correspondent, vous appelez la fonction Vérifier la vérification pour vérifier que le code saisi est correct. S'il est correct, vous définissez le cookie d'authentification WordPress pour l'utilisateur et vous le redirigez vers le tableau de bord.
wp_set_auth_cookie( $_user->ID, $remember_me );
wp_safe_redirect( $redirect_to );Si ce n'est pas le cas, il vous suffit d'appeler à nouveau la fonction verify_user et envoyez un nouveau code de vérification.
Voici un lien vers le fichier complet de la classe.
Conclusion
Dans ce tutoriel, vous avez appris les bases de la construction d'un plugin WordPress, de l'intégration de la bibliothèque PHP Nexmo, et de l'utilisation de l'API Verify de Nexmo. J'espère que vous avez trouvé cela très utile ; vous pouvez consulter le code complet sur GitHub via ce lien. Merci pour votre lecture !
