Compare commits
13 Commits
b0f92a6a8a
...
2d732e5d52
Author | SHA1 | Date | |
---|---|---|---|
2d732e5d52 | |||
d294c9449d | |||
deefd9be43 | |||
59cf0d337e | |||
c4b1d9ec51 | |||
5ce3a63878 | |||
ac8e79ab99 | |||
d0c02b91c0 | |||
2a691c147e | |||
781c87cb83 | |||
98a0b87afe | |||
88db4ccc99 | |||
6059bc1e45 |
@ -2,7 +2,6 @@ APP_NAME=Laravel
|
||||
APP_ENV=production
|
||||
APP_KEY=
|
||||
APP_DEBUG=false
|
||||
APP_URL=http://localhost
|
||||
|
||||
LOG_CHANNEL=daily
|
||||
|
||||
@ -12,7 +11,7 @@ SESSION_DRIVER=file
|
||||
SESSION_LIFETIME=120
|
||||
|
||||
LDAP_HOST=
|
||||
LDAP_BASE_DN=
|
||||
LDAP_USERNAME=
|
||||
LDAP_PASSWORD=
|
||||
LDAP_CACHE=false
|
||||
LDAP_ALERT_ROOTDN=true
|
||||
|
@ -2,7 +2,6 @@ APP_NAME=Laravel
|
||||
APP_ENV=local
|
||||
APP_KEY=
|
||||
APP_DEBUG=true
|
||||
APP_URL=http://localhost
|
||||
|
||||
LOG_CHANNEL=stderr
|
||||
|
||||
@ -12,7 +11,6 @@ SESSION_DRIVER=file
|
||||
SESSION_LIFETIME=120
|
||||
|
||||
LDAP_HOST=openldap
|
||||
LDAP_BASE_DN="dc=Test"
|
||||
LDAP_USERNAME="cn=admin,dc=Test"
|
||||
LDAP_PASSWORD="test"
|
||||
LDAP_CACHE=false
|
||||
|
@ -7,6 +7,7 @@ use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
use App\Classes\LDAP\Schema\AttributeType;
|
||||
use App\Classes\Template;
|
||||
use App\Exceptions\InvalidUsage;
|
||||
use App\Ldap\Entry;
|
||||
|
||||
@ -326,10 +327,10 @@ class Attribute implements \Countable, \ArrayAccess
|
||||
* @param bool $old Use old value
|
||||
* @param bool $new Enable adding values
|
||||
* @param bool $updated Has the entry been updated (uses rendering highlights))
|
||||
* @param string|null $template
|
||||
* @param Template|null $template
|
||||
* @return View
|
||||
*/
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE,?string $template=NULL): View
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE,?Template $template=NULL): View
|
||||
{
|
||||
if ($this->is_internal)
|
||||
// @note Internal attributes cannot be edited
|
||||
|
@ -5,7 +5,7 @@ namespace App\Classes\LDAP\Attribute\Binary;
|
||||
use Illuminate\Contracts\View\View;
|
||||
|
||||
use App\Classes\LDAP\Attribute\Binary;
|
||||
use App\Ldap\Entry;
|
||||
use App\Classes\Template;
|
||||
use App\Traits\MD5Updates;
|
||||
|
||||
/**
|
||||
@ -15,7 +15,7 @@ final class JpegPhoto extends Binary
|
||||
{
|
||||
use MD5Updates;
|
||||
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE,?string $template=NULL): View
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE,?Template $template=NULL): View
|
||||
{
|
||||
return view('components.attribute.binary.jpegphoto')
|
||||
->with('o',$this)
|
||||
|
@ -2,9 +2,6 @@
|
||||
|
||||
namespace App\Classes\LDAP\Attribute;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
use App\Classes\LDAP\Attribute;
|
||||
use App\Traits\MD5Updates;
|
||||
|
||||
|
@ -3,7 +3,6 @@
|
||||
namespace App\Classes\LDAP\Attribute;
|
||||
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Classes\LDAP\Attribute;
|
||||
|
||||
|
@ -5,14 +5,14 @@ namespace App\Classes\LDAP\Attribute\Internal;
|
||||
use Illuminate\Contracts\View\View;
|
||||
|
||||
use App\Classes\LDAP\Attribute\Internal;
|
||||
use App\Ldap\Entry;
|
||||
use App\Classes\Template;
|
||||
|
||||
/**
|
||||
* Represents an attribute whose values are timestamps
|
||||
*/
|
||||
final class Timestamp extends Internal
|
||||
{
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE,?string $template=NULL): View
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE,?Template $template=NULL): View
|
||||
{
|
||||
// @note Internal attributes cannot be edited
|
||||
return view('components.attribute.internal.timestamp')
|
||||
|
@ -5,7 +5,7 @@ namespace App\Classes\LDAP\Attribute;
|
||||
use Illuminate\Contracts\View\View;
|
||||
|
||||
use App\Classes\LDAP\Attribute;
|
||||
use App\Ldap\Entry;
|
||||
use App\Classes\Template;
|
||||
use App\Traits\MD5Updates;
|
||||
|
||||
/**
|
||||
@ -17,7 +17,7 @@ final class KrbPrincipalKey extends Attribute
|
||||
|
||||
protected(set) bool $no_attr_tags = TRUE;
|
||||
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE,?string $template=NULL): View
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE,?Template $template=NULL): View
|
||||
{
|
||||
return view('components.attribute.krbprincipalkey')
|
||||
->with('o',$this)
|
||||
|
@ -6,7 +6,7 @@ use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
use App\Classes\LDAP\Attribute;
|
||||
use App\Ldap\Entry;
|
||||
use App\Classes\Template;
|
||||
|
||||
/**
|
||||
* Represents an attribute whose value is a Kerberos Ticket Flag
|
||||
@ -50,7 +50,7 @@ final class KrbTicketFlags extends Attribute
|
||||
return $helpers;
|
||||
}
|
||||
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE,?string $template=NULL): View
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE,?Template $template=NULL): View
|
||||
{
|
||||
return view('components.attribute.krbticketflags')
|
||||
->with('o',$this)
|
||||
|
@ -6,7 +6,7 @@ use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
use App\Classes\LDAP\Attribute;
|
||||
use App\Ldap\Entry;
|
||||
use App\Classes\Template;
|
||||
|
||||
/**
|
||||
* Represents an ObjectClass Attribute
|
||||
@ -70,7 +70,7 @@ final class ObjectClass extends Attribute
|
||||
->contains($value);
|
||||
}
|
||||
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE,?string $template=NULL): View
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE,?Template $template=NULL): View
|
||||
{
|
||||
return view('components.attribute.objectclass')
|
||||
->with('o',$this)
|
||||
|
@ -7,7 +7,7 @@ use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
use App\Classes\LDAP\Attribute;
|
||||
use App\Ldap\Entry;
|
||||
use App\Classes\Template;
|
||||
use App\Traits\MD5Updates;
|
||||
|
||||
/**
|
||||
@ -80,7 +80,7 @@ final class Password extends Attribute
|
||||
return ($helpers=static::helpers())->has($id) ? new ($helpers->get($id)) : NULL;
|
||||
}
|
||||
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE,?string $template=NULL): View
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE,?Template $template=NULL): View
|
||||
{
|
||||
return view('components.attribute.password')
|
||||
->with('o',$this)
|
||||
|
@ -6,7 +6,7 @@ use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
use App\Classes\LDAP\Attribute;
|
||||
use App\Ldap\Entry;
|
||||
use App\Classes\Template;
|
||||
|
||||
/**
|
||||
* Represents the RDN for an Entry
|
||||
@ -35,7 +35,7 @@ final class RDN extends Attribute
|
||||
]);
|
||||
}
|
||||
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE,?string $template=NULL): View
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE,?Template $template=NULL): View
|
||||
{
|
||||
return view('components.attribute.rdn')
|
||||
->with('o',$this);
|
||||
|
@ -2,12 +2,10 @@
|
||||
|
||||
namespace App\Classes\LDAP\Attribute;
|
||||
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
use App\Classes\LDAP\Attribute;
|
||||
use App\Ldap\Entry;
|
||||
|
||||
/**
|
||||
* Represents an attribute whose values are schema related
|
||||
|
@ -5,14 +5,14 @@ namespace App\Classes\LDAP\Attribute\Schema;
|
||||
use Illuminate\Contracts\View\View;
|
||||
|
||||
use App\Classes\LDAP\Attribute\Schema;
|
||||
use App\Ldap\Entry;
|
||||
use App\Classes\Template;
|
||||
|
||||
/**
|
||||
* Represents a Generic Schema Attribute
|
||||
*/
|
||||
class Generic extends Schema
|
||||
{
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE,?string $template=NULL): View
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE,?Template $template=NULL): View
|
||||
{
|
||||
// @note Schema attributes cannot be edited
|
||||
return view('components.attribute.schema.generic')
|
||||
|
@ -5,7 +5,7 @@ namespace App\Classes\LDAP\Attribute\Schema;
|
||||
use Illuminate\Contracts\View\View;
|
||||
|
||||
use App\Classes\LDAP\Attribute\Schema;
|
||||
use App\Ldap\Entry;
|
||||
use App\Classes\Template;
|
||||
|
||||
/**
|
||||
* Represents a Mechanisms Attribute
|
||||
@ -34,7 +34,7 @@ final class Mechanisms extends Schema
|
||||
return parent::_get(config_path('ldap_supported_saslmechanisms.txt'),$string,$key);
|
||||
}
|
||||
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE,?string $template=NULL): View
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE,?Template $template=NULL): View
|
||||
{
|
||||
// @note Schema attributes cannot be edited
|
||||
return view('components.attribute.schema.mechanisms')
|
||||
|
@ -5,7 +5,7 @@ namespace App\Classes\LDAP\Attribute\Schema;
|
||||
use Illuminate\Contracts\View\View;
|
||||
|
||||
use App\Classes\LDAP\Attribute\Schema;
|
||||
use App\Ldap\Entry;
|
||||
use App\Classes\Template;
|
||||
|
||||
/**
|
||||
* Represents an OID Attribute
|
||||
@ -35,7 +35,7 @@ final class OID extends Schema
|
||||
return parent::_get(config_path('ldap_supported_oids.txt'),$string,$key);
|
||||
}
|
||||
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE,?string $template=NULL): View
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE,?Template $template=NULL): View
|
||||
{
|
||||
// @note Schema attributes cannot be edited
|
||||
return view('components.attribute.schema.oid')
|
||||
|
@ -29,7 +29,7 @@ abstract class Export
|
||||
|
||||
abstract public function __toString(): string;
|
||||
|
||||
protected function header()
|
||||
protected function header(): string
|
||||
{
|
||||
$output = '';
|
||||
|
||||
@ -42,7 +42,7 @@ abstract class Export
|
||||
//$output .= sprintf('# %s: %s',__('Search Filter'),$this->entry->dn).$this->br;
|
||||
$output .= sprintf('# %s: %s',__('Total Entries'),$this->items->count()).$this->br;
|
||||
$output .= '#'.$this->br;
|
||||
$output .= sprintf('# %s %s (%s) on %s',__('Generated by'),config('app.name'),config('app.url'),date('F j, Y g:i a')).$this->br;
|
||||
$output .= sprintf('# %s %s (%s) on %s',__('Generated by'),config('app.name'),request()->root(),date('F j, Y g:i a')).$this->br;
|
||||
$output .= sprintf('# %s %s',__('Exported by'),Auth::user() ?: 'Anonymous').$this->br;
|
||||
$output .= sprintf('# %s: %s',__('Version'),config('app.version')).$this->br;
|
||||
|
||||
|
@ -69,7 +69,7 @@ final class Server
|
||||
public static function baseDNs(bool $objects=TRUE): Collection
|
||||
{
|
||||
try {
|
||||
$rootdse = self::rootDSE();
|
||||
$namingcontexts = collect(config('pla.base_dns') ?: self::rootDSE()?->namingcontexts);
|
||||
|
||||
/**
|
||||
* LDAP Error Codes:
|
||||
@ -175,13 +175,13 @@ final class Server
|
||||
}
|
||||
|
||||
if (! $objects)
|
||||
return collect($rootdse->namingcontexts ?: []);
|
||||
return $namingcontexts;
|
||||
|
||||
return Cache::remember('basedns'.Session::id(),config('ldap.cache.time'),function() use ($rootdse) {
|
||||
return Cache::remember('basedns'.Session::id(),config('ldap.cache.time'),function() use ($namingcontexts) {
|
||||
$result = collect();
|
||||
|
||||
// @note: Incase our rootDSE didnt return a namingcontext, we'll have no base DNs
|
||||
foreach (($rootdse->namingcontexts ?: []) as $dn)
|
||||
foreach ($namingcontexts as $dn)
|
||||
$result->push(self::get($dn)->read()->find($dn));
|
||||
|
||||
return $result->filter()->sort(fn($item)=>$item->sort_key);
|
||||
@ -298,6 +298,7 @@ final class Server
|
||||
*
|
||||
* @param string $key
|
||||
* @return int|bool
|
||||
* @throws InvalidUsage
|
||||
*/
|
||||
public function get_attr_id(string $key): int|bool
|
||||
{
|
||||
|
@ -20,6 +20,8 @@ class Template
|
||||
$this->file = $file;
|
||||
|
||||
try {
|
||||
// @todo Load in the proper attribute objects and objectclass objects
|
||||
// @todo Make sure we have a structural objectclass, or make the template invalid
|
||||
$this->template = json_decode($td->get($file),null,512,JSON_OBJECT_AS_ARRAY|JSON_THROW_ON_ERROR);
|
||||
|
||||
} catch (\JsonException $e) {
|
||||
@ -31,11 +33,12 @@ class Template
|
||||
public function __get(string $key): mixed
|
||||
{
|
||||
return match ($key) {
|
||||
'name' => Str::replaceEnd('.json','',$this->file),
|
||||
'attributes' => collect(array_map('strtolower',array_keys(Arr::get($this->template,$key)))),
|
||||
'objectclasses' => collect(array_map('strtolower',Arr::get($this->template,$key))),
|
||||
'attributes' => collect(Arr::get($this->template,$key))->keys(),
|
||||
'enabled' => Arr::get($this->template,$key,FALSE) && (! $this->invalid),
|
||||
'icon','regexp','title' => Arr::get($this->template,$key),
|
||||
'name' => Str::replaceEnd('.json','',$this->file),
|
||||
'objectclasses' => collect(Arr::get($this->template,$key)),
|
||||
'order' => collect(Arr::get($this->template,'attributes'))->map(fn($item)=>$item['order']),
|
||||
|
||||
default => throw new \Exception('Unknown key: '.$key),
|
||||
};
|
||||
@ -46,8 +49,159 @@ class Template
|
||||
return array_key_exists($key,$this->template);
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
private function autofill()
|
||||
{
|
||||
return $this->invalid ? '' : Arr::get($this->template,'title','No Template Name');
|
||||
/*
|
||||
autoFill:string
|
||||
string is a literal string, and may contain many fields like %attr|start-end/flags|additionalcontrolchar%
|
||||
to substitute values read from other fields.
|
||||
|start-end is optional, but must be present if the k flag is used.
|
||||
/flags is optional.
|
||||
|additionalcontrolchar is optional.
|
||||
|
||||
flags may be:
|
||||
T: Read display text from selection item (drop-down list), otherwise, read the value of the field
|
||||
For fields that aren't selection items, /T shouldn't be used, and the field value will always be read.
|
||||
k: Tokenize:
|
||||
If the "k" flag is not given:
|
||||
A |start-end instruction will perform a sub-string operation upon
|
||||
the value of the attr, passing character positions start-end through.
|
||||
start can be 0 for first character, or any other integer.
|
||||
end can be 0 for last character, or any other integer for a specific position.
|
||||
If the "k" flag is given:
|
||||
The string read will be split into fields, using : as a delimiter
|
||||
"start" indicates which field number to pass through.
|
||||
K: The string read will be split into fields, using ' ' as a delimiter "start" indicates which field number to pass through.
|
||||
If additionalcontrolchar is given, it will be used as delimiter (e.g. this allows for splitting e-mail addresses
|
||||
into domain and domain-local part).
|
||||
l: Make the result lower case.
|
||||
U: Make the result upper case.
|
||||
A: Remap special characters to their corresponding ASCII value
|
||||
*/
|
||||
if (! preg_match('/;/',$arg)) {
|
||||
system_message(array(
|
||||
'title'=>_('Problem with autoFill() in template'),
|
||||
'body'=>sprintf('%s (<b>%s</b>)',_('There is only 1 argument, when there should be two'),$attribute->getName(false)),
|
||||
'type'=>'warn'));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
list($attr,$string) = preg_split('(([^,]+);(.*))',$arg,-1,PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
|
||||
preg_match_all('/%(\w+)(\|[0-9]*-[0-9]*)?(\/[KklTUA]+)?(?:\|(.))?%/U',$string,$matchall);
|
||||
//print"<PRE>";print_r($matchall); //0 = highlevel match, 1 = attr, 2 = subst, 3 = mod, 4 = delimiter
|
||||
|
||||
if (! isset($attribute->js['autoFill']))
|
||||
$attribute->js['autoFill'] = '';
|
||||
|
||||
$formula = $string;
|
||||
$formula = preg_replace('/^([^%])/','\'$1',$formula);
|
||||
$formula = preg_replace('/([^%])$/','$1\'',$formula);
|
||||
|
||||
# Check that our attributes match our schema attributes.
|
||||
foreach ($matchall[1] as $index => $checkattr) {
|
||||
$sattr = $this->getServer()->getSchemaAttribute($checkattr);
|
||||
|
||||
# If the attribute is the same as in the XML file, then dont need to do anything.
|
||||
if (! $sattr || ! strcasecmp($sattr->getName(),$checkattr))
|
||||
continue;
|
||||
|
||||
$formula = preg_replace("/$checkattr/",$sattr->getName(),$formula);
|
||||
$matchall[1][$index] = $sattr->getName();
|
||||
}
|
||||
|
||||
$elem_id = 0;
|
||||
|
||||
foreach ($matchall[0] as $index => $null) {
|
||||
$match_attr = strtolower($matchall[1][$index]);
|
||||
$match_subst = $matchall[2][$index];
|
||||
$match_mod = $matchall[3][$index];
|
||||
$match_delim = $matchall[4][$index];
|
||||
|
||||
$substrarray = array();
|
||||
|
||||
if (! isset($varcount[$match_attr]))
|
||||
$varcount[$match_attr] = 0;
|
||||
else
|
||||
$varcount[$match_attr]++;
|
||||
|
||||
$js_match_attr = $match_attr;
|
||||
$match_attr = $js_match_attr.'xx'.$varcount[$match_attr];
|
||||
|
||||
$formula = preg_replace('/%'.$js_match_attr.'([|\/%])/i','%'.$match_attr.'$1',$formula,1);
|
||||
|
||||
$attribute->js['autoFill'] .= sprintf(" var %s;\n",$match_attr);
|
||||
$attribute->js['autoFill'] .= sprintf(
|
||||
" var elem$elem_id = document.getElementById(pre+'%s'+suf);\n".
|
||||
" if (!elem$elem_id) return;\n", $js_match_attr);
|
||||
|
||||
if (strstr($match_mod,'T')) {
|
||||
$attribute->js['autoFill'] .= sprintf(" %s = elem$elem_id.options[elem$elem_id.selectedIndex].text;\n",
|
||||
$match_attr);
|
||||
} else {
|
||||
$attribute->js['autoFill'] .= sprintf(" %s = elem$elem_id.value;\n",$match_attr);
|
||||
}
|
||||
|
||||
$elem_id++;
|
||||
|
||||
if (strstr($match_mod,'k')) {
|
||||
preg_match_all('/([0-9]+)/',trim($match_subst),$substrarray);
|
||||
if (isset($substrarray[1][0])) {
|
||||
$tok_idx = $substrarray[1][0];
|
||||
} else {
|
||||
$tok_idx = '0';
|
||||
}
|
||||
$attribute->js['autoFill'] .= sprintf(" %s = %s.split(':')[%s];\n",$match_attr,$match_attr,$tok_idx);
|
||||
|
||||
} elseif (strstr($match_mod,'K')) {
|
||||
preg_match_all('/([0-9]+)/',trim($match_subst),$substrarray);
|
||||
if (isset($substrarray[1][0])) {
|
||||
$tok_idx = $substrarray[1][0];
|
||||
} else {
|
||||
$tok_idx = '0';
|
||||
}
|
||||
|
||||
if ($match_delim == '') {
|
||||
$delimiter = ' ';
|
||||
} else {
|
||||
$delimiter = preg_quote($match_delim);
|
||||
}
|
||||
$attribute->js['autoFill'] .= sprintf(" %s = %s.split('%s')[%s];\n",$match_attr,$match_attr,$delimiter,$tok_idx);
|
||||
|
||||
} else {
|
||||
preg_match_all('/([0-9]*)-([0-9]*)/',trim($match_subst),$substrarray);
|
||||
if ((isset($substrarray[1][0]) && $substrarray[1][0]) || (isset($substrarray[2][0]) && $substrarray[2][0])) {
|
||||
$attribute->js['autoFill'] .= sprintf(" %s = %s.substr(%s,%s);\n",
|
||||
$match_attr,$match_attr,
|
||||
$substrarray[1][0] ? $substrarray[1][0] : '0',
|
||||
$substrarray[2][0] ? $substrarray[2][0] : sprintf('%s.length',$match_attr));
|
||||
}
|
||||
}
|
||||
|
||||
if (strstr($match_mod,'l')) {
|
||||
$attribute->js['autoFill'] .= sprintf(" %s = %s.toLowerCase();\n",$match_attr,$match_attr);
|
||||
}
|
||||
if (strstr($match_mod,'U')) {
|
||||
$attribute->js['autoFill'] .= sprintf(" %s = %s.toUpperCase();\n",$match_attr,$match_attr);
|
||||
}
|
||||
if (strstr($match_mod,'A')) {
|
||||
$attribute->js['autoFill'] .= sprintf(" %s = toAscii(%s);\n",$match_attr,$match_attr);
|
||||
}
|
||||
|
||||
# Matchfor only entry without modifiers.
|
||||
$formula = preg_replace('/^%('.$match_attr.')%$/U','$1 + \'\'',$formula);
|
||||
# Matchfor only entry with modifiers.
|
||||
$formula = preg_replace('/^%('.$match_attr.')(\|[0-9]*-[0-9]*)?(\/[KklTUA]+)?(?:\|(.))?%$/U','$1 + \'\'',$formula);
|
||||
# Matchfor begining entry.
|
||||
$formula = preg_replace('/^%('.$match_attr.')(\|[0-9]*-[0-9]*)?(\/[KklTUA]+)?(?:\|(.))?%/U','$1 + \'',$formula);
|
||||
# Matchfor ending entry.
|
||||
$formula = preg_replace('/%('.$match_attr.')(\|[0-9]*-[0-9]*)?(\/[KklTUA]+)?(?:\|(.))?%$/U','\' + $1 ',$formula);
|
||||
# Match for entries not at begin/end.
|
||||
$formula = preg_replace('/%('.$match_attr.')(\|[0-9]*-[0-9]*)?(\/[KklTUA]+)?(?:\|(.))?%/U','\' + $1 + \'',$formula);
|
||||
$attribute->js['autoFill'] .= "\n";
|
||||
}
|
||||
|
||||
$attribute->js['autoFill'] .= sprintf(" fillRec(pre+'%s'+suf, %s); // %s\n",strtolower($attr),$formula,$string);
|
||||
$attribute->js['autoFill'] .= "\n";
|
||||
}
|
||||
}
|
@ -12,6 +12,8 @@ use App\Classes\LDAP\Server;
|
||||
|
||||
class AjaxController extends Controller
|
||||
{
|
||||
private const LOGKEY = 'CAc';
|
||||
|
||||
/**
|
||||
* Get the LDAP server BASE DNs
|
||||
*
|
||||
@ -27,7 +29,7 @@ class AjaxController extends Controller
|
||||
'lazy'=>TRUE,
|
||||
'icon'=>'fa-fw fas fa-sitemap',
|
||||
'tooltip'=>$item->getDn(),
|
||||
]);
|
||||
])->values();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -42,7 +44,7 @@ class AjaxController extends Controller
|
||||
if (str_starts_with($dn,'*') && ($x=strpos($dn,'|')))
|
||||
$dn = substr($dn,$x+1);
|
||||
|
||||
Log::debug(sprintf('%s: Query [%s]',__METHOD__,$dn));
|
||||
Log::debug(sprintf('%s:Query [%s]',self::LOGKEY,$dn));
|
||||
|
||||
return (config('server'))
|
||||
->children($dn)
|
||||
|
@ -8,7 +8,9 @@ use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Exceptions\InvalidUsage;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Ldap\Entry;
|
||||
|
||||
class LoginController extends Controller
|
||||
{
|
||||
@ -51,6 +53,30 @@ class LoginController extends Controller
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* When attempt to login
|
||||
*
|
||||
* @param Request $request
|
||||
* @return void
|
||||
* @throws InvalidUsage
|
||||
*/
|
||||
public function attemptLogin(Request $request)
|
||||
{
|
||||
$attempt = $this->guard()->attempt(
|
||||
$this->credentials($request), $request->boolean('remember')
|
||||
);
|
||||
|
||||
// If the login failed, and PLA is set to use DN login, check if the entry exists.
|
||||
// If the entry doesnt exist, it might be the root DN, which cannot be used to login
|
||||
if ((! $attempt) && $request->dn && config('pla.login.alert_rootdn',TRUE)) {
|
||||
$dn = config('server')->fetch($request->dn);
|
||||
$o = new Entry;
|
||||
|
||||
if (! $dn && $o->getConnection()->getLdapConnection()->errNo() === 32)
|
||||
abort(501,'Authentication set to DN, but the DN doesnt exist');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We need to delete our encrypted username/password cookies
|
||||
*
|
||||
|
@ -26,6 +26,8 @@ use App\Ldap\Entry;
|
||||
|
||||
class HomeController extends Controller
|
||||
{
|
||||
private const LOGKEY = 'CHc';
|
||||
|
||||
/**
|
||||
* Create a new object in the LDAP server
|
||||
*
|
||||
@ -58,9 +60,13 @@ class HomeController extends Controller
|
||||
$template = $o->template($request->validated('template'));
|
||||
$o->objectclass = [Entry::TAG_NOTAG=>$template->objectclasses->toArray()];
|
||||
|
||||
foreach ($o->getAvailableAttributes()->filter(fn($item)=>$item->names_lc->intersect($template->attributes)->count()) as $ao)
|
||||
foreach ($o->getAvailableAttributes()
|
||||
->filter(fn($item)=>$item->names_lc->intersect($template->attributes->map('strtolower'))->count())
|
||||
->sortBy(fn($item)=>Arr::get($template->order,$item->name)) as $ao)
|
||||
{
|
||||
$o->{$ao->name} = [Entry::TAG_NOTAG=>''];
|
||||
}
|
||||
}
|
||||
|
||||
$step = $request->step ? $request->step+1 : old('step');
|
||||
|
||||
|
@ -10,10 +10,12 @@ use Illuminate\Support\Facades\Log;
|
||||
|
||||
class AcceptLanguage
|
||||
{
|
||||
private const LOGKEY = 'MAL';
|
||||
|
||||
public function handle(Request $request,Closure $next): mixed
|
||||
{
|
||||
if ($locale=$this->parseHttpLocale($request)) {
|
||||
Log::debug(sprintf('Accept Language changed from [%s] to [%s] from Browser (%s)',app()->getLocale(),$locale,$request->header('Accept-Language')));
|
||||
Log::debug(sprintf('%s:Accept Language changed from [%s] to [%s] from Browser (%s)',self::LOGKEY,app()->getLocale(),$locale,$request->header('Accept-Language')));
|
||||
|
||||
app()->setLocale($locale);
|
||||
}
|
||||
|
@ -159,8 +159,11 @@ class Entry extends Model
|
||||
if ($this->dn && (! in_array(strtolower($this->dn),['cn=subschema']))) {
|
||||
$this->templates = $this->templates
|
||||
->filter(fn($item)=>$item->enabled
|
||||
&& (! count($item->objectclasses->diff(array_map('strtolower',Arr::get($this->attributes,'objectclass'))))))
|
||||
->sortBy(fn($item)=>$item);
|
||||
&& (! $item->objectclasses
|
||||
->map('strtolower')
|
||||
->diff(array_map('strtolower',Arr::get($this->attributes,'objectclass')))
|
||||
->count()))
|
||||
->sortBy(fn($item)=>$item->title);
|
||||
}
|
||||
|
||||
return $this;
|
||||
@ -208,7 +211,7 @@ class Entry extends Model
|
||||
$o = $this->objects->get($attribute) ?: Attribute\Factory::create($this->dn ?: '',$attribute,[]);
|
||||
$o->addValue($tag,[$value]);
|
||||
|
||||
$this->objects->put($attribute,$o);
|
||||
$this->objects->put($key,$o);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -6,6 +6,7 @@ use Illuminate\Contracts\View\View;
|
||||
use Illuminate\View\Component;
|
||||
|
||||
use App\Classes\LDAP\Attribute as LDAPAttribute;
|
||||
use App\Classes\Template;
|
||||
|
||||
class Attribute extends Component
|
||||
{
|
||||
@ -14,11 +15,12 @@ class Attribute extends Component
|
||||
public bool $new;
|
||||
public bool $old;
|
||||
public bool $updated;
|
||||
public ?Template $template;
|
||||
|
||||
/**
|
||||
* Create a new component instance.
|
||||
*/
|
||||
public function __construct(?LDAPAttribute $o,bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE,string $template=NULL)
|
||||
public function __construct(?LDAPAttribute $o,bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE,?Template $template=NULL)
|
||||
{
|
||||
$this->o = $o;
|
||||
$this->edit = $edit;
|
||||
@ -37,7 +39,12 @@ class Attribute extends Component
|
||||
{
|
||||
return $this->o
|
||||
? $this->o
|
||||
->render(edit: $this->edit,old: $this->old,new: $this->new,template: $this->template,updated: $this->updated)
|
||||
->render(
|
||||
edit: $this->edit,
|
||||
old: $this->old,
|
||||
new: $this->new,
|
||||
updated: $this->updated,
|
||||
template: $this->template)
|
||||
: __('Unknown');
|
||||
}
|
||||
}
|
@ -43,19 +43,6 @@ return [
|
||||
|
||||
'debug' => (bool) env('APP_DEBUG', false),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application URL
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This URL is used by the console to properly generate URLs when using
|
||||
| the Artisan command line tool. You should set this to the root of
|
||||
| the application so that it's available within Artisan commands.
|
||||
|
|
||||
*/
|
||||
|
||||
'url' => env('APP_URL', 'http://localhost'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application Timezone
|
||||
|
@ -35,7 +35,6 @@ return [
|
||||
'username' => env('LDAP_USERNAME', 'cn=user,dc=local,dc=com'),
|
||||
'password' => env('LDAP_PASSWORD', 'secret'),
|
||||
'port' => env('LDAP_PORT', 389),
|
||||
'base_dn' => env('LDAP_BASE_DN', 'dc=local,dc=com'),
|
||||
'timeout' => env('LDAP_TIMEOUT', 5),
|
||||
'use_ssl' => env('LDAP_SSL', false),
|
||||
'use_tls' => env('LDAP_TLS', false),
|
||||
@ -47,7 +46,6 @@ return [
|
||||
'username' => env('LDAP_USERNAME', 'cn=user,dc=local,dc=com'),
|
||||
'password' => env('LDAP_PASSWORD', 'secret'),
|
||||
'port' => env('LDAP_PORT', 636),
|
||||
'base_dn' => env('LDAP_BASE_DN', 'dc=local,dc=com'),
|
||||
'timeout' => env('LDAP_TIMEOUT', 5),
|
||||
'use_ssl' => env('LDAP_SSL', true),
|
||||
'use_tls' => env('LDAP_TLS', false),
|
||||
@ -59,7 +57,6 @@ return [
|
||||
'username' => env('LDAP_USERNAME', 'cn=user,dc=local,dc=com'),
|
||||
'password' => env('LDAP_PASSWORD', 'secret'),
|
||||
'port' => env('LDAP_PORT', 389),
|
||||
'base_dn' => env('LDAP_BASE_DN', 'dc=local,dc=com'),
|
||||
'timeout' => env('LDAP_TIMEOUT', 5),
|
||||
'use_ssl' => env('LDAP_SSL', false),
|
||||
'use_tls' => env('LDAP_TLS', true),
|
||||
@ -72,7 +69,6 @@ return [
|
||||
'username' => 'cn=Directory Manager',
|
||||
'password' => 'password',
|
||||
'port' => 1389,
|
||||
'base_dn' => 'dc=example,dc=com',
|
||||
'timeout' => env('LDAP_TIMEOUT', 5),
|
||||
'use_ssl' => env('LDAP_SSL', false),
|
||||
'use_tls' => env('LDAP_TLS', false),
|
||||
|
@ -43,6 +43,17 @@ return [
|
||||
|
||||
'allow_guest' => env('LDAP_ALLOW_GUEST',FALSE),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Base DNs
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Normally PLA will get the base DNs from the rootDSE's namingcontexts
|
||||
| entry. Instead of using that, you can define your own base DNs to use.
|
||||
|
|
||||
*/
|
||||
'base_dns' => ($x=env('LDAP_BASE_DN', NULL)) ? explode(',',$x) : NULL,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Custom Date Format
|
||||
@ -73,8 +84,12 @@ return [
|
||||
* setup.
|
||||
*/
|
||||
'login' => [
|
||||
'attr' => [env('LDAP_LOGIN_ATTR','uid') => env('LDAP_LOGIN_ATTR_DESC','User ID')], // Attribute used to find user for login
|
||||
'objectclass' => explode(',',env('LDAP_LOGIN_OBJECTCLASS', 'posixAccount')), // Objectclass that users must contain to login
|
||||
// Attribute used to find user for login
|
||||
'attr' => [strtolower(env('LDAP_LOGIN_ATTR','uid')) => env('LDAP_LOGIN_ATTR_DESC','User ID')],
|
||||
// Objectclass that users must contain to login
|
||||
'objectclass' => explode(',',env('LDAP_LOGIN_OBJECTCLASS', 'posixAccount')),
|
||||
// Alert if DN is being used, and the login fails, and the the DN doesnt exist
|
||||
'alert_rootdn' => env('LDAP_ALERT_ROOTDN',TRUE) && strtolower(env('LDAP_LOGIN_ATTR','uid')) === 'dn',
|
||||
],
|
||||
|
||||
'template' => [
|
||||
|
@ -37,10 +37,10 @@ function getNode(item) {
|
||||
$('.main-content').empty().append(e.responseText);
|
||||
break;
|
||||
case 409: // Not in root
|
||||
location.replace('/#'+item);
|
||||
break;
|
||||
case 419: // Session Expired
|
||||
location.replace('/#'+item);
|
||||
// When the session expires, and we are in the tree, we need to force a reload
|
||||
if (location.pathname === '/')
|
||||
location.reload();
|
||||
break;
|
||||
case 500:
|
||||
|
@ -169,6 +169,9 @@
|
||||
$('button[id^="link-"]').on('click',function(item) {
|
||||
var content;
|
||||
|
||||
// Remove our fancy-tree highlight, since we are rendering the frame
|
||||
$('.fancytree-node.fancytree-active').removeClass('fancytree-active');
|
||||
|
||||
$.ajax({
|
||||
url: $(this).data('link'),
|
||||
method: 'GET',
|
||||
|
@ -3,8 +3,8 @@
|
||||
@foreach($o->langtags as $langtag)
|
||||
@foreach(($o->tagValues($langtag)->count() ? $o->tagValues($langtag) : [$langtag => NULL]) as $key => $value)
|
||||
@if($edit)
|
||||
<div class="input-group has-validation mb-3">
|
||||
<x-form.select id="userpassword_hash_{{$loop->index}}{{$template ?? ''}}" name="userpassword_hash[{{ $langtag }}][]" :value="$o->hash($new ? '' : ($value ?? ''))->id()" :options="$helpers" allowclear="false" :disabled="! $new"/>
|
||||
<div class="input-group has-validation">
|
||||
<x-form.select id="userpassword_hash_{{$loop->index}}{{$template?->name ?? ''}}" name="userpassword_hash[{{ $langtag }}][]" :value="$o->hash($new ? '' : ($value ?? ''))->id()" :options="$helpers" allowclear="false" :disabled="! $new"/>
|
||||
<input type="password" @class(['form-control','is-invalid'=>($e=$errors->get($o->name_lc.'.'.$langtag.'.'.$loop->index)),'mb-1','border-focus'=>! $o->tagValuesOld($langtag)->contains($value),'bg-success-subtle'=>$updated]) name="{{ $o->name_lc }}[{{ $langtag }}][]" value="{{ Arr::get(old($o->name_lc),$langtag.'.'.$loop->index,$value ? md5($value) : '') }}" @readonly(! $new)>
|
||||
|
||||
<div class="invalid-feedback pb-2">
|
||||
@ -20,9 +20,9 @@
|
||||
@endforeach
|
||||
</x-attribute.layout>
|
||||
|
||||
@if($edit)
|
||||
@if($edit && $o->tagValuesOld($langtag)->dot()->filter()->count())
|
||||
<div class="row">
|
||||
<div class="offset-1 col-4 p-2">
|
||||
<div class="offset-1 col-4">
|
||||
<span class="p-0 m-0">
|
||||
<button id="entry-userpassword-check" type="button" class="btn btn-sm btn-outline-dark mt-3" data-bs-toggle="modal" data-bs-target="#page-modal"><i class="fas fa-user-check"></i> @lang('Check Password')</button>
|
||||
</span>
|
||||
|
33
resources/views/errors/501.blade.php
Normal file
33
resources/views/errors/501.blade.php
Normal file
@ -0,0 +1,33 @@
|
||||
@extends('architect::layouts.error')
|
||||
|
||||
@section('error')
|
||||
501: @lang('LDAP Authentication Error')
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<table class="table table-sm table-borderless table-condensed">
|
||||
<tr>
|
||||
<th>@lang('Error')</th>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="2">{{ $exception->getMessage() }}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th>@lang('Possible Causes')</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<ul class="ps-3">
|
||||
<li>The DN you used to login actually doesnt exist in the server (DN's must exist in order to login)</li>
|
||||
<li>You are attempting to use the <strong>rootdn</strong> to login (not supported)</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p>To suppress this message, set <strong>LDAP_ALERT_ROOTDN</strong> to <strong>FALSE</strong> before starting PLA.</p>
|
||||
<p>Back to <a href="{{ url('login') }}">login</a>?</p>
|
||||
|
||||
@endsection
|
@ -8,8 +8,8 @@
|
||||
<div class="tab-content">
|
||||
@php($up=(session()->pull('updated') ?: collect()))
|
||||
|
||||
@foreach($o->getVisibleAttributes()->filter(fn($item)=>$template->attributes->contains($item->name_lc)) as $ao)
|
||||
<x-attribute-type :o="$ao" :edit="TRUE" :new="FALSE" :template="$template->name" :updated="$up->contains($ao->name_lc)"/>
|
||||
@foreach($o->getVisibleAttributes()->filter(fn($item)=>$template->attributes->map('strtolower')->contains($item->name_lc)) as $ao)
|
||||
<x-attribute-type :o="$ao" :edit="TRUE" :new="FALSE" :template="$template" :updated="$up->contains($ao->name_lc)"/>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
|
@ -66,7 +66,7 @@
|
||||
<x-attribute-type :o="$o->getObject('rdn')" :edit="TRUE" :new="FALSE" :updated="FALSE"/>
|
||||
|
||||
@foreach($o->getVisibleAttributes() as $ao)
|
||||
<x-attribute-type :o="$ao" :edit="TRUE" :new="FALSE" :updated="FALSE"/>
|
||||
<x-attribute-type :o="$ao" :edit="TRUE" :new="FALSE" :template="$template" :updated="FALSE"/>
|
||||
@endforeach
|
||||
|
||||
@if(! $template)
|
||||
@ -91,7 +91,6 @@
|
||||
@endsection
|
||||
|
||||
@section('page-scripts')
|
||||
|
||||
<script type="text/javascript">
|
||||
var rdn_attr;
|
||||
|
||||
|
@ -75,8 +75,8 @@
|
||||
<div class="d-flex justify-content-center">
|
||||
<div role="group" class="btn-group btn-group-sm nav pb-3">
|
||||
<!-- If we have templates that cover this entry -->
|
||||
@foreach($o->templates as $template => $name)
|
||||
<span data-bs-toggle="tab" href="#template-{{$template}}" @class(['btn','btn-outline-focus','active'=>$loop->index === 0])><i class="fa fa-fw pe-2 {{ $o->template($template)->icon }}"></i> {{ $name }}</span>
|
||||
@foreach($o->templates as $template)
|
||||
<span data-bs-toggle="tab" href="#template-{{ $template->name }}" @class(['btn','btn-outline-focus','active'=>$loop->index === 0])><i class="fa fa-fw pe-2 {{ $template->icon }}"></i> {{ $template->title }}</span>
|
||||
@endforeach
|
||||
@if($o->templates->count())
|
||||
<span data-bs-toggle="tab" href="#template-default" @class(['btn','btn-outline-focus','p-1','active'=>(! $o->templates->count())])>{{ __('LDAP Entry') }}</span>
|
||||
@ -85,9 +85,9 @@
|
||||
</div>
|
||||
|
||||
<div class="tab-content">
|
||||
@foreach($o->templates as $template => $name)
|
||||
<div @class(['tab-pane','active'=>$loop->index === 0]) id="template-{{$template}}" role="tabpanel">
|
||||
@include('fragment.template.dn',['template'=>$o->template($template)])
|
||||
@foreach($o->templates as $template)
|
||||
<div @class(['tab-pane','active'=>$loop->index === 0]) id="template-{{ $template->name }}" role="tabpanel">
|
||||
@include('fragment.template.dn',['template'=>$template])
|
||||
</div>
|
||||
@endforeach
|
||||
|
||||
|
@ -19,7 +19,23 @@
|
||||
"attribute2": {
|
||||
"display": "Attribute 2",
|
||||
"hint": "This is an example",
|
||||
"type": "input", // Default is input
|
||||
"order": 2
|
||||
},
|
||||
"attribute3": {
|
||||
"display": "Attribute 3",
|
||||
"type": "select",
|
||||
"options": {
|
||||
"/bin/bash": "Bash",
|
||||
"/bin/csh": "C Shell",
|
||||
"/bin/dash": "Dash",
|
||||
"/bin/sh": "Shell",
|
||||
"/bin/tsh": "Turbo C Shell",
|
||||
"/bin/zsh": "ZSH",
|
||||
"/bin/false": "False",
|
||||
"/usr/sbin/nologin": "No Login"
|
||||
},
|
||||
"order": 8
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -66,7 +66,8 @@
|
||||
},
|
||||
"loginShell": {
|
||||
"display": "Login Shell",
|
||||
"select": {
|
||||
"type": "select",
|
||||
"options": {
|
||||
"/bin/bash": "Bash",
|
||||
"/bin/csh": "C Shell",
|
||||
"/bin/dash": "Dash",
|
||||
|
Loading…
x
Reference in New Issue
Block a user