WordPress custom login requirement and error message using authenticate hook - wordpress

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);

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
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

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. Lost your password?'), 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. Lost your password?'),
$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

Program to creating WordPress user login system for some defined user roles

I have updated my code, but the problem is get_the_ID not getting any value. Can you please help. This code was adding function.php in child theme.
// Works in single post outside of the Loop
add_filter( 'authenticate', 'myplugin_auth_signon', 30, 3 );
function myplugin_auth_signon( $user, $username, $password ) {
$user = get_user_by( 'login', $username );
$roles = $user->roles['0'];
$id = get_the_ID();
echo $id;
if ( is_page( $id == 400380 ) )
{
echo "Employee Page";
$user = new WP_Error( 'denied', "Customer have no permission to login from this employee login form" );
}
if ( is_page( $id == 399649 ) )
{
echo "Customer";
$user = new WP_Error( 'denied', "Employee have no permission to login from this customer login form" );
}
return $user;
}
You can restrict other role from login use authenticate filter hook.
add_filter( 'authenticate', 'myplugin_auth_signon', 30, 3 );
function myplugin_auth_signon( $user, $username, $password ) {
$user = get_user_by( 'login', $username );
$roles = $user->roles['0'];
if($roles != 'sales' && is_page('YOUR_SALES_PAGE_ID')){
$user = new WP_Error( 'denied', "You have not permission to login from this form" );
return $user;
}
return $user;
}
Replace YOUR_SALES_PAGE_ID with your current sales login page id.
For more help see this link : Click here
User roles comes from database ? check it before, then do your logic.

Woocommerce Login Custome API Endpoint

I am developing an app using woocommerece store and using the Woocommerce REST API for Fetching the Products and Order details, but now I am facing the problem in login because Woocommerce didn't provide this type of API.
So I am creating a custom endpoint and trying this but I am getting the error 404, no rest route available.
Here is my custome end point which i registered.
add_action( 'rest_api_init', function () {
register_rest_route( 'wc/v2', '/login/)', array(
'methods' => 'POST',
'callback'=> 'my_awesome_func',
'args' => array(
),
) );
} );
Here is the login of Login but i think i am doing anything wrong at someplace so please check and help me .
function my_awesome_func( WP_REST_Request $request ) {
global $wpdb;
$username = $request['email'];
$password = $request['password'];
$db = new DbOperation();
$response = array();
$login_data = array();
$login_data['user_login'] = $username;
$login_data['user_password'] = $password;
$results = $wpdb->get_row( "SELECT ID FROM rd_users WHERE user_email='".$username."'");
$activation_id = $results->ID;
$activation_key = get_user_meta( $activation_id, 'has_to_be_activated', true );
if($activation_key != false ){
$results = 2;//if activation key exists than show the error
}
else{
$user_verify = wp_signon( $login_data, false );
if ( is_wp_error($user_verify) )
{
$results = 0; //show invalid username and password.
}
else {
$results = 1; //login success.
}
}
if ($results== 1) {
$user_info = get_userdata($student[0]->ID);
$response['id'] = $user_info->ID;
$response['name'] = $user_info->display_name;
$response['fname'] = $user_info->first_name;
$response['lname'] = $user_info->last_name;
$response['email'] = $user_info->user_email;
$response['status'] = 1;
$response["error"] = false;
$response['message'] = "You have successfully Logedin!";
} else {
if($results == 0){
$response['status'] = 0;
$response["error"] = true;
$response['message'] = "Invalid username or password";
}
else{
$response['status'] = 2;
$response["error"] = true;
$response['message'] ="Your account has not been activated yet.
To activate it check your email and clik on the activation link.";
}
}
return $response;
}
See what i have found,
used https authentication. In postman, instead of using oAuth1.0 as the authentication, use Basic authentication and pass consumer key as the username. And the password should be consumer secret.
I hope that would work.

Send sms to different numbers based on the recipient Twilio and Contact form 7 - Wordpress

