Password Reset in Self-Service

roethelbc
New Contributor III

Hello,

We use AD to manage all user accounts in our University. As many of you know, the Keychain can be a bit problematic when syncing with a Password Reset. Many of our Mac users will reset there AD password trough our Password reset site, which causes there Keychain password not to be synced with there AD credentials. Does anyone have (or know of) methods to have a password reset option that will reset the password on the computer and sync it with the keychain?

11 REPLIES 11

bentoms
Release Candidate Programs Tester

Hi @roethelbc,

Have a look @ ADPassMon, my fork of it is detailed here: http://macmule.com/2014/04/01/announcing-adpassmon-v2-fork/

Not applicable

@andrinak gave a talk at the last JNUC (I think) and touched on keychain resets..

The video: http://www.jamfsoftware.com/news/video-getting-users-to-do-your-job-without-them-knowing-it/

And her script:

#!/bin/bash ######################################################################## # Created By: Andrina Kelly, andrina.kelly@bellmedia.ca, Ext 4995 # Creation Date: July 2013 # Last modified: July 25th, 2013 # Brief Description: Deletes the users login.keychain, and creates a new keychain ######################################################################## # Set CocoaDialog Location CD="/Path/to/CocoaDialog.app/Contents/MacOS/CocoaDialog" #Find out who's logged in USER=who | grep console | awk '{print $1}' #Get the name of the users keychain - some messy sed and awk to set up the correct name for security to like KEYCHAIN=su $USER -c "security list-keychains" | grep login | sed -e 's/"//g' | sed -e 's/// /g' | awk '{print $NF}' #Go delete the keychain in question... su $USER -c "security delete-keychain $KEYCHAIN" #Ask the user for their login password to create a new keychain rv=($($CD secure-standard-inputbox --title "Set New Keychain Password" --no-newline --informative-text "Enter your current login password")) PASSWORD=${rv[1]} #Create the new login keychain expect <<- DONE set timeout -1 spawn su $USER -c "security create-keychain login.keychain" # Look for prompt expect "?chain:" # send user entered password from CocoaDialog send "$PASSWORD " expect "?chain:" send "$PASSWORD " expect EOF DONE #Set the newly created login.keychain as the users default keychain su $USER -c "security default-keychain -s login.keychain"

Definitely something I need to tighten up in my environments as well.

bentoms
Release Candidate Programs Tester

Look out for the local items keychain in 10.9 too: http://macmule.com/2014/03/30/the-local-items-keychain-in-mavericks/

clifhirtle
Contributor II

@pete_c nuking the user's login keychain is one approach. I tend to try and avoid that if at all possible. Currently using an AppleScript that can be run to search for, remove, then update known organization servers with new passwords, when needed. Not perfect, but a good solution in a bind (http://github.com/clifhirtle/keychain).

@bentoms got your forked ADPassMon working now and looking like a great bridge between external directory changes and local keychain passwords!

Related: any one tried leveraging a Self Service policy for self-service password resets: prompt for password, go through various steps of updating, check/resolve any keychain issues, then logout/reboot user as needed? This may be redundant given Ben's forked ADPassMon, but it would be nice to have something that tries to take care of all those changes in one sweep as well. I have a Self Service MS Outlook setup script I was testing that could probably be adapted, but always good to leverage existing efforts, if out there.

roethelbc
New Contributor III

@bentoms I like your forked ADPassMon and I use it personally to monitor and reset my passwords. However, our users sometimes are not (to put it nicely) patient enough to go and click the password reset button. Have you or anyone you know integrated ADPassMon to go straight to the password reset option in the App from the Self Service? A script that just points to "Change Password..." . That would be great!

Matt
Valued Contributor

Keychain minder?

roethelbc
New Contributor III

Well what I am using ADPassMon for now is just general password reset. I have a script solution if the keychain becomes out of sync. What I would like is for the user to click a option in Self Service and it auto launches the dialog box in ADPassMon.

EliasG
Contributor

I tried this script from @andrinak and I am having some bad luck with it to make it work...any help would be great with this keychain errors that i am getting from users.

bentoms
Release Candidate Programs Tester

@roethelbc I'm not sure how to do that tbh, or if it's even possible using the app.

But you could prompt them via applescript dialogs from AppleScript via Self Service, along the lines of: http://macmule.com/2013/07/13/change-screenshot-location-from-self-service-with-gui-prompt/

Aaron
Contributor II

I hand rolled a password change script a little while ago, because I needed some very particular keychain loving, in particular with our proxy (causing account lockouts very rapidly).

I chip away at it from time to time, adding little bits and pieces, but it's been an invaluable tool in my environment and my users are much happier.

