Ported the schema browser
This commit is contained in:
583
app/Classes/LDAP/Schema/AttributeType.php
Normal file
583
app/Classes/LDAP/Schema/AttributeType.php
Normal file
@@ -0,0 +1,583 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\LDAP\Schema;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Represents an LDAP AttributeType
|
||||
*
|
||||
* @package phpLDAPadmin
|
||||
* @subpackage Schema
|
||||
*/
|
||||
class AttributeType extends Base {
|
||||
// The attribute from which this attribute inherits (if any)
|
||||
private ?string $sup_attribute = NULL;
|
||||
|
||||
// Array of AttributeTypes which inherit from this one
|
||||
private Collection $children;
|
||||
|
||||
// The equality rule used
|
||||
private ?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.
|
||||
private bool $forced_as_may = FALSE;
|
||||
|
||||
/**
|
||||
* Creates a new AttributeType object from a raw LDAP AttributeType string.
|
||||
*
|
||||
* 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) {
|
||||
Log::debug(sprintf('Parsing AttributeType [%s]',$line));
|
||||
|
||||
parent::__construct($line);
|
||||
|
||||
$strings = preg_split('/[\s,]+/',$line,-1,PREG_SPLIT_DELIM_CAPTURE);
|
||||
|
||||
// Init
|
||||
$this->children = collect();
|
||||
$this->aliases = collect();
|
||||
$this->used_in_object_classes = collect();
|
||||
$this->required_by_object_classes = collect();
|
||||
|
||||
for ($i=0; $i < count($strings); $i++) {
|
||||
switch ($strings[$i]) {
|
||||
case '(':
|
||||
case ')':
|
||||
break;
|
||||
|
||||
case 'NAME':
|
||||
// @note Some schema's return a (' instead of a ( '
|
||||
if ($strings[$i+1] != '(' && ! preg_match('/^\(/',$strings[$i+1])) {
|
||||
do {
|
||||
$this->name .= (strlen($this->name) ? ' ' : '').$strings[++$i];
|
||||
|
||||
} while (! preg_match("/\'$/s",$strings[$i]));
|
||||
|
||||
// This attribute has no aliases
|
||||
//$this->aliases = collect();
|
||||
|
||||
} else {
|
||||
$i++;
|
||||
|
||||
do {
|
||||
// In case we came here becaues of a ('
|
||||
if (preg_match('/^\(/',$strings[$i]))
|
||||
$strings[$i] = preg_replace('/^\(/','',$strings[$i]);
|
||||
else
|
||||
$i++;
|
||||
|
||||
$this->name .= (strlen($this->name) ? ' ' : '').$strings[++$i];
|
||||
|
||||
} while (! preg_match("/\'$/s",$strings[$i]));
|
||||
|
||||
// Add alias names for this attribute
|
||||
while ($strings[++$i] != ')') {
|
||||
$alias = $strings[$i];
|
||||
$alias = preg_replace("/^\'(.*)\'$/",'$1',$alias);
|
||||
$this->addAlias($alias);
|
||||
}
|
||||
}
|
||||
|
||||
$this->name = preg_replace("/^\'(.*)\'$/",'$1',$this->name);
|
||||
|
||||
Log::debug(sprintf('- Case NAME returned (%s)',$this->name),['aliases'=>$this->aliases]);
|
||||
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 'SUP':
|
||||
$i++;
|
||||
$this->sup_attribute = preg_replace("/^\'(.*)\'$/",'$1',$strings[$i]);
|
||||
|
||||
Log::debug(sprintf('- Case SUP returned (%s)',$this->sup_attribute));
|
||||
break;
|
||||
|
||||
case 'EQUALITY':
|
||||
$this->equality = $strings[++$i];
|
||||
|
||||
Log::debug(sprintf('- Case EQUALITY returned (%s)',$this->equality));
|
||||
break;
|
||||
|
||||
case 'ORDERING':
|
||||
$this->ordering = $strings[++$i];
|
||||
|
||||
Log::debug(sprintf('- Case ORDERING returned (%s)',$this->ordering));
|
||||
break;
|
||||
|
||||
case 'SUBSTR':
|
||||
$this->sub_str_rule = $strings[++$i];
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
Log::debug(sprintf('- Case SINGLE-VALUE returned (%s)',$this->is_single_value));
|
||||
break;
|
||||
|
||||
case 'COLLECTIVE':
|
||||
$this->is_collective = TRUE;
|
||||
|
||||
Log::debug(sprintf('- Case COLLECTIVE returned (%s)',$this->is_collective));
|
||||
break;
|
||||
|
||||
case 'NO-USER-MODIFICATION':
|
||||
$this->is_no_user_modification = TRUE;
|
||||
|
||||
Log::debug(sprintf('- Case NO-USER-MODIFICATION returned (%s)',$this->is_no_user_modification));
|
||||
break;
|
||||
|
||||
case 'USAGE':
|
||||
$this->usage = $strings[++$i];
|
||||
|
||||
Log::debug(sprintf('- Case USAGE returned (%s)',$this->usage));
|
||||
break;
|
||||
|
||||
// @note currently not captured
|
||||
case 'X-ORDERED':
|
||||
Log::error(sprintf('- Case X-ORDERED returned (%s)',$strings[++$i]));
|
||||
break;
|
||||
|
||||
// @note currently not captured
|
||||
case 'X-ORIGIN':
|
||||
$value = '';
|
||||
|
||||
do {
|
||||
$value .= (strlen($value) ? ' ' : '').$strings[++$i];
|
||||
|
||||
} while (! preg_match("/\'$/s",$strings[$i]));
|
||||
|
||||
Log::error(sprintf('- Case X-ORIGIN returned (%s)',$value));
|
||||
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 __clone()
|
||||
{
|
||||
// When we clone, we need to break the reference to
|
||||
$this->aliases = clone $this->aliases;
|
||||
}
|
||||
|
||||
public function __get(string $key): mixed
|
||||
{
|
||||
switch ($key) {
|
||||
case 'aliases': return $this->aliases;
|
||||
case 'children': return $this->children;
|
||||
case 'forced_as_may': return $this->forced_as_may;
|
||||
case 'is_collective': return $this->is_collective;
|
||||
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 '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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Children of this attribute type that inherit from this one
|
||||
*
|
||||
* @param string $child
|
||||
* @return void
|
||||
*/
|
||||
public function addChild(string $child): void
|
||||
{
|
||||
$this->children->push($child);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an objectClass name to this attribute's list of "required by" objectClasses,
|
||||
* that is the list of objectClasses which must have this attribute.
|
||||
*
|
||||
* @param string $name The name of the objectClass to add.
|
||||
*/
|
||||
public function addRequiredByObjectClass(string $name): void
|
||||
{
|
||||
if ($this->required_by_object_classes->search($name) === FALSE)
|
||||
$this->required_by_object_classes->push($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an objectClass name to this attribute's list of "used in" objectClasses,
|
||||
* that is the list of objectClasses which provide this attribute.
|
||||
*
|
||||
* @param string $name The name of the objectClass to add.
|
||||
*/
|
||||
public function addUsedInObjectClass(string $name): void
|
||||
{
|
||||
if ($this->used_in_object_classes->search($name) === FALSE)
|
||||
$this->used_in_object_classes->push($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 the list of "required by" objectClasses, that is the list of objectClasses
|
||||
* which provide must have attribute.
|
||||
*
|
||||
* @return array An array of names of objectclasses (strings) which provide this attribute
|
||||
*/
|
||||
public function getRequiredByObjectClasses() {
|
||||
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
|
||||
debug_log('Entered (%%)',9,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->required_by_object_classes);
|
||||
|
||||
return $this->required_by_object_classes;
|
||||
}
|
||||
/**
|
||||
* 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 raw syntax string (ie: "1.2.3.4{16}").
|
||||
*
|
||||
* @return string The raw syntax string
|
||||
*/
|
||||
public function getSyntaxString() {
|
||||
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
|
||||
debug_log('Entered (%%)',9,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->syntax);
|
||||
|
||||
return $this->syntax;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this attribute's type
|
||||
*
|
||||
* @return string The attribute's type.
|
||||
* @deprecated use $this->type;
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the specified attribute is an alias for this one (based on this attribute's alias list).
|
||||
*
|
||||
* @param string $attr_name The name of the attribute to check.
|
||||
* @return boolean TRUE if the specified attribute is an alias for this one, or FALSE otherwise.
|
||||
*/
|
||||
public function isAliasFor($attr_name) {
|
||||
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
|
||||
debug_log('Entered (%%)',9,0,__FILE__,__LINE__,__METHOD__,$fargs);
|
||||
|
||||
foreach ($this->aliases as $alias_attr_name)
|
||||
if (strcasecmp($alias_attr_name,$attr_name) == 0)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @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.
|
||||
*/
|
||||
public function removeAlias(string $alias): void
|
||||
{
|
||||
if (($x=$this->aliases->search($alias)) !== FALSE)
|
||||
$this->aliases->forget($x);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will mark this attribute as a forced MAY attribute
|
||||
*/
|
||||
public function setForceMay() {
|
||||
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
|
||||
debug_log('Entered (%%)',9,1,__FILE__,__LINE__,__METHOD__,$fargs);
|
||||
|
||||
$this->forced_as_may = TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this attribute is single-valued.
|
||||
*
|
||||
* @param boolean $is
|
||||
*/
|
||||
public function setIsSingleValue(bool $is): void
|
||||
{
|
||||
$this->is_single_value = $is;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this attribute's SUP attribute (ie, the attribute from which this attribute inherits).
|
||||
*
|
||||
* @param string $attr The name of the new parent (SUP) attribute
|
||||
*/
|
||||
public function setSupAttribute(string $attr): void
|
||||
{
|
||||
$this->sup_attribute = trim($attr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this attribute's type.
|
||||
*
|
||||
* @param string $type The new type.
|
||||
*/
|
||||
public function setType($type) {
|
||||
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
|
||||
debug_log('Entered (%%)',9,1,__FILE__,__LINE__,__METHOD__,$fargs);
|
||||
|
||||
$this->type = $type;
|
||||
}
|
||||
}
|
110
app/Classes/LDAP/Schema/Base.php
Normal file
110
app/Classes/LDAP/Schema/Base.php
Normal file
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\LDAP\Schema;
|
||||
|
||||
use App\Exceptions\InvalidUsage;
|
||||
|
||||
/**
|
||||
* Generic parent class for all schema items.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
abstract class Base {
|
||||
// Record the LDAP String
|
||||
private string $line;
|
||||
|
||||
// The schema item's name.
|
||||
protected ?string $name = NULL;
|
||||
|
||||
// The OID of this schema item.
|
||||
protected string $oid;
|
||||
|
||||
# The description of this schema item.
|
||||
protected ?string $description = NULL;
|
||||
|
||||
// Boolean value indicating whether this objectClass is obsolete
|
||||
private bool $is_obsolete = FALSE;
|
||||
|
||||
public function __construct(string $line)
|
||||
{
|
||||
$this->line = $line;
|
||||
}
|
||||
|
||||
public function __get(string $key): mixed
|
||||
{
|
||||
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 'oid': return $this->oid;
|
||||
|
||||
default:
|
||||
throw new InvalidUsage('Unknown key: '.$key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
public function setDescription(string $desc): void
|
||||
{
|
||||
$this->description = $desc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this attribute's name.
|
||||
*
|
||||
* @param string $name The new name to give this attribute.
|
||||
*/
|
||||
public function setName($name): void
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
public function setOID(string $oid): void
|
||||
{
|
||||
$this->oid = $oid;
|
||||
}
|
||||
}
|
79
app/Classes/LDAP/Schema/LDAPSyntax.php
Normal file
79
app/Classes/LDAP/Schema/LDAPSyntax.php
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\LDAP\Schema;
|
||||
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Represents an LDAP Syntax
|
||||
*
|
||||
* @package phpLDAPadmin
|
||||
* @subpackage Schema
|
||||
*/
|
||||
class LDAPSyntax extends Base {
|
||||
// Is human readable?
|
||||
private ?bool $is_not_human_readable = NULL;
|
||||
|
||||
// Binary transfer required?
|
||||
private ?bool $binary_transfer_required = NULL;
|
||||
|
||||
/**
|
||||
* Creates a new Syntax object from a raw LDAP syntax string.
|
||||
*/
|
||||
public function __construct(string $line) {
|
||||
Log::debug(sprintf('Parsing LDAPSyntax [%s]',$line));
|
||||
|
||||
parent::__construct($line);
|
||||
|
||||
$strings = preg_split('/[\s,]+/',$line,-1,PREG_SPLIT_DELIM_CAPTURE);
|
||||
|
||||
for ($i=0; $i<count($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':
|
||||
$this->binary_transfer_required = (str_replace("'",'',$strings[++$i]) === 'TRUE');
|
||||
|
||||
Log::debug(sprintf('- Case X-BINARY-TRANSFER-REQUIRED returned (%s)',$this->binary_transfer_required));
|
||||
break;
|
||||
|
||||
case 'X-NOT-HUMAN-READABLE':
|
||||
$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));
|
||||
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 'binary_transfer_required': return $this->binary_transfer_required;
|
||||
case 'is_not_human_readable': return $this->is_not_human_readable;
|
||||
|
||||
default: return parent::__get($key);
|
||||
}
|
||||
}
|
||||
}
|
142
app/Classes/LDAP/Schema/MatchingRule.php
Normal file
142
app/Classes/LDAP/Schema/MatchingRule.php
Normal file
@@ -0,0 +1,142 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\LDAP\Schema;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Represents an LDAP MatchingRule
|
||||
*
|
||||
* @package phpLDAPadmin
|
||||
* @subpackage Schema
|
||||
*/
|
||||
class MatchingRule extends Base {
|
||||
// This rule's syntax OID
|
||||
private ?string $syntax = NULL;
|
||||
|
||||
// An array of attribute names who use this MatchingRule
|
||||
private 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
|
||||
*/
|
||||
public function addUsedByAttr(string $name): void
|
||||
{
|
||||
$name = trim($name);
|
||||
|
||||
if ($this->used_by_attrs->search($name) === FALSE)
|
||||
$this->used_by_attrs->push($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of attribute names (strings) which use this MatchingRule
|
||||
*
|
||||
* @return array The array of attribute names (strings).
|
||||
* @deprecated use $this->used_by_attrs
|
||||
*/
|
||||
public function getUsedByAttrs()
|
||||
{
|
||||
return $this->used_by_attrs;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
99
app/Classes/LDAP/Schema/MatchingRuleUse.php
Normal file
99
app/Classes/LDAP/Schema/MatchingRuleUse.php
Normal file
@@ -0,0 +1,99 @@
|
||||
<?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
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
529
app/Classes/LDAP/Schema/ObjectClass.php
Normal file
529
app/Classes/LDAP/Schema/ObjectClass.php
Normal file
@@ -0,0 +1,529 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\LDAP\Schema;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use LdapRecord\Connection;
|
||||
|
||||
use App\Classes\LDAP\Server;
|
||||
use App\Exceptions\InvalidUsage;
|
||||
use App\Ldap\Entry;
|
||||
|
||||
/**
|
||||
* Represents an LDAP Schema objectClass
|
||||
*
|
||||
* @package phpLDAPadmin
|
||||
* @subpackage Schema
|
||||
*/
|
||||
class ObjectClass extends Base {
|
||||
// The server ID that this objectclass belongs to.
|
||||
private Server $server;
|
||||
private Connection $connection;
|
||||
|
||||
// Array of objectClass names from which this objectClass inherits
|
||||
private Collection $sup_classes;
|
||||
|
||||
// One of STRUCTURAL, ABSTRACT, or AUXILIARY
|
||||
private int $type;
|
||||
|
||||
// Arrays of attribute names that this objectClass requires
|
||||
private Collection $must_attrs;
|
||||
|
||||
// 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;
|
||||
|
||||
/* ObjectClass Types */
|
||||
private const OC_STRUCTURAL = 0x01;
|
||||
private const OC_ABSTRACT = 0x02;
|
||||
private const OC_AUXILIARY = 0x03;
|
||||
|
||||
/**
|
||||
* 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 )
|
||||
*/
|
||||
public function __construct(string $line,Entry $entry,Server $server)
|
||||
{
|
||||
parent::__construct($line);
|
||||
|
||||
Log::debug(sprintf('Parsing ObjectClass [%s]',$line));
|
||||
|
||||
$strings = preg_split('/[\s,]+/',$line,-1,PREG_SPLIT_DELIM_CAPTURE);
|
||||
|
||||
// Init
|
||||
$this->connection = $entry->getConnection();
|
||||
$this->server = $server;
|
||||
$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);
|
||||
|
||||
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 '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]));
|
||||
}
|
||||
|
||||
Log::debug(sprintf('- Case SUP returned (%s)',$this->sup_classes->join(',')));
|
||||
break;
|
||||
|
||||
case 'ABSTRACT':
|
||||
$this->type = self::OC_ABSTRACT;
|
||||
|
||||
Log::debug(sprintf('- Case ABSTRACT returned (%s)',$this->type));
|
||||
break;
|
||||
|
||||
case 'STRUCTURAL':
|
||||
$this->type = self::OC_STRUCTURAL;
|
||||
|
||||
Log::debug(sprintf('- Case STRUCTURAL returned (%s)',$this->type));
|
||||
break;
|
||||
|
||||
case 'AUXILIARY':
|
||||
$this->type = self::OC_AUXILIARY;
|
||||
|
||||
Log::debug(sprintf('- Case AUXILIARY returned (%s)',$this->type));
|
||||
break;
|
||||
|
||||
case 'MUST':
|
||||
$attrs = collect();
|
||||
|
||||
$i = $this->parseList(++$i,$strings,$attrs);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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];
|
||||
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 'sup':
|
||||
return $this->sup_classes;
|
||||
|
||||
case 'type_name':
|
||||
switch ($this->type) {
|
||||
case self::OC_STRUCTURAL: return 'Structural';
|
||||
case self::OC_ABSTRACT: return 'Abstract';
|
||||
case self::OC_AUXILIARY: return 'Auxiliary';
|
||||
default:
|
||||
throw new InvalidUsage('Unknown ObjectClass Type: '.$this->type);
|
||||
}
|
||||
|
||||
default: return parent::__get($key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an objectClass to the list of objectClasses that inherit
|
||||
* from this objectClass.
|
||||
*
|
||||
* @param String $name The name of the objectClass to add
|
||||
*/
|
||||
public function addChildObjectClass(string $name): void
|
||||
{
|
||||
if ($this->child_objectclasses->search($name) === FALSE) {
|
||||
$this->child_objectclasses->push($name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of AttributeType objects that entries of this ObjectClass may define.
|
||||
* This differs from getMayAttrNames in that it returns an array of AttributeType objects
|
||||
*
|
||||
* @param bool $parents Also get the may attrs of our parents.
|
||||
* @return Collection The array of allowed AttributeType objects.
|
||||
*
|
||||
* @throws InvalidUsage
|
||||
* @see getMustAttrNames
|
||||
* @see getMustAttrs
|
||||
* @see getMayAttrNames
|
||||
* @see AttributeType
|
||||
*/
|
||||
public function getMayAttrs(bool $parents=FALSE): Collection
|
||||
{
|
||||
// If we dont need our parents, then we'll just return ours.
|
||||
if (! $parents)
|
||||
return $this->may_attrs->sortBy(function($item) { return strtolower($item->name.$item->source); });
|
||||
|
||||
$attrs = $this->may_attrs;
|
||||
|
||||
foreach ($this->getParents() as $object_class) {
|
||||
$sc = $this->server->schema('objectclasses',$object_class);
|
||||
$attrs = $attrs->merge($sc->getMayAttrs($parents));
|
||||
}
|
||||
|
||||
// Remove any duplicates
|
||||
$attrs = $attrs->unique(function($item) { return $item->name; });
|
||||
|
||||
// Return a sorted list
|
||||
return $attrs->sortBy(function($item) { return strtolower($item->name.$item->source); });
|
||||
}
|
||||
|
||||
/**
|
||||
* 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');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of AttributeType objects that entries of this ObjectClass must define.
|
||||
* This differs from getMustAttrNames in that it returns an array of AttributeType objects
|
||||
*
|
||||
* @param bool $parents Also get the must attrs of our parents.
|
||||
* @return Collection The array of required AttributeType objects.
|
||||
*
|
||||
* @throws InvalidUsage
|
||||
* @see getMustAttrNames
|
||||
* @see getMayAttrs
|
||||
* @see getMayAttrNames
|
||||
*/
|
||||
public function getMustAttrs(bool $parents=FALSE): Collection
|
||||
{
|
||||
// If we dont need our parents, then we'll just return ours.
|
||||
if (! $parents)
|
||||
return $this->must_attrs->sortBy(function($item) { return strtolower($item->name.$item->source); });
|
||||
|
||||
$attrs = $this->must_attrs;
|
||||
|
||||
foreach ($this->getParents() as $object_class) {
|
||||
$sc = $this->server->schema('objectclasses',$object_class);
|
||||
$attrs = $attrs->merge($sc->getMustAttrs($parents));
|
||||
}
|
||||
|
||||
// Remove any duplicates
|
||||
$attrs = $attrs->unique(function($item) { return $item->name; });
|
||||
|
||||
// Return a sorted list
|
||||
return $attrs->sortBy(function($item) { return strtolower($item->name.$item->source); });
|
||||
}
|
||||
|
||||
/**
|
||||
* 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');
|
||||
}
|
||||
|
||||
/**
|
||||
* This will return all our parent ObjectClass Objects
|
||||
*/
|
||||
public function getParents(): Collection
|
||||
{
|
||||
// If the only class is 'top', then we have no more parents
|
||||
if (($this->sup_classes->count() === 1) && (strtolower($this->sup_classes->first()) === 'top'))
|
||||
return collect();
|
||||
|
||||
$result = collect();
|
||||
|
||||
foreach ($this->sup_classes as $object_class) {
|
||||
$result->push($object_class);
|
||||
|
||||
$oc = $this->server->schema('objectclasses',$object_class);
|
||||
|
||||
if ($oc)
|
||||
$result = $result->merge($oc->getParents());
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
$oc = $this->server->schema('objectclasses',$object_class);
|
||||
|
||||
if ($oc->isStructural() && in_array_ignore_case($this->name,$oc->getParents()))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
public function isStructural(): bool
|
||||
{
|
||||
return $this->type === self::OC_STRUCTURAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an LDAP schema list
|
||||
*
|
||||
* A list starts with a ( followed by a list of attributes separated by $ terminated by )
|
||||
* The first token can therefore be a ( or a (NAME or a (NAME)
|
||||
* The last token can therefore be a ) or NAME)
|
||||
* The last token may be terminated by more than one bracket
|
||||
*/
|
||||
private function parseList(int $i,array $strings,Collection &$attrs): int
|
||||
{
|
||||
$string = $strings[$i];
|
||||
|
||||
if (! preg_match('/^\(/',$string)) {
|
||||
// A bareword only - can be terminated by a ) if the last item
|
||||
if (preg_match('/\)+$/',$string))
|
||||
$string = preg_replace('/\)+$/','',$string);
|
||||
|
||||
$attrs->push($string);
|
||||
|
||||
} elseif (preg_match('/^\(.*\)$/',$string)) {
|
||||
$string = preg_replace('/^\(/','',$string);
|
||||
$string = preg_replace('/\)+$/','',$string);
|
||||
|
||||
$attrs->push($string);
|
||||
|
||||
} else {
|
||||
// Handle the opening cases first
|
||||
if ($string === '(') {
|
||||
$i++;
|
||||
|
||||
} elseif (preg_match('/^\(./',$string)) {
|
||||
$string = preg_replace('/^\(/','',$string);
|
||||
$attrs->push($string);
|
||||
$i++;
|
||||
}
|
||||
|
||||
// Token is either a name, a $ or a ')'
|
||||
// NAME can be terminated by one or more ')'
|
||||
while (! preg_match('/\)+$/',$strings[$i])) {
|
||||
$string = $strings[$i];
|
||||
|
||||
if ($string === '$') {
|
||||
$i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (preg_match('/\)$/',$string))
|
||||
$string = preg_replace('/\)+$/','',$string);
|
||||
else
|
||||
$i++;
|
||||
|
||||
$attrs->push($string);
|
||||
}
|
||||
}
|
||||
|
||||
$attrs = $attrs->sort();
|
||||
|
||||
return $i;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the objectClass names from which this objectClass inherits.
|
||||
*
|
||||
* @return array An array of objectClass names (strings)
|
||||
* @deprecated use $this->sup_classes;
|
||||
*/
|
||||
public function getSupClasses() {
|
||||
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;
|
||||
}
|
||||
}
|
41
app/Classes/LDAP/Schema/ObjectClassAttribute.php
Normal file
41
app/Classes/LDAP/Schema/ObjectClassAttribute.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?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.
|
||||
*/
|
||||
class ObjectClassAttribute extends Base {
|
||||
// This Attribute's root.
|
||||
private string $source;
|
||||
|
||||
/**
|
||||
* 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
|
||||
{
|
||||
switch ($key) {
|
||||
case 'source':
|
||||
return $this->source;
|
||||
|
||||
default: return parent::__get($key);
|
||||
}
|
||||
}
|
||||
}
|
@@ -5,21 +5,38 @@ namespace App\Classes\LDAP;
|
||||
use Carbon\Carbon;
|
||||
use Exception;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection as ArrayCollection;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use LdapRecord\Models\Model;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use LdapRecord\Query\Collection;
|
||||
use LdapRecord\Query\Model\Builder;
|
||||
|
||||
use App\Classes\LDAP\Schema\{AttributeType,Base,LDAPSyntax,MatchingRule,MatchingRuleUse,ObjectClass};
|
||||
use App\Exceptions\InvalidUsage;
|
||||
use App\Ldap\Entry;
|
||||
|
||||
class Server
|
||||
{
|
||||
// This servers schema objectclasses
|
||||
private ArrayCollection $attributetypes;
|
||||
private ArrayCollection $ldapsyntaxes;
|
||||
private ArrayCollection $matchingrules;
|
||||
private ArrayCollection $matchingruleuse;
|
||||
private ArrayCollection $objectclasses;
|
||||
|
||||
// Valid items that can be fetched
|
||||
public const schema_types = [
|
||||
'objectclasses',
|
||||
'attributetypes',
|
||||
'ldapsyntaxes',
|
||||
'matchingrules',
|
||||
];
|
||||
|
||||
/**
|
||||
* Query the server for a DN and return it's children and if those children have children.
|
||||
* Query the server for a DN and return its children and if those children have children.
|
||||
*
|
||||
* @param string $dn
|
||||
* @return array|Collection|null
|
||||
* @return Collection|null
|
||||
*/
|
||||
public function children(string $dn): ?Collection
|
||||
{
|
||||
@@ -37,7 +54,7 @@ class Server
|
||||
*
|
||||
* @param string $dn
|
||||
* @param array $attrs
|
||||
* @return array|Model|Collection|Builder|null
|
||||
* @return Entry|null
|
||||
*/
|
||||
public function fetch(string $dn,array $attrs=['*','+']): ?Entry
|
||||
{
|
||||
@@ -103,4 +120,265 @@ class Server
|
||||
($key == 'desc' ? 'No description available, can you help with one?' : ($key == 'title' ? $oid : NULL))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function determines if the specified attribute is contained in the force_may list
|
||||
* as configured in config.php.
|
||||
*
|
||||
* @return boolean True if the specified attribute is configured to be force as a may attribute
|
||||
*/
|
||||
public function isForceMay($attr_name): bool
|
||||
{
|
||||
return in_array($attr_name,config('pla.force_may',[]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the server's schema
|
||||
*
|
||||
* @param string $item Schema Item to Fetch
|
||||
* @param string|null $key
|
||||
* @return ArrayCollection|Base
|
||||
* @throws InvalidUsage
|
||||
*/
|
||||
public function schema(string $item,string $key=NULL): ArrayCollection|Base|NULL
|
||||
{
|
||||
// Ensure our item to fetch is lower case
|
||||
$item = strtolower($item);
|
||||
if ($key)
|
||||
$key = strtolower($key);
|
||||
|
||||
// This error message is not localized as only developers should ever see it
|
||||
if (! in_array($item,self::schema_types))
|
||||
throw new InvalidUsage('Invalid request to fetch schema: '.$item);
|
||||
|
||||
// First pass if we have already retrieved the schema item
|
||||
switch ($item) {
|
||||
case 'attributetypes':
|
||||
if (isset($this->attributetypes))
|
||||
return is_null($key) ? $this->attributetypes : $this->attributetypes->get($key);
|
||||
else
|
||||
$this->attributetypes = collect();
|
||||
|
||||
break;
|
||||
|
||||
case 'ldapsyntaxes':
|
||||
if (isset($this->ldapsyntaxes))
|
||||
return is_null($key) ? $this->ldapsyntaxes : $this->ldapsyntaxes->get($key);
|
||||
else
|
||||
$this->ldapsyntaxes = collect();
|
||||
|
||||
break;
|
||||
|
||||
case 'matchingrules':
|
||||
if (isset($this->matchingrules))
|
||||
return is_null($key) ? $this->matchingrules : $this->matchingrules->get($key);
|
||||
else
|
||||
$this->matchingrules = collect();
|
||||
|
||||
break;
|
||||
|
||||
/*
|
||||
case 'matchingruleuse':
|
||||
if (isset($this->matchingruleuse))
|
||||
return is_null($key) ? $this->matchingruleuse : $this->matchingruleuse->get($key);
|
||||
else
|
||||
$this->matchingruleuse = collect();
|
||||
|
||||
break;
|
||||
*/
|
||||
|
||||
case 'objectclasses':
|
||||
if (isset($this->objectclasses))
|
||||
return is_null($key) ? $this->objectclasses : $this->objectclasses->get($key);
|
||||
else
|
||||
$this->objectclasses = collect();
|
||||
|
||||
break;
|
||||
|
||||
// Shouldnt get here
|
||||
default:
|
||||
throw new InvalidUsage('Invalid request to fetch schema: '.$item);
|
||||
}
|
||||
|
||||
// Try to get the schema DN from the specified entry.
|
||||
$schema_dn = Entry::schemaDN();
|
||||
$schema = (new Server)->fetch($schema_dn);
|
||||
|
||||
switch ($item) {
|
||||
case 'attributetypes':
|
||||
Log::debug('Attribute Types');
|
||||
// build the array of attribueTypes
|
||||
//$syntaxes = $this->SchemaSyntaxes($dn);
|
||||
|
||||
foreach ($schema->{$item} as $line) {
|
||||
if (is_null($line) || ! strlen($line))
|
||||
continue;
|
||||
|
||||
$o = new AttributeType($line);
|
||||
$this->attributetypes->put($o->name_lc,$o);
|
||||
|
||||
/*
|
||||
if (isset($syntaxes[$attr->getSyntaxOID()])) {
|
||||
$syntax = $syntaxes[$attr->getSyntaxOID()];
|
||||
$attr->setType($syntax->getDescription());
|
||||
}
|
||||
$this->attributetypes[$attr->getName()] = $attr;
|
||||
*/
|
||||
|
||||
/**
|
||||
* bug 856832: create an entry in the $attrs_oid array too. This
|
||||
* will be a ref to the $attrs entry for maintenance and performance
|
||||
* reasons
|
||||
*/
|
||||
//$attrs_oid[$attr->getOID()] = &$attrs[$attr->getName()];
|
||||
}
|
||||
|
||||
// go back and add data from aliased attributeTypes
|
||||
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('\ Attribute [%s] has the following aliases [%s]',$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
|
||||
foreach ($this->attributetypes as $o)
|
||||
if ($o->sup_attribute) {
|
||||
$parent = strtolower($o->sup_attribute);
|
||||
|
||||
if ($this->attributetypes->has($parent) !== FALSE)
|
||||
$this->attributetypes[$parent]->addChild($o->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 ($this->attributetypes as $parent) {
|
||||
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
|
||||
* (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))
|
||||
$this->attributetypes[$child]->setIsSingleValue($parent->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);
|
||||
|
||||
// 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);
|
||||
|
||||
// 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 is_null($key) ? $this->attributetypes : $this->attributetypes->get($key);
|
||||
|
||||
case 'objectclasses':
|
||||
Log::debug('Object Classes');
|
||||
|
||||
foreach ($schema->{$item} as $line) {
|
||||
if (is_null($line) || ! strlen($line))
|
||||
continue;
|
||||
|
||||
$o = new ObjectClass($line,$schema,$this);
|
||||
$this->objectclasses->put($o->name_lc,$o);
|
||||
}
|
||||
|
||||
// Now go through and reference the parent/child relationships
|
||||
foreach ($this->objectclasses as $o)
|
||||
foreach ($o->getSupClasses() as $parent) {
|
||||
$parent = strtolower($parent);
|
||||
if ($this->objectclasses->has($parent) !== FALSE)
|
||||
$this->objectclasses[$parent]->addChildObjectClass($o->name);
|
||||
}
|
||||
|
||||
return is_null($key) ? $this->objectclasses : $this->objectclasses->get($key);
|
||||
|
||||
case 'ldapsyntaxes':
|
||||
Log::debug('LDAP Syntaxes');
|
||||
|
||||
foreach ($schema->{$item} as $line) {
|
||||
if (is_null($line) || ! strlen($line))
|
||||
continue;
|
||||
|
||||
$o = new LDAPSyntax($line);
|
||||
$this->ldapsyntaxes->put(strtolower($o->oid),$o);
|
||||
}
|
||||
|
||||
return is_null($key) ? $this->ldapsyntaxes : $this->ldapsyntaxes->get($key);
|
||||
|
||||
case 'matchingrules':
|
||||
Log::debug('Matching Rules');
|
||||
$this->matchingruleuse = collect();
|
||||
|
||||
foreach ($schema->{$item} as $line) {
|
||||
if (is_null($line) || ! strlen($line))
|
||||
continue;
|
||||
|
||||
$o = new MatchingRule($line);
|
||||
$this->matchingrules->put($o->name_lc,$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) {
|
||||
$rule_key = strtolower($attr->getEquality());
|
||||
|
||||
if ($this->matchingrules->has($rule_key) !== FALSE)
|
||||
$this->matchingrules[$rule_key]->addUsedByAttr($attr->name);
|
||||
}
|
||||
}
|
||||
|
||||
return is_null($key) ? $this->matchingrules : $this->matchingrules->get($key);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
public function schemaSyntaxName(string $oid): ?LDAPSyntax
|
||||
{
|
||||
return $this->schema('ldapsyntaxes',$oid);
|
||||
}
|
||||
}
|
10
app/Exceptions/InvalidUsage.php
Normal file
10
app/Exceptions/InvalidUsage.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace App\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
class InvalidUsage extends Exception
|
||||
{
|
||||
//
|
||||
}
|
@@ -34,4 +34,31 @@ class APIController extends Controller
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
public function schema_view(Request $request)
|
||||
{
|
||||
$server = new Server;
|
||||
|
||||
switch($request->type) {
|
||||
case 'objectclasses':
|
||||
return view('frames.schema.objectclasses')
|
||||
->with('objectclasses',$server->schema('objectclasses')->sortBy(function($item) { return strtolower($item->name); }));
|
||||
|
||||
case 'attributetypes':
|
||||
return view('frames.schema.attributetypes')
|
||||
->with('server',$server)
|
||||
->with('attributetypes',$server->schema('attributetypes')->sortBy(function($item) { return strtolower($item->name); }));
|
||||
|
||||
case 'ldapsyntaxes':
|
||||
return view('frames.schema.ldapsyntaxes')
|
||||
->with('ldapsyntaxes',$server->schema('ldapsyntaxes')->sortBy(function($item) { return strtolower($item->description); }));
|
||||
|
||||
case 'matchingrules':
|
||||
return view('frames.schema.matchingrules')
|
||||
->with('matchingrules',$server->schema('matchingrules')->sortBy(function($item) { return strtolower($item->name); }));
|
||||
|
||||
default:
|
||||
abort(404);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -8,7 +8,7 @@ use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use LdapRecord\Models\ModelNotFoundException;
|
||||
use LdapRecord\Query\ObjectNotFoundException;
|
||||
|
||||
use App\Ldap\Entry;
|
||||
use App\Classes\LDAP\Server;
|
||||
@@ -49,7 +49,7 @@ class HomeController extends Controller
|
||||
* LDAP Server INFO
|
||||
*
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
|
||||
* @throws ModelNotFoundException
|
||||
* @throws ObjectNotFoundException
|
||||
*/
|
||||
public function info()
|
||||
{
|
||||
@@ -74,7 +74,7 @@ class HomeController extends Controller
|
||||
});
|
||||
|
||||
// @todo If we cant get server info, we should probably show a nice error dialog
|
||||
} catch (ModelNotFoundException $e) {
|
||||
} catch (ObjectNotFoundException $e) {
|
||||
$attrs = collect();
|
||||
}
|
||||
|
||||
@@ -98,6 +98,11 @@ class HomeController extends Controller
|
||||
->with('dn',$dn);
|
||||
}
|
||||
|
||||
public function schema_frame()
|
||||
{
|
||||
return view('frames.schema');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort the attributes
|
||||
*
|
||||
|
@@ -14,13 +14,6 @@ use App\Classes\LDAP\Attribute\Factory;
|
||||
|
||||
class Entry extends Model
|
||||
{
|
||||
/**
|
||||
* The object classes of the LDAP model.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $objectClasses = [];
|
||||
|
||||
/* OVERRIDES */
|
||||
|
||||
public function getAttributes(): array
|
||||
@@ -39,23 +32,18 @@ class Entry extends Model
|
||||
* Gets the root DN of the specified LDAPServer, or throws an exception if it
|
||||
* can't find it.
|
||||
*
|
||||
* @param null $connection
|
||||
* @param null $connection Return a collection of baseDNs
|
||||
* @param bool $objects Return a collection of Entry Models
|
||||
* @return Collection
|
||||
* @throws ObjectNotFoundException
|
||||
* @testedin GetBaseDNTest::testBaseDNExists();
|
||||
*/
|
||||
public static function baseDNs($connection = NULL): Collection
|
||||
public static function baseDNs($connection=NULL,bool $objects=TRUE): Collection
|
||||
{
|
||||
$cachetime = Carbon::now()->addSeconds(Config::get('ldap.cache.time'));
|
||||
|
||||
try {
|
||||
$base = static::on($connection ?? (new static)->getConnectionName())
|
||||
->cache($cachetime)
|
||||
->in(NULL)
|
||||
->read()
|
||||
->select(['namingcontexts'])
|
||||
->whereHas('objectclass')
|
||||
->firstOrFail();
|
||||
$base = self::rootDSE($connection,$cachetime);
|
||||
|
||||
/**
|
||||
* LDAP Error Codes:
|
||||
@@ -160,6 +148,9 @@ class Entry extends Model
|
||||
}
|
||||
}
|
||||
|
||||
if (! $objects)
|
||||
return collect($base->namingcontexts);
|
||||
|
||||
/**
|
||||
* @note While we are caching our baseDNs, it seems if we have more than 1,
|
||||
* our caching doesnt generate a hit on a subsequent call to this function (before the cache expires).
|
||||
@@ -174,6 +165,32 @@ class Entry extends Model
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the rootDSE for the server, that gives us server information
|
||||
*
|
||||
* @param null $connection
|
||||
* @return Entry|null
|
||||
* @throws ObjectNotFoundException
|
||||
* @testedin TranslateOidTest::testRootDSE();
|
||||
*/
|
||||
public static function rootDSE($connection=NULL,Carbon $cachetime=NULL): ?Model
|
||||
{
|
||||
return static::on($connection ?? (new static)->getConnectionName())
|
||||
->cache($cachetime)
|
||||
->in(NULL)
|
||||
->read()
|
||||
->select(['+'])
|
||||
->whereHas('objectclass')
|
||||
->firstOrFail();
|
||||
}
|
||||
|
||||
public static function schemaDN($connection = NULL): string
|
||||
{
|
||||
$cachetime = Carbon::now()->addSeconds(Config::get('ldap.cache.time'));
|
||||
|
||||
return collect(self::rootDSE($connection,$cachetime)->subschemasubentry)->first();
|
||||
}
|
||||
|
||||
/* ATTRIBUTES */
|
||||
|
||||
/**
|
||||
@@ -254,22 +271,4 @@ class Entry extends Model
|
||||
// Default
|
||||
return 'fa-fw fas fa-cog';
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the rootDSE for the server, that gives us server information
|
||||
*
|
||||
* @param null $connection
|
||||
* @return Entry|null
|
||||
* @throws ObjectNotFoundException
|
||||
* @testedin TranslateOidTest::testRootDSE();
|
||||
*/
|
||||
public function rootDSE($connection = NULL): ?Entry
|
||||
{
|
||||
return static::on($connection ?? (new static)->getConnectionName())
|
||||
->in(NULL)
|
||||
->read()
|
||||
->select(['+'])
|
||||
->whereHas('objectclass')
|
||||
->firstOrFail();
|
||||
}
|
||||
}
|
||||
}
|
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use LdapRecord\Configuration\DomainConfiguration;
|
||||
use LdapRecord\Laravel\LdapRecord;
|
||||
@@ -32,5 +33,12 @@ class AppServiceProvider extends ServiceProvider
|
||||
public function boot()
|
||||
{
|
||||
$this->loadViewsFrom(__DIR__.'/../../resources/themes/architect/views/','architect');
|
||||
|
||||
// Enable pluck on collections to work on private values
|
||||
Collection::macro('ppluck', function ($attr) {
|
||||
return $this->map(function (object $item) use ($attr) {
|
||||
return $item->{$attr};
|
||||
})->values();
|
||||
});
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user