Hello,
Bellow is a script I put together to notify users via e-mail about their domain account password expiration.
The script is set to:
- notify users when there are 7 or 3 or 1 days left until the password will expire;
- create ticket via e-mail when there are 7, 3, 1 days left until the password will expire, but there’s no e-mail address set for that account;
- create ticket via e-mail when password already expired ( this can be easily changed to “spam” the user). Please note this will basically open a ticket/day until the problem is solved.
- create ticket via e-mail when password already expired and also there’s no e-mail address set for that account. Please note this will basically open a ticket/day until the problem is solved.
So, basically, the script is composed of 5 files: the main script, handling the data and 4 “e-mail templates”, 1 for each situation described above.
Some problems I encountered while working on this script:
- You will probably want to exclude from the accounts to be verified the following:
- guest and administrator accounts
- service accounts
- other accounts, which, for whatever reason, have the password set to never expire.
- while retrieving the data, you will need to escape [count] from the array generated by ldap_get_entries function. I solved this by using a little function. Others may consider something else.
Prerequisites:
- you will need a service account set in your AD;
- a webserver to handle the PHP and PHP Ldap ( I used Debian 8 & Lamp ). For an easy tutorial, please check this link
- access to the system crontab ( or, if using other OS, a way to schedule the script to run once every day ) . Check this link if you need help understanding the crontab mechanism.
Main script:
I tried to document all steps in the script, however, you can just remove the comments.
Also, make sure you are using a correct base dn, that includes all the user accounts.
<?php /* SCRIPT : ldap_notify_expire_pass.php AUTHOR : Marin Nedea WEBSITE : http://urbanlinux.com BLOG : http://urbanlinux.com CREATED : 09-11-2016 COMMENT : Script to notify AD users via e-mail when their password is about to expire or to notify the admins team via e-mail/ticket. LICENSE : Copyright (C) 2016 - Marin Nedea @ http://urbanlinux.com 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 the Free Software Foundation, either version 3 of the License, or at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ set_time_limit(30); ini_set('error_reporting', E_ALL); ini_set('display_errors',0); // LDAP server config $ldapserver = 'example.com'; $ldapuser = 'serviceuser'; $ldappass = 'password_here'; $base_dn = 'CN=Users,DC=example,DC=com'; // Connect to AD $ldapconn = ldap_connect($ldapserver) or die('Could not connect to LDAP server.'); // Using LDAP version 3. Change the version to 2 if needed ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3); // If you try to perform the searches on Windows 2003 Server Active Directory or above, it seems that you have to set the LDAP_OPT_REFERRALS option to 0. // Without this, you will get "Operations error" if you try to search the whole AD (using root of the domain as a $base_dn). ldap_set_option($ldapconn, LDAP_OPT_REFERRALS, 0); if($ldapconn) { // Binding to AD $ldapbind = ldap_bind($ldapconn, $ldapuser, $ldappass) or die ('Error trying to bind: '.ldap_error($ldapconn)); // If bind was successful if ($ldapbind) { // echo 'Connected to LDAP server<br /><br />'; /* I know that (objectCategory=person) and (objectClass=user) are kind of redundant, but the result will be correct; Remove from the search the default Guest account, the Adminstrator Account, the group containing the Service Accounts and the accounts marked for deletion. */ //Set a search filter $filter='(&(objectCategory=person)(objectClass=user)(!(sAMAccountName=Guest))(!(sAMAccountName=Administrator)))'; // Set an array of attributes you wish to retrieve for each entry $attrs = array('cn', 'displayname', 'sn', 'givenname', 'mail', 'samaccountname', 'pwdlastset', 'useraccountcontrol', 'memberof'); // Set the search $result = ldap_search($ldapconn, $base_dn, $filter, $attrs) or die ('Error in search query: '.ldap_error($ldapconn)); // Get an array containg the results $data = ldap_get_entries($ldapconn, $result); // Function to remove [count] from the ldap_get_entries result // See http://stackoverflow.com/questions/5997815/php-strip-count-value-from-array for details. function rCountRemover($arr) { foreach($arr as $key=>$val) { // (int)0 == "count", so we need to use === if($key === "count") unset($arr[$key]); elseif(is_array($val)) $arr[$key] = rCountRemover($arr[$key]); } return $arr; } // Renew $data array using the function above $data = rCountRemover($data); // Print number of entries found // echo 'Results: ' . ldap_count_entries($ldapconn, $result) . '<br />; // Get the data parsed for each entry foreach($data as $key => $value) { $user_display_name = ucfirst($userinfo['displayname'][0]; $username = $value['samaccountname'][0]; $user_email = $value['mail'][0]; // Get the time since last password change $fileTime = $value['pwdlastset'][0]; $winSecs = (int)($fileTime / 10000000); // divide by 10 000 000 to get seconds $unixTimestamp = ($winSecs - 11644473600); // 1.1.1600 -> 1.1.1970 difference in seconds $timestamp = date(DateTime::RFC822, $unixTimestamp); // time passed since Last Password Change $date2 = date_create($timestamp); $datetime2 = date_format($date2, 'Y-m-d'); $since = strtotime($datetime2); $today = time(); $difference = $today - $since; // Get the number of days till the password will expire $expire_days = floor($difference / (60 * 60 * 24)); // Get the remaining days till the password expire $remaining_days = 90 - $expire_days; /* In order to avoid spam ( you don't wanna send an e-mail every day, do you?), I decided to send e-mails when the remainig days until the password will expire are 1, 3 or 7. So .. I'm making a simple array containg the numbers 1,3 7 */ $a = array(1,3,7); // checking if the value of $expire_days will match values in our array $a if (in_array(''.$expire_days.'', $a)){ // Preparing to send e-mail. We need to check if we have an e-amil address to send to. // Also, please check https://css-tricks.com/sending-nice-html-email-with-php/ for information // on sending HTML formated e-mail. if(empty($user_email)){ /* If there's no e-mail address set for the user, we need to notify someone (an admin member, or a ticketing system) by e-mail, to update the account for that user with an e-mail address. We are using OTRS as ticketing system here, so I set an e-mail account on our e-mail server just for the OTRS, and I'm fetching in OTRS the e-mails every 5 minutes. The advantage of this is that, in case the e-mail address of your recipient is set wrong in the Active Directory, when sending the e-mail you will also get an error reply mail on your inbox. Since OTRS is fetching the e-mails in that inbox, it will creat a ticket and let you know that a specific e-mail address is incorrect/doesn't exists. If you are using a different method, you could use, with similar result, a service e-mail account that everyone in your team is reading frequently. */ // Setting the $user_email to a hardcoded value, corresponding to our ticketing system/service e-maila ccount $user_email = 'ticketing@example.com'; // Including the formated e-mail to create a ticket. include('ticketing_mail.php'); /* echo '<pre>'; echo $username.'<br />'; echo $user_email.'<br />'; echo $remaining_days.'<br />'; echo 'creating ticket - email empty<br />'; echo '</pre>'; */ } else { // Including the script to send e-mail to the user include('reset_pass_mail.php'); /* echo '<pre>'; echo $username.'<br />'; echo $user_email.'<br />'; echo $remaining_days.'<br />'; echo 'notify user - will expire pass<br />'; echo '</pre>'; */ } } else if($expire_days > 90){ // If password already expired if(empty($user_email)){ // Setting the $user_email to a hardcoded value, corresponding to our ticketing system/service e-maila ccount $user_email = 'ticketing@example.com'; // Including the formated e-mail to create a ticket. include('ticketing_expired_no_email_mail.php'); /* echo '<pre>'; echo $username.'<br />'; echo $user_email.'<br />'; echo $remaining_days.'<br />'; echo 'creating ticket - email empty and password expired<br />'; echo '</pre>'; */ } else { // Create a ticket in ticketing system, letting know the admins the user // didn't renew his password. include('expire_password_ticketing_mail.php'); /* echo '<pre>'; echo $username.'<br />'; echo $user_email.'<br />'; echo $remaining_days.'<br />'; echo 'creating ticket - password expired<br />'; echo '</pre>'; */ } } /* // Uncomment this if you wish to list the accounts without password problems. else { // Close if password already expired echo '<pre>'; echo $username.'<br />'; echo $user_email.'<br />'; echo $remaining_days.'<br />'; echo 'All OK<br />'; echo '</pre>'; } */ // NOTE: // You need to replace "-fserver_email@example.com" with your actual e-mail account used to send // e-mails. // Please make sure you keep the "-f" (envelope FROM: ) in front of the e-mail address! If your e-mail // is, let's say, no-reply@example.com, in the script you should have "-fno-reply@example.com". Please check // http://stackoverflow.com/questions/179014/how-to-change-envelope-from-address-using-php-mail for more. // Sending the actual mail mail($to, $subject, $message, $headers, '-fserver_email@example.com'); } // close foreach } else { // Close if bind echo 'LDAP bind failed...'; } } // close LDAP connection ldap_close($ldapconn); ?>
E-mail templates:
Case 1: password about to expire, the account has an e-mail address set.
<?php /* SCRIPT : will_expire_with_email.php AUTHOR : Marin Nedea WEBSITE : http://urbanlinux.com BLOG : http://urbanlinux.com CREATED : 09-11-2016 COMMENT : This is a mail template used to notify users via e-mail when their AD password is about to expire. LICENSE : Copyright (C) 2016 - Marin Nedea @ http://urbanlinux.com 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 the Free Software Foundation, either version 3 of the License, or at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ $subject = 'Your Domain Account password is about to expire in '. $expire_days .' days'; // Prepare the e-mail to be sent $headers = 'MIME-Version: 1.0' . "\r\n"; $headers .= 'Content-type: text/html; charset=utf-8' . "\r\n"; $headers .= 'To:<'.$usermailaddress.'>'."\r\n"; $headers .= 'From: Support Team <no-reply@example.com>' . "\r\n"; $headers .= 'Subject:'.$subject.''."\r\n"; $message = '<html> <body> <p>Hello ' .$user_display_name.', <br /> <br /> The password for your Domain account ' .$username. ' will expire in ' .$expire_days.' days. <br /><br /> <p> To change your domain Account password, please <a href="#">click here</a> and follow instructions in the page.<br /> If you are unable to change the password, for whatever reason, please open a ticket to us via the ticketing system.<br /><br /> <strong>Please note this is an automated e-mail and <i>shall</i> not be replied!</strong><br /><br /> <br /> Best Regards,<br /> The Support Team </p> </body> </html>'; ?>
Case 2: Password about to expire, the account has no e-mail address set, opening ticket.
<?php /* SCRIPT : will_expire_no_email.php AUTHOR : Marin Nedea WEBSITE : http://urbanlinux.com BLOG : http://urbanlinux.com CREATED : 09-11-2016 COMMENT : This is a mail template used to notify admins via e-mail/ticket when someone's AD account password is about to expire, but there's no e-mail address set for that account. LICENSE : Copyright (C) 2016 - Marin Nedea @ http://urbanlinux.com 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 the Free Software Foundation, either version 3 of the License, or at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ $subject = 'The password for the Domain Account ' .$username. ' will expire in '. $expire_days .' days'; // Prepare the e-mail to be sent $headers = 'MIME-Version: 1.0' . "\r\n"; $headers .= 'Content-type: text/html; charset=utf-8' . "\r\n"; $headers .= 'To:<tickets@example.com>'."\r\n"; $headers .= 'From: Support Team <support@example.com>' . "\r\n"; $headers .= 'Subject:'.$subject.''."\r\n"; $message = '<html> <body> <p>Hello ' .$user_display_name.', <br /> <br /> The password for the Domain account ' .$username. ' will expire in ' . $expire_days .' days but there\'s no e-mail address set for this account. <br /><br /> <p> Please verify if the account and update the e-mail address.<br /><br /> <strong>Please note this is an automated e-mail and <i>shall</i> not be replied!</strong><br /><br /> <br /> Best Regards,<br /> The Support Team </p> </body> </html>'; ?>
Case 3: Password expired – opening ticket.
<?php /* SCRIPT : expired_with_mail.php AUTHOR : Marin Nedea WEBSITE : http://urbanlinux.com BLOG : http://urbanlinux.com CREATED : 09-11-2016 COMMENT : This is a mail template used to notify admins via e-mail/ticket when someone's AD account password is already expired. LICENSE : Copyright (C) 2016 - Marin Nedea @ http://urbanlinux.com 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 the Free Software Foundation, either version 3 of the License, or at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ $subject = 'The password for the Domain Account ' .$username. ' expired'; // Prepare the e-mail to be sent $headers = 'MIME-Version: 1.0' . "\r\n"; $headers .= 'Content-type: text/html; charset=utf-8' . "\r\n"; $headers .= 'To:<tickets@example.com>'."\r\n"; $headers .= 'From: Support Team <support@example.com>' . "\r\n"; $headers .= 'Subject:'.$subject.''."\r\n"; $message = '<html> <body> <p>Hello ' .$user_display_name.', <br /> <br /> The password for the Domain account ' .$username. ' expired ' . $remaining_days .' days ago. <br /><br /> <p> Please verify if the account owner still needs this account.<br /><br /> <strong>Please note this is an automated e-mail and <i>shall</i> not be replied!</strong><br /><br /> <br /> Best Regards,<br /> The Support Team </p> </body> </html>'; ?>
Case 4: Password expired and also account has no e-mail address set – opening ticket.
<?php /* SCRIPT : expired_no_email.php AUTHOR : Marin Nedea WEBSITE : http://urbanlinux.com BLOG : http://urbanlinux.com CREATED : 09-11-2016 COMMENT : This is a mail template used to notify admins via e-mail/ticket when someone's AD account password is already expired, but there's no e-mail address set for that account. LICENSE : Copyright (C) 2016 - Marin Nedea @ http://urbanlinux.com 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 the Free Software Foundation, either version 3 of the License, or at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ $subject = 'The password for the Domain Account ' .$username. ' expired'; // Prepare the e-mail to be sent $headers = 'MIME-Version: 1.0' . "\r\n"; $headers .= 'Content-type: text/html; charset=utf-8' . "\r\n"; $headers .= 'To:<tickets@example.com>'."\r\n"; $headers .= 'From: Support Team <support@example.com>' . "\r\n"; $headers .= 'Subject:'.$subject.''."\r\n"; $message = '<html> <body> <p>Hello ' .$user_display_name.', <br /> <br /> The password for the Domain account ' .$username. ' expired ' . $remaining_days .' days ago.<br /> Also, please note there is no e-mail address set for this account. <br /><br /> <p> Please verify if the account owner still needs this account.<br /> <br /> <strong>Please note this is an automated e-mail and <i>shall</i> not be replied!</strong><br /><br /> <br /> Best Regards,<br /> The Support Team </p> </body> </html>'; ?>
Now, once you have the whole script, upload it to your web server to the directory you usually keep your custom apps/scrips ( e.g /usr/local ).
Now, to have your script run every day at a specific time, make a new entry in crontab. To do that, open a shell to your server with:
$ crontab -e
and add the following line at the end of the crontab file
10 1 * * * /usr/bin/php5 /usr/local/ldap_notify/ldap_notify_expire_pass.php
The above line will have the script “/usr/local/ldap_notify/ldap_notify_expire_pass.php” run every day, at 01:10 AM .
[media-downloader media_id=”25″ texts=”Download Files”]
One response to “PHP LDAP notify on expiring passwords”
Hi, I use a company called m247. The link to the plan I use is: https://www.m247.ro/en/personal-ssd-hosting.php (the 11 Euro/year one). For a starting blog I think is more than enough. BTW.. sorry for the late reply.