diff --git a/src/Ltb/Date.php b/src/Ltb/Date.php new file mode 100644 index 0000000..f871b23 --- /dev/null +++ b/src/Ltb/Date.php @@ -0,0 +1,91 @@ +\d{4})'; + // month = ( %x30 %x31-39 ) ; "01" (January) to "09" + // / ( %x31 %x30-32 ) ; "10" to "12" + $month = '(?P0[1-9]|1[0-2])'; + // day = ( %x30 %x31-39 ) ; "01" to "09" + // / ( %x31-32 %x30-39 ) ; "10" to "29" + // / ( %x33 %x30-31 ) ; "30" to "31" + $day = '(?P0[1-9]|[0-2]\d|3[01])'; + // hour = ( %x30-31 %x30-39 ) / ( %x32 %x30-33 ) ; "00" to "23" + $hour = '(?P[0-1]\d|2[0-3])'; + // minute = %x30-35 %x30-39 ; "00" to "59" + $minute = '(?P[0-5]\d)'; + // second = ( %x30-35 %x30-39 ) ; "00" to "59" + // leap-second = ( %x36 %x30 ) ; "60" + $second = '(?P[0-5]\d|60)'; + // fraction = ( DOT / COMMA ) 1*(%x30-39) + $fraction = '([.,](?P\d+))'; + // g-time-zone = %x5A ; "Z" + // / g-differential + // g-differential = ( MINUS / PLUS ) hour [ minute ] + $timezone = '(?PZ|[-+]([0-1]\d|2[0-3])([0-5]\d)?)'; + + // GeneralizedTime = century year month day hour + // [ minute [ second / leap-second ] ] + // [ fraction ] + // g-time-zone + $pattern = '/^'. + "$year$month$day$hour". + "($minute$second?)?". + "$fraction?". + $timezone. + '$/'; + + if (preg_match($pattern, $string, $m)) { + if (empty($m['minute'])) { + $m['minute'] = '00'; + } + if (empty($m['second'])) { + $m['second'] = '00'; + } + if (empty($m['fraction'])) { + $m['fraction'] = '0'; + } + $date = new DateTime($m['year'].'-'.$m['month'].'-'.$m['day'].'T'.$m['hour'].':'.$m['minute'].':'.$m['second'].'.'.$m['fraction'].$m['timezone']); + $date->setTimezone(new DateTimeZone('UTC')); + return $date; + } else { + return false; + } + } + + static function string2ldapDate($string) { + $values = explode("/",$string); + $day = $values[0]; + $month = $values[1]; + $year = $values[2]; + + $ldapdate = $year.$month.$day."000000Z"; + + return $ldapdate; + } + + static function adDate2phpDate($string) { + $winSecs = (int)($string / 10000000); // divide by 10 000 000 to get seconds + $unixTimestamp = ($winSecs - 11644473600); // 1.1.1600 -> 1.1.1970 difference in seconds + $date = new DateTime(); + $date->setTimestamp($unixTimestamp); + return $date; + } + + static function timestamp2adDate($string) { + $adDate = ((int)$string + 11644473600) * 10000000; + return $adDate; + } + +} diff --git a/src/Ltb/Directory.php b/src/Ltb/Directory.php new file mode 100644 index 0000000..20edb5b --- /dev/null +++ b/src/Ltb/Directory.php @@ -0,0 +1,77 @@ +getUnlockDate($ldap, $dn, $config); + + if ($lockoutTime > 0 and !$unlockDate) { + return true; + } + + if ($unlockDate and time() <= $unlockDate->getTimestamp()) { + return true; + } + + return false; + } + + public function getLockDate($ldap, $dn) : ?DateTime { + + $lockDate = NULL; + + # Get entry + $search = \Ltb\PhpLDAP::ldap_read($ldap, $dn, "(objectClass=*)", array('lockouttime')); + $errno = \Ltb\PhpLDAP::ldap_errno($ldap); + + if ( $errno ) { + error_log("LDAP - Search error $errno (".ldap_error($ldap).")"); + return $unlockDate; + } else { + $entry = \Ltb\PhpLDAP::ldap_get_entries($ldap, $search); + } + + # Get lockoutTime + $lockoutTime = $entry[0]['lockouttime'][0]; + + if ( !$lockoutTime or $lockoutTime === 0) { + return $lockDate; + } + + $lockDate = \Ltb\Date::adDate2phpDate($lockoutTime); + return $lockDate; + } + + public function getUnlockDate($ldap, $dn, $config) : ?DateTime { + + $unlockDate = NULL; + + # Get lock date + $lockDate = $this->getLockDate($ldap, $dn); + + if ( !$lockDate ) { + return $unlockDate; + } + + # Get lockout duration + $lockoutDuration = $config["lockout_duration"]; + + # Compute unlock date + if (isset($lockoutDuration) and ($lockoutDuration > 0)) { + $unlockDate = date_add( $lockDate, new DateInterval('PT'.$lockoutDuration.'S')); + } + + return $unlockDate; + } + + public function lockAccount($ldap, $dn) : bool { + + // Not supported by AD + return false; + } + + public function unlockAccount($ldap, $dn) : bool { + + $modification = \Ltb\PhpLdap::ldap_mod_replace($ldap, $dn, array("lockoutTime" => array("0"))); + $errno = ldap_errno($ldap); + + if ( $errno ) { + error_log("LDAP - Unlock account error $errno (".ldap_error($ldap).")"); + return false; + } else { + return true; + } + } + + public function isPasswordExpired($ldap, $dn, $config) : bool { + + # Get entry + $search = \Ltb\PhpLDAP::ldap_read($ldap, $dn, "(objectClass=*)", array('pwdlastset')); + $errno = \Ltb\PhpLDAP::ldap_errno($ldap); + + if ( $errno ) { + error_log("LDAP - Search error $errno (".ldap_error($ldap).")"); + return false; + } else { + $entry = \Ltb\PhpLDAP::ldap_get_entries($ldap, $search); + + } + + # Get pwdLastSet + $pwdLastSet = $entry[0]['pwdlastset'][0]; + + if (!$pwdLastSet) { + return false; + } + + # Get password expiration date + $expirationDate = $this->getPasswordExpirationDate($ldap, $dn, $config); + + if (!$expirationDate) { + return false; + } + + if ($expirationDate and time() >= $expirationDate->getTimestamp()) { + return true; + } + + return false; + } + + public function getPasswordExpirationDate($ldap, $dn, $config) : ?DateTime { + + $expirationDate = NULL; + + # Get entry + $search = \Ltb\PhpLDAP::ldap_read($ldap, $dn, "(objectClass=*)", array('pwdlastset')); + $errno = \Ltb\PhpLDAP::ldap_errno($ldap); + + if ( $errno ) { + error_log("LDAP - Search error $errno (".ldap_error($ldap).")"); + return $expirationDate; + } else { + $entry = \Ltb\PhpLDAP::ldap_get_entries($ldap, $search); + } + + # Get pwdLastSet + $pwdLastSet = $entry[0]['pwdlastset'][0]; + + if ( !$pwdLastSet or $pwdLastSet === 0) { + return $expirationDate; + } + + # Get pwdMaxAge + $pwdMaxAge = $config["password_max_age"]; + + # Compute expiration date + if ($pwdMaxAge) { + $adExpirationDate = $pwdLastSet + ($pwdMaxAge * 10000000); + $expirationDate = \Ltb\Date::adDate2phpDate($adExpirationDate); + } + + return $expirationDate; + } + + public function modifyPassword($ldap, $dn, $password, $forceReset) : bool { + + $adPassword = \Ltb\Password::make_ad_password($password); + $changes = array('unicodePwd' => $adPassword); + + if ($forceReset) { + $changes['pwdLastSet'] = 0; + } + + $update = \Ltb\PhpLDAP::ldap_mod_replace($ldap, $dn, $changes); + $errno = ldap_errno($ldap); + + if ($errno) { + error_log("LDAP - Modify password error $errno (".ldap_error($ldap).")"); + return false; + } else { + return true; + } + } + + public function resetAtNextConnection($ldap, $dn) : bool { + + # Get entry + $search = \Ltb\PhpLDAP::ldap_read($ldap, $dn, "(objectClass=*)", array('pwdlastset')); + $errno = \Ltb\PhpLDAP::ldap_errno($ldap); + + if ( $errno ) { + error_log("LDAP - Search error $errno (".ldap_error($ldap).")"); + return false; + } else { + $entry = \Ltb\PhpLDAP::ldap_get_entries($ldap, $search); + } + + if ($entry[0]['pwdlastset'] and $entry[0]['pwdlastset'][0] === 0) { + return true; + } else { + return false; + } + } + + public function enableAccount($ldap, $dn) : bool { + + # Get entry + $search = \Ltb\PhpLDAP::ldap_read($ldap, $dn, "(objectClass=*)", array('userAccountControl')); + $errno = \Ltb\PhpLDAP::ldap_errno($ldap); + + if ( $errno ) { + error_log("LDAP - Search error $errno (".ldap_error($ldap).")"); + return false; + } else { + $entry = \Ltb\PhpLDAP::ldap_get_entries($ldap, $search); + } + + if ($entry[0]['useraccountcontrol'] and ( $entry[0]['useraccountcontrol'][0] & 2)) { + $newUAC = $entry[0]['useraccountcontrol'][0] & ~2; + $update = \Ltb\PhpLDAP::ldap_mod_replace($ldap, $dn, array( "userAccountControl" => $newUAC)); + $errno = ldap_errno($ldap); + + if ($errno) { + error_log("LDAP - Modify userAccountControl error $errno (".ldap_error($ldap).")"); + return false; + } else { + return true; + } + } else { + return true; + } + } + + public function disableAccount($ldap, $dn) : bool { + + # Get entry + $search = \Ltb\PhpLDAP::ldap_read($ldap, $dn, "(objectClass=*)", array('userAccountControl')); + $errno = \Ltb\PhpLDAP::ldap_errno($ldap); + + if ( $errno ) { + error_log("LDAP - Search error $errno (".ldap_error($ldap).")"); + return false; + } else { + $entry = \Ltb\PhpLDAP::ldap_get_entries($ldap, $search); + } + + if ($entry[0]['useraccountcontrol'] and ( $entry[0]['useraccountcontrol'][0] ^ 2)) { + $newUAC = $entry[0]['useraccountcontrol'][0] | 2; + $update = \Ltb\PhpLDAP::ldap_mod_replace($ldap, $dn, array( "userAccountControl" => $newUAC)); + $errno = ldap_errno($ldap); + + if ($errno) { + error_log("LDAP - Modify userAccountControl error $errno (".ldap_error($ldap).")"); + return false; + } else { + return true; + } + } else { + return true; + } + + } + + public function isAccountEnabled($ldap, $dn) : bool { + + # Get entry + $search = \Ltb\PhpLDAP::ldap_read($ldap, $dn, "(objectClass=*)", array('userAccountControl')); + $errno = \Ltb\PhpLDAP::ldap_errno($ldap); + + if ( $errno ) { + error_log("LDAP - Search error $errno (".ldap_error($ldap).")"); + return false; + } else { + $entry = \Ltb\PhpLDAP::ldap_get_entries($ldap, $search); + } + + if ($entry[0]['useraccountcontrol'] and ( $entry[0]['useraccountcontrol'][0] & 2)) { + return false; + } else { + return true; + } + } + + public function getLdapDate($date) : string { + return \Ltb\Date::timestamp2adDate( $date->getTimeStamp() ); + } + + public function getPwdPolicyConfiguration($ldap, $entry_dn, $default_ppolicy_dn) : Array { + + $ppolicyConfig = array(); + + # Get values from default ppolicy + $search = \Ltb\PhpLDAP::ldap_read($ldap, $default_ppolicy_dn, "(objectClass=*)", array('lockoutDuration', 'maxPwdAge')); + $errno = \Ltb\PhpLDAP::ldap_errno($ldap); + + if ( $errno ) { + error_log("LDAP - Search error $errno (".ldap_error($ldap).")"); + return $ppolicyConfig; + } else { + $entry = \Ltb\PhpLDAP::ldap_get_entries($ldap, $search); + } + + $ppolicyConfig["dn"] = $entry[0]["dn"]; + $ppolicyConfig["lockout_duration"] = $entry[0]["lockoutduration"][0] / -10000000 ; + $ppolicyConfig["password_max_age"] = $entry[0]["maxpwdage"][0] / -10000000; + $ppolicyConfig["lockout_enabled"] = false; + + return $ppolicyConfig; + } +} diff --git a/src/Ltb/Directory/OpenLDAP.php b/src/Ltb/Directory/OpenLDAP.php new file mode 100644 index 0000000..1a4bbb2 --- /dev/null +++ b/src/Ltb/Directory/OpenLDAP.php @@ -0,0 +1,278 @@ +getUnlockDate($ldap, $dn, $config); + + if ( $unlockDate and time() <= $unlockDate->getTimestamp() ) { + return true; + } + + return false; + } + + public function getLockDate($ldap, $dn) : ?DateTime { + + $lockDate = NULL; + + # Get entry + $search = \Ltb\PhpLDAP::ldap_read($ldap, $dn, "(objectClass=*)", array('pwdaccountlockedtime')); + $errno = \Ltb\PhpLDAP::ldap_errno($ldap); + + if ( $errno ) { + error_log("LDAP - Search error $errno (".ldap_error($ldap).")"); + return $lockDate; + } else { + $entry = \Ltb\PhpLDAP::ldap_get_entries($ldap, $search); + } + + # Get pwdAccountLockedTime + $pwdAccountLockedTime = $entry[0]['pwdaccountlockedtime'][0]; + + if (!$pwdAccountLockedTime or $pwdAccountLockedTime === "000001010000Z") { + return $lockDate; + } + + $lockDate = \Ltb\Date::ldapDate2phpDate($pwdAccountLockedTime); + return $lockDate; + } + + public function getUnlockDate($ldap, $dn, $config) : ?DateTime { + + $unlockDate = NULL; + + # Get lock date + $lockDate = $this->getLockDate($ldap, $dn); + + if (!$lockDate) { + return $unlockDate; + } + + # Get lockout duration + $lockoutDuration = $config["lockout_duration"]; + + if (isset($lockoutDuration) and ($lockoutDuration > 0)) { + $unlockDate = date_add( $lockDate, new DateInterval('PT'.$lockoutDuration.'S')); + } + + return $unlockDate; + } + + public function lockAccount($ldap, $dn) : bool { + + $modification = \Ltb\PhpLdap::ldap_mod_replace($ldap, $dn, array("pwdAccountLockedTime" => array("000001010000Z"))); + $errno = ldap_errno($ldap); + + if ( $errno ) { + error_log("LDAP - Lock account error $errno (".ldap_error($ldap).")"); + return false; + } else { + return true; + } + } + + public function unlockAccount($ldap, $dn) : bool { + + $modification = \Ltb\PhpLdap::ldap_mod_replace($ldap, $dn, array("pwdAccountLockedTime" => array())); + $errno = ldap_errno($ldap); + + if ( $errno ) { + error_log("LDAP - Unlock account error $errno (".ldap_error($ldap).")"); + return false; + } else { + return true; + } + } + + public function isPasswordExpired($ldap, $dn, $config) : bool { + + # Get entry + $search = \Ltb\PhpLDAP::ldap_read($ldap, $dn, "(objectClass=*)", array('pwdchangedtime')); + $errno = \Ltb\PhpLDAP::ldap_errno($ldap); + + if ( $errno ) { + error_log("LDAP - Search error $errno (".ldap_error($ldap).")"); + return false; + } else { + $entry = \Ltb\PhpLDAP::ldap_get_entries($ldap, $search); + + } + + # Get pwdChangedTime + $pwdChangedTime = $entry[0]['pwdchangedtime'][0]; + + if (!$pwdChangedTime) { + return false; + } + + # Get password expiration date + $expirationDate = $this->getPasswordExpirationDate($ldap, $dn, $config); + + if (!$expirationDate) { + return false; + } + + if ($expirationDate and time() >= $expirationDate->getTimestamp()) { + return true; + } + + return false; + } + + public function getPasswordExpirationDate($ldap, $dn, $config) : ?DateTime { + + $expirationDate = NULL; + + # Get entry + $search = \Ltb\PhpLDAP::ldap_read($ldap, $dn, "(objectClass=*)", array('pwdchangedtime')); + $errno = \Ltb\PhpLDAP::ldap_errno($ldap); + + if ( $errno ) { + error_log("LDAP - Search error $errno (".ldap_error($ldap).")"); + return $expirationDate; + } else { + $entry = \Ltb\PhpLDAP::ldap_get_entries($ldap, $search); + } + + # Get pwdChangedTime + $pwdChangedTime = $entry[0]['pwdchangedtime'][0]; + + if (!$pwdChangedTime) { + return $expirationDate; + } + + # Get pwdMaxAge + $pwdMaxAge = $config["password_max_age"]; + + # Compute expiration date + if ($pwdMaxAge) { + $changedDate = \Ltb\Date::ldapDate2phpDate($pwdChangedTime); + $expirationDate = date_add( $changedDate, new DateInterval('PT'.$pwdMaxAge.'S')); + } + + return $expirationDate; + } + + public function modifyPassword($ldap, $dn, $password, $forceReset) : bool { + + $changes = array('userPassword' => $password); + + if ($forceReset) { + $changes['pwdReset'] = 'TRUE'; + } + + $update = \Ltb\PhpLDAP::ldap_mod_replace($ldap, $dn, $changes); + $errno = ldap_errno($ldap); + + if ($errno) { + error_log("LDAP - Modify password error $errno (".ldap_error($ldap).")"); + return false; + } else { + return true; + } + } + + public function resetAtNextConnection($ldap, $dn) : bool { + + # Get entry + $search = \Ltb\PhpLDAP::ldap_read($ldap, $dn, "(objectClass=*)", array('pwdreset')); + $errno = \Ltb\PhpLDAP::ldap_errno($ldap); + + if ( $errno ) { + error_log("LDAP - Search error $errno (".ldap_error($ldap).")"); + return false; + } else { + $entry = \Ltb\PhpLDAP::ldap_get_entries($ldap, $search); + } + + if ($entry[0]['pwdreset'] and $entry[0]['pwdreset'][0] === "TRUE") { + return true; + } else { + return false; + } + } + + public function enableAccount($ldap, $dn) : bool { + // Not implemented + return false; + } + + public function disableAccount($ldap, $dn) : bool { + // Not implemented + return false; + } + + public function isAccountEnabled($ldap, $dn) : bool { + // Not implemented + return true; + } + + public function getLdapDate($date) : string { + return \Ltb\Date::string2ldapDate( $date->format('d/m/Y') ); + } + + public function getPwdPolicyConfiguration($ldap, $entry_dn, $default_ppolicy_dn) : Array { + + $ppolicyConfig = array(); + + # Check pwdPolicySubEntry + $search_user = \Ltb\PhpLDAP::ldap_read($ldap, $entry_dn, "(objectClass=*)", array('pwdpolicysubentry')); + $errno = \Ltb\PhpLDAP::ldap_errno($ldap); + + if ( $errno ) { + error_log("LDAP - Search error $errno (".ldap_error($ldap).")"); + return $ppolicyConfig; + } else { + $user_entry = \Ltb\PhpLDAP::ldap_get_entries($ldap, $search_user); + } + + $ppolicy_dn = $user_entry[0]['pwdpolicysubentry'] ? $user_entry[0]['pwdpolicysubentry'][0] : $default_ppolicy_dn; + + # Get values from ppolicy + $search = \Ltb\PhpLDAP::ldap_read($ldap, $ppolicy_dn, "(objectClass=pwdPolicy)", array('pwdLockoutDuration', 'pwdMaxAge', 'pwdLockout')); + $errno = \Ltb\PhpLDAP::ldap_errno($ldap); + + if ( $errno ) { + error_log("LDAP - Search error $errno (".ldap_error($ldap).")"); + return $ppolicyConfig; + } else { + $entry = \Ltb\PhpLDAP::ldap_get_entries($ldap, $search); + } + + $ppolicyConfig["dn"] = $entry[0]["dn"]; + $ppolicyConfig["lockout_duration"] = $entry[0]["pwdlockoutduration"][0]; + $ppolicyConfig["password_max_age"] = $entry[0]["pwdmaxage"][0]; + $ppolicyConfig["lockout_enabled"] = strtolower($entry[0]['pwdlockout'][0]) == "true" ? true : false; + + return $ppolicyConfig; + } + +} diff --git a/tests/Ltb/DirectoryTest.php b/tests/Ltb/DirectoryTest.php new file mode 100644 index 0000000..e4ce2f4 --- /dev/null +++ b/tests/Ltb/DirectoryTest.php @@ -0,0 +1,730 @@ +shouldreceive([ + 'ldap_read' => null, + 'ldap_errno' => 0, + 'ldap_get_entries' => [ + 'count' => 1, + 0 => [ + 'pwdaccountlockedtime' => [ + 'count' => 1, + 0 => "000001010000Z", + ] + ] + ] + ]); + + $isLocked = (new Ltb\Directory\OpenLDAP)->isLocked(null, null, null); + $this->assertTrue($isLocked, "Account should be locked forever"); + } + + public function test_openldap_islocked_not_locked(): void + { + $phpLDAPMock = Mockery::mock('overload:Ltb\PhpLDAP'); + $phpLDAPMock->shouldreceive([ + 'ldap_read' => null, + 'ldap_errno' => 0, + 'ldap_get_entries' => [ + 'count' => 1, + 0 => [ + 'pwdaccountlockedtime' => [ + 'count' => 1, + 0 => null, + ] + ] + ] + ]); + + $isLocked = (new Ltb\Directory\OpenLDAP)->isLocked(null, null, null); + $this->assertFalse($isLocked, "Account should not be locked"); + } + + public function test_openldap_islocked_still_locked(): void + { + $phpLDAPMock = Mockery::mock('overload:Ltb\PhpLDAP'); + $phpLDAPMock->shouldreceive([ + 'ldap_read' => null, + 'ldap_errno' => 0, + 'ldap_get_entries' => [ + 'count' => 1, + 0 => [ + 'pwdaccountlockedtime' => [ + 'count' => 1, + 0 => (new DateTime)->format("Ymdhis\Z"), + ] + ] + ] + ]); + + $isLocked = (new Ltb\Directory\OpenLDAP)->isLocked(null, null, array('lockout_duration' => 86400)); + $this->assertTrue($isLocked, "Account should still be locked"); + } + + public function test_openldap_islocked_no_more_locked(): void + { + $phpLDAPMock = Mockery::mock('overload:Ltb\PhpLDAP'); + $phpLDAPMock->shouldreceive([ + 'ldap_read' => null, + 'ldap_errno' => 0, + 'ldap_get_entries' => [ + 'count' => 1, + 0 => [ + 'pwdaccountlockedtime' => [ + 'count' => 1, + 0 => (new DateTime)->modify("-10 days")->format("Ymdhis\Z"), + ] + ] + ] + ]); + + $isLocked = (new Ltb\Directory\OpenLDAP)->isLocked(null, null, array('lockout_duration' => 86400)); + $this->assertFalse($isLocked, "Account should no more be locked"); + } + + public function test_openldap_getlockdate_empty(): void + { + $phpLDAPMock = Mockery::mock('overload:Ltb\PhpLDAP'); + $phpLDAPMock->shouldreceive([ + 'ldap_read' => null, + 'ldap_errno' => 0, + 'ldap_get_entries' => [ + 'count' => 1, + 0 => [ + 'pwdaccountlockedtime' => [ + 'count' => 1, + 0 => null, + ] + ] + ] + ]); + + $getLockDate = (new Ltb\Directory\OpenLDAP)->getLockDate(null, null); + $this->assertNull($getLockDate, "Lock date should be null"); + } + + public function test_openldap_getlockdate_lock_forever(): void + { + $phpLDAPMock = Mockery::mock('overload:Ltb\PhpLDAP'); + $phpLDAPMock->shouldreceive([ + 'ldap_read' => null, + 'ldap_errno' => 0, + 'ldap_get_entries' => [ + 'count' => 1, + 0 => [ + 'pwdaccountlockedtime' => [ + 'count' => 1, + 0 => "000001010000Z", + ] + ] + ] + ]); + + $getLockDate = (new Ltb\Directory\OpenLDAP)->getLockDate(null, null); + $this->assertNull($getLockDate, "Lock date should be null if user is locked forever"); + } + + public function test_openldap_getlockdate_notempty(): void + { + $dt = new DateTime; + $phpLDAPMock = Mockery::mock('overload:Ltb\PhpLDAP'); + $phpLDAPMock->shouldreceive([ + 'ldap_read' => null, + 'ldap_errno' => 0, + 'ldap_get_entries' => [ + 'count' => 1, + 0 => [ + 'pwdaccountlockedtime' => [ + 'count' => 1, + 0 => $dt->format("Ymdhis\Z"), + ] + ] + ] + ]); + + $getLockDate = (new Ltb\Directory\OpenLDAP)->getLockDate(null, null); + $this->assertInstanceOf("DateTime", $getLockDate, "Lock date should be a PHP DateTime object"); + $this->assertEquals($dt->format("Y/m/d - h:i:s"), $getLockDate->format("Y/m/d - h:i:s"), "Lock date is correct"); + } + + public function test_openldap_getunlockdate_noduration(): void + { + $dt = new DateTime; + $phpLDAPMock = Mockery::mock('overload:Ltb\PhpLDAP'); + $phpLDAPMock->shouldreceive([ + 'ldap_read' => null, + 'ldap_errno' => 0, + 'ldap_get_entries' => [ + 'count' => 1, + 0 => [ + 'pwdaccountlockedtime' => [ + 'count' => 1, + 0 => $dt->format("Ymdhis\Z"), + ] + ] + ] + ]); + + $unlockDate = (new Ltb\Directory\OpenLDAP)->getUnlockDate(null, null, array('lockout_duration' => 0)); + $this->assertNull($unlockDate, "Unkock date should be null"); + } + + public function test_openldap_getunlockdate_duration(): void + { + $dt = new DateTime; + $phpLDAPMock = Mockery::mock('overload:Ltb\PhpLDAP'); + $phpLDAPMock->shouldreceive([ + 'ldap_read' => null, + 'ldap_errno' => 0, + 'ldap_get_entries' => [ + 'count' => 1, + 0 => [ + 'pwdaccountlockedtime' => [ + 'count' => 1, + 0 => $dt->format("Ymdhis\Z"), + ] + ] + ] + ]); + + $unlockDate = (new Ltb\Directory\OpenLDAP)->getUnlockDate(null, null, array('lockout_duration' => 86400)); + $this->assertInstanceOf("DateTime", $unlockDate, "Unlock date should be a PHP DateTime object"); + $this->assertEquals($dt->modify("+1 day")->format("Y/m/d - h:i:s"), $unlockDate->format("Y/m/d - h:i:s"), "Unlock date is correct"); + } + + public function test_openldap_isexpired_expired(): void + { + $dt = new DateTime; + $phpLDAPMock = Mockery::mock('overload:Ltb\PhpLDAP'); + $phpLDAPMock->shouldreceive([ + 'ldap_read' => null, + 'ldap_errno' => 0, + 'ldap_get_entries' => [ + 'count' => 1, + 0 => [ + 'pwdchangedtime' => [ + 'count' => 1, + 0 => $dt->modify("-1 month")->format("Ymdhis\Z"), + ] + ] + ] + ]); + + $isPasswordExpired = (new Ltb\Directory\OpenLDAP)->isPasswordExpired(null, null, array('password_max_age' => 86400)); + $this->assertTrue($isPasswordExpired, "Password should be expired"); + } + + public function test_openldap_isexpired_not_expired(): void + { + $dt = new DateTime; + $phpLDAPMock = Mockery::mock('overload:Ltb\PhpLDAP'); + $phpLDAPMock->shouldreceive([ + 'ldap_read' => null, + 'ldap_errno' => 0, + 'ldap_get_entries' => [ + 'count' => 1, + 0 => [ + 'pwdchangedtime' => [ + 'count' => 1, + 0 => $dt->modify("-1 hour")->format("Ymdhis\Z"), + ] + ] + ] + ]); + + $isPasswordExpired = (new Ltb\Directory\OpenLDAP)->isPasswordExpired(null, null, array('password_max_age' => 86400)); + $this->assertFalse($isPasswordExpired, "Password should not be expired"); + } + + public function test_openldap_getpasswordexpirationdate_empty(): void + { + $phpLDAPMock = Mockery::mock('overload:Ltb\PhpLDAP'); + $phpLDAPMock->shouldreceive([ + 'ldap_read' => null, + 'ldap_errno' => 0, + 'ldap_get_entries' => [ + 'count' => 1, + 0 => [ + 'pwdchangedtime' => [ + 'count' => 1, + 0 => null, + ] + ] + ] + ]); + + $passwordExpirationDate = (new Ltb\Directory\OpenLDAP)->getPasswordExpirationDate(null, null, null); + $this->assertNull($passwordExpirationDate, "Password expiration date should be null"); + } + + public function test_openldap_getpasswordexpirationdate_notempty(): void + { + $dt = new DateTime; + $phpLDAPMock = Mockery::mock('overload:Ltb\PhpLDAP'); + $phpLDAPMock->shouldreceive([ + 'ldap_read' => null, + 'ldap_errno' => 0, + 'ldap_get_entries' => [ + 'count' => 1, + 0 => [ + 'pwdchangedtime' => [ + 'count' => 1, + 0 => $dt->format("Ymdhis\Z"), + ] + ] + ] + ]); + + $passwordExpirationDate = (new Ltb\Directory\OpenLDAP)->getPasswordExpirationDate(null, null, array('password_max_age' => 86400)); + $this->assertInstanceOf("DateTime", $passwordExpirationDate, "Password expiration date should be a PHP DateTime object"); + $this->assertEquals($dt->modify("+1 day")->format("Y/m/d - h:i:s"), $passwordExpirationDate->format("Y/m/d - h:i:s"), "Password expiration date is correct"); + } + + public function test_openldap_reset_true(): void + { + $phpLDAPMock = Mockery::mock('overload:Ltb\PhpLDAP'); + $phpLDAPMock->shouldreceive([ + 'ldap_read' => null, + 'ldap_errno' => 0, + 'ldap_get_entries' => [ + 'count' => 1, + 0 => [ + 'pwdreset' => [ + 'count' => 1, + 0 => "TRUE", + ] + ] + ] + ]); + + $reset = (new Ltb\Directory\OpenLDAP)->resetAtNextConnection(null, null); + $this->assertTrue($reset, "Reset should be true"); + } + + public function test_openldap_reset_false(): void + { + $phpLDAPMock = Mockery::mock('overload:Ltb\PhpLDAP'); + $phpLDAPMock->shouldreceive([ + 'ldap_read' => null, + 'ldap_errno' => 0, + 'ldap_get_entries' => [ + 'count' => 1, + 0 => [ + 'pwdreset' => [ + 'count' => 1, + 0 => "FALSE", + ] + ] + ] + ]); + + $reset = (new Ltb\Directory\OpenLDAP)->resetAtNextConnection(null, null); + $this->assertFalse($reset, "Reset should be false"); + } + + public function test_openldap_reset_false_empty(): void + { + $phpLDAPMock = Mockery::mock('overload:Ltb\PhpLDAP'); + $phpLDAPMock->shouldreceive([ + 'ldap_read' => null, + 'ldap_errno' => 0, + 'ldap_get_entries' => [ + 'count' => 1, + 0 => [ + 'pwdreset' => [ + 'count' => 1, + 0 => null, + ] + ] + ] + ]); + + $reset = (new Ltb\Directory\OpenLDAP)->resetAtNextConnection(null, null); + $this->assertFalse($reset, "Reset should be false"); + } + + public function test_activedirectory_islocked_locked_forever(): void + { + $ad_date = ((int)time() + 11644473600) * 10000000; + $phpLDAPMock = Mockery::mock('overload:Ltb\PhpLDAP'); + $phpLDAPMock->shouldreceive([ + 'ldap_read' => null, + 'ldap_errno' => 0, + 'ldap_get_entries' => [ + 'count' => 1, + 0 => [ + 'lockouttime' => [ + 'count' => 1, + 0 => $ad_date + ] + ] + ] + ]); + + $isLocked = (new Ltb\Directory\ActiveDirectory)->isLocked(null, null, array('lockout_duration' => 0)); + $this->assertTrue($isLocked, "Account should be locked forever"); + } + + public function test_activedirectory_islocked_not_locked(): void + { + $phpLDAPMock = Mockery::mock('overload:Ltb\PhpLDAP'); + $phpLDAPMock->shouldreceive([ + 'ldap_read' => null, + 'ldap_errno' => 0, + 'ldap_get_entries' => [ + 'count' => 1, + 0 => [ + 'lockouttime' => [ + 'count' => 1, + 0 => null + ] + ] + ] + ]); + + $isLocked = (new Ltb\Directory\ActiveDirectory)->isLocked(null, null, array('lockout_duration' => 0)); + $this->assertFalse($isLocked, "Account should not be locked"); + } + + public function test_activedirectory_islocked_still_locked(): void + { + $ad_date = ((int)time() + 11644473600) * 10000000; + $phpLDAPMock = Mockery::mock('overload:Ltb\PhpLDAP'); + $phpLDAPMock->shouldreceive([ + 'ldap_read' => null, + 'ldap_errno' => 0, + 'ldap_get_entries' => [ + 'count' => 1, + 0 => [ + 'lockouttime' => [ + 'count' => 1, + 0 => $ad_date + ] + ] + ] + ]); + + $isLocked = (new Ltb\Directory\ActiveDirectory)->isLocked(null, null, array('lockout_duration' => 86400)); + $this->assertTrue($isLocked, "Account should be still locked"); + } + + public function test_activedirectory_islocked_no_more_locked(): void + { + $ad_date = ((int)time() - 864000 + 11644473600) * 10000000; + $phpLDAPMock = Mockery::mock('overload:Ltb\PhpLDAP'); + $phpLDAPMock->shouldreceive([ + 'ldap_read' => null, + 'ldap_errno' => 0, + 'ldap_get_entries' => [ + 'count' => 1, + 0 => [ + 'lockouttime' => [ + 'count' => 1, + 0 => $ad_date + ] + ] + ] + ]); + + $isLocked = (new Ltb\Directory\ActiveDirectory)->isLocked(null, null, array('lockout_duration' => 86400)); + $this->assertFalse($isLocked, "Account should no more be locked"); + } + + public function test_activedirectory_getlockdate_empty(): void + { + $phpLDAPMock = Mockery::mock('overload:Ltb\PhpLDAP'); + $phpLDAPMock->shouldreceive([ + 'ldap_read' => null, + 'ldap_errno' => 0, + 'ldap_get_entries' => [ + 'count' => 1, + 0 => [ + 'lockouttime' => [ + 'count' => 1, + 0 => null, + ] + ] + ] + ]); + + $getLockDate = (new Ltb\Directory\ActiveDirectory)->getLockDate(null, null); + $this->assertNull($getLockDate, "Lock date should be null"); + } + + public function test_activedirectory_getlockdate_notempty(): void + { + $dt = new DateTime; + $ad_date = ((int)$dt->getTimestamp() + 11644473600) * 10000000; + $phpLDAPMock = Mockery::mock('overload:Ltb\PhpLDAP'); + $phpLDAPMock->shouldreceive([ + 'ldap_read' => null, + 'ldap_errno' => 0, + 'ldap_get_entries' => [ + 'count' => 1, + 0 => [ + 'lockouttime' => [ + 'count' => 1, + 0 => $ad_date, + ] + ] + ] + ]); + + $getLockDate = (new Ltb\Directory\ActiveDirectory)->getLockDate(null, null); + $this->assertInstanceOf("DateTime", $getLockDate, "Lock date should be a PHP DateTime object"); + $this->assertEquals($dt->format("Y/m/d - h:i:s"), $getLockDate->format("Y/m/d - h:i:s"), "Lock date is correct"); + } + + public function test_activedirectory_getunlockdate_noduration(): void + { + $ad_date = ((int)time() + 11644473600) * 10000000; + $phpLDAPMock = Mockery::mock('overload:Ltb\PhpLDAP'); + $phpLDAPMock->shouldreceive([ + 'ldap_read' => null, + 'ldap_errno' => 0, + 'ldap_get_entries' => [ + 'count' => 1, + 0 => [ + 'lockouttime' => [ + 'count' => 1, + 0 => $ad_date, + ] + ] + ] + ]); + + $unlockDate = (new Ltb\Directory\ActiveDirectory)->getUnlockDate(null, null, array('lockout_duration' => 0)); + $this->assertNull($unlockDate, "Unock date should be null"); + } + + public function test_activedirectory_getunlockdate_duration(): void + { + $dt = new DateTime; + $ad_date = ((int)$dt->getTimestamp() + 11644473600) * 10000000; + $phpLDAPMock = Mockery::mock('overload:Ltb\PhpLDAP'); + $phpLDAPMock->shouldreceive([ + 'ldap_read' => null, + 'ldap_errno' => 0, + 'ldap_get_entries' => [ + 'count' => 1, + 0 => [ + 'lockouttime' => [ + 'count' => 1, + 0 => $ad_date, + ] + ] + ] + ]); + + $unlockDate = (new Ltb\Directory\ActiveDirectory)->getUnlockDate(null, null, array('lockout_duration' => 86400)); + $this->assertInstanceOf("DateTime", $unlockDate, "Unlock date should be a PHP DateTime object"); + $this->assertEquals($dt->modify("+1 day")->format("Y/m/d - h:i:s"), $unlockDate->format("Y/m/d - h:i:s"), "Unlock date is correct"); + } + + public function test_activedirectory_isexpired_expired(): void + { + $dt = new DateTime; + $ad_date = ((int)$dt->modify("-1 month")->getTimestamp() + 11644473600) * 10000000; + $phpLDAPMock = Mockery::mock('overload:Ltb\PhpLDAP'); + $phpLDAPMock->shouldreceive([ + 'ldap_read' => null, + 'ldap_errno' => 0, + 'ldap_get_entries' => [ + 'count' => 1, + 0 => [ + 'pwdlastset' => [ + 'count' => 1, + 0 => $ad_date, + ] + ] + ] + ]); + + $isPasswordExpired = (new Ltb\Directory\ActiveDirectory)->isPasswordExpired(null, null, array('password_max_age' => 86400)); + $this->assertTrue($isPasswordExpired, "Password should be expired"); + } + + public function test_activedirectory_isexpired_not_expired(): void + { + $dt = new DateTime; + $ad_date = ((int)$dt->modify("-1 hour")->getTimestamp() + 11644473600) * 10000000; + $phpLDAPMock = Mockery::mock('overload:Ltb\PhpLDAP'); + $phpLDAPMock->shouldreceive([ + 'ldap_read' => null, + 'ldap_errno' => 0, + 'ldap_get_entries' => [ + 'count' => 1, + 0 => [ + 'pwdlastset' => [ + 'count' => 1, + 0 => $ad_date, + ] + ] + ] + ]); + + $isPasswordExpired = (new Ltb\Directory\ActiveDirectory)->isPasswordExpired(null, null, array('password_max_age' => 86400)); + $this->assertFalse($isPasswordExpired, "Password should not be expired"); + } + + public function test_activedirectory_getpasswordexpirationdate_empty(): void + { + $phpLDAPMock = Mockery::mock('overload:Ltb\PhpLDAP'); + $phpLDAPMock->shouldreceive([ + 'ldap_read' => null, + 'ldap_errno' => 0, + 'ldap_get_entries' => [ + 'count' => 1, + 0 => [ + 'pwdlastset' => [ + 'count' => 1, + 0 => null, + ] + ] + ] + ]); + + $getPasswordExpirationDate = (new Ltb\Directory\ActiveDirectory)->getPasswordExpirationDate(null, null, null); + $this->assertNull($getPasswordExpirationDate, "Password expiration date should be null"); + } + + public function test_activedirectory_getpasswordexpirationdate_notempty(): void + { + $dt = new DateTime; + $ad_date = ((int)$dt->getTimestamp() + 11644473600) * 10000000; + $phpLDAPMock = Mockery::mock('overload:Ltb\PhpLDAP'); + $phpLDAPMock->shouldreceive([ + 'ldap_read' => null, + 'ldap_errno' => 0, + 'ldap_get_entries' => [ + 'count' => 1, + 0 => [ + 'pwdlastset' => [ + 'count' => 1, + 0 => $ad_date, + ] + ] + ] + ]); + + $passwordExpirationDate = (new Ltb\Directory\ActiveDirectory)->getPasswordExpirationDate(null, null, array('password_max_age' => 86400)); + $this->assertInstanceOf("DateTime", $passwordExpirationDate, "Password expiration date should be a PHP DateTime object"); + $this->assertEquals($dt->modify("+1 day")->format("Y/m/d - h:i:s"), $passwordExpirationDate->format("Y/m/d - h:i:s"), "Password expiration date is correct"); + } + + public function test_activedirectory_reset_true(): void + { + $phpLDAPMock = Mockery::mock('overload:Ltb\PhpLDAP'); + $phpLDAPMock->shouldreceive([ + 'ldap_read' => null, + 'ldap_errno' => 0, + 'ldap_get_entries' => [ + 'count' => 1, + 0 => [ + 'pwdlastset' => [ + 'count' => 1, + 0 => 0, + ] + ] + ] + ]); + + $reset = (new Ltb\Directory\ActiveDirectory)->resetAtNextConnection(null, null); + $this->assertTrue($reset, "Reset should be true"); + } + + public function test_activedirectory_reset_false(): void + { + $dt = new DateTime; + $ad_date = ((int)$dt->getTimestamp() + 11644473600) * 10000000; + $phpLDAPMock = Mockery::mock('overload:Ltb\PhpLDAP'); + $phpLDAPMock->shouldreceive([ + 'ldap_read' => null, + 'ldap_errno' => 0, + 'ldap_get_entries' => [ + 'count' => 1, + 0 => [ + 'pwdlastset' => [ + 'count' => 1, + 0 => $ad_date, + ] + ] + ] + ]); + + $reset = (new Ltb\Directory\ActiveDirectory)->resetAtNextConnection(null, null); + $this->assertFalse($reset, "Reset should be false"); + } + + public function test_activedirectory_reset_false_empty(): void + { + $phpLDAPMock = Mockery::mock('overload:Ltb\PhpLDAP'); + $phpLDAPMock->shouldreceive([ + 'ldap_read' => null, + 'ldap_errno' => 0, + 'ldap_get_entries' => [ + 'count' => 1, + 0 => [ + 'pwdlastset' => [ + 'count' => 1, + 0 => null, + ] + ] + ] + ]); + + $reset = (new Ltb\Directory\ActiveDirectory)->resetAtNextConnection(null, null); + $this->assertFalse($reset, "Reset should be false"); + } + + public function test_activedirectory_isenabled_true(): void + { + $phpLDAPMock = Mockery::mock('overload:Ltb\PhpLDAP'); + $phpLDAPMock->shouldreceive([ + 'ldap_read' => null, + 'ldap_errno' => 0, + 'ldap_get_entries' => [ + 'count' => 1, + 0 => [ + 'useraccountcontrol' => [ + 'count' => 1, + 0 => 512, + ] + ] + ] + ]); + + $accountEnabled = (new Ltb\Directory\ActiveDirectory)->isAccountEnabled(null, null); + $this->assertTrue($accountEnabled, "Account should be enabled"); + } + + public function test_activedirectory_isenabled_false(): void + { + $phpLDAPMock = Mockery::mock('overload:Ltb\PhpLDAP'); + $phpLDAPMock->shouldreceive([ + 'ldap_read' => null, + 'ldap_errno' => 0, + 'ldap_get_entries' => [ + 'count' => 1, + 0 => [ + 'useraccountcontrol' => [ + 'count' => 1, + 0 => 514, + ] + ] + ] + ]); + + $accountEnabled = (new Ltb\Directory\ActiveDirectory)->isAccountEnabled(null, null); + $this->assertFalse($accountEnabled, "Account should be disabled"); + } + +}