Skip to content

Commit

Permalink
Add skip strategies setting and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
joshcanhelp committed Sep 3, 2018
1 parent ccec093 commit c20072b
Show file tree
Hide file tree
Showing 15 changed files with 757 additions and 88 deletions.
12 changes: 4 additions & 8 deletions WP_Auth0.php
Original file line number Diff line number Diff line change
Expand Up @@ -526,9 +526,7 @@ private function autoloader( $class ) {
if ( ! function_exists( 'get_auth0userinfo' ) ) {
function get_auth0userinfo( $user_id ) {

global $wpdb;

$profile = get_user_meta( $user_id, $wpdb->prefix . 'auth0_obj', true );
$profile = WP_Auth0_UsersRepo::get_meta( $user_id, 'auth0_obj' );

if ( $profile ) {
return WP_Auth0_Serializer::unserialize( $profile );
Expand All @@ -554,17 +552,15 @@ function get_currentauth0userinfo() {
if ( ! function_exists( 'get_currentauth0user' ) ) {
function get_currentauth0user() {

global $wpdb;

$current_user = wp_get_current_user();

$serialized_profile = get_user_meta( $current_user->ID, $wpdb->prefix . 'auth0_obj', true );
$serialized_profile = WP_Auth0_UsersRepo::get_meta( $current_user->ID, 'auth0_obj' );

$data = new stdClass;

$data->auth0_obj = empty( $serialized_profile ) ? false : WP_Auth0_Serializer::unserialize( $serialized_profile );
$data->last_update = get_user_meta( $current_user->ID, $wpdb->prefix . 'last_update', true );
$data->auth0_id = get_user_meta( $current_user->ID, $wpdb->prefix . 'auth0_id', true );
$data->last_update = WP_Auth0_UsersRepo::get_meta( $current_user->ID, 'last_update' );
$data->auth0_id = WP_Auth0_UsersRepo::get_meta( $current_user->ID, 'auth0_id' );

return $data;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/WP_Auth0_DBManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,7 @@ protected function migrate_users_data() {
$repo = new WP_Auth0_UsersRepo( $this->a0_options );

foreach ( $userRows as $row ) {
$auth0_id = get_user_meta( $row->wp_id, $wpdb->prefix . 'auth0_id', true );
$auth0_id = WP_Auth0_UsersRepo::get_meta( $row->wp_id, 'auth0_id' );

if ( ! $auth0_id ) {
$repo->update_auth0_object( $row->wp_id, WP_Auth0_Serializer::unserialize( $row->auth0_obj ) );
Expand Down
3 changes: 2 additions & 1 deletion lib/WP_Auth0_Export_Users.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ public function a0_export_users( $user_ids = null ) {
global $wpdb;

foreach ( $users as $user ) {
$profile = new WP_Auth0_UserProfile( get_user_meta( $user->ID, $wpdb->prefix . 'auth0_obj', true ) );
$auth0_obj = WP_Auth0_UsersRepo::get_meta( $user->ID, 'auth0_obj' );
$profile = new WP_Auth0_UserProfile( $auth0_obj );

echo $this->process_str( $profile->get_email(), true );
echo $this->process_str( $profile->get_nickname(), true );
Expand Down
24 changes: 21 additions & 3 deletions lib/WP_Auth0_LoginManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,17 @@ class WP_Auth0_LoginManager {
/**
* Should the new user have an administrator role?
*
* TODO: Deprecate, not used
*
* @var bool|null
*/
protected $admin_role;

/**
* Ignore verified email requirement in Settings > Advanced.
*
* TODO: Deprecate, not used
*
* @var bool
*/
protected $ignore_unverified_email;
Expand Down Expand Up @@ -397,14 +401,28 @@ public function implicit_login() {
* @throws WP_Auth0_BeforeLoginException - Errors encountered during the auth0_before_login action.
*/
public function login_user( $userinfo, $id_token = null, $access_token = null, $refresh_token = null ) {
$auth0_sub = $userinfo->sub;
list( $strategy ) = explode( '|', $auth0_sub );

// Check that the user has a verified email, if required.
if ( ! $this->ignore_unverified_email && $this->a0_options->get( 'requires_verified_email' ) ) {
if (
// Admin settings enforce verified email.
$this->a0_options->get( 'requires_verified_email' ) &&
// Email verification is not ignored (set at class initialization).
! $this->ignore_unverified_email &&
// Strategy for the user is not skipped.
! $this->a0_options->strategy_skips_verified_email( $strategy )
) {

// Email address is empty so cannot proceed.
if ( empty( $userinfo->email ) ) {
throw new WP_Auth0_LoginFlowValidationException(
__( 'This account does not have an email associated, as required by your site administrator.', 'wp-auth0' )
);
}
if ( ! $userinfo->email_verified ) {

// Die with an action to re-send email verification.
if ( empty( $userinfo->email_verified ) ) {
WP_Auth0_Email_Verification::render_die( $userinfo );
}
}
Expand All @@ -418,7 +436,7 @@ public function login_user( $userinfo, $id_token = null, $access_token = null, $
}
}
} else {
$user = $this->users_repo->find_auth0_user( $userinfo->sub );
$user = $this->users_repo->find_auth0_user( $auth0_sub );
}

$user = apply_filters( 'auth0_get_wp_user', $user, $userinfo );
Expand Down
24 changes: 24 additions & 0 deletions lib/WP_Auth0_Options.php
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,29 @@ public function add_lock_connection( $connection ) {
}
}

/**
* Check if provided strategy is allowed to skip email verification.
* Useful for Enterprise strategies that do not provide a email_verified profile value.
*
* @param string $strategy - Strategy to check against saved setting.
*
* @return bool
*
* @since 3.8.0
*/
public function strategy_skips_verified_email( $strategy ) {
$skip_strategies = trim( $this->get( 'skip_verified_email' ) );

// No strategies to skip.
if ( empty( $skip_strategies ) ) {
return false;
}

$skip_strategies = explode( ',', $skip_strategies );
$skip_strategies = array_map( 'trim', $skip_strategies );
return in_array( $strategy, $skip_strategies );
}

/**
* Default settings when plugin is installed or reset
*
Expand Down Expand Up @@ -229,6 +252,7 @@ protected function defaults() {

// Advanced
'requires_verified_email' => true,
'skip_verified_email' => '',
'remember_users_session' => false,
'default_login_redirection' => home_url(),
'passwordless_enabled' => false,
Expand Down
125 changes: 66 additions & 59 deletions lib/WP_Auth0_UsersRepo.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,90 +68,83 @@ public function tokenHasRequiredScopes( $jwt ) {

}

public function create( $userinfo, $token, $access_token = null, $role = null, $ignore_unverified_email = false ) {

// If the user doesn't exist we need to either create a new one, or assign them to an existing one
$isDatabaseUser = false;

if ( isset( $userinfo->identities ) ) {
/**
* Create or join a WP user with an incoming Auth0 one or reject with an exception.
*
* @param object $userinfo - Profile object from Auth0.
* @param string $token - ID token from Auth0.
* @param null|string $access_token - TODO: Deprecate, not used
* @param null|string $role - TODO: Deprecate, not used
* @param bool $skip_email_verified - TODO: Deprecate, not used
*
* @return int|null|WP_Error
*
* @throws WP_Auth0_CouldNotCreateUserException
* @throws WP_Auth0_EmailNotVerifiedException
* @throws WP_Auth0_RegistrationNotEnabledException
*/
public function create( $userinfo, $token, $access_token = null, $role = null, $skip_email_verified = false ) {
$auth0_sub = $userinfo->sub;
list($strategy) = explode( '|', $auth0_sub );
$opts = WP_Auth0_Options::Instance();
$wp_user = null;
$user_id = null;

// Check legacy identities profile object for a DB connection.
$is_db_connection = 'auth0' === $strategy;
if ( ! $is_db_connection && ! empty( $userinfo->identities ) ) {
foreach ( $userinfo->identities as $identity ) {
if ( $identity->provider == 'auth0' ) {
$isDatabaseUser = true;
if ( 'auth0' === $identity->provider ) {
$is_db_connection = true;
break;
}
}
} else {
$sub = $userinfo->sub;
list($provider, $id) = explode( '|', $sub );
if ( $provider == 'auth0' ) {
$isDatabaseUser = true;
}
}

$joinUser = null;

// If the user has a verified email or is a database user try to see if there is
// a user to join with. The isDatabase is because we don't want to allow database
// user creation if there is an existing one with no verified email
$shouldJoinUser = ( isset( $userinfo->email ) // if a0 user has email
&& ( ( $ignore_unverified_email || ( isset( $userinfo->email_verified ) && $userinfo->email_verified ) ) // and it is verified (or we should ignore verification)
|| ! $isDatabaseUser // or it is not a database user (we can trust the email is valid)
)
); // if true, we can join the a0 user with the wp one
// Email is considered verified if flagged as such, if we ignore the requirement, or if the strategy is skipped.
$email_verified = ! empty( $userinfo->email_verified )
|| $skip_email_verified
|| $opts->strategy_skips_verified_email( $strategy );

// WP user to join with incoming Auth0 user.
if ( ! empty( $userinfo->email ) ) {
$joinUser = get_user_by( 'email', $userinfo->email );
$wp_user = get_user_by( 'email', $userinfo->email );
}

$auto_provisioning = WP_Auth0_Options::Instance()->get( 'auto_provisioning' );
$allow_signup = WP_Auth0_Options::Instance()->is_wp_registration_enabled() || $auto_provisioning;

$user_id = null;

global $wpdb;

// If there is a user with the same email, we should check if the wp user was joined with an auth0 user. If so, we shouldn't allow it again
if ( ! is_null( $joinUser ) && $joinUser instanceof WP_User ) {
$auth0_id = get_user_meta( $joinUser->ID, $wpdb->prefix . 'auth0_id', true );

if ( $auth0_id ) { // if it has an a0 id, we cant join it
$msg = __( 'There is a user with the same email', 'wp-auth0' );
if ( is_object( $wp_user ) && $wp_user instanceof WP_User ) {
// WP user exists, check if we can join.
$user_id = $wp_user->ID;

throw new WP_Auth0_CouldNotCreateUserException( $msg );
}
}

if ( $shouldJoinUser && ! is_null( $joinUser ) && $joinUser instanceof WP_User ) {
// If we are here, we have a potential join user
// Don't allow creation or assignation of user if the email is not verified, that would
// be hijacking
if ( $ignore_unverified_email || $userinfo->email_verified ) {
$user_id = $joinUser->ID;
} else {
// Cannot join a DB connection user without a verified email.
if ( $is_db_connection && ! $email_verified ) {
throw new WP_Auth0_EmailNotVerifiedException( $userinfo, $token );
}
} elseif ( $allow_signup ) {

// If we are here, we need to create the user
// If the user has a different Auth0 ID, we cannot join it.
$current_auth0_id = self::get_meta( $user_id, 'auth0_id' );
if ( ! empty( $current_auth0_id ) && $auth0_sub !== $current_auth0_id ) {
throw new WP_Auth0_CouldNotCreateUserException( __( 'There is a user with the same email.', 'wp-auth0' ) );
}
} elseif ( $opts->is_wp_registration_enabled() || $opts->get( 'auto_provisioning' ) ) {
// WP user does not exist and registration is allowed.
$user_id = WP_Auth0_Users::create_user( $userinfo, $role );

// Check if user was created
if ( is_wp_error( $user_id ) ) {
throw new WP_Auth0_CouldNotCreateUserException( $user_id->get_error_message() );
} elseif ( $user_id == -2 ) {
$msg = __( 'Could not create user. The registration process were rejected. Please verify that your account is whitelisted for this system. Please contact your site’s administrator.', 'wp-auth0' );

throw new WP_Auth0_CouldNotCreateUserException( $msg );
} elseif ( -2 === $user_id ) {
// Registration rejected by wpa0_should_create_user filter in WP_Auth0_Users::create_user().
throw new WP_Auth0_CouldNotCreateUserException( __( 'Registration rejected.', 'wp-auth0' ) );
} elseif ( $user_id < 0 ) {
// Registration failed for another reason.
throw new WP_Auth0_CouldNotCreateUserException();
}
} elseif ( ! $allow_signup ) {
} else {
// Signup is not allowed.
throw new WP_Auth0_RegistrationNotEnabledException();
}

// If we are here we should have a valid $user_id with a new user or an existing one
// log him in, and update the auth0_user table
$this->update_auth0_object( $user_id, $userinfo );

return $user_id;
}

Expand Down Expand Up @@ -202,4 +195,18 @@ public function delete_auth0_object( $user_id ) {
delete_user_meta( $user_id, $wpdb->prefix . 'last_update' );
}

/**
* Get a user's Auth0 meta data.
*
* @param integer $user_id - WordPress user ID.
* @param string - $key - Usermeta key to get.
*
* @return mixed
*
* @since 3.8.0
*/
public static function get_meta( $user_id, $key ) {
global $wpdb;
return get_user_meta( $user_id, $wpdb->prefix . $key, true );
}
}
Loading

0 comments on commit c20072b

Please sign in to comment.