Skip to main content
Question

Enterprise Connect Login Item

  • August 10, 2016
  • 35 replies
  • 50 views

Show first post

35 replies

Forum|alt.badge.img+12
  • Contributor
  • August 29, 2016

iJake / tanderson,

Thx again, just can not get LaunchAgents to work for whatever reason. I see Login Items mentioned above, and tried that. Using osascript to enter a Login Item for EC and then a simple open Enterprise Connect script, working great.

thx,

John


Forum|alt.badge.img+7
  • Valued Contributor
  • September 23, 2016

@iJake Hey Jake, would you mind sharing your scripts with me regarding the LA?

I've followed along with whats recommended here and it's working for the most part. Except if a user doesn't enter credentials upon first launch then it wont get added to the users startup items. I think ideally it would be best to have the LA check for process and run if it isn't running rather than add a startup item that the user can easily remove.


iJake
Forum|alt.badge.img+23
  • Contributor
  • September 28, 2016

@rickwhois Sorry for the delay, I was traveling. Below is the script our LaunchAgent calls. There is a lot in this that ties to a daemon we also use because we have wrapped EC in a whole password policy management solution we wrote but not the part that makes sure EC is running. That code is fairly simple and near the bottom of this script. As you can see we do a few checks to make sure EC is configured properly before we worry about making sure it is running. We do not rely on the Startup Item at all and only this LaunchAgent. The LaunchAgent running is enforced by checks from the Casper side to be sure its always loaded. Let me know if you have any questions.

#!/bin/bash

## HEADER
# Script Title: Enterprise Connect Launcher
# Author: Jacob Davidson <jadavids@cisco.com>