It's a bash script, but I use AppleScript for my prompts. I find it to be much more reliable than a pure AppleScript. This was before I got cocoaDialog working in my environment.

The main part is the single line:

result=$(dscl "$SEARCHPATH" passwd "/Users/$USER" "$CURPASSWORD" "$NEWPASSWORD")

As that will change the password on AD as well as update the login keychain password at the same time. Everything else is basically just local-side checks. I've left comments and commented lines in, so you can see where I was getting at.

Feel free to tweak to your needs:

#!/bin/bash

# Written by Aaron Redzik (aaron.redzik@petermac.org), 28/11/2013
# Last updated 25/07/2014
#
# Script should hopefully be scoped through Self Service to only
# be availble to Macs bound to domain. Includes some checks to
# make sure anyway. 

MINPASSWORDAGE=5
MAXPASSWORDAGE=90
# Making DAYSWARNING the same as MAXPASSWORDAGE will make it so it will prompt the user regardless of age
# This is specifically for running through Self Service
# Non-interactive/background process should be set to 10 or something
DAYSWARNING=$MAXPASSWORDAGE
USER=`stat -f%Su /dev/console`
PROXYADDRLONG="..."
PROXYADDRSHORT="..."
PROXYPORT=8080
#DOMAIN=`dsconfigad -show | grep -m 1 Domain | awk '{ print $5 }'`
MAILSERVER="..."

################################################################################

if [ "$USER" == "admin" ] || [ "$USER" == "administrator" ] || [ "$USER" == "root" ]; then
    # local admin users, don't go any further
    echo "Local admin account, exiting..." >&2
    exit 0
fi

if [ `dsconfigad -show | grep Namespace | awk '{ print $4 }'` != "domain" ]; then
    # Mac is not bound to the domain, so accounts will only be local. Don't go any further
    # Technically, this condition should never be met
    echo "Not bound to domain, exiting..." >&2
    exit 0
fi

if [ ! -d "/Users/$USER" ]; then
    # Home path does not exist. Not a mobile account? Don't go any further
    echo "No home directory exists, exiting..." >&2
    exit 0
fi

if [[ -z `id "$USER" | grep Domain` ]]; then
    echo "Local user account, exiting..." >&2
    exit 0
fi

# Retrieves SMBPasswordLastSet from AD
#SMBDATE=`dscl localhost read "/Search/Users/$USER" SMBPasswordLastSet | grep -m 1 SMBPasswordLastSet | awk '{ print $2 }'`

# TODO: Add some logic here for userAccountControl to determine if password can be changed, doesn't expire, etc

SEARCHPATH=`dscl localhost -read /Search CSPSearchPath | grep -m 1 "Active" | sed 's/^ *//'`

SMBDATE=`dscl "$SEARCHPATH" -read "/Users/$USER" SMBPasswordLastSet 2>&1`
if [[ $SMBDATE == *rror* ]]; then
    # Error of some sort. Spit it out to stderr and exit
    # ie: user not found, could not connect, etc
    echo "User: $USER
SMBPasswordLastSet: $SMBDATE" >&2
    exit 1
elif [[ $SMBDATE == *such* ]]; then
    # "No such key: SMBPasswordLastSet"
    # Something funky
    echo "Error: $SMBDATE" >&2
    exit 1 
fi

SMBDATE=`echo $SMBDATE | grep -m 1 SMBPasswordLastSet | awk '{ print $2 }'`
SMBDATE=`echo $SMBDATE / 10000000 - 11644473600 | bc`

DATENOW=`date +%s`

DAYSPASSED=`echo "($DATENOW - $SMBDATE) / 86400" | bc`
DAYSREMAIN=`echo $MAXPASSWORDAGE - $DAYSPASSED | bc`

##if [ $DAYSREMAIN -gt $DAYSWARNING ]; then
##    # Password expiry hasn't triggered a warning - do nothing
##    exit 0
if [ $DAYSPASSED -le $MINPASSWORDAGE ]; then
    # Password has already been changed recently, can't change again yet
    osascript -e 'tell application "System Events" to display alert "You have already changed your password '$DAYSPASSED' days ago, you cannot change it again so soon." as warning'
    echo "User: $USER
SMBPasswordLastSet: $SMBDATE (DAYSREMAIN: $DAYSREMAIN)" >&2
    exit 1
elif [ $DAYSREMAIN -lt -1 ]; then
    # Something weird happened, probably returned a value like -15427
    osascript -e 'tell application "System Events" to display alert "Something weird happened. Please try again, and if the issue persists, contact IT Helpdesk" as warning'
    echo "Error
