-
Notifications
You must be signed in to change notification settings - Fork 186
Description
Summary
The JWTConfig.Builder constructor hardcodes the instantiation of DefaultPrivateKeyDecryptor on line 270, which causes issues when testing with custom PrivateKeyDecryptor implementations that use different BouncyCastle library versions.
If we exclude org.bouncycastle:bcprov-jdk18on:1.83 as described in https://github.com/box/box-java-sdk?tab=readme-ov-file#fips-140-2-compliance and add FIPS compatible libs, we can't use JWTConfig.Builder since it hardcodes DefaultPrivateKeyDecryptor in constructor, so it fails even before we set it via .privateKeyDecryptor(fipsPrivateKeyDecryptor)
org.bouncycastle.jce.provider.BouncyCastleProvider
java.lang.ClassNotFoundException: org.bouncycastle.jce.provider.BouncyCastleProvider
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:525)
at com.box.sdkgen.box.jwtauth.JWTConfig$Builder.<init>(JWTConfig.java:270)
Current Behavior
In JWTConfig.java (line 270):
public Builder(
String clientId,
String clientSecret,
String jwtKeyId,
String privateKey,
String privateKeyPassphrase) {
this.clientId = clientId;
this.clientSecret = clientSecret;
this.jwtKeyId = jwtKeyId;
this.privateKey = privateKey;
this.privateKeyPassphrase = privateKeyPassphrase;
this.algorithm = new EnumWrapper<JwtAlgorithm>(JwtAlgorithm.RS256);
this.tokenStorage = new InMemoryTokenStorage();
this.privateKeyDecryptor = new DefaultPrivateKeyDecryptor(); // <-- Hardcoded instantiation
}Even when using .privateKeyDecryptor(customDecryptor), the DefaultPrivateKeyDecryptor is instantiated first during Builder construction, which can cause class loading failures if:
- The test environment uses a different BouncyCastle version (e.g.,
bcprov-jdk18on:1.83for FIPS compliance) - The
DefaultPrivateKeyDecryptordepends on incompatible BouncyCastle classes - Tests need to use FIPS-compliant cryptography providers
Expected Behavior
The DefaultPrivateKeyDecryptor should only be instantiated when actually needed (lazy initialization), or the Builder should support passing a custom PrivateKeyDecryptor from the start to avoid instantiating the default one.
Proposed Solutions
Option 1: Lazy initialization in build()
public JWTConfig build() {
if (this.privateKeyDecryptor == null) {
this.privateKeyDecryptor = new DefaultPrivateKeyDecryptor();
}
return new JWTConfig(this);
}Option 2: Add constructor overload
public Builder(
String clientId,
String clientSecret,
String jwtKeyId,
String privateKey,
String privateKeyPassphrase,
PrivateKeyDecryptor privateKeyDecryptor) {
this.clientId = clientId;
this.clientSecret = clientSecret;
this.jwtKeyId = jwtKeyId;
this.privateKey = privateKey;
this.privateKeyPassphrase = privateKeyPassphrase;
this.algorithm = new EnumWrapper<JwtAlgorithm>(JwtAlgorithm.RS256);
this.tokenStorage = new InMemoryTokenStorage();
this.privateKeyDecryptor = privateKeyDecryptor != null ? privateKeyDecryptor : new DefaultPrivateKeyDecryptor();
}Use Case
This is needed for FIPS 140-2 compliant environments where:
- Custom
PrivateKeyDecryptorimplementations use FIPS-certified BouncyCastle providers - Tests require
testImplementation("org.bouncycastle:bcprov-jdk18on:1.83") - The
DefaultPrivateKeyDecryptorclass loading conflicts with the required BouncyCastle version