Compare commits
8 Commits
16880cd0e2
...
817b72cdac
Author | SHA1 | Date | |
---|---|---|---|
817b72cdac | |||
6eb20a071c | |||
47662ba091 | |||
f83beece87 | |||
0a074d6121 | |||
05ab9ed346 | |||
3fc6b55757 | |||
80a329afc2 |
@ -19,24 +19,21 @@ class Attribute implements \Countable, \ArrayAccess, \Iterator
|
|||||||
|
|
||||||
// Is this attribute an internal attribute
|
// Is this attribute an internal attribute
|
||||||
protected(set) bool $is_internal = FALSE;
|
protected(set) bool $is_internal = FALSE;
|
||||||
|
protected(set) bool $no_attr_tags = FALSE;
|
||||||
|
|
||||||
// MIN/MAX number of values
|
// MIN/MAX number of values
|
||||||
protected(set) int $min_values_count = 0;
|
protected(set) int $min_values_count = 0;
|
||||||
protected(set) int $max_values_count = 0;
|
protected(set) int $max_values_count = 0;
|
||||||
|
|
||||||
// RFC3866 Language Tags
|
|
||||||
/* @deprecated use $values/$values_old when playing with language tags */
|
|
||||||
protected Collection $lang_tags;
|
|
||||||
|
|
||||||
// The schema's representation of this attribute
|
// The schema's representation of this attribute
|
||||||
protected(set) ?AttributeType $schema;
|
protected(set) ?AttributeType $schema;
|
||||||
|
|
||||||
// The DN this object is in
|
// The DN this object is in
|
||||||
protected(set) string $dn;
|
protected(set) string $dn;
|
||||||
// The old values for this attribute - helps with isDirty() to determine if there is an update pending
|
// The old values for this attribute - helps with isDirty() to determine if there is an update pending
|
||||||
protected(set) Collection $values_old;
|
private Collection $_values_old;
|
||||||
// Current Values
|
// Current Values
|
||||||
public Collection $values;
|
private Collection $_values;
|
||||||
// The objectclasses of the entry that has this attribute
|
// The objectclasses of the entry that has this attribute
|
||||||
protected(set) Collection $oc;
|
protected(set) Collection $oc;
|
||||||
|
|
||||||
@ -107,7 +104,6 @@ class Attribute implements \Countable, \ArrayAccess, \Iterator
|
|||||||
|
|
||||||
$this->values = collect();
|
$this->values = collect();
|
||||||
$this->oc = collect($oc);
|
$this->oc = collect($oc);
|
||||||
$this->lang_tags = collect();
|
|
||||||
|
|
||||||
$this->schema = (new Server)
|
$this->schema = (new Server)
|
||||||
->schema('attributetypes',$name);
|
->schema('attributetypes',$name);
|
||||||
@ -152,19 +148,43 @@ class Attribute implements \Countable, \ArrayAccess, \Iterator
|
|||||||
'required_by' => $this->schema?->required_by_object_classes ?: collect(),
|
'required_by' => $this->schema?->required_by_object_classes ?: collect(),
|
||||||
// Used in Object Classes
|
// Used in Object Classes
|
||||||
'used_in' => $this->schema?->used_in_object_classes ?: collect(),
|
'used_in' => $this->schema?->used_in_object_classes ?: collect(),
|
||||||
|
// The current attribute values
|
||||||
|
'values' => $this->no_attr_tags ? collect($this->_values->first()) : $this->_values,
|
||||||
|
// The original attribute values
|
||||||
|
'values_old' => $this->no_attr_tags ? collect($this->_values_old->first()) : $this->_values_old,
|
||||||
|
|
||||||
default => throw new \Exception('Unknown key:' . $key),
|
default => throw new \Exception('Unknown key:' . $key),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function __set(string $key,mixed $values)
|
||||||
|
{
|
||||||
|
switch ($key) {
|
||||||
|
case 'values':
|
||||||
|
$this->_values = $values;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'values_old':
|
||||||
|
$this->_values_old = $values;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new \Exception('Unknown key:'.$key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function __toString(): string
|
public function __toString(): string
|
||||||
{
|
{
|
||||||
return $this->name;
|
return $this->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addValue(string $value): void
|
public function addValue(string $tag,string $value): void
|
||||||
{
|
{
|
||||||
$this->values->push($value);
|
$this->_values->put(
|
||||||
|
$tag,
|
||||||
|
$this->_values
|
||||||
|
->get($tag,collect())
|
||||||
|
->push($value));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function current(): mixed
|
public function current(): mixed
|
||||||
@ -236,10 +256,6 @@ class Attribute implements \Countable, \ArrayAccess, \Iterator
|
|||||||
if ($this->required()->count())
|
if ($this->required()->count())
|
||||||
$result->put(__('required'),sprintf('%s: %s',__('Required Attribute by ObjectClass(es)'),$this->required()->join(', ')));
|
$result->put(__('required'),sprintf('%s: %s',__('Required Attribute by ObjectClass(es)'),$this->required()->join(', ')));
|
||||||
|
|
||||||
// This attribute has language tags
|
|
||||||
if ($this->lang_tags->count())
|
|
||||||
$result->put(__('language tags'),sprintf('%s: %d',__('This Attribute has Language Tags'),$this->lang_tags->count()));
|
|
||||||
|
|
||||||
return $result->toArray();
|
return $result->toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,17 +329,4 @@ class Attribute implements \Countable, \ArrayAccess, \Iterator
|
|||||||
? $this->oc->intersect($this->schema->required_by_object_classes->keys())->sort()
|
? $this->oc->intersect($this->schema->required_by_object_classes->keys())->sort()
|
||||||
: collect();
|
: collect();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* If this attribute has RFC3866 Language Tags, this will enable those values to be captured
|
|
||||||
*
|
|
||||||
* @param string $tag
|
|
||||||
* @param array $value
|
|
||||||
* @return void
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
public function setLangTag(string $tag,array $value): void
|
|
||||||
{
|
|
||||||
$this->lang_tags->put($tag,$value);
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -22,11 +22,17 @@ class Factory
|
|||||||
public const map = [
|
public const map = [
|
||||||
'createtimestamp' => Internal\Timestamp::class,
|
'createtimestamp' => Internal\Timestamp::class,
|
||||||
'creatorsname' => Internal\DN::class,
|
'creatorsname' => Internal\DN::class,
|
||||||
|
'configcontext' => Schema\Generic::class,
|
||||||
'contextcsn' => Internal\CSN::class,
|
'contextcsn' => Internal\CSN::class,
|
||||||
'entrycsn' => Internal\CSN::class,
|
'entrycsn' => Internal\CSN::class,
|
||||||
'entrydn' => Internal\DN::class,
|
'entrydn' => Internal\DN::class,
|
||||||
'entryuuid' => Internal\UUID::class,
|
'entryuuid' => Internal\UUID::class,
|
||||||
'etag' => Internal\Etag::class,
|
'etag' => Internal\Etag::class,
|
||||||
|
'krblastfailedauth' => Attribute\NoAttrTags\Generic::class,
|
||||||
|
'krblastpwdchange' => Attribute\NoAttrTags\Generic::class,
|
||||||
|
'krblastsuccessfulauth' => Attribute\NoAttrTags\Generic::class,
|
||||||
|
'krbpasswordexpiration' => Attribute\NoAttrTags\Generic::class,
|
||||||
|
'krbloginfailedcount' => Attribute\NoAttrTags\Generic::class,
|
||||||
'krbprincipalkey' => KrbPrincipalKey::class,
|
'krbprincipalkey' => KrbPrincipalKey::class,
|
||||||
'krbticketflags' => KrbTicketFlags::class,
|
'krbticketflags' => KrbTicketFlags::class,
|
||||||
'gidnumber' => GidNumber::class,
|
'gidnumber' => GidNumber::class,
|
||||||
@ -34,6 +40,8 @@ class Factory
|
|||||||
'jpegphoto' => Binary\JpegPhoto::class,
|
'jpegphoto' => Binary\JpegPhoto::class,
|
||||||
'modifytimestamp' => Internal\Timestamp::class,
|
'modifytimestamp' => Internal\Timestamp::class,
|
||||||
'modifiersname' => Internal\DN::class,
|
'modifiersname' => Internal\DN::class,
|
||||||
|
'monitorcontext' => Schema\Generic::class,
|
||||||
|
'namingcontexts' => Schema\Generic::class,
|
||||||
'numsubordinates' => Internal\NumSubordinates::class,
|
'numsubordinates' => Internal\NumSubordinates::class,
|
||||||
'objectclass' => ObjectClass::class,
|
'objectclass' => ObjectClass::class,
|
||||||
'pwdpolicysubentry' => Internal\PwdPolicySubentry::class,
|
'pwdpolicysubentry' => Internal\PwdPolicySubentry::class,
|
||||||
@ -42,6 +50,7 @@ class Factory
|
|||||||
'supportedcontrol' => Schema\OID::class,
|
'supportedcontrol' => Schema\OID::class,
|
||||||
'supportedextension' => Schema\OID::class,
|
'supportedextension' => Schema\OID::class,
|
||||||
'supportedfeatures' => Schema\OID::class,
|
'supportedfeatures' => Schema\OID::class,
|
||||||
|
'supportedldapversion' => Schema\Generic::class,
|
||||||
'supportedsaslmechanisms' => Schema\Mechanisms::class,
|
'supportedsaslmechanisms' => Schema\Mechanisms::class,
|
||||||
'userpassword' => Password::class,
|
'userpassword' => Password::class,
|
||||||
];
|
];
|
||||||
|
@ -9,4 +9,5 @@ use App\Classes\LDAP\Attribute;
|
|||||||
*/
|
*/
|
||||||
final class GidNumber extends Attribute
|
final class GidNumber extends Attribute
|
||||||
{
|
{
|
||||||
|
protected(set) bool $no_attr_tags = FALSE;
|
||||||
}
|
}
|
@ -12,6 +12,7 @@ use App\Classes\LDAP\Attribute;
|
|||||||
abstract class Internal extends Attribute
|
abstract class Internal extends Attribute
|
||||||
{
|
{
|
||||||
protected(set) bool $is_internal = TRUE;
|
protected(set) bool $is_internal = TRUE;
|
||||||
|
protected(set) bool $no_attr_tags = TRUE;
|
||||||
|
|
||||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE): View
|
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE): View
|
||||||
{
|
{
|
||||||
|
@ -15,6 +15,8 @@ final class KrbPrincipalKey extends Attribute
|
|||||||
{
|
{
|
||||||
use MD5Updates;
|
use MD5Updates;
|
||||||
|
|
||||||
|
protected(set) bool $no_attr_tags = TRUE;
|
||||||
|
|
||||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE): View
|
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE): View
|
||||||
{
|
{
|
||||||
return view('components.attribute.krbprincipalkey')
|
return view('components.attribute.krbprincipalkey')
|
||||||
|
@ -13,6 +13,8 @@ use Illuminate\Support\Collection;
|
|||||||
*/
|
*/
|
||||||
final class KrbTicketFlags extends Attribute
|
final class KrbTicketFlags extends Attribute
|
||||||
{
|
{
|
||||||
|
protected(set) bool $no_attr_tags = TRUE;
|
||||||
|
|
||||||
private const DISALLOW_POSTDATED = 0x00000001;
|
private const DISALLOW_POSTDATED = 0x00000001;
|
||||||
private const DISALLOW_FORWARDABLE = 0x00000002;
|
private const DISALLOW_FORWARDABLE = 0x00000002;
|
||||||
private const DISALLOW_TGT_BASED = 0x00000004;
|
private const DISALLOW_TGT_BASED = 0x00000004;
|
||||||
|
13
app/Classes/LDAP/Attribute/NoAttrTags/Generic.php
Normal file
13
app/Classes/LDAP/Attribute/NoAttrTags/Generic.php
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Classes\LDAP\Attribute\NoAttrTags;
|
||||||
|
|
||||||
|
use App\Classes\LDAP\Attribute;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an Attribute that doesnt have Lang Tags
|
||||||
|
*/
|
||||||
|
class Generic extends Attribute
|
||||||
|
{
|
||||||
|
protected(set) bool $no_attr_tags = TRUE;
|
||||||
|
}
|
@ -12,6 +12,8 @@ use App\Classes\LDAP\Attribute;
|
|||||||
*/
|
*/
|
||||||
final class ObjectClass extends Attribute
|
final class ObjectClass extends Attribute
|
||||||
{
|
{
|
||||||
|
protected(set) bool $no_attr_tags = TRUE;
|
||||||
|
|
||||||
// The schema ObjectClasses for this objectclass of a DN
|
// The schema ObjectClasses for this objectclass of a DN
|
||||||
protected Collection $oc_schema;
|
protected Collection $oc_schema;
|
||||||
|
|
||||||
@ -21,7 +23,7 @@ final class ObjectClass extends Attribute
|
|||||||
* @param string $dn DN this attribute is used in
|
* @param string $dn DN this attribute is used in
|
||||||
* @param string $name Name of the attribute
|
* @param string $name Name of the attribute
|
||||||
* @param array $values Current Values
|
* @param array $values Current Values
|
||||||
* @param array $oc The objectclasses that the DN of this attribute has
|
* @param array $oc The objectclasses that the DN of this attribute has (ignored for objectclasses)
|
||||||
*/
|
*/
|
||||||
public function __construct(string $dn,string $name,array $values,array $oc=[])
|
public function __construct(string $dn,string $name,array $values,array $oc=[])
|
||||||
{
|
{
|
||||||
@ -29,7 +31,7 @@ final class ObjectClass extends Attribute
|
|||||||
|
|
||||||
$this->oc_schema = config('server')
|
$this->oc_schema = config('server')
|
||||||
->schema('objectclasses')
|
->schema('objectclasses')
|
||||||
->filter(fn($item)=>$this->values->merge($this->values_old)->unique()->contains($item->name));
|
->filter(fn($item)=>$this->values_old->contains($item->name));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __get(string $key): mixed
|
public function __get(string $key): mixed
|
||||||
|
@ -15,6 +15,9 @@ use App\Traits\MD5Updates;
|
|||||||
final class Password extends Attribute
|
final class Password extends Attribute
|
||||||
{
|
{
|
||||||
use MD5Updates;
|
use MD5Updates;
|
||||||
|
|
||||||
|
protected(set) bool $no_attr_tags = TRUE;
|
||||||
|
|
||||||
private const password_helpers = 'Classes/LDAP/Attribute/Password';
|
private const password_helpers = 'Classes/LDAP/Attribute/Password';
|
||||||
public const commands = 'App\\Classes\\LDAP\\Attribute\\Password\\';
|
public const commands = 'App\\Classes\\LDAP\\Attribute\\Password\\';
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ use App\Classes\LDAP\Attribute;
|
|||||||
abstract class Schema extends Attribute
|
abstract class Schema extends Attribute
|
||||||
{
|
{
|
||||||
protected bool $internal = TRUE;
|
protected bool $internal = TRUE;
|
||||||
|
protected(set) bool $no_attr_tags = TRUE;
|
||||||
|
|
||||||
protected static function _get(string $filename,string $string,string $key): ?string
|
protected static function _get(string $filename,string $string,string $key): ?string
|
||||||
{
|
{
|
||||||
@ -30,7 +31,7 @@ abstract class Schema extends Attribute
|
|||||||
while (! feof($f)) {
|
while (! feof($f)) {
|
||||||
$line = trim(fgets($f));
|
$line = trim(fgets($f));
|
||||||
|
|
||||||
if (! $line OR preg_match('/^#/',$line))
|
if ((! $line) || preg_match('/^#/',$line))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
$fields = explode(':',$line);
|
$fields = explode(':',$line);
|
||||||
@ -41,12 +42,15 @@ abstract class Schema extends Attribute
|
|||||||
'desc'=>Arr::get($fields,3,__('No description available, can you help with one?')),
|
'desc'=>Arr::get($fields,3,__('No description available, can you help with one?')),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose($f);
|
fclose($f);
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
});
|
});
|
||||||
|
|
||||||
return Arr::get(($array ? $array->get($string) : []),$key);
|
return Arr::get(($array ? $array->get($string) : []),
|
||||||
|
$key,
|
||||||
|
__('No description available, can you help with one?'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE): View
|
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE): View
|
||||||
|
20
app/Classes/LDAP/Attribute/Schema/Generic.php
Normal file
20
app/Classes/LDAP/Attribute/Schema/Generic.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Classes\LDAP\Attribute\Schema;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\View\View;
|
||||||
|
|
||||||
|
use App\Classes\LDAP\Attribute\Schema;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a Generic Schema Attribute
|
||||||
|
*/
|
||||||
|
class Generic extends Schema
|
||||||
|
{
|
||||||
|
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE): View
|
||||||
|
{
|
||||||
|
// @note Schema attributes cannot be edited
|
||||||
|
return view('components.attribute.schema.generic')
|
||||||
|
->with('o',$this);
|
||||||
|
}
|
||||||
|
}
|
@ -41,13 +41,25 @@ class LDIF extends Export
|
|||||||
|
|
||||||
// Display Attributes
|
// Display Attributes
|
||||||
foreach ($o->getObjects() as $ao) {
|
foreach ($o->getObjects() as $ao) {
|
||||||
foreach ($ao->values as $value) {
|
if ($ao->no_attr_tags)
|
||||||
$result .= $this->multiLineDisplay(
|
foreach ($ao->values as $value) {
|
||||||
Str::isAscii($value)
|
$result .= $this->multiLineDisplay(
|
||||||
? sprintf('%s: %s',$ao->name,$value)
|
Str::isAscii($value)
|
||||||
: sprintf('%s:: %s',$ao->name,base64_encode($value))
|
? sprintf('%s: %s',$ao->name,$value)
|
||||||
,$this->br);
|
: sprintf('%s:: %s',$ao->name,base64_encode($value))
|
||||||
}
|
,$this->br);
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
foreach ($ao->values as $tag => $tagvalues) {
|
||||||
|
foreach ($tagvalues as $value) {
|
||||||
|
$result .= $this->multiLineDisplay(
|
||||||
|
Str::isAscii($value)
|
||||||
|
? sprintf('%s: %s',$ao->name.($tag ? ';'.$tag : ''),$value)
|
||||||
|
: sprintf('%s:: %s',$ao->name.($tag ? ';'.$tag : ''),base64_encode($value))
|
||||||
|
,$this->br);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,8 +59,6 @@ class LDIF extends Import
|
|||||||
$base64encoded = FALSE;
|
$base64encoded = FALSE;
|
||||||
$attribute = NULL;
|
$attribute = NULL;
|
||||||
$value = '';
|
$value = '';
|
||||||
|
|
||||||
// Else its a blank line
|
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
@ -69,7 +67,7 @@ class LDIF extends Import
|
|||||||
$m = [];
|
$m = [];
|
||||||
preg_match('/^([a-zA-Z0-9;-]+)(:+)\s+(.*)$/',$line,$m);
|
preg_match('/^([a-zA-Z0-9;-]+)(:+)\s+(.*)$/',$line,$m);
|
||||||
|
|
||||||
switch ($x=Arr::get($m,1)) {
|
switch (Arr::get($m,1)) {
|
||||||
case 'changetype':
|
case 'changetype':
|
||||||
if ($m[2] !== ':')
|
if ($m[2] !== ':')
|
||||||
throw new GeneralException(sprintf('ChangeType cannot be base64 encoded set at [%d]. (line %d)',$version,$c));
|
throw new GeneralException(sprintf('ChangeType cannot be base64 encoded set at [%d]. (line %d)',$version,$c));
|
||||||
@ -133,7 +131,6 @@ class LDIF extends Import
|
|||||||
|
|
||||||
// Start of a new attribute
|
// Start of a new attribute
|
||||||
$base64encoded = ($m[2] === '::');
|
$base64encoded = ($m[2] === '::');
|
||||||
// @todo Need to parse attributes with ';' options
|
|
||||||
$attribute = $m[1];
|
$attribute = $m[1];
|
||||||
$value = $m[3];
|
$value = $m[3];
|
||||||
|
|
||||||
@ -160,7 +157,7 @@ class LDIF extends Import
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function readEntry() {
|
public function readEntry() {
|
||||||
static $haveVersion = false;
|
static $haveVersion = FALSE;
|
||||||
|
|
||||||
if ($lines = $this->nextLines()) {
|
if ($lines = $this->nextLines()) {
|
||||||
|
|
||||||
@ -179,7 +176,7 @@ class LDIF extends Import
|
|||||||
} else
|
} else
|
||||||
$changetype = 'add';
|
$changetype = 'add';
|
||||||
|
|
||||||
$this->template = new Template($this->server_id,null,null,$changetype);
|
$this->template = new Template($this->server_id,NULL,NULL,$changetype);
|
||||||
|
|
||||||
switch ($changetype) {
|
switch ($changetype) {
|
||||||
case 'add':
|
case 'add':
|
||||||
@ -201,7 +198,7 @@ class LDIF extends Import
|
|||||||
return $this->error(sprintf('%s %s',_('DN does not exist'),$dn),$lines);
|
return $this->error(sprintf('%s %s',_('DN does not exist'),$dn),$lines);
|
||||||
|
|
||||||
$this->template->setDN($dn);
|
$this->template->setDN($dn);
|
||||||
$this->template->accept(false,true);
|
$this->template->accept(FALSE,TRUE);
|
||||||
|
|
||||||
return $this->getModifyDetails($lines);
|
return $this->getModifyDetails($lines);
|
||||||
|
|
||||||
@ -228,6 +225,6 @@ class LDIF extends Import
|
|||||||
return $this->error(_('A valid dn line is required'),$lines);
|
return $this->error(_('A valid dn line is required'),$lines);
|
||||||
|
|
||||||
} else
|
} else
|
||||||
return false;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -16,6 +16,9 @@ use App\Exceptions\InvalidUsage;
|
|||||||
|
|
||||||
class Entry extends Model
|
class Entry extends Model
|
||||||
{
|
{
|
||||||
|
private const TAG_CHARS = 'a-zA-Z0-9-';
|
||||||
|
private const TAG_CHARS_LANG = 'lang-['.self::TAG_CHARS.']';
|
||||||
|
|
||||||
// Our Attribute objects
|
// Our Attribute objects
|
||||||
private Collection $objects;
|
private Collection $objects;
|
||||||
/* @deprecated */
|
/* @deprecated */
|
||||||
@ -51,7 +54,11 @@ class Entry extends Model
|
|||||||
public function getAttributes(): array
|
public function getAttributes(): array
|
||||||
{
|
{
|
||||||
return $this->objects
|
return $this->objects
|
||||||
->map(fn($item)=>$item->values)
|
->flatMap(fn($item)=>
|
||||||
|
($item->no_attr_tags)
|
||||||
|
? [strtolower($item->name)=>$item->values]
|
||||||
|
: $item->values
|
||||||
|
->flatMap(fn($v,$k)=>[strtolower($item->name.($k ? ';'.$k : ''))=>$v]))
|
||||||
->toArray();
|
->toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,15 +165,26 @@ class Entry extends Model
|
|||||||
if (! is_string($value))
|
if (! is_string($value))
|
||||||
throw new \Exception('value should be a string');
|
throw new \Exception('value should be a string');
|
||||||
|
|
||||||
$key = $this->normalizeAttributeKey($key);
|
$key = $this->normalizeAttributeKey(strtolower($key));
|
||||||
|
|
||||||
if (! config('server')->schema('attributetypes')->has($key))
|
// If the attribute name has tags
|
||||||
throw new AttributeException(sprintf('Schema doesnt have attribute [%s]',$key));
|
$matches = [];
|
||||||
|
if (preg_match(sprintf('/^([%s]+);+([%s;]+)/',self::TAG_CHARS,self::TAG_CHARS),$key,$matches)) {
|
||||||
|
$attribute = $matches[1];
|
||||||
|
$tags = $matches[2];
|
||||||
|
|
||||||
$o = $this->objects->get($key) ?: Attribute\Factory::create($this->dn ?: '',$key,[]);
|
} else {
|
||||||
$o->addValue($value);
|
$attribute = $key;
|
||||||
|
$tags = '';
|
||||||
|
}
|
||||||
|
|
||||||
$this->objects->put($key,$o);
|
if (! config('server')->schema('attributetypes')->has($attribute))
|
||||||
|
throw new AttributeException(sprintf('Schema doesnt have attribute [%s]',$attribute));
|
||||||
|
|
||||||
|
$o = $this->objects->get($attribute) ?: Attribute\Factory::create($this->dn ?: '',$attribute,[]);
|
||||||
|
$o->addValue($tags,$value);
|
||||||
|
|
||||||
|
$this->objects->put($attribute,$o);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -179,34 +197,34 @@ class Entry extends Model
|
|||||||
$result = collect();
|
$result = collect();
|
||||||
$entry_oc = Arr::get($this->attributes,'objectclass',[]);
|
$entry_oc = Arr::get($this->attributes,'objectclass',[]);
|
||||||
|
|
||||||
foreach ($this->attributes as $attribute => $values) {
|
foreach ($this->attributes as $attrtag => $values) {
|
||||||
// If the attribute name has tags
|
// If the attribute name has tags
|
||||||
$matches = [];
|
$matches = [];
|
||||||
if (preg_match('/^([a-zA-Z]+)(;([a-zA-Z-;]+))+/',$attribute,$matches)) {
|
if (preg_match(sprintf('/^([%s]+);+([%s;]+)/',self::TAG_CHARS,self::TAG_CHARS),$attrtag,$matches)) {
|
||||||
$attribute = $matches[1];
|
$attribute = $matches[1];
|
||||||
|
$tags = $matches[2];
|
||||||
// If the attribute doesnt exist we'll create it
|
|
||||||
$o = Arr::get(
|
|
||||||
$result,
|
|
||||||
$attribute,
|
|
||||||
Factory::create(
|
|
||||||
$this->dn,
|
|
||||||
$attribute,
|
|
||||||
Arr::get($this->original,$attribute,[]),
|
|
||||||
$entry_oc,
|
|
||||||
));
|
|
||||||
$o->setLangTag($matches[3],$values);
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$o = Factory::create($this->dn,$attribute,Arr::get($this->original,$attribute,[]),$entry_oc);
|
$attribute = $attrtag;
|
||||||
|
$tags = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! $result->has($attribute)) {
|
$orig = Arr::get($this->original,$attrtag,[]);
|
||||||
// Store our new values to know if this attribute has changed
|
|
||||||
$o->values = collect($values);
|
|
||||||
|
|
||||||
$result->put($attribute,$o);
|
// If the attribute doesnt exist we'll create it
|
||||||
}
|
$o = Arr::get(
|
||||||
|
$result,
|
||||||
|
$attribute,
|
||||||
|
Factory::create(
|
||||||
|
$this->dn,
|
||||||
|
$attribute,
|
||||||
|
[$tags=>$orig],
|
||||||
|
$entry_oc,
|
||||||
|
));
|
||||||
|
|
||||||
|
$o->values = $o->values->merge([$tags=>$values]);
|
||||||
|
|
||||||
|
$result->put($attribute,$o);
|
||||||
}
|
}
|
||||||
|
|
||||||
$sort = collect(config('pla.attr_display_order',[]))->map(fn($item)=>strtolower($item));
|
$sort = collect(config('pla.attr_display_order',[]))->map(fn($item)=>strtolower($item));
|
||||||
@ -274,6 +292,36 @@ class Entry extends Model
|
|||||||
->filter(fn($item)=>$item->is_internal);
|
->filter(fn($item)=>$item->is_internal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identify the language tags (RFC 3866) used by this entry
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function getLangTags(): Collection
|
||||||
|
{
|
||||||
|
return $this->getObjects()
|
||||||
|
->filter(fn($item)=>! $item->no_attr_tags)
|
||||||
|
->map(fn($item)=>$item
|
||||||
|
->values
|
||||||
|
->keys()
|
||||||
|
->filter(fn($item)=>preg_match(sprintf('/%s+;?/',self::TAG_CHARS_LANG),$item)))
|
||||||
|
->filter(fn($item)=>$item->count());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Of all the items with lang tags, which ones have more than 1 lang tag
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function getLangMultiTags(): Collection
|
||||||
|
{
|
||||||
|
return $this->getLangTags()
|
||||||
|
->map(fn($item)=>$item->values()
|
||||||
|
->map(fn($item)=>explode(';',$item))
|
||||||
|
->filter(fn($item)=>count($item) > 1))
|
||||||
|
->filter(fn($item)=>$item->count());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an attribute as an object
|
* Get an attribute as an object
|
||||||
*
|
*
|
||||||
@ -299,6 +347,29 @@ class Entry extends Model
|
|||||||
return $this->objects;
|
return $this->objects;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find other attribute tags used by this entry
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function getOtherTags(): Collection
|
||||||
|
{
|
||||||
|
return $this->getObjects()
|
||||||
|
->filter(fn($item)=>! $item->no_attr_tags)
|
||||||
|
->map(fn($item)=>$item
|
||||||
|
->values
|
||||||
|
->keys()
|
||||||
|
->filter(fn($item)=>
|
||||||
|
$item && collect(explode(';',$item))->filter(
|
||||||
|
fn($item)=>
|
||||||
|
(! preg_match(sprintf('/^%s+$/',self::TAG_CHARS_LANG),$item))
|
||||||
|
&& (! preg_match('/^binary$/',$item))
|
||||||
|
)
|
||||||
|
->count())
|
||||||
|
)
|
||||||
|
->filter(fn($item)=>$item->count());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a list of attributes without any values
|
* Return a list of attributes without any values
|
||||||
*
|
*
|
||||||
|
@ -1 +1 @@
|
|||||||
v2.0.2-rel
|
v2.1.0-dev
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
<div class="alert alert-danger p-0" style="font-size: .80em;">
|
||||||
|
<table class="table table-borderless table-danger p-0 m-0">
|
||||||
|
<tr>
|
||||||
|
<td class="align-top" style="width: 5%;"><i class="fas fa-fw fa-2x fa-exclamation-triangle"></i></td>
|
||||||
|
<td>Unable to display this attribute as it has attribute tags [<strong>{!! $tags->join('</strong>, <strong>') !!}</strong>].<br>
|
||||||
|
You can manage it with an LDIF import.</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
@ -1,19 +1,31 @@
|
|||||||
<!-- $o=Attribute::class -->
|
<!-- $o=Attribute::class -->
|
||||||
<x-attribute.layout :edit="$edit ?? FALSE" :new="$new ?? FALSE" :o="$o">
|
<x-attribute.layout :edit="$edit ?? FALSE" :new="$new ?? FALSE" :o="$o">
|
||||||
@foreach(old($o->name_lc,($new ?? FALSE) ? [NULL] : $o->values) as $value)
|
@foreach(old($o->name_lc,($new ?? FALSE) ? [NULL] : $o->values) as $tag=>$tagvalues)
|
||||||
@if (($edit ?? FALSE) && ! $o->is_rdn)
|
<div class="row p-2 border rounded">
|
||||||
<div class="input-group has-validation">
|
<div class="col-2">
|
||||||
<input type="text" @class(['form-control','is-invalid'=>($e=$errors->get($o->name_lc.'.'.$loop->index)),'mb-1','border-focus'=>($o->values->contains($value))]) name="{{ $o->name_lc }}[]" value="{{ $value }}" placeholder="{{ ! is_null($x=Arr::get($o->values,$loop->index)) ? $x : '['.__('NEW').']' }}" @readonly(! ($new ?? FALSE))>
|
{{ $tag }}
|
||||||
|
</div>
|
||||||
|
<div class="col-10">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
@foreach($tagvalues as $value)
|
||||||
|
@if(($edit ?? FALSE) && ! $o->is_rdn)
|
||||||
|
<div class="input-group has-validation">
|
||||||
|
<input type="text" @class(['form-control','is-invalid'=>($e=$errors->get($o->name_lc.'.'.$loop->index)),'mb-1','border-focus'=>($o->values->contains($value))]) name="{{ $o->name_lc }}[]" value="{{ $value }}" placeholder="{{ ! is_null($x=Arr::get($o->values,$loop->index)) ? $x : '['.__('NEW').']' }}" @readonly(! ($new ?? FALSE))>
|
||||||
|
|
||||||
<div class="invalid-feedback pb-2">
|
<div class="invalid-feedback pb-2">
|
||||||
@if($e)
|
@if($e)
|
||||||
{{ join('|',$e) }}
|
{{ join('|',$e) }}
|
||||||
@endif
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@else
|
||||||
|
{{ $value }}
|
||||||
|
@endif
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
@else
|
|
||||||
{{ $value }}
|
|
||||||
@endif
|
|
||||||
@endforeach
|
@endforeach
|
||||||
</x-attribute.layout>
|
</x-attribute.layout>
|
@ -1,5 +1,5 @@
|
|||||||
<!-- $o=Internal::class -->
|
<!-- $o=Internal::class -->
|
||||||
@foreach (old($o->name_lc,$o->values) as $value)
|
@foreach(old($o->name_lc,$o->values) as $value)
|
||||||
@if($loop->index)<br>@endif
|
@if($loop->index)<br>@endif
|
||||||
{{ $value }}
|
{{ $value }}
|
||||||
@endforeach
|
@endforeach
|
@ -1,5 +1,5 @@
|
|||||||
<!-- $o=Internal\Timestamp::class -->
|
<!-- $o=Internal\Timestamp::class -->
|
||||||
@foreach (old($o->name_lc,$o->values) as $value)
|
@foreach(old($o->name_lc,$o->values) as $value)
|
||||||
@if($loop->index)<br>@endif
|
@if($loop->index)<br>@endif
|
||||||
{{ \Carbon\Carbon::createFromTimestamp(strtotime($value))->format(config('pla.datetime_format','Y-m-d H:i:s')) }}
|
{{ \Carbon\Carbon::createFromTimestamp(strtotime($value))->format(config('pla.datetime_format','Y-m-d H:i:s')) }}
|
||||||
@endforeach
|
@endforeach
|
@ -1,8 +1,2 @@
|
|||||||
<!-- $o=Attribute::class -->
|
<!-- $o=NoAttrTags/Generic::class -->
|
||||||
<x-attribute.layout :edit="false" :new="false" :detail="true" :o="$o">
|
@include('components.form.disabled.datetime')
|
||||||
@foreach(old($o->name_lc,($new ?? FALSE) ? [NULL] : $o->values) as $value)
|
|
||||||
<div class="input-group">
|
|
||||||
<input type="text" @class(['form-control','mb-1']) name="{{ $o->name_lc }}[]" value="{{ \Carbon\Carbon::createFromTimestamp(strtotime($value))->format(config('pla.datetime_format','Y-m-d H:i:s')) }}" @disabled(true)>
|
|
||||||
</div>
|
|
||||||
@endforeach
|
|
||||||
</x-attribute.layout>
|
|
||||||
|
@ -1 +1,2 @@
|
|||||||
@include('components.attribute.krblastfailedauth')
|
<!-- $o=NoAttrTags/Generic::class -->
|
||||||
|
@include('components.form.disabled.datetime')
|
@ -1 +1,2 @@
|
|||||||
@include('components.attribute.krblastfailedauth')
|
<!-- $o=NoAttrTags/Generic::class -->
|
||||||
|
@include('components.form.disabled.datetime')
|
@ -1,8 +1,2 @@
|
|||||||
<!-- $o=Attribute::class -->
|
<!-- $o=NoAttrTags/Generic::class -->
|
||||||
<x-attribute.layout :edit="false" :new="false" :detail="true" :o="$o">
|
@include('components.form.disabled.input')
|
||||||
@foreach(old($o->name_lc,($new ?? FALSE) ? [NULL] : $o->values) as $value)
|
|
||||||
<div class="input-group">
|
|
||||||
<input type="text" @class(['form-control','mb-1']) name="{{ $o->name_lc }}[]" value="{{ $value }}" @disabled(true)>
|
|
||||||
</div>
|
|
||||||
@endforeach
|
|
||||||
</x-attribute.layout>
|
|
@ -1 +1,2 @@
|
|||||||
@include('components.attribute.krblastfailedauth')
|
<!-- $o=NoAttrTags/Generic::class -->
|
||||||
|
@include('components.form.disabled.datetime')
|
@ -1,5 +1,5 @@
|
|||||||
<!-- @todo We are not handling redirect backs yet with updated passwords -->
|
<!-- @todo We are not handling redirect backs yet with updated passwords -->
|
||||||
<!-- $o=Password::class -->
|
<!-- $o=KrbPrincipleKey::class -->
|
||||||
<x-attribute.layout :edit="$edit ?? FALSE" :new="$new ?? FALSE" :o="$o">
|
<x-attribute.layout :edit="$edit ?? FALSE" :new="$new ?? FALSE" :o="$o">
|
||||||
@foreach($o->values_old as $value)
|
@foreach($o->values_old as $value)
|
||||||
@if($edit)
|
@if($edit)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<!-- $o=Attribute::class -->
|
<!-- $o=Attribute::class -->
|
||||||
<x-attribute.layout :edit="$edit" :new="$new" :o="$o">
|
<x-attribute.layout :edit="$edit" :new="$new" :o="$o">
|
||||||
@foreach(old($o->name_lc,$o->values) as $value)
|
@foreach(old($o->name_lc,$o->values) as $value)
|
||||||
@if ($edit)
|
@if($edit)
|
||||||
<x-attribute.widget.objectclass :o="$o" :edit="$edit" :new="$new" :loop="$loop" :value="$value"/>
|
<x-attribute.widget.objectclass :o="$o" :edit="$edit" :new="$new" :loop="$loop" :value="$value"/>
|
||||||
@else
|
@else
|
||||||
{{ $value }}
|
{{ $value }}
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
{!! $o->values->join('<br>') !!}
|
@ -0,0 +1,8 @@
|
|||||||
|
<!-- $o=Attribute::class -->
|
||||||
|
<x-attribute.layout :edit="false" :new="false" :detail="true" :o="$o">
|
||||||
|
@foreach(old($o->name_lc,($new ?? FALSE) ? [NULL] : $o->values) as $value)
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="text" @class(['form-control','mb-1']) name="{{ $o->name_lc }}[]" value="{{ \Carbon\Carbon::createFromTimestamp(strtotime($value))->format(config('pla.datetime_format','Y-m-d H:i:s')) }}" @disabled(true)>
|
||||||
|
</div>
|
||||||
|
@endforeach
|
||||||
|
</x-attribute.layout>
|
8
resources/views/components/form/disabled/input.blade.php
Normal file
8
resources/views/components/form/disabled/input.blade.php
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<!-- $o=Attribute::class -->
|
||||||
|
<x-attribute.layout :edit="false" :new="false" :detail="true" :o="$o">
|
||||||
|
@foreach(old($o->name_lc,($new ?? FALSE) ? [NULL] : $o->values) as $value)
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="text" @class(['form-control','mb-1']) name="{{ $o->name_lc }}[]" value="{{ $value }}" @disabled(true)>
|
||||||
|
</div>
|
||||||
|
@endforeach
|
||||||
|
</x-attribute.layout>
|
@ -26,6 +26,12 @@
|
|||||||
<x-attribute :o="$o->getObject('entryuuid')" :na="__('Unknown')"/>
|
<x-attribute :o="$o->getObject('entryuuid')" :na="__('Unknown')"/>
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
@if(($x=$o->getLangTags())->count())
|
||||||
|
<tr class="mt-1">
|
||||||
|
<td class="p-0 pe-2">Tags</td>
|
||||||
|
<th class="p-0">{{ $x->flatMap(fn($item)=>$item->values())->unique()->join(', ') }}</th>
|
||||||
|
</tr>
|
||||||
|
@endif
|
||||||
</table>
|
</table>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -38,6 +38,24 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
@if(($x=$o->getOtherTags())->count())
|
||||||
|
<div class="ms-4 mt-4 alert alert-danger p-2" style="max-width: 30em; font-size: 0.80em;">
|
||||||
|
This entry has [<strong>{!! $x->flatten()->join('</strong>, <strong>') !!}</strong>] tags used by [<strong>{!! $x->keys()->join('</strong>, <strong>') !!}</strong>] that cant be managed by PLA. You can though manage those tags with an LDIF import.
|
||||||
|
</div>
|
||||||
|
@elseif(($x=$o->getLangMultiTags())->count())
|
||||||
|
<div class="ms-4 mt-4 alert alert-danger p-2" style="max-width: 30em; font-size: 0.80em;">
|
||||||
|
This entry has multi-language tags used by [<strong>{!! $x->keys()->join('</strong>, <strong>') !!}</strong>] that cant be managed by PLA. You can though manage those lang tags with an LDIF import.
|
||||||
|
</div>
|
||||||
|
@elseif(($x=$o->getLangTags())->count())
|
||||||
|
<div class="ms-4 mt-4 alert alert-warning p-2" style="max-width: 30em; font-size: 0.80em;">
|
||||||
|
This entry has language tags used by [<strong>{!! $x->keys()->join('</strong>, <strong>') !!}</strong>] that cant be managed by PLA yet. You can though manage those lang tags with an LDIF import.
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
@section('main-content')
|
@section('main-content')
|
||||||
|
Loading…
x
Reference in New Issue
Block a user