User: $USER
SMBPasswordLastSet: $SMBDATE (DAYSREMAIN: $DAYSREMAIN)" >&2
    exit 1
fi

# Prompt user if they want to change their password
a=$(osascript -e 'tell application "System Events" to activate' -e 'tell application "System Events" to set question to display dialog "Your Petermac password is due to expire in '$DAYSREMAIN' days. Do you want to change it now?" buttons {"Yes", "No"} default button 2 with icon caution' -e 'button returned of question')
if [ "$a" == "No" ]; then
    # User doesn't want to change password yet
    exit 0
fi

# Get current password from user, for authentication purposes
while true; do
    CURPASSWORD="$(osascript -e 'tell application "System Events" to display dialog "Please enter your CURRENT Petermac password:" with hidden answer default answer ""' -e 'text returned of result' 2>/dev/null)"
    if [ $? -ne 0 ]; then
        # Pressed cancel
        exit 0
    elif [ -z "$CURPASSWORD" ]; then
        # Left blank
        osascript -e 'tell application "System Events" to display alert "Password can not be left blank." as warning'
    else break
    fi
done

# Prompt for new password, including some validation checks to reduce server errors
while true; do
    NEWPASSWORD="$(osascript -e 'Tell application "System Events" to display dialog "Please enter your NEW Petermac password.

