Compare commits

...

4 Commits

Author SHA1 Message Date
6e06cd721a Revert version to 2.1.3-dev
All checks were successful
Create Docker Image / Test Application (x86_64) (push) Successful in 28s
Create Docker Image / Build Docker Image (x86_64) (push) Successful in 1m23s
Create Docker Image / Build Docker Image (arm64) (push) Successful in 4m30s
Create Docker Image / Final Docker Image Manifest (push) Successful in 9s
2025-05-04 00:01:40 +10:00
f8d7819153 Fix for ARGON2 passwords, they shouldnt be base64 encoded. Fixes #316 2025-05-04 00:01:40 +10:00
75dbb37d8b $langtag doesnt need to be passed to x-attribute.layout. Fix adding new userpassword. Only show Add Value when the Attribute has atleast 1 old value 2025-05-04 00:01:40 +10:00
309fe83c98 LDAP server errors were not being displayed when used with ->withErrors(), so created a new component x-failed 2025-05-04 00:01:40 +10:00
16 changed files with 50 additions and 36 deletions

View File

@ -18,6 +18,7 @@ final class Password extends Attribute
use MD5Updates; use MD5Updates;
protected(set) bool $no_attr_tags = TRUE; protected(set) bool $no_attr_tags = TRUE;
protected(set) int $max_values_count = 1;
private const password_helpers = 'Classes/LDAP/Attribute/Password'; private const password_helpers = 'Classes/LDAP/Attribute/Password';
public const commands = 'App\\Classes\\LDAP\\Attribute\\Password\\'; public const commands = 'App\\Classes\\LDAP\\Attribute\\Password\\';

View File

@ -10,16 +10,16 @@ final class Argon2i extends Base
public static function subid(string $password): bool 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 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 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));
} }
} }

View File

@ -127,7 +127,7 @@ class HomeController extends Controller
case 50: case 50:
return Redirect::to('/') return Redirect::to('/')
->withInput() ->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: default:
abort(599,$e->getDetailedError()->getErrorMessage()); 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 // @todo when we create an entry, and it already exists, enable a redirect to it
} catch (LdapRecordException $e) { } catch (LdapRecordException $e) {
return Redirect::back() return Redirect::back()
->withInput() ->withInput()
->withErrors(sprintf('%s: %s - %s: %s', ->with('failed',sprintf('%s: %s - %s: %s',
__('LDAP Server Error Code'), __('LDAP Server Error Code'),
$e->getDetailedError()->getErrorCode(), $e->getDetailedError()->getErrorCode(),
__($e->getDetailedError()->getErrorMessage()), __($e->getDetailedError()->getErrorMessage()),
$e->getDetailedError()->getDiagnosticMessage(), $e->getDetailedError()->getDiagnosticMessage(),
)); ));
} }
return Redirect::to('/') return Redirect::to('/')
@ -165,7 +165,7 @@ class HomeController extends Controller
case 50: case 50:
return Redirect::to('/') return Redirect::to('/')
->withInput() ->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: default:
abort(599,$e->getDetailedError()->getErrorMessage()); abort(599,$e->getDetailedError()->getErrorMessage());
@ -178,7 +178,7 @@ class HomeController extends Controller
case 8: case 8:
return Redirect::to('/') return Redirect::to('/')
->withInput() ->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: default:
abort(599,$e->getDetailedError()->getErrorMessage()); abort(599,$e->getDetailedError()->getErrorMessage());
@ -335,21 +335,21 @@ class HomeController extends Controller
case 50: case 50:
return Redirect::to('/') return Redirect::to('/')
->withInput() ->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: default:
abort(599,$e->getDetailedError()->getErrorMessage()); abort(599,$e->getDetailedError()->getErrorMessage());
} }
} catch (LdapRecordException $e) { } catch (LdapRecordException $e) {
return Redirect::to('/') return Redirect::to('/')
->withInput() ->withInput()
->withErrors(sprintf('%s: %s - %s: %s', ->with('failed',sprintf('%s: %s - %s: %s',
__('LDAP Server Error Code'), __('LDAP Server Error Code'),
$e->getDetailedError()->getErrorCode(), $e->getDetailedError()->getErrorCode(),
__($e->getDetailedError()->getErrorMessage()), __($e->getDetailedError()->getErrorMessage()),
$e->getDetailedError()->getDiagnosticMessage(), $e->getDetailedError()->getDiagnosticMessage(),
)); ));
} }
return Redirect::to('/') return Redirect::to('/')

