Joomla! 3.2 includes an abundance of new features appealing to end users and developers alike. One of these new features is two factor authentication. In this tutorial you will learn what two factor authentication is and how you can use it in your components to enhance the security of potentially dangerous or important operations, just like most banks do.

Joomla! 3.2 includes an abundance of new features appealing to end users and developers alike. One of these new features is two factor authentication. In this tutorial you will learn what two factor authentication is and how you can use it in your components to enhance the security of potentially dangerous or important operations, just like most banks do.

Introduction to Two Factor Authentication

First, let’s understand two factor authentication. Logging in to a site is commonly performed by entering a username and password, i.e. something you know. This is not very secure as passwords can be forgotten or stolen. In the latter case a malicious agent can impersonate the user in the system and perform potentially catastrophic changes.

Two-factor authentication changes this login procedure by asking not only a username and password (something you know) but also a regularly changing, cryptographically secure secret code (something you have). Its name comes from the fact that the authentication of the user depends on two factors: something you know and something you have.

The secret code can be generated by a variety of means. Joomla! 3.2 supports Google Authenticator and YubiKey out of the box. Google Authenticator is a smartphone application which generates a different six digit code every thirty seconds using a cryptographically sound procedure, using an initial per-user secret code which is provided to the user in the setup of this method (he simply scans a QR code, nothing to be afraid about!). YubiKey, on the other hand, is a secure, inexpensive, hardware token that plugs into a USB port. As soon as the user presses its button it emits a one-time, cryptographically generated code which is then checked against a validation server. This prevents replay attacks.

Two Factor Authentication for risk management

While these methods are great for logging in a user they don’t fight off some common attack vectors. For starters, if a user makes use of the Remember Me function Joomla! will log him in automatically even if his session expires. Unless he remembers to log out, he’s permanently logged in. A lost or stolen device thus becomes a free pass to the site. Moreover, a hacker can use various ways to hijack a user’s session, especially if the user is logging in over an untrusted machine (e.g. Internet CafĂ©) or network (e.g. public, unencrypted, unprotected Wi-Fi). Furthermore, malware can be used to intercept the login cookie and allow a malicious agent to pose as the user.

There are times when a user can perform an important operation on the site, such as modifying information, deleting records or perform changes which can directly or indirectly lead to an adverse financial impact. Banks are already dealing with such issues by issuing OTP (One Time Password) devices to their clients and requiring an OTP to be entered before performing any such transaction. Incidentally, this is exactly what Two Factor Authentication is all about: being able to verify the user’s identity using an one time password, also known as a “secret code”. Joomla! already provides the API to perform this kind of checks, even in third party applications. So let’s see how you can do that in your components.

Using Two Factor Authentication in your software

Implementing Two Factor Authentication (TFA) on your component constitutes of three steps:

  1. Determine whether the user has enabled TFA on his/her account. If not, you should either instruct them to do so or not make use of TFA.
  2. Include a “Secret Code” field in your form.
  3. Validate the Secret Code.

First, figuring out if TFA is enabled on the current user’s account:

/**
 * Checks if the Two Factor Authentication method is globally enabled and if the
 * user has enabled a specific TFA method on their account. Only if both conditions
 * are met will this method return true;
 *
 * @param   integer $userId The user ID to check. Skip to use the current user.
 *
 * @return  boolean  True if TFA is enabled for this user
 */
public function isTFAEnabled($userId = null)
{
   // Include the necessary user model and helper
   require_once JPATH_ADMINISTRATOR . '/components/com_users/helpers/users.php';
   require_once JPATH_ADMINISTRATOR . '/components/com_users/models/user.php';

   // Is TFA globally turned off?
   $twoFactorMethods = UsersHelper::getTwoFactorMethods();

   if (count($twoFactorMethods) <= 1)
   {
      return false;
   }

   // Do we need to get the User ID?
   if (empty($userId))
   {
      $userId = JFactory::getUser()->id;
   }

   // Has this user turned on TFA on their account?
   $model     = new UsersModelUser;
   $otpConfig = $model->getOtpConfig($userId);

   return !(empty($otpConfig->method) || ($otpConfig->method == 'none'));
}

If that method returns true, show your user a Secret Code field.

Then, you need to validate that code. Use the following method:

/**
 * Checks if the provided secret code is a valid two factor authentication
 * code for the user whose $userId is provided. If TFA is disabled globally
 * or for the specific user you will receive true.
 *
 * @param   string  $code   The secret code to check
 * @param   integer $userId The user ID to check. Skip to use the current user.
 *
 * @return  boolean  True if you should accept the code
 */
public function isValidTFA($code, $userId = null)
{
   // Include the necessary user model
   require_once JPATH_ADMINISTRATOR . '/components/com_users/models/user.php';

   // Do we need to get the User ID?
   if (empty($userId))
   {
      $userId = JFactory::getUser()->id;
   }
   
   // Check the secret code
   $model   = new UsersModelUser;
   $options = ['warn_if_not_req' => false,];

   return $model->isValidSecretKey($userId, $code, $options);
}

If that returns true the code is accepted and you should proceed with whatever your code does. If it returns false, don’t. See? Two factor authentication is not rocket science with Joomla! 3.2.

Published by Nicholas Dionysopoulos

PHP developer, author of Akeeba Backup and Admin Tools. Father, husband, cat herder and geek. Proudly uses all major Operating Systems on desktop and mobile.