Remember that your password must:
	• be at least 8 characters long
	• contain at least one capital letter
	• contain at least one digit or symbol
	• not contain your name
	• be different from your previous 24 passwords
	• not be within 5 days of the last password change" with hidden answer default answer ""' -e 'text returned of result' 2>/dev/null)"
    if [ $? -ne 0 ]; then
        # Pressed cancel
        exit 0
    elif [ -z "$NEWPASSWORD" ]; then
        # Left blank
        osascript -e 'Tell application "System Events" to display alert "Password can not be left blank." as warning'
    elif [ ${#NEWPASSWORD} -lt 8 ]; then
        osascript -e 'Tell application "System Events" to display alert "New password is not long enough." as warning'
    elif [[ ! "$NEWPASSWORD" =~ [A-Z] ]]; then
        osascript -e 'Tell application "System Events" to display alert "New password does not contain any capital letters." as warning'
    elif [[ ! "$NEWPASSWORD" =~ [!-@] ]]; then
        osascript -e 'Tell application "System Events" to display alert "New password does not contain any numbers or symbols." as warning'
    else break
    fi
done

# Get the user to type the password again to confirm
while true; do
    CONFIRMPASSWORD="$(osascript -e 'tell application "System Events" to display dialog "Please CONFIRM your new Petermac password." with hidden answer default answer ""' -e 'text returned of result' 2>/dev/null)"
    if [ $? -ne 0 ]; then
        # Pressed cancel
        exit 0
    elif [ -z "$CONFIRMPASSWORD" ]; then
        # Left blank
        osascript -e 'tell application "System Events" to display alert "Password can not be left blank." as warning'
    elif [ "$CONFIRMPASSWORD" != "$NEWPASSWORD" ]; then
        osascript -e 'tell application "System Events" to display alert "Passwords do not match." as warning'
    else break
    fi
done

result=$(dscl "$SEARCHPATH" passwd "/Users/$USER" "$CURPASSWORD" "$NEWPASSWORD")
result=`echo $result | awk '{ print $4 }'`
#result=""
#eDSAuthFailed
#eDSAuthMethodNotSupported
#eDSAuthPasswordQualityCheckFailed
if [ "$result" == "eDSAuthPasswordQualityCheckFailed" ]; then
    osascript -e 'Tell application "System Events" to display alert "(eDSAuthPasswordQualityCheckFailed):
New password has failed complexity requirements. It is most likely that your password had already been changed in the past 5 days, or is the same as one of your previous 24 passwords." as warning'
    exit 1
elif [ "$result" == "eDSAuthMethodNotSupported" ] || [ "$result" == "eDSAuthFailed" ]; then
    osascript -e 'Tell application "System Events" to display alert "('$result'):
Failed validation. It is most likely that you entered your current password incorrectly, or you are not logged in with your Petermac account." as warning'
    exit 1
elif [ "$result" != "" ]; then
    osascript -e 'Tell application "System Events" to display alert "('$result'):
Unhandled error. Please contact IT Helpdesk." as warning'
    exit 1
fi

# System keychain should almost always default to "/Library/Keychains/System.keychain"
# but you never know...
USERKEYCHAIN=`security default-keychain | xargs`
SYSKEYCHAIN=`security default-keychain -d system | xargs`

# Removes proxy entries from keychain
# No API to iterate over the keychain! Ugly hack coming up...
while true
do
    k=`strings "$USERKEYCHAIN" | grep -m 1 www-proxy | awk '{print $1}'`
    if [[ $k ]]; then
        security delete-internet-password -s "$k"
    else
        break
    fi
done

while true
do
    k=`strings "$SYSKEYCHAIN" | grep -m 1 www-proxy | awk '{print $1}'`
    if [[ $k ]]; then
        security delete-internet-password -s "$k" "$SYSKEYCHAIN"
    else
        break
    fi
done

## -----------------------------------------------------------------------
## # Do it a couple of times because there's no wildcard option to get rid
## # of "www-proxy" and "www-proxy.petermac.org.au" entries in one hit
## security delete-internet-password -s "$PROXYADDRLONG"
## security delete-internet-password -s "$PROXYADDRLONG"
## security delete-internet-password -s "$PROXYADDRSHORT"
## security delete-internet-password -s "$PROXYADDRSHORT"
## # The following typicaly requires sudo
## security delete-internet-password -s "$PROXYADDRLONG" "$SYSKEYCHAIN"
## security delete-internet-password -s "$PROXYADDRLONG" "$SYSKEYCHAIN"
## security delete-internet-password -s "$PROXYADDRSHORT" "$SYSKEYCHAIN"
## security delete-internet-password -s "$PROXYADDRSHORT" "$SYSKEYCHAIN"
## -----------------------------------------------------------------------

# Adds passwords into keychain for proxy access
security add-internet-password -a "$USER" -w "$NEWPASSWORD" -r htpx -P $PROXYPORT -s "$PROXYADDRLONG" -A -l "$PROXYADDRLONG ($USER)" -j "default" -t "dflt"
security add-internet-password -a "$USER" -w "$NEWPASSWORD" -r htsx -P $PROXYPORT -s "$PROXYADDRLONG" -A -l "$PROXYADDRLONG ($USER)" -j "default" -t "dflt"
##----- DON'T USE THIS ANYMORE, this was a hack to work around a fucky issue with the first Mavericks release
## # The following typically requires sudo
## security add-internet-password -a "$USER" -w "$NEWPASSWORD" -r htpx -P $PROXYPORT -s "$PROXYADDRLONG" -A -l "$PROXYADDRLONG ($USER)" -j "default" -t "dflt" "$SYSKEYCHAIN" 
## security add-internet-password -a "$USER" -w "$NEWPASSWORD" -r htsx -P $PROXYPORT -s "$PROXYADDRLONG" -A -l "$PROXYADDRLONG ($USER)" -j "default" -t "dflt" "$SYSKEYCHAIN" 
##-----

# Removes SecureWireless1 entries in keychain. There's no way to update pre-existing entries
# so just delete it and get the user to update if required
if [[ -n $(strings "$USERKEYCHAIN" | grep -m 1 SecureWireless1) ]]; then
    security delete-generic-password -l "SecureWireless1"
fi

## security delete-generic-password -l "SecureWireless1"
## security delete-generic-password -l "SecureWireless1" "$SYSKEYCHAIN"

# Same again with Exchange/email entries
# Sometimes there is more than one, for some reason...
while true
do
    k=`strings "$USERKEYCHAIN" | grep -m 1 Exchange | awk '{print $1}'`
    if [[ $k ]]; then
        security delete-generic-password -l "Exchange" -a "$USER@$MAILSERVER"
    else
        break
    fi
done
# And then put it back in
security add-generic-password -a "$USER@$MAILSERVER" -w "$NEWPASSWORD" -A -l "Exchange" -s "Exchange"

osascript -e 'Tell application "System Events" to display alert "You have successfully changed your Petermac password.

If you have any mobile devices that you use to connect to the Petermac wireless or email, be sure to update your password on there as well, as soon as possible."'

# Detect if Dropbox is running - Dropbox does not allow for CLI manipulation, and the config is encrypted.
# Easier to just get the user to do it themselves.
drop=`ps aux | grep '[D]ropbox'`
if [ ! -z "$drop" ]; then
    osascript -e 'Tell application "System Events" to display alert "Dropbox has been detected.

You will need to manually change your proxy password in the Dropbox preferences (click the Dropbox icon, click the cog, Preferences -> Network -> Proxies: Change Settings) in order for it to work again. Do this as soon as possible, otherwise it will lock your account." as warning'
fi

sdunbar
Contributor

@Aaron
I had been using your script for a while now, as a nice tool for users in Self Service. It now will reset the AD password but not update the Keychain, so I guess something has changed in Catalina.

I appreciate this is an old thread, but if you had an updated version or could see why it is not updating the keychain that would be great.

Many thanks