Skip to content

Commit

Permalink
Add functions to manage lock status and unlock date
Browse files Browse the repository at this point in the history
  • Loading branch information
coudot committed Jul 22, 2024
1 parent f96f86e commit 531c4d0
Show file tree
Hide file tree
Showing 4 changed files with 174 additions and 32 deletions.
5 changes: 4 additions & 1 deletion src/Ltb/Date.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php namespace Ltb;
use \DateTime;

/**
* Date functions
Expand Down Expand Up @@ -76,7 +77,9 @@ static function string2ldapDate($string) {
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
return date(DateTime::RFC822, $unixTimestamp);
$date = new DateTime();
$date->setTimestamp($unixTimestamp);
return $date;
}

}
21 changes: 20 additions & 1 deletion src/Ltb/Directory.php
Original file line number Diff line number Diff line change
@@ -1,8 +1,27 @@
<?php

namespace Ltb;
use \DateTime;

interface Directory
{
public function isLocked($ldap, $dn, $config);
/*
* Is account locked?
*/
public function isLocked($ldap, $dn, $config) : bool;

/*
* Date when account will be automatically unlocked
*/
public function getUnlockDate($ldap, $dn, $config) : ?DateTime;

/*
* Lock duration (in seconds)
*/
public function getLockoutDuration($ldap, $dn, $config) : ?int;

/*
* Can account be locked?
*/
public function canLockAccount($ldap, $dn, $config) : bool;
}
67 changes: 59 additions & 8 deletions src/Ltb/Directory/ActiveDirectory.php
Original file line number Diff line number Diff line change
@@ -1,29 +1,80 @@
<?php

namespace Ltb\Directory;
use \DateTime;

