168 lines
4.9 KiB
PHP
168 lines
4.9 KiB
PHP
<?php
|
|
|
|
namespace RSSSL\Security\WordPress\Two_Fa\Controllers;
|
|
|
|
use Exception;
|
|
use RSSSL\Security\WordPress\Two_Fa\Models\Rsssl_Request_Parameters;
|
|
use RSSSL\Security\WordPress\Two_Fa\Providers\Rsssl_Provider_Loader;
|
|
use RSSSL\Security\WordPress\Two_Fa\Providers\Rsssl_Two_Factor_Provider;
|
|
use RSSSL\Security\WordPress\Two_Fa\Rsssl_Two_Factor_Settings;
|
|
use WP_REST_Request;
|
|
use WP_REST_Response;
|
|
use WP_User;
|
|
|
|
final class Rsssl_Base_Controller extends Rsssl_Abstract_Controller
|
|
{
|
|
protected const METHOD = 'POST';
|
|
protected const FEATURE_ROUTE = '/two-fa';
|
|
|
|
protected string $namespace;
|
|
|
|
|
|
public function __construct($namespace, $version, $featureVersion)
|
|
{
|
|
parent::__construct($namespace, $version, $featureVersion);
|
|
add_action('rest_api_init', array($this, 'register_api_routes'));
|
|
}
|
|
|
|
/**
|
|
* Registers the REST API routes for the base controller.
|
|
*
|
|
* @return void
|
|
* @throws Exception
|
|
*/
|
|
public function register_api_routes(): void
|
|
{
|
|
$this->route($this->namespace,
|
|
self::METHOD,
|
|
'do_not_ask_again',
|
|
array($this, 'disable_two_fa_for_user'),
|
|
null,
|
|
$this->build_args(array('user_id', 'login_nonce'), array('redirect_to'))
|
|
);
|
|
$this->route($this->namespace,
|
|
self::METHOD,
|
|
'skip_onboarding',
|
|
array($this, 'skip_onboarding'),
|
|
null,
|
|
$this->build_args(array('user_id', 'login_nonce'), array('redirect_to'))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Disables two-factor authentication for the user.
|
|
*
|
|
* @param WP_REST_Request $request The REST request object.
|
|
*
|
|
* @return WP_REST_Response The REST response object.
|
|
*/
|
|
public function disable_two_fa_for_user( WP_REST_Request $request ): WP_REST_Response {
|
|
$parameters = new Rsssl_Request_Parameters( $request );
|
|
|
|
try {
|
|
$user = $this->check_login_and_get_user($parameters->user_id, $parameters->login_nonce);
|
|
} catch (Exception $e) {
|
|
return new WP_REST_Response(['error' => $e->getMessage()], 403);
|
|
}
|
|
|
|
if ( $this->is_forced_user( $user->ID ) ) {
|
|
return new WP_REST_Response(
|
|
[
|
|
'error' => __( 'Two-Factor Authentication cannot be disabled for this account.', 'really-simple-ssl' ),
|
|
],
|
|
403
|
|
);
|
|
}
|
|
|
|
// if the 2FA is not enabled for the user, we only handle the passkey meta key
|
|
if ( ! (bool) rsssl_get_option( 'login_protection_enabled' ) ) {
|
|
// Remove the passkey meta key for the user.
|
|
update_user_meta( $user->ID, 'rsssl_passkey_configured', 'ignored' );
|
|
}
|
|
$loader = Rsssl_Provider_Loader::get_loader();
|
|
// We get all the available providers for the user.
|
|
foreach ($loader::get_providers() as $provider ) {
|
|
/**
|
|
* Set the user status to disable.
|
|
*
|
|
* @var Rsssl_Two_Factor_Provider $provider
|
|
*/
|
|
$provider::set_user_status( $user->ID, 'disabled' );
|
|
}
|
|
|
|
// Finally we redirect the user to the redirect_to page.
|
|
return $this->authenticate_and_redirect( $user->ID, $parameters->redirect_to );
|
|
}
|
|
|
|
/**
|
|
* Skips the onboarding process for the user.
|
|
*
|
|
* @param WP_REST_Request $request The REST request object.
|
|
*
|
|
* @return WP_REST_Response The REST response object.
|
|
*/
|
|
public function skip_onboarding( WP_REST_Request $request ): WP_REST_Response {
|
|
$parameters = new Rsssl_Request_Parameters( $request );
|
|
|
|
try {
|
|
$user = $this->check_login_and_get_user($parameters->user_id, $parameters->login_nonce);
|
|
} catch (Exception $e) {
|
|
return new WP_REST_Response(['error' => $e->getMessage()], 403);
|
|
}
|
|
|
|
if ( ! $this->can_user_skip_onboarding( $user ) ) {
|
|
return new WP_REST_Response(
|
|
[
|
|
'error' => __( 'Two-Factor Authentication setup is required for this account.', 'really-simple-ssl' ),
|
|
],
|
|
403
|
|
);
|
|
}
|
|
|
|
return $this->authenticate_and_redirect( $user->ID, $parameters->redirect_to );
|
|
}
|
|
|
|
/**
|
|
* Check if the user has an enabled provider that is forced for their role.
|
|
*
|
|
* @param int $user_id The user ID.
|
|
*
|
|
* @return bool
|
|
*/
|
|
private function is_forced_user( int $user_id ): bool {
|
|
$user = get_userdata( $user_id );
|
|
if ( ! $user instanceof WP_User ) {
|
|
return false;
|
|
}
|
|
|
|
$loader = Rsssl_Provider_Loader::get_loader();
|
|
|
|
foreach ( $loader::available_providers() as $method => $provider ) {
|
|
if ( ! $provider::is_enabled( $user ) ) {
|
|
continue;
|
|
}
|
|
|
|
if ( 'forced' === Rsssl_Two_Factor_Settings::get_role_status( $method, $user_id ) ) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Check if onboarding can be skipped for the given user.
|
|
*
|
|
* @param WP_User $user The user object.
|
|
*
|
|
* @return bool
|
|
*/
|
|
private function can_user_skip_onboarding( WP_User $user ): bool {
|
|
if ( ! $this->is_forced_user( $user->ID ) ) {
|
|
return true;
|
|
}
|
|
|
|
return false !== Rsssl_Two_Factor_Settings::is_user_in_grace_period( $user );
|
|
}
|
|
}
|