Skip to content

Commit

Permalink
fix Ldap.php and Password.php functions + add tests (#11)
Browse files Browse the repository at this point in the history
  • Loading branch information
David Coutadeur authored and davidcoutadeur committed Apr 2, 2024
1 parent f979f92 commit 70eacb6
Show file tree
Hide file tree
Showing 5 changed files with 396 additions and 60 deletions.
43 changes: 23 additions & 20 deletions src/Ltb/Ldap.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

final class Ldap {

# LDAP Functions
# LDAP Functions

static function connect($ldap_url, $ldap_starttls, $ldap_binddn, $ldap_bindpw, $ldap_network_timeout, $ldap_krb5ccname) {

Expand Down Expand Up @@ -136,23 +136,24 @@ static function sorted_search($ldap, $ldap_base, $ldap_filter, $attributes, $sor

return array($ldap_result,$errno,$entries);
}

/**
* Gets the value of the password attribute
* @param \LDAP\Connection|array $ldap An LDAP\Connection instance, returned by ldap_connect()
* @param \LDAP\Connection $ldap An LDAP\Connection instance, returned by ldap_connect()
* @param string $dn the dn of the user
* @param type $pwdattribute the Attribute that contains the password
* @return string the value of $pwdattribute
* @param string $pwdattribute the Attribute that contains the password
* @return array|false the values of the password, as returned by ldap_get_values
*/
static function get_password_value($ldap, $dn, $pwdattribute): string {
static function get_password_values($ldap, $dn, $pwdattribute): array|false {
$search_userpassword = \Ltb\PhpLDAP::ldap_read($ldap, $dn, "(objectClass=*)", array($pwdattribute));
if ($search_userpassword) {
return \Ltb\PhpLDAP::ldap_get_values($ldap, ldap_first_entry($ldap, $search_userpassword), $pwdattribute);
return \Ltb\PhpLDAP::ldap_get_values($ldap, \Ltb\PhpLDAP::ldap_first_entry($ldap, $search_userpassword), $pwdattribute);
}
return false;
}

/**
* Changes the password of an user while binded as the user in an Active Directory
* Changes the password of a user while binded as the user in an Active Directory
* @param \LDAP\Connection|array $ldap An LDAP\Connection instance, returned by ldap_connect()
* @param string $dn the dn of the user
* @param string $oldpassword the old password
Expand All @@ -163,7 +164,7 @@ static function change_ad_password_as_user($ldap, $dn, $oldpassword, $password):
# The AD password change procedure is modifying the attribute unicodePwd by
# first deleting unicodePwd with the old password and them adding it with the
# the new password
$oldpassword_hashed = make_ad_password($oldpassword);
$oldpassword_hashed = \Ltb\Password::make_ad_password($oldpassword);

$modifications = array(
array(
Expand All @@ -175,15 +176,15 @@ static function change_ad_password_as_user($ldap, $dn, $oldpassword, $password):
"attrib" => "unicodePwd",
"modtype" => LDAP_MODIFY_BATCH_ADD,
"values" => array($password),
),
)
);

\Ltb\PhpLDAP::ldap_modify_batch($ldap, $dn, $modifications);
$error_code = ldap_errno($ldap);
$error_msg = ldap_error($ldap);
$error_code = \Ltb\PhpLDAP::ldap_errno($ldap);
$error_msg = \Ltb\PhpLDAP::ldap_error($ldap);
return array($error_code, $error_msg);
}

static protected function get_ppolicy_error_code($ctrls) {
if (isset($ctrls[LDAP_CONTROL_PASSWORDPOLICYRESPONSE])) {
$value = $ctrls[LDAP_CONTROL_PASSWORDPOLICYRESPONSE]['value'];
Expand Down Expand Up @@ -224,17 +225,19 @@ static function change_password_with_exop($ldap, $dn, $oldpassword, $password, $
}
return array($error_code, $error_msg, $ppolicy_error_code);
}

/**
* Changes attributes (and password) using Password Policy Control
* Changes attributes (and possibly password) using Password Policy Control
* @param \LDAP\Connection|array $ldap An LDAP\Connection instance, returned by ldap_connect()
* @param string $dn the dn of the user
* @param array $userdata the array, containing the new (hashed) password
* @param array $userdata the array, containing the modifications
* @return array 0: error_code, 1: error_msg, 2: ppolicy_error_code
*/
static function modify_attributes_using_ppolicy($ldap, $dn, $userdata): array {
$error_code = "";
$error_msg = "";
$matcheddn = null;
$referrals = array();
$ctrls = array();
$ppolicy_error_code = false;
$ppolicy_replace = \Ltb\PhpLDAP::ldap_mod_replace_ext($ldap, $dn, $userdata, [['oid' => LDAP_CONTROL_PASSWORDPOLICYREQUEST]]);
Expand All @@ -243,7 +246,7 @@ static function modify_attributes_using_ppolicy($ldap, $dn, $userdata): array {
}
return array($error_code, $error_msg, $ppolicy_error_code);
}

/**
* Changes attributes (and password)
* @param \LDAP\Connection|array $ldap An LDAP\Connection instance, returned by ldap_connect()
Expand All @@ -253,8 +256,8 @@ static function modify_attributes_using_ppolicy($ldap, $dn, $userdata): array {
*/
static function modify_attributes($ldap, $dn, $userdata): array {
\Ltb\PhpLDAP::ldap_mod_replace($ldap, $dn, $userdata);
$error_code = ldap_errno($ldap);
$error_msg = ldap_error($ldap);
$error_code = \Ltb\PhpLDAP::ldap_errno($ldap);
$error_msg = \Ltb\PhpLDAP::ldap_error($ldap);
return array($error_code, $error_msg);
}

Expand Down
38 changes: 19 additions & 19 deletions src/Ltb/Password.php
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
<?php namespace Ltb;

/**
*
* Password functions
*/
final class Password {
# Create SSHA password
static function make_ssha_password($password): string {
$salt = random_bytes(4);
return "{SSHA}" . base64_encode(pack("H*", sha1($password . $salt)) . $salt);
}

static function check_ssha_password($password, $hash): bool {
$salt = substr(base64_decode(substr($hash, 6)), 20);
$hash2 = "{SSHA}" . base64_encode(pack("H*", sha1($password . $salt)) . $salt);
Expand All @@ -21,7 +21,7 @@ static function make_ssha256_password($password): string {
$salt = random_bytes(4);
return "{SSHA256}" . base64_encode(pack("H*", hash('sha256', $password . $salt)) . $salt);
}

static function check_ssha256_password($password, $hash): bool {
$salt = substr(base64_decode(substr($hash, 9)), 32);
$hash2 = "{SSHA256}".base64_encode(hash('sha256', $password.$salt, true).$salt);
Expand All @@ -33,7 +33,7 @@ static function make_ssha384_password($password): string {
$salt = random_bytes(4);
return "{SSHA384}" . base64_encode(pack("H*", hash('sha384', $password . $salt)) . $salt);
}

static function check_ssha384_password($password, $hash): bool {
$salt = substr(base64_decode(substr($hash, 9)), 48);
$hash2 = "{SSHA384}".base64_encode(hash('sha384', $password.$salt, true).$salt);
Expand All @@ -45,7 +45,7 @@ static function make_ssha512_password($password): string {
$salt = random_bytes(4);
return "{SSHA512}" . base64_encode(pack("H*", hash('sha512', $password . $salt)) . $salt);
}

static function check_ssha512_password($password, $hash): bool {
$salt = substr(base64_decode(substr($hash, 9)), 64); //salt of given hash (remove {SSHA512}, decode it, and only the bits after 512/8=64 bits)
$hash2 = "{SSHA512}".base64_encode(hash('sha512', $password.$salt, true).$salt);
Expand All @@ -56,7 +56,7 @@ static function check_ssha512_password($password, $hash): bool {
static function make_sha_password($password): string {
return "{SHA}" . base64_encode(pack("H*", sha1($password)));
}

static function check_sha_password($password, $hash): bool {
return ($hash === self::make_sha_password($password));
}
Expand All @@ -65,7 +65,7 @@ static function check_sha_password($password, $hash): bool {
static function make_sha256_password($password): string {
return "{SHA256}" . base64_encode(pack("H*", hash('sha256', $password)));
}

static function check_sha256_password($password, $hash): bool {
return ($hash === self::make_sha256_password($password));
}
Expand All @@ -74,7 +74,7 @@ static function check_sha256_password($password, $hash): bool {
static function make_sha384_password($password): string {
return "{SHA384}" . base64_encode(pack("H*", hash('sha384', $password)));
}

static function check_sha384_password($password, $hash): bool {
return ($hash === self::make_sha384_password($password));
}
Expand All @@ -83,7 +83,7 @@ static function check_sha384_password($password, $hash): bool {
static function make_sha512_password($password): string {
return "{SHA512}" . base64_encode(pack("H*", hash('sha512', $password)));
}

static function check_sha512_password($password, $hash): bool {
return ($hash === self::make_sha512_password($password));
}
Expand All @@ -93,7 +93,7 @@ static function make_smd5_password($password): string {
$salt = random_bytes(4);
return "{SMD5}" . base64_encode(pack("H*", md5($password . $salt)) . $salt);
}

static function check_smd5_password($password, $hash): bool {
$salt = substr(base64_decode(substr($hash, 6)), 16);
$hash2 = "{SMD5}" . base64_encode(pack("H*", md5($password . $salt)) . $salt);
Expand All @@ -104,7 +104,7 @@ static function check_smd5_password($password, $hash): bool {
static function make_md5_password($password): string {
return "{MD5}" . base64_encode(pack("H*", md5($password)));
}

static function check_md5_password($password, $hash): bool {
return ($hash === self::make_md5_password($password));
}
Expand Down Expand Up @@ -134,20 +134,20 @@ static function make_crypt_password($password, $hash_options): string {

return '{CRYPT}' . crypt( $password, $salt);
}

static function check_crypt_password($password, $hash): bool {
return password_verify($password, substr($hash, 7));
}

# Create ARGON2 password
static function make_argon2_password($password, $hash_options): string {
if (!isset($hash_options['memory_cost'])) { $hash_options['memory_cost'] = 4096; }
if (!isset($hash_options['time_cost'])) { $hash_options['time_cost'] = 3; }
if (!isset($hash_options['memory_cost'])) { $hash_options['memory_cost'] = 4096; }
if (!isset($hash_options['time_cost'])) { $hash_options['time_cost'] = 3; }
if (!isset($hash_options['threads'])) { $hash_options['threads'] = 1; }

return '{ARGON2}' . password_hash($password,PASSWORD_ARGON2I,$hash_options);
}

static function check_argon2_password($password, $hash): bool {
return password_verify($password, substr($hash, 8));
}
Expand All @@ -160,7 +160,7 @@ static function make_md4_password($password): string {
return strtoupper( bin2hex( mhash( MHASH_MD4, iconv( "UTF-8", "UTF-16LE", $password ) ) ) );
}
}

static function check_md4_password($password, $hash): bool {
return ($hash === self::make_md4_password($password));
}
Expand Down Expand Up @@ -272,7 +272,7 @@ static function get_hash_type($userpassword): string {
}
return "";
}

static function set_samba_data($userdata, $samba_options, $password, $time): array {
$userdata["sambaNTPassword"] = self::make_md4_password($password);
$userdata["sambaPwdLastSet"] = $time;
Expand All @@ -287,7 +287,7 @@ static function set_samba_data($userdata, $samba_options, $password, $time): arr
}
return $userdata;
}

static function set_ad_data($userdata, $ad_options, $password): array {
$userdata["unicodePwd"] = $password;
if ( $ad_options['force_unlock'] ) {
Expand All @@ -298,7 +298,7 @@ static function set_ad_data($userdata, $ad_options, $password): array {
}
return $userdata;
}

static function set_shadow_data($userdata, $shadow_options, $time): array {
if ( $shadow_options['update_shadowLastChange'] ) {
$userdata["shadowLastChange"] = floor($time / 86400);
Expand Down
37 changes: 21 additions & 16 deletions src/Ltb/PhpLDAP.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,31 +70,36 @@ public static function ldap_count_entries($ldap, $result)
{
return ldap_count_entries($ldap, $result);
}
public static function ldap_modify_batch($ldap, $dn, $modifications)

public static function ldap_modify_batch(...$args)
{
return ldap_modify_batch($ldap, $dn, $modifications);
return ldap_modify_batch(...$args);
}
public static function ldap_exop_passwd($ldap, $dn, $oldpassword, $password, $ctrls)

public static function ldap_exop_passwd(...$args)
{
return ldap_exop_passwd($ldap, $dn, $oldpassword, $password, $ctrls);
return ldap_exop_passwd(...$args);
}
public static function ldap_mod_replace_ext($ldap, $dn, $userdata, $ctrls)

public static function ldap_mod_replace_ext(...$args)
{
return ldap_mod_replace_ext($ldap, $dn, $userdata, $ctrls);
return ldap_mod_replace_ext(...$args);
}
public static function ldap_parse_result($ldap, $ppolicy_replace, $error_code, $matcheddn, $error_msg, $referrals, $ctrls)

public static function ldap_parse_result(...$args)
{
return ldap_parse_result($ldap, $ppolicy_replace, $error_code, $matcheddn, $error_msg, $referrals, $ctrls);
return ldap_parse_result(...$args);
}
public static function ldap_mod_replace($ldap, $dn, $userdata)

public static function ldap_mod_replace(...$args)
{
return ldap_mod_replace($ldap, $dn, $userdata);
return ldap_mod_replace(...$args);
}


public static function ldap_first_entry($ldap, $entry, $attribute)
{
return ldap_first_entry($ldap, $entry, $attribute);
}

}
?>
Loading

0 comments on commit 70eacb6

Please sign in to comment.