248 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			248 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| namespace nur\ldap\schemas;
 | |
| 
 | |
| use nur\A;
 | |
| use nur\b\IllegalAccessException;
 | |
| use nur\b\ValueException;
 | |
| use nur\data\types\md_utils;
 | |
| use nur\data\types\Metadata;
 | |
| use nur\ldap\consts;
 | |
| use nur\ldap\LdapAttr;
 | |
| use nur\ldap\LdapConn;
 | |
| use nur\ldap\syntaxes\BinarySyntax;
 | |
| use nur\ldap\syntaxes\StringSyntax;
 | |
| 
 | |
| /**
 | |
|  * Class LdapSchemaExtractor: extracteur de schéma LDAP, pour utilisation avec
 | |
|  * PHP
 | |
|  */
 | |
| class LdapSchemaExtractor {
 | |
|   function __construct(?array $schemaInfos=null) {
 | |
|     if ($schemaInfos !== null) {
 | |
|       [
 | |
|         "ldap_syntaxes" => $this->ldapSyntaxes,
 | |
|         "attribute_types" => $this->attributeTypes,
 | |
|         "object_classes" => $this->objectClasses,
 | |
|       ] = $schemaInfos;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   protected $ldapSyntaxes;
 | |
| 
 | |
|   protected $attributeTypes;
 | |
| 
 | |
|   protected $objectClasses;
 | |
| 
 | |
|   function loadSchema(LdapConn $conn): array {
 | |
|     $schema = null;
 | |
|     $schemaDn = $conn->getRootDse()->first("subschemaSubentry");
 | |
|     if ($schemaDn !== null) {
 | |
|       $schema = $conn->empty()->load($schemaDn, $conn->_search($schemaDn, [
 | |
|         "suffix" => "",
 | |
|         "attrs" => [
 | |
|           "ldapSyntaxes",
 | |
|           "attributeTypes",
 | |
|           "objectClasses",
 | |
|         ],
 | |
|         "scope" => "base",
 | |
|       ])->first());
 | |
|     }
 | |
|     if ($schema === null) {
 | |
|       throw new IllegalAccessException("unable to find subschemaSubentry attribute");
 | |
|     }
 | |
| 
 | |
|     $parser = new LseSyntax();
 | |
|     $ldapSyntaxes = [];
 | |
|     foreach ($schema->get("ldapSyntaxes", []) as $ldapSyntax) {
 | |
|       $ldapSyntax = $parser->parse($ldapSyntax);
 | |
|       $ldapSyntaxes[$ldapSyntax["oid"]] = $ldapSyntax;
 | |
|     }
 | |
|     $parser = new LseAttribute();
 | |
|     $attributeTypes = [];
 | |
|     foreach ($schema->get("attributeTypes", []) as $attributeType) {
 | |
|       $attributeType = $parser->parse($attributeType);
 | |
|       $attributeTypes[$attributeType["oid"]] = $attributeType;
 | |
|     }
 | |
|     $parser = new LseObjectClass();
 | |
|     $objectClasses = [];
 | |
|     foreach ($schema->get("objectClasses", []) as $objectClass) {
 | |
|       $objectClass = $parser->parse($objectClass);
 | |
|       $objectClasses[$objectClass["oid"]] = $objectClass;
 | |
|     }
 | |
|     return [
 | |
|       "ldap_syntaxes" => $this->ldapSyntaxes = $ldapSyntaxes,
 | |
|       "attribute_types" => $this->attributeTypes = $attributeTypes,
 | |
|       "object_classes" => $this->objectClasses = $objectClasses,
 | |
|     ];
 | |
|   }
 | |
| 
 | |
|   protected $syntaxes;
 | |
|   protected $attributes;
 | |
|   protected $canonAttrs;
 | |
|   protected $classes;
 | |
|   protected $canonClasses;
 | |
| 
 | |
|   function init(): array {
 | |
|     ## calculer la liste des syntaxes, et les classer par OID
 | |
|     $ldapSyntaxes = $this->ldapSyntaxes;
 | |
|     # rajouter une liste connue de syntaxes
 | |
|     A::merge($ldapSyntaxes, consts::KNOWN_SLAPD_SYNTAXES);
 | |
|     $syntaxes = [];
 | |
|     foreach ($ldapSyntaxes as $syntax) {
 | |
|       $oid = $syntax["oid"];
 | |
|       # si la syntaxe a déjà été définie, ignorer
 | |
|       if (array_key_exists($oid, $syntaxes)) continue;
 | |
|       $class = A::get(consts::KNOWN_SYNTAX_CLASSES, $oid);
 | |
|       if ($class === null) {
 | |
|         $binary = $syntax["x_not_human_readable"] || $syntax["x_binary_transfer_required"];
 | |
|         $class = $binary? BinarySyntax::class: StringSyntax::class;
 | |
|       }
 | |
|       $syntax["class"] = $class;
 | |
|       $syntaxes[$oid] = $syntax;
 | |
|     }
 | |
| 
 | |
|     ## calculer la liste des attributs, et les classer par nom canonique
 | |
|     $attributes = [];
 | |
|     $canonAttrs = [];
 | |
|     foreach ($this->attributeTypes as $attribute) {
 | |
|       $names = $attribute["names"];
 | |
|       $canonName = $names[0];
 | |
|       $attribute["name"] = $canonName;
 | |
|       foreach ($names as $name) {
 | |
|         $canonAttrs[strtolower($name)] = $canonName;
 | |
|       }
 | |
|       $attribute["class"] = A::_pget($syntaxes, [$attribute["syntax"], "class"]);
 | |
|       $attributes[strtolower($canonName)] = $attribute;
 | |
|     }
 | |
|     # résoudre l'héritage des attributs
 | |
|     foreach ($attributes as &$attribute) {
 | |
|       foreach ($attribute["sups"] as $sup) {
 | |
|         $sup = strtolower(A::get($canonAttrs, strtolower($sup), $sup));
 | |
|         A::update_n($attribute, $attributes[$sup]);
 | |
|       }
 | |
|     }; unset($attribute);
 | |
|     # puis mettre à false les valeurs booléennes nulles
 | |
|     foreach ($attributes as &$attribute) {
 | |
|       foreach (LseAttribute::BOOL_ATTRS as $name) {
 | |
|         $attribute[$name] = boolval($attribute[$name]);
 | |
|       }
 | |
|     }; unset($attribute);
 | |
| 
 | |
|     ## calculer la liste des classes, et les classer par nom canonique.
 | |
|     ## les noms des attributs sont aussi canonisés
 | |
|     $classes = [];
 | |
|     $canonClasses = [];
 | |
|     foreach ($this->objectClasses as $class) {
 | |
|       $names = $class["names"];
 | |
|       $canonName = $names[0];
 | |
|       $class["name"] = $canonName;
 | |
|       foreach ($names as $name) {
 | |
|         $canonClasses[strtolower($name)] = $canonName;
 | |
|       }
 | |
|       $musts = A::with($class["musts"]);
 | |
|       foreach ($musts as &$name) {
 | |
|         $name = A::get($canonAttrs, strtolower($name), $name);
 | |
|       }; unset($name);
 | |
|       $class["musts"] = $musts;
 | |
|       $mays = A::with($class["mays"]);
 | |
|       foreach ($mays as &$name) {
 | |
|         $name = A::get($canonAttrs, strtolower($name), $name);
 | |
|       }; unset($name);
 | |
|       $class["mays"] = $mays;
 | |
|       $class["attrs"] = array_merge($musts, $mays);
 | |
|       $classes[strtolower($canonName)] = $class;
 | |
|     }
 | |
|     # résoudre l'héritage des classes
 | |
|     foreach ($classes as &$class) {
 | |
|       foreach ($class["sups"] as $sup) {
 | |
|         $sup = strtolower(A::get($canonAttrs, strtolower($sup), $sup));
 | |
|         $sup = $classes[$sup];
 | |
|         A::update_n($class, $sup);
 | |
|         A::merge($class["musts"], $sup["musts"]);
 | |
|         A::merge($class["mays"], $sup["mays"]);
 | |
|       }
 | |
|     }; unset($class);
 | |
| 
 | |
|     ## fin de l'initialisation
 | |
|     return [
 | |
|       "syntaxes" => $this->syntaxes = $syntaxes,
 | |
|       "attributes" => $this->attributes = $attributes,
 | |
|       "canon_attrs" => $this->canonAttrs = $canonAttrs,
 | |
|       "classes" => $this->classes = $classes,
 | |
|       "canon_classes" => $this->canonClasses = $canonClasses,
 | |
|     ];
 | |
|   }
 | |
| 
 | |
|   const getAttributes_overrides_SCHEMA = [
 | |
|     "name" => "string",
 | |
|     "class" => "?string",
 | |
|     "set" => "?int",
 | |
|     "reset" => "?int",
 | |
|   ];
 | |
|   /** @var Metadata */
 | |
|   private static $getAttributes_overrides_md;
 | |
| 
 | |
|   function getAttributes(array $objectClasses, ?array $overrides=null): array {
 | |
|     if ($overrides !== null) {
 | |
|       $tmp = [];
 | |
|       foreach ($overrides as $name => $override) {
 | |
|         $attribute = ValueException::check_nn(
 | |
|           A::get($this->attributes, strtolower($name))
 | |
|           , "$name: attribut non défini");
 | |
|         $tmp[$attribute["name"]] = $override;
 | |
|       }
 | |
|       $overrides = $tmp;
 | |
|       $md = md_utils::ensure_md(self::$getAttributes_overrides_md, self::getAttributes_overrides_SCHEMA);
 | |
|       $md->eachEnsureSchema($overrides);
 | |
|     }
 | |
| 
 | |
|     $nameRequired = [];
 | |
|     foreach ($objectClasses as $name) {
 | |
|       $name = A::get($this->canonClasses, strtolower($name), $name);
 | |
|       $class = ValueException::check_nn(
 | |
|         A::get($this->classes, strtolower($name))
 | |
|         , "$name: classe non définie");
 | |
|       foreach ($class["musts"] as $must) {
 | |
|         $nameRequired[$must] = true;
 | |
|       }
 | |
|       foreach ($class["mays"] as $may) {
 | |
|         A::replace_nx($nameRequired, $may, false);
 | |
|       }
 | |
|     }
 | |
|     $attributes = [
 | |
|       "dn" => [
 | |
|         "name" => "dn",
 | |
|         "class" => StringSyntax::class,
 | |
|         "flags" => LdapAttr::MONOVALUED,
 | |
|       ],
 | |
|     ];
 | |
|     foreach ($nameRequired as $name => $required) {
 | |
|       $lname = strtolower($name);
 | |
|       $attribute = ValueException::check_nn(
 | |
|         A::get($this->attributes, $lname)
 | |
|         , "$name: attribut non défini");
 | |
|       $syntax = ValueException::check_nn(
 | |
|         A::get($this->syntaxes, $attribute["syntax"])
 | |
|         , "$attribute[syntax]: syntaxe non définie");
 | |
|       $class = $attribute["class"];
 | |
|       $monovalued = $attribute["single_value"]? LdapAttr::MONOVALUED: 0;
 | |
|       $binary = $syntax["x_binary_transfer_required"]? LdapAttr::BINARY: 0;
 | |
|       $ordered = $attribute["x_ordered"]? LdapAttr::ORDERED: 0;
 | |
|       $notHumanReadable = $syntax["x_not_human_readable"]? LdapAttr::NOT_HUMAN_READABLE: 0;
 | |
|       $flags = $monovalued + $binary + $ordered + $notHumanReadable;
 | |
|       $override = A::get($overrides, $name);
 | |
|       if ($override !== null) {
 | |
|         if ($override["class"] !== null) $class = $override["class"];
 | |
|         if ($override["set"] !== null) $flags = $flags | $override["set"];
 | |
|         if ($override["reset"] !== null) $flags = $flags & ~$override["reset"];
 | |
|       }
 | |
|       $attributes[$lname] = [
 | |
|         "name" => $name,
 | |
|         "class" => $class,
 | |
|         "flags" => $flags,
 | |
|       ];
 | |
|     }
 | |
|     return $attributes;
 | |
|   }
 | |
| }
 |