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
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:
parent
77a139016b
commit
d3d7881e3b
@ -6,7 +6,6 @@ use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
use App\Classes\LDAP\Attribute\Password\Base;
|
||||
use App\Classes\LDAP\Attribute;
|
||||
use App\Traits\MD5Updates;
|
||||
|
||||
@ -28,41 +27,54 @@ final class Password extends Attribute
|
||||
continue;
|
||||
|
||||
$class = self::commands.preg_replace('/\.php$/','',$file);
|
||||
if ($helpers->count())
|
||||
$helpers->push('');
|
||||
|
||||
$helpers = $helpers
|
||||
->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
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
{
|
||||
return view('components.attribute.password')
|
||||
@ -75,11 +87,17 @@ final class Password extends Attribute
|
||||
|
||||
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
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
25
app/Classes/LDAP/Attribute/Password/Argon2i.php
Normal file
25
app/Classes/LDAP/Attribute/Password/Argon2i.php
Normal 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)));
|
||||
}
|
||||
}
|
25
app/Classes/LDAP/Attribute/Password/Argon2id.php
Normal file
25
app/Classes/LDAP/Attribute/Password/Argon2id.php
Normal 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)));
|
||||
}
|
||||
}
|
@ -4,11 +4,65 @@ namespace App\Classes\LDAP\Attribute\Password;
|
||||
|
||||
abstract class Base
|
||||
{
|
||||
abstract public function compare(string $source,string $compare): bool;
|
||||
protected const subkey = '';
|
||||
|
||||
abstract public function encode(string $password): 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
22
app/Classes/LDAP/Attribute/Password/Bcrypt.php
Normal file
22
app/Classes/LDAP/Attribute/Password/Bcrypt.php
Normal 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)));
|
||||
}
|
||||
}
|
@ -4,12 +4,7 @@ namespace App\Classes\LDAP\Attribute\Password;
|
||||
|
||||
final class Clear extends Base
|
||||
{
|
||||
public const key = 'Clear';
|
||||
|
||||
public function compare(string $source,string $compare): bool
|
||||
{
|
||||
return $source === $compare;
|
||||
}
|
||||
public const key = '*clear*';
|
||||
|
||||
public function encode(string $password): string
|
||||
{
|
||||
|
13
app/Classes/LDAP/Attribute/Password/MD5.php
Normal file
13
app/Classes/LDAP/Attribute/Password/MD5.php
Normal 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)));
|
||||
}
|
||||
}
|
13
app/Classes/LDAP/Attribute/Password/SHA.php
Normal file
13
app/Classes/LDAP/Attribute/Password/SHA.php
Normal 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)));
|
||||
}
|
||||
}
|
13
app/Classes/LDAP/Attribute/Password/SHA256.php
Normal file
13
app/Classes/LDAP/Attribute/Password/SHA256.php
Normal 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)));
|
||||
}
|
||||
}
|
13
app/Classes/LDAP/Attribute/Password/SHA384.php
Normal file
13
app/Classes/LDAP/Attribute/Password/SHA384.php
Normal 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)));
|
||||
}
|
||||
}
|
13
app/Classes/LDAP/Attribute/Password/SHA512.php
Normal file
13
app/Classes/LDAP/Attribute/Password/SHA512.php
Normal 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)));
|
||||
}
|
||||
}
|
22
app/Classes/LDAP/Attribute/Password/SMD5.php
Normal file
22
app/Classes/LDAP/Attribute/Password/SMD5.php
Normal 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));
|
||||
}
|
||||
}
|
19
app/Classes/LDAP/Attribute/Password/SSHA.php
Normal file
19
app/Classes/LDAP/Attribute/Password/SSHA.php
Normal 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));
|
||||
}
|
||||
}
|
19
app/Classes/LDAP/Attribute/Password/SSHA256.php
Normal file
19
app/Classes/LDAP/Attribute/Password/SSHA256.php
Normal 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));
|
||||
}
|
||||
}
|
19
app/Classes/LDAP/Attribute/Password/SSHA384.php
Normal file
19
app/Classes/LDAP/Attribute/Password/SSHA384.php
Normal 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));
|
||||
}
|
||||
}
|
19
app/Classes/LDAP/Attribute/Password/SSHA512.php
Normal file
19
app/Classes/LDAP/Attribute/Password/SSHA512.php
Normal 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));
|
||||
}
|
||||
}
|
@ -99,11 +99,11 @@ class HomeController extends Controller
|
||||
|
||||
$result = collect();
|
||||
foreach ($password as $key => $value) {
|
||||
$type = $password->hash_id($value);
|
||||
$hash = $password->hash($value);
|
||||
$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;
|
||||
@ -128,9 +128,15 @@ class HomeController extends Controller
|
||||
// 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 ($value) {
|
||||
$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;
|
||||
@ -199,8 +205,7 @@ class HomeController extends Controller
|
||||
|
||||
return Redirect::to('/')
|
||||
->withInput()
|
||||
->with('success',__('Entry updated'))
|
||||
->with('updated',$dirty);
|
||||
->with('updated',collect($dirty)->map(fn($key,$item)=>$o->getObject($item)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -11,3 +11,22 @@ function login_attr_name(): string
|
||||
{
|
||||
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;
|
||||
}
|
@ -1757,32 +1757,6 @@ function expand_dn_with_base($base,$sub_dn) {
|
||||
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
|
||||
*/
|
||||
@ -1999,368 +1973,6 @@ function draw_jpeg_photo($server,$dn,$attr_name='jpegphoto',$index,$draw_delete_
|
||||
$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
|
||||
*
|
||||
|
2
public/css/custom.css
vendored
2
public/css/custom.css
vendored
@ -9,7 +9,7 @@ div#userpassword .select2-container--bootstrap-5 .select2-selection {
|
||||
font-size: inherit;
|
||||
border-bottom-right-radius: unset;
|
||||
border-top-right-radius: unset;
|
||||
width: 7em;
|
||||
width: 9em;
|
||||
border: #444054 1px solid;
|
||||
background-color: #f0f0f0;
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
@foreach($o->values as $value)
|
||||
@if($edit)
|
||||
<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)>
|
||||
|
||||
<div class="invalid-feedback pb-2">
|
||||
@ -13,7 +13,7 @@
|
||||
</div>
|
||||
</div>
|
||||
@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
|
||||
@endforeach
|
||||
</x-attribute.layout>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<x-form.base {{ $attributes }}>
|
||||
@isset($name)
|
||||
<input type="hidden" id="{{ $name }}_disabled" name="{{ $name }}" value="" disabled>
|
||||
<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))
|
||||
|
@ -2,10 +2,9 @@
|
||||
<div class="alert alert-success">
|
||||
<h4 class="alert-heading"><i class="fas fa-fw fa-thumbs-up"></i> Success!</h4>
|
||||
<hr>
|
||||
<p>{{ session()->pull('success') }}</p>
|
||||
<ul style="list-style-type: square;">
|
||||
@foreach (session()->pull('updated') as $key => $values)
|
||||
<li>{{ $key }}: {{ join(',',$values) }}</li>
|
||||
@foreach (session()->get('success') as $item)
|
||||
<li>{{ $item }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
|
12
resources/views/components/updated.blade.php
Normal file
12
resources/views/components/updated.blade.php
Normal 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
|
@ -6,7 +6,7 @@
|
||||
|
||||
@section('main-content')
|
||||
<x-note/>
|
||||
<x-success/>
|
||||
<x-updated/>
|
||||
<x-error/>
|
||||
|
||||
<!-- @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'))
|
||||
<!-- CHECK USERPASSWORD -->
|
||||
<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-header">
|
||||
<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)
|
||||
<tr>
|
||||
<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>
|
||||
<input type="password" style="width: 90%" name="password[{{$key}}]"> <i class="fas fa-fw fa-lock"></i>
|
||||
<div class="invalid-feedback pb-2">
|
||||
|
Loading…
x
Reference in New Issue
Block a user