I am trying to create a task that would involve the Java keytool binary, but apparently I am unable to pass the dname argument properly. Spaces seem to be the problem, but only when run as a Gradle script. When I copy-paste the same command into a terminal it works. (I believe in both cases the same keytool binary is being used.)
This is my script:
task generateTomcatKeystore() {
doLast {
def serverAlias = "server_debug"
def serverStorePass = "changeit_server"
def serverKeyPass = "changeit_server"
def ourDomain = "domain.net"
def ourName = "Company"
def dName = /CN=$ourDomain, OU=Backend, O=$ourName, L=Prague, S=Czech Republic, C=CZ/
def keytoolCommand = /keytool -genkeypair -alias $serverAlias -keyalg RSA -keysize 2048 -sigalg SHA1withRSA -dname "$dName" -validity 365 -keypass $serverKeyPass -keystore tomcat.jks -storepass $serverStorePass/;
// what exactly am I executing?
println keytoolCommand
def outputErr = keytoolCommand.execute().err.text
// errors?
println outputErr
// am I calling the right binary? ...apparently yes
println 'which keytool'.execute().text
}
}
This is the complaint I am getting:
Illegal option: OU=Backend,
When I eliminate all the spaces in between the dname components like this:
def dName = /CN=$ourDomain,OU=Backend,O=$ourName,L=Prague,S=Czech Republic,C=CZ/
the error changes to:
Illegal option: Republic,C=CZ"
...so clearly the spaces are the issue. But only when run from within Gradle.
Note that my -dname is enclosed by double quotes:
keytool -genkeypair -alias server_debug -keyalg RSA -keysize 2048 -sigalg SHA1withRSA -dname "CN=domain.net,OU=Backend,O=Company,L=Prague,S=Czech Republic,C=CZ" -validity 365 -keypass changeit_server -keystore tomcat.jks -storepass changeit_server
According to Oracle only commas have to be escaped within the dname argument, see for yourself.
Under the hood, groovy has added an execute() method to java.lang.String
that splits your string into an array. It probably does this by splitting on space characters. See String.execute()
I suggest you use Gradle's Project.exec(Closure) instead. You could do something like
ByteArrayOutputStream errorOut = new ByteArrayOutputStream()
exec {
workingDir = "$javaHome/bin"
errorOutput = errorOut
args "keytool -genkeypair -alias $serverAlias -keyalg RSA -keysize 2048 -sigalg SHA1withRSA -dname".split(' ')
args dName
args "-validity 365 -keypass $serverKeyPass -keystore tomcat.jks -storepass $serverStorePass".split(' ')
}
String errors = errorOut.toString()