We are using Maven 2 and have a maven repository manager secured with SSL client authentication. In order for Maven to access the repository the following system properties must be passed to Java:
javax.net.ssl.trustStore=trust.jks
javax.net.ssl.trustStorePassword=<trustPass>
javax.net.ssl.keyStore=keystore.p12
javax.net.ssl.keyStoreType=pkcs12
javax.net.ssl.keyStorePassword=<keyStorePass>
See this mini-guide for more details.
In order to set these system properties in Maven, I have to use the MAVEN_OPTS environment variable (or pass them directly on the command-line). Either way, when Maven actually executes, all of these properties become visible to other users on the system (via ps), including my key store password.
Is there a way to set these properties so that the password doesn't get exposed on the command-line?
The solution I came up with on OSX is the following .mavenrc
. It uses a python script to access the password in the keychain in order to open the client certificate and then generates a random passphrase and a temporary certificate with that random password.
Put this in ~/.mavenrc
and add your client certificate to the OSX keychain. Make sure and set MAVEN_CLIENT_CERT
to the location of your client certificate.
export MAVEN_CLIENT_CERT=<PATH.TO.CLIENT.CERTIFICATE>
# Retrieve secret from keychain
export SECRET=$(python <<END
from subprocess import Popen, PIPE
import re, sys, os
passlabel = os.environ.get("MAVEN_CLIENT_CERT", None)
p = Popen(['security', 'find-generic-password', '-l',passlabel,'-g'], stdout=PIPE, stderr=PIPE, stdin=PIPE)
sys.stdout.write(re.compile('password:\\s"(.*)"').match(p.stderr.read()).group(1))
sys.exit(0)
END)
TMPDIR=/tmp
TMPTMPL=mvn-$(id -u)-XXXXXXXXXX
PASSPHRASE=$(openssl rand -base64 32)
export PASSPHRASE TMPDIR
pemfile=$(mktemp $TMPDIR/$TMPTMPL)
openssl pkcs12 -in $MAVEN_CLIENT_CERT -passin env:SECRET -out $pemfile -passout env:PASSPHRASE
p12file=$(mktemp $TMPDIR/$TMPTMPL)
openssl pkcs12 -export -in $pemfile -out $p12file -passin env:PASSPHRASE -passout env:PASSPHRASE
sh -c "while kill -0 $$ 2>/dev/null; do sleep 1; done; rm -f $pemfile; rm -f $p12file;" &
MAVEN_OPTS="$MAVEN_OPTS -Djavax.net.ssl.keyStore=$p12file -Djavax.net.ssl.keyStoreType=pkcs12 -Djavax.net.ssl.keyStorePassword=$PASSPHRASE"
On Linux, the following .mavenrc will work with gnome keyring (make sure and add the cert password to your login keyring and set the id variable KEYRING_ID
):
MAVEN_CLIENT_CERT=<PATH.TO.CLIENT.CERTIFICATE>
export KEYRING_NAME="login"
export KEYRING_ID=<KEYRING.ID>
# Try to get secret from the gnome keyring
export SECRET=$(python <<END
import sys, os
# Test for gtk
try:
import gtk #ensure that the application name is correctly set
import gnomekeyring as gk
except ImportError:
gtk = None
if gtk:
id = os.environ.get("KEYRING_ID", None)
name = os.environ.get("KEYRING_NAME", None)
try:
if id:
info = gk.item_get_info_sync(name, int(id))
attr = gk.item_get_attributes_sync(name, int(id))
sys.stdout.write(str(info.get_secret()))
else:
params = {}
types = {'secret': gk.ITEM_GENERIC_SECRET, 'network': gk.ITEM_NETWORK_PASSWORD, 'note': gk.ITEM_NOTE}
eparams = os.environ.get("KEYRING_PARAMS", None)
etype = os.environ.get("KEYRING_ITEMTYPE", None)
if eparams and etype:
list = eparams.split(',')
for i in list:
if i:
k, v = i.split('=', 1)
if v.isdigit():
params[k] = int(v)
else:
params[k] = v
matches = gk.find_items_sync(types[etype], params)
# Write 1st out and break out of loop.
# TODO: Handle more then one secret.
for match in matches:
sys.stdout.write(str(match.secret))
break
sys.exit(0)
except gk.Error:
pass
sys.exit(1)
END
)
TMPDIR=/dev/shm
TMPTMPL=mvn-$(id -u)-XXXXXXXXXX
PASSPHRASE=$(openssl rand -base64 32)
export PASSPHRASE TMPDIR
pemfile=$(mktemp $TMPDIR/$TMPTMPL)
openssl pkcs12 -in $MAVEN_CLIENT_CERT -passin env:SECRET -out $pemfile -passout env:PASSPHRASE
p12file=$(mktemp $TMPDIR/$TMPTMPL)
openssl pkcs12 -export -in $pemfile -out $p12file -passin env:PASSPHRASE -passout env:PASSPHRASE
sh -c "while kill -0 $$ 2>/dev/null; do sleep 1; done; rm -f $pemfile; rm -f $p12file;" &
MAVEN_OPTS="$MAVEN_OPTS -Djavax.net.ssl.keyStore=$p12file -Djavax.net.ssl.keyStoreType=pkcs12 -Djavax.net.ssl.keyStorePassword=$PASSPHRASE"