207 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			207 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
namespace nur\b\authnz;
 | 
						|
 | 
						|
use nur\A;
 | 
						|
use nur\base;
 | 
						|
use nur\config;
 | 
						|
use nur\data\types\Metadata;
 | 
						|
use nur\txt;
 | 
						|
 | 
						|
/**
 | 
						|
 * Class UserManager: gestionnaire d'utilisateurs et de groupes
 | 
						|
 *
 | 
						|
 * cette implémentation lit la clé conf.authnz de la configuration
 | 
						|
 * - users: liste des utilisateurs
 | 
						|
 * - groups: liste des groupes
 | 
						|
 * - default_role: rôle principal par défaut
 | 
						|
 * - user_perms, user_role, user_groups: associations par utilisateur
 | 
						|
 * - group_perms, group_role: associations par groupe
 | 
						|
 */
 | 
						|
class SimpleUserManager implements IUserManager {
 | 
						|
  const USER_SCHEMA = [
 | 
						|
    "username" => ["string", null, "nom d'utilisateur"],
 | 
						|
    "password" => ["?string", null, "mot de passe"],
 | 
						|
    "mail" => ["?string", null, "mail de l'utilisateur"],
 | 
						|
    "role" => ["?string", null, "role principal de l'utilisateur"],
 | 
						|
    "perms" => ["?array", null, "permissions attribuées à l'utilisateur"],
 | 
						|
    "groups" => ["?array", null, "groupes dont l'utilisateur fait partie"],
 | 
						|
    "display_name" => ["?string", null, "nom d'affichage long"],
 | 
						|
    "short_name" => ["?string", null, "nom d'affichage court"],
 | 
						|
    "disabled" => ["bool", false, "ce compte est-il désactivé?"],
 | 
						|
  ];
 | 
						|
  
 | 
						|
  const GROUP_SCHEMA = [
 | 
						|
    "groupname" => ["string", null, "identifiant", "required" => true],
 | 
						|
    "lib" => ["?string", null, "libellé"],
 | 
						|
    "role" => ["?string", null, "rôle par défaut attribué aux membres de ce groupe"],
 | 
						|
    "perms" => ["?array", null, "permissions supplémentaires associées à ce groupe"],
 | 
						|
  ];
 | 
						|
 | 
						|
  const OVERRIDES_SCHEMA = [
 | 
						|
    "cas_attrs" => ["?array", null, "attributs CAS"],
 | 
						|
  ];
 | 
						|
 | 
						|
  private static $user_md;
 | 
						|
  protected static function user_md(): Metadata {
 | 
						|
    if (self::$user_md === null) self::$user_md = new Metadata(self::USER_SCHEMA);
 | 
						|
    return self::$user_md;
 | 
						|
  }
 | 
						|
  