I'm working on integrating Twilio with Wordpress and Contact form 7 plugin.
I made a hook for Contact form 7 to send sms with Twilio on form submission. It works.
My next step is to send to different numbers based on the recipient ( I have 3 different location in the contact form 7 and the recipient changes based on the chosen location).
I can't make it work.
Below is my code, any thoughts?
This hook works and sends to 1 number only
add_action( 'wpcf7_mail_sent', 'your_wpcf7_mail_sent_function' );
function your_wpcf7_mail_sent_function() {
$sid = 'xxx';
$token = 'xxx';
$client = new Client($sid, $token);
$to = '+1111111111';
$client->messages->create(
// the number you'd like to send the message to
$to,
array(
'from' =>'+1212121211',
'body' => "form submitted"
)
);
}
This is the second part, I can't make it work.
global $to;
function wpcf7_do_something (&$WPCF7_ContactForm) {
if ($WPCF7_ContactForm->mail['recipient'] = "bla#bla.com") {
$to = '+1XXXXXXXXX';
} else if($WPCF7_ContactForm->mail['recipient'] = "blabla#blabla.com") {
$to = '+1x1x1x1x1x';
} else {
$to = "+1000000000"
}
}
add_action('wpcf7_before_send_mail', 'wpcf7_do_something');
add_action( 'wpcf7_mail_sent', 'your_wpcf7_mail_sent_function' );
function your_wpcf7_mail_sent_function() {
$sid = 'xxxxxxx';
$token = 'xxxxxxx';
$client = new Client($sid, $token);
$client->messages->create(
// the number you'd like to send the message to
$to,
array(
'from' =>'+1XXXXXXXXX',
'body' => "form submitted"
)
);
}
Twilio developer evangelist here.
From what I can tell from other Stack Overflow and Stack Exchange questions, you actually get passed the form to the wpcf7_mail_sent hook, so you don't need the two hooks like you have been trying. Something like the following should work:
add_action( 'wpcf7_mail_sent', 'your_wpcf7_mail_sent_function' );
function your_wpcf7_mail_sent_function($cf7form) {
if ($cf7form->mail['recipient'] = "bla#bla.com") {
$to = '+1XXXXXXXXX';
} else if($cf7form->mail['recipient'] = "blabla#blabla.com") {
$to = '+1x1x1x1x1x';
} else {
$to = "+1000000000"
}
$sid = 'xxx';
$token = 'xxx';
$client = new Client($sid, $token);
$client->messages->create(
// the number you'd like to send the message to
$to,
array(
'from' =>'+1212121211',
'body' => "form submitted"
)
);
}
Let me know if that helps at all.

How to allow Laravel and WordPress to share logins?

