Compare commits
10 Commits
673f070cb7
...
82220fe17f
Author | SHA1 | Date | |
---|---|---|---|
82220fe17f | |||
7322a13c0c | |||
2ad0ddd764 | |||
db7a2468f6 | |||
2f8d120ce8 | |||
16452ebfa9 | |||
4dfebe9053 | |||
05012c9e6c | |||
3d40288506 | |||
6a461d320a |
@ -5,27 +5,31 @@ namespace App\Classes\LDAP\Attribute;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
use App\Classes\LDAP\{Attribute,Server};
|
||||
use App\Classes\LDAP\Attribute;
|
||||
|
||||
/**
|
||||
* Represents an ObjectClass Attribute
|
||||
*/
|
||||
final class ObjectClass extends Attribute
|
||||
{
|
||||
// Which of the values is the structural object class
|
||||
protected Collection $structural;
|
||||
// The schema ObjectClasses for this objectclass of a DN
|
||||
protected Collection $oc_schema;
|
||||
|
||||
public function __construct(string $name,array $values)
|
||||
{
|
||||
parent::__construct($name,$values);
|
||||
|
||||
$this->structural = collect();
|
||||
$this->oc_schema = config('server')
|
||||
->schema('objectclasses')
|
||||
->filter(fn($item)=>$this->values->contains($item->name));
|
||||
}
|
||||
|
||||
// Determine which of the values is the structural objectclass
|
||||
foreach ($values as $oc) {
|
||||
if ((new Server)->schema('objectclasses',$oc)->isStructural())
|
||||
$this->structural->push($oc);
|
||||
}
|
||||
public function __get(string $key): mixed
|
||||
{
|
||||
return match ($key) {
|
||||
'structural' => $this->oc_schema->filter(fn($item) => $item->isStructural()),
|
||||
default => parent::__get($key),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@ -36,7 +40,9 @@ final class ObjectClass extends Attribute
|
||||
*/
|
||||
public function isStructural(string $value): bool
|
||||
{
|
||||
return $this->structural->contains($value);
|
||||
return $this->structural
|
||||
->map(fn($item)=>$item->name)
|
||||
->contains($value);
|
||||
}
|
||||
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE): View
|
||||
|
@ -334,10 +334,10 @@ final class AttributeType extends Base {
|
||||
*
|
||||
* @param string $name The name of the objectClass to add.
|
||||
*/
|
||||
public function addUsedInObjectClass(string $name): void
|
||||
public function addUsedInObjectClass(string $name,bool $structural): void
|
||||
{
|
||||
if (! $this->used_in_object_classes->contains($name))
|
||||
$this->used_in_object_classes->push($name);
|
||||
if (! $this->used_in_object_classes->has($name))
|
||||
$this->used_in_object_classes->put($name,$structural);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
namespace App\Classes\LDAP\Schema;
|
||||
|
||||
use Config;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
@ -410,7 +409,7 @@ final class ObjectClass extends Base
|
||||
$result = collect();
|
||||
|
||||
foreach ($this->sup_classes as $object_class) {
|
||||
$oc = Config::get('server')
|
||||
$oc = config('server')
|
||||
->schema('objectclasses',$object_class);
|
||||
|
||||
if ($oc) {
|
||||
@ -443,6 +442,16 @@ final class ObjectClass extends Base
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if this objectclass is auxiliary
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isAuxiliary(): bool
|
||||
{
|
||||
return $this->type === Server::OC_AUXILIARY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if an array is listed in the may_force attrs
|
||||
*/
|
||||
|
@ -59,14 +59,14 @@ final class Server
|
||||
* Gets the root DN of the specified LDAPServer, or throws an exception if it
|
||||
* can't find it.
|
||||
*
|
||||
* @param null $connection Return a collection of baseDNs
|
||||
* @param string|null $connection Return a collection of baseDNs
|
||||
* @param bool $objects Return a collection of Entry Models
|
||||
* @return Collection
|
||||
* @throws ObjectNotFoundException
|
||||
* @testedin GetBaseDNTest::testBaseDNExists();
|
||||
* @todo Need to allow for the scenario if the baseDN is not readable by ACLs
|
||||
*/
|
||||
public static function baseDNs(string $connection='default',bool $objects=TRUE): Collection
|
||||
public static function baseDNs(string $connection=NULL,bool $objects=TRUE): Collection
|
||||
{
|
||||
$cachetime = Carbon::now()
|
||||
->addSeconds(Config::get('ldap.cache.time'));
|
||||
@ -360,9 +360,13 @@ final class Server
|
||||
}
|
||||
|
||||
// Try to get the schema DN from the specified entry.
|
||||
$schema_dn = $this->schemaDN('default');
|
||||
$schema_dn = $this->schemaDN($this->connection);
|
||||
$schema = $this->fetch($schema_dn);
|
||||
|
||||
// If our schema's null, we didnt find it.
|
||||
if (! $schema)
|
||||
throw new Exception('Couldnt find schema at:'.$schema_dn);
|
||||
|
||||
switch ($item) {
|
||||
case 'attributetypes':
|
||||
Log::debug('Attribute Types');
|
||||
@ -442,7 +446,7 @@ final class Server
|
||||
// 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);
|
||||
$this->attributetypes[strtolower($attr_name)]->addUsedInObjectClass($object_class->name,$object_class->isStructural());
|
||||
|
||||
// Add Required By.
|
||||
foreach ($must_attrs as $attr_name)
|
||||
|
@ -68,6 +68,28 @@ class HomeController extends Controller
|
||||
->with('page_actions',$page_actions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a new attribute view
|
||||
*
|
||||
* @param Request $request
|
||||
* @param string $id
|
||||
* @return \Closure|\Illuminate\Contracts\View\View|string
|
||||
*/
|
||||
public function entry_attr_new(Request $request,string $id)
|
||||
{
|
||||
$xx = new \stdClass();
|
||||
$xx->index = 0;
|
||||
|
||||
$x = $request->noheader
|
||||
? (string)view(sprintf('components.attribute.widget.%s',$id))
|
||||
->with('o',new Attribute($id,[]))
|
||||
->with('value',$request->value)
|
||||
->with('loop',$xx)
|
||||
: (new AttributeType(new Attribute($id,[]),TRUE))->render();
|
||||
|
||||
return $x;
|
||||
}
|
||||
|
||||
public function entry_export(Request $request,string $id)
|
||||
{
|
||||
$dn = Crypt::decryptString($id);
|
||||
@ -84,10 +106,33 @@ class HomeController extends Controller
|
||||
->with('result',new LDIFExport($result));
|
||||
}
|
||||
|
||||
public function entry_newattr(string $id)
|
||||
/**
|
||||
* Render an available list of objectclasses for an Entry
|
||||
*
|
||||
* @param string $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function entry_objectclass_add(string $id)
|
||||
{
|
||||
$x = new AttributeType(new Attribute($id,[]),TRUE);
|
||||
return $x->render();
|
||||
$dn = Crypt::decryptString($id);
|
||||
$o = config('server')->fetch($dn);
|
||||
|
||||
$ocs = $o->getObject('objectclass')
|
||||
->structural
|
||||
->map(fn($item)=>$item->getParents())
|
||||
->flatten()
|
||||
->merge(
|
||||
config('server')->schema('objectclasses')
|
||||
->filter(fn($item)=>$item->isAuxiliary())
|
||||
)
|
||||
->sortBy(fn($item)=>$item->name);
|
||||
|
||||
return $ocs->groupBy(fn($item)=>$item->isStructural())
|
||||
->map(fn($item,$key) =>
|
||||
[
|
||||
'text' => sprintf('%s Object Class',$key ? 'Structural' : 'Auxiliary'),
|
||||
'children' => $item->map(fn($item)=>['id'=>$item->name,'text'=>$item->name]),
|
||||
]);
|
||||
}
|
||||
|
||||
public function entry_password_check(Request $request)
|
||||
@ -126,20 +171,22 @@ class HomeController extends Controller
|
||||
$o->{$key} = array_filter($value,fn($item)=>! is_null($item));
|
||||
|
||||
// We need to process and encrypt the password
|
||||
$passwords = [];
|
||||
foreach ($request->userpassword as $key => $value) {
|
||||
// If the password is still the MD5 of the old password, then it hasnt changed
|
||||
if (($old=Arr::get($o->userpassword,$key)) && ($value === md5($old))) {
|
||||
array_push($passwords,$old);
|
||||
continue;
|
||||
}
|
||||
if ($request->userpassword) {
|
||||
$passwords = [];
|
||||
foreach ($request->userpassword as $key => $value) {
|
||||
// If the password is still the MD5 of the old password, then it hasnt changed
|
||||
if (($old=Arr::get($o->userpassword,$key)) && ($value === md5($old))) {
|
||||
array_push($passwords,$old);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($value) {
|
||||
$type = Arr::get($request->userpassword_hash,$key);
|
||||
array_push($passwords,Attribute\Password::hash_id($type)->encode($value));
|
||||
if ($value) {
|
||||
$type = Arr::get($request->userpassword_hash,$key);
|
||||
array_push($passwords,Attribute\Password::hash_id($type)->encode($value));
|
||||
}
|
||||
}
|
||||
$o->userpassword = $passwords;
|
||||
}
|
||||
$o->userpassword = $passwords;
|
||||
|
||||
if (! $o->getDirty())
|
||||
return back()
|
||||
@ -294,10 +341,8 @@ class HomeController extends Controller
|
||||
*/
|
||||
public function schema_frame(Request $request)
|
||||
{
|
||||
$s = config('server');
|
||||
|
||||
// If an invalid key, we'll 404
|
||||
if ($request->type && $request->key && ($s->schema($request->type)->has($request->key) === FALSE))
|
||||
if ($request->type && $request->key && (! config('server')->schema($request->type)->has($request->key)))
|
||||
abort(404);
|
||||
|
||||
return view('frames.schema')
|
||||
|
@ -3,8 +3,8 @@
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Config;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
|
||||
use App\Classes\LDAP\Server;
|
||||
use App\Ldap\User;
|
||||
|
@ -3,10 +3,10 @@
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Config;
|
||||
use GuzzleHttp\Client;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class CheckUpdate
|
||||
|
@ -290,7 +290,7 @@ class Entry extends Model
|
||||
public function getMissingAttributes(): Collection
|
||||
{
|
||||
return $this->getAvailableAttributes()
|
||||
->diff($this->getVisibleAttributes());
|
||||
->filter(fn($a)=>(! $this->getVisibleAttributes()->contains(fn($b)=>($a->name === $b->name))));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -13,7 +13,7 @@ return [
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('LDAP_CONNECTION', 'default'),
|
||||
'default' => env('LDAP_CONNECTION', 'openldap'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
@ -28,7 +28,7 @@ return [
|
||||
|
||||
'connections' => [
|
||||
|
||||
'default' => [
|
||||
'openldap' => [
|
||||
'hosts' => [env('LDAP_HOST', '127.0.0.1')],
|
||||
'username' => env('LDAP_USERNAME', 'cn=user,dc=local,dc=com'),
|
||||
'password' => env('LDAP_PASSWORD', 'secret'),
|
||||
@ -40,6 +40,18 @@ return [
|
||||
'name' => env('LDAP_NAME','LDAP Server'),
|
||||
],
|
||||
|
||||
'opendj' => [
|
||||
'hosts' => ['opendj'],
|
||||
'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),
|
||||
'name' => 'OpenDJ Server',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|
5
public/css/fixes.css
vendored
5
public/css/fixes.css
vendored
@ -291,3 +291,8 @@ select2-container--bootstrap-5 .select2-selection--multiple .select2-selection__
|
||||
line-height: 1.0;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
.select2-container--bootstrap-5 .select2-dropdown .select2-results__options .select2-results__option[role=group] .select2-results__group {
|
||||
color: #212529;
|
||||
font-weight: 800;
|
||||
}
|
@ -57,7 +57,7 @@
|
||||
</div>
|
||||
@endif
|
||||
<div class="float-end">
|
||||
<button class="btn btn-primary btn-lg">Login</button>
|
||||
<button class="btn btn-lg btn-primary">Login</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
@ -30,7 +30,7 @@
|
||||
@if ((isset($page_actions) && $page_actions->contains('edit')) || old())
|
||||
<li class="nav-item">
|
||||
<span class="nav-link pt-0 pb-1">
|
||||
<button id="entry-edit" class="p-2 m-0 border-0 btn-transition btn btn-outline-dark w-100 text-start">
|
||||
<button id="entry-edit" class="p-2 m-0 border-0 btn btn-transition btn-outline-dark w-100 text-start">
|
||||
<i class="fas fa-fw fa-edit me-2"></i> @lang('Edit')
|
||||
</button>
|
||||
</span>
|
||||
@ -40,7 +40,7 @@
|
||||
@if (isset($page_actions) && $page_actions->contains('export'))
|
||||
<li class="nav-item">
|
||||
<a class="nav-link pt-0 pb-1">
|
||||
<button type="button" class="p-2 m-0 border-0 btn-transition btn btn-outline-dark w-100 text-start" data-bs-toggle="modal" data-bs-target="#entry-export-modal" {{--data-bs-whatever="ldif"--}}>
|
||||
<button type="button" class="p-2 m-0 border-0 btn btn-transition btn-outline-dark w-100 text-start" data-bs-toggle="modal" data-bs-target="#entry_export-modal">
|
||||
<i class="fas fa-fw fa-file-export me-2"></i> @lang('Export')
|
||||
</button>
|
||||
</a>
|
||||
@ -50,7 +50,7 @@
|
||||
@if (isset($page_actions) && $page_actions->contains('copy'))
|
||||
<li class="nav-item">
|
||||
<a class="nav-link pt-0 pb-1">
|
||||
<button class="p-2 m-0 border-0 btn-transition btn btn-outline-dark w-100 text-start">
|
||||
<button class="p-2 m-0 border-0 btn btn-transition btn-outline-dark w-100 text-start">
|
||||
<i class="fas fa-fw fa-truck-moving me-2"></i> @lang('Copy or Move')
|
||||
</button>
|
||||
</a>
|
||||
|
@ -22,7 +22,7 @@
|
||||
</div>
|
||||
<div class="app-header__menu">
|
||||
<span>
|
||||
<button type="button" class="btn-icon btn-icon-only btn btn-primary btn-sm mobile-toggle-header-nav">
|
||||
<button type="button" class="btn-icon btn-icon-only btn btn-sm btn-primary mobile-toggle-header-nav">
|
||||
<span class="btn-icon-wrapper">
|
||||
<i class="fas fa-ellipsis-v fa-w-6"></i>
|
||||
</span>
|
||||
|
@ -22,7 +22,7 @@
|
||||
</div>
|
||||
<div class="app-header__menu">
|
||||
<span>
|
||||
<button type="button" class="btn-icon btn-icon-only btn btn-primary btn-sm mobile-toggle-header-nav">
|
||||
<button type="button" class="btn-icon btn-icon-only btn btn-sm btn-primary mobile-toggle-header-nav">
|
||||
<span class="btn-icon-wrapper">
|
||||
<i class="fas fa-ellipsis-v fa-w-6"></i>
|
||||
</span>
|
||||
|
@ -2,14 +2,7 @@
|
||||
<x-attribute.layout :edit="$edit" :new="$new" :o="$o">
|
||||
@foreach (old($o->name_lc,$o->values) as $value)
|
||||
@if ($edit && ($value === NULL || (! $o->isStructural($value))))
|
||||
<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(true)>
|
||||
<div class="invalid-feedback pb-2">
|
||||
@if($e)
|
||||
{{ join('|',$e) }}
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
<x-attribute.widget.objectclass :o="$o" :edit="$edit" :new="$new" :loop="$loop" :value="$value"/>
|
||||
@else
|
||||
{{ $value }}
|
||||
@if ($o->isStructural($value))
|
||||
|
@ -22,7 +22,7 @@
|
||||
<div class="row">
|
||||
<div class="offset-1 col-4 p-2">
|
||||
<span class="p-0 m-0">
|
||||
<button type="button" class="btn btn-transition btn-sm btn-outline-dark mt-3" data-bs-toggle="modal" data-bs-target="#userpassword-check-modal"><i class="fas fa-user-check"></i> @lang('Check Password')</button>
|
||||
<button type="button" class="btn btn-transition btn-sm btn-outline-dark mt-3" data-bs-toggle="modal" data-bs-target="#userpassword_check-modal"><i class="fas fa-user-check"></i> @lang('Check Password')</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -0,0 +1,19 @@
|
||||
<div class="input-group has-validation">
|
||||
<!-- @todo Have an "x" to remove the entry, we need an event to process the removal, removing any attribute values along the way -->
|
||||
<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="{{ Arr::get($o->values,$loop->index,'['.__('NEW').']') }}" @readonly(true)>
|
||||
<div class="invalid-feedback pb-2">
|
||||
@if($e)
|
||||
{{ join('|',$e) }}
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
<span class="input-group-delete"><i class="fas fa-fw fa-xmark"></i></span>
|
||||
|
||||
<style>
|
||||
.input-group-delete {
|
||||
float: right;
|
||||
position: relative;
|
||||
top: -32px;
|
||||
right: 10px;
|
||||
}
|
||||
</style>
|
@ -1,22 +1,138 @@
|
||||
@php($clone=FALSE)
|
||||
@if($o->is_rdn)
|
||||
<span class="btn btn-sm btn-outline-focus mt-3"><i class="fas fa-fw fa-exchange"></i> @lang('Rename')</span>
|
||||
@elseif($edit && $o->can_addvalues)
|
||||
<span class="p-0 m-0">
|
||||
<span @class(['btn','btn-sm','btn-outline-primary','mt-3','addable','d-none'=>(! $new)]) id="{{ $o->name_lc }}"><i class="fas fa-fw fa-plus"></i> @lang('Add Value')</span>
|
||||
@switch(get_class($o))
|
||||
@case('App\Classes\LDAP\Attribute\Binary\JpegPhoto')
|
||||
<span @class(['btn','btn-sm','btn-outline-primary','mt-3','addable','d-none'=>(! $new)]) id="{{ $o->name_lc }}"><i class="fas fa-fw fa-plus"></i> @lang('Upload JpegPhoto')</span>
|
||||
|
||||
@break
|
||||
|
||||
@case('App\Classes\LDAP\Attribute\ObjectClass')
|
||||
<button type="button" @class(['btn','btn-sm','btn-outline-primary','mt-3','addable','d-none'=>(! $new)]) data-bs-toggle="modal" data-bs-target="#new_objectclass-modal"><i class="fas fa-fw fa-plus"></i> @lang('Add Objectclass')</button>
|
||||
|
||||
<!-- NEW OBJECT CLASS -->
|
||||
<div class="modal fade" id="new_objectclass-modal" tabindex="-1" aria-labelledby="new_objectclass-label" aria-hidden="true" data-bs-backdrop="static">
|
||||
<div class="modal-dialog modal-lg modal-fullscreen-lg-down">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h1 class="modal-title fs-5" id="new_objectclass-label">New Object Class</h1>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<x-form.select id="newoc" label="Select from..."/>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-sm btn-primary" data-bs-dismiss="modal">Next</button>
|
||||
{{--
|
||||
<button type="button" class="btn btn-sm btn-primary" data-bs-dismiss="modal"><i class="fas fa-fw fa-spinner fa-spin d-none"></i> Next</button>
|
||||
--}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@section('page-scripts')
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
var added_oc = []; // Object classes being added to this entry
|
||||
|
||||
// Show our ObjectClass modal so that we can add more objectclasses
|
||||
$('#new_objectclass-modal').on('shown.bs.modal',function() {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
success: function(data) {
|
||||
$('select#newoc').select2({
|
||||
dropdownParent: $('#new_objectclass-modal'),
|
||||
theme: 'bootstrap-5',
|
||||
allowClear: true,
|
||||
multiple: true,
|
||||
data: data,
|
||||
});
|
||||
},
|
||||
error: function(e) {
|
||||
if (e.status != 412)
|
||||
alert('That didnt work? Please try again....');
|
||||
},
|
||||
url: '{{ url('entry/objectclass/add') }}/'+dn,
|
||||
cache: false
|
||||
});
|
||||
})
|
||||
|
||||
// When the ObjectClass modal is closed, process what was selected
|
||||
$('#new_objectclass-modal').on('hide.bs.modal',function() {
|
||||
var c = {{ $o->values->count() }}; // @todo do we need this?
|
||||
var newadded = $('select#newoc').val();
|
||||
|
||||
// If nothing selected, we dont have anything to do
|
||||
if (! newadded.length)
|
||||
return;
|
||||
|
||||
// Find out what was selected, and add them
|
||||
newadded.forEach(function (item) {
|
||||
if (added_oc.indexOf(item) !== -1)
|
||||
return;
|
||||
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
beforeSend: function() {},
|
||||
success: function(data) {
|
||||
console.log(data);
|
||||
$('#{{ $o->name_lc }}').append(data);
|
||||
console.log('set to:'+item);
|
||||
},
|
||||
error: function(e) {
|
||||
if (e.status != 412)
|
||||
alert('That didnt work? Please try again....');
|
||||
},
|
||||
url: '{{ url('entry/attr/add',[$o->name_lc]) }}',
|
||||
data: {noheader: true,value: item,loop: c++}, // @todo can we omit loop and c
|
||||
cache: false
|
||||
});
|
||||
|
||||
// @todo add any required attributes that are defined required as a result of adding this OC
|
||||
// @todo Add attributes to "Add new Attribute" that are now available
|
||||
});
|
||||
|
||||
// Loop through added_oc, and remove anything not in newadded
|
||||
added_oc.forEach(function(item) {
|
||||
if (newadded.indexOf(item) === -1) {
|
||||
$('input[value="'+item+'"]').parent().empty();
|
||||
|
||||
// @todo remove any required attributes that are no longer defined as a result of removing this OC
|
||||
// @todo Remove attributes from "Add new Attribute" that are no longer available
|
||||
}
|
||||
});
|
||||
|
||||
added_oc = newadded;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@append
|
||||
@break
|
||||
|
||||
@case('App\Classes\LDAP\Attribute')
|
||||
@default
|
||||
@php($clone=TRUE)
|
||||
<span @class(['btn','btn-sm','btn-outline-primary','mt-3','addable','d-none'=>(! $new)]) id="{{ $o->name_lc }}"><i class="fas fa-fw fa-plus"></i> @lang('Add Value')</span>
|
||||
|
||||
@section('page-scripts')
|
||||
@if($clone && $edit && $o->can_addvalues)
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
// Create a new entry when Add Value clicked
|
||||
$('#{{ $o->name_lc }}.addable').click(function (item) {
|
||||
var cln = $(this).parent().parent().find('input:last').parent().clone();
|
||||
cln.find('input:last').attr('value','').attr('placeholder', '[@lang('NEW')]');
|
||||
cln.appendTo('#' + item.currentTarget.id)
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endif
|
||||
@append
|
||||
@endswitch
|
||||
</span>
|
||||
@endif
|
||||
|
||||
@section('page-scripts')
|
||||
@if($edit && $o->can_addvalues)
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
// Create a new entry when Add Value clicked
|
||||
$('#{{ $o->name_lc }}.addable').click(function (item) {
|
||||
var cln = $(this).parent().parent().find('input:last').clone();
|
||||
cln.attr('value','').attr('placeholder', '[@lang('NEW')]');
|
||||
cln.appendTo('#' + item.currentTarget.id)
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endif
|
||||
@append
|
@ -3,7 +3,7 @@
|
||||
<input type="hidden" id="{{ $id ?? $name }}_disabled" name="{{ $name }}" value="" disabled>
|
||||
@endisset
|
||||
<select style="width: 80%" class="form-select @isset($name)@error((! empty($old)) ? $old : $name) is-invalid @enderror @endisset" id="{{ $id ?? $name }}" @isset($name)name="{{ $name }}"@endisset @required(isset($required) && $required) @disabled(isset($disabled) && $disabled)>
|
||||
@if(empty($value) || isset($addnew) || isset($choose))
|
||||
@if((empty($value) && ! empty($options)) || isset($addnew) || isset($choose))
|
||||
<option value=""></option>
|
||||
@isset($addnew)
|
||||
<option value="new">{{ $addnew ?: 'Add New' }}</option>
|
||||
|
@ -90,16 +90,21 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td>@lang('Used by ObjectClasses')</td>
|
||||
<td><strong>
|
||||
<td>
|
||||
@if ($o->used_in_object_classes->count())
|
||||
@foreach ($o->used_in_object_classes as $class)
|
||||
@if ($loop->index)</strong> <strong>@endif
|
||||
@foreach ($o->used_in_object_classes as $class => $structural)
|
||||
@if($structural)
|
||||
<strong>
|
||||
@endif
|
||||
<a class="objectclass" id="{{ strtolower($class) }}" href="#{{ strtolower($class) }}">{{ $class }}</a>
|
||||
@if($structural)
|
||||
</strong>
|
||||
@endif
|
||||
@endforeach
|
||||
@else
|
||||
@lang('(none)')
|
||||
@endif
|
||||
</strong></td>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>@lang('Force as MAY by config')</td><td><strong>@lang($o->forced_as_may ? 'Yes' : 'No')</strong></td>
|
||||
|
@ -28,7 +28,7 @@
|
||||
<form id="dn-edit" method="POST" class="needs-validation" action="{{ url('entry/update/pending') }}" novalidate>
|
||||
@csrf
|
||||
|
||||
<input type="hidden" name="dn" value="{{ $o->getDNSecure() }}">
|
||||
<input type="hidden" name="dn" value="">
|
||||
|
||||
@foreach ($o->getVisibleAttributes() as $ao)
|
||||
<x-attribute-type :edit="true" :o="$ao"/>
|
||||
@ -113,21 +113,21 @@
|
||||
|
||||
@section('page-modals')
|
||||
<!-- EXPORT -->
|
||||
<div class="modal fade" id="entry-export-modal" tabindex="-1" aria-labelledby="entry-export-label" aria-hidden="true">
|
||||
<div class="modal fade" id="entry_export-modal" tabindex="-1" aria-labelledby="entry_export-label" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg modal-fullscreen-xl-down">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h1 class="modal-title fs-5" id="entry-export-label">LDIF for {{ $dn }}</h1>
|
||||
<h1 class="modal-title fs-5" id="entry_export-label">LDIF for {{ $dn }}</h1>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<div id="entry-export"><div class="fa-3x"><i class="fas fa-spinner fa-pulse fa-sm"></i></div></div>
|
||||
<div id="entry_export"><div class="fa-3x"><i class="fas fa-spinner fa-pulse fa-sm"></i></div></div>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-primary btn-sm" id="entry-export-download">Download</button>
|
||||
<button type="button" class="btn btn-sm btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-sm btn-primary" id="entry_export-download">Download</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -135,11 +135,11 @@
|
||||
|
||||
@if($up=$o->getObject('userpassword'))
|
||||
<!-- CHECK USERPASSWORD -->
|
||||
<div class="modal fade" id="userpassword-check-modal" tabindex="-1" aria-labelledby="userpassword-check-label" aria-hidden="true">
|
||||
<div class="modal fade" id="userpassword_check-modal" tabindex="-1" aria-labelledby="userpassword_check-label" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg modal-fullscreen-lg-down">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h1 class="modal-title fs-5" id="userpassword-check-label">Check Passwords for {{ $dn }}</h1>
|
||||
<h1 class="modal-title fs-5" id="userpassword_check-label">Check Passwords for {{ $dn }}</h1>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
|
||||
@ -161,8 +161,8 @@
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-primary btn-sm" id="userpassword_check_submit"><i class="fas fa-fw fa-spinner fa-spin d-none"></i> Check</button>
|
||||
<button type="button" class="btn btn-sm btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-sm btn-primary" id="userpassword_check-submit"><i class="fas fa-fw fa-spinner fa-spin d-none"></i> Check</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -172,6 +172,8 @@
|
||||
|
||||
@section('page-scripts')
|
||||
<script type="text/javascript">
|
||||
var dn = '{{ $o->getDNSecure() }}';
|
||||
|
||||
function download(filename,text) {
|
||||
var element = document.createElement('a');
|
||||
|
||||
@ -185,10 +187,16 @@
|
||||
}
|
||||
|
||||
function editmode() {
|
||||
$('#dn-edit input[name="dn"]').val(dn);
|
||||
|
||||
$('button[id=entry-edit]').addClass('active').removeClass('btn-outline-dark').addClass('btn-outline-light');
|
||||
|
||||
// Find all input items and turn off readonly
|
||||
$('input.form-control').each(function() {
|
||||
// Except for objectClass - @todo show an "X" instead
|
||||
if ($(this)[0].name.match(/^objectclass/))
|
||||
return;
|
||||
|
||||
$(this).attr('readonly',false);
|
||||
});
|
||||
|
||||
@ -218,7 +226,7 @@
|
||||
if (e.status != 412)
|
||||
alert('That didnt work? Please try again....');
|
||||
},
|
||||
url: '{{ url('entry/newattr') }}/'+item.target.value,
|
||||
url: '{{ url('entry/attr/add') }}/'+item.target.value,
|
||||
cache: false
|
||||
});
|
||||
|
||||
@ -239,33 +247,33 @@
|
||||
editmode();
|
||||
});
|
||||
|
||||
$('#entry-export-download').on('click',function(item) {
|
||||
$('#entry_export-download').on('click',function(item) {
|
||||
item.preventDefault();
|
||||
|
||||
let ldif = $('#entry-export').find('pre:first'); // update this selector in your local version
|
||||
let ldif = $('#entry_export').find('pre:first'); // update this selector in your local version
|
||||
download('ldap-export.ldif',ldif.html());
|
||||
});
|
||||
|
||||
$('#entry-export-modal').on('shown.bs.modal',function() {
|
||||
$('#entry_export-modal').on('shown.bs.modal',function() {
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
success: function(data) {
|
||||
$('#entry-export').empty().append(data);
|
||||
$('#entry_export').empty().append(data);
|
||||
},
|
||||
error: function(e) {
|
||||
if (e.status != 412)
|
||||
alert('That didnt work? Please try again....');
|
||||
},
|
||||
url: '{{ url('entry/export',$o->getDNSecure()) }}/',
|
||||
url: '{{ url('entry/export') }}/'+dn,
|
||||
cache: false
|
||||
})
|
||||
})
|
||||
|
||||
@if($up)
|
||||
$('button[id=userpassword_check_submit]').on('click',function(item) {
|
||||
$('button[id=userpassword_check-submit]').on('click',function(item) {
|
||||
var that = $(this);
|
||||
|
||||
var passwords = $('#userpassword-check-modal')
|
||||
var passwords = $('#userpassword_check-modal')
|
||||
.find('input[name^="password["')
|
||||
.map((key,item)=>item.value);
|
||||
|
||||
@ -284,16 +292,14 @@
|
||||
},
|
||||
success: function(data) {
|
||||
data.forEach(function(item,key) {
|
||||
var i = $('#userpassword-check-modal')
|
||||
var i = $('#userpassword_check-modal')
|
||||
.find('input[name="password['+key+']')
|
||||
.siblings('i');
|
||||
|
||||
var feedback = $('#userpassword-check-modal')
|
||||
var feedback = $('#userpassword_check-modal')
|
||||
.find('input[name="password['+key+']')
|
||||
.siblings('div.invalid-feedback');
|
||||
|
||||
console.log(feedback.attr('display'));
|
||||
|
||||
if (item === 'OK') {
|
||||
i.removeClass('text-danger').addClass('text-success').removeClass('fa-lock').addClass('fa-lock-open');
|
||||
if (feedback.is(':visible'))
|
||||
@ -311,7 +317,7 @@
|
||||
},
|
||||
url: '{{ url('entry/password/check') }}',
|
||||
data: {
|
||||
dn: '{{ $o->getDNSecure() }}',
|
||||
dn: dn,
|
||||
password: Array.from(passwords),
|
||||
},
|
||||
dataType: 'json',
|
||||
|
@ -38,10 +38,11 @@ Route::group(['prefix'=>'user'],function() {
|
||||
Route::get('image',[HomeController::class,'user_image']);
|
||||
});
|
||||
|
||||
Route::post('entry/update/commit',[HomeController::class,'entry_update']);
|
||||
Route::post('entry/update/pending',[HomeController::class,'entry_pending_update']);
|
||||
Route::get('entry/newattr/{id}',[HomeController::class,'entry_newattr']);
|
||||
Route::get('entry/export/{id}',[HomeController::class,'entry_export']);
|
||||
Route::post('entry/password/check/',[HomeController::class,'entry_password_check']);
|
||||
Route::get('entry/attr/add/{id}',[HomeController::class,'entry_attr_add']);
|
||||
Route::post('entry/objectclass/add/{id}',[HomeController::class,'entry_objectclass_add']);
|
||||
Route::post('entry/update/commit',[HomeController::class,'entry_update']);
|
||||
Route::post('entry/update/pending',[HomeController::class,'entry_pending_update']);
|
||||
|
||||
Route::post('import/process/{type}',[HomeController::class,'import']);
|
7
tests/server/openldap/data/04-z_labeleduri.ldif
Normal file
7
tests/server/openldap/data/04-z_labeleduri.ldif
Normal file
@ -0,0 +1,7 @@
|
||||
|
||||
dn: cn=tech_staff,dc=example.com
|
||||
cn: tech_staff
|
||||
labeleduri: ldap:///ou=People,o=Simpsons?uid?one?(&(sn=Simpson)(|(uidNumber
|
||||
=1000)(uidNumber=1001)))
|
||||
objectclass: nisMailAlias
|
||||
objectclass: labeledURIObject
|
@ -1,9 +0,0 @@
|
||||
# At the moment we want to override osixia/ldap to enable anonymous reads
|
||||
dn: olcDatabase={1}{{ LDAP_BACKEND }},cn=config
|
||||
changetype: modify
|
||||
delete: olcAccess
|
||||
-
|
||||
add: olcAccess
|
||||
olcAccess: to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage by * break
|
||||
olcAccess: to attrs=userPassword,shadowLastChange by self read by dn="cn=admin,{{ LDAP_BASE_DN }}" write by anonymous read by * read
|
||||
olcAccess: to * by self read by dn="cn=admin,{{ LDAP_BASE_DN }}" write by * read
|
Loading…
x
Reference in New Issue
Block a user