WordPress custom login requirement and error message using authenticate hook

Viewed 2930

For security reasons I want every user from a certain domain (for now I've used @company.com) to be forced to login using the login with Google button, so I wrote this check.

Which works fine but the error message on the login page doesn't change, it says FOUT: Verkeerde logingegevens. which is Dutch for ERROR: Wrong credentials.. I did return a new error with a different message, so how would I display this message?

function check_login($user, $username, $password) {
    if (!empty($username)) {
        if (substr($user->user_email, -12) == "@company.com") {
            $user = new WP_Error( 'authentication_failed', __( '<strong>ERROR</strong>: Please login using Google.' ) );
        }
    }

    return $user;
}

add_filter('authenticate', 'check_login', 100, 3);
3 Answers

Wordpress Core

Your issue comes from the fact that the $user variable you are filtering is already a WP_Error and not a WP_User, so your filter cannot work because $user->user_email is null, hopefully Wordpress uses another intermediate hook in it's login function

You should use this filter instead wp_authenticate_user which will fire after the user is retrieved from the database but before the password is checked, converting the user into a WP_Error

function check_login($user) {
    if ($user instanceof WP_User) {
        if (substr($user->user_email, -12) == "@company.com") {
            $user = new WP_Error( 'authentication_failed', __( '<strong>ERROR</strong>: Please login using Google.' ) );
        }
    }

    return $user;
}

add_filter('wp_authenticate_user', 'check_login', 9, 1);

Third Party plugin

If you are using a security plugin, they usually have an option that disable error login messages, here's how to disable it in some major ones

IThemes Security

One option this plugin provides is to hide all login error messages, you can disable this in the settings of the plugin > Wordpress Tweaks > Uncheck Login Error Messages ithemessecurity options

Or access this page by appending this url to your website /wp-admin/admin.php?page=itsec&module=wordpress-tweaks&module_type=recommended

Wordfence

This plugin gives the user a generic error message to prevent revealing if it's the password or the username that is incorrect, you can disable this option there enter image description here

You'll need to remove the original authenticate filter and replace it with your own.

This way, you can set a custom error message for each different case.

Just make sure to add your custom @company.com check at the top, before checking for other cases.

remove_filter('authenticate', 'wp_authenticate_username_password');
add_filter('authenticate', 'wpse_115539_authenticate_username_password', 20, 3);
/**
 * Remove Wordpress filer and write our own with changed error text.
 */
function wpse_115539_authenticate_username_password($user, $username, $password) {

  if (!empty($username)) {
    if (substr($user->user_email, -12) == "@company.com") {
      return new WP_Error('authentication_failed', __('<strong>ERROR</strong>: Please login using Google.'));
    }
  }

  if (is_a($user, 'WP_User'))
    return $user;

  if (empty($username) || empty($password)) {
    if (is_wp_error($user))
      return $user;

    $error = new WP_Error();

    if (empty($username))
      $error->add('empty_username', __('<strong>ERROR</strong>: The username field is empty.'));

    if (empty($password))
      $error->add('empty_password', __('<strong>ERROR</strong>: The password field is empty.'));

    return $error;
  }

  $user = get_user_by('login', $username);

  if (!$user)
    return new WP_Error('invalid_username', sprintf(__('<strong>ERROR</strong>: Invalid username. <a href="%s" title="Password Lost and Found">Lost your password</a>?'), wp_lostpassword_url()));

  $user = apply_filters('wp_authenticate_user', $user, $password);
  if (is_wp_error($user))
    return $user;

  if (!wp_check_password($password, $user->user_pass, $user->ID))
    return new WP_Error('incorrect_password', sprintf(__('<strong>ERROR</strong>: The password you entered for the username <strong>%1$s</strong> is incorrect. <a href="%2$s" title="Password Lost and Found">Lost your password</a>?'),
      $username, wp_lostpassword_url()));

  return $user;
}

FYI, I found this code here.

function wp_authenticate( $username, $password ) {
    $username = sanitize_user( $username );
    $password = trim( $password );


    $user = apply_filters( 'authenticate', null, $username, $password );

    if ( $user == null ) {
        // TODO what should the error message be? (Or would these even happen?)
        // Only needed if all authentication handlers fail to return anything.
        $user = new WP_Error( 'authentication_failed', __( '<strong>ERROR</strong>: Invalid username, email address or incorrect password.' ) );
    }

    $ignore_codes = array( 'empty_username', 'empty_password' );

    if ( is_wp_error( $user ) && ! in_array( $user->get_error_code(), $ignore_codes ) ) {

        do_action( 'wp_login_failed', $username );
    }

    return $user;
}
Related