View File

@ -1 +1 @@
v2.1.2-rel v2.1.3-dev

View File

@ -3,7 +3,7 @@
<!-- $o=Attribute::class --> <!-- $o=Attribute::class -->
<x-attribute.layout :edit="$edit=($edit ?? FALSE)" :new="$new=($new ?? FALSE)" :o="$o"> <x-attribute.layout :edit="$edit=($edit ?? FALSE)" :new="$new=($new ?? FALSE)" :o="$o">
<div class="col-12"> <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)) @if($edit && (! $o->is_rdn))
<div class="input-group has-validation"> <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())> <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())>

View File

@ -1,6 +1,6 @@
<!-- @todo We are not handling redirect backs yet with updated photos --> <!-- @todo We are not handling redirect backs yet with updated photos -->
<!-- $o=Binary\JpegPhoto::class --> <!-- $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"> <table class="table table-borderless p-0 m-0">
@foreach($o->tagValuesOld() as $key => $value) @foreach($o->tagValuesOld() as $key => $value)
<tr> <tr>

View File

@ -1,10 +1,10 @@
<!-- @todo We are not handling redirect backs yet with updated passwords --> <!-- @todo We are not handling redirect backs yet with updated passwords -->
<!-- $o=KrbPrincipleKey::class --> <!-- $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) @foreach($o->tagValuesOld($langtag) as $key => $value)
@if($edit) @if($edit)
<div class="input-group has-validation mb-3"> <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"> <div class="invalid-feedback pb-2">
@if($e) @if($e)

View File

@ -1,5 +1,5 @@
<!-- $o=Attribute/ObjectClass::class --> <!-- $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) @foreach(Arr::get(old($o->name_lc,[$langtag=>$new ? [NULL] : $o->tagValues($langtag)]),$langtag,[]) as $key => $value)
@if($edit) @if($edit)
<x-attribute.widget.objectclass :o="$o" :edit="$edit" :new="$new" :langtag="$langtag" :updated="$updated" :value="$value" :loop="$loop" /> <x-attribute.widget.objectclass :o="$o" :edit="$edit" :new="$new" :langtag="$langtag" :updated="$updated" :value="$value" :loop="$loop" />

View File

@ -1,11 +1,11 @@
<!-- @todo We are not handling redirect backs yet with updated passwords --> <!-- @todo We are not handling redirect backs yet with updated passwords -->
<!-- $o=Password::class --> <!-- $o=Password::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) @foreach(Arr::get(old($o->name_lc,[$langtag=>$new ? [NULL] : $o->tagValues($langtag)]),$langtag,[]) as $key => $value)
@if($edit) @if($edit)
<div class="input-group has-validation mb-3"> <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"/> <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(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"> <div class="invalid-feedback pb-2">
@if($e) @if($e)

View File

@ -255,7 +255,9 @@
@default @default
@if($o->isDynamic()) @break @endif @if($o->isDynamic()) @break @endif
@php($clone=TRUE) @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') @section('page-scripts')
@if($clone && $edit && $o->can_addvalues) @if($clone && $edit && $o->can_addvalues)

View 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

View File

@ -1,7 +1,7 @@
@use(App\Classes\LDAP\Attribute\Certificate) @use(App\Classes\LDAP\Attribute\Certificate)
<!-- $o=Certificate::class --> <!-- $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) @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 this attribute is not handle, it'll be an Attribute::class, we'll just render it normally -->
@if(($o instanceof Certificate) && $edit) @if(($o instanceof Certificate) && $edit)

View File

@ -1,5 +1,5 @@
<!-- $o=CertificateList::class --> <!-- $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) @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 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> <span class="form-control mb-1"><pre class="m-0">{{ $o->render_item_old('binary.'.$key) }}</pre></span>

View File

@ -11,6 +11,7 @@
@section('page_status') @section('page_status')
<x-error/> <x-error/>
<x-failed/>
@endsection @endsection
@section('main-content') @section('main-content')

View File

@ -67,6 +67,7 @@
<x-note/> <x-note/>
<x-error/> <x-error/>
<x-updated/> <x-updated/>
<x-failed/>
@endsection @endsection
@section('main-content') @section('main-content')

View File

@ -0,0 +1,4 @@
dn: cn=z-module{0},cn=config
changetype: modify
add: olcModuleLoad
olcModuleLoad: argon2