## Definitions
softwareTitle="enterpriseConnectLauncher"
logFolder="/PATH/TO/LOGS"
timeStamp=`date "+%Y %b %d %T"`
consoleUser=$(stat -f %Su "/dev/console")
logSize=$(stat -f%z $LogFile)
maxSize=1000000
compliancePlist="REDACTED"
enterpriseConnectApp="/Applications/Enterprise Connect.app"
enterpriseConnectPrefs="/Library/Preferences/com.apple.Enterprise-Connect.plist"
enterpriseConnectMainUser=$(defaults read "$compliancePlist" mainUser)
timeStamp14dBack=$(date -v-14d -u +"%s")
fiveDays=432000
twoDays=172800
ecKeychainUser=$(/usr/bin/security find-generic-password -l "Enterprise Connect" | grep "acct" | awk -F "=" '{print $2}' | tr -d """)
NCutil="/PATH/TO/NCutil.py"
yo="/PATH/TO/yo.app/Contents/MacOS/yo"
title="Enterprise Connect Alert"
icon="/Applications/Enterprise Connect.app/Contents/Resources/AppIcon.icns"
ecKiller="/PATH/TO/enterpriseConnectKiller.sh"

## Functions

grabConsoleUserAndHome()
{
currentUser=$(stat -f %Su "/dev/console")
homeFolder=$(dscl . read "/Users/$currentUser" NFSHomeDirectory | cut -d: -f 2 | sed 's/^ *//'| tr -d '
')
  case "$homeFolder" in  
     * * )
           homeFolder=$(printf %q "$homeFolder")
          ;;
       *)
           ;;
esac
}

grabConsoleUserAndHome

logFile="$homeFolder$logFolder"/"$softwareTitle.log"

writeLog(){ echo "[$(date "+%Y-%m-%d %H:%M:%S")] [$consoleUser] [$softwareTitle] $1" >> "$logFile"; }
[[ -e "$(dirname "$logFile")" ]] || mkdir -p -m 775 "$(dirname "$logFile")"
[[ "$(stat -f%z "$logFile")" -ge 1000000 ]] && rm -rf "$logFile"

killEnterpriseConnect()
{
killall "Enterprise Connect"
}

launchEnterpriseConnect()
{
if [[ $(curl -sL -w "%{http_code}" "INTERNAL URL" -o /dev/null) -eq 200 ]]
    then
        writeLog "CAPnet detected. Launching..."
        osascript <<EOF
set theDirectory to "$enterpriseConnectApp"
set macPath to POSIX file theDirectory as Unicode text
tell application "Finder" to open file macPath
EOF
    else
        writeLog "CAPnet NOT detected. NOT launching..."
fi
}

yoNotifSettings()
{
$NCutil -i com.github.sheagcraig.yo
$NCutil -a alerts com.github.sheagcraig.yo
$NCutil --show-on-lock-screen true com.github.sheagcraig.yo
sleep 2
}

yoFix() 
{
if [[ $(curl -sL -w "%{http_code}" "INTERNAL URL" -o /dev/null) -eq 200 ]]
    then
        writeLog "CAPnet detected. Prompting..."
        if [[ -e $yo ]]
            then
                yoNotifSettings
                $yo -d -t "$title" -b "Fix" -B "bash "$ecKiller"" -s "$1" -n "$2" -p -i "$icon"

            else
                $3
        fi
    else
        writeLog "CAPnet NOT detected. NOT prompting..."
fi
}

newInstallPrompt()
{
msg="Enterprise Connect has just been installed!

Enterprise Connect is the new Password Policy
enforcement tool for Macs at Cisco.

To learn more go to:
INFO URL

Enterprise Connect will prompt you to log in after you close this dialog."
/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType utility -title "$title" -description "$msg" -icon "$icon" -button1 "Continue" -defaultButton 1 -lockHUD -startlaunchd -windowPosition ur
killEnterpriseConnect
sleep 2
launchEnterpriseConnect
defaults write "$userCompliancePlist" newInstallAlertSeen -bool TRUE
exit
}


keychainMissingPrompt()
{
msg="Enterprise Connect has not been configured.

This is required per Cisco policy.

Enterprise Connect will prompt you to log in after you close this dialog."
/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType utility -title "$title" -description "$msg" -icon "$icon" -button1 "Continue" -defaultButton 1 -lockHUD -startlaunchd -windowPosition ur
killEnterpriseConnect
sleep 2
launchEnterpriseConnect
}

oldADSyncPrompt()
{
msg="Enterprise Connect has not connected in two weeks. This is required per Cisco policy. Enterprise Connect will prompt you to log in after you close this dialog."
/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType utility -title "$title" -description "$msg" -icon "$icon" -button1 "Continue" -defaultButton 1 -lockHUD -startlaunchd -windowPosition ur
killEnterpriseConnect
sleep 2
launchEnterpriseConnect
}

prefsMissingPrompt()
{
msg="Enterprise Connect has not been configured.

This is required per Cisco policy.

Enterprise Connect will prompt you to log in after you close this dialog."
/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType utility -title "$title" -description "$msg" -icon "$icon" -button1 "Continue" -defaultButton 1 -lockHUD -startlaunchd -windowPosition ur
killEnterpriseConnect
sleep 2
launchEnterpriseConnect
}

adNotSyncedPrompt()
{
msg="Your local password is not synced with your CEC password.

This is required per Cisco policy.

Enterprise Connect will prompt you to sync them after you close this dialog."
/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType utility -title "$title" -description "$msg" -icon "$icon" -button1 "Continue" -defaultButton 1 -lockHUD -startlaunchd -windowPosition ur
killEnterpriseConnect
sleep 2
launchEnterpriseConnect
}

expirationAlertPrompt()
{
msg="Your CEC password is expiring in less than two days!

Please change your password with Enterprise Connect from the Menubar."
/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType utility -title "$title" -description "$msg" -icon "$icon" -button1 "Continue" -defaultButton 1 -lockHUD -startlaunchd -windowPosition ur
launchEnterpriseConnect
}


userCompliancePlist="REDACTED"

if [[ "$currentUser" == "root" ]]
    then
        exit
fi

if [[ "$enterpriseConnectMainUser" != "$currentUser" ]]
    then
        writeLog "$currentUser is not the determined Main User. Exiting..."
        exit
    else
        writeLog "$currentUser IS determined Main User. Checking Enterprise Connect configuration..."
fi

#We can't be sure logged in user account matches AD username so this section has been removed
# if [[ "$ecKeychainUser" = "$enterpriseConnectMainUser" ]]
#   then
#       writeLog "Enterprise Connect keychain configured for correct user..."
#   elif [[ "$ecKeychainUser" = "security: SecKeychainSearchCopyNext: The specified item could not be found in the keychain." ]]
#       then
#           # writeLog "Enterprise Connect keychain item is missing. Prompting and relaunchig app to fix..."
#           writeLog "Enterprise Connect keychain item is missing."
#           # yoFix "Enterprise Connect not configured" "Click the fix button to configure" "keychainMissingPrompt"
#           exit
#   else
#           # writeLog "Enterprise Connect keychain not configured for current user. Prompting and relaunchig app to fix..."
#           writeLog "Enterprise Connect keychain not configured for current user."
#           # yoFix "Enterprise Connect not configured" "Click the fix button to configure" "keychainMissingPrompt"
#           exit    
# fi

enterpriseConnectPrefsCreateDate=$(date -j -f "%Y-%m-%d%T" "$(mdls -n kMDItemFSCreationDate "$homeFolder""$enterpriseConnectPrefs"  | awk '{print $3 $4}')" "+%s")
# dateExpirationChecked=$(defaults read "$homeFolder""$enterpriseConnectPrefs" dateExpirationChecked | awk '!($3="")' | sed 's/ *$//')
# dateExpirationCheckedEpoch=$(date -j -f "%Y-%m-%d %T" "$dateExpirationChecked" +%s)
mainUserLastConnectEpoch=$(defaults read "$userCompliancePlist" mainUserLastConnect)
newInstallAlertSeen=$(defaults read "$userCompliancePlist" newInstallAlertSeen)

if [[ $mainUserLastConnectEpoch =~ ^-?[0-9]+$ ]]
    then
        writeLog "Enterprise Connect HAS connected at least once. Continuning..."
    else
        if [[ $newInstallAlertSeen -eq 1 ]]
            then
                writeLog "New install prompt HAS been seen. Alerting to configure..."
                yoFix "Enterprise Connect not configured" "Click the fix button to configure" "prefsMissingPrompt"
                exit
            else
                writeLog "Enterprise Connect HAS NOT connected at least once. Prompting..."
            newInstallPrompt
        fi
fi

if [[ -e "$homeFolder""$enterpriseConnectPrefs" ]]
    then
        writeLog "Enterprise Connect prefs exist..."
        if [[ $mainUserLastConnectEpoch -lt $timeStamp14dBack ]]
            then
                writeLog "Enterprise Connect hasn't checked AD in 14 days. Prompting and relaunching app to fix..."
                yoFix "EC hasn't connected in 2 weeks" "Click the fix button to login" "oldADSyncPrompt"
                exit
            else
                writeLog "Enterprise Connect checked AD $(date -j -f "%s" "$mainUserLastConnectEpoch" "+%Y-%m-%d %T"). Continuing..."
                defaults read "$homeFolder""$enterpriseConnectPrefs" datePasswordExpires
                if [[ $? -eq 0 ]]
                    then
                        adExpirationDateEpoch=$(date -j -f "%Y-%m-%d %T" "$(defaults read "$homeFolder""$enterpriseConnectPrefs" datePasswordExpires | awk '{print $1,$2}')" "+%s")
                        twoDaysCheck=$[$adExpirationDateEpoch - $(date "+%s")]
                        if [[ $twoDaysCheck -lt $twoDays ]]
                            then
                                writeLog "AD password expires in less than two days. Prompting..."
                                expirationAlertPrompt
                        fi
                        adExpirationDatePlusFiveEpoch=$[$adExpirationDateEpoch + $fiveDays]
                        adExpirationDatePlusFive=$(date -j -f "%s" "$adExpirationDatePlusFiveEpoch" "+%m/%d/%Y")
                        writeLog "Updating $currentUser password expiration date key to AD+5, $adExpirationDatePlusFive"
                        defaults write "$userCompliancePlist" mainUserExpirEpoch "$adExpirationDatePlusFiveEpoch"
                        defaults write "$userCompliancePlist" mainUserExpir "$adExpirationDatePlusFive"
                        chmod 664 "$userCompliancePlist"
                    else
                        writeLog "adExpirationDate is missing. Not setting expiration date or alerting..."
                fi
        fi
        writeLog "Verifying password is synced with AD..."
        localADPasswordsInSync=$(defaults read "$homeFolder""$enterpriseConnectPrefs" localADPasswordsInSync)
        if [[ $localADPasswordsInSync -eq 0 ]]
            then
                writeLog "${currentUser}'s password is not synced with AD. Prompting and relaunchig app to fix..."
                defaults write "$userCompliancePlist" localADPasswordsInSync -bool FALSE
                chmod 664 "$userCompliancePlist"
                yoFix "Local password doesn't match CEC" "Click the fix button to sync" "adNotSyncedPrompt"
                exit    
            elif [[ $localADPasswordsInSynced -eq 1 ]]
                then
                    writeLog "${currentUser}'s password is synced with AD..."
                    defaults write "$userCompliancePlist" localADPasswordsInSync -bool TRUE
                    chmod 664 "$userCompliancePlist"
        fi
    else
        writeLog "Enterprise Connect prefs don't exist. Prompting and launching app to fix..."
        yoFix "Enterprise Connect not configured" "Click the fix button to configure" "prefsMissingPrompt"
        exit
fi


if [[ -e "$enterpriseConnectApp" ]]
    then
        counter=1
        while [[ $(ps aucxwwm | grep -v  grep | grep -Ec '(^|s)Enterprise Connect($|s)') -lt 1 ]]
        do
            if [ $counter -gt 9 ]
                then
                    if [[ $(ps aucxwwm | grep -v  grep | grep -Ec '(^|s)Enterprise Connect($|s)') -lt 1 ]]
                        then
                            writeLog "Error"
                            writeLog "Unable to get Enterprise Connect running. Exiting..."
                            exit 1
                        else
                            writeLog "Enterprise Connect launched on attempt $counter"
                            break
                    fi
                else
                    if [[ $(ps aucxwwm | grep -v  grep | grep -Ec '(^|s)Enterprise Connect($|s)') -lt 1 ]]
                        then
                            writeLog "Enterprise Connect not running. Launching..."
                            launchEnterpriseConnect
                        else
                            writeLog "Enterprise Connect launched on attempt $counter"
                            break
                        fi
            fi
            counter=$[$counter+1]
            sleep 10
        done
    else
        writeLog "Enterprise Connect missing. Exiting..."
fi

writeLog "Enterprise Connect running..."

exit

Forum|alt.badge.img+7
  • Valued Contributor
  • September 28, 2016

@iJake this is quite magical! It has got my gears turning for sure. Thanks very much for sharing this.


iJake
Forum|alt.badge.img+23
  • Contributor
  • September 28, 2016

@rickwhois Glad to help! If you or anyone has the same or similar case where you need to manage the password policy for non-bound accounts using pwpolicy I'd be more than happy to make a write up on our whole implementation we wrote around Enterprise Connect.


Forum|alt.badge.img+13
  • Valued Contributor
  • June 29, 2017

@iJake I'd love to see your implementation! Few months later, but I think more than a few people are getting away from bound devices.


iJake
Forum|alt.badge.img+23
  • Contributor
  • June 29, 2017

Below is an overview of the moving parts of Cisco's implementation including where they are located, what they do, and what invokes them. If you would like details on any individual part I can provide that.

Our implementation of Enterprise Connect at Cisco has a heavily customized workflow with daemon, agents, and both Casper-side and local scripts to leverage Enterprise Connect as the basis for our password policy and local account enforcement. As part of this, the daemon will attempt to determine the main user of the machine when there are multiple accounts in order to only present the alerts and Enterprise Connect GUI to one user.

For local accounts determined not to be the main user, password policy enforcement will work by comparing the date the password of the account was last set to the date the latest password policy was installed. If the password was set earlier than the policy install date then the account will have it’s password expired so that it can be updated to ensure it meets policy. Passwords for these secondary accounts are expired after 180 days of their last change should they reach that age.

Casper Side
1. Enforces (if user logged in) a. pwpolicy up to date (via hashing to ensure tamper-resistant) b. LaunchDaemon installed and running c. LaunchAgent installed and running d. MDM Configuration Profile installed e. Enterprise Connect installed, up to date, and running f. Yo.app installed g. Removes legacy ChangePW install

  1. Scripts a. enterpriseConnectEnforce_MONTH-DAY-YEAR.sh i. Casper-side enforcement script ii. Date is pwpolicy xml date b. enterpriseConnectPayload.sh i. Casper-side installation script called by enforce script ii. Installs Enterprise Connect.app, LaunchDaemon, LaunchAgent, and associated scripts c. enterpriseConnectPWpolicyInstaller.sh i. Clears current local and installs latest pwpolicy via XML embedded in script ii. Calculates hash of pwpolicy output after installing and stores it in plist for verification by local daemon
  2. Packages a. CiscoYo.pkg i. Installs Cisco-branded Yo.app ii. Used to alert users

Client Side
1. LaunchDaemon (Runs as root) a. Determines main user of machine (if multiple found) i. Removes password hint ii. Sets expiration of main user to AD +5 Days determined by LaunchAgent b. Enforces pwpolicy up to date (via hashing to ensure tamper-resistant) c. Manages password expiration of secondary accounts i. If password is older than pwpolicy install time password is expired ii. Unless password is already expired

  1. LaunchAgent (runs as user) a. Reads in main user which determines if EC needs to be running i. Ensures is running if main user logged in b. Ensures EC is configured for main user i. Alerts via Yo.app or jamfhelper if not c. Ensures EC has check AD in at least 14 days i. Alerts via Yo.app or jamfhelper if not d. Reads AD password expiration date. Calculates AD +5 days for LaunchDaemon e. If AD password expires in less than 2 days presents additional alerting i. Alerts via Yo.app or jamfhelper if not f. Ensures local password is synced with AD password i. Alerts via Yo.app or jamfhelper if not

  2. Enterprise Connect.app a. Preferences managed via MDM profile from Casper b. Asks for and stores, in Keychain, users CEC credentials c. Checks credentials and reads AD expiration date from AD on network state change d. Acquires Kerberos TGT e. Notifies user of impending AD account expiration f. Allows user to see AD account expiration in menu bar g. Allows user to set network shares to automatically mount on connection h. Asks user to sync local password with AD

  3. Scripts a. /Library/CiscoIT/Scripts/EnterpriseConnect/enterpriseConnectDaemon.sh i. Called by LaunchDaemon b. /Library/CiscoIT/Scripts/EnterpriseConnect/enterpriseConnectLauncher.sh i. Called by LaunchAgent c. /Library/CiscoIT/Scripts/EnterpriseConnect/enterpriseConnectSuccessConnect.sh i. Called by Enterprise Connect.app on successful auth to AD ii. Records timestamp of last time AD expiration was checked iii. Set by MDM Profile d. /Library/CiscoIT/Scripts/EnterpriseConnect/enterpriseConnectPassSync.sh i. Called by enterpriseConnectPassSyncLauncher.sh ii. Attempts to sync AD password at pwreset.cisco.com iii. Users can choose to manually sync instead iv. Updates blizzard and Outlook keychain entries with new password e. /Library/CiscoIT/Scripts/EnterpriseConnect/enterpriseConnectPassSyncLauncher.sh i. Called by Enterprise Connect.app on successful AD password change ii. Runs enterpriseConnectPassSync.sh in background iii. EC GUI would appear frozen if sync not tasked out f. /Library/CiscoIT/Scripts/EnterpriseConnect/enterpriseConnectKiller.sh i. Quits and reopens Enterprise Connect.app process for Launcher


Forum|alt.badge.img+4
  • New Contributor
  • March 9, 2019

I've given up on EC's ability to auto launch and wrote a launchD for it.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>EnvironmentVariables</key>
    <dict>
        <key>PATH</key>
        <string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/VMware Fusion.app/Contents/Public:/Library/Frameworks/Mono.framework/Versions/Current/Commands:/Applications/Wireshark.app/Contents/MacOS:/usr/local/sbin</string>
    </dict>
    <key>KeepAlive</key>
    <dict>
        <key>SuccessfulExit</key>
        <true/>
    </dict>
    <key>Label</key>
    <string>LnchEC</string>
    <key>ProgramArguments</key>
    <array>
        <string>/Applications/Enterprise Connect.app/Contents/MacOS/Enterprise Connect</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>StartCalendarInterval</key>
    <array>
        <dict>
            <key>Minute</key>
            <integer>60</integer>
        </dict>
    </array>
</dict>
</plist>

Forum|alt.badge.img+11

Here's what I cooked up. It ain't pretty, but it works.

#!/bin/bash

#app="${4}"
app="Enterprise Connect"
#appPath="${5}"
appPath="/Applications/Enterprise Connect.app"

IFS=","

# Identify the username of the logged-in user
currentUser=`python -c 'from SystemConfiguration import SCDynamicStoreCopyConsoleUser; import sys; username = (SCDynamicStoreCopyConsoleUser(None, None, None) or [None])[0]; username = [username,""][username in [u"loginwindow", None, u""]]; sys.stdout.write(username + "
");'`

if [[ $? != 0 ]]; then
    currentUser=$( /usr/bin/stat -f%Su /dev/console )
    /bin/echo "Python user check failed. Checking console."
    /bin/echo "Logged in username is $currentUser"
else
    /bin/echo "Python user check successful."
    /bin/echo "Logged in username is $currentUser"
fi

# Identify the UID of the logged-in user
currentUserUID=`id -u "$currentUser"`

listLoginItems=$(/bin/launchctl asuser "$currentUserUID" /usr/bin/osascript -e 'tell application "System Events" to get the name of every login item')

/bin/echo "Login Items: $listLoginItems"

for v in $listLoginItems; do
    noSpace="$(echo -e "${v}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
    if [[ "$noSpace" == "$app" ]]; then
        /bin/echo "$noSpace found in Login Items. Exiting..."
        exit 0
    fi
done

/bin/echo "$app was not found in Login Items. Adding login item $app..."
/bin/launchctl asuser "$currentUserUID" /usr/bin/osascript -e 'tell application "System Events" to make login item at end with properties {name: "'$app'",path:"'$appPath'", hidden:false}'

listLoginItems=$(/bin/launchctl asuser "$currentUserUID" /usr/bin/osascript -e 'tell application "System Events" to get the name of every login item')
for v in $listLoginItems; do
    noSpace="$(echo -e "${v}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
    if [[ "$noSpace" == "$app" ]]; then
        /bin/echo "$app found in Login Items. Exiting..."
        exit 0
    fi
done

/bin/echo "Something went wrong. $app was not found in Login Items. Exiting..."
/bin/echo "Login Items: $listLoginItems"
exit 1

Forum|alt.badge.img
  • New Contributor
  • September 26, 2019

Hello,
I hope this is the right discussion for this. If not, please help me finding an answer to my problem.
My organization uses Enterprise Connect. Problems come when a user is not connected to our domain network and his/her password has expired.
We've found a workaround for this but only works if the user is still able to login into his/her Mac but, many times, users are locked out from their Mac systems and the old password doesn't work (since it has expired) and a new temporary one is not accepted (it seems that Enterprise Connect is unable to work with AD temporary passwords).
Do you think that a new password set with an external tool could work?

Thanks for your time, guys.