-
Notifications
You must be signed in to change notification settings - Fork 48
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
Fix IllegalArgumentException when using EdDSA signature algorithm #800
Fix IllegalArgumentException when using EdDSA signature algorithm #800
Conversation
It is also possible to call Alternatively, |
@0rzech Thanks for the PR, that should have been fixed with 4.5.2, can you retry please ? |
If you still see the problem, can you type the code here which leads to the EdDSA algorithm name conversion issue ? |
It still happens with 4.5.2 for me. All you need to do is set
in
in your code. Alternatively, you can remove |
@0rzech But the correct name is |
|
@0rzech Ok, thanks, let me have a look a little bit later just to refresh in my mind the whole logic of delaing with algo names, in general, I think I'd prefer to tune it inside |
Sure! I can adjust PR to your decision. Unless you prefer to fix it yourself, of course. 😉 IMHO, it would be even better not to map back and forth between |
I forgot to add, that the public interface requiring one to use |
@sberyozkin It looks like when I don't set On the other hand, I have to set IMHO, in both these cases exception suggestions are confusing to Quarkus users, because they mention internal signature algorithm representation and the rest of stack traces' lines do not mention values expected from users at all. |
Thanks for investigating @0rzech, I'll get to adding tests for different cases, it will take a bit of time, but we'll get it cleaned up |
@0rzech So, lets focus on generating tokens with EdDSA first, I think we have these 2 cases working OK
These 2 cases do not work:
Can you please try to add 2 tests for these failing cases ? I'd also prefer if we can manage the correct conversion for EdDSA inside smallrye-jwt/implementation/jwt-build/src/main/java/io/smallrye/jwt/build/impl/JwtSignatureImpl.java Line 203 in 7807b3f
.fromAlgorithm() .
Please take your time, I'll be on PTO and realistically I'll have time to review and merge this PR from 11th June onwards |
https://github.com/smallrye/smallrye-jwt/blob/main/implementation/common/src/main/java/io/smallrye/jwt/algorithm/SignatureAlgorithm.java#L34 can handle it nicely. Please also add extra log/error messages if you prefer |
This fixes `java.lang.IllegalArgumentException: No enum constant io.smallrye.jwt.algorithm.SignatureAlgorithm.EdDSA` when `EDDSA` is set through `smallrye.jwt.new-token.signature-algorithm` property, or when it is set with `JwtClaimsBuilderImpl`. Currently, `JwtSignatureImpl.getConfiguredSignatureAlgorithm()` returns algorithm name as a String from `SignatureAlgorithm.algorithmName` field, in case of it being loaded from a configuration file. If the algorithm was set through `JwtClaimsBuilderImpl`, the value is returned as-is from the header, which means `EdDSA`, because this is how `JwtClaimsBuilderImpl` puts the value there. This name is then used to get appropriate `SignatureAlgorithm` enum variant in `JwtSignatureImpl.getSigningKeyFromKeyContent(String)`, but without using `toUpperCase()` on the name, causing exception when `EdDSA` is used. The fix adds `toUpperCase()` call on algorithm name before passing it to `SignatureAlgorithm.valueOf(String)`.
@@ -57,6 +57,10 @@ | |||
<groupId>junit</groupId> | |||
<artifactId>junit</artifactId> | |||
</dependency> | |||
<dependency> |
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.
We don't need another dependency IMHO
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.
If we want to be able to write property-based tests, then we do need it. Given it's just a test dependency, it would be shame to resign from this. But it's your call.
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.
@0rzech I see, I missed you meant to use it for tests only. These tests look fine, but for some reasons this dependency requires a dedicated exclusion in .gitignore (what exactly is generated there ?). I appreciate you like the style offered but me being quite conservative, I'd say we can easily enough, even if it will be more verbose, to write similar tests without it.
Let me ask Mike. @MikeEdgar, do you think we should bring it or just use existing test dependencies ?
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.
.jqwik-database
is a file to store data of previous runs. Given how property-based testing works with shrinking etc., I don't think we should try to emulate it ourselves.
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.
At the same time, we don't really need to introduce it IMHO if it keeps some local state after runs
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 helpful if one wants to re-run failing properties, but I can disable it.
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'm not entirely seeing the benefit of jqwik versus just using @ParameterizedTest
with one of the arguments being some predetermined invalid value. I'm not saying there is no value for something like jqwik, rather it may not be worth it to have a few tests that look/behave differently from the rest of the suite for what otherwise appears to be a minor fix/change.
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.
The whole point of property-based testing is not to rely on one or few specific input examples, but to have tests that cover large space of inputs and help with pinpointing specific errors. @ParameterizedTest
was not made for this.
IMHO, it's worth investing even more into property-based testing where appropriate, especially in security-related project. For instance, property-based tests could be used to randomize claim headers in JWTs, instead of just making sure that headers work fine for https://issuer.com
issuer and customHeader
with custom-header-value
, because this is what current tests actually prove.
The reason I was hit with the bug was that the tests did not cover the code path my project triggered, that's why I've added tests covering all other signature algorithms. To be fair, though, because all possible algorithms is a relatively small finite input space, @ParameterizedTest
could do it. It's opposite for invalid inputs in this particular case.
If you are worried about jqwik
being some random library, then here's Oracle's Java Magazine article about it from almost 5 years ago. Jqwik has also plugins for Spring Boot and Micronaut, and even someone wanted to add jqwik extension to Quarkus, though - unfortunately - to no avail it seems (here and here), and here's Apache Kafka using @ParameterizedTest
, @Property
and normal @Test
in a single test class no problem.
Having said all that, I fully respect it's your project, not mine. I just hope that at least most arguments are taken into consideration, that's it.
May I ask to help me with understanding why it is such an issue with adding this library, though? I genuinely don't get it, given it's not code that will run in production anyway and the jqwik project seems to have been started over 8 years ago. I may lack some context, though. It's been years since I was programming Java for a living and I'm completely new to Quarkus.
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 think for me it's less about a new test dependency and more about having a small subset of the tests using a different paradigm. Based on what I've seen/read, I'm not really opposed to something like property-based testing per se, but rather it might be confusing to do things multiple ways within a single project.
Another possible "gotcha" is IDE support for jqwik. It might be fine, but just guessing it might trip up Eclipse's JUnit runner (for example).
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.
Thanks for your reply!
You can't use property-based testing only. Not everything makes sense that way, because not every test input is large.
The same way one wouldn't want to do everything with builder pattern, because most constructors have short list of parameters. And the opposite - one wouldn't want to resign from builder pattern completely just to not confuse developers with doing things multiple ways in a single project. It's a matter of familiarity.
I don't know how Eclipse will react, but jqwik is an alternative engine for Junit 5 platform, so there shouldn't be problems with running tests and reporting. Perhaps one would have to make Eclipse aware of jqwik's test annotations, so that the code won't be marked as unused. I don't know, I tend not to write code to make IDE's happy, but to adjust IDEs to the code. ;) Nevertheless, IntelliJ was able to run jqwik tests pretty fine.
} | ||
} | ||
|
||
private static String getValidNames() { |
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.
We only need to make sure that if someone typed rs256
or RS256
, it works, so this is why to upper case conversion was there, and do a single specific if
for EdDSA
, this kind of check does not need a new dependency IMHO
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.
Jqwik is used here as well just not to mix it with Junit Parametrized
.
The true reason for jqwik is testing the method's property of failing for any other string than the valid ones here, and most likely in other tests I have yet to write.
As this is still WIP, I haven't added checking mixed-case names yet.
@0rzech It certainly looks like a high quality PR, thanks a million for it. But, please don't get me wrong, this dependency makes me a bit nervous, possibly due to my ignorance, but having to add these exclusions here and there looks like an extra hassle that can be avoided. And PR goes beyond what the issue is about. In general I'd like to avoid somewhat mixed updates to avoid even slightest side-effects with the library now used not only in Quarkus but WildFly etc. Let me offer you a compromise. In this PR lets handle only a case of Once we merge and tag this fix, lets then do another PR to comprehensively test all the name conversions for all types of algorithms, and there please check with @MikeEdgar if we really want to add this one extra test dependency. Hope this proposal is not too bad, thanks for understanding. Thanks |
@sberyozkin The code has already been allowing any-cased letters when signature algorithm is set through properties file. Letters case is already being ignored on that code path and this is already a part of library's public interface. Only when it is set through header builder method, will it fail for any other letter cases than those matching enum variants, and this is what this PR changes - to match behaviour when reading from file. The exception is thrown due to how So, IMHO, adding a special case just for Nevertheless, I have created #801 with just 3 tests. |
Closing in favor of #801 |
This fixes
java.lang.IllegalArgumentException: No enum constant io.smallrye.jwt.algorithm.SignatureAlgorithm.EdDSA
whenEDDSA
is set throughsmallrye.jwt.new-token.signature-algorithm
property, or when it is set withJwtClaimsBuilderImpl
.Currently,
JwtSignatureImpl.getConfiguredSignatureAlgorithm()
returnsalgorithm name as a String from
SignatureAlgorithm.algorithmName
field,in case of it being loaded from a configuration file.
If the algorithm was set through
JwtClaimsBuilderImpl
, the value is returnedas-is from the header, which means
EdDSA
, because this is howJwtClaimsBuilderImpl
puts the value there.This name is then used to get appropriate
SignatureAlgorithm
enum variantin
JwtSignatureImpl.getSigningKeyFromKeyContent(String)
, but withoutusing
toUpperCase()
on the name, causing exception whenEdDSA
is used.The fix adds
toUpperCase()
call on algorithm name before passing itto
SignatureAlgorithm.valueOf(String)
.