Ported the schema browser
This commit is contained in:
parent
815cd49868
commit
8ec1d2b1fe
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 Carbon\Carbon;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
|
use Illuminate\Support\Collection as ArrayCollection;
|
||||||
use Illuminate\Support\Facades\Cache;
|
use Illuminate\Support\Facades\Cache;
|
||||||
use Illuminate\Support\Facades\Config;
|
use Illuminate\Support\Facades\Config;
|
||||||
use LdapRecord\Models\Model;
|
use Illuminate\Support\Facades\Log;
|
||||||
use LdapRecord\Query\Collection;
|
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;
|
use App\Ldap\Entry;
|
||||||
|
|
||||||
class Server
|
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
|
* @param string $dn
|
||||||
* @return array|Collection|null
|
* @return Collection|null
|
||||||
*/
|
*/
|
||||||
public function children(string $dn): ?Collection
|
public function children(string $dn): ?Collection
|
||||||
{
|
{
|
||||||
@ -37,7 +54,7 @@ class Server
|
|||||||
*
|
*
|
||||||
* @param string $dn
|
* @param string $dn
|
||||||
* @param array $attrs
|
* @param array $attrs
|
||||||
* @return array|Model|Collection|Builder|null
|
* @return Entry|null
|
||||||
*/
|
*/
|
||||||
public function fetch(string $dn,array $attrs=['*','+']): ?Entry
|
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))
|
($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\Auth;
|
||||||
use Illuminate\Support\Facades\Crypt;
|
use Illuminate\Support\Facades\Crypt;
|
||||||
use Illuminate\Support\Facades\File;
|
use Illuminate\Support\Facades\File;
|
||||||
use LdapRecord\Models\ModelNotFoundException;
|
use LdapRecord\Query\ObjectNotFoundException;
|
||||||
|
|
||||||
use App\Ldap\Entry;
|
use App\Ldap\Entry;
|
||||||
use App\Classes\LDAP\Server;
|
use App\Classes\LDAP\Server;
|
||||||
@ -49,7 +49,7 @@ class HomeController extends Controller
|
|||||||
* LDAP Server INFO
|
* LDAP Server INFO
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
|
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
|
||||||
* @throws ModelNotFoundException
|
* @throws ObjectNotFoundException
|
||||||
*/
|
*/
|
||||||
public function info()
|
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
|
// @todo If we cant get server info, we should probably show a nice error dialog
|
||||||
} catch (ModelNotFoundException $e) {
|
} catch (ObjectNotFoundException $e) {
|
||||||
$attrs = collect();
|
$attrs = collect();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,6 +98,11 @@ class HomeController extends Controller
|
|||||||
->with('dn',$dn);
|
->with('dn',$dn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function schema_frame()
|
||||||
|
{
|
||||||
|
return view('frames.schema');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sort the attributes
|
* Sort the attributes
|
||||||
*
|
*
|
||||||
|
@ -14,13 +14,6 @@ use App\Classes\LDAP\Attribute\Factory;
|
|||||||
|
|
||||||
class Entry extends Model
|
class Entry extends Model
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* The object classes of the LDAP model.
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
public static $objectClasses = [];
|
|
||||||
|
|
||||||
/* OVERRIDES */
|
/* OVERRIDES */
|
||||||
|
|
||||||
public function getAttributes(): array
|
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
|
* Gets the root DN of the specified LDAPServer, or throws an exception if it
|
||||||
* can't find 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
|
* @return Collection
|
||||||
* @throws ObjectNotFoundException
|
* @throws ObjectNotFoundException
|
||||||
* @testedin GetBaseDNTest::testBaseDNExists();
|
* @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'));
|
$cachetime = Carbon::now()->addSeconds(Config::get('ldap.cache.time'));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$base = static::on($connection ?? (new static)->getConnectionName())
|
$base = self::rootDSE($connection,$cachetime);
|
||||||
->cache($cachetime)
|
|
||||||
->in(NULL)
|
|
||||||
->read()
|
|
||||||
->select(['namingcontexts'])
|
|
||||||
->whereHas('objectclass')
|
|
||||||
->firstOrFail();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* LDAP Error Codes:
|
* 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,
|
* @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).
|
* 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;
|
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 */
|
/* ATTRIBUTES */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -254,22 +271,4 @@ class Entry extends Model
|
|||||||
// Default
|
// Default
|
||||||
return 'fa-fw fas fa-cog';
|
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;
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\ServiceProvider;
|
use Illuminate\Support\ServiceProvider;
|
||||||
use LdapRecord\Configuration\DomainConfiguration;
|
use LdapRecord\Configuration\DomainConfiguration;
|
||||||
use LdapRecord\Laravel\LdapRecord;
|
use LdapRecord\Laravel\LdapRecord;
|
||||||
@ -32,5 +33,12 @@ class AppServiceProvider extends ServiceProvider
|
|||||||
public function boot()
|
public function boot()
|
||||||
{
|
{
|
||||||
$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', function ($attr) {
|
||||||
|
return $this->map(function (object $item) use ($attr) {
|
||||||
|
return $item->{$attr};
|
||||||
|
})->values();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -492,15 +492,6 @@ $servers->setValue('server','name','My LDAP Server');
|
|||||||
// $servers->setValue('server','custom_attrs',array(''));
|
// $servers->setValue('server','custom_attrs',array(''));
|
||||||
# $servers->setValue('server','custom_attrs',array('nsRoleDN','nsRole','nsAccountLock'));
|
# $servers->setValue('server','custom_attrs',array('nsRoleDN','nsRole','nsAccountLock'));
|
||||||
|
|
||||||
/* These attributes will be forced to MAY attributes and become option in the
|
|
||||||
templates. If they are not defined in the templates, then they wont appear
|
|
||||||
as per normal template processing. You may want to do this because your LDAP
|
|
||||||
server may automatically calculate a default value.
|
|
||||||
In Fedora Directory Server using the DNA Plugin one could ignore uidNumber,
|
|
||||||
gidNumber and sambaSID. */
|
|
||||||
// $servers->setValue('server','force_may',array(''));
|
|
||||||
# $servers->setValue('server','force_may',array('uidNumber','gidNumber','sambaSID'));
|
|
||||||
|
|
||||||
/*********************************************
|
/*********************************************
|
||||||
* Unique attributes *
|
* Unique attributes *
|
||||||
*********************************************/
|
*********************************************/
|
||||||
|
16
config/pla.php
Normal file
16
config/pla.php
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
/**
|
||||||
|
* These attributes will be forced to MAY attributes and become optional in the
|
||||||
|
* templates. If they are not defined in the templates, then they wont appear
|
||||||
|
* as per normal template processing. You may want to do this because your LDAP
|
||||||
|
* server may automatically calculate a default value.
|
||||||
|
*
|
||||||
|
* In Fedora Directory Server using the DNA Plugin one could ignore uidNumber,
|
||||||
|
* gidNumber and sambaSID.
|
||||||
|
*
|
||||||
|
# 'force_may' => ['uidNumber','gidNumber','sambaSID'],
|
||||||
|
*/
|
||||||
|
'force_may' => [],
|
||||||
|
];
|
@ -1,640 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Displays the schema for the specified server
|
|
||||||
*
|
|
||||||
* Variables that come in as GET vars:
|
|
||||||
* - view (optional)
|
|
||||||
* Shows attribute, objectclass or matching rule
|
|
||||||
* - viewvalue (optional)
|
|
||||||
* Shows the attribute, objectclass or matching rule
|
|
||||||
* - highlight_oid (optional)
|
|
||||||
* Use to higlight the oid in the syntaxes view.
|
|
||||||
*
|
|
||||||
* @package phpLDAPadmin
|
|
||||||
* @subpackage Page
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
|
|
||||||
require './common.php';
|
|
||||||
|
|
||||||
$entry = array();
|
|
||||||
$entry['view'] = get_request('view','GET','false','objectclasses');
|
|
||||||
$entry['value'] = get_request('viewvalue','GET');
|
|
||||||
|
|
||||||
if (! is_null($entry['value'])) {
|
|
||||||
$entry['viewed'] = false;
|
|
||||||
$entry['value'] = strtolower($entry['value']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$schema_error_str = sprintf('%s <b>%s</b>.<br /><br /></div>%s<ul><li>%s</li><li>%s</li><li>%s</li><li>%s</li></ul>',
|
|
||||||
_('Could not retrieve schema from'),$app['server']->getName(),
|
|
||||||
_('This could happen for several reasons, the most probable of which are:'),_('The server does not fully support the LDAP protocol.'),
|
|
||||||
_('Your version of PHP does not correctly perform the query.'),_('phpLDAPadmin doesn\'t know how to fetch the schema for your server.'),
|
|
||||||
_('Or lastly, your LDAP server doesnt provide this information.'));
|
|
||||||
|
|
||||||
printf('<h3 class="title">%s <b>%s</b></h3>',_('Schema for server'),$app['server']->getName());
|
|
||||||
|
|
||||||
$entry['schema_types'] = array(
|
|
||||||
'objectclasses'=>_('ObjectClasses'),
|
|
||||||
'attributes'=>_('Attribute Types'),
|
|
||||||
'syntaxes'=>_('Syntaxes'),
|
|
||||||
'matching_rules'=>_('Matching Rules'));
|
|
||||||
|
|
||||||
echo '<br />';
|
|
||||||
echo '<div style="text-align: center;">';
|
|
||||||
|
|
||||||
$counter = 0;
|
|
||||||
foreach ($entry['schema_types'] as $item => $value) {
|
|
||||||
if ($counter++)
|
|
||||||
echo ' | ';
|
|
||||||
|
|
||||||
$entry['href'][$item] = sprintf('cmd=schema&server_id=%s&view=%s',$app['server']->getIndex(),$item);
|
|
||||||
|
|
||||||
if ($entry['view'] == $item) {
|
|
||||||
echo _($value);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if (isAjaxEnabled())
|
|
||||||
printf('<a href="cmd.php?%s" onclick="return ajDISPLAY(\'BODY\',\'%s\',\'Loading %s\');" title="Loading %s">%s</a>',
|
|
||||||
htmlspecialchars($entry['href'][$item]),htmlspecialchars($entry['href'][$item]),$value,$value,$value);
|
|
||||||
else
|
|
||||||
printf('<a href="cmd.php?%s">%s</a>',htmlspecialchars($entry['href'][$item]),_($value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
echo '</div>';
|
|
||||||
echo '<br />';
|
|
||||||
|
|
||||||
switch($entry['view']) {
|
|
||||||
case 'syntaxes':
|
|
||||||
$highlight_oid = get_request('highlight_oid','GET',false,false);
|
|
||||||
|
|
||||||
echo '<table class="result_table" border="0" style="margin-left: auto; margin-right: auto;">';
|
|
||||||
printf('<tr class="heading"><td>%s</td><td>%s</td></tr>',_('Syntax OID'),_('Description'));
|
|
||||||
|
|
||||||
$counter = 1;
|
|
||||||
|
|
||||||
$schema_syntaxes = $app['server']->SchemaSyntaxes();
|
|
||||||
if (! $schema_syntaxes)
|
|
||||||
error($schema_error_str,'error','index.php');
|
|
||||||
|
|
||||||
foreach ($schema_syntaxes as $syntax) {
|
|
||||||
$counter++;
|
|
||||||
$oid = $syntax->getOID();
|
|
||||||
$desc = $syntax->getDescription();
|
|
||||||
|
|
||||||
if ($highlight_oid && $highlight_oid == $oid)
|
|
||||||
echo '<tr class="highlight">';
|
|
||||||
|
|
||||||
else
|
|
||||||
printf('<tr class="%s">',$counter%2==0?'even':'odd');
|
|
||||||
|
|
||||||
printf('<td>%s</td><td>%s</td></tr>',$oid,$desc);
|
|
||||||
}
|
|
||||||
|
|
||||||
echo '</table>';
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'attributes':
|
|
||||||
$entry['attr_types'] = array(
|
|
||||||
'desc' => _('Description'),
|
|
||||||
'obsolete' => _('Obsolete'),
|
|
||||||
'inherits' => _('Inherits from'),
|
|
||||||
'equality' => _('Equality'),
|
|
||||||
'ordering' => _('Ordering'),
|
|
||||||
'substring_rule' => _('Substring Rule'),
|
|
||||||
'syntax' => _('Syntax'),
|
|
||||||
'single_valued' => _('Single Valued'),
|
|
||||||
'collective' => _('Collective'),
|
|
||||||
'user_modification' => _('User Modification'),
|
|
||||||
'usage' => _('Usage'),
|
|
||||||
'maximum_length' => _('Maximum Length'),
|
|
||||||
'aliases' => _('Aliases'),
|
|
||||||
'used_by_objectclasses' => _('Used by objectClasses'),
|
|
||||||
'force_as_may' => _('Force as MAY by config')
|
|
||||||
);
|
|
||||||
|
|
||||||
$sattrs = $app['server']->SchemaAttributes();
|
|
||||||
|
|
||||||
if (! $sattrs || ! $app['server']->SchemaObjectClasses())
|
|
||||||
error($schema_error_str,'error','index.php');
|
|
||||||
|
|
||||||
printf('<small>%s:</small>',_('Jump to an attribute type'));
|
|
||||||
echo '<form action="cmd.php" method="get">';
|
|
||||||
echo '<div>';
|
|
||||||
echo '<input type="hidden" name="cmd" value="schema" />';
|
|
||||||
printf('<input type="hidden" name="view" value="%s" />',$entry['view']);
|
|
||||||
printf('<input type="hidden" name="server_id" value="%s" />',$app['server']->getIndex());
|
|
||||||
|
|
||||||
if (isAjaxEnabled()) {
|
|
||||||
drawJSItems($sattrs);
|
|
||||||
echo '<select name="viewvalue" onchange="ajSHOWSCHEMA(\'attributes\',\'at\')" id="attributes">';
|
|
||||||
} else
|
|
||||||
echo '<select name="viewvalue" onchange="submit()">';
|
|
||||||
|
|
||||||
echo '<option value=""> - all -</option>';
|
|
||||||
foreach ($sattrs as $name => $attr)
|
|
||||||
printf('<option value="%s" %s>%s</option>',
|
|
||||||
$name,$name == $entry['value'] ? 'selected="selected" ': '',$attr->getName(false));
|
|
||||||
echo '</select>';
|
|
||||||
|
|
||||||
if (isAjaxEnabled())
|
|
||||||
printf('<input type="button" value="%s" onclick="ajSHOWSCHEMA(\'attributes\',\'at\')"/>',_('Go'));
|
|
||||||
else
|
|
||||||
printf('<input type="submit" value="%s" />',_('Go'));
|
|
||||||
echo '</div>';
|
|
||||||
echo '</form>';
|
|
||||||
echo '<br />';
|
|
||||||
|
|
||||||
foreach ($sattrs as $attr) {
|
|
||||||
if (isAjaxEnabled() || (is_null($entry['value']) || ! trim($entry['value']) || $entry['value']==$attr->getName())) {
|
|
||||||
if ((! is_null($entry['value']) && $entry['value']==$attr->getName()) || ! trim($entry['value']))
|
|
||||||
$entry['viewed'] = true;
|
|
||||||
|
|
||||||
if (isAjaxEnabled() && $entry['value'])
|
|
||||||
printf('<div id="at%s" style="display: %s">',$attr->getName(),strcasecmp($entry['value'],$attr->getName()) ? 'none' : 'block');
|
|
||||||
else
|
|
||||||
printf('<div id="at%s">',$attr->getName());
|
|
||||||
|
|
||||||
echo '<table class="result_table" width="100%" border="0">';
|
|
||||||
printf('<tr class="heading"><td colspan="2"><a name="%s">%s</a></td></tr>',
|
|
||||||
$attr->getName(),$attr->getName(false));
|
|
||||||
|
|
||||||
$counter = 0;
|
|
||||||
|
|
||||||
foreach ($entry['attr_types'] as $item => $value) {
|
|
||||||
|
|
||||||
printf('<tr class="%s">',++$counter%2 ? 'odd' : 'even');
|
|
||||||
printf('<td class="title" style="width: 30%%;">%s</td>',$value);
|
|
||||||
|
|
||||||
switch ($item) {
|
|
||||||
case 'desc':
|
|
||||||
printf('<td>%s</td>',
|
|
||||||
is_null($attr->getDescription()) ?
|
|
||||||
'('._('no description').')' : $attr->getDescription());
|
|
||||||
|
|
||||||
echo '</tr>';
|
|
||||||
printf('<tr class="%s">',++$counter%2 ? 'odd' : 'even');
|
|
||||||
echo '<td class="title"><acronym title="Object Identier">OID</acronym></td>';
|
|
||||||
printf('<td>%s</td>',$attr->getOID());
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'obsolete':
|
|
||||||
printf('<td>%s</td>',$attr->getIsObsolete() ? '<b>'._('Yes').'</b>' : _('No'));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'inherits':
|
|
||||||
echo '<td>';
|
|
||||||
|
|
||||||
if (is_null($attr->getSupAttribute()))
|
|
||||||
printf('(%s)',_('none'));
|
|
||||||
|
|
||||||
else {
|
|
||||||
$href = htmlspecialchars(sprintf('%s&viewvalue=%s',$entry['href']['attributes'],strtolower($attr->getSupAttribute())));
|
|
||||||
if (isAjaxEnabled())
|
|
||||||
printf('<a href="cmd.php?%s" onclick="return ajSHOWSCHEMA(\'attributes\',\'at\',\'%s\');">%s</a>',
|
|
||||||
$href,strtolower($attr->getSupAttribute()),$attr->getSupAttribute());
|
|
||||||
else
|
|
||||||
printf('<a href="cmd.php?%s">%s</a>',$href,$attr->getSupAttribute());
|
|
||||||
}
|
|
||||||
|
|
||||||
echo '</td>';
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'equality':
|
|
||||||
echo '<td>';
|
|
||||||
|
|
||||||
if (is_null($attr->getEquality()))
|
|
||||||
printf('(%s)',_('not specified'));
|
|
||||||
|
|
||||||
else {
|
|
||||||
$href = htmlspecialchars(sprintf('%s&viewvalue=%s',$entry['href']['matching_rules'],$attr->getEquality()));
|
|
||||||
if (isAjaxEnabled())
|
|
||||||
printf('<a href="cmd.php?%s" onclick="return ajJUMP(\'%s\',\'%s\',\'%s\');">%s</a>',
|
|
||||||
$href,$href,_('Matching Rules'),$attr->getEquality(),$attr->getEquality());
|
|
||||||
else
|
|
||||||
printf('<a href="cmd.php?%s">%s</a>',$href,$attr->getEquality());
|
|
||||||
}
|
|
||||||
|
|
||||||
echo '</td>';
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'ordering':
|
|
||||||
printf('<td>%s</td>',
|
|
||||||
is_null($attr->getOrdering()) ? '('._('not specified').')' : $attr->getOrdering());
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'substring_rule':
|
|
||||||
printf('<td>%s</td>',
|
|
||||||
is_null($attr->getSubstr()) ? '('._('not specified').')' : $attr->getSubstr());
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'syntax':
|
|
||||||
echo '<td>';
|
|
||||||
|
|
||||||
if (is_null($attr->getType())) {
|
|
||||||
echo $attr->getSyntaxOID();
|
|
||||||
|
|
||||||
} else {
|
|
||||||
$href = htmlspecialchars(sprintf('%s&highlight_oid=%s',$entry['href']['syntaxes'],$attr->getSyntaxOID()));
|
|
||||||
if (isAjaxEnabled())
|
|
||||||
printf('<a href="cmd.php?%s" onclick="return ajJUMP(\'%s\',\'%s\',\'%s\');">%s (%s)</a>',
|
|
||||||
$href,$href,_('Syntaxes'),'',$attr->getType(),$attr->getSyntaxOID());
|
|
||||||
else
|
|
||||||
printf('<a href="cmd.php?%s">%s (%s)</a>',$href,$attr->getType(),$attr->getSyntaxOID());
|
|
||||||
}
|
|
||||||
|
|
||||||
echo '</td>';
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'single_valued':
|
|
||||||
printf('<td>%s</td>',$attr->getIsSingleValue() ? _('Yes') : _('No'));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'collective':
|
|
||||||
printf('<td>%s</td>',$attr->getIsCollective() ? _('Yes') : _('No'));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'user_modification':
|
|
||||||
printf('<td>%s</td>',$attr->getIsNoUserModification() ? _('No') : _('Yes'));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'usage':
|
|
||||||
printf('<td>%s</td>',$attr->getUsage() ? $attr->getUsage() : '('._('not specified').')');
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'maximum_length':
|
|
||||||
echo '<td>';
|
|
||||||
|
|
||||||
if ( is_null($attr->getMaxLength()))
|
|
||||||
echo '('._('not applicable').')';
|
|
||||||
|
|
||||||
else
|
|
||||||
printf('%s %s',number_format($attr->getMaxLength()),
|
|
||||||
$attr->getMaxLength()>1 ? _('characters') : _('character'));
|
|
||||||
|
|
||||||
echo '</td>';
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'aliases':
|
|
||||||
echo '<td>';
|
|
||||||
|
|
||||||
if (count($attr->getAliases()) == 0)
|
|
||||||
printf('(%s)',_('none'));
|
|
||||||
|
|
||||||
else
|
|
||||||
foreach ($attr->getAliases() as $alias) {
|
|
||||||
$href = htmlspecialchars(sprintf('%s&viewvalue=%s',$entry['href']['attributes'],strtolower($alias)));
|
|
||||||
if (isAjaxEnabled())
|
|
||||||
printf('<a href="cmd.php?%s" onclick="return ajSHOWSCHEMA(\'attributes\',\'at\',\'%s\');">%s</a>',
|
|
||||||
$href,strtolower($alias),$alias);
|
|
||||||
else
|
|
||||||
printf('<a href="cmd.php?%s">%s</a>',$href,$alias);
|
|
||||||
}
|
|
||||||
|
|
||||||
echo '</td>';
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'used_by_objectclasses':
|
|
||||||
echo '<td>';
|
|
||||||
|
|
||||||
if (count($attr->getUsedInObjectClasses()) == 0)
|
|
||||||
printf('(%s)',_('none'));
|
|
||||||
|
|
||||||
else
|
|
||||||
foreach ($attr->getUsedInObjectClasses() as $objectclass) {
|
|
||||||
$href = htmlspecialchars(sprintf('%s&viewvalue=%s',$entry['href']['objectclasses'],strtolower($objectclass)));
|
|
||||||
if (isAjaxEnabled())
|
|
||||||
printf('<a href="cmd.php?%s" onclick="return ajJUMP(\'%s\',\'%s\',\'%s\');">%s</a> ',
|
|
||||||
$href,$href,_('ObjectClasses'),strtolower($objectclass),$objectclass);
|
|
||||||
else
|
|
||||||
printf('<a href="cmd.php?%s">%s</a> ',$href,$objectclass);
|
|
||||||
}
|
|
||||||
|
|
||||||
echo '</td>';
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'force_as_may':
|
|
||||||
printf('<td>%s</td>',$attr->isForceMay() ? _('Yes') : _('No'));
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
echo '</tr>';
|
|
||||||
}
|
|
||||||
echo '</table>';
|
|
||||||
echo '<br />';
|
|
||||||
echo '</div>';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'matching_rules':
|
|
||||||
$schema_matching_rules = $app['server']->MatchingRules();
|
|
||||||
if (! $schema_matching_rules)
|
|
||||||
error($schema_error_str,'error','index.php');
|
|
||||||
|
|
||||||
printf('<small>%s</small><br />',_('Jump to a matching rule'));
|
|
||||||
|
|
||||||
echo '<form action="cmd.php" method="get">';
|
|
||||||
echo '<div>';
|
|
||||||
echo '<input type="hidden" name="cmd" value="schema" />';
|
|
||||||
printf('<input type="hidden" name="server_id" value="%s" />',$app['server']->getIndex());
|
|
||||||
echo '<input type="hidden" name="view" value="matching_rules" />';
|
|
||||||
|
|
||||||
if (isAjaxEnabled()) {
|
|
||||||
drawJSItems($schema_matching_rules);
|
|
||||||
echo '<select name="viewvalue" onchange="ajSHOWSCHEMA(\'matchingrules\',\'mr\')" id="matchingrules">';
|
|
||||||
} else
|
|
||||||
echo '<select name="viewvalue" onchange="submit()">';
|
|
||||||
|
|
||||||
echo '<option value=""> - all -</option>';
|
|
||||||
foreach ($schema_matching_rules as $rule)
|
|
||||||
printf('<option value="%s" %s>%s</option>',
|
|
||||||
$rule->getName(),
|
|
||||||
($rule->getName() == $entry['value'] ? 'selected="selected"': ''),
|
|
||||||
$rule->getName(false));
|
|
||||||
|
|
||||||
echo '</select>';
|
|
||||||
|
|
||||||
if (isAjaxEnabled())
|
|
||||||
printf('<input type="button" value="%s" onclick="ajSHOWSCHEMA(\'matchingrules\',\'mr\')"/>',_('Go'));
|
|
||||||
else
|
|
||||||
printf('<input type="submit" value="%s" />',_('Go'));
|
|
||||||
echo '</div>';
|
|
||||||
echo '</form>';
|
|
||||||
echo '<br />';
|
|
||||||
|
|
||||||
echo '<table class="result_table" width="100%" border="0">';
|
|
||||||
printf('<tr class="heading"><td>%s</td><td>%s</td><td>%s</td></tr>',
|
|
||||||
_('Matching Rule OID'),_('Name'),_('Used by Attributes'));
|
|
||||||
|
|
||||||
$counter = 1;
|
|
||||||
|
|
||||||
foreach ($schema_matching_rules as $rule) {
|
|
||||||
$counter++;
|
|
||||||
$oid = $rule->getOID();
|
|
||||||
$desc = $rule->getName(false);
|
|
||||||
|
|
||||||
if (isAjaxEnabled() || (is_null($entry['value']) || ! trim($entry['value']) || $entry['value']==$rule->getName())) {
|
|
||||||
if ((! is_null($entry['value']) && $entry['value']==$rule->getName()) || ! trim($entry['value']))
|
|
||||||
$entry['viewed'] = true;
|
|
||||||
|
|
||||||
if (null != $rule->getDescription())
|
|
||||||
$desc .= sprintf(' (%s)',$rule->getDescription());
|
|
||||||
|
|
||||||
if ( $rule->getIsObsolete())
|
|
||||||
$desc .= sprintf(' <span style="color:red">%s</span>',_('Obsolete'));
|
|
||||||
|
|
||||||
if (isAjaxEnabled() && $entry['value'])
|
|
||||||
printf('<tr class="%s" id="mr%s" style="display: %s">',$counter%2 ? 'odd' : 'even',$rule->getName(),
|
|
||||||
strcasecmp($entry['value'],$rule->getName()) ? 'none' : '');
|
|
||||||
else
|
|
||||||
printf('<tr class="%s" id="mr%s">',$counter%2 ? 'odd' : 'even',$rule->getName());
|
|
||||||
printf('<td>%s</td>',$oid);
|
|
||||||
printf('<td>%s</td>',$desc);
|
|
||||||
|
|
||||||
echo '<td>';
|
|
||||||
|
|
||||||
if (count($rule->getUsedByAttrs()) == 0) {
|
|
||||||
printf('<div style="text-align: center;">(%s)</div><br /><br />',_('none'));
|
|
||||||
|
|
||||||
} else {
|
|
||||||
echo '<table width="100%" border="0"><tr><td>';
|
|
||||||
echo '<form action="cmd.php" method="get">';
|
|
||||||
echo '<div>';
|
|
||||||
echo '<input type="hidden" name="cmd" value="schema" />';
|
|
||||||
printf('<input type="hidden" name="server_id" value="%s" />',$app['server']->getIndex());
|
|
||||||
echo '<input type="hidden" name="view" value="attributes" />';
|
|
||||||
|
|
||||||
printf('<select size="4" name="viewvalue" id="vv%s">',$rule->getName());
|
|
||||||
foreach ($rule->getUsedByAttrs() as $attr)
|
|
||||||
printf('<option>%s</option>',$attr);
|
|
||||||
echo '</select><br />';
|
|
||||||
|
|
||||||
if (isAjaxEnabled())
|
|
||||||
printf('<input type="button" value="%s" onclick="return ajJUMP(\'cmd=schema&view=attributes&server_id=%s\',\'%s\',\'%s\',\'vv\');"/>',
|
|
||||||
_('Go'),$app['server']->getIndex(),_('Attributes'),$rule->getName());
|
|
||||||
else
|
|
||||||
printf('<input type="submit" value="%s" />',_('Go'));
|
|
||||||
echo '</div>';
|
|
||||||
echo '</form>';
|
|
||||||
echo '</td></tr></table>';
|
|
||||||
}
|
|
||||||
echo '</td>';
|
|
||||||
echo '</tr>';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
echo '</table>';
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'objectclasses':
|
|
||||||
$socs = $app['server']->SchemaObjectClasses();
|
|
||||||
if (! $socs)
|
|
||||||
error($schema_error_str,'error','index.php');
|
|
||||||
|
|
||||||
printf('<small>%s:</small>',_('Jump to an objectClass'));
|
|
||||||
|
|
||||||
echo '<form action="cmd.php" method="get">';
|
|
||||||
echo '<div>';
|
|
||||||
echo '<input type="hidden" name="cmd" value="schema" />';
|
|
||||||
printf('<input type="hidden" name="view" value="%s" />',$entry['view']);
|
|
||||||
printf('<input type="hidden" name="server_id" value="%s" />',$app['server']->getIndex());
|
|
||||||
|
|
||||||
if (isAjaxEnabled()) {
|
|
||||||
drawJSItems($socs);
|
|
||||||
echo '<select name="viewvalue" onchange="ajSHOWSCHEMA(\'objectclasses\',\'oc\')" id="objectclasses">';
|
|
||||||
} else
|
|
||||||
echo '<select name="viewvalue" onchange="submit()">';
|
|
||||||
|
|
||||||
echo '<option value=""> - all - </option>';
|
|
||||||
foreach ($socs as $name => $oclass)
|
|
||||||
printf('<option value="%s" %s>%s</option>',
|
|
||||||
$name,$name == $entry['value'] ? 'selected="selected" ': '',$oclass->getName(false));
|
|
||||||
|
|
||||||
echo '</select>';
|
|
||||||
|
|
||||||
if (isAjaxEnabled())
|
|
||||||
printf('<input type="button" value="%s" onclick="ajSHOWSCHEMA(\'objectclasses\',\'oc\')"/>',_('Go'));
|
|
||||||
else
|
|
||||||
printf('<input type="submit" value="%s" />',_('Go'));
|
|
||||||
echo '</div>';
|
|
||||||
echo '</form>';
|
|
||||||
echo '<br />';
|
|
||||||
|
|
||||||
foreach ($socs as $name => $oclass) {
|
|
||||||
if (isAjaxEnabled() || (is_null($entry['value']) || ! trim($entry['value']) || $entry['value']==$oclass->getName())) {
|
|
||||||
if ((! is_null($entry['value']) && $entry['value']==$oclass->getName()) || ! trim($entry['value']))
|
|
||||||
$entry['viewed'] = true;
|
|
||||||
|
|
||||||
if (isAjaxEnabled() && $entry['value'])
|
|
||||||
printf('<div id="oc%s" style="display: %s">',$oclass->getName(),strcasecmp($entry['value'],$oclass->getName()) ? 'none' : '');
|
|
||||||
else
|
|
||||||
printf('<div id="oc%s">',$oclass->getName());
|
|
||||||
|
|
||||||
echo '<table class="result_table" width="100%" border="0">';
|
|
||||||
printf('<tr class="heading"><td colspan="4"><a name="%s">%s</a></td></tr>',$name,$oclass->getName(false));
|
|
||||||
printf('<tr class="odd"><td colspan="4">%s: <b>%s</b></td></tr>',_('OID'),$oclass->getOID());
|
|
||||||
|
|
||||||
if ($oclass->getDescription())
|
|
||||||
printf('<tr class="odd"><td colspan="4">%s: <b>%s</b></td></tr>',_('Description'),$oclass->getDescription());
|
|
||||||
|
|
||||||
printf('<tr class="odd"><td colspan="4">%s: <b>%s</b></td></tr>',_('Type'),$oclass->getType());
|
|
||||||
|
|
||||||
if ($oclass->getIsObsolete())
|
|
||||||
printf('<tr class="odd"><td colspan="4">%s</td></tr>',_('This objectClass is obsolete.'));
|
|
||||||
|
|
||||||
printf('<tr class="odd"><td colspan="4">%s: <b>',_('Inherits from'));
|
|
||||||
if (count($oclass->getSupClasses()) == 0)
|
|
||||||
printf('(%s)',_('none'));
|
|
||||||
|
|
||||||
else
|
|
||||||
foreach ($oclass->getSupClasses() as $i => $object_class) {
|
|
||||||
$href = htmlspecialchars(sprintf('%s&viewvalue=%s',$entry['href']['objectclasses'],strtolower($object_class)));
|
|
||||||
if (isAjaxEnabled())
|
|
||||||
printf('<a href="cmd.php?%s" onclick="return ajSHOWSCHEMA(\'objectclasses\',\'oc\',\'%s\');">%s</a>',
|
|
||||||
$href,strtolower($object_class),$object_class);
|
|
||||||
else
|
|
||||||
printf('<a href="cmd.php?%s&viewvalue=%s" title="%s">%s</a>',
|
|
||||||
$href,$object_class,_('Jump to this objectClass definition'),$object_class);
|
|
||||||
|
|
||||||
if ($i < count($oclass->getSupClasses()) - 1)
|
|
||||||
echo ', ';
|
|
||||||
}
|
|
||||||
echo '</b></td></tr>';
|
|
||||||
|
|
||||||
printf('<tr class="odd"><td colspan="4">%s: <b>',_('Parent to'));
|
|
||||||
if (strcasecmp($oclass->getName(),'top') == 0) {
|
|
||||||
$href = htmlspecialchars($entry['href']['objectclasses']);
|
|
||||||
if (isAjaxEnabled())
|
|
||||||
printf('<a href="cmd.php?%s" onclick="return ajSHOWSCHEMA(\'objectclasses\',\'oc\',\'\');">all</a>',
|
|
||||||
$href);
|
|
||||||
else
|
|
||||||
printf('(<a href="cmd.php?%s">all</a>)',$href);
|
|
||||||
|
|
||||||
} elseif (count($oclass->getChildObjectClasses()) == 0)
|
|
||||||
printf('(%s)',_('none'));
|
|
||||||
|
|
||||||
else
|
|
||||||
foreach ($oclass->getChildObjectClasses() as $i => $object_class) {
|
|
||||||
$href = htmlspecialchars(sprintf('%s&viewvalue=%s',$entry['href']['objectclasses'],strtolower($object_class)));
|
|
||||||
if (isAjaxEnabled())
|
|
||||||
printf('<a href="cmd.php?%s" title="%s" onclick="return ajSHOWSCHEMA(\'objectclasses\',\'oc\',\'%s\');">%s</a>',
|
|
||||||
$href,_('Jump to this objectClass definition'),strtolower($object_class),$object_class);
|
|
||||||
else
|
|
||||||
printf('<a href="cmd.php?%s" title="%s">%s</a>',$href,_('Jump to this objectClass definition'),$object_class);
|
|
||||||
|
|
||||||
if ( $i < count($oclass->getChildObjectClasses()) - 1)
|
|
||||||
echo ', ';
|
|
||||||
}
|
|
||||||
echo '</b></td></tr>';
|
|
||||||
|
|
||||||
printf('<tr class="even"><td class="blank" rowspan="2" style="width: 5%%;"> </td><td style="width: 45%%;"><b>%s</b></td><td style="width: 45%%;"><b>%s</b></td><td class="blank" rowspan="2" style="width: 5%%;"> </td></tr>',
|
|
||||||
_('Required Attributes'),_('Optional Attributes'));
|
|
||||||
|
|
||||||
echo '<tr class="odd">';
|
|
||||||
echo '<td>';
|
|
||||||
|
|
||||||
if ($attrs = $oclass->getMustAttrs(true)) {
|
|
||||||
echo '<ul class="list">';
|
|
||||||
|
|
||||||
foreach ($attrs as $attr) {
|
|
||||||
echo '<li>';
|
|
||||||
$href = htmlspecialchars(sprintf('%s&viewvalue=%s',$entry['href']['attributes'],$attr->getName()));
|
|
||||||
if (isAjaxEnabled())
|
|
||||||
printf('<a href="cmd.php?%s" onclick="return ajJUMP(\'%s\',\'%s\',\'%s\');">%s</a>',
|
|
||||||
$href,$href,_('Attributes'),$attr->getName(),$attr->getName(false));
|
|
||||||
else
|
|
||||||
printf('<a href="cmd.php?%s">%s</a>',$href,$attr->getName(false));
|
|
||||||
|
|
||||||
if ($attr->getSource() != $oclass->getName(false)) {
|
|
||||||
echo '<br />';
|
|
||||||
$href = htmlspecialchars(sprintf('%s&viewvalue=%s',$entry['href']['objectclasses'],strtolower($attr->getSource())));
|
|
||||||
printf('<small>(%s ',_('Inherited from'));
|
|
||||||
if (isAjaxEnabled())
|
|
||||||
printf('<a href="cmd.php?%s" title="%s" onclick="return ajSHOWSCHEMA(\'objectclasses\',\'oc\',\'%s\');">%s</a>',
|
|
||||||
$href,_('Jump to this objectClass definition'),strtolower($attr->getSource()),$attr->getSource());
|
|
||||||
else
|
|
||||||
printf('<a href="cmd.php?%s">%s</a>',$href,$attr->getSource());
|
|
||||||
echo ')</small>';
|
|
||||||
}
|
|
||||||
echo '</li>';
|
|
||||||
}
|
|
||||||
echo '</ul>';
|
|
||||||
|
|
||||||
} else
|
|
||||||
printf('(%s)',_('none'));
|
|
||||||
|
|
||||||
echo '</td>';
|
|
||||||
echo '<td>';
|
|
||||||
|
|
||||||
if ($attrs = $oclass->getMayAttrs(true)) {
|
|
||||||
echo '<ul class="list">';
|
|
||||||
|
|
||||||
foreach ($attrs as $attr) {
|
|
||||||
echo '<li>';
|
|
||||||
$href = htmlspecialchars(sprintf('%s&viewvalue=%s',$entry['href']['attributes'],$attr->getName()));
|
|
||||||
if (isAjaxEnabled())
|
|
||||||
printf('<a href="cmd.php?%s" onclick="return ajJUMP(\'%s\',\'%s\',\'%s\');">%s</a>',
|
|
||||||
$href,$href,_('Attributes'),$attr->getName(),$attr->getName(false));
|
|
||||||
else
|
|
||||||
printf('<a href="cmd.php?%s">%s</a>',$href,$attr->getName(false));
|
|
||||||
|
|
||||||
if ($attr->getSource() != $oclass->getName(false)) {
|
|
||||||
echo '<br />';
|
|
||||||
$href = htmlspecialchars(sprintf('%s&viewvalue=%s',$entry['href']['objectclasses'],strtolower($attr->getSource())));
|
|
||||||
printf('<small>(%s ',_('Inherited from'));
|
|
||||||
if (isAjaxEnabled())
|
|
||||||
printf('<a href="cmd.php?%s" title="%s" onclick="return ajSHOWSCHEMA(\'objectclasses\',\'oc\',\'%s\');">%s</a>',
|
|
||||||
$href,_('Jump to this objectClass definition'),strtolower($attr->getSource()),$attr->getSource());
|
|
||||||
else
|
|
||||||
printf('<a href="cmd.php?%s">%s</a>',$href,$attr->getSource());
|
|
||||||
echo ')</small>';
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($oclass->isForceMay($attr->getName())) {
|
|
||||||
echo '<br />';
|
|
||||||
printf('<small>%s</small>',_('This attribute has been forced as a MAY attribute by the configuration'));
|
|
||||||
}
|
|
||||||
echo '</li>';
|
|
||||||
}
|
|
||||||
echo '</ul>';
|
|
||||||
|
|
||||||
} else
|
|
||||||
printf('(%s)',_('none'));
|
|
||||||
|
|
||||||
echo '</td>';
|
|
||||||
echo '</tr>';
|
|
||||||
echo '</table>';
|
|
||||||
echo '<br />';
|
|
||||||
echo '</div>';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! is_null($entry['value']) && ! $entry['viewed'])
|
|
||||||
error(sprintf(_('No such schema item: "%s"'),$entry['value']),'error','index.php');
|
|
||||||
|
|
||||||
function drawJSItems($object) {
|
|
||||||
echo '<script type="text/javascript">'."\n";
|
|
||||||
|
|
||||||
echo "
|
|
||||||
function items() {
|
|
||||||
var \$items = new Array();";
|
|
||||||
$counter = 0;
|
|
||||||
foreach ($object as $attr) {
|
|
||||||
printf(' items[%s] = "%s";',$counter++,$attr->getName());
|
|
||||||
echo "\n";
|
|
||||||
}
|
|
||||||
echo '
|
|
||||||
return items;
|
|
||||||
}';
|
|
||||||
|
|
||||||
echo '</script>';
|
|
||||||
}
|
|
||||||
?>
|
|
852
lib/ds_ldap.php
852
lib/ds_ldap.php
@ -1134,859 +1134,7 @@ class ldap extends DS {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getRootDSE($method=null) {
|
|
||||||
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
|
|
||||||
debug_log('Entered (%%)',17,0,__FILE__,__LINE__,__METHOD__,$fargs);
|
|
||||||
|
|
||||||
$query = array();
|
|
||||||
$query['base'] = '';
|
|
||||||
$query['scope'] = 'base';
|
|
||||||
$query['attrs'] = $this->getValue('server','root_dse_attributes');
|
|
||||||
$query['baseok'] = true;
|
|
||||||
$results = $this->query($query,$method);
|
|
||||||
|
|
||||||
if (is_array($results) && count($results) == 1)
|
|
||||||
return array_change_key_case(array_pop($results));
|
|
||||||
else
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Schema Methods **/
|
/** Schema Methods **/
|
||||||
/**
|
|
||||||
* This function will query the ldap server and request the subSchemaSubEntry which should be the Schema DN.
|
|
||||||
*
|
|
||||||
* If we cant connect to the LDAP server, we'll return false.
|
|
||||||
* If we can connect but cant get the entry, then we'll return null.
|
|
||||||
*
|
|
||||||
* @param string Which connection method resource to use
|
|
||||||
* @param dn The DN to use to obtain the schema
|
|
||||||
* @return array|false Schema if available, null if its not or false if we cant connect.
|
|
||||||
*/
|
|
||||||
private function getSchemaDN($method=null,$dn='') {
|
|
||||||
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
|
|
||||||
debug_log('Entered (%%)',25,0,__FILE__,__LINE__,__METHOD__,$fargs);
|
|
||||||
|
|
||||||
# If we already got the SchemaDN, then return it.
|
|
||||||
if ($this->_schemaDN)
|
|
||||||
return $this->_schemaDN;
|
|
||||||
|
|
||||||
if (! $this->connect($method))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
$search = @ldap_read($this->connect($method),$dn,'objectclass=*',array('subschemaSubentry'),false,0,10,LDAP_DEREF_NEVER);
|
|
||||||
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Search returned (%s)',24,0,__FILE__,__LINE__,__METHOD__,is_resource($search));
|
|
||||||
|
|
||||||
# Fix for broken ldap.conf configuration.
|
|
||||||
if (! $search && ! $dn) {
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Trying to find the DN for "broken" ldap.conf',80,0,__FILE__,__LINE__,__METHOD__);
|
|
||||||
|
|
||||||
if (isset($this->_baseDN)) {
|
|
||||||
foreach ($this->_baseDN as $base) {
|
|
||||||
$search = @ldap_read($this->connect($method),$base,'objectclass=*',array('subschemaSubentry'),false,0,10,LDAP_DEREF_NEVER);
|
|
||||||
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Search returned (%s) for base (%s)',24,0,__FILE__,__LINE__,__METHOD__,
|
|
||||||
is_resource($search),$base);
|
|
||||||
|
|
||||||
if ($search)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! $search)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
if (! @ldap_count_entries($this->connect($method),$search)) {
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Search returned 0 entries. Returning NULL',25,0,__FILE__,__LINE__,__METHOD__);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$entries = @ldap_get_entries($this->connect($method),$search);
|
|
||||||
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Search returned [%s]',24,0,__FILE__,__LINE__,__METHOD__,$entries);
|
|
||||||
|
|
||||||
if (! $entries || ! is_array($entries))
|
|
||||||
return null;
|
|
||||||
|
|
||||||
$entry = isset($entries[0]) ? $entries[0] : false;
|
|
||||||
if (! $entry) {
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Entry is false, Returning NULL',80,0,__FILE__,__LINE__,__METHOD__);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$sub_schema_sub_entry = isset($entry[0]) ? $entry[0] : false;
|
|
||||||
if (! $sub_schema_sub_entry) {
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Sub Entry is false, Returning NULL',80,0,__FILE__,__LINE__,__METHOD__);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->_schemaDN = isset($entry[$sub_schema_sub_entry][0]) ? $entry[$sub_schema_sub_entry][0] : false;
|
|
||||||
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Returning (%s)',25,0,__FILE__,__LINE__,__METHOD__,$this->_schemaDN);
|
|
||||||
|
|
||||||
return $this->_schemaDN;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches the raw schema array for the subschemaSubentry of the server. Note,
|
|
||||||
* this function has grown many hairs to accomodate more LDAP servers. It is
|
|
||||||
* needfully complicated as it now supports many popular LDAP servers that
|
|
||||||
* don't necessarily expose their schema "the right way".
|
|
||||||
*
|
|
||||||
* Please note: On FC systems, it seems that php_ldap uses /etc/openldap/ldap.conf in
|
|
||||||
* the search base if it is blank - so edit that file and comment out the BASE line.
|
|
||||||
*
|
|
||||||
* @param string Which connection method resource to use
|
|
||||||
* @param string A string indicating which type of schema to
|
|
||||||
* fetch. Five valid values: 'objectclasses', 'attributetypes',
|
|
||||||
* 'ldapsyntaxes', 'matchingruleuse', or 'matchingrules'.
|
|
||||||
* Case insensitive.
|
|
||||||
* @param dn (optional) This paremeter is the DN of the entry whose schema you
|
|
||||||
* would like to fetch. Entries have the option of specifying
|
|
||||||
* their own subschemaSubentry that points to the DN of the system
|
|
||||||
* schema entry which applies to this attribute. If unspecified,
|
|
||||||
* this will try to retrieve the schema from the RootDSE subschemaSubentry.
|
|
||||||
* Failing that, we use some commonly known schema DNs. Default
|
|
||||||
* value is the Root DSE DN (zero-length string)
|
|
||||||
* @return array an array of strings of this form:
|
|
||||||
* Array (
|
|
||||||
* [0] => "(1.3.6.1.4.1.7165.1.2.2.4 NAME 'gidPool' DESC 'Pool ...
|
|
||||||
* [1] => "(1.3.6.1.4.1.7165.2.2.3 NAME 'sambaAccount' DESC 'Sa ...
|
|
||||||
* etc.
|
|
||||||
*/
|
|
||||||
private function getRawSchema($method,$schema_to_fetch,$dn='') {
|
|
||||||
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
|
|
||||||
debug_log('Entered (%%)',25,0,__FILE__,__LINE__,__METHOD__,$fargs);
|
|
||||||
|
|
||||||
$valid_schema_to_fetch = array('objectclasses','attributetypes','ldapsyntaxes','matchingrules','matchingruleuse');
|
|
||||||
|
|
||||||
if (! $this->connect($method) || $this->noconnect)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
# error checking
|
|
||||||
$schema_to_fetch = strtolower($schema_to_fetch);
|
|
||||||
|
|
||||||
if (! is_null($this->_schema_entries) && isset($this->_schema_entries[$schema_to_fetch])) {
|
|
||||||
$schema = $this->_schema_entries[$schema_to_fetch];
|
|
||||||
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Returning CACHED (%s)',25,0,__FILE__,__LINE__,__METHOD__,$schema);
|
|
||||||
|
|
||||||
return $schema;
|
|
||||||
}
|
|
||||||
|
|
||||||
# This error message is not localized as only developers should ever see it
|
|
||||||
if (! in_array($schema_to_fetch,$valid_schema_to_fetch))
|
|
||||||
error(sprintf('Bad parameter provided to function to %s::getRawSchema(). "%s" is not valid for the schema_to_fetch parameter.',
|
|
||||||
get_class($this),$schema_to_fetch),'error','index.php');
|
|
||||||
|
|
||||||
# Try to get the schema DN from the specified entry.
|
|
||||||
$schema_dn = $this->getSchemaDN($method,$dn);
|
|
||||||
|
|
||||||
# Do we need to try again with the Root DSE?
|
|
||||||
if (! $schema_dn && trim($dn))
|
|
||||||
$schema_dn = $this->getSchemaDN($method,'');
|
|
||||||
|
|
||||||
# Store the eventual schema retrieval in $schema_search
|
|
||||||
$schema_search = null;
|
|
||||||
|
|
||||||
if ($schema_dn) {
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Using Schema DN (%s)',24,0,__FILE__,__LINE__,__METHOD__,$schema_dn);
|
|
||||||
|
|
||||||
foreach (array('(objectClass=*)','(objectClass=subschema)') as $schema_filter) {
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Looking for schema with Filter (%s)',24,0,__FILE__,__LINE__,__METHOD__,$schema_filter);
|
|
||||||
|
|
||||||
$schema_search = @ldap_read($this->connect($method),$schema_dn,$schema_filter,array($schema_to_fetch),false,0,10,LDAP_DEREF_NEVER);
|
|
||||||
|
|
||||||
if (is_null($schema_search))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
$schema_entries = @ldap_get_entries($this->connect($method),$schema_search);
|
|
||||||
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Search returned [%s]',24,0,__FILE__,__LINE__,__METHOD__,$schema_entries);
|
|
||||||
|
|
||||||
if (is_array($schema_entries) && isset($schema_entries['count']) && $schema_entries['count']) {
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Found schema with (DN:%s) (FILTER:%s) (ATTR:%s)',24,0,__FILE__,__LINE__,__METHOD__,
|
|
||||||
$schema_dn,$schema_filter,$schema_to_fetch);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Didnt find schema with filter (%s)',24,0,__FILE__,__LINE__,__METHOD__,$schema_filter);
|
|
||||||
|
|
||||||
unset($schema_entries);
|
|
||||||
$schema_search = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Second chance: If the DN or Root DSE didn't give us the subschemaSubentry, ie $schema_search
|
|
||||||
* is still null, use some common subSchemaSubentry DNs as a work-around. */
|
|
||||||
if (is_null($schema_search)) {
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Attempting work-arounds for "broken" LDAP servers...',24,0,__FILE__,__LINE__,__METHOD__);
|
|
||||||
|
|
||||||
foreach ($this->getBaseDN() as $base) {
|
|
||||||
$ldap['W2K3 AD'][expand_dn_with_base($base,'cn=Aggregate,cn=Schema,cn=configuration,')] = '(objectClass=*)';
|
|
||||||
$ldap['W2K AD'][expand_dn_with_base($base,'cn=Schema,cn=configuration,')] = '(objectClass=*)';
|
|
||||||
$ldap['W2K AD'][expand_dn_with_base($base,'cn=Schema,ou=Admin,')] = '(objectClass=*)';
|
|
||||||
}
|
|
||||||
|
|
||||||
# OpenLDAP and Novell
|
|
||||||
$ldap['OpenLDAP']['cn=subschema'] = '(objectClass=*)';
|
|
||||||
|
|
||||||
foreach ($ldap as $ldap_server_name => $ldap_options) {
|
|
||||||
foreach ($ldap_options as $ldap_dn => $ldap_filter) {
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Attempting [%s] (%s) (%s)<BR>',24,0,__FILE__,__LINE__,__METHOD__,
|
|
||||||
$ldap_server_name,$ldap_dn,$ldap_filter);
|
|
||||||
|
|
||||||
$schema_search = @ldap_read($this->connect($method),$ldap_dn,$ldap_filter,array($schema_to_fetch),false,0,10,LDAP_DEREF_NEVER);
|
|
||||||
if (is_null($schema_search))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
$schema_entries = @ldap_get_entries($this->connect($method),$schema_search);
|
|
||||||
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Search returned [%s]',24,0,__FILE__,__LINE__,__METHOD__,$schema_entries);
|
|
||||||
|
|
||||||
if ($schema_entries && isset($schema_entries[0][$schema_to_fetch])) {
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Found schema with filter of (%s)',24,0,__FILE__,__LINE__,__METHOD__,$ldap_filter);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Didnt find schema with filter (%s)',24,0,__FILE__,__LINE__,__METHOD__,$ldap_filter);
|
|
||||||
|
|
||||||
unset($schema_entries);
|
|
||||||
$schema_search = null;
|
|
||||||
}
|
|
||||||
if ($schema_search)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Option 3: try cn=config
|
|
||||||
$olc_schema = 'olc'.$schema_to_fetch;
|
|
||||||
$olc_schema_found = false;
|
|
||||||
if (is_null($schema_search)) {
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Attempting cn=config work-around...',24,0,__FILE__,__LINE__,__METHOD__);
|
|
||||||
|
|
||||||
$ldap_dn = 'cn=schema,cn=config';
|
|
||||||
$ldap_filter = '(objectClass=*)';
|
|
||||||
|
|
||||||
$schema_search = @ldap_search($this->connect($method),$ldap_dn,$ldap_filter,array($olc_schema),false,0,10,LDAP_DEREF_NEVER);
|
|
||||||
|
|
||||||
if (! is_null($schema_search)) {
|
|
||||||
$schema_entries = @ldap_get_entries($this->connect($method),$schema_search);
|
|
||||||
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Search returned [%s]',24,0,__FILE__,__LINE__,__METHOD__,$schema_entries);
|
|
||||||
|
|
||||||
if ($schema_entries) {
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Found schema with filter of (%s) and attribute filter (%s)',24,0,__FILE__,__LINE__,__METHOD__,$ldap_filter,$olc_schema);
|
|
||||||
|
|
||||||
$olc_schema_found = true;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Didnt find schema with filter (%s) and attribute filter (%s)',24,0,__FILE__,__LINE__,__METHOD__,$ldap_filter,$olc_schema);
|
|
||||||
|
|
||||||
unset($schema_entries);
|
|
||||||
$schema_search = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_null($schema_search)) {
|
|
||||||
/* Still cant find the schema, try with the RootDSE
|
|
||||||
* Attempt to pull schema from Root DSE with scope "base", or
|
|
||||||
* Attempt to pull schema from Root DSE with scope "one" (work-around for Isode M-Vault X.500/LDAP) */
|
|
||||||
foreach (array('base','one') as $ldap_scope) {
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Attempting to find schema with scope (%s), filter (objectClass=*) and a blank base.',24,0,__FILE__,__LINE__,__METHOD__,
|
|
||||||
$ldap_scope);
|
|
||||||
|
|
||||||
switch ($ldap_scope) {
|
|
||||||
case 'base':
|
|
||||||
$schema_search = @ldap_read($this->connect($method),'','(objectClass=*)',array($schema_to_fetch),false,0,10,LDAP_DEREF_NEVER);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'one':
|
|
||||||
$schema_search = @ldap_list($this->connect($method),'','(objectClass=*)',array($schema_to_fetch),false,0,10,LDAP_DEREF_NEVER);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_null($schema_search))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
$schema_entries = @ldap_get_entries($this->connect($method),$schema_search);
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Search returned [%s]',24,0,__FILE__,__LINE__,__METHOD__,$schema_entries);
|
|
||||||
|
|
||||||
if ($schema_entries && isset($schema_entries[0][$schema_to_fetch])) {
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Found schema with filter of (%s)',24,0,__FILE__,__LINE__,__METHOD__,'(objectClass=*)');
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Didnt find schema with filter (%s)',24,0,__FILE__,__LINE__,__METHOD__,'(objectClass=*)');
|
|
||||||
|
|
||||||
unset($schema_entries);
|
|
||||||
$schema_search = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$schema_error_message = 'Please contact the phpLDAPadmin developers and let them know:<ul><li>Which LDAP server you are running, including which version<li>What OS it is running on<li>Which version of PHP<li>As well as a link to some documentation that describes how to obtain the SCHEMA information</ul><br />We\'ll then add support for your LDAP server in an upcoming release.';
|
|
||||||
$schema_error_message_array = array('objectclasses','attributetypes');
|
|
||||||
|
|
||||||
# Shall we just give up?
|
|
||||||
if (is_null($schema_search)) {
|
|
||||||
# We need to have objectclasses and attribues, so display an error, asking the user to get us this information.
|
|
||||||
if (in_array($schema_to_fetch,$schema_error_message_array))
|
|
||||||
system_message(array(
|
|
||||||
'title'=>sprintf('%s (%s)',_('Our attempts to find your SCHEMA have failed'),$schema_to_fetch),
|
|
||||||
'body'=>sprintf('<b>%s</b>: %s',_('Error'),$schema_error_message),
|
|
||||||
'type'=>'error'));
|
|
||||||
else
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Returning because schema_search is NULL ()',25,0,__FILE__,__LINE__,__METHOD__);
|
|
||||||
|
|
||||||
# We'll set this, so if we return here our cache will return the known false.
|
|
||||||
$this->_schema_entries[$schema_to_fetch] = false;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! $schema_entries) {
|
|
||||||
$return = false;
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Returning false since ldap_get_entries() returned false.',25,0,__FILE__,__LINE__,__METHOD__,$return);
|
|
||||||
|
|
||||||
return $return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($olc_schema_found) {
|
|
||||||
unset ($schema_entries['count']);
|
|
||||||
|
|
||||||
foreach ($schema_entries as $entry) {
|
|
||||||
if (isset($entry[$olc_schema])) {
|
|
||||||
unset($entry[$olc_schema]['count']);
|
|
||||||
|
|
||||||
foreach ($entry[$olc_schema] as $schema_definition)
|
|
||||||
/* Schema definitions in child nodes prefix the schema entries with "{n}"
|
|
||||||
the preg_replace call strips out this prefix. */
|
|
||||||
$schema[] = preg_replace('/^\{\d*\}\(/','(',$schema_definition);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($schema)) {
|
|
||||||
$this->_schema_entries[$olc_schema] = $schema;
|
|
||||||
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Returning (%s)',25,0,__FILE__,__LINE__,__METHOD__,$schema);
|
|
||||||
|
|
||||||
return $schema;
|
|
||||||
|
|
||||||
} else
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! isset($schema_entries[0][$schema_to_fetch])) {
|
|
||||||
if (in_array($schema_to_fetch,$schema_error_message_array)) {
|
|
||||||
error(sprintf('Our attempts to find your SCHEMA for "%s" have return UNEXPECTED results.<br /><br /><small>(We expected a "%s" in the $schema array but it wasnt there.)</small><br /><br />%s<br /><br />Dump of $schema_search:<hr /><pre><small>%s</small></pre>',
|
|
||||||
$schema_to_fetch,gettype($schema_search),$schema_error_message,serialize($schema_entries)),'error','index.php');
|
|
||||||
|
|
||||||
} else {
|
|
||||||
$return = false;
|
|
||||||
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Returning because (%s) isnt in the schema array. (%s)',25,0,__FILE__,__LINE__,__METHOD__,$schema_to_fetch,$return);
|
|
||||||
|
|
||||||
return $return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make a nice array of this form:
|
|
||||||
Array (
|
|
||||||
[0] => "(1.3.6.1.4.1.7165.1.2.2.4 NAME 'gidPool' DESC 'Pool ...)"
|
|
||||||
[1] => "(1.3.6.1.4.1.7165.2.2.3 NAME 'sambaAccount' DESC 'Sa ...)"
|
|
||||||
etc.) */
|
|
||||||
|
|
||||||
$schema = $schema_entries[0][$schema_to_fetch];
|
|
||||||
unset($schema['count']);
|
|
||||||
$this->_schema_entries[$schema_to_fetch] = $schema;
|
|
||||||
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Returning (%s)',25,0,__FILE__,__LINE__,__METHOD__,$schema);
|
|
||||||
|
|
||||||
return $schema;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a single ObjectClass object specified by name.
|
|
||||||
*
|
|
||||||
* @param string $oclass_name The name of the objectClass to fetch.
|
|
||||||
* @param string $dn (optional) It is easier to fetch schema if a DN is provided
|
|
||||||
* which defines the subschemaSubEntry attribute (all entries should).
|
|
||||||
*
|
|
||||||
* @return ObjectClass The specified ObjectClass object or false on error.
|
|
||||||
*
|
|
||||||
* @see ObjectClass
|
|
||||||
* @see SchemaObjectClasses
|
|
||||||
*/
|
|
||||||
public function getSchemaObjectClass($oclass_name,$method=null,$dn='') {
|
|
||||||
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
|
|
||||||
debug_log('Entered (%%)',25,0,__FILE__,__LINE__,__METHOD__,$fargs);
|
|
||||||
|
|
||||||
$oclass_name = strtolower($oclass_name);
|
|
||||||
$socs = $this->SchemaObjectClasses($method,$dn);
|
|
||||||
|
|
||||||
# Default return value
|
|
||||||
$return = false;
|
|
||||||
|
|
||||||
if (isset($socs[$oclass_name]))
|
|
||||||
$return = $socs[$oclass_name];
|
|
||||||
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Returning (%s)',25,0,__FILE__,__LINE__,__METHOD__,$return);
|
|
||||||
|
|
||||||
return $return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a single AttributeType object specified by name.
|
|
||||||
*
|
|
||||||
* @param string $oclass_name The name of the AttributeType to fetch.
|
|
||||||
* @param string $dn (optional) It is easier to fetch schema if a DN is provided
|
|
||||||
* which defines the subschemaSubEntry attribute (all entries should).
|
|
||||||
*
|
|
||||||
* @return AttributeType The specified AttributeType object or false on error.
|
|
||||||
*
|
|
||||||
* @see AttributeType
|
|
||||||
* @see SchemaAttributes
|
|
||||||
*/
|
|
||||||
public function getSchemaAttribute($attr_name,$method=null,$dn='') {
|
|
||||||
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
|
|
||||||
debug_log('Entered (%%)',25,0,__FILE__,__LINE__,__METHOD__,$fargs);
|
|
||||||
|
|
||||||
$attr_name = strtolower($attr_name);
|
|
||||||
$sattrs = $this->SchemaAttributes($method,$dn);
|
|
||||||
|
|
||||||
# Default return value
|
|
||||||
$return = false;
|
|
||||||
|
|
||||||
if (isset($sattrs[$attr_name]))
|
|
||||||
$return = $sattrs[$attr_name];
|
|
||||||
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Returning (%s)',25,0,__FILE__,__LINE__,__METHOD__,$return);
|
|
||||||
|
|
||||||
return $return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets an associative array of ObjectClass objects for the specified
|
|
||||||
* server. Each array entry's key is the name of the objectClass
|
|
||||||
* in lower-case and the value is an ObjectClass object.
|
|
||||||
*
|
|
||||||
* @param string $dn (optional) It is easier to fetch schema if a DN is provided
|
|
||||||
* which defines the subschemaSubEntry attribute (all entries should).
|
|
||||||
*
|
|
||||||
* @return array An array of ObjectClass objects.
|
|
||||||
*
|
|
||||||
* @see ObjectClass
|
|
||||||
* @see getSchemaObjectClass
|
|
||||||
*/
|
|
||||||
public function SchemaObjectClasses($method=null,$dn='') {
|
|
||||||
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
|
|
||||||
debug_log('Entered (%%)',25,0,__FILE__,__LINE__,__METHOD__,$fargs);
|
|
||||||
|
|
||||||
# Set default return
|
|
||||||
$return = null;
|
|
||||||
|
|
||||||
if ($return = get_cached_item($this->index,'schema','objectclasses')) {
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Returning CACHED [%s] (%s)',25,0,__FILE__,__LINE__,__METHOD__,$this->index,'objectclasses');
|
|
||||||
|
|
||||||
return $return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$raw = $this->getRawSchema($method,'objectclasses',$dn);
|
|
||||||
|
|
||||||
if ($raw) {
|
|
||||||
# Build the array of objectClasses
|
|
||||||
$return = array();
|
|
||||||
|
|
||||||
foreach ($raw as $line) {
|
|
||||||
if (is_null($line) || ! strlen($line))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
$object_class = new ObjectClass($line,$this);
|
|
||||||
$return[$object_class->getName()] = $object_class;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Now go through and reference the parent/child relationships
|
|
||||||
foreach ($return as $oclass)
|
|
||||||
foreach ($oclass->getSupClasses() as $parent_name)
|
|
||||||
if (isset($return[strtolower($parent_name)]))
|
|
||||||
$return[strtolower($parent_name)]->addChildObjectClass($oclass->getName(false));
|
|
||||||
|
|
||||||
ksort($return);
|
|
||||||
|
|
||||||
# cache the schema to prevent multiple schema fetches from LDAP server
|
|
||||||
set_cached_item($this->index,'schema','objectclasses',$return);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Returning (%s)',25,0,__FILE__,__LINE__,__METHOD__,$return);
|
|
||||||
|
|
||||||
return $return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets an associative array of AttributeType objects for the specified
|
|
||||||
* server. Each array entry's key is the name of the attributeType
|
|
||||||
* in lower-case and the value is an AttributeType object.
|
|
||||||
*
|
|
||||||
* @param string $dn (optional) It is easier to fetch schema if a DN is provided
|
|
||||||
* which defines the subschemaSubEntry attribute (all entries should).
|
|
||||||
*
|
|
||||||
* @return array An array of AttributeType objects.
|
|
||||||
*/
|
|
||||||
public function SchemaAttributes($method=null,$dn='') {
|
|
||||||
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
|
|
||||||
debug_log('Entered (%%)',25,0,__FILE__,__LINE__,__METHOD__,$fargs);
|
|
||||||
|
|
||||||
# Set default return
|
|
||||||
$return = null;
|
|
||||||
|
|
||||||
if ($return = get_cached_item($this->index,'schema','attributes')) {
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('(): Returning CACHED [%s] (%s)',25,0,__FILE__,__LINE__,__METHOD__,$this->index,'attributes');
|
|
||||||
|
|
||||||
return $return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$raw = $this->getRawSchema($method,'attributeTypes',$dn);
|
|
||||||
|
|
||||||
if ($raw) {
|
|
||||||
# build the array of attribueTypes
|
|
||||||
$syntaxes = $this->SchemaSyntaxes($method,$dn);
|
|
||||||
$attrs = array();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bug 856832: create two arrays - one indexed by name (the standard
|
|
||||||
* $attrs array above) and one indexed by oid (the new $attrs_oid array
|
|
||||||
* below). This will help for directory servers, like IBM's, that use OIDs
|
|
||||||
* in their attribute definitions of SUP, etc
|
|
||||||
*/
|
|
||||||
$attrs_oid = array();
|
|
||||||
foreach ($raw as $line) {
|
|
||||||
if (is_null($line) || ! strlen($line))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
$attr = new AttributeType($line);
|
|
||||||
if (isset($syntaxes[$attr->getSyntaxOID()])) {
|
|
||||||
$syntax = $syntaxes[$attr->getSyntaxOID()];
|
|
||||||
$attr->setType($syntax->getDescription());
|
|
||||||
}
|
|
||||||
$attrs[$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 ($attrs as $name => $attr) {
|
|
||||||
$aliases = $attr->getAliases();
|
|
||||||
|
|
||||||
if (is_array($aliases) && count($aliases) > 0) {
|
|
||||||
/* 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.*/
|
|
||||||
foreach ($aliases as $alias_attr_name) {
|
|
||||||
$new_attr = clone $attr;
|
|
||||||
|
|
||||||
$new_attr->setName($alias_attr_name);
|
|
||||||
$new_attr->addAlias($attr->getName(false));
|
|
||||||
$new_attr->removeAlias($alias_attr_name);
|
|
||||||
$new_attr_key = strtolower($alias_attr_name);
|
|
||||||
$attrs[$new_attr_key] = $new_attr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# go back and add any inherited descriptions from parent attributes (ie, cn inherits name)
|
|
||||||
foreach ($attrs as $key => $attr) {
|
|
||||||
$sup_attr_name = $attr->getSupAttribute();
|
|
||||||
$sup_attr = null;
|
|
||||||
|
|
||||||
if (trim($sup_attr_name)) {
|
|
||||||
|
|
||||||
/* This loop really should traverse infinite levels of inheritance (SUP) for attributeTypes,
|
|
||||||
* but just in case we get carried away, stop at 100. This shouldn't happen, but for
|
|
||||||
* some weird reason, we have had someone report that it has happened. Oh well.*/
|
|
||||||
$i = 0;
|
|
||||||
while ($i++<100 /** 100 == INFINITY ;) */) {
|
|
||||||
|
|
||||||
if (isset($attrs_oid[$sup_attr_name])) {
|
|
||||||
$attr->setSupAttribute($attrs_oid[$sup_attr_name]->getName());
|
|
||||||
$sup_attr_name = $attr->getSupAttribute();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! isset($attrs[strtolower($sup_attr_name)])){
|
|
||||||
error(sprintf('Schema error: attributeType "%s" inherits from "%s", but attributeType "%s" does not exist.',
|
|
||||||
$attr->getName(),$sup_attr_name,$sup_attr_name),'error','index.php');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$sup_attr = $attrs[strtolower($sup_attr_name)];
|
|
||||||
$sup_attr_name = $sup_attr->getSupAttribute();
|
|
||||||
|
|
||||||
# Does this superior attributeType not have a superior attributeType?
|
|
||||||
if (is_null($sup_attr_name) || strlen(trim($sup_attr_name)) == 0) {
|
|
||||||
|
|
||||||
/* Since this attribute's superior attribute does not have another superior
|
|
||||||
* attribute, clone its properties for this attribute. Then, replace
|
|
||||||
* those cloned values with those that can be explicitly set by the child
|
|
||||||
* attribute attr). Save those few properties which the child can set here:*/
|
|
||||||
$tmp_name = $attr->getName(false);
|
|
||||||
$tmp_oid = $attr->getOID();
|
|
||||||
$tmp_sup = $attr->getSupAttribute();
|
|
||||||
$tmp_aliases = $attr->getAliases();
|
|
||||||
$tmp_single_val = $attr->getIsSingleValue();
|
|
||||||
$tmp_desc = $attr->getDescription();
|
|
||||||
|
|
||||||
/* clone the SUP attributeType and populate those values
|
|
||||||
* that were set by the child attributeType */
|
|
||||||
$attr = clone $sup_attr;
|
|
||||||
|
|
||||||
$attr->setOID($tmp_oid);
|
|
||||||
$attr->setName($tmp_name);
|
|
||||||
$attr->setSupAttribute($tmp_sup);
|
|
||||||
$attr->setAliases($tmp_aliases);
|
|
||||||
$attr->setDescription($tmp_desc);
|
|
||||||
|
|
||||||
/* only overwrite the SINGLE-VALUE property if the child explicitly sets it
|
|
||||||
* (note: All LDAP attributes default to multi-value if not explicitly set SINGLE-VALUE) */
|
|
||||||
if ($tmp_single_val)
|
|
||||||
$attr->setIsSingleValue(true);
|
|
||||||
|
|
||||||
/* replace this attribute in the attrs array now that we have populated
|
|
||||||
new values therein */
|
|
||||||
$attrs[$key] = $attr;
|
|
||||||
|
|
||||||
# very important: break out after we are done with this attribute
|
|
||||||
$sup_attr_name = null;
|
|
||||||
$sup_attr = null;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ksort($attrs);
|
|
||||||
|
|
||||||
# Add the used in and required_by values.
|
|
||||||
$socs = $this->SchemaObjectClasses($method);
|
|
||||||
if (! is_array($socs))
|
|
||||||
return array();
|
|
||||||
|
|
||||||
foreach ($socs as $object_class) {
|
|
||||||
$must_attrs = $object_class->getMustAttrNames();
|
|
||||||
$may_attrs = $object_class->getMayAttrNames();
|
|
||||||
$oclass_attrs = array_unique(array_merge($must_attrs,$may_attrs));
|
|
||||||
|
|
||||||
# Add Used In.
|
|
||||||
foreach ($oclass_attrs as $attr_name)
|
|
||||||
if (isset($attrs[strtolower($attr_name)]))
|
|
||||||
$attrs[strtolower($attr_name)]->addUsedInObjectClass($object_class->getName(false));
|
|
||||||
|
|
||||||
# Add Required By.
|
|
||||||
foreach ($must_attrs as $attr_name)
|
|
||||||
if (isset($attrs[strtolower($attr_name)]))
|
|
||||||
$attrs[strtolower($attr_name)]->addRequiredByObjectClass($object_class->getName(false));
|
|
||||||
|
|
||||||
# Force May
|
|
||||||
foreach ($object_class->getForceMayAttrs() as $attr_name)
|
|
||||||
if (isset($attrs[strtolower($attr_name->name)]))
|
|
||||||
$attrs[strtolower($attr_name->name)]->setForceMay();
|
|
||||||
}
|
|
||||||
|
|
||||||
$return = $attrs;
|
|
||||||
|
|
||||||
# cache the schema to prevent multiple schema fetches from LDAP server
|
|
||||||
set_cached_item($this->index,'schema','attributes',$return);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Returning (%s)',25,0,__FILE__,__LINE__,__METHOD__,$return);
|
|
||||||
|
|
||||||
return $return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an array of MatchingRule objects for the specified server.
|
|
||||||
* The key of each entry is the OID of the matching rule.
|
|
||||||
*/
|
|
||||||
public function MatchingRules($method=null,$dn='') {
|
|
||||||
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
|
|
||||||
debug_log('Entered (%%)',25,0,__FILE__,__LINE__,__METHOD__,$fargs);
|
|
||||||
|
|
||||||
# Set default return
|
|
||||||
$return = null;
|
|
||||||
|
|
||||||
if ($return = get_cached_item($this->index,'schema','matchingrules')) {
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Returning CACHED [%s] (%s).',25,0,__FILE__,__LINE__,__METHOD__,$this->index,'matchingrules');
|
|
||||||
|
|
||||||
return $return;
|
|
||||||
}
|
|
||||||
|
|
||||||
# build the array of MatchingRule objects
|
|
||||||
$raw = $this->getRawSchema($method,'matchingRules',$dn);
|
|
||||||
|
|
||||||
if ($raw) {
|
|
||||||
$rules = array();
|
|
||||||
|
|
||||||
foreach ($raw as $line) {
|
|
||||||
if (is_null($line) || ! strlen($line))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
$rule = new MatchingRule($line);
|
|
||||||
$key = $rule->getName();
|
|
||||||
$rules[$key] = $rule;
|
|
||||||
}
|
|
||||||
|
|
||||||
ksort($rules);
|
|
||||||
|
|
||||||
/* For each MatchingRuleUse entry, add the attributes who use it to the
|
|
||||||
* MatchingRule in the $rules array.*/
|
|
||||||
$raw = $this->getRawSchema($method,'matchingRuleUse');
|
|
||||||
|
|
||||||
if ($raw != false) {
|
|
||||||
foreach ($raw as $line) {
|
|
||||||
if (is_null($line) || ! strlen($line))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
$rule_use = new MatchingRuleUse($line);
|
|
||||||
$key = $rule_use->getName();
|
|
||||||
|
|
||||||
if (isset($rules[$key]))
|
|
||||||
$rules[$key]->setUsedByAttrs($rule_use->getUsedByAttrs());
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
/* No MatchingRuleUse entry in the subschema, so brute-forcing
|
|
||||||
* the reverse-map for the "$rule->getUsedByAttrs()" data.*/
|
|
||||||
$sattrs = $this->SchemaAttributes($method,$dn);
|
|
||||||
if (is_array($sattrs))
|
|
||||||
foreach ($sattrs as $attr) {
|
|
||||||
$rule_key = strtolower($attr->getEquality());
|
|
||||||
|
|
||||||
if (isset($rules[$rule_key]))
|
|
||||||
$rules[$rule_key]->addUsedByAttr($attr->getName(false));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$return = $rules;
|
|
||||||
|
|
||||||
# cache the schema to prevent multiple schema fetches from LDAP server
|
|
||||||
set_cached_item($this->index,'schema','matchingrules',$return);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Returning (%s)',25,0,__FILE__,__LINE__,__METHOD__,$return);
|
|
||||||
|
|
||||||
return $return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an array of Syntax objects that this LDAP server uses mapped to
|
|
||||||
* their descriptions. The key of each entry is the OID of the Syntax.
|
|
||||||
*/
|
|
||||||
public function SchemaSyntaxes($method=null,$dn='') {
|
|
||||||
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
|
|
||||||
debug_log('Entered (%%)',25,0,__FILE__,__LINE__,__METHOD__,$fargs);
|
|
||||||
|
|
||||||
# Set default return
|
|
||||||
$return = null;
|
|
||||||
|
|
||||||
if ($return = get_cached_item($this->index,'schema','syntaxes')) {
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Returning CACHED [%s] (%s).',25,0,__FILE__,__LINE__,__METHOD__,$this->index,'syntaxes');
|
|
||||||
|
|
||||||
return $return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$raw = $this->getRawSchema($method,'ldapSyntaxes',$dn);
|
|
||||||
|
|
||||||
if ($raw) {
|
|
||||||
# build the array of attributes
|
|
||||||
$return = array();
|
|
||||||
|
|
||||||
foreach ($raw as $line) {
|
|
||||||
if (is_null($line) || ! strlen($line))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
$syntax = new Syntax($line);
|
|
||||||
$key = strtolower(trim($syntax->getOID()));
|
|
||||||
|
|
||||||
if (! $key)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
$return[$key] = $syntax;
|
|
||||||
}
|
|
||||||
|
|
||||||
ksort($return);
|
|
||||||
|
|
||||||
# cache the schema to prevent multiple schema fetches from LDAP server
|
|
||||||
set_cached_item($this->index,'schema','syntaxes',$return);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DEBUG_ENABLED)
|
|
||||||
debug_log('Returning (%s)',25,0,__FILE__,__LINE__,__METHOD__,$return);
|
|
||||||
|
|
||||||
return $return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
function isForceMay($attr_name) {
|
|
||||||
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
|
|
||||||
debug_log('Entered (%%)',17,0,__FILE__,__LINE__,__METHOD__,$fargs);
|
|
||||||
|
|
||||||
return in_array($attr_name,unserialize(strtolower(serialize($this->getValue('server','force_may')))));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Much like getDNAttrValues(), but only returns the values for
|
* Much like getDNAttrValues(), but only returns the values for
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -18,13 +18,13 @@
|
|||||||
<div class="page-title-actions">
|
<div class="page-title-actions">
|
||||||
{{--
|
{{--
|
||||||
<button type="button" data-toggle="tooltip" title="Example Tooltip" data-placement="bottom" class="btn-shadow mr-3 btn btn-dark">
|
<button type="button" data-toggle="tooltip" title="Example Tooltip" data-placement="bottom" class="btn-shadow mr-3 btn btn-dark">
|
||||||
<i class="fa fa-star"></i>
|
<i class="fas fa-star"></i>
|
||||||
</button>
|
</button>
|
||||||
--}}
|
--}}
|
||||||
<div class="d-inline-block dropdown">
|
<div class="d-inline-block dropdown">
|
||||||
<button type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" class="btn-shadow dropdown-toggle btn btn-info">
|
<button type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" class="btn-shadow dropdown-toggle btn btn-info">
|
||||||
<span class="btn-icon-wrapper pr-2 opacity-7">
|
<span class="btn-icon-wrapper pr-2 opacity-7">
|
||||||
<i class="fa fa-business-time fa-w-20"></i>
|
<i class="fas fa-business-time fa-w-20"></i>
|
||||||
</span>
|
</span>
|
||||||
Item Menu
|
Item Menu
|
||||||
</button>
|
</button>
|
||||||
|
@ -44,6 +44,9 @@
|
|||||||
<!-- Theme style -->
|
<!-- Theme style -->
|
||||||
<link rel="stylesheet" href="{{ asset('/css/architect.min.css') }}">
|
<link rel="stylesheet" href="{{ asset('/css/architect.min.css') }}">
|
||||||
|
|
||||||
|
<!-- Select 2 -->
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" />
|
||||||
|
|
||||||
@if(file_exists('css/fixes.css'))
|
@if(file_exists('css/fixes.css'))
|
||||||
<!-- CSS Fixes -->
|
<!-- CSS Fixes -->
|
||||||
<link rel="stylesheet" href="{{ asset('/css/fixes.css') }}">
|
<link rel="stylesheet" href="{{ asset('/css/fixes.css') }}">
|
||||||
|
@ -37,11 +37,9 @@
|
|||||||
<div class="font-icon-wrapper float-left mr-1 server-icon">
|
<div class="font-icon-wrapper float-left mr-1 server-icon">
|
||||||
<a class="p-0 m-0" href="{{ LaravelLocalization::localizeUrl('info') }}" onclick="return false;" style="display: contents;"><i class="fas fa-fw fa-info"></i></a>
|
<a class="p-0 m-0" href="{{ LaravelLocalization::localizeUrl('info') }}" onclick="return false;" style="display: contents;"><i class="fas fa-fw fa-info"></i></a>
|
||||||
</div>
|
</div>
|
||||||
{{--
|
|
||||||
<div class="font-icon-wrapper float-left ml-1 mr-1 server-icon">
|
<div class="font-icon-wrapper float-left ml-1 mr-1 server-icon">
|
||||||
<a class="p-0 m-0" href="{{ LaravelLocalization::localizeUrl('schema') }}" onclick="return false;" style="display: contents;"><i class="fas fa-fw fa-fingerprint"></i></a>
|
<a class="p-0 m-0" href="{{ LaravelLocalization::localizeUrl('schema') }}" onclick="return false;" style="display: contents;"><i class="fas fa-fw fa-fingerprint"></i></a>
|
||||||
</div>
|
</div>
|
||||||
--}}
|
|
||||||
@env(['local'])
|
@env(['local'])
|
||||||
<div class="font-icon-wrapper float-right ml-1 server-icon">
|
<div class="font-icon-wrapper float-right ml-1 server-icon">
|
||||||
<a class="p-0 m-0" href="{{ LaravelLocalization::localizeUrl('debug') }}" onclick="return false;" style="display: contents;"><i class="fas fa-fw fa-toolbox"></i></a>
|
<a class="p-0 m-0" href="{{ LaravelLocalization::localizeUrl('debug') }}" onclick="return false;" style="display: contents;"><i class="fas fa-fw fa-toolbox"></i></a>
|
||||||
|
@ -32,6 +32,12 @@
|
|||||||
</table>
|
</table>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
<!-- Schema DN -->
|
||||||
|
<tr>
|
||||||
|
<td>Schema DN</td>
|
||||||
|
<td>{{ \App\Ldap\Entry::schemaDN() }}</td>
|
||||||
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
78
resources/views/frames/schema.blade.php
Normal file
78
resources/views/frames/schema.blade.php
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
@extends('layouts.dn')
|
||||||
|
|
||||||
|
@section('page_title')
|
||||||
|
<table class="table table-borderless">
|
||||||
|
<tr>
|
||||||
|
<td style="border-radius: 5px;"><div class="page-title-icon f32"><i class="fas fa-fingerprint"></i></div></td>
|
||||||
|
<td class="top text-right align-text-top p-0 pt-2"><strong>{{ \App\Ldap\Entry::schemaDN() }}</strong><br><small>{{ $o->entryuuid[0] ?? '' }}</small></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('main-content')
|
||||||
|
<div class="main-card mb-3 card">
|
||||||
|
<div class="card-body"><h5 class="card-title">{{ __('Schema Information') }}</h5>
|
||||||
|
<ul class="nav nav-tabs">
|
||||||
|
<li class="nav-item"><a data-toggle="tab" href="#objectclasses" class="nav-link">{{ __('Object Classes') }}</a></li>
|
||||||
|
<li class="nav-item"><a data-toggle="tab" href="#attributetypes" class="nav-link">{{ __('Attribute Types') }}</a></li>
|
||||||
|
<li class="nav-item"><a data-toggle="tab" href="#ldapsyntaxes" class="nav-link">{{ __('Syntaxes') }}</a></li>
|
||||||
|
<li class="nav-item"><a data-toggle="tab" href="#matchingrules" class="nav-link">{{ __('Matching Rules') }}</a></li>
|
||||||
|
</ul>
|
||||||
|
<div class="tab-content">
|
||||||
|
<!-- Object Classes -->
|
||||||
|
<div class="tab-pane" id="objectclasses" role="tabpanel">
|
||||||
|
<div id="schema.objectclasses"><i class="fas fa-fw fa-spinner fa-pulse"></i></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Attribute Types -->
|
||||||
|
<div class="tab-pane" id="attributetypes" role="tabpanel">
|
||||||
|
<div id="schema.attributetypes"><i class="fas fa-fw fa-spinner fa-pulse"></i></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Syntaxes -->
|
||||||
|
<div class="tab-pane" id="ldapsyntaxes" role="tabpanel">
|
||||||
|
<div id="schema.ldapsyntaxes"><i class="fas fa-fw fa-spinner fa-pulse"></i></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Matching Rules -->
|
||||||
|
<div class="tab-pane" id="matchingrules" role="tabpanel">
|
||||||
|
<div id="schema.matchingrules"><i class="fas fa-fw fa-spinner fa-pulse"></i></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('page-scripts')
|
||||||
|
<script type="text/javascript">
|
||||||
|
var loaded = [];
|
||||||
|
|
||||||
|
$(document).ready(function() {
|
||||||
|
$('a[data-toggle="tab"]').on('shown.bs.tab', function (item) {
|
||||||
|
// activated tab
|
||||||
|
var type = $(item.target).attr('href').substring(1);
|
||||||
|
if (loaded[type])
|
||||||
|
return false;
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: '{{ url('api/schema/view') }}',
|
||||||
|
method: 'POST',
|
||||||
|
data: { type: type },
|
||||||
|
dataType: 'html',
|
||||||
|
|
||||||
|
}).done(function(html) {
|
||||||
|
$('div[id="schema.'+type+'"]').empty().append(html);
|
||||||
|
loaded[type] = true;
|
||||||
|
|
||||||
|
}).fail(function() {
|
||||||
|
alert('Failed');
|
||||||
|
});
|
||||||
|
|
||||||
|
item.stopPropagation();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Open our objectclasses tab automatically
|
||||||
|
$('.nav-item a[href="#objectclasses"]').tab('show');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@append
|
153
resources/views/frames/schema/attributetypes.blade.php
Normal file
153
resources/views/frames/schema/attributetypes.blade.php
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="col-12 col-xl-3">
|
||||||
|
<select id="attributetype" class="form-control">
|
||||||
|
<option value="-all-">-all-</option>
|
||||||
|
@foreach ($attributetypes as $o)
|
||||||
|
<option value="{{ $o->name_lc }}">{{ $o->name }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12 col-xl-9">
|
||||||
|
@foreach ($attributetypes as $o)
|
||||||
|
<span id="at-{{ $o->name_lc }}">
|
||||||
|
<table class="schema table table-sm table-bordered table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="table-dark" colspan="2">{{ $o->name }}<span class="float-right"><abbr title="{{ $o->line }}"><i class="fas fa-fw fa-file-contract"></i></abbr></span></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="w-25">{{ __('Description') }}</td><td><strong>{{ __($o->description ?: '(no description)') }}</strong></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><abbr title="{{ __('Object Identifier') }}">OID</abbr></td><td><strong>{{ $o->oid }}</strong></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{{ __('Obsolete') }}</td><td><strong>{{ $o->is_obsolete ? __('Yes') : __('No') }}</strong></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{{ __('Inherits from') }}</td>
|
||||||
|
<td><strong>@if ($o->sup_attribute)<a class="attributetype" id="{{ strtolower($o->sup_attribute) }}" href="#{{ strtolower($o->sup_attribute) }}">{{ $o->sup_attribute }}</a>@else {{ __('(none)') }}@endif</strong></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{{ __('Parent to') }}</td>
|
||||||
|
<td>
|
||||||
|
<strong>
|
||||||
|
@if (! $o->children->count())
|
||||||
|
{{ __('(none)') }}
|
||||||
|
@else
|
||||||
|
@foreach ($o->children->sort() as $child)
|
||||||
|
@if($loop->index)</strong> <strong>@endif
|
||||||
|
<a class="attributetype" id="{{ strtolower($child) }}" href="#{{ strtolower($child) }}">{{ $child }}</a>
|
||||||
|
@endforeach
|
||||||
|
@endif
|
||||||
|
</strong>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{{ __('Equality') }}</td><td><strong>{{ $o->equality ?: __('(not specified)') }}</strong></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{{ __('Ordering') }}</td><td><strong>{{ $o->ordering ?: __('(not specified)') }}</strong></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{{ __('Substring Rule') }}</td><td><strong>{{ $o->sub_str_rule ?: __('(not specified)') }}</strong></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{{ __('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>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{{ __('Single Valued') }}</td><td><strong>{{ $o->is_single_value ? __('Yes') : __('No') }}</strong></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{{ __('Collective') }}</td><td><strong>{{ $o->is_collective ? __('Yes') : __('No') }}</strong></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{{ __('User Modification') }}</td><td><strong>{{ $o->is_no_user_modification ? __('Yes') : __('No') }}</strong></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{{ __('Usage') }}</td><td><strong>{{ $o->usage ?: __('(not specified)') }}</strong></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{{ __('Maximum Length') }}</td><td><strong>{{ is_null($o->max_length) ? __('(not applicable)') : sprintf('%s %s',number_format($o->max_length),Str::plural('character',$o->max_length)) }}</strong></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{{ __('Aliases') }}</td>
|
||||||
|
<td><strong>
|
||||||
|
@if ($o->aliases->count())
|
||||||
|
@foreach ($o->aliases as $alias)
|
||||||
|
@if ($loop->index)</strong> <strong>@endif
|
||||||
|
<a class="attributetype" id="{{ strtolower($alias) }}" href="#{{ strtolower($alias) }}">{{ $alias }}</a>
|
||||||
|
@endforeach
|
||||||
|
@else
|
||||||
|
{{ __('(none)') }}
|
||||||
|
@endif
|
||||||
|
</strong></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{{ __('Used by ObjectClasses') }}</td>
|
||||||
|
<td><strong>
|
||||||
|
@if ($o->used_in_object_classes->count())
|
||||||
|
@foreach ($o->used_in_object_classes as $class)
|
||||||
|
@if ($loop->index)</strong> <strong>@endif
|
||||||
|
<a class="objectclass" id="{{ strtolower($class) }}" href="#{{ strtolower($class) }}">{{ $class }}</a>
|
||||||
|
@endforeach
|
||||||
|
@else
|
||||||
|
{{ __('(none)') }}
|
||||||
|
@endif
|
||||||
|
</strong></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{{ __('Force as MAY by config') }}</td><td><strong>{{ $o->forced_as_may ? __('Yes') : __('No') }}</strong></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</span>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(document).ready(function() {
|
||||||
|
<!-- Links to object class -->
|
||||||
|
$('.objectclass')
|
||||||
|
.on('click',function(item) {
|
||||||
|
$('.nav-item a[href="#objectclasses"]').tab('show');
|
||||||
|
|
||||||
|
$('#objectclass').val(item.target.id).trigger('change');
|
||||||
|
});
|
||||||
|
|
||||||
|
<!-- Handle our parent to/inherits from fields -->
|
||||||
|
$('.attributetype')
|
||||||
|
.on('click',function(item) {
|
||||||
|
$('.nav-item a[href="#attributetypes"]').tab('show');
|
||||||
|
$('#attributetype').val(item.target.id).trigger('change');
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
<!-- Handle our select list -->
|
||||||
|
$('#attributetype')
|
||||||
|
.select2({width: '100%'})
|
||||||
|
.on('change',function(item) {
|
||||||
|
if (item.target.value === '-all-') {
|
||||||
|
$('#attributetypes span').each(function() { $(this).show(); });
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$('#attributetypes span').each(function() {
|
||||||
|
if ($(this)[0].id.match(/select2/) || (! $(this)[0].id))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ('at-'+item.target.value === $(this)[0].id)
|
||||||
|
$(this).show();
|
||||||
|
else
|
||||||
|
$(this).hide();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
29
resources/views/frames/schema/ldapsyntaxes.blade.php
Normal file
29
resources/views/frames/schema/ldapsyntaxes.blade.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<div class="row">
|
||||||
|
<div class="col-5 m-auto">
|
||||||
|
<table class="schema table table-sm table-bordered table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="table-dark">{{ __('Description') }}</th>
|
||||||
|
<th class="table-dark">OID</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
@foreach ($ldapsyntaxes as $o)
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<abbr title="{{ $o->line }}">{{ $o->description }}</abbr>
|
||||||
|
@if ($o->binary_transfer_required)
|
||||||
|
<span class="float-right"><i class="fas fa-fw fa-file-download"></i></span>
|
||||||
|
@endif
|
||||||
|
@if ($o->is_not_human_readable)
|
||||||
|
<span class="float-right"><i class="fas fa-fw fa-tools"></i></span>
|
||||||
|
@endif
|
||||||
|
</td>
|
||||||
|
<td>{{ $o->oid }}</td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
101
resources/views/frames/schema/matchingrules.blade.php
Normal file
101
resources/views/frames/schema/matchingrules.blade.php
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
<div class="row">
|
||||||
|
<div class="col-12 col-xl-3">
|
||||||
|
<select id="matchingrule" class="form-control">
|
||||||
|
<option value="-all-">-all-</option>
|
||||||
|
@foreach ($matchingrules as $o)
|
||||||
|
<option value="{{ $o->name_lc }}">{{ $o->name }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12 col-xl-9">
|
||||||
|
@foreach ($matchingrules as $o)
|
||||||
|
<span id="mr-{{ $o->name_lc }}">
|
||||||
|
<table class="schema table table-sm table-bordered table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="table-dark" colspan="2">{{ $o->name }}<span class="float-right"><abbr title="{{ $o->line }}"><i class="fas fa-fw fa-file-contract"></i></abbr></span></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="w-25">{{ __('Description') }}</td><td><strong>{{ __($o->description ?: '(no description)') }}</strong></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="w-25"><abbr title="{{ __('Object Identifier') }}">OID</abbr></td><td><strong>{{ $o->oid }}</strong></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="w-25">{{ __('Syntax') }}</td><td><strong>{{ $o->syntax }}</strong></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{{ __('Used by Attributes') }}</td>
|
||||||
|
<td>
|
||||||
|
<strong>
|
||||||
|
@if ($o->used_by_attrs->count() === 0)
|
||||||
|
{{ __('(none)') }}
|
||||||
|
@else
|
||||||
|
@foreach ($o->used_by_attrs as $attr)
|
||||||
|
@if($loop->index)</strong> <strong>@endif
|
||||||
|
<a class="attributetype" id="{{ strtolower($attr) }}" href="#at-{{ strtolower($attr) }}">{{ $attr }}</a>
|
||||||
|
@endforeach
|
||||||
|
@endif
|
||||||
|
</strong>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</span>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
function hl_attribute(item,count) {
|
||||||
|
if ((count < 50) && (! loaded['attributetypes'])) {
|
||||||
|
setTimeout(hl_attribute,250,item,++count);
|
||||||
|
} else if (count >= 50) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
$('#attributetype').val(item.target.id).trigger('change');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).ready(function() {
|
||||||
|
$('.attributetype')
|
||||||
|
.on('click',function(item) {
|
||||||
|
$('.nav-item a[href="#attributetypes"]').tab('show');
|
||||||
|
|
||||||
|
return hl_attribute(item,0);
|
||||||
|
});
|
||||||
|
|
||||||
|
<!-- Handle our parent to/inherits from fields -->
|
||||||
|
$('.matchingrule')
|
||||||
|
.on('click',function(item) {
|
||||||
|
$('#matchingrule').val(item.target.id).trigger('change');
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
<!-- Handle our select list -->
|
||||||
|
$('#matchingrule')
|
||||||
|
.select2({width: '100%'})
|
||||||
|
.on('change',function(item) {
|
||||||
|
if (item.target.value === '-all-') {
|
||||||
|
$('#matchingrules span').each(function() { $(this).show(); });
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$('#matchingrules span').each(function() {
|
||||||
|
if ($(this)[0].id.match(/select2/) || (! $(this)[0].id))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ('mr-'+item.target.value === $(this)[0].id)
|
||||||
|
$(this).show();
|
||||||
|
else
|
||||||
|
$(this).hide();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
147
resources/views/frames/schema/objectclasses.blade.php
Normal file
147
resources/views/frames/schema/objectclasses.blade.php
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
<div class="row">
|
||||||
|
<div class="col-12 col-xl-3">
|
||||||
|
<select id="objectclass" class="form-control">
|
||||||
|
<option value="-all-">-all-</option>
|
||||||
|
@foreach ($objectclasses as $o)
|
||||||
|
<option value="{{ $o->name_lc }}">{{ $o->name }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12 col-xl-9">
|
||||||
|
@foreach ($objectclasses as $o)
|
||||||
|
<span id="oc-{{ $o->name_lc }}">
|
||||||
|
<table class="schema table table-sm table-bordered table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="table-dark" colspan="4">{{ $o->name }}<span class="float-right"><abbr title="{{ $o->line }}"><i class="fas fa-fw fa-file-contract"></i></abbr></span></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="w-25">{{ __('Description') }}</td><td colspan="3"><strong>{{ __($o->description ?: '(no description)') }}</strong></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="w-25"><abbr title="{{ __('Object Identifier') }}">OID</abbr></td><td colspan="3"><strong>{{ $o->oid }}</strong></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{{ __('Type') }}</td><td colspan="3"><strong>{{ __($o->type_name) }}</strong></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{{ __('Inherits from') }}</td>
|
||||||
|
<td colspan="3">
|
||||||
|
<strong>
|
||||||
|
@if ($o->sup->count() === 0)
|
||||||
|
{{ __('(none)') }}
|
||||||
|
@else
|
||||||
|
@foreach ($o->sup as $sup)
|
||||||
|
@if($loop->index)</strong> <strong>@endif
|
||||||
|
<a class="objectclass" id="{{ strtolower($sup) }}" href="#{{ strtolower($sup) }}">{{ $sup }}</a>
|
||||||
|
@endforeach
|
||||||
|
@endif
|
||||||
|
</strong>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>{{ __('Parent to') }}</td>
|
||||||
|
<td colspan="3">
|
||||||
|
<strong>
|
||||||
|
@if (strtolower($o->name) === 'top')
|
||||||
|
<a class="objectclass" id="-all-">(all)</a>
|
||||||
|
@elseif (! $o->getChildObjectClasses()->count())
|
||||||
|
{{ __('(none)') }}
|
||||||
|
@else
|
||||||
|
@foreach ($o->getChildObjectClasses() as $childoc)
|
||||||
|
@if($loop->index)</strong> <strong>@endif
|
||||||
|
<a class="objectclass" id="{{ strtolower($childoc) }}" href="#{{ strtolower($childoc) }}">{{ $childoc }}</a>
|
||||||
|
@endforeach
|
||||||
|
@endif
|
||||||
|
</strong>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td class="align-top w-50" colspan="2">
|
||||||
|
<table class="clearfix table table-sm table-borderless">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="table-primary">{{ __('Required Attributes') }}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<ul class="pl-3" style="list-style-type: square;">
|
||||||
|
@foreach ($o->getMustAttrs(TRUE) as $oo)
|
||||||
|
<li>{{ $oo->name }} @if($oo->source !== $o->name)[<strong><a class="objectclass" id="{{ strtolower($oo->source) }}" href="#{{ strtolower($oo->source) }}">{{ $oo->source }}</a></strong>]@endif</li>
|
||||||
|
@endforeach
|
||||||
|
</ul>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="align-top w-50" colspan="2">
|
||||||
|
<table class="clearfix table table-sm table-borderless">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="table-primary">{{ __('Optional Attributes') }}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<ul class="pl-3" style="list-style-type: square;">
|
||||||
|
@foreach ($o->getMayAttrs(TRUE) as $oo)
|
||||||
|
<li>{{ $oo->name }} @if($oo->source !== $o->name)[<strong><a class="objectclass" id="{{ strtolower($oo->source) }}" href="#{{ strtolower($oo->source) }}">{{ $oo->source }}</a></strong>]@endif</li>
|
||||||
|
@endforeach
|
||||||
|
</ul>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</span>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(document).ready(function() {
|
||||||
|
<!-- Handle our parent to/inherits from fields -->
|
||||||
|
$('.objectclass')
|
||||||
|
.on('click',function(item) {
|
||||||
|
$('#objectclass').val(item.target.id).trigger('change');
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
<!-- Handle our select list -->
|
||||||
|
$('#objectclass')
|
||||||
|
.select2({width: '100%'})
|
||||||
|
.on('change',function(item) {
|
||||||
|
if (item.target.value === '-all-') {
|
||||||
|
$('#objectclasses span').each(function() { $(this).show(); });
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$('#objectclasses span').each(function() {
|
||||||
|
if ($(this)[0].id.match(/select2/) || (! $(this)[0].id))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ('oc-'+item.target.value === $(this)[0].id)
|
||||||
|
$(this).show();
|
||||||
|
else
|
||||||
|
$(this).hide();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
@ -50,7 +50,7 @@
|
|||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
@section('page-scripts')
|
@section('page-scripts')
|
||||||
<script>
|
<script type="text/javascript">
|
||||||
var basedn = {!! $bases->toJson() !!};
|
var basedn = {!! $bases->toJson() !!};
|
||||||
</script>
|
</script>
|
||||||
@append
|
@append
|
@ -8,4 +8,6 @@
|
|||||||
<!-- Your Page Content Here -->
|
<!-- Your Page Content Here -->
|
||||||
@yield('main-content')
|
@yield('main-content')
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@yield('page-scripts')
|
@ -16,8 +16,9 @@ use App\Http\Controllers\APIController;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Route::group([],function() {
|
Route::group([],function() {
|
||||||
Route::get('/bases',[APIController::class,'bases']);
|
Route::get('bases',[APIController::class,'bases']);
|
||||||
Route::get('/children',[APIController::class,'children']);
|
Route::get('children',[APIController::class,'children']);
|
||||||
|
Route::post('schema/view',[APIController::class,'schema_view']);
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::group(['middleware'=>'auth:api','prefix'=>'user'],function() {
|
Route::group(['middleware'=>'auth:api','prefix'=>'user'],function() {
|
||||||
|
@ -30,6 +30,7 @@ Route::group(['prefix' => LaravelLocalization::setLocale()], function() {
|
|||||||
Route::get('info',[HomeController::class,'info']);
|
Route::get('info',[HomeController::class,'info']);
|
||||||
Route::post('dn',[HomeController::class,'dn_frame']);
|
Route::post('dn',[HomeController::class,'dn_frame']);
|
||||||
Route::get('debug',[HomeController::class,'debug']);
|
Route::get('debug',[HomeController::class,'debug']);
|
||||||
|
Route::get('schema',[HomeController::class,'schema_frame']);
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::get('logout',[LoginController::class,'logout']);
|
Route::get('logout',[LoginController::class,'logout']);
|
||||||
|
Loading…
Reference in New Issue
Block a user