Reputation: 3310
Debian has a great mechanism to compile all commonly used CA certificates from Thawte, Let's Encrypt etc. as well as locally installed ones from /usr/local/share/ssl
into one /etc/ssl/certs/java/cacerts
JKS file. That is usually symlinked to $JAVA_HOME/lib/security/cacerts
.
With sdkman I switch between different non-Debian Java versions in ~/.sdkman/candidates/java/current/
which use the cacerts provided by the SDK creator.
Is there some kind of post-inst hook mechanism where I could automatically create a symlink to the Debian cacerts file whenever I switch sdkman Java versions?
Upvotes: 21
Views: 6929
Reputation: 14979
You could use an extension script. If you create a file in the ${SDKMAN_DIR}/ext/
folder (ie: ${SDKMAN_DIR}/ext/sdk-install-then-symlink-cacerts.sh
) with the following code:
#!/bin/bash
source <(sed 's/__sdk_install/__sdk_builtin_install/g' "${SDKMAN_DIR}/src/sdkman-install.sh")
function __sdk_install() {
__sdk_builtin_install "$@"
local exit_code=$?
if ((exit_code==0)); then
local java_home
java_home="$(__sdk_home "${1}" "${2}")"
rm "${java_home}/lib/security/cacerts"
ln -s "/etc/ssl/certs/java/cacerts" "${java_home}/lib/security/cacerts"
fi
return "${exit_code}"
}
It would replace the pre-packaged cacerts
with a symlink to the /etc/ssl/certs/java/cacerts
for each new install.
Upvotes: 0
Reputation: 2250
SDKMAN has predefined post installation hooks but there doesn't seem any way to customize them or add your own. I didn't want to create a new wrapper tool like @PeterMue because it'd cause cognitive load and also the footgun of users forgetting to run that, so my solution was to hook into the shell's prompt mechanism. I installed starship
(https://starship.rs) and put the eval "$(starship init <shell>)"
below SDKMan, and in ~/.config/starship.toml
I defined a section for a custom command which will be run during prompt generation:
[custom.java-cacerts]
when = true
shell = "sh"
command = """
set -xe
[ -f /etc/ssl/certs/java/cacerts ]
ALL_CACERTS=$(find -P "$SDKMAN_DIR/candidates/java" -name cacerts -type f | grep .)
echo "[java: symlinking cacerts]"
for cacerts in $ALL_CACERTS; do
mv "$cacerts" "$cacerts.original"
ln -s /etc/ssl/certs/java/cacerts "$cacerts"
done 2>&1
"""
Explanation:
set -xe
sets the e
flag (exit when any command errors) and the x
flag (log commands to stderr
)e
flag is set, we can skip the if
clause and write the condition at the top. If it fails, the script will short circuitfind -P
doesn't follow symlinks, so the current
symlink is ignored. -type f
to only find cacerts
which are regular files (no symlinks)find
always returns success even when no match was found. Piping that into grep .
matches anything and causes a non-zero status when there is no input so the script will stopset -x
writes everything to stderr
, but starship
only captures stdout
and ignores stderr, so I use 2>&1
on the for
loop to print those 2 commands to inform the user.This runs very fast and on my machine the prompt delay is almost not noticeable. Also using find
rather than a predefined path on $JDK/lib/security/cacerts
is more backward compatible as for Java 8 the cacerts
is under $JDK/jre/lib/security/cacerts
.
Upvotes: 0
Reputation: 13
I solves this with a custom zsh function so I just have to run sdkman cacerts ~/.cacerts
to symlink all cacerts for all sdkman installed jdks.
# sdkman
sdkman() {
case $1 in
--help)
cat <<EOF
Alias for sdk with additional custom functions.
Usage: $0 <subcommand> [candidate] [version]
Additional Commands
$0 --help Print this help message
$0 cacerts [cacerts] Symlink all java cacerts to a custom location (default: ~/.cacerts)
EOF
;;
cacerts)
cacerts="${2:-$HOME/.cacerts}"
if [[ -f "$cacerts" ]]; then
for jdk in $(sdk list java | grep installed | sed 's/^.*\| \(.*\)$/\1/g'); do
jdkHome=$(sdk home java $jdk)
pushd "$jdkHome/lib/security"
mv cacerts cacerts.orginal
ln -s "$cacerts" "cacerts"
popd
done
else
echo "Abort: file $cacerts not found."
fi
;;
*)
sdk "$@"
esac
}
Upvotes: 1