-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Quarkus 2.x has java.lang.NoClassDefFoundError: Could not initialize class javax.crypto.JceSecurity #19265
Comments
/cc @sberyozkin |
How can I reproduce this? I can load the class fine using Class.forName(). That error is also an initializion error, which means the static init block in JceSecurity is throwing an exception. Attaching a debugger to see what is actually throwing the exception would also be really helpful if you can't provide a reproducer. |
Yeah our code project is huge, posting it is not practical.
I can say that the code that uses this is annotated with @singleton and it
is used very early in the Quarkus framework code to decrypt the DB
password. Our app.yml has 3 data sources but only one of them uses the
Quarkus CredentialsProvider to decrypt the password, that is the usage that
is failing.
I can try to attach a debugger to see what error is given.
I never like to use static blocks as they have too many bad behaviors. But
since you say it's thrown there I would say there was a change in
Quarkus 2.x such that whatever is needed there is not available yet as it
works fine in Quarkus 1.x.
…-Dave
On Sun, Aug 8, 2021 at 8:59 PM Stuart Douglas ***@***.***> wrote:
How can I reproduce this? I can load the class fine using Class.forName().
That error is also an initializion error, which means the static init
block in JceSecurity is throwing an exception. Attaching a debugger to see
what is actually throwing the exception would also be really helpful if you
can't provide a reproducer.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#19265 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAL7BL6YAA4VVKP4JZ2SMADT35AA5ANCNFSM5BUVWYZQ>
.
Triage notifications on the go with GitHub Mobile for iOS
<https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675>
or Android
<https://play.google.com/store/apps/details?id=com.github.android&utm_campaign=notification-email>
.
|
The static block is in the JDK itself, not much we can do about it. I tried with pretty much the exact same code and it worked. Looking through the source code of JceSecurity I don't see how anything Quarkus was doing could actually affect it, so I am really not sure what is going on. You are going to need to attach a debugger to see what is actually throwing the exception (Java makes it really hard to debug these kinds of errors, as the cause is lost and turned into NoClassDefFoundError instead). |
Understood, I will do this as soon as possible.
…-Dave
On Mon, Aug 9, 2021 at 4:57 PM Stuart Douglas ***@***.***> wrote:
The static block is in the JDK itself, not much we can do about it. I
tried with pretty much the exact same code and it worked.
Looking through the source code of JceSecurity I don't see how anything
Quarkus was doing could actually affect it, so I am really not sure what is
going on. You are going to need to attach a debugger to see what is
actually throwing the exception (Java makes it really hard to debug these
kinds of errors, as the cause is lost and turned into NoClassDefFoundError
instead).
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#19265 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAL7BL47AEYNH6VIAWPGT5TT4BMOXANCNFSM5BUVWYZQ>
.
Triage notifications on the go with GitHub Mobile for iOS
<https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675>
or Android
<https://play.google.com/store/apps/details?id=com.github.android&utm_campaign=notification-email>
.
|
I am having a hard time getting more details as I debug this. Here is the full stack trace. 2021-08-19 15:34:14,891 ERROR [io.qua.run.Application] (main) Failed to start application (with profile prod): java.lang.NoClassDefFoundError: Could not initialize class javax.crypto.JceSecurity The line in java.base/javax.crypto.Cipher.getInstance where it is failing is on this line: However my IDE will never go into that method it throws the NoClassDefFoundError exception. The strange part is when I debug this the code lands on 540 about 20 times in a loop, giving an error each time. Then it just quits with the above stack trace. Note our app has 3 data sources and two of them use the DataSourceCredentialsProvider. The third data source is not available in our DEV environment so that one just fails...but we expect that one to fail. With Quarkus 2.x all of them fail with this new NoClassDefFoundError error. I have verified this fails with the new 2.1.3.Final version as well. So in summary fails with all Quarkus 2.x Here is my Java: Note this is very early code in application startup. Agroal is trying to get the password for our DB and to do that it has to use our AES decryption that is used in the CredentialsProvider implementation. |
It looks like the static init block has the following:
Can you set a breakpoint for SecurityException, and try and figure out what the underlying exception is? Also what mode is this, is it prod, dev or both? If it is prod using fast-jar is it still a problem with legacy-jar or uber-jar? |
Its not throwing in the static block, all good there. We are running in prod using an uber-jar. |
Can you make a reproducer? It seems like this is all in the database startup code so I am assuming a small project with the same config would have the same issue? |
I doubt that will be possible. If no one else is having any troubles with their 2.x apps my new simple one will likely work as well. I'll keep investigating but not getting far on this. |
Is there something specific in your datasource config that is triggering this code path? It's really weird because I don't really see how Quarkus can affect a JDK class like this, especially given we don't do anything special with ClassLoading in an Uber Jar. |
Nothing special. Just using quarkus.datasource.credentials-provider config so Quarkus uses CredentialsProvider to get DB credentials. Quarkus calls this very early as it needs the DB credentials early. |
So I tried something outside of Quarkus in a standalone trivial Java code. 2 classes Foo.java
Bar.java
I then run this code with Java 11 and here's what I get as the output:
Notice that the first attempt that called the static method
However, the subsequent attempts on
This detail is crucial, because in one of your comment you said:
So it looks like somewhere in your code in this flow you have a catch block which catches the exception (actually I think some part of your code is catching So what you could do is, in the following flow/classes:
Find out where such a loop or try/catch block exists. See what's it's doing and if needs to be fixed. Since you are able to debug this code, I think if you can add a breakpoint in this catch block and inspect the first thrown exception, then it's likely that it will have a |
I would also try adding a breakpoint for |
Thanks for the detailed reply and ideas, I will try to track this down. I do have some initial feedback though. We no NOT have any retries or loops in our code regarding this issue. We make ONE call to Cipher.getInstance(cryptoModePadding) for every ONE call of Quarkus/Agroal to CredentialsProvider#getCredentials(String credentialsProviderName) I believe the loop of 20 I mentioned is in the JDK here: public static final Cipher getInstance(String transformation){ |
That however doesn't explain why the thrown exception is not getting propagated out of the loop and method, the very first instance. I don't see any catch block around that call to
Where did you download and install this from? |
I agree, the errors just are not making sense to me.
I don't recall the site where I got the JDK but here is what is in the
release file:
IMPLEMENTOR="AdoptOpenJDK"
IMPLEMENTOR_VERSION="AdoptOpenJDK-11.0.11+9"
JAVA_VERSION="11.0.11"
JAVA_VERSION_DATE="2021-04-20"
MODULES="java.base java.compiler java.datatransfer java.xml java.prefs
java.desktop java.instrument java.logging java.management
java.security.sasl java.naming java.rmi java.management.rmi java.net.http
java.scripting java.security.jgss java.transaction.xa java.sql
java.sql.rowset java.xml.crypto java.se java.smartcardio jdk.accessibility
jdk.internal.vm.ci jdk.management jdk.unsupported jdk.internal.vm.compiler
jdk.aot jdk.internal.jvmstat jdk.attach jdk.charsets jdk.compiler
jdk.crypto.ec jdk.crypto.cryptoki jdk.crypto.mscapi jdk.dynalink
jdk.internal.ed jdk.editpad jdk.hotspot.agent jdk.httpserver
jdk.internal.le jdk.internal.opt jdk.internal.vm.compiler.management
jdk.jartool jdk.javadoc jdk.jcmd jdk.management.agent jdk.jconsole
jdk.jdeps jdk.jdwp.agent jdk.jdi jdk.jfr jdk.jlink jdk.jshell jdk.jsobject
jdk.jstatd jdk.localedata jdk.management.jfr jdk.naming.dns jdk.naming.ldap
jdk.naming.rmi jdk.net jdk.pack jdk.rmic jdk.scripting.nashorn
jdk.scripting.nashorn.shell jdk.sctp jdk.security.auth jdk.security.jgss
jdk.unsupported.desktop jdk.xml.dom jdk.zipfs"
OS_ARCH="x86_64"
OS_NAME="Windows"
SOURCE=".:git:9a5c368512c6"
BUILD_SOURCE="git:4ad15fd"
FULL_VERSION="11.0.11+9"
SEMANTIC_VERSION="11.0.11+9"
BUILD_INFO="OS: Windows Server 2012 R2 Version: 6.3"
JVM_VARIANT="Hotspot"
JVM_VERSION="11.0.11+9"
IMAGE_TYPE="JDK"
Yesterday I also installed a later JDK 11 to see if it made any difference
but I got the same error, here is its release file contents from openjdk-11+28_windows-x64_bin.zip
IMPLEMENTOR="Oracle Corporation"
IMPLEMENTOR_VERSION="18.9"
JAVA_VERSION="11"
JAVA_VERSION_DATE="2018-09-25"
MODULES="java.base java.compiler java.datatransfer java.xml java.prefs
java.desktop java.instrument java.logging java.management
java.security.sasl java.naming java.rmi java.management.rmi java.net.http
java.scripting java.security.jgss java.transaction.xa java.sql
java.sql.rowset java.xml.crypto java.se java.smartcardio jdk.accessibility
jdk.internal.vm.ci jdk.management jdk.unsupported jdk.internal.vm.compiler
jdk.aot jdk.internal.jvmstat jdk.attach jdk.charsets jdk.compiler
jdk.crypto.ec jdk.crypto.cryptoki jdk.crypto.mscapi jdk.dynalink
jdk.internal.ed jdk.editpad jdk.hotspot.agent jdk.httpserver
jdk.internal.le jdk.internal.opt jdk.internal.vm.compiler.management
jdk.jartool jdk.javadoc jdk.jcmd jdk.management.agent jdk.jconsole
jdk.jdeps jdk.jdwp.agent jdk.jdi jdk.jfr jdk.jlink jdk.jshell jdk.jsobject
jdk.jstatd jdk.localedata jdk.management.jfr jdk.naming.dns jdk.naming.rmi
jdk.net jdk.pack jdk.rmic jdk.scripting.nashorn jdk.scripting.nashorn.shell
jdk.sctp jdk.security.auth jdk.security.jgss jdk.unsupported.desktop
jdk.xml.dom jdk.zipfs"
OS_ARCH="x86_64"
OS_NAME="Windows"
SOURCE=".:76072a077ee1"
…On Wed, Aug 25, 2021 at 9:07 AM Jaikiran ***@***.***> wrote:
I believe the loop of 20 I mentioned is in the JDK here:
public static final Cipher getInstance(String transformation){
...
Iterator t = services.iterator();
Exception failure = null;
while (t.hasNext()) {
Service s = t.next();
if (JceSecurity.canUseProvider(s.getProvider()) == false) {
continue;
}
That however doesn't explain why the thrown exception is not getting
propagated out of the loop and method, the very first instance. I don't see
any catch block around that call to JceSecurity.canUseProvider, unless
I'm not looking at the right JDK version/implementation?
We are using JDK 11.0.11+9
Where did you download and install this from?
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#19265 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAL7BLZU25US6WCSOEUMQBDT6UBM7ANCNFSM5BUVWYZQ>
.
Triage notifications on the go with GitHub Mobile for iOS
<https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675>
or Android
<https://play.google.com/store/apps/details?id=com.github.android&utm_campaign=notification-email>
.
|
If the "easier" path of debugging doesn't solve this, then I think the last resort is the Byteman approach. In that case, please follow these steps:
(you might have to fiddle with the java launch command. Essentially you just need to additionally add the javaagent option as noted above in addition to whatever you are currently using to launch your application) This should generate (hopefully) enough exception stacktrace/output on the console when the JceSecurity class initialization errors out. P.S: Long back, I had wondered whether Quarkus should have a much more seamless integration with Byteman to help with issues like these. I think it's time to experiment a bit and see how to make debugging Quarkus in cases like these easier with Byteman. I'll see if I can try a PoC to make this easier. |
@stuartwdouglas, @mkouba, any chance the dynamic bytecode that we generate[1] in this
might have swallowed the exception/throwable from |
Fyi...I tried 2.1.3.Final in 3 more Quarkus apps, all much smaller then the first one. Two did not have this error but one does so 2 in total have this error and 2 do not. And just as a reminder this is with 2.x only, 1.x is fine. |
Is there any obvious similarities between the ones that don't work?
Stuart
…On Thu, 26 Aug 2021, 2:24 am David Hoffer, ***@***.***> wrote:
Fyi...I tried 2.1.3.Final in 3 more Quarkus apps, all much smaller then
the first one. Two did not have this error but one does so 2 in total have
this error and 2 do not. And just as a reminder this is with 2.x only, 1.x
is fine.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#19265 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AACQG6ZKQQ65X2HC4ZWKVSTT6UKKRANCNFSM5BUVWYZQ>
.
Triage notifications on the go with GitHub Mobile for iOS
<https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675>
or Android
<https://play.google.com/store/apps/details?id=com.github.android&utm_campaign=notification-email>
.
|
I finally have good news to report. The tips provided by @jaikiran were incredibly helpful. I added Byteman just as described and the logs immediately reported: java.util.ServiceConfigurationError: java.net.spi.URLStreamHandlerProvider: Provider org.infinispan.commons.jdkspecific.ClasspathURLStreamHandlerProvider not found So then a quick Google query brought me here: infinispan/infinispan-quarkus#55 It turns out that in the two apps that fail we had a dependency on this component. But it turns out it's OBE as it builds/runs with out the infinispan-quarkus dependency. So some observations/questions/suggestions.
I am good on this issue but Quarkus might want to evaluate the above and see if there is a way to help others when they have strange issues like this one. Many thanks to @jaikiran on this one! -Dave |
The client proxy should not be hiding anything. What was the full stack trace? It should shed some light on what hid the exception. There is an issue for a byteman extension, although it was mostly in reference to native: #2263 |
Thank you for continuing to investigate this.
So I suspect, it's this[1] |
Do you mean you want to see all that Byteman reported? If so I can try to
do that test first thing tomorrow. I did not capture all of it.
…-Dave
On Wed, Aug 25, 2021 at 7:51 PM Jaikiran ***@***.***> wrote:
Thank you for continuing to investigate this.
I added Byteman just as described and the logs immediately reported:
java.util.ServiceConfigurationError:
java.net.spi.URLStreamHandlerProvider: Provider
org.infinispan.commons.jdkspecific.ClasspathURLStreamHandlerProvider not
found
at java.base/java.util.ServiceLoader.fail(ServiceLoader.java:589)
So I suspect, it's this[1] static block in JceSecurity which is
triggering that URLStreamHandler lookup. So like Stuart says, if you can
show us the entire exception stacktrace, that will help us understand where
this exception is getting swallowed and we can provide a fix if relevant.
[1]
https://github.com/openjdk/jdk11u-dev/blob/master/src/java.base/share/classes/javax/crypto/JceSecurity.java.template#L237
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#19265 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAL7BL6INQHPKRKQIONMQF3T6WMYNANCNFSM5BUVWYZQ>
.
Triage notifications on the go with GitHub Mobile for iOS
<https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675>
or Android
<https://play.google.com/store/apps/details?id=com.github.android&utm_campaign=notification-email>
.
|
Yes, please. That will be crucial for us (Quarkus) to solve this properly, if at all this turns out to be something that needs to be solved in Quarkus. |
Here is the full log with Byteman. Please ignore the use of google cache in our part of the code that is new and has nothing to do with this issue, the cache just means we only have to get the user/password once per datasource. org.jboss.byteman.agent.Transformer : possible trigger for rule JceSecurity exception exit in class javax.crypto.JceSecurity And here is the log w/o Byteman. 2021-08-26 08:38:41,374 ERROR [io.qua.run.Application] (main) Failed to start application (with profile prod): java.lang.NoClassDefFoundError: Could not initialize class javax.crypto.JceSecurity Notice that w/o Byteman everything that happens inside of Cipher.getInstance(Cipher.java:540) is lost. |
Thank you very much for that stacktrace. That's very useful. So here's the relevant one from your post:
There are at least 3 or 4 interesting points here:
Looking at the place where that log message is coming from, it's this catch block[2] in [1] https://github.com/agroal/agroal/blob/master/agroal-pool/src/main/java/io/agroal/pool/util/PriorityScheduledExecutor.java#L109 |
I have opened agroal/agroal#39 |
I read up the docs in detail today and as per[2]:
So that API is behaving fine as per what it states in its javadocs. |
I read up the JLS and section 12.4.2[1] states:
So the current behaviour is as per the spec, so there's no issue in this area. I see that Stuart has opened a PR to fix agroal to log these exceptions that fall off the thread execution. So that should sort out the major part of this issue. The only final question is, should we improve the [1] https://docs.oracle.com/javase/specs/jls/se16/html/jls-12.html#jls-12.4.2 |
Is this still an issue? |
Closing for lack of feedback |
Describe the bug
After upgrading from 1.13.7.Final to any of the 2.x versions we get this error at startup.
I retested with 2.1.1.Final and it has the same behavior.
We are using JDK 11.0.11+9. Code and JDK work fine with pre 2.x Quarkus.
This code is just trying to decrypt a password in the io.quarkus.credentials.CredentialsProvider implementation used to connect to the database.
2021-08-05 15:21:21,296 ERROR [io.qua.run.Application] (main) Failed to start application (with profile prod): java.lang.NoClassDefFoundError: Could not initialize class javax.crypto.JceSecurity
at java.base/javax.crypto.Cipher.getInstance(Cipher.java:540)
at com.bs.util.encryption.AESEncryptDecrypt.getInitializedCipher(AESEncryptDecrypt.java:151)
at com.bs.util.encryption.AESEncryptDecrypt.decrypt(AESEncryptDecrypt.java:127)
at com.bs.util.encryption.AESEncryptDecryptProxy.decrypt(AESEncryptDecryptProxy.java:44)
at com.bs.util.BSDataSourceCredentialsProvider.getCredentials(BSDataSourceCredentialsProvider.java:33)
at com.bs.util.BSDataSourceCredentialsProvider_ClientProxy.getCredentials(BSDataSourceCredentialsProvider_ClientProxy.zig:157)
at io.quarkus.agroal.runtime.AgroalVaultCredentialsProviderPassword.asProperties(AgroalVaultCredentialsProviderPassword.java:21)
at io.agroal.api.security.AgroalDefaultSecurityProvider.getSecurityProperties(AgroalDefaultSecurityProvider.java:23)
at io.agroal.pool.ConnectionFactory.securityProperties(ConnectionFactory.java:190)
at io.agroal.pool.ConnectionFactory.securityProperties(ConnectionFactory.java:179)
at io.agroal.pool.ConnectionFactory.jdbcProperties(ConnectionFactory.java:160)
at io.agroal.pool.ConnectionFactory.createConnection(ConnectionFactory.java:204)
at io.agroal.pool.ConnectionPool$CreateConnectionTask.call(ConnectionPool.java:470)
at io.agroal.pool.ConnectionPool$CreateConnectionTask.call(ConnectionPool.java:452)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at io.agroal.pool.util.PriorityScheduledExecutor.beforeExecute(PriorityScheduledExecutor.java:68)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1126)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:829)
Expected behavior
Quarkus should be able to load the JDK class javax.crypto.JceSecurity.
Actual behavior
See stacktrace in description.
How to Reproduce?
No response
Output of
uname -a
orver
No response
Output of
java -version
openjdk 11.0.11 2021-04-20 OpenJDK Runtime Environment AdoptOpenJDK-11.0.11+9 (build 11.0.11+9) OpenJDK 64-Bit Server VM AdoptOpenJDK-11.0.11+9 (build 11.0.11+9, mixed mode)
GraalVM version (if different from Java)
No response
Quarkus version or git rev
2.1.1.Final
Build tool (ie. output of
mvnw --version
orgradlew --version
)No response
Additional information
No response
The text was updated successfully, but these errors were encountered: