[[linux_wiki:freeipa_report_password_expiry]]

FreeIPA Report Password Expiry

General Information

Intended to be run daily via cron, this script will:

  • Check all user accounts for an upcoming password expiration
  • Auto disable accounts that have been expired for a certain amount of time
  • Notify users about auto disabled account or upcoming password expiration
  • Create a summary report and e-mail to the admins

Checklist


The Script

Run this script daily via cron on your FreeIPA server.

cron_report-password-expiry.sh
#!/bin/bash
# Name: cron_report-password-expiry.sh
# Description: Meant to be executed via cron:
#              -Check all user accounts for an upcoming password expiration
#              -Auto disable accounts that have been expired for a certain amount of time
#              -Notify users about auto disabled account or upcoming password expiration
#              -Create a summary report and e-mail to the admins
# Last Updated: 2018-05-31
# Recent Changes:-Initial release
###############################################################################################
 
#====================================
##### Customize These Variables #####
#====================================
 
# Admin credentials: For ipa commands
admin_user="admin"
admin_pass='adminpwhere'
 
# Email password expiry summary report to
email_to="systemadmins@yourdomain.org"
 
# FreeIPA self service portal URL (included in user reminder email)
self_service_portal="https://ldapserver.yourdomain.org/ipa/ui/"
 
# Auto disable user account when password expired for many days?(negative number expected)
auto_disable_days=-4
 
# Warn about passwords expiring in how many days or less?
password_expiry_warn_days=14
 
# Users are sent password expiration reminder emails on these days left until expiry
remind_on_days=(14 7 3 1 0)
 
# Temp files for building e-mail messages
password_report_email="/root/ldap-scripts/tmp/cron_report-password-expiry-to-admins_report"
password_report_disabled_users="/root/ldap-scripts/tmp/cron_report-password-expiry-to-admins_disabled-users"
password_expiry_email="/root/ldap-scripts/tmp/cron_email-users-password-expiry_email"
 
#=====================================
##### End of Customize Variables #####
#=====================================
 
#==========================================
#### Functions Here: Main Starts After ####
#==========================================
 
# Create the initial summary report layout/header
function create_report_header() {
 
# Clear out email temp file contents
cat /dev/null > ${password_report_email}
cat /dev/null > ${password_report_disabled_users}
 
# Overwrite temp file contents
echo -e "---- FreeIPA User Expiration Report ----" > ${password_report_email}
echo -e "\nAccounts that will expire in ${password_expiry_warn_days} days or less." >> ${password_report_email}
echo -e "Accounts will be automatically disabled and users emailed notification when expired for: ${auto_disable_days} days." >> ${password_report_email}
echo -e "Users are sent password expiration warning emails on days: ${remind_on_days[@]}" >> ${password_report_email}
 
# Setup report header
echo -e "\n----------------------------------------------------------------" >> ${password_report_email}
echo -e "User\t\tDays Left Until Expiration" >> ${password_report_email}
echo -e "----------------------------------------------------------------" >> ${password_report_email}
 
}
 
# Add usernames and days left until expiration to the report
function add_to_report() {
 
# Set variables passed to the function
username=${1}
expires_in_days=${2}
expires_in_secs=${3}
expires_on_epoch=${4}
 
# Determine the friendly looking expiration date
userpw_expiry_date_long=$(date --date="@${expires_on_epoch}")
 
# Determine day_format (Day vs Days)
if [[ ${expires_in_days} -eq 1 || ${expires_in_days} -eq -1 ]]; then
  day_format="day"
else
  day_format="days"
fi
 
# Determine if expiring in the future or if already expired
if [[ ${expires_in_days} -le 0 ]]; then
  if [[ ${expires_in_secs} -le 0 ]]; then
    # expired now
    dialog_expires="${expires_in_days} ${day_format} (Expired Since: ${userpw_expiry_date_long}) ----> Auto Disable Warning!"
  else
    # expiring less than a day
    dialog_expires="${expires_in_days} ${day_format} (Expires On: ${userpw_expiry_date_long})"
  fi
else
  # expiring on a future day
  dialog_expires="${expires_in_days} ${day_format} (Expires On: ${userpw_expiry_date_long})"
fi
 
# Status message
echo "--Adding ${username} to password report."
 
## Add user account and expiration line to report file
if [[ $(echo ${username} | wc --max-line-length) -lt 8 ]]; then
  # If less than 8 character username, use two tabs
  echo -e "${username}\t\t${dialog_expires}" >> ${password_report_email}
else
  # If 8 or more characters, use one tab
  echo -e "${username}\t${dialog_expires}" >> ${password_report_email}
fi
 
}
 
# Add usernames that have been disabled to a disabled list
function add_to_disabled_list() {
 
# Set variables passed to the function
username=${1}
 
# Status message
echo "--Adding ${username} to disabled report."
 
## Add user account and expiration line to report file
echo -e "${username}" >> ${password_report_disabled_users}
 
}
 
# Add usernames that have been disabled to the end of the email report
function add_disabled_list_to_report() {
 
# Setup disabled users header
echo -e "\n\n----------------------------------------------------------------" >> ${password_report_email}
echo -e "Users that have been automatically disabled" >> ${password_report_email}
echo -e "----------------------------------------------------------------" >> ${password_report_email}
 
# Add Disabled Users to end of report
if [[ -s ${password_report_disabled_users} ]]; then
  # If file size is greater than 0, add content to report
  cat ${password_report_disabled_users} >> ${password_report_email}
else
  # If file size is 0, give a status message
  echo "No users auto disabled during this script run." >> ${password_report_email}
fi
 
}
 
# Email user to notify them that their account was auto disabled
function notify_disabled_user(){
 
# Set username from passed variable
username=${1}
 
# Status message
echo "--Notify ${username} that their account was disabled."
 
# Gather email address, first name for the email
name_email="$(/usr/bin/ipa user-show ${username} | grep -E "(First name|Email address)" | awk '{print $3}')"
first_name="$(echo $name_email | awk '{print $1}')"
user_email_address="$(echo $name_email | awk '{print $2}')"
 
# Email user notification that their account has been disabled
echo -e "${first_name},\n\nYour Linux account (${username}), has been automatically disabled due to having an expired password for ${auto_disable_days} days.\nPlease contact your System Administrators if you wish to enable the account.\n\n----\nSystem Administrators\n${email_to}" | /usr/bin/mail -s "Linux Account Auto-Disabled" -r ${email_to} -b ${email_to} ${user_email_address}
 
}
 
# Email user a reminder of their upcoming password expiration
function email_user_reminder() {
 
# Set variables passed to the function
username=${1}
expires_in_days=${2}
expires_in_secs=${3}
expires_on_epoch=${4}
 
# Determine day_format (Day vs Days)
if [[ ${expires_in_days} -eq 1 ]]; then
  day_format="Day"
else
  day_format="Days"
fi
 
# Determine if expiring in the future or if already expired
if [[ ${expires_in_days} -le 0 ]]; then
  if [[ ${expires_in_secs} -le 0 ]]; then
    # expired now
    dialog_expires_subject="Has Expired!"
    dialog_expires_body="expired on"
  else
    # expiring in less than a day
    dialog_expires_subject="Expires in < 24 Hours!"
    dialog_expires_body="will expire on"
  fi
else
  # expiring on a future day
  dialog_expires_subject="Expires in: ${expires_in_days} ${day_format}"
  dialog_expires_body="will expire on"
fi
 
# Gather email address, first name, and friendly date for the email
name_email="$(/usr/bin/ipa user-show ${username} | grep -E "(First name|Email address)" | awk '{print $3}')"
first_name="$(echo $name_email | awk '{print $1}')"
user_email_address="$(echo $name_email | awk '{print $2}')"
userpw_expiry_date_long=$(date --date="@${expires_on_epoch}")
 
## Create email message file to send user
echo "${first_name}," > ${password_expiry_email}
 
echo -e "\nYour Linux password for (${username}) ${dialog_expires_body}: ${userpw_expiry_date_long}" >> ${password_expiry_email}
 
echo -e "\nWarning: After a password has been expired for ${auto_disable_days} days, the account is automatically disabled." >> ${password_expiry_email}
 
echo -e "\n==== Action Required ====" >> ${password_expiry_email}
 
echo -e "\nChange your password using either the CLI or Web Portal method below." >> ${password_expiry_email}
 
echo -e "\n== Change Password: CLI Method ==" >> ${password_expiry_email}
 
echo -e "\n->Login to one of the systems that you have access to and change it by executing the 'passwd' command." >> ${password_expiry_email}
echo "--You will be prompted for your current password and then new password twice." >> ${password_expiry_email}
echo "--Login with your new password going forward." >> ${password_expiry_email}
 
echo -e "\n== Change Password: Web Portal Method ==" >> ${password_expiry_email}
 
echo -e "\nAlternatively, login to the self-service portal to change it (Cancel on any browser login pop-ups, use the actual web page form): ${self_service_portal}" >> ${password_expiry_email}
 
echo -e "\n-After logging in, in the upper right corner:" >> ${password_expiry_email}
echo "--Click your name for a drop down box, then 'Change password'." >> ${password_expiry_email}
echo "----Enter in your 'Current Password'." >> ${password_expiry_email}
echo "----Leave the 'OTP' field blank." >> ${password_expiry_email}
echo "----Enter in your 'New Password' and again in 'Verify Password'." >> ${password_expiry_email}
echo "--Click the 'Reset Password' button when complete." >> ${password_expiry_email}
 
echo -e "\n==== New Password Requirements ====" >> ${password_expiry_email}
 
echo -e "\nYour new password requirements are:" >> ${password_expiry_email}
echo "->At least 12 characters in length" >> ${password_expiry_email}
echo "->At least 3 types of characters from the following categories:" >> ${password_expiry_email}
echo "--Upper case letters" >> ${password_expiry_email}
echo "--Lower case letters" >> ${password_expiry_email}
echo "--Numbers" >> ${password_expiry_email}
echo "--Special Characters" >> ${password_expiry_email}
 
echo -e "\nIf you have any questions, please contact your System Administrators." >> ${password_expiry_email}
 
echo -e "\n----\nSystem Administrators" >> ${password_expiry_email}
echo "${email_to}" >> ${password_expiry_email}
 
# Status message
echo "--Emailing upcoming password expiry reminder to: ${username} (${user_email_address})..."
 
## E-mail the password expiry warning to the user
/usr/bin/mail -s "Linux Password ${dialog_expires_subject}" -r ${email_to} ${user_email_address} < ${password_expiry_email}
 
# Allow some time for the message to exit the queue
sleep 5
 
# Clear out email contents
cat /dev/null > ${password_expiry_email}
 
}
 
#=========================
#### End of Functions ####
#=========================
 
#=========================
#### Main Starts Here ####
#=========================
 
# Initialize a kerberos ticket as admin and wait a short time
echo ${admin_pass} | /usr/bin/kinit ${admin_user}
sleep 3
 
# Build a list of enabled accounts
#- Find all users | grep logins and disabled status lines |
#- If the current line matches "False" (/False/), print the stored username (print username),
#- next, store the current line's field 3 in the variable username (username=$3)
user_list=$(/usr/bin/ipa user-find --sizelimit=0 --all | grep -E "(User login|Account disabled)" | awk '/False/ { print username }; { username=$3 }')
 
# Get today's epoch time (seconds since Jan 1st, 1970, midnight UTC)
todays_epoch=$(date +%s)
 
# Create the system admin report header
create_report_header
 
