Authentication Into ANT


For developers, we all know that it is not very good to keep our passwords, usernames, and security tokens in a plain text file, yet the sample provided by Salesforce in the force.com migration tool does this.  I was looking for a better way.  I have a few but ultimately, my goal is to type in a string for my developer environment and have authentication be handled for me.

This post is geared towards both mac and pc.

Example 1 – A better way, but not great:

  1. Limitations:
    1. You must install ant contrib for this example to work.
    2. You have to type in your password + security token, username and specify if it is a sandbox each push / retrieve.  This gets old fast.  Not preferred but a good example if you don’t want to do too much setup.

 

Step 1:

Install ant-contrib.  I won’t give step-by-step instructions for this.  The ant-contrib documentation has this clearly spelled out here.

 

<project name="Sample usage of Salesforce Ant tasks" default="retrieveUnpackaged" basedir="." xmlns:sf="antlib:com.salesforce">
    
    <taskdef resource="net/sf/antcontrib/antcontrib.properties">
      <classpath>
        <pathelement location="[Yourfilelocation]/ant-contrib-1.0b3.jar"/>
      </classpath>
    </taskdef>

    <property file="build.properties"/>
    <property environment="env"/>

    <input message="Username:" addproperty="sf.username" />
    <input message="secure-input:" addproperty="sf.password">
        <handler classname="org.apache.tools.ant.input.SecureInputHandler" />
    </input>
    <echo message="Username: ${sf.username}" />  
    <echo message="Stop execution if incorrect!" />
    
    
    <input message="Is sandbox (Y/N)?" addproperty="sf.sandbox" >
        
    </input>

    <if>
     <equals arg1="${sf.sandbox}" arg2="Y" />
     <then>
       <property name="sf.serverurl" value="https://test.salesforce.com" />
     </then>
     <else>
       <property name="sf.serverurl" value="https://login.salesforce.com" />
     </else>
    </if>
    <echo message="Login URL: ${sf.serverurl}" />
    
        
    <condition property="sf.username" value=""> <not> <isset property="sf.username"/> </not> </condition>
    <condition property="sf.password" value=""> <not> <isset property="sf.password"/> </not> </condition>

    <taskdef resource="com/salesforce/antlib.xml" uri="antlib:com.salesforce">
        <classpath>
            <pathelement location="../ant-salesforce.jar" />        	
        </classpath>
    </taskdef>
    
    <!-- Retrieve an unpackaged set of metadata from your org -->
    <!-- The file unpackaged/package.xml lists what is to be retrieved -->
    <target name="retrieveUnpackaged">
      <mkdir dir="retrieveUnpackaged"/>
      <sf:retrieve username="${sf.username}" password="${sf.password}"  serverurl="${sf.serverurl}" maxPoll="${sf.maxPoll}" retrieveTarget="retrieveUnpackaged" unpackaged="unpackaged/package.xml"/>
    </target>

</project>

If you have correctly entered your password and selected the correct type environment, sandbox / prod, your output will look like this:

Success - ant enter inputs

 

Example 2 – A better way using a password manager:

  1. Why this is better:
    1. You don’t need to remember your username, the endpoint or the security token.  You type in the value of your lastPass environment and the rest is done for you.
    2. You don’t need ant-contrib for your build.xml.
    3. Using a password manager that has strong encryption and security standards means that your platform is more protected – much more so than if you have your password in a plain text file.
  2. Limitations:
    1. This requires lastpass but there are plenty of other password managers that have CLI integration to use.  I just happen to use this one.
      1. I chose lastpass because it has cli support, works on any device, and also supports two factor authentication, either via google authenticator or SF authenticator.
    2. The setup is a bit more intensive, but pays dividends in the time it takes to enter your password, enter your security token, enter the endpoint, & repeat.

Let’s get started!

Step 1:

If you don’t have a lastpass account, you’ll need to get one.  You can get one for free from here.

Step 2:

Install lastpass for cli from the github repository.  The installation instructions are very clear on the github repo.  If you want the full documentation on usage of the CLI, it is available here.

Step 3:

Go to your last pass account and create a new site, storing your security token in the notes field.

Step 4:

Define your package.xml as follows:

