Compare commits
8 Commits
b87b1dcfd0
...
3b2a4a7752
Author | SHA1 | Date | |
---|---|---|---|
3b2a4a7752 | |||
089c3e5b97 | |||
acf19cdc5b | |||
56fcd729e7 | |||
d61f6168a4 | |||
f2eaed247a | |||
31e3c75bc9 | |||
9f0290bd40 |
@ -7,6 +7,7 @@ use Illuminate\Support\Arr;
|
|||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
use App\Classes\LDAP\Schema\AttributeType;
|
use App\Classes\LDAP\Schema\AttributeType;
|
||||||
|
use App\Exceptions\InvalidUsage;
|
||||||
use App\Ldap\Entry;
|
use App\Ldap\Entry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -14,9 +15,6 @@ use App\Ldap\Entry;
|
|||||||
*/
|
*/
|
||||||
class Attribute implements \Countable, \ArrayAccess
|
class Attribute implements \Countable, \ArrayAccess
|
||||||
{
|
{
|
||||||
// Attribute Name
|
|
||||||
protected string $name;
|
|
||||||
|
|
||||||
// Is this attribute an internal attribute
|
// Is this attribute an internal attribute
|
||||||
protected ?bool $_is_internal = NULL;
|
protected ?bool $_is_internal = NULL;
|
||||||
protected(set) bool $no_attr_tags = FALSE;
|
protected(set) bool $no_attr_tags = FALSE;
|
||||||
@ -98,11 +96,11 @@ class Attribute implements \Countable, \ArrayAccess
|
|||||||
* @param string $name Name of the attribute
|
* @param string $name Name of the attribute
|
||||||
* @param array $values Current Values
|
* @param array $values Current Values
|
||||||
* @param array $oc The objectclasses that the DN of this attribute has
|
* @param array $oc The objectclasses that the DN of this attribute has
|
||||||
|
* @throws InvalidUsage
|
||||||
*/
|
*/
|
||||||
public function __construct(string $dn,string $name,array $values,array $oc=[])
|
public function __construct(string $dn,string $name,array $values,array $oc=[])
|
||||||
{
|
{
|
||||||
$this->dn = $dn;
|
$this->dn = $dn;
|
||||||
$this->name = $name;
|
|
||||||
$this->_values = collect($values);
|
$this->_values = collect($values);
|
||||||
$this->_values_old = collect($values);
|
$this->_values_old = collect($values);
|
||||||
|
|
||||||
@ -113,8 +111,12 @@ class Attribute implements \Countable, \ArrayAccess
|
|||||||
|
|
||||||
// Get the objectclass heirarchy for required attribute determination
|
// Get the objectclass heirarchy for required attribute determination
|
||||||
foreach ($oc as $objectclass) {
|
foreach ($oc as $objectclass) {
|
||||||
$this->oc->push($objectclass);
|
$soc = config('server')->schema('objectclasses',$objectclass);
|
||||||
$this->oc = $this->oc->merge(config('server')->schema('objectclasses',$objectclass)->getParents()->pluck('name'));
|
|
||||||
|
if ($soc) {
|
||||||
|
$this->oc->push($soc->oid);
|
||||||
|
$this->oc = $this->oc->merge($soc->getParents()->pluck('oid'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -140,8 +142,6 @@ class Attribute implements \Countable, \ArrayAccess
|
|||||||
public function __get(string $key): mixed
|
public function __get(string $key): mixed
|
||||||
{
|
{
|
||||||
return match ($key) {
|
return match ($key) {
|
||||||
// List all the attributes
|
|
||||||
'attributes' => $this->attributes(),
|
|
||||||
// Can this attribute have more values
|
// Can this attribute have more values
|
||||||
'can_addvalues' => $this->schema && (! $this->schema->is_single_value) && ((! $this->max_values_count) || ($this->values->count() < $this->max_values_count)),
|
'can_addvalues' => $this->schema && (! $this->schema->is_single_value) && ((! $this->max_values_count) || ($this->values->count() < $this->max_values_count)),
|
||||||
// Schema attribute description
|
// Schema attribute description
|
||||||
@ -164,7 +164,7 @@ class Attribute implements \Countable, \ArrayAccess
|
|||||||
// Is this attribute an RDN attribute
|
// Is this attribute an RDN attribute
|
||||||
'is_rdn' => $this->isRDN(),
|
'is_rdn' => $this->isRDN(),
|
||||||
// We prefer the name as per the schema if it exists
|
// We prefer the name as per the schema if it exists
|
||||||
'name' => $this->schema ? $this->schema->{$key} : $this->{$key},
|
'name' => $this->schema->{$key},
|
||||||
// Attribute name in lower case
|
// Attribute name in lower case
|
||||||
'name_lc' => strtolower($this->name),
|
'name_lc' => strtolower($this->name),
|
||||||
// Required by Object Classes
|
// Required by Object Classes
|
||||||
@ -268,9 +268,6 @@ class Attribute implements \Countable, \ArrayAccess
|
|||||||
if ($this->is_rdn)
|
if ($this->is_rdn)
|
||||||
$result->put(__('rdn'),__('This attribute is required for the RDN'));
|
$result->put(__('rdn'),__('This attribute is required for the RDN'));
|
||||||
|
|
||||||
// If this attribute name is an alias for the schema attribute name
|
|
||||||
// @todo
|
|
||||||
|
|
||||||
if ($this->required()->count())
|
if ($this->required()->count())
|
||||||
$result->put(__('required'),sprintf('%s: %s',__('Required Attribute by ObjectClass(es)'),$this->required()->join(', ')));
|
$result->put(__('required'),sprintf('%s: %s',__('Required Attribute by ObjectClass(es)'),$this->required()->join(', ')));
|
||||||
|
|
||||||
@ -302,7 +299,7 @@ class Attribute implements \Countable, \ArrayAccess
|
|||||||
{
|
{
|
||||||
return $this->schema->used_in_object_classes
|
return $this->schema->used_in_object_classes
|
||||||
->keys()
|
->keys()
|
||||||
->intersect($this->schema->heirachy($this->oc))
|
->intersect($this->oc)
|
||||||
->count() === 0;
|
->count() === 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -329,9 +326,10 @@ class Attribute implements \Countable, \ArrayAccess
|
|||||||
* @param bool $old Use old value
|
* @param bool $old Use old value
|
||||||
* @param bool $new Enable adding values
|
* @param bool $new Enable adding values
|
||||||
* @param bool $updated Has the entry been updated (uses rendering highlights))
|
* @param bool $updated Has the entry been updated (uses rendering highlights))
|
||||||
|
* @param string|null $template
|
||||||
* @return View
|
* @return View
|
||||||
*/
|
*/
|
||||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE): View
|
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE,?string $template=NULL): View
|
||||||
{
|
{
|
||||||
if ($this->is_internal)
|
if ($this->is_internal)
|
||||||
// @note Internal attributes cannot be edited
|
// @note Internal attributes cannot be edited
|
||||||
@ -352,6 +350,7 @@ class Attribute implements \Countable, \ArrayAccess
|
|||||||
->with('edit',$edit)
|
->with('edit',$edit)
|
||||||
->with('old',$old)
|
->with('old',$old)
|
||||||
->with('new',$new)
|
->with('new',$new)
|
||||||
|
->with('template',$template)
|
||||||
->with('updated',$updated);
|
->with('updated',$updated);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ final class JpegPhoto extends Binary
|
|||||||
{
|
{
|
||||||
use MD5Updates;
|
use MD5Updates;
|
||||||
|
|
||||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE): View
|
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE,?string $template=NULL): View
|
||||||
{
|
{
|
||||||
return view('components.attribute.binary.jpegphoto')
|
return view('components.attribute.binary.jpegphoto')
|
||||||
->with('o',$this)
|
->with('o',$this)
|
||||||
|
@ -59,8 +59,6 @@ class Factory
|
|||||||
public static function create(string $dn,string $attribute,array $values,array $oc=[]): Attribute
|
public static function create(string $dn,string $attribute,array $values,array $oc=[]): Attribute
|
||||||
{
|
{
|
||||||
$class = Arr::get(self::map,strtolower($attribute),Attribute::class);
|
$class = Arr::get(self::map,strtolower($attribute),Attribute::class);
|
||||||
Log::debug(sprintf('%s:Creating LDAP Attribute [%s] as [%s]',static::LOGKEY,$attribute,$class));
|
|
||||||
|
|
||||||
return new $class($dn,$attribute,$values,$oc);
|
return new $class($dn,$attribute,$values,$oc);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -12,7 +12,7 @@ use App\Ldap\Entry;
|
|||||||
*/
|
*/
|
||||||
final class Timestamp extends Internal
|
final class Timestamp extends Internal
|
||||||
{
|
{
|
||||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE): View
|
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE,?string $template=NULL): View
|
||||||
{
|
{
|
||||||
// @note Internal attributes cannot be edited
|
// @note Internal attributes cannot be edited
|
||||||
return view('components.attribute.internal.timestamp')
|
return view('components.attribute.internal.timestamp')
|
||||||
|
@ -17,7 +17,7 @@ final class KrbPrincipalKey extends Attribute
|
|||||||
|
|
||||||
protected(set) bool $no_attr_tags = TRUE;
|
protected(set) bool $no_attr_tags = TRUE;
|
||||||
|
|
||||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE): View
|
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE,?string $template=NULL): View
|
||||||
{
|
{
|
||||||
return view('components.attribute.krbprincipalkey')
|
return view('components.attribute.krbprincipalkey')
|
||||||
->with('o',$this)
|
->with('o',$this)
|
||||||
|
@ -50,7 +50,7 @@ final class KrbTicketFlags extends Attribute
|
|||||||
return $helpers;
|
return $helpers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE): View
|
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE,?string $template=NULL): View
|
||||||
{
|
{
|
||||||
return view('components.attribute.krbticketflags')
|
return view('components.attribute.krbticketflags')
|
||||||
->with('o',$this)
|
->with('o',$this)
|
||||||
|
@ -70,7 +70,7 @@ final class ObjectClass extends Attribute
|
|||||||
->contains($value);
|
->contains($value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE): View
|
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE,?string $template=NULL): View
|
||||||
{
|
{
|
||||||
return view('components.attribute.objectclass')
|
return view('components.attribute.objectclass')
|
||||||
->with('o',$this)
|
->with('o',$this)
|
||||||
|
@ -80,13 +80,14 @@ final class Password extends Attribute
|
|||||||
return ($helpers=static::helpers())->has($id) ? new ($helpers->get($id)) : NULL;
|
return ($helpers=static::helpers())->has($id) ? new ($helpers->get($id)) : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE): View
|
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE,?string $template=NULL): View
|
||||||
{
|
{
|
||||||
return view('components.attribute.password')
|
return view('components.attribute.password')
|
||||||
->with('o',$this)
|
->with('o',$this)
|
||||||
->with('edit',$edit)
|
->with('edit',$edit)
|
||||||
->with('old',$old)
|
->with('old',$old)
|
||||||
->with('new',$new)
|
->with('new',$new)
|
||||||
|
->with('template',$template)
|
||||||
->with('updated',$updated)
|
->with('updated',$updated)
|
||||||
->with('helpers',static::helpers()->map(fn($item,$key)=>['id'=>$key,'value'=>$key])->sort());
|
->with('helpers',static::helpers()->map(fn($item,$key)=>['id'=>$key,'value'=>$key])->sort());
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ final class RDN extends Attribute
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE): View
|
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE,?string $template=NULL): View
|
||||||
{
|
{
|
||||||
return view('components.attribute.rdn')
|
return view('components.attribute.rdn')
|
||||||
->with('o',$this);
|
->with('o',$this);
|
||||||
|
@ -53,11 +53,4 @@ abstract class Schema extends Attribute
|
|||||||
$key,
|
$key,
|
||||||
__('No description available, can you help with one?'));
|
__('No description available, can you help with one?'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE): View
|
|
||||||
{
|
|
||||||
// @note Schema attributes cannot be edited
|
|
||||||
return view('components.attribute.internal')
|
|
||||||
->with('o',$this);
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -12,7 +12,7 @@ use App\Ldap\Entry;
|
|||||||
*/
|
*/
|
||||||
class Generic extends Schema
|
class Generic extends Schema
|
||||||
{
|
{
|
||||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE): View
|
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE,?string $template=NULL): View
|
||||||
{
|
{
|
||||||
// @note Schema attributes cannot be edited
|
// @note Schema attributes cannot be edited
|
||||||
return view('components.attribute.schema.generic')
|
return view('components.attribute.schema.generic')
|
||||||
|
@ -34,7 +34,7 @@ final class Mechanisms extends Schema
|
|||||||
return parent::_get(config_path('ldap_supported_saslmechanisms.txt'),$string,$key);
|
return parent::_get(config_path('ldap_supported_saslmechanisms.txt'),$string,$key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE): View
|
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE,?string $template=NULL): View
|
||||||
{
|
{
|
||||||
// @note Schema attributes cannot be edited
|
// @note Schema attributes cannot be edited
|
||||||
return view('components.attribute.schema.mechanisms')
|
return view('components.attribute.schema.mechanisms')
|
||||||
|
@ -35,7 +35,7 @@ final class OID extends Schema
|
|||||||
return parent::_get(config_path('ldap_supported_oids.txt'),$string,$key);
|
return parent::_get(config_path('ldap_supported_oids.txt'),$string,$key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE): View
|
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE,?string $template=NULL): View
|
||||||
{
|
{
|
||||||
// @note Schema attributes cannot be edited
|
// @note Schema attributes cannot be edited
|
||||||
return view('components.attribute.schema.oid')
|
return view('components.attribute.schema.oid')
|
||||||
|
@ -7,304 +7,74 @@ use Illuminate\Support\Collection;
|
|||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
use App\Classes\LDAP\Attribute;
|
use App\Classes\LDAP\Attribute;
|
||||||
|
use App\Exceptions\InvalidUsage;
|
||||||
use App\Ldap\Entry;
|
use App\Ldap\Entry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an LDAP AttributeType
|
* Represents an LDAP AttributeType
|
||||||
*
|
|
||||||
* @package phpLDAPadmin
|
|
||||||
* @subpackage Schema
|
|
||||||
*/
|
*/
|
||||||
final class AttributeType extends Base {
|
final class AttributeType extends Base
|
||||||
// The attribute from which this attribute inherits (if any)
|
{
|
||||||
private ?string $sup_attribute = NULL;
|
private const LOGKEY = 'SAT';
|
||||||
|
|
||||||
// Array of AttributeTypes which inherit from this one
|
// An array of AttributeTypes which inherit from this one
|
||||||
private Collection $children;
|
private(set) Collection $children;
|
||||||
|
|
||||||
// The equality rule used
|
// The equality rule used
|
||||||
private ?string $equality = NULL;
|
private(set) ?string $equality = NULL;
|
||||||
|
|
||||||
// The ordering of the attributeType
|
|
||||||
private ?string $ordering = NULL;
|
|
||||||
|
|
||||||
// Supports substring matching?
|
|
||||||
private ?string $sub_str_rule = NULL;
|
|
||||||
|
|
||||||
// The full syntax string, ie 1.2.3.4{16}
|
|
||||||
private ?string $syntax = NULL;
|
|
||||||
private ?string $syntax_oid = NULL;
|
|
||||||
|
|
||||||
// boolean: is single valued only?
|
|
||||||
private bool $is_single_value = FALSE;
|
|
||||||
|
|
||||||
// boolean: is collective?
|
|
||||||
private bool $is_collective = FALSE;
|
|
||||||
|
|
||||||
// boolean: can use modify?
|
|
||||||
private bool $is_no_user_modification = FALSE;
|
|
||||||
|
|
||||||
// The usage string set by the LDAP schema
|
|
||||||
private ?string $usage = NULL;
|
|
||||||
|
|
||||||
// An array of alias attribute names, strings
|
|
||||||
private Collection $aliases;
|
|
||||||
|
|
||||||
// The max number of characters this attribute can be
|
|
||||||
private ?int $max_length = NULL;
|
|
||||||
|
|
||||||
// A string description of the syntax type (taken from the LDAPSyntaxes)
|
|
||||||
/**
|
|
||||||
* @deprecated - reference syntaxes directly if possible
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private ?string $type = NULL;
|
|
||||||
|
|
||||||
// An array of objectClasses which use this attributeType (must be set by caller)
|
|
||||||
private Collection $used_in_object_classes;
|
|
||||||
|
|
||||||
// A list of object class names that require this attribute type.
|
|
||||||
private Collection $required_by_object_classes;
|
|
||||||
|
|
||||||
// This attribute has been forced a MAY attribute by the configuration.
|
// This attribute has been forced a MAY attribute by the configuration.
|
||||||
private bool $forced_as_may = FALSE;
|
private(set) bool $forced_as_may = FALSE;
|
||||||
|
|
||||||
/**
|
// boolean: is collective?
|
||||||
* Creates a new AttributeType object from a raw LDAP AttributeType string.
|
private(set) bool $is_collective = FALSE;
|
||||||
*
|
|
||||||
* eg: ( 2.5.4.0 NAME 'objectClass' DESC 'RFC4512: object classes of the entity' EQUALITY objectIdentifierMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )
|
|
||||||
*/
|
|
||||||
public function __construct(string $line) {
|
|
||||||
if (static::DEBUG_VERBOSE)
|
|
||||||
Log::debug(sprintf('Parsing AttributeType [%s]',$line));
|
|
||||||
|
|
||||||
parent::__construct($line);
|
// Is this a must attribute
|
||||||
|
private(set) bool $is_must = FALSE;
|
||||||
|
|
||||||
$strings = preg_split('/[\s,]+/',$line,-1,PREG_SPLIT_DELIM_CAPTURE);
|
// boolean: can use modify?
|
||||||
|
private(set) bool $is_no_user_modification = FALSE;
|
||||||
|
|
||||||
// Init
|
// boolean: is single valued only?
|
||||||
$this->children = collect();
|
private(set) bool $is_single_value = FALSE;
|
||||||
$this->aliases = collect();
|
|
||||||
$this->used_in_object_classes = collect();
|
|
||||||
$this->required_by_object_classes = collect();
|
|
||||||
|
|
||||||
for ($i=0; $i < count($strings); $i++) {
|
// The max number of characters this attribute can be
|
||||||
switch ($strings[$i]) {
|
private(set) ?int $max_length = NULL;
|
||||||
case '(':
|
|
||||||
case ')':
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'NAME':
|
// An array of names (including aliases) that this attribute is known by
|
||||||
// @note Some schema's return a (' instead of a ( '
|
private(set) Collection $names;
|
||||||
if ($strings[$i+1] != '(' && ! preg_match('/^\(/',$strings[$i+1])) {
|
|
||||||
do {
|
|
||||||
$this->name .= ($this->name ? ' ' : '').$strings[++$i];
|
|
||||||
|
|
||||||
} while (! preg_match("/\'$/s",$strings[$i]));
|
// The ordering of the attributeType
|
||||||
|
private(set) ?string $ordering = NULL;
|
||||||
|
|
||||||
// This attribute has no aliases
|
// A list of object class names that require this attribute type.
|
||||||
//$this->aliases = collect();
|
private(set) Collection $required_by_object_classes;
|
||||||
|
|
||||||
} else {
|
// Which objectclass is defining this attribute for an Entry
|
||||||
$i++;
|
public ?string $source = NULL;
|
||||||
|
|
||||||
do {
|
// Supports substring matching?
|
||||||
// In case we came here becaues of a ('
|
private(set) ?string $sub_str_rule = NULL;
|
||||||
if (preg_match('/^\(/',$strings[$i]))
|
|
||||||
$strings[$i] = preg_replace('/^\(/','',$strings[$i]);
|
|
||||||
else
|
|
||||||
$i++;
|
|
||||||
|
|
||||||
$this->name .= ($this->name ? ' ' : '').$strings[++$i];
|
// The attribute from which this attribute inherits (if any)
|
||||||
|
private(set) ?string $sup_attribute = NULL;
|
||||||
|
|
||||||
} while (! preg_match("/\'$/s",$strings[$i]));
|
// The full syntax string, ie 1.2.3.4{16}
|
||||||
|
private(set) ?string $syntax = NULL;
|
||||||
|
private(set) ?string $syntax_oid = NULL;
|
||||||
|
|
||||||
// Add alias names for this attribute
|
// The usage string set by the LDAP schema
|
||||||
while ($strings[++$i] != ')') {
|
private(set) ?string $usage = NULL;
|
||||||
$alias = $strings[$i];
|
|
||||||
$alias = preg_replace("/^\'(.*)\'$/",'$1',$alias);
|
|
||||||
$this->addAlias($alias);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->name = preg_replace("/^\'(.*)\'$/",'$1',$this->name);
|
// An array of objectClasses which use this attributeType (must be set by caller)
|
||||||
|
private(set) Collection $used_in_object_classes;
|
||||||
if (static::DEBUG_VERBOSE)
|
|
||||||
Log::debug(sprintf('- Case NAME returned (%s)',$this->name),['aliases'=>$this->aliases]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'DESC':
|
|
||||||
do {
|
|
||||||
$this->description .= ($this->description ? ' ' : '').$strings[++$i];
|
|
||||||
|
|
||||||
} while (! preg_match("/\'$/s",$strings[$i]));
|
|
||||||
|
|
||||||
$this->description = preg_replace("/^\'(.*)\'$/",'$1',$this->description);
|
|
||||||
|
|
||||||
if (static::DEBUG_VERBOSE)
|
|
||||||
Log::debug(sprintf('- Case DESC returned (%s)',$this->description));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'OBSOLETE':
|
|
||||||
$this->is_obsolete = TRUE;
|
|
||||||
|
|
||||||
if (static::DEBUG_VERBOSE)
|
|
||||||
Log::debug(sprintf('- Case OBSOLETE returned (%s)',$this->is_obsolete));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'SUP':
|
|
||||||
$i++;
|
|
||||||
$this->sup_attribute = preg_replace("/^\'(.*)\'$/",'$1',$strings[$i]);
|
|
||||||
|
|
||||||
if (static::DEBUG_VERBOSE)
|
|
||||||
Log::debug(sprintf('- Case SUP returned (%s)',$this->sup_attribute));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'EQUALITY':
|
|
||||||
$this->equality = $strings[++$i];
|
|
||||||
|
|
||||||
if (static::DEBUG_VERBOSE)
|
|
||||||
Log::debug(sprintf('- Case EQUALITY returned (%s)',$this->equality));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'ORDERING':
|
|
||||||
$this->ordering = $strings[++$i];
|
|
||||||
|
|
||||||
if (static::DEBUG_VERBOSE)
|
|
||||||
Log::debug(sprintf('- Case ORDERING returned (%s)',$this->ordering));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'SUBSTR':
|
|
||||||
$this->sub_str_rule = $strings[++$i];
|
|
||||||
|
|
||||||
if (static::DEBUG_VERBOSE)
|
|
||||||
Log::debug(sprintf('- Case SUBSTR returned (%s)',$this->sub_str_rule));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'SYNTAX':
|
|
||||||
$this->syntax = $strings[++$i];
|
|
||||||
$this->syntax_oid = preg_replace('/{\d+}$/','',$this->syntax);
|
|
||||||
if (static::DEBUG_VERBOSE)
|
|
||||||
Log::debug(sprintf('/ Evaluating SYNTAX returned (%s) [%s]',$this->syntax,$this->syntax_oid));
|
|
||||||
|
|
||||||
// Does this SYNTAX string specify a max length (ie, 1.2.3.4{16})
|
|
||||||
$m = [];
|
|
||||||
if (preg_match('/{(\d+)}$/',$this->syntax,$m))
|
|
||||||
$this->max_length = $m[1];
|
|
||||||
else
|
|
||||||
$this->max_length = NULL;
|
|
||||||
|
|
||||||
if ($i < count($strings) - 1 && $strings[$i+1] == '{')
|
|
||||||
do {
|
|
||||||
$this->name .= ' '.$strings[++$i];
|
|
||||||
} while ($strings[$i] != '}');
|
|
||||||
|
|
||||||
$this->syntax = preg_replace("/^\'(.*)\'$/",'$1',$this->syntax);
|
|
||||||
$this->syntax_oid = preg_replace("/^\'(.*)\'$/",'$1',$this->syntax_oid);
|
|
||||||
|
|
||||||
if (static::DEBUG_VERBOSE)
|
|
||||||
Log::debug(sprintf('- Case SYNTAX returned (%s) [%s] {%d}',$this->syntax,$this->syntax_oid,$this->max_length));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'SINGLE-VALUE':
|
|
||||||
$this->is_single_value = TRUE;
|
|
||||||
|
|
||||||
if (static::DEBUG_VERBOSE)
|
|
||||||
Log::debug(sprintf('- Case SINGLE-VALUE returned (%s)',$this->is_single_value));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'COLLECTIVE':
|
|
||||||
$this->is_collective = TRUE;
|
|
||||||
|
|
||||||
if (static::DEBUG_VERBOSE)
|
|
||||||
Log::debug(sprintf('- Case COLLECTIVE returned (%s)',$this->is_collective));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'NO-USER-MODIFICATION':
|
|
||||||
$this->is_no_user_modification = TRUE;
|
|
||||||
|
|
||||||
if (static::DEBUG_VERBOSE)
|
|
||||||
Log::debug(sprintf('- Case NO-USER-MODIFICATION returned (%s)',$this->is_no_user_modification));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'USAGE':
|
|
||||||
$this->usage = $strings[++$i];
|
|
||||||
|
|
||||||
if (static::DEBUG_VERBOSE)
|
|
||||||
Log::debug(sprintf('- Case USAGE returned (%s)',$this->usage));
|
|
||||||
break;
|
|
||||||
|
|
||||||
// @note currently not captured
|
|
||||||
case 'X-ORDERED':
|
|
||||||
if (static::DEBUG_VERBOSE)
|
|
||||||
Log::error(sprintf('- Case X-ORDERED returned (%s)',$strings[++$i]));
|
|
||||||
break;
|
|
||||||
|
|
||||||
// @note currently not captured
|
|
||||||
case 'X-ORIGIN':
|
|
||||||
$value = '';
|
|
||||||
|
|
||||||
do {
|
|
||||||
$value .= ($value ? ' ' : '').$strings[++$i];
|
|
||||||
|
|
||||||
} while (! preg_match("/\'$/s",$strings[$i]));
|
|
||||||
|
|
||||||
if (static::DEBUG_VERBOSE)
|
|
||||||
Log::error(sprintf('- Case X-ORIGIN returned (%s)',$value));
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
if (preg_match('/[\d\.]+/i',$strings[$i]) && ($i === 1)) {
|
|
||||||
$this->oid = $strings[$i];
|
|
||||||
if (static::DEBUG_VERBOSE)
|
|
||||||
Log::debug(sprintf('- Case default returned (%s)',$this->oid));
|
|
||||||
|
|
||||||
} elseif ($strings[$i])
|
|
||||||
Log::alert(sprintf('! Case default discovered a value NOT parsed (%s)',$strings[$i]),['line'=>$line]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __clone()
|
|
||||||
{
|
|
||||||
// When we clone, we need to break the reference too
|
|
||||||
$this->aliases = clone $this->aliases;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __get(string $key): mixed
|
public function __get(string $key): mixed
|
||||||
{
|
{
|
||||||
switch ($key) {
|
return match ($key) {
|
||||||
case 'aliases': return $this->aliases;
|
'names_lc' => $this->names->map('strtolower'),
|
||||||
case 'children': return $this->children;
|
default => parent::__get($key)
|
||||||
case 'forced_as_may': return $this->forced_as_may;
|
};
|
||||||
case 'is_collective': return $this->is_collective;
|
|
||||||
case 'is_editable': return ! $this->is_no_user_modification;
|
|
||||||
case 'is_no_user_modification': return $this->is_no_user_modification;
|
|
||||||
case 'is_single_value': return $this->is_single_value;
|
|
||||||
case 'equality': return $this->equality;
|
|
||||||
case 'max_length': return $this->max_length;
|
|
||||||
case 'ordering': return $this->ordering;
|
|
||||||
case 'required_by_object_classes': return $this->required_by_object_classes;
|
|
||||||
case 'sub_str_rule': return $this->sub_str_rule;
|
|
||||||
case 'sup_attribute': return $this->sup_attribute;
|
|
||||||
case 'syntax': return $this->syntax;
|
|
||||||
case 'syntax_oid': return $this->syntax_oid;
|
|
||||||
case 'type': return $this->type;
|
|
||||||
case 'usage': return $this->usage;
|
|
||||||
case 'used_in_object_classes': return $this->used_in_object_classes;
|
|
||||||
|
|
||||||
default: return parent::__get($key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an attribute name to the alias array.
|
|
||||||
*
|
|
||||||
* @param string $alias The name of a new attribute to add to this attribute's list of aliases.
|
|
||||||
*/
|
|
||||||
public function addAlias(string $alias): void
|
|
||||||
{
|
|
||||||
$this->aliases->push($alias);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -315,7 +85,8 @@ final class AttributeType extends Base {
|
|||||||
*/
|
*/
|
||||||
public function addChild(string $child): void
|
public function addChild(string $child): void
|
||||||
{
|
{
|
||||||
$this->children->push($child);
|
$this->children
|
||||||
|
->push($child);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -346,144 +117,10 @@ final class AttributeType extends Base {
|
|||||||
|
|
||||||
private function factory(): Attribute
|
private function factory(): Attribute
|
||||||
{
|
{
|
||||||
return Attribute\Factory::create(dn:'',attribute:$this->name,values:[]);
|
return Attribute\Factory::create(
|
||||||
}
|
dn:'',
|
||||||
|
attribute:$this->name,
|
||||||
/**
|
values:[]);
|
||||||
* Gets the names of attributes that are an alias for this attribute (if any).
|
|
||||||
*
|
|
||||||
* @return Collection An array of names of attributes which alias this attribute or
|
|
||||||
* an empty array if no attribute aliases this object.
|
|
||||||
* @deprecated use class->aliases
|
|
||||||
*/
|
|
||||||
public function getAliases(): Collection
|
|
||||||
{
|
|
||||||
return $this->aliases;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets this attribute's equality string
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
* @deprecated use $this->equality
|
|
||||||
*/
|
|
||||||
public function getEquality()
|
|
||||||
{
|
|
||||||
return $this->equality;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets whether this attribute is collective.
|
|
||||||
*
|
|
||||||
* @return boolean Returns TRUE if this attribute is collective and FALSE otherwise.
|
|
||||||
* @deprecated use $this->is_collective
|
|
||||||
*/
|
|
||||||
public function getIsCollective(): bool
|
|
||||||
{
|
|
||||||
return $this->is_collective;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets whether this attribute is not modifiable by users.
|
|
||||||
*
|
|
||||||
* @return boolean Returns TRUE if this attribute is not modifiable by users.
|
|
||||||
* @deprecated use $this->is_no_user_modification
|
|
||||||
*/
|
|
||||||
public function getIsNoUserModification(): bool
|
|
||||||
{
|
|
||||||
return $this->is_no_user_modification;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets whether this attribute is single-valued. If this attribute only supports single values, TRUE
|
|
||||||
* is returned. If this attribute supports multiple values, FALSE is returned.
|
|
||||||
*
|
|
||||||
* @return boolean Returns TRUE if this attribute is single-valued or FALSE otherwise.
|
|
||||||
* @deprecated use class->is_single_value
|
|
||||||
*/
|
|
||||||
public function getIsSingleValue(): bool
|
|
||||||
{
|
|
||||||
return $this->is_single_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets this attribute's the maximum length. If no maximum is defined by the LDAP server, NULL is returned.
|
|
||||||
*
|
|
||||||
* @return int The maximum length (in characters) of this attribute or NULL if no maximum is specified.
|
|
||||||
* @deprecated use $this->max_length;
|
|
||||||
*/
|
|
||||||
public function getMaxLength()
|
|
||||||
{
|
|
||||||
return $this->max_length;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets this attribute's ordering specification.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
* @deprecated use $this->ordering
|
|
||||||
*/
|
|
||||||
public function getOrdering(): string
|
|
||||||
{
|
|
||||||
return $this->ordering;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets this attribute's substring matching specification
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
* @deprecated use $this->sub_str_rule;
|
|
||||||
*/
|
|
||||||
public function getSubstr() {
|
|
||||||
return $this->sub_str_rule;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets this attribute's parent attribute (if any). If this attribute does not
|
|
||||||
* inherit from another attribute, NULL is returned.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
* @deprecated use $class->sup_attribute directly
|
|
||||||
*/
|
|
||||||
public function getSupAttribute() {
|
|
||||||
return $this->sup_attribute;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets this attribute's syntax OID. Differs from getSyntaxString() in that this
|
|
||||||
* function only returns the actual OID with any length specification removed.
|
|
||||||
* Ie, if the syntax string is "1.2.3.4{16}", this function only retruns
|
|
||||||
* "1.2.3.4".
|
|
||||||
*
|
|
||||||
* @return string The syntax OID string.
|
|
||||||
* @deprecated use $this->syntax_oid;
|
|
||||||
*/
|
|
||||||
public function getSyntaxOID()
|
|
||||||
{
|
|
||||||
return $this->syntax_oid;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets this attribute's usage string as defined by the LDAP server
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
* @deprecated use $this->usage
|
|
||||||
*/
|
|
||||||
public function getUsage()
|
|
||||||
{
|
|
||||||
return $this->usage;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the list of "used in" objectClasses, that is the list of objectClasses
|
|
||||||
* which provide this attribute.
|
|
||||||
*
|
|
||||||
* @return Collection An array of names of objectclasses (strings) which provide this attribute
|
|
||||||
* @deprecated use $this->used_in_object_classes
|
|
||||||
*/
|
|
||||||
public function getUsedInObjectClasses(): Collection
|
|
||||||
{
|
|
||||||
return $this->used_in_object_classes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -492,58 +129,162 @@ final class AttributeType extends Base {
|
|||||||
* @param Collection $ocs
|
* @param Collection $ocs
|
||||||
* @return Collection
|
* @return Collection
|
||||||
*/
|
*/
|
||||||
public function heirachy(Collection $ocs): Collection
|
private function heirachy(Collection $ocs): Collection
|
||||||
{
|
{
|
||||||
$result = collect();
|
$result = collect();
|
||||||
|
|
||||||
foreach ($ocs as $oc) {
|
foreach ($ocs as $oc) {
|
||||||
$schema = config('server')
|
$item = config('server')
|
||||||
->schema('objectclasses',$oc)
|
->schema('objectclasses',$oc);
|
||||||
->getParents(TRUE)
|
|
||||||
->pluck('name');
|
|
||||||
|
|
||||||
$result = $result->merge($schema)->push($oc);
|
$result = $result
|
||||||
|
->merge($item
|
||||||
|
->getParents(TRUE)
|
||||||
|
->pluck('oid'))
|
||||||
|
->push($item->oid);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return bool
|
* Creates a new AttributeType object from a raw LDAP AttributeType string.
|
||||||
* @deprecated use $this->forced_as_may
|
|
||||||
*/
|
|
||||||
public function isForceMay(): bool
|
|
||||||
{
|
|
||||||
return $this->forced_as_may;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes an attribute name from this attribute's alias array.
|
|
||||||
*
|
*
|
||||||
* @param string $alias The name of the attribute to remove.
|
* eg: ( 2.5.4.0 NAME 'objectClass' DESC 'RFC4512: object classes of the entity' EQUALITY objectIdentifierMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )
|
||||||
*/
|
*/
|
||||||
public function removeAlias(string $alias): void
|
protected function parse(string $line): void
|
||||||
{
|
{
|
||||||
if (($x=$this->aliases->search($alias)) !== FALSE)
|
Log::debug(sprintf('%s:Parsing AttributeType [%s]',self::LOGKEY,$line));
|
||||||
$this->aliases->forget($x);
|
|
||||||
|
// Init
|
||||||
|
$this->names = collect();
|
||||||
|
$this->children = collect();
|
||||||
|
$this->used_in_object_classes = collect();
|
||||||
|
$this->required_by_object_classes = collect();
|
||||||
|
|
||||||
|
parent::parse($line);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected function parse_chunk(array $strings,int &$i): void
|
||||||
* Sets this attribute's list of aliases.
|
|
||||||
*
|
|
||||||
* @param Collection $aliases The array of alias names (strings)
|
|
||||||
* @deprecated use $this->aliases =
|
|
||||||
*/
|
|
||||||
public function setAliases(Collection $aliases): void
|
|
||||||
{
|
{
|
||||||
$this->aliases = $aliases;
|
switch ($strings[$i]) {
|
||||||
|
case 'NAME':
|
||||||
|
$name = '';
|
||||||
|
|
||||||
|
// @note Some schema's return a (' instead of a ( '
|
||||||
|
// @note This attribute format has no aliases
|
||||||
|
if ($strings[$i+1] !== '(' && ! preg_match('/^\(/',$strings[$i+1])) {
|
||||||
|
do {
|
||||||
|
$name .= ($name ? ' ' : '').$strings[++$i];
|
||||||
|
|
||||||
|
} while (! preg_match("/\'$/s",$strings[$i]));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$i++;
|
||||||
|
|
||||||
|
do {
|
||||||
|
// In case we came here because of a ('
|
||||||
|
if (preg_match('/^\(/',$strings[$i]))
|
||||||
|
$strings[$i] = preg_replace('/^\(/','',$strings[$i]);
|
||||||
|
else
|
||||||
|
$i++;
|
||||||
|
|
||||||
|
$name .= ($name ? ' ' : '').$strings[++$i];
|
||||||
|
|
||||||
|
} while (! preg_match("/\'$/s",$strings[$i]));
|
||||||
|
|
||||||
|
// Add alias names for this attribute
|
||||||
|
while ($strings[++$i] !== ')') {
|
||||||
|
$alias = preg_replace("/^\'(.*)\'$/",'$1',$strings[$i]);
|
||||||
|
$this->names->push($alias);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
$this->names = $this->names->push(preg_replace("/^\'(.*)\'$/",'$1',$name))->sort();
|
||||||
* This function will mark this attribute as a forced MAY attribute
|
$this->forced_as_may = $this->names_lc
|
||||||
*/
|
->intersect(array_map('strtolower',config('pla.force_may',[])))
|
||||||
public function setForceMay() {
|
->count() > 0;
|
||||||
$this->forced_as_may = TRUE;
|
|
||||||
|
if (static::DEBUG_VERBOSE)
|
||||||
|
Log::debug(sprintf('%s:- Case NAME returned (%s)',self::LOGKEY,$this->name),['names'=>$this->names]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'SUP':
|
||||||
|
$this->sup_attribute = preg_replace("/^\'(.*)\'$/",'$1',$strings[++$i]);
|
||||||
|
|
||||||
|
if (static::DEBUG_VERBOSE)
|
||||||
|
Log::debug(sprintf('%s:- Case SUP returned (%s)',self::LOGKEY,$this->sup_attribute));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'EQUALITY':
|
||||||
|
$this->equality = $strings[++$i];
|
||||||
|
|
||||||
|
if (static::DEBUG_VERBOSE)
|
||||||
|
Log::debug(sprintf('%s:- Case EQUALITY returned (%s)',self::LOGKEY,$this->equality));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'ORDERING':
|
||||||
|
$this->ordering = $strings[++$i];
|
||||||
|
|
||||||
|
if (static::DEBUG_VERBOSE)
|
||||||
|
Log::debug(sprintf('%s:- Case ORDERING returned (%s)',self::LOGKEY,$this->ordering));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'SUBSTR':
|
||||||
|
$this->sub_str_rule = $strings[++$i];
|
||||||
|
|
||||||
|
if (static::DEBUG_VERBOSE)
|
||||||
|
Log::debug(sprintf('%s:- Case SUBSTR returned (%s)',self::LOGKEY,$this->sub_str_rule));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'SYNTAX':
|
||||||
|
$this->syntax = preg_replace("/^\'(.*)\'$/",'$1',$strings[++$i]);
|
||||||
|
$this->syntax_oid = preg_replace("/^\'?(.*){\d+}\'?$/",'$1',$this->syntax);
|
||||||
|
|
||||||
|
if (static::DEBUG_VERBOSE)
|
||||||
|
Log::debug(sprintf('%s:/ Evaluating SYNTAX returned (%s) [%s]',self::LOGKEY,$this->syntax,$this->syntax_oid));
|
||||||
|
|
||||||
|
// Does this SYNTAX string specify a max length (ie, 1.2.3.4{16})
|
||||||
|
$m = [];
|
||||||
|
$this->max_length = preg_match('/{(\d+)}$/',$this->syntax,$m)
|
||||||
|
? $m[1]
|
||||||
|
: NULL;
|
||||||
|
|
||||||
|
if (static::DEBUG_VERBOSE)
|
||||||
|
Log::debug(sprintf('%s:- Case SYNTAX returned (%s) [%s] {%d}',self::LOGKEY,$this->syntax,$this->syntax_oid,$this->max_length));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'SINGLE-VALUE':
|
||||||
|
$this->is_single_value = TRUE;
|
||||||
|
|
||||||
|
if (static::DEBUG_VERBOSE)
|
||||||
|
Log::debug(sprintf('%s:- Case SINGLE-VALUE returned (%s)',self::LOGKEY,$this->is_single_value));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'COLLECTIVE':
|
||||||
|
$this->is_collective = TRUE;
|
||||||
|
|
||||||
|
if (static::DEBUG_VERBOSE)
|
||||||
|
Log::debug(sprintf('%s:- Case COLLECTIVE returned (%s)',self::LOGKEY,$this->is_collective));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'NO-USER-MODIFICATION':
|
||||||
|
$this->is_no_user_modification = TRUE;
|
||||||
|
|
||||||
|
if (static::DEBUG_VERBOSE)
|
||||||
|
Log::debug(sprintf('%s:- Case NO-USER-MODIFICATION returned (%s)',self::LOGKEY,$this->is_no_user_modification));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'USAGE':
|
||||||
|
$this->usage = $strings[++$i];
|
||||||
|
|
||||||
|
if (static::DEBUG_VERBOSE)
|
||||||
|
Log::debug(sprintf('%s:- Case USAGE returned (%s)',self::LOGKEY,$this->usage));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
parent::parse_chunk($strings,$i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -557,13 +298,28 @@ final class AttributeType extends Base {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets this attribute's SUP attribute (ie, the attribute from which this attribute inherits).
|
* If this is a MUST attribute to the objectclass that defines it
|
||||||
*
|
*
|
||||||
* @param string $attr The name of the new parent (SUP) attribute
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function setSupAttribute(string $attr): void
|
public function setMust(): void
|
||||||
{
|
{
|
||||||
$this->sup_attribute = trim($attr);
|
$this->is_must = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets this attribute's name.
|
||||||
|
*
|
||||||
|
* @param string $name The new name to give this attribute.
|
||||||
|
* @throws InvalidUsage
|
||||||
|
*/
|
||||||
|
public function setName(string $name): void
|
||||||
|
{
|
||||||
|
// Quick validation
|
||||||
|
if ($this->names_lc->count() && (! $this->names_lc->contains(strtolower($name))))
|
||||||
|
throw new InvalidUsage(sprintf('Cannot set attribute name to [%s], its not an alias for [%s]',$name,$this->names->join(',')));
|
||||||
|
|
||||||
|
$this->name = $name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
namespace App\Classes\LDAP\Schema;
|
namespace App\Classes\LDAP\Schema;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
use App\Exceptions\InvalidUsage;
|
use App\Exceptions\InvalidUsage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -10,38 +12,38 @@ use App\Exceptions\InvalidUsage;
|
|||||||
* A schema item is an ObjectClass, an AttributeBype, a MatchingRule, or a Syntax.
|
* A schema item is an ObjectClass, an AttributeBype, a MatchingRule, or a Syntax.
|
||||||
* All schema items have at least two things in common: An OID and a Description.
|
* All schema items have at least two things in common: An OID and a Description.
|
||||||
*/
|
*/
|
||||||
abstract class Base {
|
abstract class Base
|
||||||
|
{
|
||||||
|
private const LOGKEY = 'Sb-';
|
||||||
|
|
||||||
protected const DEBUG_VERBOSE = FALSE;
|
protected const DEBUG_VERBOSE = FALSE;
|
||||||
|
|
||||||
// Record the LDAP String
|
// Record the LDAP String
|
||||||
private string $line;
|
private(set) string $line;
|
||||||
|
|
||||||
// The schema item's name.
|
// The schema item's name.
|
||||||
protected string $name = '';
|
protected(set) string $name = '';
|
||||||
|
|
||||||
// The OID of this schema item.
|
// The OID of this schema item.
|
||||||
protected string $oid = '';
|
protected(set) string $oid = '';
|
||||||
|
|
||||||
# The description of this schema item.
|
# The description of this schema item.
|
||||||
protected string $description = '';
|
protected(set) string $description = '';
|
||||||
|
|
||||||
// Boolean value indicating whether this objectClass is obsolete
|
// Boolean value indicating whether this objectClass is obsolete
|
||||||
private bool $is_obsolete = FALSE;
|
private(set) bool $is_obsolete = FALSE;
|
||||||
|
|
||||||
public function __construct(string $line)
|
public function __construct(string $line)
|
||||||
{
|
{
|
||||||
$this->line = $line;
|
$this->line = $line;
|
||||||
|
|
||||||
|
$this->parse($line);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __get(string $key): mixed
|
public function __get(string $key): mixed
|
||||||
{
|
{
|
||||||
switch ($key) {
|
switch ($key) {
|
||||||
case 'description': return $this->description;
|
|
||||||
case 'is_obsolete': return $this->is_obsolete;
|
|
||||||
case 'line': return $this->line;
|
|
||||||
case 'name': return $this->name;
|
|
||||||
case 'name_lc': return strtolower($this->name);
|
case 'name_lc': return strtolower($this->name);
|
||||||
case 'oid': return $this->oid;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new InvalidUsage('Unknown key:'.$key);
|
throw new InvalidUsage('Unknown key:'.$key);
|
||||||
@ -54,69 +56,95 @@ abstract class Base {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function __toString(): string
|
public function __toString(): string
|
||||||
{
|
|
||||||
return $this->name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
* @deprecated replace with $class->description
|
|
||||||
*/
|
|
||||||
public function getDescription(): string
|
|
||||||
{
|
|
||||||
return $this->description;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets whether this item is flagged as obsolete by the LDAP server.
|
|
||||||
*
|
|
||||||
* @deprecated replace with $this->is_obsolete
|
|
||||||
*/
|
|
||||||
public function getIsObsolete(): bool
|
|
||||||
{
|
|
||||||
return $this->is_obsolete;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the objects name.
|
|
||||||
*
|
|
||||||
* @param boolean $lower Return the name in lower case (default)
|
|
||||||
* @return string The name
|
|
||||||
* @deprecated use object->name
|
|
||||||
*/
|
|
||||||
public function getName(bool $lower=TRUE): string
|
|
||||||
{
|
|
||||||
return $lower ? strtolower($this->name) : $this->name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the objects name.
|
|
||||||
*
|
|
||||||
* @return string The name
|
|
||||||
* @deprecated use object->oid
|
|
||||||
*/
|
|
||||||
public function getOID(): string
|
|
||||||
{
|
{
|
||||||
return $this->oid;
|
return $this->oid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setDescription(string $desc): void
|
protected function parse(string $line): void
|
||||||
{
|
{
|
||||||
$this->description = $desc;
|
$strings = preg_split('/[\s,]+/',$line,-1,PREG_SPLIT_DELIM_CAPTURE);
|
||||||
|
|
||||||
|
for ($i=0; $i < count($strings); $i++) {
|
||||||
|
$this->parse_chunk($strings,$i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected function parse_chunk(array $strings,int &$i): void
|
||||||
* Sets this attribute's name.
|
|
||||||
*
|
|
||||||
* @param string $name The new name to give this attribute.
|
|
||||||
*/
|
|
||||||
public function setName($name): void
|
|
||||||
{
|
{
|
||||||
$this->name = $name;
|
switch ($strings[$i]) {
|
||||||
|
case '(':
|
||||||
|
case ')':
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'NAME':
|
||||||
|
if ($strings[$i+1] !== '(') {
|
||||||
|
do {
|
||||||
|
$this->name .= (strlen($this->name) ? ' ' : '').$strings[++$i];
|
||||||
|
} while (! preg_match('/\'$/s',$strings[$i]));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$i++;
|
||||||
|
|
||||||
|
do {
|
||||||
|
$this->name .= (strlen($this->name) ? ' ' : '').$strings[++$i];
|
||||||
|
} while (! preg_match('/\'$/s',$strings[$i]));
|
||||||
|
|
||||||
|
do {
|
||||||
|
$i++;
|
||||||
|
} while (! preg_match('/\)+\)?/',$strings[$i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setOID(string $oid): void
|
$this->name = preg_replace("/^\'(.*)\'$/",'$1',$this->name);
|
||||||
{
|
|
||||||
$this->oid = $oid;
|
if (static::DEBUG_VERBOSE)
|
||||||
|
Log::debug(sprintf('%s:- Case NAME returned (%s)',self::LOGKEY,$this->name));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'DESC':
|
||||||
|
do {
|
||||||
|
$this->description .= (strlen($this->description) ? ' ' : '').$strings[++$i];
|
||||||
|
|
||||||
|
} while (! preg_match('/\'$/s',$strings[$i]));
|
||||||
|
|
||||||
|
$this->description = preg_replace("/^\'(.*)\'$/",'$1',$this->description);
|
||||||
|
|
||||||
|
if (static::DEBUG_VERBOSE)
|
||||||
|
Log::debug(sprintf('%s:- Case DESC returned (%s)',self::LOGKEY,$this->description));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'OBSOLETE':
|
||||||
|
$this->is_obsolete = TRUE;
|
||||||
|
|
||||||
|
if (static::DEBUG_VERBOSE)
|
||||||
|
Log::debug(sprintf('%s:- Case OBSOLETE returned (%s)',self::LOGKEY,$this->is_obsolete));
|
||||||
|
break;
|
||||||
|
|
||||||
|
// @note currently not captured
|
||||||
|
case 'X-SUBST':
|
||||||
|
case 'X-ORDERED':
|
||||||
|
case 'X-EQUALITY':
|
||||||
|
case 'X-ORIGIN':
|
||||||
|
$value = '';
|
||||||
|
|
||||||
|
do {
|
||||||
|
$value .= ($value ? ' ' : '').preg_replace('/^\'(.+)\'$/','$1',$strings[++$i]);
|
||||||
|
|
||||||
|
} while (! preg_match("/\'$/s",$strings[$i]));
|
||||||
|
|
||||||
|
if (static::DEBUG_VERBOSE)
|
||||||
|
Log::debug(sprintf('%s:- Case [%s] returned (%s) - IGNORED',self::LOGKEY,$strings[$i],$value));
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (preg_match('/[\d\.]+/i',$strings[$i]) && ($i === 1)) {
|
||||||
|
$this->oid = $strings[$i];
|
||||||
|
|
||||||
|
if (static::DEBUG_VERBOSE)
|
||||||
|
Log::debug(sprintf('%s:- Case default returned OID (%s)',self::LOGKEY,$this->oid));
|
||||||
|
|
||||||
|
} elseif ($strings[$i])
|
||||||
|
Log::alert(sprintf('%s:! Case default discovered a value NOT parsed (%s)',self::LOGKEY,$strings[$i]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,74 +6,49 @@ use Illuminate\Support\Facades\Log;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an LDAP Syntax
|
* Represents an LDAP Syntax
|
||||||
*
|
|
||||||
* @package phpLDAPadmin
|
|
||||||
* @subpackage Schema
|
|
||||||
*/
|
*/
|
||||||
final class LDAPSyntax extends Base {
|
final class LDAPSyntax extends Base
|
||||||
|
{
|
||||||
|
private const LOGKEY = 'SLS';
|
||||||
|
|
||||||
// Is human readable?
|
// Is human readable?
|
||||||
private ?bool $is_not_human_readable = NULL;
|
private(set) ?bool $is_not_human_readable = NULL;
|
||||||
|
|
||||||
// Binary transfer required?
|
// Binary transfer required?
|
||||||
private ?bool $binary_transfer_required = NULL;
|
private(set) ?bool $binary_transfer_required = NULL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new Syntax object from a raw LDAP syntax string.
|
* Creates a new Syntax object from a raw LDAP syntax string.
|
||||||
*/
|
*/
|
||||||
public function __construct(string $line) {
|
protected function parse(string $line): void
|
||||||
Log::debug(sprintf('Parsing LDAPSyntax [%s]',$line));
|
{
|
||||||
|
if (static::DEBUG_VERBOSE)
|
||||||
|
Log::debug(sprintf('%s:Parsing LDAPSyntax [%s]',self::LOGKEY,$line));
|
||||||
|
|
||||||
parent::__construct($line);
|
parent::parse($line);
|
||||||
|
}
|
||||||
$strings = preg_split('/[\s,]+/',$line,-1,PREG_SPLIT_DELIM_CAPTURE);
|
|
||||||
|
|
||||||
|
protected function parse_chunk(array $strings,int &$i): void
|
||||||
|
{
|
||||||
for ($i=0; $i<count($strings); $i++) {
|
for ($i=0; $i<count($strings); $i++) {
|
||||||
switch($strings[$i]) {
|
switch($strings[$i]) {
|
||||||
case '(':
|
|
||||||
case ')':
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'DESC':
|
|
||||||
do {
|
|
||||||
$this->description .= (strlen($this->description) ? ' ' : '').$strings[++$i];
|
|
||||||
|
|
||||||
} while (! preg_match("/\'$/s",$strings[$i]));
|
|
||||||
|
|
||||||
$this->description = preg_replace("/^\'(.*)\'$/",'$1',$this->description);
|
|
||||||
|
|
||||||
Log::debug(sprintf('- Case DESC returned (%s)',$this->description));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'X-BINARY-TRANSFER-REQUIRED':
|
case 'X-BINARY-TRANSFER-REQUIRED':
|
||||||
$this->binary_transfer_required = (str_replace("'",'',$strings[++$i]) === 'TRUE');
|
$this->binary_transfer_required = (str_replace("'",'',$strings[++$i]) === 'TRUE');
|
||||||
|
|
||||||
Log::debug(sprintf('- Case X-BINARY-TRANSFER-REQUIRED returned (%s)',$this->binary_transfer_required));
|
if (static::DEBUG_VERBOSE)
|
||||||
|
Log::debug(sprintf('%s:- Case X-BINARY-TRANSFER-REQUIRED returned (%s)',self::LOGKEY,$this->binary_transfer_required));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'X-NOT-HUMAN-READABLE':
|
case 'X-NOT-HUMAN-READABLE':
|
||||||
$this->is_not_human_readable = (str_replace("'",'',$strings[++$i]) === 'TRUE');
|
$this->is_not_human_readable = (str_replace("'",'',$strings[++$i]) === 'TRUE');
|
||||||
|
|
||||||
Log::debug(sprintf('- Case X-NOT-HUMAN-READABLE returned (%s)',$this->is_not_human_readable));
|
if (static::DEBUG_VERBOSE)
|
||||||
|
Log::debug(sprintf('%s:- Case X-NOT-HUMAN-READABLE returned (%s)',self::LOGKEY,$this->is_not_human_readable));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (preg_match('/[\d\.]+/i',$strings[$i]) && ($i === 1)) {
|
parent::parse_chunk($strings,$i);
|
||||||
$this->oid = $strings[$i];
|
|
||||||
Log::debug(sprintf('- Case default returned (%s)',$this->oid));
|
|
||||||
|
|
||||||
} elseif ($strings[$i])
|
|
||||||
Log::alert(sprintf('! Case default discovered a value NOT parsed (%s)',$strings[$i]),['line'=>$line]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __get(string $key): mixed
|
|
||||||
{
|
|
||||||
switch ($key) {
|
|
||||||
case 'binary_transfer_required': return $this->binary_transfer_required;
|
|
||||||
case 'is_not_human_readable': return $this->is_not_human_readable;
|
|
||||||
|
|
||||||
default: return parent::__get($key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -7,106 +7,16 @@ use Illuminate\Support\Facades\Log;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an LDAP MatchingRule
|
* Represents an LDAP MatchingRule
|
||||||
*
|
|
||||||
* @package phpLDAPadmin
|
|
||||||
* @subpackage Schema
|
|
||||||
*/
|
*/
|
||||||
final class MatchingRule extends Base {
|
final class MatchingRule extends Base
|
||||||
|
{
|
||||||
|
private const LOGKEY = 'SMR';
|
||||||
|
|
||||||
// This rule's syntax OID
|
// This rule's syntax OID
|
||||||
private ?string $syntax = NULL;
|
private(set) ?string $syntax = NULL;
|
||||||
|
|
||||||
// An array of attribute names who use this MatchingRule
|
// An array of attribute names who use this MatchingRule
|
||||||
private Collection $used_by_attrs;
|
private(set) Collection $used_by_attrs;
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new MatchingRule object from a raw LDAP MatchingRule string.
|
|
||||||
*/
|
|
||||||
function __construct(string $line) {
|
|
||||||
Log::debug(sprintf('Parsing MatchingRule [%s]',$line));
|
|
||||||
|
|
||||||
parent::__construct($line);
|
|
||||||
|
|
||||||
$strings = preg_split('/[\s,]+/',$line,-1,PREG_SPLIT_DELIM_CAPTURE);
|
|
||||||
|
|
||||||
// Init
|
|
||||||
$this->used_by_attrs = collect();
|
|
||||||
|
|
||||||
for ($i=0; $i<count($strings); $i++) {
|
|
||||||
switch ($strings[$i]) {
|
|
||||||
case '(':
|
|
||||||
case ')':
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'NAME':
|
|
||||||
if ($strings[$i+1] != '(') {
|
|
||||||
do {
|
|
||||||
$this->name .= (strlen($this->name) ? ' ' : '').$strings[++$i];
|
|
||||||
|
|
||||||
} while (! preg_match("/\'$/s",$strings[$i]));
|
|
||||||
|
|
||||||
} else {
|
|
||||||
$i++;
|
|
||||||
|
|
||||||
do {
|
|
||||||
$this->name .= (strlen($this->name) ? ' ' : '').$strings[++$i];
|
|
||||||
|
|
||||||
} while (! preg_match("/\'$/s",$strings[$i]));
|
|
||||||
|
|
||||||
do {
|
|
||||||
$i++;
|
|
||||||
|
|
||||||
} while (! preg_match('/\)+\)?/',$strings[$i]));
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->name = preg_replace("/^\'/",'',$this->name);
|
|
||||||
$this->name = preg_replace("/\'$/",'',$this->name);
|
|
||||||
|
|
||||||
Log::debug(sprintf(sprintf('- Case NAME returned (%s)',$this->name)));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'DESC':
|
|
||||||
do {
|
|
||||||
$this->description .= (strlen($this->description) ? ' ' : '').$strings[++$i];
|
|
||||||
|
|
||||||
} while (! preg_match("/\'$/s",$strings[$i]));
|
|
||||||
|
|
||||||
$this->description = preg_replace("/^\'(.*)\'$/",'$1',$this->description);
|
|
||||||
|
|
||||||
Log::debug(sprintf('- Case DESC returned (%s)',$this->description));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'OBSOLETE':
|
|
||||||
$this->is_obsolete = TRUE;
|
|
||||||
|
|
||||||
Log::debug(sprintf('- Case OBSOLETE returned (%s)',$this->is_obsolete));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'SYNTAX':
|
|
||||||
$this->syntax = $strings[++$i];
|
|
||||||
|
|
||||||
Log::debug(sprintf('- Case SYNTAX returned (%s)',$this->syntax));
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
if (preg_match('/[\d\.]+/i',$strings[$i]) && ($i === 1)) {
|
|
||||||
$this->oid = $strings[$i];
|
|
||||||
Log::debug(sprintf('- Case default returned (%s)',$this->oid));
|
|
||||||
|
|
||||||
} elseif ($strings[$i])
|
|
||||||
Log::alert(sprintf('! Case default discovered a value NOT parsed (%s)',$strings[$i]),['line'=>$line]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __get(string $key): mixed
|
|
||||||
{
|
|
||||||
switch ($key) {
|
|
||||||
case 'syntax': return $this->syntax;
|
|
||||||
case 'used_by_attrs': return $this->used_by_attrs;
|
|
||||||
|
|
||||||
default: return parent::__get($key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds an attribute name to the list of attributes who use this MatchingRule
|
* Adds an attribute name to the list of attributes who use this MatchingRule
|
||||||
@ -120,23 +30,33 @@ final class MatchingRule extends Base {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets an array of attribute names (strings) which use this MatchingRule
|
* Creates a new MatchingRule object from a raw LDAP MatchingRule string.
|
||||||
*
|
*
|
||||||
* @return array The array of attribute names (strings).
|
* @param string $line
|
||||||
* @deprecated use $this->used_by_attrs
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function getUsedByAttrs()
|
protected function parse(string $line): void
|
||||||
{
|
{
|
||||||
return $this->used_by_attrs;
|
if (static::DEBUG_VERBOSE)
|
||||||
|
Log::debug(sprintf('%s:Parsing MatchingRule [%s]',self::LOGKEY,$line));
|
||||||
|
|
||||||
|
// Init
|
||||||
|
$this->used_by_attrs = collect();
|
||||||
|
|
||||||
|
parent::parse($line);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected function parse_chunk(array $strings,int &$i): void
|
||||||
* Sets the list of used_by_attrs to the array specified by $attrs;
|
|
||||||
*
|
|
||||||
* @param Collection $attrs The array of attribute names (strings) which use this MatchingRule
|
|
||||||
*/
|
|
||||||
public function setUsedByAttrs(Collection $attrs): void
|
|
||||||
{
|
{
|
||||||
$this->used_by_attrs = $attrs;
|
switch ($strings[$i]) {
|
||||||
|
case 'SYNTAX':
|
||||||
|
$this->syntax = $strings[++$i];
|
||||||
|
|
||||||
|
Log::debug(sprintf('- Case SYNTAX returned (%s)',$this->syntax));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
parent::parse_chunk($strings,$i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,99 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Classes\LDAP\Schema;
|
|
||||||
|
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
use Illuminate\Support\Facades\Log;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents an LDAP schema matchingRuleUse entry
|
|
||||||
*
|
|
||||||
* @package phpLDAPadmin
|
|
||||||
* @subpackage Schema
|
|
||||||
*/
|
|
||||||
final class MatchingRuleUse extends Base {
|
|
||||||
// An array of attribute names who use this MatchingRule
|
|
||||||
private Collection $used_by_attrs;
|
|
||||||
|
|
||||||
function __construct(string $line) {
|
|
||||||
Log::debug(sprintf('Parsing MatchingRuleUse [%s]',$line));
|
|
||||||
|
|
||||||
parent::__construct($line);
|
|
||||||
|
|
||||||
$strings = preg_split('/[\s,]+/',$line,-1,PREG_SPLIT_DELIM_CAPTURE);
|
|
||||||
|
|
||||||
// Init
|
|
||||||
$this->used_by_attrs = collect();
|
|
||||||
|
|
||||||
for ($i=0; $i<count($strings); $i++) {
|
|
||||||
switch ($strings[$i]) {
|
|
||||||
case '(':
|
|
||||||
case ')':
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'NAME':
|
|
||||||
if ($strings[$i+1] != '(') {
|
|
||||||
do {
|
|
||||||
$this->name .= (strlen($this->name) ? ' ' : '').$strings[++$i];
|
|
||||||
|
|
||||||
} while (! preg_match("/\'$/s",$strings[$i]));
|
|
||||||
|
|
||||||
} else {
|
|
||||||
$i++;
|
|
||||||
|
|
||||||
do {
|
|
||||||
$this->name .= (strlen($this->name) ? ' ' : '').$strings[++$i];
|
|
||||||
|
|
||||||
} while (! preg_match("/\'$/s",$strings[$i]));
|
|
||||||
|
|
||||||
do {
|
|
||||||
$i++;
|
|
||||||
|
|
||||||
} while (! preg_match('/\)+\)?/',$strings[$i]));
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->name = preg_replace("/^\'(.*)\'$/",'$1',$this->name);
|
|
||||||
|
|
||||||
Log::debug(sprintf(sprintf('- Case NAME returned (%s)',$this->name)));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'APPLIES':
|
|
||||||
if ($strings[$i+1] != '(') {
|
|
||||||
// Has a single attribute name
|
|
||||||
$this->used_by_attrs = collect($strings[++$i]);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// Has multiple attribute names
|
|
||||||
while ($strings[++$i] != ')') {
|
|
||||||
$new_attr = $strings[++$i];
|
|
||||||
$new_attr = preg_replace("/^\'(.*)\'$/",'$1',$new_attr);
|
|
||||||
|
|
||||||
$this->used_by_attrs->push($new_attr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Log::debug(sprintf('- Case APPLIES returned (%s)',$this->used_by_attrs->join(',')));
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
if (preg_match('/[\d\.]+/i',$strings[$i]) && ($i === 1)) {
|
|
||||||
$this->oid = $strings[$i];
|
|
||||||
Log::debug(sprintf('- Case default returned (%s)',$this->oid));
|
|
||||||
|
|
||||||
} elseif ($strings[$i])
|
|
||||||
Log::alert(sprintf('! Case default discovered a value NOT parsed (%s)',$strings[$i]),['line'=>$line]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets an array of attribute names (strings) which use this MatchingRuleUse object.
|
|
||||||
*
|
|
||||||
* @return array The array of attribute names (strings).
|
|
||||||
* @deprecated use $this->used_by_attrs
|
|
||||||
*/
|
|
||||||
public function getUsedByAttrs()
|
|
||||||
{
|
|
||||||
return $this->used_by_attrs;
|
|
||||||
}
|
|
||||||
}
|
|
@ -10,206 +10,28 @@ use App\Exceptions\InvalidUsage;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an LDAP Schema objectClass
|
* Represents an LDAP Schema objectClass
|
||||||
*
|
|
||||||
* @package phpLDAPadmin
|
|
||||||
* @subpackage Schema
|
|
||||||
*/
|
*/
|
||||||
final class ObjectClass extends Base
|
final class ObjectClass extends Base
|
||||||
{
|
{
|
||||||
|
private const LOGKEY = 'SOC';
|
||||||
|
|
||||||
|
// Array of objectClasses which inherit from this one
|
||||||
|
private(set) Collection $child_classes;
|
||||||
|
|
||||||
// Array of objectClass names from which this objectClass inherits
|
// Array of objectClass names from which this objectClass inherits
|
||||||
private Collection $sup_classes;
|
private(set) Collection $sup_classes;
|
||||||
|
|
||||||
// One of STRUCTURAL, ABSTRACT, or AUXILIARY
|
// One of STRUCTURAL, ABSTRACT, or AUXILIARY
|
||||||
private int $type;
|
private int $type;
|
||||||
|
|
||||||
// Arrays of attribute names that this objectClass requires
|
// Attributes that this objectclass defines
|
||||||
private Collection $must_attrs;
|
private(set) Collection $attributes;
|
||||||
|
|
||||||
// Arrays of attribute names that this objectClass allows, but does not require
|
|
||||||
private Collection $may_attrs;
|
|
||||||
|
|
||||||
// Arrays of attribute names that this objectClass has been forced to MAY attrs, due to configuration
|
|
||||||
private Collection $may_force;
|
|
||||||
|
|
||||||
// Array of objectClasses which inherit from this one
|
|
||||||
private Collection $child_objectclasses;
|
|
||||||
|
|
||||||
private bool $is_obsolete;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new ObjectClass object given a raw LDAP objectClass string.
|
|
||||||
*
|
|
||||||
* eg: ( 2.5.6.0 NAME 'top' DESC 'top of the superclass chain' ABSTRACT MUST objectClass )
|
|
||||||
*
|
|
||||||
* @param string $line Schema Line
|
|
||||||
* @param Server $server
|
|
||||||
* @todo Deprecate this $server variable? It is only used for isForceMay() determination, and that might be better done elsewhere?
|
|
||||||
*/
|
|
||||||
public function __construct(string $line,Server $server)
|
|
||||||
{
|
|
||||||
parent::__construct($line);
|
|
||||||
|
|
||||||
if (static::DEBUG_VERBOSE)
|
|
||||||
Log::debug(sprintf('Parsing ObjectClass [%s]',$line));
|
|
||||||
|
|
||||||
$strings = preg_split('/[\s,]+/',$line,-1,PREG_SPLIT_DELIM_CAPTURE);
|
|
||||||
|
|
||||||
// Init
|
|
||||||
$this->may_attrs = collect();
|
|
||||||
$this->may_force = collect();
|
|
||||||
$this->must_attrs = collect();
|
|
||||||
$this->sup_classes = collect();
|
|
||||||
$this->child_objectclasses = collect();
|
|
||||||
|
|
||||||
for ($i=0; $i < count($strings); $i++) {
|
|
||||||
switch ($strings[$i]) {
|
|
||||||
case '(':
|
|
||||||
case ')':
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'NAME':
|
|
||||||
if ($strings[$i+1] != '(') {
|
|
||||||
do {
|
|
||||||
$this->name .= (strlen($this->name) ? ' ' : '').$strings[++$i];
|
|
||||||
|
|
||||||
} while (! preg_match('/\'$/s',$strings[$i]));
|
|
||||||
|
|
||||||
} else {
|
|
||||||
$i++;
|
|
||||||
|
|
||||||
do {
|
|
||||||
$this->name .= (strlen($this->name) ? ' ' : '').$strings[++$i];
|
|
||||||
|
|
||||||
} while (! preg_match('/\'$/s',$strings[$i]));
|
|
||||||
|
|
||||||
do {
|
|
||||||
$i++;
|
|
||||||
} while (! preg_match('/\)+\)?/',$strings[$i]));
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->name = preg_replace("/^\'(.*)\'$/",'$1',$this->name);
|
|
||||||
|
|
||||||
if (static::DEBUG_VERBOSE)
|
|
||||||
Log::debug(sprintf(sprintf('- Case NAME returned (%s)',$this->name)));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'DESC':
|
|
||||||
do {
|
|
||||||
$this->description .= (strlen($this->description) ? ' ' : '').$strings[++$i];
|
|
||||||
|
|
||||||
} while (! preg_match('/\'$/s',$strings[$i]));
|
|
||||||
|
|
||||||
$this->description = preg_replace("/^\'(.*)\'$/",'$1',$this->description);
|
|
||||||
|
|
||||||
if (static::DEBUG_VERBOSE)
|
|
||||||
Log::debug(sprintf('- Case DESC returned (%s)',$this->description));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'OBSOLETE':
|
|
||||||
$this->is_obsolete = TRUE;
|
|
||||||
|
|
||||||
if (static::DEBUG_VERBOSE)
|
|
||||||
Log::debug(sprintf('- Case OBSOLETE returned (%s)',$this->is_obsolete));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'SUP':
|
|
||||||
if ($strings[$i+1] != '(') {
|
|
||||||
$this->sup_classes->push(preg_replace("/'/",'',$strings[++$i]));
|
|
||||||
|
|
||||||
} else {
|
|
||||||
$i++;
|
|
||||||
|
|
||||||
do {
|
|
||||||
$i++;
|
|
||||||
|
|
||||||
if ($strings[$i] != '$')
|
|
||||||
$this->sup_classes->push(preg_replace("/'/",'',$strings[$i]));
|
|
||||||
|
|
||||||
} while (! preg_match('/\)+\)?/',$strings[$i+1]));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (static::DEBUG_VERBOSE)
|
|
||||||
Log::debug(sprintf('- Case SUP returned (%s)',$this->sup_classes->join(',')));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'ABSTRACT':
|
|
||||||
$this->type = Server::OC_ABSTRACT;
|
|
||||||
|
|
||||||
if (static::DEBUG_VERBOSE)
|
|
||||||
Log::debug(sprintf('- Case ABSTRACT returned (%s)',$this->type));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'STRUCTURAL':
|
|
||||||
$this->type = Server::OC_STRUCTURAL;
|
|
||||||
|
|
||||||
if (static::DEBUG_VERBOSE)
|
|
||||||
Log::debug(sprintf('- Case STRUCTURAL returned (%s)',$this->type));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'AUXILIARY':
|
|
||||||
$this->type = Server::OC_AUXILIARY;
|
|
||||||
|
|
||||||
if (static::DEBUG_VERBOSE)
|
|
||||||
Log::debug(sprintf('- Case AUXILIARY returned (%s)',$this->type));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'MUST':
|
|
||||||
$attrs = collect();
|
|
||||||
|
|
||||||
$i = $this->parseList(++$i,$strings,$attrs);
|
|
||||||
|
|
||||||
if (static::DEBUG_VERBOSE)
|
|
||||||
Log::debug(sprintf('= parseList returned %d (%s)',$i,$attrs->join(',')));
|
|
||||||
|
|
||||||
foreach ($attrs as $string) {
|
|
||||||
$attr = new ObjectClassAttribute($string,$this->name);
|
|
||||||
|
|
||||||
if ($server->isForceMay($attr->getName())) {
|
|
||||||
$this->may_force->push($attr);
|
|
||||||
$this->may_attrs->push($attr);
|
|
||||||
|
|
||||||
} else
|
|
||||||
$this->must_attrs->push($attr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (static::DEBUG_VERBOSE)
|
|
||||||
Log::debug(sprintf('- Case MUST returned (%s) (%s)',$this->must_attrs->join(','),$this->may_force->join(',')));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'MAY':
|
|
||||||
$attrs = collect();
|
|
||||||
|
|
||||||
$i = $this->parseList(++$i,$strings,$attrs);
|
|
||||||
|
|
||||||
if (static::DEBUG_VERBOSE)
|
|
||||||
Log::debug(sprintf('parseList returned %d (%s)',$i,$attrs->join(',')));
|
|
||||||
|
|
||||||
foreach ($attrs as $string) {
|
|
||||||
$attr = new ObjectClassAttribute($string,$this->name);
|
|
||||||
$this->may_attrs->push($attr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (static::DEBUG_VERBOSE)
|
|
||||||
Log::debug(sprintf('- Case MAY returned (%s)',$this->may_attrs->join(',')));
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
if (preg_match('/[\d\.]+/i',$strings[$i]) && ($i === 1)) {
|
|
||||||
$this->oid = $strings[$i];
|
|
||||||
if (static::DEBUG_VERBOSE)
|
|
||||||
Log::debug(sprintf('- Case default returned (%s)',$this->oid));
|
|
||||||
|
|
||||||
} elseif ($strings[$i])
|
|
||||||
Log::alert(sprintf('! Case default discovered a value NOT parsed (%s)',$strings[$i]),['line'=>$line]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __get(string $key): mixed
|
public function __get(string $key): mixed
|
||||||
{
|
{
|
||||||
return match ($key) {
|
return match ($key) {
|
||||||
'attributes' => $this->getAllAttrs(TRUE),
|
'all_attributes' => $this->getMustAttrs(TRUE)
|
||||||
'sup' => $this->sup_classes,
|
->merge($this->getMayAttrs(TRUE)),
|
||||||
'type_name' => match ($this->type) {
|
'type_name' => match ($this->type) {
|
||||||
Server::OC_STRUCTURAL => 'Structural',
|
Server::OC_STRUCTURAL => 'Structural',
|
||||||
Server::OC_ABSTRACT => 'Abstract',
|
Server::OC_ABSTRACT => 'Abstract',
|
||||||
@ -220,23 +42,6 @@ final class ObjectClass extends Base
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a list of attributes that this objectClass provides
|
|
||||||
*
|
|
||||||
* @param bool $parents
|
|
||||||
* @return Collection
|
|
||||||
* @throws InvalidUsage
|
|
||||||
*/
|
|
||||||
public function getAllAttrs(bool $parents=FALSE): Collection
|
|
||||||
{
|
|
||||||
return $this->getMustAttrs($parents)
|
|
||||||
->transform(function($item) {
|
|
||||||
$item->required = true;
|
|
||||||
return $item;
|
|
||||||
})
|
|
||||||
->merge($this->getMayAttrs($parents));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds an objectClass to the list of objectClasses that inherit
|
* Adds an objectClass to the list of objectClasses that inherit
|
||||||
* from this objectClass.
|
* from this objectClass.
|
||||||
@ -245,57 +50,8 @@ final class ObjectClass extends Base
|
|||||||
*/
|
*/
|
||||||
public function addChildObjectClass(string $name): void
|
public function addChildObjectClass(string $name): void
|
||||||
{
|
{
|
||||||
if (! $this->child_objectclasses->contains($name))
|
if (! $this->child_classes->contains($name))
|
||||||
$this->child_objectclasses->push($name);
|
$this->child_classes->push($name);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the array of objectClass names which inherit from this objectClass.
|
|
||||||
*
|
|
||||||
* @return Collection Names of objectClasses which inherit from this objectClass.
|
|
||||||
* @deprecated use $this->child_objectclasses
|
|
||||||
*/
|
|
||||||
public function getChildObjectClasses(): Collection
|
|
||||||
{
|
|
||||||
return $this->child_objectclasses;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Behaves identically to addMustAttrs, but it operates on the MAY
|
|
||||||
* attributes of this objectClass.
|
|
||||||
*
|
|
||||||
* @param array $attr An array of attribute names (strings) to add.
|
|
||||||
*/
|
|
||||||
private function addMayAttrs(array $attr): void
|
|
||||||
{
|
|
||||||
if (! is_array($attr) || ! count($attr))
|
|
||||||
return;
|
|
||||||
|
|
||||||
$this->may_attrs = $this->may_attrs->merge($attr)->unique();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds the specified array of attributes to this objectClass' list of
|
|
||||||
* MUST attributes. The resulting array of must attributes will contain
|
|
||||||
* unique members.
|
|
||||||
*
|
|
||||||
* @param array $attr An array of attribute names (strings) to add.
|
|
||||||
*/
|
|
||||||
private function addMustAttrs(array $attr): void
|
|
||||||
{
|
|
||||||
if (! is_array($attr) || ! count($attr))
|
|
||||||
return;
|
|
||||||
|
|
||||||
$this->must_attrs = $this->must_attrs->merge($attr)->unique();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Collection
|
|
||||||
* @deprecated use $this->may_force
|
|
||||||
*/
|
|
||||||
public function getForceMayAttrs(): Collection
|
|
||||||
{
|
|
||||||
return $this->may_force;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -313,42 +69,26 @@ final class ObjectClass extends Base
|
|||||||
*/
|
*/
|
||||||
public function getMayAttrs(bool $parents=FALSE): Collection
|
public function getMayAttrs(bool $parents=FALSE): Collection
|
||||||
{
|
{
|
||||||
// If we dont need our parents, then we'll just return ours.
|
$attrs = $this->attributes
|
||||||
if (! $parents)
|
->filter(fn($item)=>! $item->is_must)
|
||||||
return $this->may_attrs
|
->transform(function($item) {
|
||||||
->sortBy(fn($item)=>strtolower($item->name.$item->source));
|
$item->source = $this->name;
|
||||||
|
return $item;
|
||||||
$attrs = $this->may_attrs;
|
});
|
||||||
|
|
||||||
|
if ($parents)
|
||||||
foreach ($this->getParents() as $object_class)
|
foreach ($this->getParents() as $object_class)
|
||||||
$attrs = $attrs->merge($object_class->getMayAttrs($parents));
|
$attrs = $attrs->merge($object_class
|
||||||
|
->getMayAttrs($parents)
|
||||||
// Remove any duplicates
|
->transform(function($item) use ($object_class) {
|
||||||
$attrs = $attrs->unique(function($item) { return $item->name; });
|
$item->source = $item->source ?: $object_class->name;
|
||||||
|
return $item;
|
||||||
|
}));
|
||||||
|
|
||||||
// Return a sorted list
|
// Return a sorted list
|
||||||
return $attrs->sortBy(function($item) { return strtolower($item->name.$item->source); });
|
return $attrs
|
||||||
}
|
->unique(fn($item)=>$item->name)
|
||||||
|
->sortBy(fn($item)=>$item->name);
|
||||||
/**
|
|
||||||
* Gets an array of attribute names (strings) that entries of this ObjectClass must define.
|
|
||||||
* This differs from getMayAttrs in that it returns an array of strings rather than
|
|
||||||
* array of AttributeType objects
|
|
||||||
*
|
|
||||||
* @param bool $parents An array of ObjectClass objects to use when traversing
|
|
||||||
* the inheritance tree. This presents some what of a bootstrapping problem
|
|
||||||
* as we must fetch all objectClasses to determine through inheritance which
|
|
||||||
* attributes this objectClass provides.
|
|
||||||
* @return Collection The array of allowed attribute names (strings).
|
|
||||||
*
|
|
||||||
* @throws InvalidUsage
|
|
||||||
* @see getMustAttrs
|
|
||||||
* @see getMayAttrs
|
|
||||||
* @see getMustAttrNames
|
|
||||||
*/
|
|
||||||
public function getMayAttrNames(bool $parents=FALSE): Collection
|
|
||||||
{
|
|
||||||
return $this->getMayAttrs($parents)->ppluck('name');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -365,41 +105,26 @@ final class ObjectClass extends Base
|
|||||||
*/
|
*/
|
||||||
public function getMustAttrs(bool $parents=FALSE): Collection
|
public function getMustAttrs(bool $parents=FALSE): Collection
|
||||||
{
|
{
|
||||||
// If we dont need our parents, then we'll just return ours.
|
$attrs = $this->attributes
|
||||||
if (! $parents)
|
->filter(fn($item)=>$item->is_must)
|
||||||
return $this->must_attrs->sortBy(function($item) { return strtolower($item->name.$item->source); });
|
->transform(function($item) {
|
||||||
|
$item->source = $this->name;
|
||||||
$attrs = $this->must_attrs;
|
return $item;
|
||||||
|
});
|
||||||
|
|
||||||
|
if ($parents)
|
||||||
foreach ($this->getParents() as $object_class)
|
foreach ($this->getParents() as $object_class)
|
||||||
$attrs = $attrs->merge($object_class->getMustAttrs($parents));
|
$attrs = $attrs->merge($object_class
|
||||||
|
->getMustAttrs($parents)
|
||||||
// Remove any duplicates
|
->transform(function($item) use ($object_class) {
|
||||||
$attrs = $attrs->unique(function($item) { return $item->name; });
|
$item->source = $item->source ?: $object_class->name;
|
||||||
|
return $item;
|
||||||
|
}));
|
||||||
|
|
||||||
// Return a sorted list
|
// Return a sorted list
|
||||||
return $attrs->sortBy(function($item) { return strtolower($item->name.$item->source); });
|
return $attrs
|
||||||
}
|
->unique(fn($item)=>$item->name)
|
||||||
|
->sortBy(fn($item)=>$item->name);
|
||||||
/**
|
|
||||||
* Gets an array of attribute names (strings) that entries of this ObjectClass must define.
|
|
||||||
* This differs from getMustAttrs in that it returns an array of strings rather than
|
|
||||||
* array of AttributeType objects
|
|
||||||
*
|
|
||||||
* @param bool $parents An array of ObjectClass objects to use when traversing
|
|
||||||
* the inheritance tree. This presents some what of a bootstrapping problem
|
|
||||||
* as we must fetch all objectClasses to determine through inheritance which
|
|
||||||
* attributes this objectClass provides.
|
|
||||||
* @return Collection The array of allowed attribute names (strings).
|
|
||||||
*
|
|
||||||
* @throws InvalidUsage
|
|
||||||
* @see getMustAttrs
|
|
||||||
* @see getMayAttrs
|
|
||||||
* @see getMayAttrNames
|
|
||||||
*/
|
|
||||||
public function getMustAttrNames(bool $parents=FALSE): Collection
|
|
||||||
{
|
|
||||||
return $this->getMustAttrs($parents)->ppluck('name');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -426,27 +151,6 @@ final class ObjectClass extends Base
|
|||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the objectClass names from which this objectClass inherits.
|
|
||||||
*
|
|
||||||
* @return Collection An array of objectClass names (strings)
|
|
||||||
* @deprecated use $this->sup_classes;
|
|
||||||
*/
|
|
||||||
public function getSupClasses(): Collection
|
|
||||||
{
|
|
||||||
return $this->sup_classes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the type of this objectClass: STRUCTURAL, ABSTRACT, or AUXILIARY.
|
|
||||||
*
|
|
||||||
* @deprecated use $this->type_name
|
|
||||||
*/
|
|
||||||
public function getType()
|
|
||||||
{
|
|
||||||
return $this->type;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return if this objectclass is auxiliary
|
* Return if this objectclass is auxiliary
|
||||||
*
|
*
|
||||||
@ -457,39 +161,109 @@ final class ObjectClass extends Base
|
|||||||
return $this->type === Server::OC_AUXILIARY;
|
return $this->type === Server::OC_AUXILIARY;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine if an array is listed in the may_force attrs
|
|
||||||
*/
|
|
||||||
public function isForceMay(string $attr): bool
|
|
||||||
{
|
|
||||||
return $this->may_force->ppluck('name')->contains($attr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return if this objectClass is related to $oclass
|
|
||||||
*
|
|
||||||
* @param array $oclass ObjectClasses that this attribute may be related to
|
|
||||||
* @return bool
|
|
||||||
* @throws InvalidUsage
|
|
||||||
*/
|
|
||||||
public function isRelated(array $oclass): bool
|
|
||||||
{
|
|
||||||
// If I am in the array, we'll just return false
|
|
||||||
if (in_array_ignore_case($this->name,$oclass))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
foreach ($oclass as $object_class)
|
|
||||||
if ($object_class->isStructural() && in_array_ignore_case($this->name,$object_class->getParents()->pluck('name')))
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function isStructural(): bool
|
public function isStructural(): bool
|
||||||
{
|
{
|
||||||
return $this->type === Server::OC_STRUCTURAL;
|
return $this->type === Server::OC_STRUCTURAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new ObjectClass object given a raw LDAP objectClass string.
|
||||||
|
*
|
||||||
|
* eg: ( 2.5.6.0 NAME 'top' DESC 'top of the superclass chain' ABSTRACT MUST objectClass )
|
||||||
|
*
|
||||||
|
* @param string $line Schema Line
|
||||||
|
*/
|
||||||
|
protected function parse(string $line): void
|
||||||
|
{
|
||||||
|
Log::debug(sprintf('%s:Parsing ObjectClass [%s]',self::LOGKEY,$line));
|
||||||
|
|
||||||
|
// Init
|
||||||
|
$this->attributes = collect();
|
||||||
|
$this->sup_classes = collect();
|
||||||
|
$this->child_classes = collect();
|
||||||
|
|
||||||
|
parent::parse($line);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function parse_chunk(array $strings,int &$i): void
|
||||||
|
{
|
||||||
|
switch ($strings[$i]) {
|
||||||
|
case 'SUP':
|
||||||
|
if ($strings[$i+1] !== '(') {
|
||||||
|
$this->sup_classes->push(preg_replace("/'/",'',$strings[++$i]));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$i++;
|
||||||
|
|
||||||
|
do {
|
||||||
|
$i++;
|
||||||
|
|
||||||
|
if ($strings[$i] !== '$')
|
||||||
|
$this->sup_classes->push(preg_replace("/'/",'',$strings[$i]));
|
||||||
|
|
||||||
|
} while (! preg_match('/\)+\)?/',$strings[$i+1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (static::DEBUG_VERBOSE)
|
||||||
|
Log::debug(sprintf('%s:- Case SUP returned (%s)',self::LOGKEY,$this->sup_classes->join(',')));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'ABSTRACT':
|
||||||
|
$this->type = Server::OC_ABSTRACT;
|
||||||
|
|
||||||
|
if (static::DEBUG_VERBOSE)
|
||||||
|
Log::debug(sprintf('%s:- Case ABSTRACT returned (%s)',self::LOGKEY,$this->type));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'STRUCTURAL':
|
||||||
|
$this->type = Server::OC_STRUCTURAL;
|
||||||
|
|
||||||
|
if (static::DEBUG_VERBOSE)
|
||||||
|
Log::debug(sprintf('%s:- Case STRUCTURAL returned (%s)',self::LOGKEY,$this->type));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'AUXILIARY':
|
||||||
|
$this->type = Server::OC_AUXILIARY;
|
||||||
|
|
||||||
|
if (static::DEBUG_VERBOSE)
|
||||||
|
Log::debug(sprintf('%s:- Case AUXILIARY returned (%s)',self::LOGKEY,$this->type));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'MUST':
|
||||||
|
$attrs = collect();
|
||||||
|
|
||||||
|
$i = $this->parseList(++$i,$strings,$attrs);
|
||||||
|
|
||||||
|
foreach ($attrs as $string) {
|
||||||
|
$attr = clone config('server')->schema('attributetypes',$string);
|
||||||
|
|
||||||
|
if (! $attr->forced_as_may)
|
||||||
|
$attr->setMust();
|
||||||
|
|
||||||
|
$this->attributes->push($attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (static::DEBUG_VERBOSE)
|
||||||
|
Log::debug(sprintf('%s:- Case MUST returned (%s) (%s)',self::LOGKEY,$attrs->join(','),$this->forced_as_may ? 'FORCED MAY' : 'MUST'));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'MAY':
|
||||||
|
$attrs = collect();
|
||||||
|
|
||||||
|
$i = $this->parseList(++$i,$strings,$attrs);
|
||||||
|
|
||||||
|
foreach ($attrs as $string)
|
||||||
|
$this->attributes->push(config('server')->schema('attributetypes',$string));
|
||||||
|
|
||||||
|
if (static::DEBUG_VERBOSE)
|
||||||
|
Log::debug(sprintf('%s:- Case MAY returned (%s)',self::LOGKEY,$attrs->join(',')));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
parent::parse_chunk($strings,$i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse an LDAP schema list
|
* Parse an LDAP schema list
|
||||||
*
|
*
|
||||||
|
@ -1,40 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Classes\LDAP\Schema;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A simple class for representing AttributeTypes used only by the ObjectClass class.
|
|
||||||
*
|
|
||||||
* Users should never instantiate this class. It represents an attribute internal to
|
|
||||||
* an ObjectClass. If PHP supported inner-classes and variable permissions, this would
|
|
||||||
* be interior to class ObjectClass and flagged private. The reason this class is used
|
|
||||||
* and not the "real" class AttributeType is because this class supports the notion of
|
|
||||||
* a "source" objectClass, meaning that it keeps track of which objectClass originally
|
|
||||||
* specified it. This class is therefore used by the class ObjectClass to determine
|
|
||||||
* inheritance.
|
|
||||||
*/
|
|
||||||
final class ObjectClassAttribute extends Base {
|
|
||||||
// This Attribute's root.
|
|
||||||
private string $source;
|
|
||||||
public bool $required = FALSE;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new ObjectClassAttribute with specified name and source objectClass.
|
|
||||||
*
|
|
||||||
* @param string $name the name of the new attribute.
|
|
||||||
* @param string $source the name of the ObjectClass which specifies this attribute.
|
|
||||||
*/
|
|
||||||
public function __construct($name,$source)
|
|
||||||
{
|
|
||||||
$this->name = $name;
|
|
||||||
$this->source = $source;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __get(string $key): mixed
|
|
||||||
{
|
|
||||||
return match ($key) {
|
|
||||||
'source' => $this->source,
|
|
||||||
default => parent::__get($key),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@ -16,7 +16,7 @@ use LdapRecord\Query\Builder;
|
|||||||
use LdapRecord\Query\Collection as LDAPCollection;
|
use LdapRecord\Query\Collection as LDAPCollection;
|
||||||
use LdapRecord\Query\ObjectNotFoundException;
|
use LdapRecord\Query\ObjectNotFoundException;
|
||||||
|
|
||||||
use App\Classes\LDAP\Schema\{AttributeType,Base,LDAPSyntax,MatchingRule,MatchingRuleUse,ObjectClass};
|
use App\Classes\LDAP\Schema\{AttributeType,Base,LDAPSyntax,MatchingRule,ObjectClass};
|
||||||
use App\Exceptions\InvalidUsage;
|
use App\Exceptions\InvalidUsage;
|
||||||
use App\Ldap\Entry;
|
use App\Ldap\Entry;
|
||||||
|
|
||||||
@ -28,9 +28,10 @@ final class Server
|
|||||||
private Collection $attributetypes;
|
private Collection $attributetypes;
|
||||||
private Collection $ldapsyntaxes;
|
private Collection $ldapsyntaxes;
|
||||||
private Collection $matchingrules;
|
private Collection $matchingrules;
|
||||||
private Collection $matchingruleuse;
|
|
||||||
private Collection $objectclasses;
|
private Collection $objectclasses;
|
||||||
|
|
||||||
|
private Model $rootDSE;
|
||||||
|
|
||||||
/* ObjectClass Types */
|
/* ObjectClass Types */
|
||||||
public const OC_STRUCTURAL = 0x01;
|
public const OC_STRUCTURAL = 0x01;
|
||||||
public const OC_ABSTRACT = 0x02;
|
public const OC_ABSTRACT = 0x02;
|
||||||
@ -38,6 +39,8 @@ final class Server
|
|||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
|
$this->rootDSE = self::rootDSE();
|
||||||
|
|
||||||
$this->attributetypes = collect();
|
$this->attributetypes = collect();
|
||||||
$this->ldapsyntaxes = collect();
|
$this->ldapsyntaxes = collect();
|
||||||
$this->matchingrules = collect();
|
$this->matchingrules = collect();
|
||||||
@ -47,10 +50,6 @@ final class Server
|
|||||||
public function __get(string $key): mixed
|
public function __get(string $key): mixed
|
||||||
{
|
{
|
||||||
return match($key) {
|
return match($key) {
|
||||||
'attributetypes' => $this->attributetypes,
|
|
||||||
'ldapsyntaxes' => $this->ldapsyntaxes,
|
|
||||||
'matchingrules' => $this->matchingrules,
|
|
||||||
'objectclasses' => $this->objectclasses,
|
|
||||||
'config' => config(sprintf('ldap.connections.%s',config('ldap.default'))),
|
'config' => config(sprintf('ldap.connections.%s',config('ldap.default'))),
|
||||||
'name' => Arr::get($this->config,'name',__('No Server Name Yet')),
|
'name' => Arr::get($this->config,'name',__('No Server Name Yet')),
|
||||||
default => throw new Exception('Unknown key:'.$key),
|
default => throw new Exception('Unknown key:'.$key),
|
||||||
@ -67,7 +66,7 @@ final class Server
|
|||||||
* @return Collection
|
* @return Collection
|
||||||
* @testedin GetBaseDNTest::testBaseDNExists();
|
* @testedin GetBaseDNTest::testBaseDNExists();
|
||||||
*/
|
*/
|
||||||
public static function baseDNs(bool $objects=FALSE): Collection
|
public static function baseDNs(bool $objects=TRUE): Collection
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$rootdse = self::rootDSE();
|
$rootdse = self::rootDSE();
|
||||||
@ -176,7 +175,7 @@ final class Server
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (! $objects)
|
if (! $objects)
|
||||||
return collect($rootdse->namingcontexts);
|
return collect($rootdse->namingcontexts ?: []);
|
||||||
|
|
||||||
return Cache::remember('basedns'.Session::id(),config('ldap.cache.time'),function() use ($rootdse) {
|
return Cache::remember('basedns'.Session::id(),config('ldap.cache.time'),function() use ($rootdse) {
|
||||||
$result = collect();
|
$result = collect();
|
||||||
@ -185,7 +184,7 @@ final class Server
|
|||||||
foreach (($rootdse->namingcontexts ?: []) as $dn)
|
foreach (($rootdse->namingcontexts ?: []) as $dn)
|
||||||
$result->push(self::get($dn)->read()->find($dn));
|
$result->push(self::get($dn)->read()->find($dn));
|
||||||
|
|
||||||
return $result->filter();
|
return $result->filter()->sort(fn($item)=>$item->sort_key);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,18 +256,6 @@ final class Server
|
|||||||
return $rootdse;
|
return $rootdse;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the Schema DN
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
* @throws ObjectNotFoundException
|
|
||||||
*/
|
|
||||||
public static function schemaDN(): string
|
|
||||||
{
|
|
||||||
return collect(self::rootDSE()->subschemasubentry)
|
|
||||||
->first();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* METHODS */
|
/* METHODS */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -307,15 +294,36 @@ final class Server
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function determines if the specified attribute is contained in the force_may list
|
* Get an attribute key for an attributetype name
|
||||||
* as configured in config.php.
|
|
||||||
*
|
*
|
||||||
* @return boolean True if the specified attribute is configured to be force as a may attribute
|
* @param string $key
|
||||||
* @todo There are 3 isForceMay() functions - we only need one
|
* @return int|bool
|
||||||
*/
|
*/
|
||||||
public function isForceMay($attr_name): bool
|
private function get_attr_id(string $key): int|bool
|
||||||
{
|
{
|
||||||
return in_array($attr_name,config('pla.force_may',[]));
|
static $attributes = $this->schema('attributetypes');
|
||||||
|
|
||||||
|
$attrid = $attributes->search(fn($item)=>$item->names->contains($key));
|
||||||
|
|
||||||
|
// Second chance search using lowercase items (our Entry attribute keys are lowercase)
|
||||||
|
if ($attrid === FALSE)
|
||||||
|
$attrid = $attributes->search(fn($item)=>$item->names_lc->contains(strtolower($key)));
|
||||||
|
|
||||||
|
return $attrid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given an OID, return the ldapsyntax for the OID
|
||||||
|
*
|
||||||
|
* @param string $oid
|
||||||
|
* @return LDAPSyntax|null
|
||||||
|
* @throws InvalidUsage
|
||||||
|
*/
|
||||||
|
public function get_syntax(string $oid): ?LDAPSyntax
|
||||||
|
{
|
||||||
|
return (($id=$this->schema('ldapsyntaxes')->search(fn($item)=>$item->oid === $oid)) !== FALSE)
|
||||||
|
? $this->ldapsyntaxes[$id]
|
||||||
|
: NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -336,31 +344,15 @@ final class Server
|
|||||||
* @param string $item Schema Item to Fetch
|
* @param string $item Schema Item to Fetch
|
||||||
* @param string|null $key
|
* @param string|null $key
|
||||||
* @return Collection|LDAPSyntax|Base|NULL
|
* @return Collection|LDAPSyntax|Base|NULL
|
||||||
|
* @throws InvalidUsage
|
||||||
*/
|
*/
|
||||||
public function schema(string $item,?string $key=NULL): Collection|LDAPSyntax|Base|NULL
|
public function schema(string $item,?string $key=NULL): Collection|LDAPSyntax|Base|NULL
|
||||||
{
|
{
|
||||||
// Ensure our item to fetch is lower case
|
// Ensure our item to fetch is lower case
|
||||||
$item = strtolower($item);
|
$item = strtolower($item);
|
||||||
if ($key)
|
|
||||||
$key = strtolower($key);
|
|
||||||
|
|
||||||
$result = Cache::remember('schema'.$item,config('ldap.cache.time'),function() use ($item) {
|
|
||||||
// First pass if we have already retrieved the schema item
|
|
||||||
switch ($item) {
|
|
||||||
case 'attributetypes':
|
|
||||||
case 'ldapsyntaxes':
|
|
||||||
case 'matchingrules':
|
|
||||||
case 'objectclasses':
|
|
||||||
if ($this->{$item}->count())
|
|
||||||
return $this->{$item};
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
// This error message is not localized as only developers should ever see it
|
|
||||||
default:
|
|
||||||
throw new InvalidUsage('Invalid request to fetch schema: '.$item);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (! $this->{$item}->count()) {
|
||||||
|
$this->{$item} = Cache::remember('schema.'.$item,config('ldap.cache.time'),function() use ($item) {
|
||||||
// Try to get the schema DN from the specified entry.
|
// Try to get the schema DN from the specified entry.
|
||||||
$schema_dn = $this->schemaDN();
|
$schema_dn = $this->schemaDN();
|
||||||
// @note: 389DS does not return subschemaSubentry unless it is requested
|
// @note: 389DS does not return subschemaSubentry unless it is requested
|
||||||
@ -381,72 +373,29 @@ final class Server
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
$o = new AttributeType($line);
|
$o = new AttributeType($line);
|
||||||
$this->attributetypes->put($o->name_lc,$o);
|
$this->attributetypes->push($o);
|
||||||
}
|
}
|
||||||
|
|
||||||
// go back and add data from aliased attributeTypes
|
|
||||||
foreach ($this->attributetypes as $o) {
|
foreach ($this->attributetypes as $o) {
|
||||||
/* foreach of the attribute's aliases, create a new entry in the attrs array
|
|
||||||
* with its name set to the alias name, and all other data copied.*/
|
|
||||||
|
|
||||||
if ($o->aliases->count()) {
|
|
||||||
Log::debug(sprintf('%s:\ Attribute [%s] has the following aliases [%s]',self::LOGKEY,$o->name,$o->aliases->join(',')));
|
|
||||||
|
|
||||||
foreach ($o->aliases as $alias) {
|
|
||||||
$new_attr = clone $o;
|
|
||||||
$new_attr->setName($alias);
|
|
||||||
$new_attr->addAlias($o->name);
|
|
||||||
$new_attr->removeAlias($alias);
|
|
||||||
|
|
||||||
$this->attributetypes->put(strtolower($alias),$new_attr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now go through and reference the parent/child relationships
|
// Now go through and reference the parent/child relationships
|
||||||
foreach ($this->attributetypes as $o)
|
|
||||||
if ($o->sup_attribute) {
|
if ($o->sup_attribute) {
|
||||||
$parent = strtolower($o->sup_attribute);
|
$attrid = $this->get_attr_id($o->sup_attribute);
|
||||||
|
|
||||||
if ($this->attributetypes->has($parent) !== FALSE)
|
if (! $this->attributetypes[$attrid]->children->contains($o->oid))
|
||||||
$this->attributetypes[$parent]->addChild($o->name);
|
$this->attributetypes[$attrid]->addChild($o->oid);
|
||||||
}
|
}
|
||||||
|
|
||||||
// go through any children and add details if the child doesnt have them (ie, cn inherits name)
|
// go through any children and add details if the child doesnt have them (ie, cn inherits name)
|
||||||
// @todo This doesnt traverse children properly, so children of children may not get the settings they should
|
foreach ($o->children as $child) {
|
||||||
foreach ($this->attributetypes as $parent) {
|
$attrid = $this->attributetypes->search(fn($o)=>$o->oid === $child);
|
||||||
foreach ($parent->children as $child) {
|
|
||||||
$child = strtolower($child);
|
|
||||||
|
|
||||||
/* only overwrite the child's SINGLE-VALUE property if the parent has it set, and the child doesnt
|
/* only overwrite the child's SINGLE-VALUE property if the parent has it set, and the child doesnt
|
||||||
* (note: All LDAP attributes default to multi-value if not explicitly set SINGLE-VALUE) */
|
* (note: All LDAP attributes default to multi-value if not explicitly set SINGLE-VALUE) */
|
||||||
if (! is_null($parent->is_single_value) && is_null($this->attributetypes[$child]->is_single_value))
|
if (! is_null($o->is_single_value) && is_null($this->attributetypes[$attrid]->is_single_value))
|
||||||
$this->attributetypes[$child]->setIsSingleValue($parent->is_single_value);
|
$this->attributetypes[$attrid]->setIsSingleValue($o->is_single_value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the used in and required_by values.
|
|
||||||
foreach ($this->schema('objectclasses') as $object_class) {
|
|
||||||
$must_attrs = $object_class->getMustAttrNames();
|
|
||||||
$may_attrs = $object_class->getMayAttrNames();
|
|
||||||
$oclass_attrs = $must_attrs->merge($may_attrs)->unique();
|
|
||||||
|
|
||||||
// Add Used In.
|
|
||||||
foreach ($oclass_attrs as $attr_name)
|
|
||||||
if ($this->attributetypes->has(strtolower($attr_name)))
|
|
||||||
$this->attributetypes[strtolower($attr_name)]->addUsedInObjectClass($object_class->name,$object_class->isStructural());
|
|
||||||
|
|
||||||
// Add Required By.
|
|
||||||
foreach ($must_attrs as $attr_name)
|
|
||||||
if ($this->attributetypes->has(strtolower($attr_name)))
|
|
||||||
$this->attributetypes[strtolower($attr_name)]->addRequiredByObjectClass($object_class->name,$object_class->isStructural());
|
|
||||||
|
|
||||||
// Force May
|
|
||||||
foreach ($object_class->getForceMayAttrs() as $attr_name)
|
|
||||||
if ($this->attributetypes->has(strtolower($attr_name->name)))
|
|
||||||
$this->attributetypes[strtolower($attr_name->name)]->setForceMay();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->attributetypes;
|
return $this->attributetypes;
|
||||||
|
|
||||||
case 'ldapsyntaxes':
|
case 'ldapsyntaxes':
|
||||||
@ -457,48 +406,27 @@ final class Server
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
$o = new LDAPSyntax($line);
|
$o = new LDAPSyntax($line);
|
||||||
$this->ldapsyntaxes->put(strtolower($o->oid),$o);
|
$this->ldapsyntaxes->push($o);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->ldapsyntaxes;
|
return $this->ldapsyntaxes;
|
||||||
|
|
||||||
case 'matchingrules':
|
case 'matchingrules':
|
||||||
Log::debug(sprintf('%s:Matching Rules',self::LOGKEY));
|
Log::debug(sprintf('%s:Matching Rules',self::LOGKEY));
|
||||||
$this->matchingruleuse = collect();
|
|
||||||
|
|
||||||
foreach ($schema->{$item} as $line) {
|
foreach ($schema->{$item} as $line) {
|
||||||
if (is_null($line) || ! strlen($line))
|
if (is_null($line) || ! strlen($line))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
$o = new MatchingRule($line);
|
$o = new MatchingRule($line);
|
||||||
$this->matchingrules->put($o->name_lc,$o);
|
$this->matchingrules->push($o);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* For each MatchingRuleUse entry, add the attributes who use it to the
|
|
||||||
* MatchingRule in the $rules array.
|
|
||||||
*/
|
|
||||||
if ($schema->matchingruleuse) {
|
|
||||||
foreach ($schema->matchingruleuse as $line) {
|
|
||||||
if (is_null($line) || ! strlen($line))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
$o = new MatchingRuleUse($line);
|
|
||||||
$this->matchingruleuse->put($o->name_lc,$o);
|
|
||||||
|
|
||||||
if ($this->matchingrules->has($o->name_lc) !== FALSE)
|
|
||||||
$this->matchingrules[$o->name_lc]->setUsedByAttrs($o->getUsedByAttrs());
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
/* No MatchingRuleUse entry in the subschema, so brute-forcing
|
|
||||||
* the reverse-map for the "$rule->getUsedByAttrs()" data.*/
|
|
||||||
foreach ($this->schema('attributetypes') as $attr) {
|
foreach ($this->schema('attributetypes') as $attr) {
|
||||||
$rule_key = strtolower($attr->getEquality());
|
$rule_id = $this->matchingrules->search(fn($item)=>$item->oid === $attr->equality);
|
||||||
|
|
||||||
if ($this->matchingrules->has($rule_key) !== FALSE)
|
if ($rule_id !== FALSE)
|
||||||
$this->matchingrules[$rule_key]->addUsedByAttr($attr->name);
|
$this->matchingrules[$rule_id]->addUsedByAttr($attr->name);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->matchingrules;
|
return $this->matchingrules;
|
||||||
@ -510,19 +438,35 @@ final class Server
|
|||||||
if (is_null($line) || ! strlen($line))
|
if (is_null($line) || ! strlen($line))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
$o = new ObjectClass($line,$this);
|
$o = new ObjectClass($line);
|
||||||
$this->objectclasses->put($o->name_lc,$o);
|
$this->objectclasses->push($o);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach ($this->objectclasses as $o) {
|
||||||
// Now go through and reference the parent/child relationships
|
// Now go through and reference the parent/child relationships
|
||||||
foreach ($this->objectclasses as $o)
|
foreach ($o->sup_classes as $sup) {
|
||||||
foreach ($o->getSupClasses() as $parent) {
|
$oc_id = $this->objectclasses->search(fn($item)=>$item->name === $sup);
|
||||||
$parent = strtolower($parent);
|
|
||||||
|
|
||||||
if (! $this->objectclasses->contains($parent))
|
if (($oc_id !== FALSE) && (! $this->objectclasses[$oc_id]->child_classes->contains($o->name)))
|
||||||
$this->objectclasses[$parent]->addChildObjectClass($o->name);
|
$this->objectclasses[$oc_id]->addChildObjectClass($o->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add the used in and required_by values for attributes.
|
||||||
|
foreach ($o->attributes as $attribute) {
|
||||||
|
if (($attrid = $this->schema('attributetypes')->search(fn($item)=>$item->oid === $attribute->oid)) !== FALSE) {
|
||||||
|
// Add Used In.
|
||||||
|
$this->attributetypes[$attrid]->addUsedInObjectClass($o->oid,$o->isStructural());
|
||||||
|
|
||||||
|
// Add Required By.
|
||||||
|
if ($attribute->is_must)
|
||||||
|
$this->attributetypes[$attrid]->addRequiredByObjectClass($o->oid,$o->isStructural());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put the updated attributetypes back in the cache
|
||||||
|
Cache::put('schema.attributetypes',$this->attributetypes,config('ldap.cache.time'));
|
||||||
|
|
||||||
return $this->objectclasses;
|
return $this->objectclasses;
|
||||||
|
|
||||||
// Shouldnt get here
|
// Shouldnt get here
|
||||||
@ -530,18 +474,37 @@ final class Server
|
|||||||
throw new InvalidUsage('Invalid request to fetch schema: '.$item);
|
throw new InvalidUsage('Invalid request to fetch schema: '.$item);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return is_null($key) ? $result : $result->get($key);
|
if (is_null($key))
|
||||||
|
return $this->{$item};
|
||||||
|
|
||||||
|
switch ($item) {
|
||||||
|
case 'attributetypes':
|
||||||
|
$attrid = $this->get_attr_id($key);
|
||||||
|
|
||||||
|
$attr = ($attrid === FALSE)
|
||||||
|
? new AttributeType($key)
|
||||||
|
: clone $this->{$item}->get($attrid);
|
||||||
|
|
||||||
|
$attr->setName($attr->names->get($attr->names_lc->search(strtolower($key))) ?: $key);
|
||||||
|
|
||||||
|
return $attr;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return $this->{$item}->get($key)
|
||||||
|
?: $this->{$item}->first(fn($item)=>$item->name_lc === strtolower($key));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given an OID, return the ldapsyntax for the OID
|
* Get the Schema DN
|
||||||
*
|
*
|
||||||
* @param string $oid
|
* @return string
|
||||||
* @return LDAPSyntax|null
|
* @throws ObjectNotFoundException
|
||||||
*/
|
*/
|
||||||
public function schemaSyntaxName(string $oid): ?LDAPSyntax
|
public function schemaDN(): string
|
||||||
{
|
{
|
||||||
return $this->schema('ldapsyntaxes',$oid);
|
return Arr::get($this->rootDSE->subschemasubentry,0);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,13 +4,14 @@ namespace App\Classes;
|
|||||||
|
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
class Template
|
class Template
|
||||||
{
|
{
|
||||||
private string $file;
|
private string $file;
|
||||||
private array $template;
|
private array $template;
|
||||||
private(set) bool $invalid = FALSE;
|
private(set) bool $invalid = FALSE;
|
||||||
private string $reason = '';
|
private(set) string $reason = '';
|
||||||
|
|
||||||
public function __construct(string $file)
|
public function __construct(string $file)
|
||||||
{
|
{
|
||||||
@ -30,6 +31,7 @@ class Template
|
|||||||
public function __get(string $key): mixed
|
public function __get(string $key): mixed
|
||||||
{
|
{
|
||||||
return match ($key) {
|
return match ($key) {
|
||||||
|
'name' => Str::replaceEnd('.json','',$this->file),
|
||||||
'attributes' => collect(array_map('strtolower',array_keys(Arr::get($this->template,$key)))),
|
'attributes' => collect(array_map('strtolower',array_keys(Arr::get($this->template,$key)))),
|
||||||
'objectclasses' => collect(array_map('strtolower',Arr::get($this->template,$key))),
|
'objectclasses' => collect(array_map('strtolower',Arr::get($this->template,$key))),
|
||||||
'enabled' => Arr::get($this->template,$key,FALSE) && (! $this->invalid),
|
'enabled' => Arr::get($this->template,$key,FALSE) && (! $this->invalid),
|
||||||
|
@ -17,15 +17,11 @@ class AjaxController extends Controller
|
|||||||
*
|
*
|
||||||
* @return Collection
|
* @return Collection
|
||||||
* @throws \LdapRecord\Query\ObjectNotFoundException
|
* @throws \LdapRecord\Query\ObjectNotFoundException
|
||||||
* @todo This should be consolidated with HomeController
|
|
||||||
*/
|
*/
|
||||||
public function bases(): Collection
|
public function bases(): Collection
|
||||||
{
|
{
|
||||||
$base = Server::baseDNs(TRUE) ?: collect();
|
return Server::baseDNs()
|
||||||
|
->map(fn($item)=> [
|
||||||
return $base
|
|
||||||
->transform(fn($item)=>
|
|
||||||
[
|
|
||||||
'title'=>$item->getRdn(),
|
'title'=>$item->getRdn(),
|
||||||
'item'=>$item->getDNSecure(),
|
'item'=>$item->getDNSecure(),
|
||||||
'lazy'=>TRUE,
|
'lazy'=>TRUE,
|
||||||
|
@ -26,21 +26,6 @@ use App\Ldap\Entry;
|
|||||||
|
|
||||||
class HomeController extends Controller
|
class HomeController extends Controller
|
||||||
{
|
{
|
||||||
private function bases(): Collection
|
|
||||||
{
|
|
||||||
$base = Server::baseDNs(TRUE) ?: collect();
|
|
||||||
|
|
||||||
return $base->transform(function($item) {
|
|
||||||
return [
|
|
||||||
'title'=>$item->getRdn(),
|
|
||||||
'item'=>$item->getDNSecure(),
|
|
||||||
'lazy'=>TRUE,
|
|
||||||
'icon'=>'fa-fw fas fa-sitemap',
|
|
||||||
'tooltip'=>$item->getDn(),
|
|
||||||
];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new object in the LDAP server
|
* Create a new object in the LDAP server
|
||||||
*
|
*
|
||||||
@ -59,19 +44,21 @@ class HomeController extends Controller
|
|||||||
$o = new Entry;
|
$o = new Entry;
|
||||||
$o->setRDNBase($key['dn']);
|
$o->setRDNBase($key['dn']);
|
||||||
|
|
||||||
|
foreach (collect(old())->except(['_token','key','step','rdn','rdn_value','userpassword_hash']) as $old => $value)
|
||||||
|
$o->{$old} = array_filter($value);
|
||||||
|
|
||||||
if (count($x=collect(old('objectclass',$request->validated('objectclass')))->dot()->filter())) {
|
if (count($x=collect(old('objectclass',$request->validated('objectclass')))->dot()->filter())) {
|
||||||
$o->objectclass = Arr::undot($x);
|
$o->objectclass = Arr::undot($x);
|
||||||
|
|
||||||
// Also add in our required attributes
|
// Also add in our required attributes
|
||||||
foreach($o->getAvailableAttributes()->filter(fn($item)=>$item->required) as $ao)
|
foreach ($o->getAvailableAttributes()->filter(fn($item)=>$item->is_must) as $ao)
|
||||||
$o->{$ao->name} = [Entry::TAG_NOTAG=>''];
|
$o->{$ao->name} = [Entry::TAG_NOTAG=>''];
|
||||||
|
|
||||||
} elseif ($request->validated('template')) {
|
} elseif ($request->validated('template')) {
|
||||||
$template = $o->template($request->validated('template'));
|
$template = $o->template($request->validated('template'));
|
||||||
$o->objectclass = [Entry::TAG_NOTAG=>$template->objectclasses->toArray()];
|
$o->objectclass = [Entry::TAG_NOTAG=>$template->objectclasses->toArray()];
|
||||||
|
|
||||||
// @todo We need to add aliases
|
foreach ($o->getAvailableAttributes()->filter(fn($item)=>$item->names_lc->intersect($template->attributes)->count()) as $ao)
|
||||||
foreach($o->getAvailableAttributes()->filter(fn($item)=>$template->attributes->contains($item)) as $ao)
|
|
||||||
$o->{$ao->name} = [Entry::TAG_NOTAG=>''];
|
$o->{$ao->name} = [Entry::TAG_NOTAG=>''];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,7 +66,6 @@ class HomeController extends Controller
|
|||||||
|
|
||||||
return view('frame')
|
return view('frame')
|
||||||
->with('subframe','create')
|
->with('subframe','create')
|
||||||
->with('bases',$this->bases())
|
|
||||||
->with('o',$o)
|
->with('o',$o)
|
||||||
->with('step',$step)
|
->with('step',$step)
|
||||||
->with('template',$template)
|
->with('template',$template)
|
||||||
@ -307,7 +293,6 @@ class HomeController extends Controller
|
|||||||
->with('note',__('No attributes changed'));
|
->with('note',__('No attributes changed'));
|
||||||
|
|
||||||
return view('update')
|
return view('update')
|
||||||
->with('bases',$this->bases())
|
|
||||||
->with('dn',$dn)
|
->with('dn',$dn)
|
||||||
->with('o',$o);
|
->with('o',$o);
|
||||||
}
|
}
|
||||||
@ -386,10 +371,9 @@ class HomeController extends Controller
|
|||||||
|
|
||||||
$key = $this->request_key($request,$old);
|
$key = $this->request_key($request,$old);
|
||||||
|
|
||||||
$view = ($old
|
$view = $old
|
||||||
? view('frame')->with('subframe',$key['cmd'])
|
? view('frame')->with('subframe',$key['cmd'])
|
||||||
: view('frames.'.$key['cmd']))
|
: view('frames.'.$key['cmd']);
|
||||||
->with('bases',$this->bases());
|
|
||||||
|
|
||||||
// If we are rendering a DN, rebuild our object
|
// If we are rendering a DN, rebuild our object
|
||||||
if ($key['cmd'] === 'create') {
|
if ($key['cmd'] === 'create') {
|
||||||
@ -408,6 +392,7 @@ class HomeController extends Controller
|
|||||||
'create' => $view
|
'create' => $view
|
||||||
->with('container',old('container',$key['dn']))
|
->with('container',old('container',$key['dn']))
|
||||||
->with('o',$o)
|
->with('o',$o)
|
||||||
|
->with('template',NULL)
|
||||||
->with('step',1),
|
->with('step',1),
|
||||||
|
|
||||||
'dn' => $view
|
'dn' => $view
|
||||||
@ -435,8 +420,7 @@ class HomeController extends Controller
|
|||||||
// Did we come here as a result of a redirect
|
// Did we come here as a result of a redirect
|
||||||
return count(old())
|
return count(old())
|
||||||
? $this->frame($request,collect(old()))
|
? $this->frame($request,collect(old()))
|
||||||
: view('home')
|
: view('home');
|
||||||
->with('bases',$this->bases());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -472,7 +456,6 @@ class HomeController extends Controller
|
|||||||
|
|
||||||
return view('frame')
|
return view('frame')
|
||||||
->with('subframe','import_result')
|
->with('subframe','import_result')
|
||||||
->with('bases',$this->bases())
|
|
||||||
->with('result',$result)
|
->with('result',$result)
|
||||||
->with('ldif',htmlspecialchars($x));
|
->with('ldif',htmlspecialchars($x));
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ class SearchController extends Controller
|
|||||||
|
|
||||||
$result = collect();
|
$result = collect();
|
||||||
|
|
||||||
foreach ($so->baseDNs() as $base) {
|
foreach ($so->baseDNs(FALSE) as $base) {
|
||||||
$search = (new Entry)
|
$search = (new Entry)
|
||||||
->in($base);
|
->in($base);
|
||||||
|
|
||||||
|
@ -35,9 +35,18 @@ class EntryAddRequest extends FormRequest
|
|||||||
return [];
|
return [];
|
||||||
|
|
||||||
$r = request() ?: collect();
|
$r = request() ?: collect();
|
||||||
|
$rk = array_keys($r->all());
|
||||||
|
|
||||||
return config('server')
|
return config('server')
|
||||||
->schema('attributetypes')
|
->schema('attributetypes')
|
||||||
->intersectByKeys($r->all())
|
->filter(fn($item)=>$item->names_lc->intersect($rk)->count())
|
||||||
|
->transform(function($item) use ($rk) {
|
||||||
|
// Set the attributetype name
|
||||||
|
if (($x=$item->names_lc->intersect($rk))->count() === 1)
|
||||||
|
$item->setName($x->pop());
|
||||||
|
|
||||||
|
return $item;
|
||||||
|
})
|
||||||
->map(fn($item)=>$item->validation($r->get('objectclass',[])))
|
->map(fn($item)=>$item->validation($r->get('objectclass',[])))
|
||||||
->filter()
|
->filter()
|
||||||
->flatMap(fn($item)=>$item)
|
->flatMap(fn($item)=>$item)
|
||||||
|
@ -3,7 +3,10 @@
|
|||||||
namespace App\Ldap;
|
namespace App\Ldap;
|
||||||
|
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
use Illuminate\Support\Facades\Crypt;
|
use Illuminate\Support\Facades\Crypt;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Support\Facades\Session;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use LdapRecord\Support\Arr;
|
use LdapRecord\Support\Arr;
|
||||||
@ -41,20 +44,28 @@ class Entry extends Model
|
|||||||
|
|
||||||
public function __construct(array $attributes = [])
|
public function __construct(array $attributes = [])
|
||||||
{
|
{
|
||||||
$this->objects = collect();
|
|
||||||
|
|
||||||
parent::__construct($attributes);
|
parent::__construct($attributes);
|
||||||
|
|
||||||
|
$this->objects = collect();
|
||||||
|
|
||||||
// Load any templates
|
// Load any templates
|
||||||
$x = Storage::disk(config('pla.template.dir'));
|
$this->templates = Cache::remember('templates'.Session::id(),config('ldap.cache.time'),function() {
|
||||||
$this->templates = collect();
|
$template_dir = Storage::disk(config('pla.template.dir'));
|
||||||
|
$templates = collect();
|
||||||
|
|
||||||
foreach (array_filter($x->files(),fn($item)=>Str::endsWith($item,'.json')) as $file)
|
foreach (array_filter($template_dir->files(),fn($item)=>Str::endsWith($item,'.json')) as $file) {
|
||||||
$this->templates->put($file,new Template($file));
|
$to = new Template($file);
|
||||||
|
|
||||||
$this->templates = $this->templates
|
if ($to->invalid) {
|
||||||
->filter(fn($item)=>(! $item->invalid) && $item->enabled)
|
Log::debug(sprintf('Template [%s] is not valid (%s) - ignoring',$file,$to->reason));
|
||||||
->sortBy(fn($item)=>$item);
|
|
||||||
|
} else {
|
||||||
|
$templates->put($file,new Template($file));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $templates;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function discardChanges(): static
|
public function discardChanges(): static
|
||||||
@ -147,7 +158,9 @@ class Entry extends Model
|
|||||||
// Filter out our templates specific for this entry
|
// Filter out our templates specific for this entry
|
||||||
if ($this->dn && (! in_array(strtolower($this->dn),['cn=subschema']))) {
|
if ($this->dn && (! in_array(strtolower($this->dn),['cn=subschema']))) {
|
||||||
$this->templates = $this->templates
|
$this->templates = $this->templates
|
||||||
->filter(fn($item)=>! count($item->objectclasses->diff(array_map('strtolower',Arr::get($this->attributes,'objectclass')))));
|
->filter(fn($item)=>$item->enabled
|
||||||
|
&& (! count($item->objectclasses->diff(array_map('strtolower',Arr::get($this->attributes,'objectclass'))))))
|
||||||
|
->sortBy(fn($item)=>$item);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
@ -299,7 +312,7 @@ class Entry extends Model
|
|||||||
$result = collect();
|
$result = collect();
|
||||||
|
|
||||||
foreach (($this->getObject('objectclass')?->values ?: []) as $oc)
|
foreach (($this->getObject('objectclass')?->values ?: []) as $oc)
|
||||||
$result = $result->merge(config('server')->schema('objectclasses',$oc)->attributes);
|
$result = $result->merge(config('server')->schema('objectclasses',$oc)->all_attributes);
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
@ -402,9 +415,6 @@ class Entry extends Model
|
|||||||
* Return a list of attributes without any values
|
* Return a list of attributes without any values
|
||||||
*
|
*
|
||||||
* @return Collection
|
* @return Collection
|
||||||
* @todo Dont show attributes that are not provided by an objectclass, make a new function to show those
|
|
||||||
* This is for dynamic list items eg: labeledURI, which are not editable.
|
|
||||||
* We can highlight those values that are as a result of a dynamic module
|
|
||||||
*/
|
*/
|
||||||
public function getMissingAttributes(): Collection
|
public function getMissingAttributes(): Collection
|
||||||
{
|
{
|
||||||
@ -417,7 +427,7 @@ class Entry extends Model
|
|||||||
$o = new Attribute\RDN('','dn',['']);
|
$o = new Attribute\RDN('','dn',['']);
|
||||||
// @todo for an existing object, rdnbase would be null, so dynamically get it from the DN.
|
// @todo for an existing object, rdnbase would be null, so dynamically get it from the DN.
|
||||||
$o->setBase($this->rdnbase);
|
$o->setBase($this->rdnbase);
|
||||||
$o->setAttributes($this->getAvailableAttributes()->filter(fn($item)=>$item->required));
|
$o->setAttributes($this->getAvailableAttributes()->filter(fn($item)=>$item->is_must));
|
||||||
|
|
||||||
return $o;
|
return $o;
|
||||||
}
|
}
|
||||||
|
@ -29,11 +29,5 @@ class AppServiceProvider extends ServiceProvider
|
|||||||
public function boot(): void
|
public function boot(): void
|
||||||
{
|
{
|
||||||
$this->loadViewsFrom(__DIR__.'/../../resources/themes/architect/views/','architect');
|
$this->loadViewsFrom(__DIR__.'/../../resources/themes/architect/views/','architect');
|
||||||
|
|
||||||
// Enable pluck on collections to work on private values
|
|
||||||
Collection::macro('ppluck',
|
|
||||||
fn($attr)=>$this
|
|
||||||
->map(fn($item)=>$item->{$attr})
|
|
||||||
->values());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -18,13 +18,14 @@ class Attribute extends Component
|
|||||||
/**
|
/**
|
||||||
* Create a new component instance.
|
* Create a new component instance.
|
||||||
*/
|
*/
|
||||||
public function __construct(?LDAPAttribute $o,bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE)
|
public function __construct(?LDAPAttribute $o,bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE,string $template=NULL)
|
||||||
{
|
{
|
||||||
$this->o = $o;
|
$this->o = $o;
|
||||||
$this->edit = $edit;
|
$this->edit = $edit;
|
||||||
$this->old = $old;
|
$this->old = $old;
|
||||||
$this->new = $new;
|
$this->new = $new;
|
||||||
$this->updated = $updated;
|
$this->updated = $updated;
|
||||||
|
$this->template = $template;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -36,7 +37,7 @@ class Attribute extends Component
|
|||||||
{
|
{
|
||||||
return $this->o
|
return $this->o
|
||||||
? $this->o
|
? $this->o
|
||||||
->render(edit: $this->edit,old: $this->old,new: $this->new,updated: $this->updated)
|
->render(edit: $this->edit,old: $this->old,new: $this->new,template: $this->template,updated: $this->updated)
|
||||||
: __('Unknown');
|
: __('Unknown');
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -59,7 +59,7 @@ $(document).ready(function() {
|
|||||||
if (typeof basedn !== 'undefined') {
|
if (typeof basedn !== 'undefined') {
|
||||||
sources = basedn;
|
sources = basedn;
|
||||||
} else {
|
} else {
|
||||||
sources = { url: 'ajax/bases' };
|
sources = { url: '/ajax/bases' };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attach the fancytree widget to an existing <div id="tree"> element
|
// Attach the fancytree widget to an existing <div id="tree"> element
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
@foreach(($o->tagValues($langtag)->count() ? $o->tagValues($langtag) : [$langtag => NULL]) as $key => $value)
|
@foreach(($o->tagValues($langtag)->count() ? $o->tagValues($langtag) : [$langtag => NULL]) as $key => $value)
|
||||||
@if($edit)
|
@if($edit)
|
||||||
<div class="input-group has-validation mb-3">
|
<div class="input-group has-validation mb-3">
|
||||||
<x-form.select id="userpassword_hash_{{$loop->index}}" name="userpassword_hash[{{ $langtag }}][]" :value="$o->hash($new ? '' : $value)->id()" :options="$helpers" allowclear="false" :disabled="! $new"/>
|
<x-form.select id="userpassword_hash_{{$loop->index}}{{$template ?? ''}}" name="userpassword_hash[{{ $langtag }}][]" :value="$o->hash($new ? '' : ($value ?? ''))->id()" :options="$helpers" allowclear="false" :disabled="! $new"/>
|
||||||
<input type="password" @class(['form-control','is-invalid'=>($e=$errors->get($o->name_lc.'.'.$langtag.'.'.$loop->index)),'mb-1','border-focus'=>! $o->tagValuesOld($langtag)->contains($value),'bg-success-subtle'=>$updated]) name="{{ $o->name_lc }}[{{ $langtag }}][]" value="{{ Arr::get(old($o->name_lc),$langtag.'.'.$loop->index,$value ? md5($value) : '') }}" @readonly(! $new)>
|
<input type="password" @class(['form-control','is-invalid'=>($e=$errors->get($o->name_lc.'.'.$langtag.'.'.$loop->index)),'mb-1','border-focus'=>! $o->tagValuesOld($langtag)->contains($value),'bg-success-subtle'=>$updated]) name="{{ $o->name_lc }}[{{ $langtag }}][]" value="{{ Arr::get(old($o->name_lc),$langtag.'.'.$loop->index,$value ? md5($value) : '') }}" @readonly(! $new)>
|
||||||
|
|
||||||
<div class="invalid-feedback pb-2">
|
<div class="invalid-feedback pb-2">
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
<x-form.base {{ $attributes }}>
|
<x-form.base {{ $attributes }}>
|
||||||
@isset($name)
|
@isset($name)
|
||||||
<input type="hidden" id="{{ $id ?? $name }}_disabled" name="{{ $name }}" value="" disabled>
|
<input type="hidden" id="{{ $id ?? $name }}_disabled" name="{{ $name }}" value="" disabled>
|
||||||
@else
|
|
||||||
@php(throw new \Exception('here'))
|
|
||||||
@dd('no name',$id)
|
|
||||||
@endisset
|
@endisset
|
||||||
|
|
||||||
<select class="form-select @error($old ?? ($id ?? $name)) is-invalid @enderror" id="{{ $id ?? $name }}" name="{{ $name }}" @required($required ?? FALSE) @disabled($disabled ?? FALSE)>
|
<select class="form-select @error($old ?? $id ?? $name) is-invalid @enderror" id="{{ $id ?? $name}}" @isset($name)name="{{ $name }}"@endisset @required($required ?? FALSE) @disabled($disabled ?? FALSE)>
|
||||||
@if((empty($value) && ! empty($options)) || isset($addnew))
|
@if((empty($value) && ! empty($options)) || isset($addnew))
|
||||||
<option value=""></option>
|
<option value=""></option>
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
<td>BaseDN(s)</td>
|
<td>BaseDN(s)</td>
|
||||||
<td>
|
<td>
|
||||||
<table class="table table-sm table-borderless">
|
<table class="table table-sm table-borderless">
|
||||||
@foreach($server->baseDNs(TRUE)->sort(fn($item)=>$item->sort_key) as $item)
|
@foreach($server->baseDNs() as $item)
|
||||||
<tr>
|
<tr>
|
||||||
<td class="ps-0">{{ $item->getDn() }}</td>
|
<td class="ps-0">{{ $item->getDn() }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 pt-2">
|
<div class="col-12 pt-2">
|
||||||
<x-form.select name="newattr" :label="__('Select from').'...'" :options="$o->getMissingAttributes()->sortBy('name')->unique('name')->map(fn($item)=>['id'=>$item->name,'value'=>$item->name])"/>
|
<x-form.select id="newattr" :label="__('Select from').'...'" :options="$o->getMissingAttributes()->sortBy('name')->unique('name')->map(fn($item)=>['id'=>$item->name,'value'=>$item->name])"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,19 +2,19 @@
|
|||||||
<div class="col-12 col-xl-3">
|
<div class="col-12 col-xl-3">
|
||||||
<select id="attributetype" class="form-control">
|
<select id="attributetype" class="form-control">
|
||||||
<option value="-all-">-all-</option>
|
<option value="-all-">-all-</option>
|
||||||
@foreach($attributetypes as $o)
|
@foreach(($at=$attributetypes->sortBy(fn($item)=>$item->names_lc->join(','))) as $o)
|
||||||
<option value="{{ $o->name_lc }}">{{ $o->name }}</option>
|
<option value="{{ $o->names_lc->join('-') }}">{{ $o->names->join(',') }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-12 col-xl-9">
|
<div class="col-12 col-xl-9">
|
||||||
@foreach($attributetypes as $o)
|
@foreach($at as $o)
|
||||||
<span id="at-{{ $o->name_lc }}">
|
<span id="at-{{ $o->names_lc->join('-') }}">
|
||||||
<table class="schema table table-sm table-bordered table-striped">
|
<table class="schema table table-sm table-bordered table-striped">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="table-dark" colspan="2">{{ $o->name }}<span class="float-end"><abbr title="{{ $o->line }}"><i class="fas fa-fw fa-file-contract"></i></abbr></span></th>
|
<th class="table-dark" colspan="2">{{ $o->names->join(' / ') }}<span class="float-end"><abbr title="{{ $o->line }}"><i class="fas fa-fw fa-file-contract"></i></abbr></span></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
@ -57,7 +57,7 @@
|
|||||||
<td>@lang('Substring Rule')</td><td><strong>{{ $o->sub_str_rule ?: __('(not specified)') }}</strong></td>
|
<td>@lang('Substring Rule')</td><td><strong>{{ $o->sub_str_rule ?: __('(not specified)') }}</strong></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>@lang('Syntax')</td><td><strong>{{ ($o->syntax_oid && $x=$server->schemaSyntaxName($o->syntax_oid)) ? $x->description : __('(unknown syntax)') }} @if($o->syntax_oid)({{ $o->syntax_oid }})@endif</strong></td>
|
<td>@lang('Syntax')</td><td><strong>{{ ($o->syntax_oid && $x=$server->get_syntax($o->syntax_oid)) ? $x->description : __('(unknown syntax)') }} @if($o->syntax_oid)({{ $o->syntax_oid }})@endif</strong></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>@lang('Single Valued')</td><td><strong>@lang($o->is_single_value ? 'Yes' : 'No')</strong></td>
|
<td>@lang('Single Valued')</td><td><strong>@lang($o->is_single_value ? 'Yes' : 'No')</strong></td>
|
||||||
@ -77,11 +77,8 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td>@lang('Aliases')</td>
|
<td>@lang('Aliases')</td>
|
||||||
<td><strong>
|
<td><strong>
|
||||||
@if($o->aliases->count())
|
@if($o->names->count() > 1)
|
||||||
@foreach($o->aliases as $alias)
|
{!! $o->names->join('</strong>, <strong>') !!}
|
||||||
@if($loop->index)</strong> <strong>@endif
|
|
||||||
<a class="attributetype" id="{{ strtolower($alias) }}" href="#{{ strtolower($alias) }}">{{ $alias }}</a>
|
|
||||||
@endforeach
|
|
||||||
@else
|
@else
|
||||||
@lang('(none)')
|
@lang('(none)')
|
||||||
@endif
|
@endif
|
||||||
|
@ -35,10 +35,10 @@
|
|||||||
<td>@lang('Inherits from')</td>
|
<td>@lang('Inherits from')</td>
|
||||||
<td colspan="3">
|
<td colspan="3">
|
||||||
<strong>
|
<strong>
|
||||||
@if($o->sup->count() === 0)
|
@if($o->sup_classes->count() === 0)
|
||||||
@lang('(none)')
|
@lang('(none)')
|
||||||
@else
|
@else
|
||||||
@foreach($o->sup as $sup)
|
@foreach($o->sup_classes as $sup)
|
||||||
@if($loop->index)</strong> <strong>@endif
|
@if($loop->index)</strong> <strong>@endif
|
||||||
<a class="objectclass" id="{{ strtolower($sup) }}" href="#{{ strtolower($sup) }}">{{ $sup }}</a>
|
<a class="objectclass" id="{{ strtolower($sup) }}" href="#{{ strtolower($sup) }}">{{ $sup }}</a>
|
||||||
@endforeach
|
@endforeach
|
||||||
@ -53,10 +53,10 @@
|
|||||||
<strong>
|
<strong>
|
||||||
@if(strtolower($o->name) === 'top')
|
@if(strtolower($o->name) === 'top')
|
||||||
<a class="objectclass" id="-all-">(all)</a>
|
<a class="objectclass" id="-all-">(all)</a>
|
||||||
@elseif(! $o->getChildObjectClasses()->count())
|
@elseif(! $o->child_classes->count())
|
||||||
@lang('(none)')
|
@lang('(none)')
|
||||||
@else
|
@else
|
||||||
@foreach($o->getChildObjectClasses() as $childoc)
|
@foreach($o->child_classes as $childoc)
|
||||||
@if($loop->index)</strong> <strong>@endif
|
@if($loop->index)</strong> <strong>@endif
|
||||||
<a class="objectclass" id="{{ strtolower($childoc) }}" href="#{{ strtolower($childoc) }}">{{ $childoc }}</a>
|
<a class="objectclass" id="{{ strtolower($childoc) }}" href="#{{ strtolower($childoc) }}">{{ $childoc }}</a>
|
||||||
@endforeach
|
@endforeach
|
||||||
|
@ -7,10 +7,9 @@
|
|||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
@php($up=(session()->pull('updated') ?: collect()))
|
@php($up=(session()->pull('updated') ?: collect()))
|
||||||
@php($attributes=$o->template($template)?->attributes)
|
|
||||||
|
|
||||||
@foreach($o->getVisibleAttributes()->filter(fn($item)=>$attributes->contains($item)) as $ao)
|
@foreach($o->getVisibleAttributes()->filter(fn($item)=>$template->attributes->contains($item->name_lc)) as $ao)
|
||||||
<x-attribute-type :o="$ao" :edit="TRUE" :new="FALSE" :updated="$up->contains($ao->name_lc)"/>
|
<x-attribute-type :o="$ao" :edit="TRUE" :new="FALSE" :template="$template->name" :updated="$up->contains($ao->name_lc)"/>
|
||||||
@endforeach
|
@endforeach
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -3,9 +3,3 @@
|
|||||||
@section('main-content')
|
@section('main-content')
|
||||||
@include('frames.'.$subframe)
|
@include('frames.'.$subframe)
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
@section('page-scripts')
|
|
||||||
<script type="text/javascript">
|
|
||||||
var basedn = {!! $bases->toJson() !!};
|
|
||||||
</script>
|
|
||||||
@append
|
|
@ -17,7 +17,7 @@
|
|||||||
<div class="main-card mb-3 card">
|
<div class="main-card mb-3 card">
|
||||||
|
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
@lang('Create New Entry') - @lang('Step') {{ $step }} @isset($template) <span class="ms-auto"><i class="fa fa-fw {{ $template->icon }}"></i> {{ $template->title }}</span>@endisset
|
@lang('Create New Entry') - @lang('Step') {{ $step }} @if($template) <span class="ms-auto"><i class="fa fa-fw {{ $template->icon }}"></i> {{ $template->title }}</span>@endif
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@ -69,6 +69,11 @@
|
|||||||
<x-attribute-type :o="$ao" :edit="TRUE" :new="FALSE" :updated="FALSE"/>
|
<x-attribute-type :o="$ao" :edit="TRUE" :new="FALSE" :updated="FALSE"/>
|
||||||
@endforeach
|
@endforeach
|
||||||
|
|
||||||
|
@if(! $template)
|
||||||
|
<!-- @todo When we come back from validation the javascript to append a new attribute is not loaded -->
|
||||||
|
<!-- @todo When we render attributes with javascript, the javascript is not loaded -->
|
||||||
|
@include('fragment.dn.add_attr')
|
||||||
|
@endif
|
||||||
@break;
|
@break;
|
||||||
@endswitch
|
@endswitch
|
||||||
</form>
|
</form>
|
||||||
|
@ -87,7 +87,7 @@
|
|||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
@foreach($o->templates as $template => $name)
|
@foreach($o->templates as $template => $name)
|
||||||
<div @class(['tab-pane','active'=>$loop->index === 0]) id="template-{{$template}}" role="tabpanel">
|
<div @class(['tab-pane','active'=>$loop->index === 0]) id="template-{{$template}}" role="tabpanel">
|
||||||
@include('fragment.template.dn',['template'=>$template])
|
@include('fragment.template.dn',['template'=>$o->template($template)])
|
||||||
</div>
|
</div>
|
||||||
@endforeach
|
@endforeach
|
||||||
|
|
||||||
|
@ -1,16 +1,5 @@
|
|||||||
@extends('architect::layouts.app')
|
@extends('architect::layouts.app')
|
||||||
|
|
||||||
{{--
|
|
||||||
@section('htmlheader_title')
|
|
||||||
@lang('Home')
|
|
||||||
@endsection
|
|
||||||
|
|
||||||
@section('page_title')
|
|
||||||
@endsection
|
|
||||||
@section('page_icon')
|
|
||||||
@endsection
|
|
||||||
--}}
|
|
||||||
|
|
||||||
@section('main-content')
|
@section('main-content')
|
||||||
<x-success/>
|
<x-success/>
|
||||||
|
|
||||||
@ -78,8 +67,6 @@
|
|||||||
|
|
||||||
@section('page-scripts')
|
@section('page-scripts')
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var basedn = {!! $bases->toJson() !!};
|
|
||||||
|
|
||||||
var subpage = window.location.hash;
|
var subpage = window.location.hash;
|
||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user