#### Main Loop ####
for user in ${user_list}; do
 
  echo "Checking expiry for ${user}..."
 
  # Get user's password expiration and cut off the zulu time designator trailing at the end('Z')
  userpw_expiry_datetime=$(/usr/bin/ipa user-show ${user} --all | grep krbpasswordexpiration | awk '{print $2}' | cut -c 1-14)
 
  # If the user account does not have a password expiration value, skip the user
  if [[ -z ${userpw_expiry_datetime} ]]; then
    continue
  fi
 
  # Split up the year,month,day,hour,min, and sec from the datetime string
  userpw_expiry_date_year="$(echo ${userpw_expiry_datetime} | cut -c 1-4)"
  userpw_expiry_date_month="$(echo ${userpw_expiry_datetime} | cut -c 5-6)"
  userpw_expiry_date_day="$(echo ${userpw_expiry_datetime} | cut -c 7-8)"
  userpw_expiry_time_hour="$(echo ${userpw_expiry_datetime} | cut -c 9-10)"
  userpw_expiry_time_min="$(echo ${userpw_expiry_datetime} | cut -c 11-12)"
  userpw_expiry_time_sec="$(echo ${userpw_expiry_datetime} | cut -c 13-14)"
 
  # Caculate the user's expiry date in epoch time
  userpw_expiry_epoch=$(date --utc --date="${userpw_expiry_date_year}-${userpw_expiry_date_month}-${userpw_expiry_date_day} ${userpw_expiry_time_hour}:${userpw_expiry_time_min}:${userpw_expiry_time_sec}" +%s)
 
  # Calculate how many seconds and days until password expiration
  password_expires_seconds=$(expr ${userpw_expiry_epoch} - ${todays_epoch})
  password_expires_days=$(expr ${password_expires_seconds} / 86400)
 
  # If the password expires in 'password_expiry_warn_days' days or less, determine if we should:
  # -Disable user if the password has been expired <= to the auto_disable_days
  # -Check to see if we should email the user on the remind_on_days
  # -Add user to the system admin report
  if [[ ${password_expires_days} -le ${password_expiry_warn_days} ]]; then
 
    # if password has been expired for 'auto_disable_days' or more days, disable the account/notify user
    if [[ ${password_expires_days} -le ${auto_disable_days} ]]; then
      echo "--Disabling the user account: ${user}"
      /usr/bin/ipa user-disable ${user}
 
      # Add disabled account to a list for inclusion at the footer of the system admin report
      add_to_disabled_list ${user}
 
      # Email the user and notify them that their account was auto disabled
      notify_disabled_user ${user}
    else
      # Not auto disabling user, add the user to the system admin report
      add_to_report ${user} ${password_expires_days} ${password_expires_seconds} ${userpw_expiry_epoch}
 
      # Check to see if the user should be reminded of their upcoming passowrd expiry
      # Loop through array of days to send the email reminder on
      for reminder_day in "${remind_on_days[@]}"; do
 
        # If days left before user's password expires matches a reminder day, send an email to the user
        if [[ ${password_expires_days} -eq ${reminder_day} ]]; then
          email_user_reminder ${user} ${password_expires_days} ${password_expires_seconds} ${userpw_expiry_epoch}
          break
        fi
      done
    fi
 
  fi
done
#### End Main Loop ####
 
# Add disabled users list to the end of email report
add_disabled_list_to_report
 
# Status message
echo ">>Emailing summary report to ${email_to}..."
 
# Use the date-time from the beginning of the script
todays_date_long=$(date --date="@${todays_epoch}")
 
# Email Report
/usr/bin/mail -s "FreeIPA User Expiration Report - ${todays_date_long}" ${email_to} < ${password_report_email}
 
# Wait a bit for the message queue to get sent
sleep 5
 
# Clear out email temp file contents
cat /dev/null > ${password_report_email}
cat /dev/null > ${password_report_disabled_users}

  • linux_wiki/freeipa_report_password_expiry.txt
  • Last modified: 2019/05/26 03:50
  • (external edit)