|
|
|
@ -3915,7 +3915,8 @@ class windowsUser extends baseModule implements passwordService {
|
|
|
|
|
return array(
|
|
|
|
|
new WindowsPasswordNotifyJob(),
|
|
|
|
|
new WindowsAccountExpirationCleanupJob(),
|
|
|
|
|
new WindowsAccountExpirationNotifyJob()
|
|
|
|
|
new WindowsAccountExpirationNotifyJob(),
|
|
|
|
|
new WindowsManagedGroupsNotifyJob()
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -4147,6 +4148,299 @@ if (interface_exists('\LAM\JOB\Job', false)) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Job to notify users about their managed groups.
|
|
|
|
|
*
|
|
|
|
|
* @package jobs
|
|
|
|
|
*/
|
|
|
|
|
class WindowsManagedGroupsNotifyJob extends \LAM\JOB\PasswordExpirationJob {
|
|
|
|
|
|
|
|
|
|
const MANAGED_GROUPS = 'LAM_MANAGED_GROUPS';
|
|
|
|
|
const PERIOD_MONTHLY = 'MONTHLY';
|
|
|
|
|
const PERIOD_QUARTERLY = 'QUARTERLY';
|
|
|
|
|
const PERIOD_HALF_YEARLY = 'HALF_YEARLY';
|
|
|
|
|
const PERIOD_YEARLY = 'YEARLY';
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns the alias name of the job.
|
|
|
|
|
*
|
|
|
|
|
* @return String name
|
|
|
|
|
*/
|
|
|
|
|
public function getAlias() {
|
|
|
|
|
return _('Windows') . ': ' . _('Notify users about their managed groups');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @inheritDoc
|
|
|
|
|
*/
|
|
|
|
|
public function getDescription() {
|
|
|
|
|
return _('This will send each user a summary of the managed groups and their members.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @inheritDoc
|
|
|
|
|
*/
|
|
|
|
|
public function getConfigOptions($jobID) {
|
|
|
|
|
$prefix = $this->getConfigPrefix();
|
|
|
|
|
$container = new htmlResponsiveRow();
|
|
|
|
|
$container->add(new htmlResponsiveInputField(_('From address'), $prefix . '_mailFrom' . $jobID, null, '800', true), 12);
|
|
|
|
|
$container->add(new htmlResponsiveInputField(_('Reply-to address'), $prefix . '_mailReplyTo' . $jobID, null, '801'), 12);
|
|
|
|
|
$container->add(new htmlResponsiveInputField(_('CC address'), $prefix . '_mailCC' . $jobID, null, '805'), 12);
|
|
|
|
|
$container->add(new htmlResponsiveInputField(_('BCC address'), $prefix . '_mailBCC' . $jobID, null, '806'), 12);
|
|
|
|
|
$container->add(new htmlResponsiveInputField(_('Subject'), $prefix . '_mailSubject' . $jobID, null, '802'), 12);
|
|
|
|
|
$container->add(new htmlResponsiveInputCheckbox($prefix . '_mailIsHTML' . $jobID, false, _('HTML format'), '553'), 12);
|
|
|
|
|
$container->add(new htmlResponsiveInputTextarea($prefix . '_mailtext' . $jobID, '', 50, 4, _('Text'), '810'), 12);
|
|
|
|
|
$periodOptions = array(
|
|
|
|
|
_('Monthly') => self::PERIOD_MONTHLY,
|
|
|
|
|
_('Quarterly') => self::PERIOD_QUARTERLY,
|
|
|
|
|
_('Half-yearly') => self::PERIOD_HALF_YEARLY,
|
|
|
|
|
_('Yearly') => self::PERIOD_YEARLY,
|
|
|
|
|
);
|
|
|
|
|
$periodSelect = new htmlResponsiveSelect($prefix . '_period' . $jobID, $periodOptions, array(), _('Period'), '811');
|
|
|
|
|
$periodSelect->setHasDescriptiveElements(true);
|
|
|
|
|
$periodSelect->setSortElements(false);
|
|
|
|
|
$container->add($periodSelect, 12);
|
|
|
|
|
return $container;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @inheritDoc
|
|
|
|
|
*/
|
|
|
|
|
public function checkConfigOptions($jobID, $options) {
|
|
|
|
|
$prefix = $this->getConfigPrefix();
|
|
|
|
|
$errors = array();
|
|
|
|
|
// from address
|
|
|
|
|
if (empty($options[$prefix . '_mailFrom' . $jobID][0])
|
|
|
|
|
|| !(get_preg($options[$prefix . '_mailFrom' . $jobID][0], 'email')
|
|
|
|
|
|| get_preg($options[$prefix . '_mailFrom' . $jobID][0], 'emailWithName'))) {
|
|
|
|
|
$errors[] = array('ERROR', _('Please enter a valid email address!'), _('From address'));
|
|
|
|
|
}
|
|
|
|
|
// reply-to
|
|
|
|
|
if (!empty($options[$prefix . '_mailReplyTo' . $jobID][0])
|
|
|
|
|
&& !get_preg($options[$prefix . '_mailReplyTo' . $jobID][0], 'email')
|
|
|
|
|
&& !get_preg($options[$prefix . '_mailReplyTo' . $jobID][0], 'emailWithName')) {
|
|
|
|
|
$errors[] = array('ERROR', _('Please enter a valid email address!'), _('Reply-to address'));
|
|
|
|
|
}
|
|
|
|
|
// CC address
|
|
|
|
|
if (!empty($options[$prefix . '_mailCC' . $jobID][0])
|
|
|
|
|
&& !get_preg($options[$prefix . '_mailCC' . $jobID][0], 'email')
|
|
|
|
|
&& !get_preg($options[$prefix . '_mailCC' . $jobID][0], 'emailWithName')) {
|
|
|
|
|
$errors[] = array('ERROR', _('Please enter a valid email address!'), _('CC address'));
|
|
|
|
|
}
|
|
|
|
|
// BCC address
|
|
|
|
|
if (!empty($options[$prefix . '_mailBCC' . $jobID][0])
|
|
|
|
|
&& !get_preg($options[$prefix . '_mailBCC' . $jobID][0], 'email')
|
|
|
|
|
&& !get_preg($options[$prefix . '_mailBCC' . $jobID][0], 'emailWithName')) {
|
|
|
|
|
$errors[] = array('ERROR', _('Please enter a valid email address!'), _('BCC address'));
|
|
|
|
|
}
|
|
|
|
|
// text
|
|
|
|
|
$mailText = implode('', $options[$prefix . '_mailtext' . $jobID]);
|
|
|
|
|
if (empty($mailText)) {
|
|
|
|
|
$errors[] = array('ERROR', _('Please set a email text.'));
|
|
|
|
|
}
|
|
|
|
|
if (strpos($mailText, '@@' . self::MANAGED_GROUPS . '@@') === false) {
|
|
|
|
|
$errors[] = array('ERROR', _('Please add the wildcard for the list of managed groups.'), '@@' . self::MANAGED_GROUPS . '@@');
|
|
|
|
|
}
|
|
|
|
|
return $errors;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @inheritDoc
|
|
|
|
|
*/
|
|
|
|
|
protected function getPolicyOptions() {
|
|
|
|
|
return array();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Searches for users in LDAP.
|
|
|
|
|
*
|
|
|
|
|
* @param String $jobID unique job identifier
|
|
|
|
|
* @param array $options config options (name => value)
|
|
|
|
|
* @return array list of user attributes
|
|
|
|
|
*/
|
|
|
|
|
protected function findUsers($jobID, $options) {
|
|
|
|
|
// read users
|
|
|
|
|
$sysAttrs = array('managedObjects', 'mail');
|
|
|
|
|
$attrs = $this->getAttrWildcards($jobID, $options);
|
|
|
|
|
$attrs = array_values(array_unique(array_merge($attrs, $sysAttrs)));
|
|
|
|
|
$users = searchLDAPByFilter('(&(mail=*)(managedObjects=*))', $attrs, array('user'));
|
|
|
|
|
$groups = searchLDAPByFilter('(managedBy=*)', array('cn', 'member'), array('group'));
|
|
|
|
|
$groupByDn = array();
|
|
|
|
|
foreach ($groups as $group) {
|
|
|
|
|
$groupByDn[$group['dn']] = $group;
|
|
|
|
|
}
|
|
|
|
|
$groups = null;
|
|
|
|
|
foreach ($users as $index => $user) {
|
|
|
|
|
$managedObjectDns = $user['managedobjects'];
|
|
|
|
|
$managedGroups = array();
|
|
|
|
|
foreach ($managedObjectDns as $managedObjectDn) {
|
|
|
|
|
if (array_key_exists($managedObjectDn, $groupByDn)) {
|
|
|
|
|
$managedGroups[] = $groupByDn[$managedObjectDn];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$users[$index][strtolower(self::MANAGED_GROUPS)] = $managedGroups;
|
|
|
|
|
}
|
|
|
|
|
return $users;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @inheritDoc
|
|
|
|
|
*/
|
|
|
|
|
public function execute($jobID, $options, &$pdo, $isDryRun, &$resultLog) {
|
|
|
|
|
$this->jobResultLog = &$resultLog;
|
|
|
|
|
$this->jobResultLog->logDebug("Configuration options:");
|
|
|
|
|
foreach ($options as $key => $value) {
|
|
|
|
|
if (strpos($key, $jobID) === false) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
$this->jobResultLog->logDebug($key . ': ' . implode(', ', $value));
|
|
|
|
|
}
|
|
|
|
|
$now = new DateTime(null, getTimeZone());
|
|
|
|
|
$baseDate = $this->getBaseDate($now);
|
|
|
|
|
$monthInterval = $this->getMonthInterval($options, $jobID);
|
|
|
|
|
if (!$this->shouldRun($pdo, $options, $jobID, $baseDate, $monthInterval)) {
|
|
|
|
|
$this->jobResultLog->logDebug('No run needed yet');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
$userResults = $this->findUsers($jobID, $options);
|
|
|
|
|
$this->jobResultLog->logDebug("Found " . sizeof($userResults) . " users to send an email.");
|
|
|
|
|
$isHTML = (!empty($options[$this->getConfigPrefix() . '_mailIsHTML' . $jobID][0]) && ($options[$this->getConfigPrefix() . '_mailIsHTML' . $jobID][0] == 'true'));
|
|
|
|
|
foreach ($userResults as $user) {
|
|
|
|
|
if (empty($user[strtolower(self::MANAGED_GROUPS)])) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
$user[strtolower(self::MANAGED_GROUPS)][0] = $this->formatGroups($user[strtolower(self::MANAGED_GROUPS)], $isHTML);
|
|
|
|
|
if ($isDryRun) {
|
|
|
|
|
// no action for dry run
|
|
|
|
|
$this->jobResultLog->logInfo("Managed groups text for " . $user['dn'] . ":\n" . $user[strtolower(self::MANAGED_GROUPS)][0]);
|
|
|
|
|
$this->jobResultLog->logInfo('Not sending email to ' . $user['dn'] . ' because of dry run.');
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
// send email
|
|
|
|
|
$this->sendMail($options, $jobID, $user, null);
|
|
|
|
|
}
|
|
|
|
|
if (!$isDryRun) {
|
|
|
|
|
$this->setDBLastPwdChangeTime($jobID, $pdo, $jobID, self::getLastEffectiveExecutionDate($baseDate, $monthInterval, $this->jobResultLog)->format('Y-m-d'));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns if the job should run.
|
|
|
|
|
*
|
|
|
|
|
* @param $pdo PDO
|
|
|
|
|
* @param $options job options
|
|
|
|
|
* @param $jobId job id
|
|
|
|
|
* @param DateTime $baseDate base date
|
|
|
|
|
* @param int $monthInterval month interval
|
|
|
|
|
* @return bool should run
|
|
|
|
|
*/
|
|
|
|
|
private function shouldRun(&$pdo, $options, $jobId, $baseDate, $monthInterval) {
|
|
|
|
|
$dbLastChange = $this->getDBLastPwdChangeTime($jobId, $pdo, $jobId);
|
|
|
|
|
if (empty($dbLastChange)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
$this->jobResultLog->logDebug('Base date: ' . $baseDate->format('Y-m-d'));
|
|
|
|
|
$effectiveDate = self::getLastEffectiveExecutionDate($baseDate, $monthInterval, $this->jobResultLog);
|
|
|
|
|
$dbLastChangeDate = DateTime::createFromFormat('Y-m-d', $dbLastChange, getTimeZone());
|
|
|
|
|
$this->jobResultLog->logDebug('Last run date: ' . $dbLastChangeDate->format('Y-m-d'));
|
|
|
|
|
return $effectiveDate > $dbLastChangeDate;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns the month interval.
|
|
|
|
|
*
|
|
|
|
|
* @param arry $options config options
|
|
|
|
|
* @param $jobId job id
|
|
|
|
|
* @return int interval
|
|
|
|
|
*/
|
|
|
|
|
private function getMonthInterval($options, $jobId) {
|
|
|
|
|
$monthInterval = 12;
|
|
|
|
|
switch ($options[$this->getConfigPrefix() . '_period' . $jobId][0]) {
|
|
|
|
|
case self::PERIOD_HALF_YEARLY:
|
|
|
|
|
$monthInterval = 6;
|
|
|
|
|
break;
|
|
|
|
|
case self::PERIOD_QUARTERLY:
|
|
|
|
|
$monthInterval = 3;
|
|
|
|
|
break;
|
|
|
|
|
case self::PERIOD_MONTHLY:
|
|
|
|
|
$monthInterval = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return $monthInterval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns the base date (first of month) for the current date.
|
|
|
|
|
*
|
|
|
|
|
* @param DateTime $currentDate current date
|
|
|
|
|
* @return DateTime base date
|
|
|
|
|
*/
|
|
|
|
|
private function getBaseDate($currentDate) {
|
|
|
|
|
$baseDateText = $currentDate->format('Y-m-') . '1';
|
|
|
|
|
return DateTime::createFromFormat('Y-m-d', $baseDateText, getTimeZone());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns the last effective execution date.
|
|
|
|
|
*
|
|
|
|
|
* @param DateTime $baseDate base date
|
|
|
|
|
* @param int $monthInterval number of months in interval
|
|
|
|
|
* @param \LAM\JOB\JobResultLog $resultLog result log
|
|
|
|
|
*/
|
|
|
|
|
public static function getLastEffectiveExecutionDate($baseDate, $monthInterval, $resultLog) {
|
|
|
|
|
$month = $baseDate->format('m');
|
|
|
|
|
$monthIndex = $month - 1;
|
|
|
|
|
while (($monthIndex % $monthInterval) !== 0) {
|
|
|
|
|
$monthIndex--;
|
|
|
|
|
}
|
|
|
|
|
$month = $monthIndex + 1;
|
|
|
|
|
$effectiveDateString = $baseDate->format('Y-') . $month . '-1';
|
|
|
|
|
$effectiveDate = DateTime::createFromFormat('Y-m-d', $effectiveDateString, getTimeZone());
|
|
|
|
|
$resultLog->logDebug("Effective date: " . $effectiveDate->format('Y-m-d'));
|
|
|
|
|
return $effectiveDate;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @inheritDoc
|
|
|
|
|
*/
|
|
|
|
|
protected function checkSingleUser($jobID, $options, &$pdo, $now, $policyOptions, $user, $isDryRun) {
|
|
|
|
|
// not used
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Formats the managed groups.
|
|
|
|
|
*
|
|
|
|
|
* @param $managedGroups managed groups
|
|
|
|
|
* @param bool $isHTML HTML email
|
|
|
|
|
* @return string formatted text
|
|
|
|
|
*/
|
|
|
|
|
private function formatGroups($managedGroups, bool $isHTML) {
|
|
|
|
|
$text = '';
|
|
|
|
|
foreach ($managedGroups as $managedGroup) {
|
|
|
|
|
if ($isHTML) {
|
|
|
|
|
$text .= '<br><b>' . $managedGroup['cn'][0] . '</b><br>';
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$text .= "\r\n" . $managedGroup['cn'][0] . "\r\n\r\n";
|
|
|
|
|
}
|
|
|
|
|
if (empty($managedGroup['member'])) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
foreach ($managedGroup['member'] as $member) {
|
|
|
|
|
$member = getAbstractDN($member);
|
|
|
|
|
if ($isHTML) {
|
|
|
|
|
$text .= ' ' . $member . '<br>';
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$text .= " " . $member . "\r\n";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $text;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Job to notify users about account expiration.
|
|
|
|
|
*
|
|
|
|
|