File: /wordpress/plugins/wp-cloud-client/beta/src/Access/RoleManager.php
<?php
declare(strict_types=1);
namespace VPlugins\WPCloudClient\Access;
use WP_User;
/**
* SSO-driven WordPress role grant for one-click login.
*
* The platform's desired role (administrator vs editor) is written to the
* `wpcc_desired_role` user meta by the one_click_login action before it hands
* back the login URL. On every WordPress login the flag is read and the user's
* role is reconciled to match — so a customer token following an admin token
* downgrades the user on the next login, and rotating/removing the admin token
* revokes admin access.
*
* Mirrors {@see \VPlugins\WPCloudClient\Multisite\SuperAdminManager}: only acts
* when the platform has explicitly set the meta, leaving manually-assigned roles
* on non-SSO installations untouched.
*/
final class RoleManager extends SsoLoginReconciler {
/**
* User meta key that stores the platform's desired WordPress role.
*/
public const META_KEY = 'wpcc_desired_role';
/**
* Roles the platform is permitted to assign via SSO.
*
* Constrained to the two roles LocalEdge maps to (admin portal -> administrator,
* customer portal -> editor). Anything else is rejected at the API boundary.
*
* @var string[]
*/
public const ALLOWED_ROLES = array( 'administrator', 'editor' );
/**
* Priority 9 runs before SuperAdminManager (10) so the base role is set
* first and super admin is layered on top.
*
* @return int
*/
protected function hookPriority(): int {
return 9;
}
/**
* Reconcile the user's WordPress role from the platform flag on login.
*
* @param WP_User $user The authenticated user object.
* @return void
*/
protected function reconcile( WP_User $user ): void {
$role = get_user_meta( (int) $user->ID, self::META_KEY, true );
// Absence of the meta key means the platform has no opinion — leave the
// user's role untouched (mirrors SuperAdminManager's revoke caution).
if ( ! is_string( $role ) || ! self::isAllowedRole( $role ) ) {
return;
}
self::applyRole( $user, $role );
}
/**
* Reconcile a user's WordPress role to exactly the platform's desired role.
*
* The single authority for applying an SSO role — used both on login and at
* user auto-creation so the two paths can never diverge (both run the value
* through the `wpcc_user_role` filter and the same exact-match reconciliation).
*
* Reconciliation is by exact match, not membership: the user must end up with
* *only* this role. `WP_User::set_role()` is authoritative — it strips every
* other role — so a customer login following an admin login actually downgrades
* (the leftover `administrator` is removed), and an admin login promotes.
* The write is skipped only when the user already has exactly this one role,
* to avoid a redundant destructive `set_role()` on every login.
*
* @param WP_User $user The user to reconcile.
* @param string $role The platform's desired role (must be an allowed role).
* @return void
*/
public static function applyRole( WP_User $user, string $role ): void {
if ( ! self::isAllowedRole( $role ) ) {
return;
}
/**
* Filter the desired WordPress role for an SSO login.
*
* @param string $role The role the platform wants this user to have.
* @param WP_User $user The user being logged in.
*/
$role = (string) apply_filters( 'wpcc_user_role', $role, $user );
if ( ! self::isAllowedRole( $role ) ) {
return;
}
$currentRoles = (array) $user->roles;
if ( 1 !== count( $currentRoles ) || ! in_array( $role, $currentRoles, true ) ) {
$user->set_role( $role );
}
}
/**
* Persist the platform's desired role as user meta.
*
* Intended to be called from the one_click_login flow before the login URL
* is handed back to the platform.
*
* @param int $userId The WordPress user ID.
* @param string $role The desired role (must be an allowed role).
* @return void
*/
public static function setRole( int $userId, string $role ): void {
update_user_meta( $userId, self::META_KEY, $role );
}
/**
* Whether the given role may be assigned via SSO.
*
* @param string $role The role to check.
* @return bool
*/
public static function isAllowedRole( string $role ): bool {
return in_array( $role, self::ALLOWED_ROLES, true );
}
}