-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Move Security.addProvider(new BouncyCastleProvider())
into a Callable
block to avoid NoClassDefFoundError
#5312
Conversation
@jmarti44 : Could you please link the issue which you're trying to fix in this PR? Would be nice to add some tests to validate the fix as well. |
@jmarti44 : Sorry, your PR description was hidden by comment. I've updated it now |
@rohanKanojia Would unit testing be neccessary for the method I changed since it's private method? What kind of testing could I utilize? My attempt was to illustrate screenshots from my sample projects and zipping the projects themselves as well |
Kudos, SonarCloud Quality Gate passed! |
@@ -149,13 +149,19 @@ private static PrivateKey loadKey(InputStream keyInputStream, String clientKeyAl | |||
private static PrivateKey handleECKey(InputStream keyInputStream) { | |||
// Let's wrap the code to a callable inner class to avoid NoClassDef when loading this class. | |||
try { | |||
if (Security.getProvider("BC") == null && Security.getProvider("BCFIPS") == null) { | |||
new Callable<String>() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure to understand why you are creating a anonymous Callable object just to execute the call method without reusing it afterwards?
Could probably be simplified with just
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's in case the dependency is not present at runtime. There's a utility for this sort of thing called OptionalDependencyWrapper, but it's in common, not api. We could consider moving that up to the api module for this.
@jmarti44 : Hello, Sorry for late reply. I downloaded your reproducer project and extracted it to my machine.
fabric8-issue (using
fabric8-issue-2 (using Fabric8 Kubernetes Client
|
b86a67c
to
6b12573
Compare
@jmarti44 : Could you please check what I might be missing? edit: This can only be reproduced in a FIPS enabled environment. |
@jmarti44 : I tried your project by deploying it on a Red Hat OpenShift FIPS complaint cluster.
Along with a FIPS complaint cluster, you also need a cluster that uses Elliptic Curve keys |
The problem reported in #5296 is caused due to a mix of how CertUtils.handleECKey is written and user's project configuration. The user is relying in these bouncycastle dependencies: These dependencies contain all classes used in CertUtils.handleECKey except Upon debugging this, I noticed that NoClassDefFoundError is thrown even when the if statement in this block is evaluated as User sets Lines 186 to 188 in e18b463
When if (Security.getProvider("BC") == null && Security.getProvider("BCFIPS") == null) {
new Callable<String>() {
@Override
public String call() {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
return null;
}
}.call();
} If I move this Callable block outside if block, I start getting NoClassDefFound for I checked by adding debug statements, control does not go inside the Line 189 in e18b463
|
Yes, as we discussed internally, this fix is basically swallowing the NoClassDefFound exception and moving on to the next statements. We should try to make the if-statement comply with the valid user setup instead. |
e87e03a
to
738651c
Compare
Security.addProvider(new BouncyCastleProvider())
into a Callable
block to avoid NoClassDefFoundError
+ Add a comment for the reasoning behing moving Security.addProvider into a Callable block + Add a test inside a separate module using `bc-fips` and `bcpkis-fips` that reproduces the issue Signed-off-by: Rohan Kumar <[email protected]>
738651c
to
766c08d
Compare
Quality Gate passedIssues Measures |
Description
Fix #5296
Security.addProvider
call inside a Callable block so that whole block does not throw NoClassDefFoundError for BouncyCastleProvider (In user's scenariobc-fips
is used instead ofbcprov-jdk18on
that does not containorg.bouncycastle.jce.provider.BouncyCastleProvider
kubernetes-client-deps-compatibility-tests
to Kubernetes Client project for having project specific tests where we can test behavior of client in presence of different dependencies on the classpathkubernetes-client-deps-compatibility-tests/kubernetes-client-init-bc-fips
withorg.bouncycastle:bc-fips
andorg.bouncycastle:bcpkix-fips
dependencies.where CertUtils would automatically try to create an instance of the bouncy castle provider within the callable when there is a not bouncy castle fips provider provided. Wrapping it in a callable in this fashion would automatically throw a NoClassDefFound error despite already providing a security bouncy castle fips provider. Moving the conditional where the application searches for the fips provider just outside and before the callable will successfully create an instance of PEMKeyPair and will return successfully when a BouncyCastleFipsProvider is created.
I have added two zipped maven projects to help illustrate the issue and solution. They are both simple projects that print a successful message when both a Kubernetes Client and OpenShift Client is successfully built when a FIPS provider is provided. The project
fabric8_issue
utilizes a version of the kubernetes client api with this proposed fix. It is able to print a success message as shown in the screenshot belowThe second project (fabric8_issue2) is the same project with the current version of the Kubernetes Client API (pulled from master). The NoClassDefFound Error is thrown here.
These projects were built using JDK17.
simple_projects.zip
Type of change
test, version modification, documentation, etc.)
Checklist