 | 
						|
  function _getUser(string $username): ?array {
 | 
						|
    return config::k("users.$username");
 | 
						|
  }
 | 
						|
 | 
						|
  function getUser(string $username, ?array $overrides, ?bool &$found=null): array {
 | 
						|
    $user = $this->_getUser($username);
 | 
						|
    $found = $user !== null;
 | 
						|
    self::user_md()->ensureSchema($user, $username);
 | 
						|
    # support des attributs CAS
 | 
						|
    $cas_attrs = A::get($overrides, "cas_attrs");
 | 
						|
    if ($cas_attrs !== null) {
 | 
						|
      # nom et prénom
 | 
						|
      $sn = A::first(explode(",", A::get($cas_attrs, "sn")));
 | 
						|
      $givenName = A::get($cas_attrs, "givenname");
 | 
						|
      if ($sn !== null && $givenName !== null) {
 | 
						|
        $sn = txt::upperw($sn);
 | 
						|
        $givenName = txt::upperw($givenName);
 | 
						|
        $parts = preg_split('/[- ]+/', $givenName);
 | 
						|
        $gn = "";
 | 
						|
        foreach ($parts as $part) {
 | 
						|
          $gn .= mb_substr($part, 0, 1);
 | 
						|
        }
 | 
						|
        $gn = txt::upper($gn);
 | 
						|
 | 
						|
        $displayName = "$givenName $sn";
 | 
						|
        $shortName = "$gn.$sn";
 | 
						|
        A::replace_n($user, "display_name", $displayName);
 | 
						|
        A::replace_n($user, "short_name", $shortName);
 | 
						|
      }
 | 
						|
      # mail
 | 
						|
      A::replace_n($user, "mail", A::get($cas_attrs, "mail"));
 | 
						|
    }
 | 
						|
    return $user;
 | 
						|
  }
 | 
						|
 | 
						|
  private static $group_md;
 | 
						|
  protected static function group_md(): Metadata {
 | 
						|
    if (self::$group_md === null) self::$group_md = new Metadata(self::GROUP_SCHEMA);
 | 
						|
    return self::$group_md;
 | 
						|
  }
 | 
						|
 | 
						|
  function _getGroup(string $groupname): ?array {
 | 
						|
    return config::k("groups.$groupname");
 | 
						|
  }
 | 
						|
 | 
						|
  function getGroup(string $groupname, ?array $overrides, ?bool &$found=null): array {
 | 
						|
    $group = $this->_getGroup($groupname);
 | 
						|
    $found = $group !== null;
 | 
						|
    self::group_md()->ensureSchema($group, $groupname);
 | 
						|
    # support des attributs CAS
 | 
						|
    $cas_attrs = A::get($overrides, "cas_attrs");
 | 
						|
    if ($cas_attrs !== null) {
 | 
						|
    }
 | 
						|
    return $group;
 | 
						|
  }
 | 
						|
 | 
						|
  protected function getDefaultRole(): ?string {
 | 
						|
    return config::k("default_role");
 | 
						|
  }
 | 
						|
 | 
						|
  /** retourner la liste des permissions de l'utilisateur */
 | 
						|
  protected function getUserPerms(array $user): array {
 | 
						|
    $perms = $user["perms"];
 | 
						|
    A::merge($perms, config::k("user_perms.$user[username]"));
 | 
						|
    return $perms;
 | 
						|
  }
 | 
						|
  /** retourner le rôle de l'utilisateur */
 | 
						|
  protected function getUserRole(array $user): ?string {
 | 
						|
    $role = $user["role"];
 | 
						|
    base::update_n($role, config::k("user_role.$user[username]"));
 | 
						|
    return $role;
 | 
						|
  }
 | 
						|
  /** retourner les noms des groupes dont fait partie l'utilisateur */
 | 
						|
  protected function getUserGroupnames(array $user): array {
 | 
						|
    $groups = $user["groups"];
 | 
						|
    A::merge($groups, config::k("user_groups.$user[username]"));
 | 
						|
    return $groups;
 | 
						|
  }
 | 
						|
 | 
						|
  /** retourner le rôle par défaut attribué aux membres du groupe */
 | 
						|
  protected function getGroupRole(array $group): ?string {
 | 
						|
    $role = $group["role"];
 | 
						|
    base::update_n($role, config::k("group_role.$group[groupname]"));
 | 
						|
    return $role;
 | 
						|
  }
 | 
						|
  /** retourner les permissions supplémentaires attribuées aux membres du groupe */
 | 
						|
  protected function getGroupPerms(array $group): ?array {
 | 
						|
    $perms = $group["perms"];
 | 
						|
    A::merge($perms, config::k("group_perms.$group[groupname]"));
 | 
						|
    return $perms;
 | 
						|
  }
 | 
						|
 | 
						|
  /** retourner les permissions associées au rôle */
 | 
						|
  protected function getRolePerms(string $role): ?array {
 | 
						|
    return config::k("role_perms.$role");
 | 
						|
  }
 | 
						|
 | 
						|
  protected function mergePerms(array &$userPerms, ?array $perms): void {
 | 
						|
    if ($perms === null) return;
 | 
						|
    foreach ($perms as $perm) {
 | 
						|
      $userPerms[$perm] = true;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  protected function mergeRolePerms(array &$userPerms, ?string $role): void {
 | 
						|
    if ($role === null) return;
 | 
						|
    $perms = $this->getRolePerms($role);
 | 
						|
    if ($perms === null) return;
 | 
						|
    foreach ($perms as $perm) {
 | 
						|
      $userPerms[$perm] = true;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  function getAuthzUser(string $username, ?array $overrides): ?IAuthzUser {
 | 
						|
    $user = $this->getUser($username, $overrides, $founduser);
 | 
						|
 | 
						|
    $role = null;
 | 
						|
    # permissions par défaut, ajoutées uniquement si l'utilisateur a déjà des
 | 
						|
    # permissions explicites
 | 
						|
    $defaultPerms = ["^$username" => true];
 | 
						|
    # tout d'abord calculer les permissions et rôles associées à l'utilisateur
 | 
						|
    $perms = array_fill_keys($this->getUserPerms($user), true);
 | 
						|
    $userRole = $this->getUserRole($user);
 | 
						|
    if ($role === null) $role = $userRole;
 | 
						|
    $this->mergeRolePerms($perms, $userRole);
 | 
						|
    # puis calculer les permissions et rôles associés aux groupes
 | 
						|
    $groupnames = $this->getUserGroupnames($user);
 | 
						|
    foreach ($groupnames as $groupname) {
 | 
						|
      # permission automatique basée sur le groupe
 | 
						|
      A::merge($defaultPerms, ["@$groupname" => true]);
 | 
						|
 | 
						|
      $group = $this->getGroup($groupname, $overrides, $foundgroup);
 | 
						|
      $this->mergePerms($perms, $this->getGroupPerms($group));
 | 
						|
      $groupRole = $this->getGroupRole($group);
 | 
						|
      if ($role === null) $role = $groupRole;
 | 
						|
      $this->mergeRolePerms($perms, $groupRole);
 | 
						|
      # rôle automatique du fait de l'appartenance au groupe
 | 
						|
      $this->mergeRolePerms($perms, "@$groupname");
 | 
						|
    }
 | 
						|
 | 
						|
    # si un role ou des permissions existent, considérer que l'utilisateur
 | 
						|
    # existe, même s'il n'avait pas été trouvé au départ
 | 
						|
    if (!$founduser && !$role && !$perms) return null;
 | 
						|
 | 
						|
    # permissions par défaut
 | 
						|
    A::merge($perms, $defaultPerms);
 | 
						|
    # rôle par défaut
 | 
						|
    if ($role === null) {
 | 
						|
      $role = $this->getDefaultRole();
 | 
						|
      $this->mergeRolePerms($perms, $role);
 | 
						|
    }
 | 
						|
 | 
						|
    $user["role"] = $role;
 | 
						|
    $user["perms"] = array_keys($perms);
 | 
						|
    $user["groups"] = $groupnames;
 | 
						|
    return new SimpleUser($user);
 | 
						|
  }
 | 
						|
}
 |