<project name="Sample usage of Salesforce Ant tasks" default="retrieveUnpackaged" basedir="." xmlns:sf="antlib:com.salesforce">
 
 <property file="build.properties"/>
 <property environment="env"/>

 <taskdef resource="com/salesforce/antlib.xml" uri="antlib:com.salesforce">
    <classpath>
       <pathelement location="../ant-salesforce.jar" /> 
    </classpath>
 </taskdef>
 
 <!-- Retrieve an unpackaged set of metadata from your org -->
 <!-- The file unpackaged/package.xml lists what is to be retrieved -->
 <target name="retrieveUnpackaged">
    <mkdir dir="retrieveUnpackaged"/>
    <!-- Retrieve the contents into another directory -->
    <sf:retrieve username="${sf.username}" password="${sf.password}" serverurl="${sf.serverurl}" maxPoll="${sf.maxPoll}" retrieveTarget="retrieveUnpackaged" unpackaged="unpackaged/package.xml"/>
 </target>

</project>

Step 5 – authentication in your command prompt / terminal:

Type lpass login [username].  You will be prompted for your master password and if you have two factor enabled, you will be prompted for this as well.

Step 6 – Create the scripts to run the ant commands:

We will need to create a simple script to populate the environment variables for usage to pass into ant. I highly recommend keeping these in your folder with you ant scripts.  You can put both the windows and mac version in there if you are one of those lucky individuals like me that uses both operating systems.

Windows:

Before getting started, if you’re on windows 10, you will need to enable the linux bash for windows.  This is included in their anniversary upgrade.  How to enable is here. You will use the ubuntu installation instructions from the github directory.  If you’re on a version less than windows 10, you will need to use cygwin.

Put the script from the mac section below in your directory and execution will be the same, except you will use bash instead of sh.

Make sure that you install ant & java with the following:

sudo apt-get install python-software-properties
sudo add-apt-repository ppa:webupd8team/java
sudo apt-get update
sudo apt-get install oracle-java8-installer
sudo apt-get install ant

You may also need to install the ant-salesforce.jar in the /usr/share/ant/lib directory.  To do so, login as root:

sudo su
chmod -R o=rwx ant
cp [ant-jarlocation] /usr/share/ant/lib

 

If everything works (and you’ve copied the script from the mac section below), you’ll get this:

 

Note, if you’re getting an error when running the file, you may have extra control-m characters which throws off the bash interpreter.  To check, run:

LC_ALL=C cat -e script

Where script is your script.

If you see ^M, you will need to run:

cat script | tr -d '\r' > fixedscript.sh

 

 

 

Mac:

Save the below as “loadvars.sh”.

#!/bin/bash
# Loop through variables and assign uid and antTar
while [[ $# -gt 1 ]]
do
key="$1"

case $key in
 -u|--uid)
 uid="$2"
 shift # past argument
 ;;
 -a|--antTar)
 antTar="$2"
 shift # past argument
 ;;
 *)
 # unknown option
 ;;
esac
shift # past argument or value
done

#Set up variables to pass
username=$(lpass show -u "$uid")
password=$(lpass show -p "$uid")
serverurl=$(lpass show --url "$uid")
secToken=$(lpass show --notes "$uid")
pass=$password$secToken

echo "Username: $username"
echo "Endpoint: $serverurl"
echo "Ant command: $antTar"
read -p "Are you sure you want to perform this command? " -n 1 -r
echo # (optional) move to a new line

# Verify that target is correct before pushing
if [[ $REPLY =~ ^[Yy]$ ]]
then
 # Call ant target
 ant "$antTar" -Dsf.username="$username" -Dsf.password="$pass" -Dsf.serverurl="$serverurl"
fi

To call this script, you will need to either type in:

sh loadvars.sh –uid [yourUID] –antTar [antTargetToRetrieve]

e.x.

sh loadvars.sh –uid Success_Community –antTar retrieveUnpackaged

Alternatively, you can use -u and -a as shorthand for the uid and the ant target.

If all works, your screen should look like this.

Bash Script

Both scripts will present you with the command, the username and the endpoint.  You must confirm before proceeding.  This is for your safety.  It is always good to confirm that you are deploying to the right environment, no? If you wanted to, you could add a force command for CI build scripts to bypass the prompt.

Leave a comment

Your email address will not be published. Required fields are marked *