support Windows lockoutTime

This commit is contained in:
Roland Gruber 2017-05-07 13:26:41 +02:00
parent 7169068d93
commit 7b82372a2d
3 changed files with 119 additions and 11 deletions

View File

@ -2,6 +2,7 @@ June 2017
- Support multiple configurations for same account type
- PHP 7.1 compatibility
- Samba 3: added account expiration date to PDF fields
- Windows: Support unlocking of users with too many failed login attempts
15.03.2017 5.7

View File

@ -1,5 +1,6 @@
<?php
use \LAM\TYPES\TypeManager;
use LAM\TYPES\ConfiguredType;
/*
$Id$
@ -69,6 +70,9 @@ class windowsUser extends baseModule implements passwordService {
/** business category cache */
private $businessCategoryCache = null;
/** cache for lockout duration */
private static $lockoutDurationCache = array();
/**
* Returns true if this module can manage accounts of the current type, otherwise false.
@ -111,7 +115,7 @@ class windowsUser extends baseModule implements passwordService {
'pwdLastSet', 'otherMailbox', 'homeDirectory', 'homeDrive', 'msSFU30Name', 'msSFU30NisDomain', 'pwdLastSet',
'lastLogonTimestamp', 'accountExpires', 'jpegPhoto', 'title', 'carLicense', 'employeeNumber', 'employeeType',
'businessCategory', 'department', 'ou', 'o', 'manager', 'facsimileTelephoneNumber', 'company',
'pager', 'otherPager', 'mobile', 'otherMobile', 'proxyAddresses'
'pager', 'otherPager', 'mobile', 'otherMobile', 'proxyAddresses', 'lockoutTime'
);
// help Entries
$return['help'] = array(
@ -2899,6 +2903,65 @@ class windowsUser extends baseModule implements passwordService {
return intval($myAttrs['useraccountcontrol'][0]) & windowsUser::AC_ACCOUNT_DISABLED;
}
/**
* Returns if the account is currently deactivated.
*
* @param array $attrs LDAP attributes
* @param ConfiguredType type
* @return DateTime locked till or null
*/
public static function getPasswordLocked($attrs, $type) {
$myAttrs = array_change_key_case($attrs, CASE_LOWER);
if (empty($myAttrs['lockouttime'][0])) {
return false;
}
$lockoutDuration = self::getDomainLockoutDuration($attrs['dn']);
if (empty($lockoutDuration) || ($lockoutDuration > -1)) {
return false;
}
$lockoutDurationSeconds = substr($lockoutDuration, 0, -7);
$lockoutTime = self::getFileTime($myAttrs['lockouttime'][0]);
$unlockTime = clone $lockoutTime;
$unlockTime->add(new DateInterval('PT' . abs($lockoutDurationSeconds) . 'S'));
$now = new DateTime();
if ($unlockTime > $now) {
$unlockTime->setTimezone(getTimeZone());
return $unlockTime;
}
return null;
}
/**
* Returns the domain lockout duration for this DN.
*
* @param string $dn user DN
*/
private static function getDomainLockoutDuration($dn) {
$lowerDn = strtolower($dn);
$domainRoot = substr($lowerDn, strpos($lowerDn, 'dc='));
if (isset(windowsUser::$lockoutDurationCache[$domainRoot])) {
return windowsUser::$lockoutDurationCache[$domainRoot];
}
$policyDN = 'cn=builtin,' . $domainRoot;
$policyAttrs = ldapGetDN($policyDN, array('lockoutduration'));
if (!empty($policyAttrs['lockoutduration'][0])) {
windowsUser::$lockoutDurationCache[$domainRoot] = $policyAttrs['lockoutduration'][0];
}
else {
windowsUser::$lockoutDurationCache[$domainRoot] = null;
}
return windowsUser::$lockoutDurationCache[$domainRoot];
}
/**
* Unlocks the user password. This resets 'lockoutTime' to 0.
*/
public function unlockPassword() {
if (!empty($this->attributes['lockoutTime'][0])) {
$this->attributes['lockoutTime'][0] = '0';
}
}
/**
* Sets if the account is currently deactivated.
*

View File

@ -3,7 +3,7 @@
$Id$
This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/)
Copyright (C) 2005 - 2016 Roland Gruber
Copyright (C) 2005 - 2017 Roland Gruber
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -259,10 +259,22 @@ class user extends baseType {
$ppolicyLocked = true;
}
$windowsLocked = false;
if ($windowsAvailable && windowsUser::isDeactivated($container->getAccountModule('windowsUser')->getAttributes())) {
$windowsPasswordLockedTime = null;
$windowsPasswordLocked = false;
if ($windowsAvailable){
$attrs = $container->getAccountModule('windowsUser')->getAttributes();
$attrs['dn'] = $container->dn_orig;
if (windowsUser::isDeactivated($attrs)) {
$windowsLocked = true;
}
$partiallyLocked = $unixLocked || $sambaLocked || $ppolicyLocked || $windowsLocked || $is389dsDeactivated || $is389dsLocked;
$windowsPasswordLockedTime = windowsUser::getPasswordLocked($attrs, $this->getType());
if ($windowsPasswordLockedTime != null) {
$windowsPasswordLocked = true;
}
}
$partiallyLocked = $unixLocked || $sambaLocked
|| $ppolicyLocked || $windowsLocked || $windowsPasswordLocked
|| $is389dsDeactivated || $is389dsLocked;
$fullyLocked = ($unixAvailable || $sambaAvailable || $ppolicyAvailable || $windowsAvailable || $is389dsDeactivated || $is389dsLocked)
&& (!$unixAvailable || $unixLocked)
&& (!$sambaAvailable || $sambaLocked)
@ -309,6 +321,9 @@ class user extends baseType {
}
$statusTable .= '<tr><td>' . _('Windows') . '&nbsp;&nbsp;</td><td><img height=16 width=16 src=&quot;../../graphics/' . $windowsIcon . '&quot;></td></tr>';
}
if ($windowsAvailable && $windowsPasswordLocked) {
$statusTable .= '<tr><td>' . _('Locked till') . '&nbsp;&nbsp;</td><td>' . $windowsPasswordLockedTime->format('Y-m-d H:i:s') . '</td></tr>';
}
// 389ds locked
if ($is389dsLocked) {
$statusTable .= '<tr><td>' . _('Locked') . '&nbsp;&nbsp;</td><td><img height=16 width=16 src=&quot;../../graphics/lock.png&quot;></td></tr>';
@ -325,7 +340,7 @@ class user extends baseType {
$tipContent .= '<br><img alt=&quot;hint&quot; src=&quot;../../graphics/light.png&quot;> ';
$tipContent .= _('Please click to lock/unlock this account.');
}
$dialogDiv = $this->buildAccountStatusDialogDiv($unixAvailable, $unixLocked, $sambaAvailable, $sambaLocked, $ppolicyAvailable, $ppolicyLocked, $windowsAvailable, $windowsLocked, $is389dsAvailable, $is389dsLocked, $is389dsDeactivated);
$dialogDiv = $this->buildAccountStatusDialogDiv($unixAvailable, $unixLocked, $sambaAvailable, $sambaLocked, $ppolicyAvailable, $ppolicyLocked, $windowsAvailable, $windowsLocked, $windowsPasswordLockedTime, $is389dsAvailable, $is389dsLocked, $is389dsDeactivated);
$onClick = '';
if ($isEditable) {
$onClick = 'onclick="showConfirmationDialog(\'' . _('Change account status') . '\', \'' . _('Ok') . '\', \'' . _('Cancel') . '\', \'lam_accountStatusDialog\', \'inputForm\', \'lam_accountStatusResult\');"';
@ -344,18 +359,20 @@ class user extends baseType {
* @param boolean $ppolicyLocked PPolicy part is locked
* @param boolean $windowsAvailable Windows part is active
* @param boolean $windowsLocked Windows part is locked
* @param DateTime $windowsPasswordLockedTime lock time for Windows or null
* @param boolean $is389dsAvailable 389ds is available
* @param boolean $is389dsLocked account is locked
* @param boolean $is389dsDeactivated account is deactivated
*/
private function buildAccountStatusDialogDiv($unixAvailable, $unixLocked, $sambaAvailable, $sambaLocked, $ppolicyAvailable, $ppolicyLocked, $windowsAvailable,
$windowsLocked, $is389dsAvailable, $is389dsLocked, $is389dsDeactivated) {
$partiallyLocked = $unixLocked || $sambaLocked || $ppolicyLocked || $windowsLocked || $is389dsLocked || $is389dsDeactivated;
$windowsLocked, $windowsPasswordLockedTime, $is389dsAvailable, $is389dsLocked, $is389dsDeactivated) {
$windowsPasswordLocked = ($windowsPasswordLockedTime != null);
$partiallyLocked = $unixLocked || $sambaLocked || $ppolicyLocked || $windowsLocked || $windowsPasswordLocked || $is389dsLocked || $is389dsDeactivated;
$fullyLocked = ($unixAvailable || $sambaAvailable || $ppolicyAvailable || $windowsAvailable || $is389dsLocked || $is389dsDeactivated)
&& (!$unixAvailable || $unixLocked)
&& (!$sambaAvailable || $sambaLocked)
&& (!$ppolicyAvailable || $ppolicyLocked)
&& (!$windowsAvailable || $windowsLocked);
&& (!$windowsAvailable || $windowsLocked || $windowsPasswordLocked);
$container = new htmlTable();
@ -454,6 +471,10 @@ class user extends baseType {
$unlockContent->addElement(new htmlImage('../../graphics/samba.png'));
$unlockContent->addElement(new htmlTableExtendedInputCheckbox('lam_accountStatusUnlockWindows', true, _('Windows'), null, false), true);
}
if ($windowsAvailable && $windowsPasswordLocked) {
$unlockContent->addElement(new htmlImage('../../graphics/samba.png'));
$unlockContent->addElement(new htmlTableExtendedInputCheckbox('lam_accountStatusUnlockWindowsPassword', true, _('Locked till') . ' ' . $windowsPasswordLockedTime->format('Y-m-d H:i:s'), null, false), true);
}
if ($is389dsLocked) {
$unlockContent->addElement(new htmlImage('../../graphics/security.png'));
$unlockContent->addElement(new htmlTableExtendedInputCheckbox('lam_accountStatusUnlock389ds', true, _('Unlock'), null, false), true);
@ -540,6 +561,10 @@ class user extends baseType {
if (isset($_POST['lam_accountStatusUnlockWindows']) && ($_POST['lam_accountStatusUnlockWindows'] == 'on')) {
$container->getAccountModule('windowsUser')->setIsDeactivated(false);
}
// Windows password
if (isset($_POST['lam_accountStatusUnlockWindowsPassword']) && ($_POST['lam_accountStatusUnlockWindowsPassword'] == 'on')) {
$container->getAccountModule('windowsUser')->unlockPassword();
}
// 389ds unlocking
if (isset($_POST['lam_accountStatusUnlock389ds']) && ($_POST['lam_accountStatusUnlock389ds'] == 'on')) {
$container->getAccountModule('locking389ds')->unlock(false);
@ -869,6 +894,7 @@ class lamUserList extends lamList {
$attrs[] = 'sambaAcctFlags';
$attrs[] = 'userPassword';
$attrs[] = 'userAccountControl';
$attrs[] = 'lockoutTime';
$attrs[] = 'nsAccountLock';
$attrs[] = 'accountUnlockTime';
$attrs[] = 'objectClass';
@ -890,12 +916,13 @@ class lamUserList extends lamList {
$sambaLocked = self::isSambaLocked($this->entries[$i]);
$ppolicyLocked = self::isPPolicyLocked($this->entries[$i]);
$windowsLocked = self::isWindowsLocked($this->entries[$i]);
$windowsPasswordLocked = ($this->getWindowsPasswordLockedTime($this->entries[$i]) != null);
$is389dsLocked = self::is389dsLocked($this->entries[$i]);
$is389dsDeactivated = self::is389dsDeactivated($this->entries[$i]);
$hasLocked = ($unixAvailable && $unixLocked)
|| ($sambaAvailable && $sambaLocked)
|| ($ppolicyAvailable && $ppolicyLocked)
|| ($windowsAvailable && $windowsLocked)
|| ($windowsAvailable && ($windowsLocked || $windowsPasswordLocked))
|| $is389dsDeactivated
|| $is389dsLocked;
$hasUnlocked = ($unixAvailable && !$unixLocked)
@ -937,9 +964,13 @@ class lamUserList extends lamList {
$sambaLocked = self::isSambaLocked($attrs);
$ppolicyLocked = self::isPPolicyLocked($attrs);
$windowsLocked = self::isWindowsLocked($attrs);
$windowsPasswordLockedTime = $this->getWindowsPasswordLockedTime($attrs);
$windowsPasswordLocked = ($windowsPasswordLockedTime != null);
$is389dsDeactivated = self::is389dsDeactivated($attrs);
$is389dsLocked = self::is389dsLocked($attrs);
$partiallyLocked = $unixLocked || $sambaLocked || $ppolicyLocked || $windowsLocked || $is389dsDeactivated || $is389dsLocked;
$partiallyLocked = $unixLocked || $sambaLocked
|| $ppolicyLocked || $windowsLocked || $windowsPasswordLocked
|| $is389dsDeactivated || $is389dsLocked;
$fullyLocked = ($unixAvailable || $sambaAvailable || $ppolicyAvailable || $windowsAvailable || $is389dsDeactivated || $is389dsLocked)
&& (!$unixAvailable || $unixLocked)
&& (!$sambaAvailable || $sambaLocked)
@ -987,6 +1018,9 @@ class lamUserList extends lamList {
}
$tipContent .= '<tr><td>' . _('Windows') . '&nbsp;&nbsp;</td><td><img height=16 width=16 src=&quot;../../graphics/' . $windowsIcon . '&quot;></td></tr>';
}
if ($windowsAvailable && $windowsPasswordLocked) {
$tipContent .= '<tr><td>' . _('Locked till') . '&nbsp;&nbsp;</td><td>' . $windowsPasswordLockedTime->format('Y-m-d H:i:s') . '</td></tr>';
}
// 389 locked
if ($is389dsLocked) {
$tipContent .= '<tr><td>' . _('Locked') . '&nbsp;&nbsp;</td><td><img height=16 width=16 src=&quot;../../graphics/lock.png&quot;></td></tr>';
@ -1083,6 +1117,16 @@ class lamUserList extends lamList {
return windowsUser::isDeactivated($attrs);
}
/**
* Returns if the Windows password is locked.
*
* @param array $attrs LDAP attributes
* @return DateTime Windows password lock time or null
*/
public function getWindowsPasswordLockedTime(&$attrs) {
return windowsUser::getPasswordLocked($attrs, $this->type);
}
/**
* Returns if the 389ds is activated.
*