Added additional password hashing functions
All checks were successful
Create Docker Image / Test Application (x86_64) (push) Successful in 33s
Create Docker Image / Build Docker Image (x86_64) (push) Successful in 1m26s
Create Docker Image / Build Docker Image (arm64) (push) Successful in 3m36s
Create Docker Image / Final Docker Image Manifest (push) Successful in 11s

This commit is contained in:
Deon George 2025-01-18 16:42:03 +11:00
parent 77a139016b
commit d3d7881e3b
25 changed files with 383 additions and 434 deletions

View File

@ -6,7 +6,6 @@ use Illuminate\Contracts\View\View;
use Illuminate\Support\Arr; use Illuminate\Support\Arr;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use App\Classes\LDAP\Attribute\Password\Base;
use App\Classes\LDAP\Attribute; use App\Classes\LDAP\Attribute;
use App\Traits\MD5Updates; use App\Traits\MD5Updates;
@ -28,41 +27,54 @@ final class Password extends Attribute
continue; continue;
$class = self::commands.preg_replace('/\.php$/','',$file); $class = self::commands.preg_replace('/\.php$/','',$file);
if ($helpers->count())
$helpers->push('');
$helpers = $helpers $helpers = $helpers
->merge([$class::id()=>$class]); ->merge([$class::id()=>$class]);
} }
return $helpers; return $helpers->sort();
}
/**
* Given an LDAP password syntax {xxx}yyyyyy, this function will return the object for xxx
*
* @param string $password
* @return Attribute\Password\Base|null
* @throws \Exception
*/
public static function hash(string $password): ?Attribute\Password\Base
{
$m = [];
preg_match('/^{([A-Z0-9]+)}(.*)$/',$password,$m);
$hash = Arr::get($m,1,'*clear*');
if (($potential=static::helpers()->filter(fn($hasher)=>str_starts_with($hasher::id(),$hash)))->count() > 1) {
foreach ($potential as $item) {
if ($item::subid($password))
return new $item;
}
throw new \Exception(sprintf('Couldnt figure out a password hash for %s',$password));
} elseif (! $potential->count()) {
throw new \Exception(sprintf('Couldnt figure out a password hash for %s',$password));
}
return new ($potential->pop());
} }
/** /**
* Return the object that will process a password * Return the object that will process a password
* *
* @param string $id * @param string $id
* @return Base|null * @return Attribute\Password\Base|null
*/ */
public static function hash(string $id): ?Attribute\Password\Base public static function hash_id(string $id): ?Attribute\Password\Base
{ {
return ($helpers=static::helpers())->has($id) ? new ($helpers->get($id)) : NULL; return ($helpers=static::helpers())->has($id) ? new ($helpers->get($id)) : NULL;
} }
/**
* Given an LDAP password syntax {xxx}yyyyyy, this function will return xxx
*
* @param string $password
* @return string
*/
public static function hash_id(string $password): string
{
$m = [];
preg_match('/^{([A-Z]+)}(.*)$/',$password,$m);
return Arr::get($m,1,'Clear');
}
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE): View public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE): View
{ {
return view('components.attribute.password') return view('components.attribute.password')
@ -75,11 +87,17 @@ final class Password extends Attribute
public function render_item_old(int $key): ?string public function render_item_old(int $key): ?string
{ {
return Arr::get($this->oldValues,$key) ? str_repeat('x',8) : NULL; $pw = Arr::get($this->oldValues,$key);
return $pw
? (((($x=$this->hash($pw)) && ($x::id() !== '*clear*')) ? sprintf('{%s}',$x::shortid()) : '').str_repeat('*',16))
: NULL;
} }
public function render_item_new(int $key): ?string public function render_item_new(int $key): ?string
{ {
return Arr::get($this->values,$key) ? str_repeat('x',8) : NULL; $pw = Arr::get($this->values,$key);
return $pw
? (((($x=$this->hash($pw)) && ($x::id() !== '*clear*')) ? sprintf('{%s}',$x::shortid()) : '').str_repeat('*',16))
: NULL;
} }
} }

