Compare commits
6 Commits
21c88048e3
...
16a1f85a79
Author | SHA1 | Date | |
---|---|---|---|
16a1f85a79 | |||
f8d7819153 | |||
75dbb37d8b | |||
309fe83c98 | |||
ffb98631a6 | |||
be69e22867 |
@ -3,7 +3,7 @@ run-name: ${{ gitea.actor }} Building Docker Image 🐳
|
||||
on: [push]
|
||||
env:
|
||||
DOCKER_HOST: tcp://127.0.0.1:2375
|
||||
ASSETS: c2780a3
|
||||
ASSETS: 10eca55
|
||||
|
||||
jobs:
|
||||
test:
|
||||
|
@ -38,6 +38,7 @@ The update to v2 is progressing well - here is a list of work to do and done:
|
||||
- [X] Support different password hash options
|
||||
- [X] Validate password is correct
|
||||
- [ ] JpegPhoto Create/Delete
|
||||
- [ ] Binary attribute upload
|
||||
- [X] JpegPhoto Display
|
||||
- [X] ObjectClass Add/Remove
|
||||
- [X] Add additional required attributes (for ObjectClass Addition)
|
||||
@ -53,7 +54,7 @@ The update to v2 is progressing well - here is a list of work to do and done:
|
||||
- [X] Export entries as an LDAP
|
||||
- [X] Import LDIF
|
||||
- [X] Schema Browser
|
||||
- [ ] Searching
|
||||
- [X] Searching
|
||||
- [ ] Enforcing attribute uniqueness
|
||||
- [ ] Is there something missing?
|
||||
|
||||
|
@ -18,6 +18,7 @@ final class Password extends Attribute
|
||||
use MD5Updates;
|
||||
|
||||
protected(set) bool $no_attr_tags = TRUE;
|
||||
protected(set) int $max_values_count = 1;
|
||||
|
||||
private const password_helpers = 'Classes/LDAP/Attribute/Password';
|
||||
public const commands = 'App\\Classes\\LDAP\\Attribute\\Password\\';
|
||||
|
@ -10,16 +10,16 @@ final class Argon2i extends Base
|
||||
|
||||
public static function subid(string $password): bool
|
||||
{
|
||||
return str_starts_with(base64_decode(self::password($password)),self::identifier.'$');
|
||||
return str_starts_with(self::password($password),self::identifier.'$');
|
||||
}
|
||||
|
||||
public function compare(string $source,string $compare): bool
|
||||
{
|
||||
return password_verify($compare,base64_decode($this->password($source)));
|
||||
return password_verify($compare,$this->password($source));
|
||||
}
|
||||
|
||||
public function encode(string $password): string
|
||||
{
|
||||
return sprintf('{%s}%s',self::key,base64_encode(password_hash($password,PASSWORD_ARGON2I)));
|
||||
return sprintf('{%s}%s',self::key,password_hash($password,PASSWORD_ARGON2I));
|
||||
}
|
||||
}
|
@ -127,7 +127,7 @@ class HomeController extends Controller
|
||||
case 50:
|
||||
return Redirect::to('/')
|
||||
->withInput()
|
||||
->withErrors(sprintf('%s: %s (%s)',__('LDAP Server Error Code'),$x,__($e->getDetailedError()->getErrorMessage())));
|
||||
->with('failed',sprintf('%s: %s (%s)',__('LDAP Server Error Code'),$x,__($e->getDetailedError()->getErrorMessage())));
|
||||
|
||||
default:
|
||||
abort(599,$e->getDetailedError()->getErrorMessage());
|
||||
@ -135,14 +135,14 @@ class HomeController extends Controller
|
||||
|
||||
// @todo when we create an entry, and it already exists, enable a redirect to it
|
||||
} catch (LdapRecordException $e) {
|
||||
return Redirect::back()
|
||||
->withInput()
|
||||
->withErrors(sprintf('%s: %s - %s: %s',
|
||||
__('LDAP Server Error Code'),
|
||||
$e->getDetailedError()->getErrorCode(),
|
||||
__($e->getDetailedError()->getErrorMessage()),
|
||||
$e->getDetailedError()->getDiagnosticMessage(),
|
||||
));
|
||||
return Redirect::back()
|
||||
->withInput()
|
||||
->with('failed',sprintf('%s: %s - %s: %s',
|
||||
__('LDAP Server Error Code'),
|
||||
$e->getDetailedError()->getErrorCode(),
|
||||
__($e->getDetailedError()->getErrorMessage()),
|
||||
$e->getDetailedError()->getDiagnosticMessage(),
|
||||
));
|
||||
}
|
||||
|
||||
return Redirect::to('/')
|
||||
@ -165,7 +165,7 @@ class HomeController extends Controller
|
||||
case 50:
|
||||
return Redirect::to('/')
|
||||
->withInput()
|
||||
->withErrors(sprintf('%s: %s (%s)',__('LDAP Server Error Code'),$x,__($e->getDetailedError()->getErrorMessage())));
|
||||
->with('failed',sprintf('%s: %s (%s)',__('LDAP Server Error Code'),$x,__($e->getDetailedError()->getErrorMessage())));
|
||||
|
||||
default:
|
||||
abort(599,$e->getDetailedError()->getErrorMessage());
|
||||
@ -178,7 +178,7 @@ class HomeController extends Controller
|
||||
case 8:
|
||||
return Redirect::to('/')
|
||||
->withInput()
|
||||
->withErrors(sprintf('%s: %s (%s)',__('LDAP Server Error Code'),$x,__($e->getDetailedError()->getErrorMessage())));
|
||||
->with('failed',sprintf('%s: %s (%s)',__('LDAP Server Error Code'),$x,__($e->getDetailedError()->getErrorMessage())));
|
||||
|
||||
default:
|
||||
abort(599,$e->getDetailedError()->getErrorMessage());
|
||||
@ -335,21 +335,21 @@ class HomeController extends Controller
|
||||
case 50:
|
||||
return Redirect::to('/')
|
||||
->withInput()
|
||||
->withErrors(sprintf('%s: %s (%s)',__('LDAP Server Error Code'),$x,__($e->getDetailedError()->getErrorMessage())));
|
||||
->with('failed',sprintf('%s: %s (%s)',__('LDAP Server Error Code'),$x,__($e->getDetailedError()->getErrorMessage())));
|
||||
|
||||
default:
|
||||
abort(599,$e->getDetailedError()->getErrorMessage());
|
||||
}
|
||||
|
||||
} catch (LdapRecordException $e) {
|
||||
return Redirect::to('/')
|
||||
->withInput()
|
||||
->withErrors(sprintf('%s: %s - %s: %s',
|
||||
__('LDAP Server Error Code'),
|
||||
$e->getDetailedError()->getErrorCode(),
|
||||
__($e->getDetailedError()->getErrorMessage()),
|
||||
$e->getDetailedError()->getDiagnosticMessage(),
|
||||
));
|
||||
return Redirect::to('/')
|
||||
->withInput()
|
||||
->with('failed',sprintf('%s: %s - %s: %s',
|
||||
__('LDAP Server Error Code'),
|
||||
$e->getDetailedError()->getErrorCode(),
|
||||
__($e->getDetailedError()->getErrorMessage()),
|
||||
$e->getDetailedError()->getDiagnosticMessage(),
|
||||
));
|
||||
}
|
||||
|
||||
return Redirect::to('/')
|
||||
|
59
app/Http/Controllers/SearchController.php
Normal file
59
app/Http/Controllers/SearchController.php
Normal file
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
use App\Ldap\Entry;
|
||||
|
||||
class SearchController extends Controller
|
||||
{
|
||||
public function search(Request $request): Collection
|
||||
{
|
||||
$so = config('server');
|
||||
|
||||
// We are searching for a value
|
||||
if (strpos($request->term,'=')) {
|
||||
list($attr,$value) = explode('=',$request->term,2);
|
||||
$value = trim($value);
|
||||
|
||||
$result = collect();
|
||||
|
||||
foreach ($so->baseDNs() as $base) {
|
||||
$search = (new Entry)
|
||||
->in($base);
|
||||
|
||||
$search = ($x=Str::startsWith($value,'*'))
|
||||
? $search->whereEndsWith($attr,substr($value,1))
|
||||
: $search->whereStartsWith($attr,$value);
|
||||
|
||||
$result = $result->merge($search->get());
|
||||
}
|
||||
|
||||
return $result
|
||||
->map(fn($item)=>[
|
||||
'name'=>$item->getDN(),
|
||||
'value'=>Crypt::encryptString($item->getDN()),
|
||||
'category'=>sprintf('%s: [%s=%s%s]',__('Result'),$attr,$value,($x ? '' : '*'))
|
||||
]);
|
||||
|
||||
// We are searching for an attribute
|
||||
} else {
|
||||
$attrs = $so
|
||||
->schema('attributetypes')
|
||||
->sortBy('name')
|
||||
->filter(fn($item)=>Str::contains($item->name_lc,$request->term));
|
||||
|
||||
return $attrs
|
||||
->map(fn($item)=>[
|
||||
'name'=>$item->name,
|
||||
'value'=>'',
|
||||
'category'=>__('Select attribute...')
|
||||
])
|
||||
->values();
|
||||
}
|
||||
}
|
||||
}
|
@ -1 +1 @@
|
||||
v2.1.2-rel
|
||||
v2.1.3-rel
|
||||
|
@ -33,8 +33,12 @@
|
||||
<div class="app-header-left">
|
||||
<div class="search-wrapper">
|
||||
<div class="input-holder">
|
||||
<input type="text" class="search-input" placeholder="Type to search">
|
||||
<button class="search-icon"><span></span></button>
|
||||
<input type="text" class="search-input" id="search" placeholder="Type to search">
|
||||
<button class="search-icon">
|
||||
<span></span>
|
||||
<div id="searching" class="d-none"><i class="fas fa-fw fa-spinner fa-pulse text-light"></i></div>
|
||||
</button>
|
||||
<div id="search_results" style="height: 300px; overflow: scroll"></div>
|
||||
</div>
|
||||
<button class="btn-close"></button>
|
||||
</div>
|
||||
@ -160,6 +164,13 @@
|
||||
</div>
|
||||
|
||||
@section('page-scripts')
|
||||
<style>
|
||||
#search_results ul.typeahead.dropdown-menu {
|
||||
overflow: scroll;
|
||||
max-height: 300px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
$('button[id^="link-"]').on('click',function(item) {
|
||||
@ -190,6 +201,70 @@
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.search-wrapper input[id="search"]').typeahead({
|
||||
autoSelect: false,
|
||||
scrollHeight: 10,
|
||||
theme: 'bootstrap5',
|
||||
delay: 500,
|
||||
minLength: 2,
|
||||
items: {{ $search_limit ?? 100 }},
|
||||
selectOnBlur: false,
|
||||
appendTo: "#search_results",
|
||||
source: function(query,process) {
|
||||
search('{{ url('search') }}',query,process);
|
||||
},
|
||||
// Disable sorting and just return the items (items should be sorted by the ajax method)
|
||||
sorter: function(items) {
|
||||
return items;
|
||||
},
|
||||
matcher: function() { return true; },
|
||||
// Disable sorting and just return the items (items should by the ajax method)
|
||||
updater: function(item) {
|
||||
// If item has a data value, then we'll use that
|
||||
if (item.data && item.data.length)
|
||||
return item.data;
|
||||
|
||||
if (! item.value)
|
||||
return item.name+'=';
|
||||
|
||||
location.replace('/#'+item.value);
|
||||
location.reload();
|
||||
return '';
|
||||
},
|
||||
})
|
||||
.on('keyup keypress',function(event) {
|
||||
var key = event.keyCode || event.which;
|
||||
if (key === 13) {
|
||||
event.preventDefault();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
var search = _.debounce(function(url,query,process){
|
||||
$.ajax({
|
||||
url : url,
|
||||
type : 'POST',
|
||||
data : 'term=' + query,
|
||||
dataType : 'JSON',
|
||||
async : true,
|
||||
cache : false,
|
||||
beforeSend : function() {
|
||||
$('.search-wrapper div#searching').removeClass('d-none');
|
||||
$('.search-wrapper .search-icon span').addClass('d-none');
|
||||
},
|
||||
success : function(data) {
|
||||
// if json is null, means no match, won't do again.
|
||||
if(data==null || (data.length===0)) return;
|
||||
|
||||
process(data);
|
||||
},
|
||||
complete : function() {
|
||||
$('.search-wrapper div#searching').addClass('d-none');
|
||||
$('.search-wrapper .search-icon span').removeClass('d-none');
|
||||
}
|
||||
})
|
||||
}, 500);
|
||||
</script>
|
||||
@append
|
@ -3,7 +3,7 @@
|
||||
<!-- $o=Attribute::class -->
|
||||
<x-attribute.layout :edit="$edit=($edit ?? FALSE)" :new="$new=($new ?? FALSE)" :o="$o">
|
||||
<div class="col-12">
|
||||
@foreach(Arr::get(old($o->name_lc,[($langtag=($langtag ?? Entry::TAG_NOTAG))=>$new ? [NULL] : $o->tagValues($langtag)]),$langtag,[]) as $key => $value)
|
||||
@foreach(Arr::get(old($o->name_lc,[$langtag=>$new ? [NULL] : $o->tagValues($langtag)]),$langtag,[]) as $key => $value)
|
||||
@if($edit && (! $o->is_rdn))
|
||||
<div class="input-group has-validation">
|
||||
<input type="text" @class(['form-control','is-invalid'=>($e=$errors->get($o->name_lc.'.'.$langtag.'.'.$loop->index)),'mb-1','border-focus'=>! ($tv=$o->tagValuesOld($langtag))->contains($value),'bg-success-subtle'=>$updated]) name="{{ $o->name_lc }}[{{ $langtag }}][]" value="{{ $value }}" placeholder="{{ ! is_null($x=$tv->get($loop->index)) ? $x : '['.__('NEW').']' }}" @readonly(! $new) @disabled($o->isDynamic())>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<!-- @todo We are not handling redirect backs yet with updated photos -->
|
||||
<!-- $o=Binary\JpegPhoto::class -->
|
||||
<x-attribute.layout :edit="$edit" :new="$new" :o="$o" :langtag="$langtag">
|
||||
<x-attribute.layout :edit="$edit" :new="$new" :o="$o">
|
||||
<table class="table table-borderless p-0 m-0">
|
||||
@foreach($o->tagValuesOld() as $key => $value)
|
||||
<tr>
|
||||
|
@ -1,10 +1,10 @@
|
||||
<!-- @todo We are not handling redirect backs yet with updated passwords -->
|
||||
<!-- $o=KrbPrincipleKey::class -->
|
||||
<x-attribute.layout :edit="$edit" :new="$new" :o="$o" :langtag="$langtag">
|
||||
<x-attribute.layout :edit="$edit" :new="$new" :o="$o">
|
||||
@foreach($o->tagValuesOld($langtag) as $key => $value)
|
||||
@if($edit)
|
||||
<div class="input-group has-validation mb-3">
|
||||
<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="{{ md5($value) }}" @readonly(true)>
|
||||
<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="{{ md5($value) }}" @readonly(! $new)>
|
||||
|
||||
<div class="invalid-feedback pb-2">
|
||||
@if($e)
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!-- $o=Attribute/ObjectClass::class -->
|
||||
<x-attribute.layout :edit="$edit" :new="$new" :o="$o" :langtag="$langtag">
|
||||
<x-attribute.layout :edit="$edit" :new="$new" :o="$o">
|
||||
@foreach(Arr::get(old($o->name_lc,[$langtag=>$new ? [NULL] : $o->tagValues($langtag)]),$langtag,[]) as $key => $value)
|
||||
@if($edit)
|
||||
<x-attribute.widget.objectclass :o="$o" :edit="$edit" :new="$new" :langtag="$langtag" :updated="$updated" :value="$value" :loop="$loop" />
|
||||
|
@ -1,11 +1,11 @@
|
||||
<!-- @todo We are not handling redirect backs yet with updated passwords -->
|
||||
<!-- $o=Password::class -->
|
||||
<x-attribute.layout :edit="$edit" :new="$new" :o="$o" :langtag="$langtag">
|
||||
@foreach($o->tagValuesOld($langtag) as $key => $value)
|
||||
<x-attribute.layout :edit="$edit" :new="$new" :o="$o">
|
||||
@foreach(Arr::get(old($o->name_lc,[$langtag=>$new ? [NULL] : $o->tagValues($langtag)]),$langtag,[]) as $key => $value)
|
||||
@if($edit)
|
||||
<div class="input-group has-validation mb-3">
|
||||
<x-form.select id="userpassword_hash_{{$loop->index}}" name="userpassword_hash[{{ $langtag }}][]" :value="$o->hash($value)->id()" :options="$helpers" allowclear="false" :disabled="true"/>
|
||||
<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="{{ md5($value) }}" @readonly(true)>
|
||||
<x-form.select id="userpassword_hash_{{$loop->index}}" 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="{{ md5($value) }}" @readonly(! $new)>
|
||||
|
||||
<div class="invalid-feedback pb-2">
|
||||
@if($e)
|
||||
|
@ -255,7 +255,9 @@
|
||||
@default
|
||||
@if($o->isDynamic()) @break @endif
|
||||
@php($clone=TRUE)
|
||||
<span @class(['btn','btn-sm','btn-outline-primary','mt-3','addable','d-none'=>(! $new)]) id="{{ $o->name }}-addnew"><i class="fas fa-fw fa-plus"></i> @lang('Add Value')</span>
|
||||
@if($o->values_old->count())
|
||||
<span @class(['btn','btn-sm','btn-outline-primary','mt-3','addable','d-none'=>(! $new)]) id="{{ $o->name }}-addnew"><i class="fas fa-fw fa-plus"></i> @lang('Add Value')</span>
|
||||
@endif
|
||||
|
||||
@section('page-scripts')
|
||||
@if($clone && $edit && $o->can_addvalues)
|
||||
|
5
resources/views/components/failed.blade.php
Normal file
5
resources/views/components/failed.blade.php
Normal file
@ -0,0 +1,5 @@
|
||||
@if(session()->has('failed'))
|
||||
<div class="alert alert-danger p-2">
|
||||
<p class="m-0"><i class="fas fa-fw fa-thumbs-down"></i> {{ session()->pull('failed') }}</p>
|
||||
</div>
|
||||
@endif
|
@ -1,7 +1,7 @@
|
||||
@use(App\Classes\LDAP\Attribute\Certificate)
|
||||
|
||||
<!-- $o=Certificate::class -->
|
||||
<x-attribute.layout :edit="$edit" :new="$new" :o="$o" langtag="binary">
|
||||
<x-attribute.layout :edit="$edit" :new="$new" :o="$o">
|
||||
@foreach($o->tagValuesOld('binary') as $key => $value)
|
||||
<!-- If this attribute is not handle, it'll be an Attribute::class, we'll just render it normally -->
|
||||
@if(($o instanceof Certificate) && $edit)
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!-- $o=CertificateList::class -->
|
||||
<x-attribute.layout :edit="$edit" :new="$new" :o="$o" langtag="binary">
|
||||
<x-attribute.layout :edit="$edit" :new="$new" :o="$o">
|
||||
@foreach($o->tagValuesOld('binary') as $key => $value)
|
||||
<!-- If this attribute is not handle, it'll be an Attribute::class, we'll just render it normally -->
|
||||
<span class="form-control mb-1"><pre class="m-0">{{ $o->render_item_old('binary.'.$key) }}</pre></span>
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
@section('page_status')
|
||||
<x-error/>
|
||||
<x-failed/>
|
||||
@endsection
|
||||
|
||||
@section('main-content')
|
||||
|
@ -67,6 +67,7 @@
|
||||
<x-note/>
|
||||
<x-error/>
|
||||
<x-updated/>
|
||||
<x-failed/>
|
||||
@endsection
|
||||
|
||||
@section('main-content')
|
||||
|
@ -23,18 +23,51 @@
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-sm-8">
|
||||
<h3 class="mb-1">Welcome to phpLDAPadmin</h3>
|
||||
<h4 class="mb-3"><small>{{ config('app.version') }}</small></h4>
|
||||
<p>phpLDAPadmin (or PLA for short) is an LDAP data management tool for administrators.</p>
|
||||
<p>PLA aims to adhere to the LDAP standards so that it can interact with any LDAP server that implements those standards.</p>
|
||||
<h1 class="mb-2">Welcome to phpLDAPadmin</h1>
|
||||
<p>phpLDAPadmin (or PLA for short) is an LDAP (Lightweight Directory Access Protocol) data management tool for administrators.</p>
|
||||
<p>PLA provides an easy-to-use interface for browsing, searching, and modifying data in an LDAP directory. Essentially, it's a user-friendly alternative to using command-line tools for LDAP management.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<hr>
|
||||
<p>Version 2 is a complete re-write of PLA, leveraging the advancements and modernisation of web tools and methods, libraries since version 1 was released.</p>
|
||||
<p>You can support this application by letting us know which LDAP server you use (including version and platform).</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-4">
|
||||
<span class="text-dark">
|
||||
<a class="link-opacity-50 link-opacity-100-hover link-dark" href="https://phpldapadmin.org"><i class="fas fa-fw fa-2x fa-globe me-1"></i></a>
|
||||
<a class="link-opacity-50 link-opacity-100-hover link-dark" href="https://github.com/leenooks/phpldapadmin"><i class="fab fa-fw fa-2x fa-github me-1"></i></a>
|
||||
<a class="link-opacity-50 link-opacity-100-hover link-dark" href="https://github.com/leenooks/phpLDAPadmin/discussions"><i class="fas fa-fw fa-2x fa-hand me-1"></i></a>
|
||||
<a class="link-opacity-50 link-opacity-100-hover link-dark" href="https://github.com/leenooks/phpLDAPadmin/issues"><i class="fas fa-fw fa-2x fa-bug me-1"></i></a>
|
||||
<a class="link-opacity-50 link-opacity-100-hover link-dark" href="https://hub.docker.com/r/phpldapadmin/phpldapadmin"><i class="fab fa-fw fa-2x fa-docker me-1"></i></a>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-sm-8 col-xl-4">
|
||||
<h5>Key Features and Functionality</h5>
|
||||
<ul class="list-unstyled">
|
||||
<li class="ps-0 p-1">
|
||||
<i class="fas fa-fw fa-globe me-2"></i> Easy To Use Web Interface
|
||||
</li>
|
||||
<li class="ps-0 p-1">
|
||||
<i class="fas fa-fw fa-sitemap me-2"></i> Hierarchical Tree View
|
||||
</li>
|
||||
<li class="ps-0 p-1">
|
||||
<i class="fas fa-fw fa-language me-2"></i> Multi-language Support
|
||||
</li>
|
||||
<li class="ps-0 p-1">
|
||||
<i class="fas fa-fw fa-file-export me-2"></i> LDIF Import/Export
|
||||
</li>
|
||||
<li class="ps-0 p-1">
|
||||
<i class="fas fa-fw fa-clipboard-list me-2"></i> Build on RFC Standards
|
||||
</li>
|
||||
<li class="ps-0 p-1">
|
||||
<i class="fas fa-fw fa-pen-to-square me-2"></i> Open Source
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
use App\Http\Controllers\{AjaxController,HomeController};
|
||||
use App\Http\Controllers\{AjaxController,HomeController,SearchController};
|
||||
use App\Http\Controllers\Auth\LoginController;
|
||||
use App\Http\Middleware\AllowAnonymous;
|
||||
|
||||
@ -27,6 +27,7 @@ Auth::routes([
|
||||
]);
|
||||
|
||||
Route::get('logout',[LoginController::class,'logout']);
|
||||
Route::post('search',[SearchController::class,'search']);
|
||||
|
||||
Route::controller(HomeController::class)->group(function() {
|
||||
Route::middleware(AllowAnonymous::class)->group(function() {
|
||||
|
4
tests/server/openldap/schema/modify/99-argon.ldif
Normal file
4
tests/server/openldap/schema/modify/99-argon.ldif
Normal file
@ -0,0 +1,4 @@
|
||||
dn: cn=z-module{0},cn=config
|
||||
changetype: modify
|
||||
add: olcModuleLoad
|
||||
olcModuleLoad: argon2
|
Loading…
x
Reference in New Issue
Block a user