Skip to content

Commit ecadfde

Browse files
Merge pull request #2340 from kunalmemane/JKNS-859-fix-jbcrypt-with-spring-security-rhel9
JKNS-859: Replace jbcrypt with Spring Security BCryptPasswordEncoder
2 parents b52fc08 + 030d924 commit ecadfde

4 files changed

Lines changed: 91 additions & 14 deletions

File tree

2/contrib/jenkins/jenkins-common.sh

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,51 @@ export AUTH_TOKEN=${KUBE_SA_DIR}/token
99
export JENKINS_PASSWORD KUBERNETES_SERVICE_HOST KUBERNETES_SERVICE_PORT
1010
export ITEM_ROOTDIR="\${ITEM_ROOTDIR}" # Preserve this variable Jenkins has in config.xml
1111

12-
# Takes a password and an optional salt value, outputs the hashed password.
12+
# Jenkins LTS 2.516.1 removed the jbcrypt library from the WAR.
13+
# Password hashing now uses Spring Security's BCryptPasswordEncoder instead.
14+
#
15+
# The Java source for the password utilities lives in jenkins-bcrypt-util/.
16+
# At container startup, build_password_encoder_jar compiles these sources
17+
# into password-encoder.jar using spring-security-crypto from the WAR.
18+
#
19+
# At runtime, the WAR lib directory is added to the classpath because
20+
# BCryptPasswordEncoder also needs jcl-over-slf4j and slf4j-api for logging.
21+
#
22+
# ref: https://www.jenkins.io/changelog/2.516.1/
23+
# https://www.jenkins.io/changelog/2.509/
24+
25+
PASSWORD_ENCODER_SRC="/opt/openshift/jenkins-bcrypt-util"
26+
PASSWORD_ENCODER_JAR="/opt/openshift/password-encoder.jar"
27+
28+
function build_password_encoder_jar {
29+
if [ -f "${PASSWORD_ENCODER_JAR}" ]; then
30+
return 0
31+
fi
32+
local spring_security_crypto=$(find /tmp/war/WEB-INF/lib ${JENKINS_HOME}/war/WEB-INF/lib -name "spring-security-crypto-*.jar" 2>/dev/null | head -1)
33+
javac -classpath "${spring_security_crypto}" \
34+
-d "${PASSWORD_ENCODER_SRC}" \
35+
"${PASSWORD_ENCODER_SRC}/com/redhat/openshift/PasswordEncoder.java" \
36+
"${PASSWORD_ENCODER_SRC}/com/redhat/openshift/PasswordChecker.java"
37+
jar cf "${PASSWORD_ENCODER_JAR}" -C "${PASSWORD_ENCODER_SRC}" com
38+
}
39+
40+
# Takes a password, outputs the hashed password.
1341
function obfuscate_password {
1442
local password="$1"
15-
local salt="$2"
16-
#local acegi_security_path=`find /tmp/war/WEB-INF/lib/ -name acegi-security-*.jar`
17-
#local commons_codec_path=`find /tmp/war/WEB-INF/lib/ -name commons-codec-*.jar`
18-
local jbcrypt_path=`find /tmp/war/WEB-INF/lib ${JENKINS_HOME}/war/WEB-INF/lib/ -name jbcrypt-*.jar 2> /dev/null | head -1`
19-
# source for password-encoder.jar is inside the jar.
20-
# acegi-security-1.0.7.jar is inside the jenkins war.
21-
# java -classpath "${acegi_security_path}:${commons_codec_path}:/opt/openshift/password-encoder.jar" com.redhat.openshift.PasswordEncoder $password $salt
22-
java -classpath "${jbcrypt_path}:/opt/openshift/password-encoder.jar" com.redhat.openshift.PasswordEncoder $password $salt
43+
local war_lib=$(find /tmp/war/WEB-INF/lib ${JENKINS_HOME}/war/WEB-INF/lib -maxdepth 0 -type d 2>/dev/null | head -1)
44+
45+
build_password_encoder_jar
46+
47+
java -classpath "${war_lib}/*:${PASSWORD_ENCODER_JAR}" com.redhat.openshift.PasswordEncoder "$password"
2348
}
2449

2550
# Returns 0 if password matches 1 otherwise
2651
function has_password_changed {
2752
local password="$1"
2853
local password_hash="$2"
29-
local jbcrypt_path=`find /tmp/war/WEB-INF/lib ${JENKINS_HOME}/war/WEB-INF/lib/ -name jbcrypt-*.jar 2> /dev/null | head -1`
30-
# source for password-encoder.jar is inside the jar.
31-
java -classpath "${jbcrypt_path}:/opt/openshift/password-encoder.jar" com.redhat.openshift.PasswordChecker $password $password_hash
54+
local war_lib=$(find /tmp/war/WEB-INF/lib ${JENKINS_HOME}/war/WEB-INF/lib -maxdepth 0 -type d 2>/dev/null | head -1)
55+
56+
build_password_encoder_jar
57+
58+
java -classpath "${war_lib}/*:${PASSWORD_ENCODER_JAR}" com.redhat.openshift.PasswordChecker "$password" "$password_hash"
3259
}
33-
34-
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.redhat.openshift;
2+
3+
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
4+
5+
/**
6+
* Checks bcrypt password against a raw password
7+
* using Spring Security's BCryptPasswordEncoder.
8+
*
9+
* @author kunalmemane
10+
*/
11+
12+
public class PasswordChecker {
13+
public static void main(String[] args) {
14+
String rawPassword = args[0];
15+
String encodedPassword = args[1];
16+
17+
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
18+
if (!encoder.matches(rawPassword, encodedPassword)) {
19+
System.out.println("Detected password environment variable change, Jenkins configuration must be updated...");
20+
System.exit(1);
21+
}
22+
System.exit(0);
23+
}
24+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.redhat.openshift;
2+
3+
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
4+
5+
/**
6+
* Encodes a password using Spring Security's BCryptPasswordEncoder.
7+
*
8+
* Previously used org.mindrot.jbcrypt.BCrypt, but Jenkins 2.509+ and LTS 2.516.1 removed
9+
* the jbcrypt library from the WAR and now uses Spring Security's BCryptPasswordEncoder
10+
* implementation internally.
11+
*
12+
* The output format ($2a$10$...) is identical and backward-compatible
13+
* with hashes produced by the old jbcrypt library.
14+
*
15+
* ref: https://www.jenkins.io/changelog/2.509/
16+
* https://www.jenkins.io/changelog/2.516.1/
17+
*
18+
* @author kunalmemane
19+
*/
20+
21+
public class PasswordEncoder {
22+
public static void main(String[] args) {
23+
String password = args[0];
24+
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
25+
String encodedPassword = encoder.encode(password);
26+
System.out.println(encodedPassword);
27+
}
28+
}
-2.76 KB
Binary file not shown.

0 commit comments

Comments
 (0)