View File

@ -0,0 +1,25 @@
<?php
namespace App\Classes\LDAP\Attribute\Password;
final class Argon2i extends Base
{
public const key = 'ARGON2';
protected const subkey = 'i';
protected const identifier = '$argon2i';
public static function subid(string $password): bool
{
return str_starts_with(base64_decode(self::password($password)),self::identifier.'$');
}
public function compare(string $source,string $compare): bool
{
return password_verify($compare,base64_decode($this->password($source)));
}
public function encode(string $password): string
{
return sprintf('{%s}%s',self::key,base64_encode(password_hash($password,PASSWORD_ARGON2I)));
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace App\Classes\LDAP\Attribute\Password;
final class Argon2id extends Base
{
public const key = 'ARGON2';
protected const subkey = 'id';
protected const identifier = '$argon2id';
public static function subid(string $password): bool
{
return str_starts_with(base64_decode(self::password($password)),self::identifier.'$');
}
public function compare(string $source,string $compare): bool
{
return password_verify($compare,base64_decode($this->password($source)));
}
public function encode(string $password): string
{
return sprintf('{%s}%s',self::key,base64_encode(password_hash($password,PASSWORD_ARGON2ID)));
}
}

View File

@ -4,11 +4,65 @@ namespace App\Classes\LDAP\Attribute\Password;
abstract class Base abstract class Base
{ {
abstract public function compare(string $source,string $compare): bool; protected const subkey = '';
abstract public function encode(string $password): string; abstract public function encode(string $password): string;
public static function id(): string public static function id(): string
{
return static::key.(static::subkey ? ':'.static::subkey : '');
}
/**
* Remove the hash {TEXT}xxxx from the password
*
* @param string $password
* @return string
*/
protected static function password(string $password): string
{
return preg_replace('/^{'.static::key.'}/','',$password);
}
public static function shortid(): string
{ {
return static::key; return static::key;
} }
/**
* When multiple passwords share the same ID, this determines which hash is responsible for the presented password
*
* @param string $password
* @return bool
*/
public static function subid(string $password): bool
{
return FALSE;
}
/**
* Compare our password to see if it is the same as that stored
*
* @param string $source Encoded source password
* @param string $compare Password entered by user
* @return bool
*/
public function compare(string $source,string $compare): bool
{
return $source === $this->encode($compare);
}
protected function salted_hash(string $password,string $algo,int $salt_size=8,string $salt=NULL): string
{
if (is_null($salt))
$salt = hex2bin(random_salt($salt_size));
return base64_encode(hash($algo,$password.$salt,true).$salt);
}
protected function salted_salt(string $source): string
{
$hash = base64_decode(substr($source,strlen(static::key)+2));
return substr($hash,strlen($hash)-static::salt/2);
}
} }

View File

@ -0,0 +1,22 @@
<?php
namespace App\Classes\LDAP\Attribute\Password;
final class Bcrypt extends Base
{
public const key = 'BCRYPT';
private const options = [
'cost' => 8,
];
public function compare(string $source,string $compare): bool
{
return password_verify($compare,base64_decode($this->password($source)));
}
public function encode(string $password): string
{
return sprintf('{%s}%s',self::key,base64_encode(password_hash($password,PASSWORD_BCRYPT,self::options)));
}
}

View File

@ -4,12 +4,7 @@ namespace App\Classes\LDAP\Attribute\Password;
final class Clear extends Base final class Clear extends Base
{ {
public const key = 'Clear'; public const key = '*clear*';
public function compare(string $source,string $compare): bool
{
return $source === $compare;
}
public function encode(string $password): string public function encode(string $password): string
{ {

View File

@ -0,0 +1,13 @@
<?php
namespace App\Classes\LDAP\Attribute\Password;
final class MD5 extends Base
{
public const key = 'MD5';
public function encode(string $password): string
{
return sprintf('{%s}%s',self::key,base64_encode(hash('md5',$password,true)));
}
}

View File

@ -0,0 +1,13 @@
<?php
namespace App\Classes\LDAP\Attribute\Password;
final class SHA extends Base
{
public const key = 'SHA';
public function encode(string $password): string
{
return sprintf('{%s}%s',self::key,base64_encode(hash('sha1',$password,true)));
}
}

View File

@ -0,0 +1,13 @@
<?php
namespace App\Classes\LDAP\Attribute\Password;
final class SHA256 extends Base
{
public const key = 'SHA256';
public function encode(string $password): string
{
return sprintf('{%s}%s',self::key,base64_encode(hash('sha256',$password,true)));
}
}

View File

@ -0,0 +1,13 @@
<?php
namespace App\Classes\LDAP\Attribute\Password;
final class SHA384 extends Base
{
public const key = 'SHA384';
public function encode(string $password): string
{
return sprintf('{%s}%s',self::key,base64_encode(hash('sha384',$password,true)));
}
}

View File

@ -0,0 +1,13 @@
<?php
namespace App\Classes\LDAP\Attribute\Password;
final class SHA512 extends Base
{
public const key = 'SHA512';
public function encode(string $password): string
{
return sprintf('{%s}%s',self::key,base64_encode(hash('sha512',$password,true)));
}
}

View File

@ -0,0 +1,22 @@
<?php
namespace App\Classes\LDAP\Attribute\Password;
final class SMD5 extends Base
{
public const key = 'SMD5';
protected const salt = 8;
public function compare(string $source,string $compare): bool
{
return $source === $this->encode($compare,$this->salted_salt($source));
}
public function encode(string $password,string $salt=NULL): string
{
if (is_null($salt))
$salt = hex2bin(random_salt(self::salt));
return sprintf('{%s}%s',self::key,$this->salted_hash($password,'md5',self::salt,$salt));
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Classes\LDAP\Attribute\Password;
final class SSHA extends Base
{
public const key = 'SSHA';
protected const salt = 8;
public function compare(string $source,string $compare): bool
{
return $source === $this->encode($compare,$this->salted_salt($source));
}
public function encode(string $password,string $salt=NULL): string
{
return sprintf('{%s}%s',self::key,$this->salted_hash($password,'sha1',self::salt,$salt));
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Classes\LDAP\Attribute\Password;
final class SSHA256 extends Base
{
public const key = 'SSHA256';
protected const salt = 8;
public function compare(string $source,string $compare): bool
{
return $source === $this->encode($compare,$this->salted_salt($source));
}
public function encode(string $password,string $salt=NULL): string
{
return sprintf('{%s}%s',self::key,$this->salted_hash($password,'sha256',self::salt,$salt));
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Classes\LDAP\Attribute\Password;
final class SSHA384 extends Base
{
public const key = 'SSHA384';
protected const salt = 8;
public function compare(string $source,string $compare): bool
{
return $source === $this->encode($compare,$this->salted_salt($source));
}
public function encode(string $password,string $salt=NULL): string
{
return sprintf('{%s}%s',self::key,$this->salted_hash($password,'sha384',self::salt,$salt));
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Classes\LDAP\Attribute\Password;
final class SSHA512 extends Base
{
public const key = 'SSHA512';
protected const salt = 8;
public function compare(string $source,string $compare): bool
{
return $source === $this->encode($compare,$this->salted_salt($source));
}
public function encode(string $password,string $salt=NULL): string
{
return sprintf('{%s}%s',self::key,$this->salted_hash($password,'sha512',self::salt,$salt));
}
}

View File

@ -99,11 +99,11 @@ class HomeController extends Controller
$result = collect(); $result = collect();
foreach ($password as $key => $value) { foreach ($password as $key => $value) {
$type = $password->hash_id($value); $hash = $password->hash($value);
$compare = Arr::get($request->password,$key); $compare = Arr::get($request->password,$key);
//Log::debug(sprintf('comparing [%s] with [%s] type [%s]',$value,$compare,$type)); //Log::debug(sprintf('comparing [%s] with [%s] type [%s]',$value,$compare,$hash::id()),['object'=>$hash]);
$result->push((($compare !== NULL) && Attribute\Password::hash($type)->compare($value,$compare)) ? 'OK' :'FAIL'); $result->push((($compare !== NULL) && $hash->compare($value,$compare)) ? 'OK' :'FAIL');
} }
return $result; return $result;
@ -128,9 +128,15 @@ class HomeController extends Controller
// We need to process and encrypt the password // We need to process and encrypt the password
$passwords = []; $passwords = [];
foreach ($request->userpassword as $key => $value) { 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) { if ($value) {
$type = Arr::get($request->userpassword_hash,$key); $type = Arr::get($request->userpassword_hash,$key);
array_push($passwords,Attribute\Password::hash($type)->encode($value)); array_push($passwords,Attribute\Password::hash_id($type)->encode($value));
} }
} }
$o->userpassword = $passwords; $o->userpassword = $passwords;
@ -199,8 +205,7 @@ class HomeController extends Controller
return Redirect::to('/') return Redirect::to('/')
->withInput() ->withInput()
->with('success',__('Entry updated')) ->with('updated',collect($dirty)->map(fn($key,$item)=>$o->getObject($item)));
->with('updated',$dirty);
} }
/** /**

View File

@ -11,3 +11,22 @@ function login_attr_name(): string
{ {
return key(config('ldap.login.attr')); return key(config('ldap.login.attr'));
} }
/**
* Used to generate a random salt for crypt-style passwords. Salt strings are used
* to make pre-built hash cracking dictionaries difficult to use as the hash algorithm uses
* not only the user's password but also a randomly generated string. The string is
* stored as the first N characters of the hash for reference of hashing algorithms later.
*
* @param int $length The length of the salt string to generate.
* @return string The generated salt string.
* @throws \Random\RandomException
*/
function random_salt(int $length): string
{
$str = bin2hex(random_bytes(ceil($length/2)));
if ($length%2 === 1)
return substr($str,0,-1);
return $str;
}

View File

@ -1757,32 +1757,6 @@ function expand_dn_with_base($base,$sub_dn) {
return sprintf('%s%s',$sub_dn,$base); return sprintf('%s%s',$sub_dn,$base);
} }
/**
* Used to generate a random salt for crypt-style passwords. Salt strings are used
* to make pre-built hash cracking dictionaries difficult to use as the hash algorithm uses
* not only the user's password but also a randomly generated string. The string is
* stored as the first N characters of the hash for reference of hashing algorithms later.
*
* @param int The length of the salt string to generate.
* @return string The generated salt string.
*/
function random_salt($length) {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs);
$possible = '0123456789'.
'abcdefghijklmnopqrstuvwxyz'.
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.
'./';
$str = '';
mt_srand((double)microtime() * 1000000);
while (strlen($str) < $length)
$str .= substr($possible,(rand()%strlen($possible)),1);
return $str;
}
/** /**
* Split an RDN into its attributes * Split an RDN into its attributes
*/ */
@ -1999,368 +1973,6 @@ function draw_jpeg_photo($server,$dn,$attr_name='jpegphoto',$index,$draw_delete_
$attr_name,_('Delete photo')); $attr_name,_('Delete photo'));
} }
/**
* Return the list of available password types
*
* @todo Dynamically work this list out so we only present hashes that we can encrypt
*/
function password_types() {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs);
return array(
''=>'clear',
'bcrypt'=>'bcrypt',
'blowfish'=>'blowfish',
'crypt'=>'crypt',
'ext_des'=>'ext_des',
'md5'=>'md5',
'k5key'=>'k5key',
'md5crypt'=>'md5crypt',
'sha'=>'sha',
'smd5'=>'smd5',
'ssha'=>'ssha',
'sha512'=>'sha512',
'sha256crypt'=>'sha256crypt',
'sha512crypt'=>'sha512crypt',
);
}
/**
* Hashes a password and returns the hash based on the specified enc_type.
*
* @param string The password to hash in clear text.
* @param string Standard LDAP encryption type which must be one of
* crypt, ext_des, md5crypt, blowfish, md5, sha, smd5, ssha, sha512,
* sha256crypt, sha512crypt, or clear.
* @return string The hashed password.
*/
function pla_password_hash($password_clear,$enc_type) {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs);
$enc_type = strtolower($enc_type);
switch($enc_type) {
case 'blowfish':
if (! defined('CRYPT_BLOWFISH') || CRYPT_BLOWFISH == 0)
error(_('Your system crypt library does not support blowfish encryption.'),'error','index.php');
# Hardcoded to second blowfish version and set number of rounds
$new_value = sprintf('{CRYPT}%s',crypt($password_clear,'$2a$12$'.random_salt(13)));
break;
case 'crypt':
if ($_SESSION[APPCONFIG]->getValue('password', 'no_random_crypt_salt'))
$new_value = sprintf('{CRYPT}%s',crypt($password_clear,substr($password_clear,0,2)));
else
$new_value = sprintf('{CRYPT}%s',crypt($password_clear,random_salt(2)));
break;
case 'ext_des':
# Extended des crypt. see OpenBSD crypt man page.
if (! defined('CRYPT_EXT_DES') || CRYPT_EXT_DES == 0)
error(_('Your system crypt library does not support extended DES encryption.'),'error','index.php');
$new_value = sprintf('{CRYPT}%s',crypt($password_clear,'_'.random_salt(8)));
break;
case 'k5key':
$new_value = sprintf('{K5KEY}%s',$password_clear);
system_message(array(
'title'=>_('Unable to Encrypt Password'),
'body'=>'phpLDAPadmin cannot encrypt K5KEY passwords',
'type'=>'warn'));
break;
case 'md5':
$new_value = sprintf('{MD5}%s',base64_encode(pack('H*',md5($password_clear))));
break;
case 'md5crypt':
if (! defined('CRYPT_MD5') || CRYPT_MD5 == 0)
error(_('Your system crypt library does not support md5crypt encryption.'),'error','index.php');
$new_value = sprintf('{CRYPT}%s',crypt($password_clear,'$1$'.random_salt(9)));
break;
case 'sha':
# Use php 4.3.0+ sha1 function, if it is available.
if (function_exists('sha1'))
$new_value = sprintf('{SHA}%s',base64_encode(pack('H*',sha1($password_clear))));
elseif (function_exists('mhash'))
$new_value = sprintf('{SHA}%s',base64_encode(mhash(MHASH_SHA1,$password_clear)));
else
error(_('Your PHP install does not have the mhash() function. Cannot do SHA hashes.'),'error','index.php');
break;
case 'ssha':
if (function_exists('mhash') && function_exists('mhash_keygen_s2k')) {
mt_srand((double)microtime()*1000000);
$salt = mhash_keygen_s2k(MHASH_SHA1,$password_clear,substr(pack('h*',md5(mt_rand())),0,8),4);
$new_value = sprintf('{SSHA}%s',base64_encode(mhash(MHASH_SHA1,$password_clear.$salt).$salt));
} else {
error(_('Your PHP install does not have the mhash() or mhash_keygen_s2k() function. Cannot do S2K hashes.'),'error','index.php');
}
break;
case 'bcrypt':
$options = [
'cost' => 8,
];
#Checking if password_hash() function is available.
if (function_exists('password_hash'))
$new_value = sprintf('{BCRYPT}%s',base64_encode(password_hash($password_clear, PASSWORD_BCRYPT, $options)));
else
error(_('Your PHP install does not have the password_hash() function. Cannot do BCRYPT hashes.'),'error','index.php');
break;
case 'smd5':
if (function_exists('mhash') && function_exists('mhash_keygen_s2k')) {
mt_srand((double)microtime()*1000000);
$salt = mhash_keygen_s2k(MHASH_MD5,$password_clear,substr(pack('h*',md5(mt_rand())),0,8),4);
$new_value = sprintf('{SMD5}%s',base64_encode(mhash(MHASH_MD5,$password_clear.$salt).$salt));
} else {
error(_('Your PHP install does not have the mhash() or mhash_keygen_s2k() function. Cannot do S2K hashes.'),'error','index.php');
}
break;
case 'sha512':
if (function_exists('openssl_digest') && function_exists('base64_encode')) {
$new_value = sprintf('{SHA512}%s', base64_encode(openssl_digest($password_clear, 'sha512', true)));
} else {
error(_('Your PHP install doest not have the openssl_digest() or base64_encode() function. Cannot do SHA512 hashes. '),'error','index.php');
}
break;
case 'sha256crypt':
if (! defined('CRYPT_SHA256') || CRYPT_SHA256 == 0)
error(_('Your system crypt library does not support sha256crypt encryption.'),'error','index.php');
$new_value = sprintf('{CRYPT}%s',crypt($password_clear,'$5$'.random_salt(8)));
break;
case 'sha512crypt':
if (! defined('CRYPT_SHA512') || CRYPT_SHA512 == 0)
error(_('Your system crypt library does not support sha512crypt encryption.'),'error','index.php');
$new_value = sprintf('{CRYPT}%s',crypt($password_clear,'$6$'.random_salt(8)));
break;
case 'clear':
default:
$new_value = $password_clear;
}
return $new_value;
}
/**
* Given a clear-text password and a hash, this function determines if the clear-text password
* is the password that was used to generate the hash. This is handy to verify a user's password
* when all that is given is the hash and a "guess".
* @param String The hash.
* @param String The password in clear text to test.
* @return Boolean True if the clear password matches the hash, and false otherwise.
*/
function password_check($cryptedpassword,$plainpassword,$attribute='userpassword') {
$plainpassword = htmlspecialchars_decode($plainpassword);
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',1,0,__FILE__,__LINE__,__METHOD__,$fargs);
if (in_array($attribute,array('sambalmpassword','sambantpassword'))) {
$smb = new smbHash;
switch($attribute) {
case 'sambalmpassword':
if (strcmp($smb->lmhash($plainpassword),strtoupper($cryptedpassword)) == 0)
return true;
else
return false;
case 'sambantpassword':
if (strcmp($smb->nthash($plainpassword),strtoupper($cryptedpassword)) == 0)
return true;
else
return false;
}
return false;
}
if (preg_match('/{([^}]+)}(.*)/',$cryptedpassword,$matches)) {
$cryptedpassword = $matches[2];
$cypher = strtolower($matches[1]);
} else {
$cypher = null;
}
switch($cypher) {
# SSHA crypted passwords
case 'ssha':
# Check php mhash support before using it
if (function_exists('mhash')) {
$hash = base64_decode($cryptedpassword);
# OpenLDAP uses a 4 byte salt, SunDS uses an 8 byte salt - both from char 20.
$salt = substr($hash,20);
$new_hash = base64_encode(mhash(MHASH_SHA1,$plainpassword.$salt).$salt);
if (strcmp($cryptedpassword,$new_hash) == 0)
return true;
else
return false;
} else {
error(_('Your PHP install does not have the mhash() function. Cannot do SHA hashes.'),'error','index.php');
}
break;
#BCRYPT hashed passwords
case 'bcrypt':
# Check php password_verify support before using it
if (function_exists('password_verify')) {
$hash = base64_decode($cryptedpassword);
if (password_verify($plainpassword, $hash)) {
return true;
} else {
return false;
}
} else {
error(_('Your PHP install does not have the password_verify() function. Cannot do Bcrypt hashes.'),'error','index.php');
}
break;
# Salted MD5
case 'smd5':
# Check php mhash support before using it
if (function_exists('mhash')) {
$hash = base64_decode($cryptedpassword);
$salt = substr($hash,16);
$new_hash = base64_encode(mhash(MHASH_MD5,$plainpassword.$salt).$salt);
if (strcmp($cryptedpassword,$new_hash) == 0)
return true;
else
return false;
} else {
error(_('Your PHP install does not have the mhash() function. Cannot do SHA hashes.'),'error','index.php');
}
break;
# SHA crypted passwords
case 'sha':
if (strcasecmp(pla_password_hash($plainpassword,'sha'),'{SHA}'.$cryptedpassword) == 0)
return true;
else
return false;
break;
# MD5 crypted passwords
case 'md5':
if( strcasecmp(pla_password_hash($plainpassword,'md5'),'{MD5}'.$cryptedpassword) == 0)
return true;
else
return false;
break;
# Crypt passwords
case 'crypt':
# Check if it's blowfish crypt
if (preg_match('/^\\$2+/',$cryptedpassword)) {
# Make sure that web server supports blowfish crypt
if (! defined('CRYPT_BLOWFISH') || CRYPT_BLOWFISH == 0)
error(_('Your system crypt library does not support blowfish encryption.'),'error','index.php');
list($version,$rounds,$salt_hash) = explode('$',$cryptedpassword);
if (crypt($plainpassword,'$'.$version.'$'.$rounds.'$'.$salt_hash) == $cryptedpassword)
return true;
else
return false;
}
# Check if it's an crypted md5
elseif (strstr($cryptedpassword,'$1$')) {
# Make sure that web server supports md5 crypt
if (! defined('CRYPT_MD5') || CRYPT_MD5 == 0)
error(_('Your system crypt library does not support md5crypt encryption.'),'error','index.php');
list($dummy,$type,$salt,$hash) = explode('$',$cryptedpassword);
if (crypt($plainpassword,'$1$'.$salt) == $cryptedpassword)
return true;
else
return false;
}
# Check if it's extended des crypt
elseif (strstr($cryptedpassword,'_')) {
# Make sure that web server supports ext_des
if (! defined('CRYPT_EXT_DES') || CRYPT_EXT_DES == 0)
error(_('Your system crypt library does not support extended DES encryption.'),'error','index.php');
if (crypt($plainpassword,$cryptedpassword) == $cryptedpassword)
return true;
else
return false;
}
# Password is plain crypt
else {
if (crypt($plainpassword,$cryptedpassword) == $cryptedpassword)
return true;
else
return false;
}
break;
# SHA512 crypted passwords
case 'sha512':
if (strcasecmp(pla_password_hash($plainpassword,'sha512'),'{SHA512}'.$cryptedpassword) == 0)
return true;
else
return false;
break;
# No crypt is given assume plaintext passwords are used
default:
if ($plainpassword == $cryptedpassword)
return true;
else
return false;
}
}
/** /**
* Detects password encryption type * Detects password encryption type
* *

View File

@ -9,7 +9,7 @@ div#userpassword .select2-container--bootstrap-5 .select2-selection {
font-size: inherit; font-size: inherit;
border-bottom-right-radius: unset; border-bottom-right-radius: unset;
border-top-right-radius: unset; border-top-right-radius: unset;
width: 7em; width: 9em;
border: #444054 1px solid; border: #444054 1px solid;
background-color: #f0f0f0; background-color: #f0f0f0;
} }

View File

@ -3,7 +3,7 @@
@foreach($o->values as $value) @foreach($o->values as $value)
@if($edit) @if($edit)
<div class="input-group has-validation mb-3"> <div class="input-group has-validation mb-3">
<x-form.select class="password" id="userpassword_hash_{{$loop->index}}" name="userpassword_hash[]" :value="$o->hash_id($value)" :options="$helpers" allowclear="false" disabled="true"/> <x-form.select id="userpassword_hash_{{$loop->index}}" name="userpassword_hash[]" :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.'.'.$loop->index)),'mb-1','border-focus'=>$o->values->contains($value)]) name="{{ $o->name_lc }}[]" value="{{ md5($value) }}" @readonly(true)> <input type="password" @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="{{ md5($value) }}" @readonly(true)>
<div class="invalid-feedback pb-2"> <div class="invalid-feedback pb-2">
@ -13,7 +13,7 @@
</div> </div>
</div> </div>
@else @else
{{ (($x=$o->hash_id($value)) && ($x !== 'Clear')) ? sprintf('{%s}',$x) : '' }}{{ str_repeat('x',8) }} {{ (($x=$o->hash($value)) && ($x::id() !== '*clear*')) ? sprintf('{%s}',$x::shortid()) : '' }}{{ str_repeat('*',16) }}
@endif @endif
@endforeach @endforeach
</x-attribute.layout> </x-attribute.layout>

View File

@ -1,6 +1,6 @@
<x-form.base {{ $attributes }}> <x-form.base {{ $attributes }}>
@isset($name) @isset($name)
<input type="hidden" id="{{ $name }}_disabled" name="{{ $name }}" value="" disabled> <input type="hidden" id="{{ $id ?? $name }}_disabled" name="{{ $name }}" value="" disabled>
@endisset @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)> <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) || isset($addnew) || isset($choose))

View File

@ -2,10 +2,9 @@
<div class="alert alert-success"> <div class="alert alert-success">
<h4 class="alert-heading"><i class="fas fa-fw fa-thumbs-up"></i> Success!</h4> <h4 class="alert-heading"><i class="fas fa-fw fa-thumbs-up"></i> Success!</h4>
<hr> <hr>
<p>{{ session()->pull('success') }}</p>
<ul style="list-style-type: square;"> <ul style="list-style-type: square;">
@foreach (session()->pull('updated') as $key => $values) @foreach (session()->get('success') as $item)
<li>{{ $key }}: {{ join(',',$values) }}</li> <li>{{ $item }}</li>
@endforeach @endforeach
</ul> </ul>
</div> </div>

View File

@ -0,0 +1,12 @@
@if(session()->has('updated'))
<div class="alert alert-success">
<h4 class="alert-heading"><i class="fas fa-fw fa-thumbs-up"></i> Success!</h4>
<hr>
<p>{{ __('Entry updated') }}</p>
<ul style="list-style-type: square;">
@foreach (session()->pull('updated') as $key => $o)
<li><abbr title="{{ $o->description }}">{{ $o->name }}</abbr>: {{ $o->values->map(fn($item,$key)=>$o->render_item_new($key))->join(',') }}</li>
@endforeach
</ul>
</div>
@endif

View File

@ -6,7 +6,7 @@
@section('main-content') @section('main-content')
<x-note/> <x-note/>
<x-success/> <x-updated/>
<x-error/> <x-error/>
<!-- @todo If we are redirected here, check old() and add back any attributes that were in the original submission --> <!-- @todo If we are redirected here, check old() and add back any attributes that were in the original submission -->
@ -136,7 +136,7 @@
@if($up=$o->getObject('userpassword')) @if($up=$o->getObject('userpassword'))
<!-- CHECK 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-md modal-fullscreen-md-down"> <div class="modal-dialog modal-lg modal-fullscreen-lg-down">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <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>
@ -148,7 +148,7 @@
@foreach($up->values as $key => $value) @foreach($up->values as $key => $value)
<tr> <tr>
<th>Check</th> <th>Check</th>
<td>{{ (($xx=$up->hash_id($value)) && ($xx !== 'Clear')) ? sprintf('{%s}',$xx) : '' }}{{ str_repeat('x',8) }}</td> <td>{{ $up->render_item_old($key) }}</td>
<td> <td>
<input type="password" style="width: 90%" name="password[{{$key}}]"> <i class="fas fa-fw fa-lock"></i> <input type="password" style="width: 90%" name="password[{{$key}}]"> <i class="fas fa-fw fa-lock"></i>
<div class="invalid-feedback pb-2"> <div class="invalid-feedback pb-2">