I'm a Laravel developer. I develop one ecommerce plugin with Laravel and I just want to combine WordPress with Laravel. So I need to share or make common login session between Laravel and WordPress.
How could I implement this? And are there special plugins available for this? Or could I use laravel-Auth?
The right way of doing it is to Have a Laravel (or Wordpress) as an Auth server
And create like an SSO plugin.
I was doing the same with NodeBB Forum login from Laravel.
Steps that I suggest:
Look at this package Laravel OAuth Server
Create or find any SSO plugin for wordpress
So you have all users in laravel (Registration and etc)
and if they want to login to Wordpress they login to Laravel App and give permission to login to wordpress.
Think of it Like you add Facebook Login to your site
Reading more for wordpress SSO
But to play with session and cookies it can be security issues.
Hope Helped.
Enabling Single-Sign-On in WordPress took me 18+ hours of struggle but might take you only a few minutes:
I experimented with all sorts of things: Laravel Passport (OAuth2), OpenID Connect, etc.
But the only solution I could get to work was to have the WordPress login page redirect to an auth-protected Laravel route that generates a JWT (JSON Web Token) and redirects back to a special callback URL on WordPress that either creates a new user or logs in an existing user.
It works well.
class JwtController extends Controller {
/**
* Inspired by https://github.com/WebDevStudios/aad-first-party-sso-wordpress/tree/master/lib/php-jwt
*
* #param Request $request
* #return ResponseInterface
*/
public function redirectWithToken(Request $request) {
$key = config('jwt.key');
$wpJwtUrl = $request->input('callback');
$redirectUrlAfterLogin = $request->input('redirect_to'); //Get the original intended destination and append as URL param to /jwt.
$tokenArray = $this->getToken(auth()->user(), $redirectUrlAfterLogin);
$jwt = \Firebase\JWT\JWT::encode($tokenArray, $key);
$wpJwtUrlWithTokenAsParam = $wpJwtUrl . '?token=' . $jwt;
return redirect()->away($wpJwtUrlWithTokenAsParam);
}
/**
*
* #param \App\User $user
* #param string $redirectUrlAfterLogin
* #return array
*/
public function getToken($user, $redirectUrlAfterLogin) {
$now = \Carbon\Carbon::now();
$aud = config('jwt.audience'); //root URL of the WordPress site
$firstName = StrT::getFirstNameFromFullName($user->name);
$expirationMins = config('jwt.expirationMins');
$token = [
"iss" => url("/"),
"aud" => $aud, //"audience" https://tools.ietf.org/html/rfc7519#section-4.1.3
"iat" => $now->timestamp, //"issued at" https://tools.ietf.org/html/rfc7519#section-4.1.6
"exp" => $now->addMinutes($expirationMins)->timestamp, //"expiration" https://tools.ietf.org/html/rfc7519#section-4.1.4
"attributes" => [
'emailAddress' => $user->email,
'firstName' => $firstName,
'lastName' => StrT::getLastNameFromFullName($user->name),
'nickname' => $firstName,
'displayName' => $user->name,
'redirectUrlAfterLogin' => $redirectUrlAfterLogin//In plugin: use redirectUrlAfterLogin from attributes after login.
]
];
return $token;
}
}
Install this WordPress plugin, but don't activate it until you're finished with everything else: https://wordpress.org/plugins/wp-force-login/
Install this WordPress plugin: https://as.wordpress.org/plugins/jwt-authenticator/
And then edit its auth.php to be this:
// register the callback
add_action('rest_api_init', function () {
register_rest_route('jwt-auth/v1', 'callback', [
'methods' => 'GET',
'callback' => 'ja_login'
], true);
});
require_once('JWT.php');
function ja_login() {
//get all attributes
$options = get_option('ja_settings');
$token_name = $options['token_name'];
$secret_key = $options['secret_key'];
$iss = $options['iss'];
$aud = $options['aud'];
// decode the token
$token = $_GET[$token_name];
$key = $secret_key;
$JWT = new JWT;
$json = $JWT->decode($token, $key);
$jwt = json_decode($json, true);
// use unix time for comparision
$exp = is_int($jwt['exp']) ? $jwt['exp'] : strtotime($jwt['exp']);
$nbf = $jwt['nbf'] ?? null;
$now = strtotime("now");
// if authentication successful
if (($jwt['iss'] == $iss) && ($jwt['aud'] == $aud) && ($exp > $now) && ($now > $nbf)) {
return getUserFromValidToken($options, $jwt);
} else {
return 'Login failed. Please let us know exactly what happened, and we will help you out right away.';
}
}
/**
*
* #param array $options
* #param array $jwt
* #return string
*/
function getUserFromValidToken($options, $jwt) {
$attributesKey = $options['attributes'];
$mail = $options['mail'];
$givenname = $options['first_name'];
$surname = $options['last_name'];
$nickname = $options['nickname'];
$displayname = $options['displayname'];
$default_role = $options['default_role'];
$attributes = $jwt[$attributesKey];
$redirectUrlAfterLogin = $attributes['redirectUrlAfterLogin'] ?? get_site_url();
$_SESSION['attributes'] = $attributes;
$_SESSION['jwt'] = $jwt;
// find or create user
$user = ja_find_or_create_user($attributes[$mail], $attributes[$mail], $attributes[$givenname], $attributes[$surname], $attributes[$nickname], $attributes[$displayname], $default_role);
// login user
if ($user) {
wp_clear_auth_cookie();
wp_set_current_user($user->ID, $user->user_login);
wp_set_auth_cookie($user->ID);
do_action('wp_login', $user->user_login);
wp_safe_redirect($redirectUrlAfterLogin);
exit();
} else {
return 'getUserFromValidToken failed!';
}
}
/**
*
* #param string $username
* #param string $emailAddress
* #param string $firstName
* #param string $lastName
* #param string $nickname
* #param string $displayName
* #param string $defaultRole
* #return mixed
*/
function ja_find_or_create_user($username, $emailAddress, $firstName, $lastName, $nickname, $displayName, $defaultRole) {
// if user exists, return user
if (username_exists($username)) {
return get_user_by('login', $username);
} elseif (email_exists($emailAddress)) {
return get_user_by('email', $emailAddress);
} else {// create user
$length = 16;
$include_standard_special_chars = false;
$random_password = wp_generate_password($length, $include_standard_special_chars);
// create user
$user_id = wp_create_user($username, $random_password, $emailAddress);
// update user metadata and return user id
$userData = [
'ID' => $user_id,
'first_name' => $firstName,
'last_name' => $lastName,
'nickname' => $nickname,
'display_name' => $displayName,
'role' => $defaultRole
];
return wp_update_user($userData);//(If successful, returns the user_id, otherwise returns a WP_Error object.)
}
}
/**
* Get login message link HTML for adding to the login form
* #return string
*/
function getLoginMessage() {
$options = get_option('ja_settings');
$redirect_to = $_GET['redirect_to'] ?? null;
$login_url = $options['login_url'] . '?callback=' . urlencode(site_url('/wp-json/jwt-auth/v1/callback'));
if($redirect_to){
$login_url .= '&redirect_to=' . urlencode($redirect_to);
}
$login_message = $options['login_message'];
return "<a id='jwt_link' href='{$login_url}'>{$login_message}</a>";
}
add_filter('login_message', 'getLoginMessage');
add_action( 'load-profile.php', function() {//https://wordpress.stackexchange.com/a/195370/51462 Redirect from profile.php to the dashboard since there is no reason for WordPress users to see or manage their profile since their main account is on the other site.
if( ! current_user_can( 'manage_options' ) ){
$redirectUrl = get_site_url();//admin_url()
exit( wp_safe_redirect( $redirectUrl ) );
}
} );
function show_admin_bar_conditionally(){//remove the WordPress admin toolbar https://premium.wpmudev.org/blog/remove-the-wordpress-admin-toolbar/
return current_user_can( 'manage_options' );
}
add_filter('show_admin_bar', 'show_admin_bar_conditionally');//can use 'show_admin_bar_conditionally' or '__return_false' for never.
//------------------------------------------------------------------
//for https://wordpress.org/support/topic/rest-api-26/#post-9915078
//and https://github.com/kevinvess/wp-force-login/issues/35
//and https://wordpress.org/support/topic/rest-api-26/page/2/#post-10000740
//and https://wordpress.org/support/topic/jwt-authentication/#post-10698307
add_filter( 'rest_authentication_errors', '__return_true' );
This belongs in functions.php of your theme in WordPress:
// https://codex.wordpress.org/Customizing_the_Login_Form
function my_custom_login_page() { ?>
<style type="text/css">
#loginform, #login #nav{display: none;}
#jwt_link{font-weight: bold; font-size: 20px;}
</style>
<script>
document.addEventListener("DOMContentLoaded", function(event) {
document.getElementById('jwt_link').click();//immediately upon load of login page, click the JWT link automatically
});
</script>
<?php }
add_action( 'login_enqueue_scripts', 'my_custom_login_page' );