class ActiveDirectory implements \Ltb\Directory
{
public function isLocked($ldap, $dn, $config) {
public function isLocked($ldap, $dn, $config) : bool {

$isLocked = false;
# Get entry
$search = ldap_read($ldap, $dn, "(objectClass=*)", array('lockouttime'));
$errno = ldap_errno($ldap);

if ( $errno ) {
error_log("LDAP - Search error $errno (".ldap_error($ldap).")");
return false;
} else {
$entry = ldap_get_entries($ldap, $search);

}

# Get lockoutTime
$lockoutTime = $entry[0]['lockouttime'][0];

# Get unlock date
$unlockDate = $this->getUnlockDate($ldap, $dn, $config);

if ($lockoutTime > 0 and !$unlockDate) {
return true;
}

if ($unlockDate and time() <= $unlockDate->getTimestamp()) {
return true;
}

return false;
}

public function getUnlockDate($ldap, $dn, $config) : ?DateTime {

$unlockDate = NULL;

# Get entry
$search = ldap_read($ldap, $dn, "(objectClass=*)", array('useraccountcontrol'));
$search = ldap_read($ldap, $dn, "(objectClass=*)", array('lockouttime'));
$errno = ldap_errno($ldap);

if ( $errno ) {
error_log("LDAP - Search error $errno (".ldap_error($ldap).")");
return $isLocked;
return $unlockDate;
} else {
$entry = ldap_get_entries($ldap, $search);
}

# Check userAccountControl
$userAccountControl = $entry[0]['useraccountcontrol'][0];
# Get lockoutTime
$lockoutTime = $entry[0]['lockouttime'][0];

if ( !$lockoutTime or $lockoutTime == 0) {
return $unlockDate;
}

if ($userAccountControl & 2) { $isLocked = true; }
# Get lockoutDuration
$lockoutDuration = $config["lockoutDuration"];

# Compute unlock date
if ($lockoutDuration) {
$adUnlockDate = $lockoutTime + ($lockoutDuration * 10000000);
$unlockDate = \Ltb\Date::adDate2phpDate($adUnlockDate);
}

return $unlockDate;
}

public function getLockoutDuration($ldap, $dn, $config) : ?int {
return $config['lockoutDuration'];
}

return $isLocked;
public function canLockAccount($ldap, $dn, $config) : bool {
return true;
}
}
113 changes: 91 additions & 22 deletions src/Ltb/Directory/OpenLDAP.php
Original file line number Diff line number Diff line change
@@ -1,54 +1,123 @@
<?php

namespace Ltb\Directory;
use \DateTime;

class OpenLDAP implements \Ltb\Directory
{
public function isLocked($ldap, $dn, $config) {

$isLocked = false;
public function isLocked($ldap, $dn, $config) : bool {

# Get entry
$search = ldap_read($ldap, $dn, "(objectClass=*)", array('pwdaccountlockedtime'));
$errno = ldap_errno($ldap);

if ( $errno ) {
error_log("LDAP - Search error $errno (".ldap_error($ldap).")");
return $isLocked;
return false;
} else {
$entry = ldap_get_entries($ldap, $search);
}

# Get ppolicy entry
# Get pwdAccountLockedTime
$pwdAccountLockedTime = $entry[0]['pwdaccountlockedtime'][0];

if (!$pwdAccountLockedTime) {
return false;
}

if ( $pwdAccountLockedTime === "000001010000Z" ) {
return true;
}

$unlockDate = $this->getUnlockDate($ldap, $dn, $config);

if ( $unlockDate and time() <= $unlockDate->getTimestamp() ) {
return true;
}

return false;
}

public function getUnlockDate($ldap, $dn, $config) : ?DateTime {

$unlockDate = NULL;

# Get entry
$search = ldap_read($ldap, $dn, "(objectClass=*)", array('pwdaccountlockedtime'));
$errno = ldap_errno($ldap);

if ( $errno ) {
error_log("LDAP - Search error $errno (".ldap_error($ldap).")");
return $unlockDate;
} else {
$entry = ldap_get_entries($ldap, $search);
}

# Get pwdAccountLockedTime
$pwdAccountLockedTime = $entry[0]['pwdaccountlockedtime'][0];

if (!$pwdAccountLockedTime) {
return $unlockDate;
}

# Get lockoutDuration
$lockoutDuration = $config["LockoutDuration"];

if ( $pwdAccountLockedTime === "000001010000Z" ) {
return $unlockDate;
} else if (isset($pwdLockoutDuration) and ($pwdLockoutDuration > 0)) {
$lockDate = \Ltb\Date::ldapDate2phpDate($pwdAccountLockedTime);
$unlockDate = date_add( $lockDate, new DateInterval('PT'.$pwdLockoutDuration.'S'));
}

return $unlockDate;
}

public function getLockoutDuration($ldap, $dn, $config) : ?int {

$lockoutDuration = 0;

# If lockoutDuration is forced in config
if (isset($config['lockoutDuration'])) {
return $config['lockoutDuration'];
}

# Else get password policy configuration
$ppolicy_search = ldap_read($ldap, $config['pwdPolicy'], "(objectClass=*)", array('pwdlockout', 'pwdlockoutduration'));
$errno = ldap_errno($ldap);

if ( $errno ) {
error_log("LDAP - Search error $errno (".ldap_error($ldap).")");
return $isLocked;
return $lockoutDuration;
} else {
$ppolicy_entry = ldap_get_entries($ldap, $ppolicy_search);
}

$pwdLockout = strtolower($ppolicy_entry[0]['pwdlockout'][0]) == "true" ? true : false;
$pwdLockoutDuration = $ppolicy_entry[0]['pwdlockoutduration'][0];
$pwdAccountLockedTime = $entry[0]['pwdaccountlockedtime'][0];

if ( $pwdAccountLockedTime === "000001010000Z" ) {
$isLocked = true;
} else if (isset($pwdAccountLockedTime)) {
if (isset($pwdLockoutDuration) and ($pwdLockoutDuration > 0)) {
$lockDate = \Ltb\Date::ldapDate2phpDate($pwdAccountLockedTime);
$unlockDate = date_add( $lockDate, new DateInterval('PT'.$pwdLockoutDuration.'S'));
if ( time() <= $unlockDate->getTimestamp() ) {
$isLocked = true;
}
} else {
$isLocked = true;
}
}

return $isLocked;
if ($pwdLockout) {
$lockoutDuration = $pwdLockoutDuration;
}

return $lockoutDuration;
}

public function canLockAccount($ldap, $dn, $config) : bool {

# Search password policy
$ppolicy_search = ldap_read($ldap, $config['pwdPolicy'], "(objectClass=*)", array('pwdlockout'));
$errno = ldap_errno($ldap);

if ( $errno ) {
error_log("LDAP - Search error $errno (".ldap_error($ldap).")");
return false;
} else {
$ppolicy_entry = ldap_get_entries($ldap, $ppolicy_search);
}

$pwdLockout = strtolower($ppolicy_entry[0]['pwdlockout'][0]) == "true" ? true : false;

return $pwdLockout;
}
}

0 comments on commit 531c4d0

Please sign in to comment.