An AppleScript that to automate RSA soft token generation and VPN logins on OS X 10.6, Snow Leopard. I've only tested this with version 4.1 (and 4.0.0) of the RSA SecurID application for Mac, with a Cisco IPSEC VPN, on a Mac running OS X 10.6.2. Feedback is welcomed, and I'll gladly take your money if you want to use the Donate button in the sidebar.
Initial announcement on my blog can be found here.
What it does
- Prompts for your SecurID PIN (you can save this in the script, I highly recommend you NOT do that)
- Launches the SecurID application (it if it's running it will quit it first), generates a token, stores the token in a variable, and then quits the SecurID application
- Kicks off the VPN connection process, types in the generated passcode when the window is available, and logs in.
If there's any type of a banner with terms to accept, it won't click OK there. It was written to log you in as quickly as possible, so it actively searches for the appropriate windows, rather than using an arbitrary delay. This should make it less error prone as well.
Disclaimer
This is not endorsed or recommended by Apple, Cisco or RSA, and is quite possibly in violation of your corporate policies, especially if you store your PIN in the file.
Requirements
- You must be using the RSA SecurID application. It's easy enough to remove this and just skip straight to the password prompt, but I wrote this for my own needs, not yours.
- In System Preferences > Universal Access you need to check the box "Enable access for assistive devices"

- You must be running Snow Leopard, OS X 10.6
Configuration
set theConnection to "My VPN" -- the name of your VPN connection set thePin to "" -- set to "" to prompt every time (recommended) set theApp to "UserNotificationCenter" -- shouldn't have to change this set theText to "VPN Connection" -- static text to search for in the VPN dialog, likely locale specific set tokenAppName to "SecurID" -- The name (sans .app) of the SecurID application, possibly locale specific
The only way I could find to accurately identify the VPN Connection window was to search for a window within the UserNotificationCenter process containing specific static text (theText). In English this is "VPN Connection", it will presumably be language specific.
theConnection should be set to the name of your VPN connection, as defined in System Preferences > Network.
Known Issues
Since the only way I could find to retrieve the generated passcode from the SecurID application was using the clipboard, the script saves and attempts to restore the clipboard after it retrieves the passcode. If you receive an error -25103 when running the script, it means your clipboard is too large or has some other issue that prevented it from restoring the clipboard.
Download
Download the script (last modified 2010-02-04) or view the source below.
------------------------------------------------ -- Automated token generation and VPN logins -- Copyright 2010, Corey Gilmore -- http://coreygilmore.com/ -- Last Modified: 2010-02-04 ------------------------------------------------ set theConnection to "My VPN" -- the name of your VPN connection set thePin to "" -- set to "" to prompt every time (recommended) set theApp to "UserNotificationCenter" -- shouldn't have to change this set theText to "VPN Connection" -- static text to search for in the VPN dialog, likely locale specific set tokenAppName to "SecurID" -- The name (sans .app) of the SecurID application, possibly locale specific -- Generate your passcode and open the VPN connection vpn_connect(thePin, theConnection, theApp, theText, tokenAppName) -------------------------------------- -- Helper functions below -------------------------------------- -- the actual connection - retrieve the token, initiate the connection and enter the password on vpn_connect(thePin, theConnection, theApp, theText, tokenAppName) set thePin to get_user_pin(thePin) if thePin is false then display alert "Invalid PIN." return end if --display alert "PIN: " & thePin --return set theToken to get_token(thePin, tokenAppName) log "gettoken returned: " & theToken if theToken is not null then open_vpn_connection(theConnection, theToken, theApp, theText) else display alert "Could not retrieve token, please try again." end if end vpn_connect -- helper method to retrieve the user's PIN if it's not stored on get_user_pin(thePin) if thePin is not null and thePin is not "" then return thePin set dialogResult to display dialog "Enter your PIN:" default answer "" with title "PIN" with hidden answer if button returned of dialogResult is "OK" then set thePin to text returned of dialogResult if thePin is null or thePin = "" then return false end if end if return thePin end get_user_pin -- launch the SecurID application and retrieve the current token on get_token(userPin, tokenAppName) set theToken to null -- quit the app if it's running tell application "System Events" to set allApps to (get name of every application process) if allApps contains tokenAppName then tell application tokenAppName to quit log "telling " & tokenAppName & " to quit" delay 0.5 -- arbitrary delay, give the app time to exit end if tell application tokenAppName activate copy (get the clipboard) to origClip tell application "System Events" delay 0.2 keystroke userPin key code 36 repeat with x from 1 to 20 delay 0.1 keystroke "c" using command down keystroke "c" using command down -- copy twice because it didn't always work the first time copy (get the clipboard as string) to theToken if theToken is origClip then -- if the clipboard hasn't changed, the token hasn't been generated (edge case: clipboard at launch matches the generated token) -- do nothing else log "Token is: " & theToken --keystroke "q" using command down set the clipboard to origClip -- reset the clipboard to what it was before --return (theToken as string) -- return the token we retrieved exit repeat end if end repeat end tell end tell log "tell quit" tell application tokenAppName to quit log "after quit" return (theToken as string) -- return the token we retrieved end get_token -- Find a window containing specific static text, in a given application on find_window_by_static_text(appname, staticText) log "Searching " & appname & " for " & staticText tell application "System Events" set allApps to (get name of every application process) -- get all apps if allApps contains appname then -- find the app if it's running set allWin to (get every window of application process appname) -- get all the windows for our app set numWin to count allWin -- count the number of windows repeat with winNum from 1 to numWin set aWin to window winNum of application process appname set allText to (get value of every static text of aWin) if allText contains staticText then log "fwbst winnum: " & winNum return winNum end if end repeat end if end tell return null end find_window_by_static_text -- Open a given VPN connection and enter the password on open_vpn_connection(theService, thePassword, theApp, theText) tell application "System Events" tell network preferences connect service theService end tell end tell --delay 2 repeat with x from 1 to 20 log "vc loop " & x delay 0.1 set winNum to find_window_by_static_text(theApp, theText) log "winNum is: " & winNum if winNum is not null then exit repeat end if end repeat if winNum is null then log "Could not find the VPN Connection window" return null end if tell application theApp to activate tell application "System Events" perform action "AXRaise" of item winNum of (get every window of application process theApp) keystroke thePassword key code 36 end tell end open_vpn_connection