Woocommerce Checkout not Working with No CAPTCHA reCAPTCHA for WooCommerce Plugin

when i active 'No CAPTCHA reCAPTCHA for WooCommerce' plugin, so on checkout page of WooCommerce when customer checked the 'Create an account?' check-box and than Place Order, it does not work. the page just scroll on to the top and nothing action.
any idea?
Reagrds
Faizan
The plugin is just written to protect the Woocommerce Registration and Login, not the Checkout Process.
In order to protect the Checkout Process, I tweaked registration.php like this
class WC_Ncr_Registration_Captcha extends WC_Ncr_No_Captcha_Recaptcha {
/** Initialize actions and filters */
public static function initialize() {
// initialize if login is activated
if ( isset( self::$plugin_options['captcha_wc_registration'] ) || self::$plugin_options['captcha_wc_registration'] == 'yes' ) {
// adds the captcha to the registration form
add_action( 'register_form', array( __CLASS__, 'display_captcha' ) );
}
//added the following lines to the plugin
add_action('woocommerce_after_checkout_billing_form', array( __CLASS__, 'display_captcha' ));
add_action('woocommerce_checkout_process', array(
__CLASS__,
'validate_captcha_wc_checkout'
), 10, 3 );
//added the previous lines to the plugin
}
/**
* Verify the captcha answer
*
* #param $validation_errors
* #param $username
* #param $email
*
* #return WP_Error
*/
public static function validate_captcha_wc_registration( $validation_errors, $username, $email ) {
if ( ! isset( $_POST['g-recaptcha-response'] ) || ! self::captcha_wc_verification() ) {
$validation_errors = new WP_Error( 'failed_verification', self::$error_message );
}
return $validation_errors;
}
//added the following lines to the plugin
public static function validate_captcha_wc_checkout( $validation_errors, $username, $email ) {
if ( ! isset( $_POST['g-recaptcha-response'] ) || ! self::captcha_wc_verification() ) {
wc_add_notice(__( 'Please verify you are not a robot.' ), 'error' );
}
}
//added the previous lines to the plugin
}
Add to functions.php
function my_woocommerce_before_checkout_process() {
remove_filter( 'woocommerce_registration_errors', array('WC_Ncr_Registration_Captcha', 'validate_captcha_wc_registration'), 10 );
}
add_action('woocommerce_before_checkout_process', 'my_woocommerce_before_checkout_process');

Resources