Skip to content
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

Generate RSA-256 keys on dev mode #44272

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

mcruzdev
Copy link
Contributor

@mcruzdev mcruzdev commented Nov 2, 2024

Description

Fixes #44179

This PR aims to add on DEV mode, to generate a RSA-256 pair key.

It is great for development and test environments, the user just need to set two 3 config properties:

smallrye.jwt.sign.key.location=privateKey.pem
mp.jwt.verify.publickey.location=publicKey.pem
quarkus.smallrye-jwt.generate-sign-keys=true

Status: In progress

  • Add tests
  • Add documentation
  • Improve javadoc
  • Self review

Copy link

quarkus-bot bot commented Nov 2, 2024

Thanks for your pull request!

Your pull request does not follow our editorial rules. Could you have a look?

  • title should preferably start with an uppercase character (if it makes sense!)

This message is automatically generated by a bot.

@sberyozkin
Copy link
Member

Hey @mcruzdev Thanks for giving it a try, indeed, we'd like to make it easy for quarkus-smalrye-jwt developers to start in devmode...

But what should really be done is that none of those properties should be required in devmode, no any temporary files should be created...

If mp.jwt.verify.publickey is not configured (or any other verification key properties - I can cover this part later), and no smallrye.jwt.sign.key is not configured (or any other signing key properties - I can also cover this part later) then the quarkus-smallrye-jwt devservice build step should generate an RSA key pair, and set those 2 properties to the encoded key values.

The code which will generate tokens using the published private key smallrye.jwt.sign.key has to be written by the user as only the user knows what claims should be added to the token, using a no-arg sign() and we'll also do something interactive in DevUI later as well. but the very first step is to have this key pair accessible via those 2 properties.

@michalvavrik, do you recall which build item can be used to report build time properties ? (smallrye-jwt ones related to keys are currently build time only...)

@michalvavrik
Copy link
Member

michalvavrik commented Nov 3, 2024

@michalvavrik, do you recall which build item can be used to report build time properties ? (smallrye-jwt ones related to keys are currently build time only...)

If this https://github.com/smallrye/smallrye-jwt/blob/74638c415a0096e1916363e51571e6ed4aecf8d2/implementation/jwt-auth/src/main/java/io/smallrye/jwt/config/JWTAuthContextInfoProvider.java#L219 is the only place where this property is used, then I'd expect returning them from DevServicesResultBuildItem should work. However if you are certain they are build-time properties then I think you need to define your own SmallRye Config source, or maybe use customizer as is done here (but make sure nothing happens when it is not a DEV mode) https://github.com/quarkusio/quarkus/blob/main/core/deployment/src/main/java/io/quarkus/deployment/configuration/BuildTimeConfigBuilderCustomizer.java.

@mcruzdev
Copy link
Contributor Author

mcruzdev commented Nov 3, 2024

Hi @sberyozkin, was necessary to get the properties (*.location) from the user, because I do not know how to change configuration values on build time, I think that config is read-only. I will try the customizer here.

@quarkus-bot quarkus-bot bot added the area/core label Nov 3, 2024
@mcruzdev
Copy link
Contributor Author

mcruzdev commented Nov 3, 2024

Thank you, it works! Now I will continue here...

Copy link

github-actions bot commented Nov 3, 2024

🎊 PR Preview 98942f6 has been successfully built and deployed to https://quarkus-pr-main-44272-preview.surge.sh/version/main/guides/

  • Images of blog posts older than 3 months are not available.
  • Newsletters older than 3 months are not available.

@sberyozkin
Copy link
Member

Thanks @mcruzdev, IMHO it will be a nice addition, I've left a few comments, but it all is going well, thanks for the effort, and please take your time to address the comments

@mcruzdev mcruzdev requested a review from sberyozkin November 4, 2024 11:48
@mcruzdev mcruzdev marked this pull request as ready for review November 4, 2024 11:48
@mcruzdev mcruzdev changed the title [DRAFT] Generate RSA-256 keys on dev mode Generate RSA-256 keys on dev mode Nov 4, 2024

This comment has been minimized.

This comment has been minimized.

This comment has been minimized.

This comment has been minimized.


private static String getStringKey(Key key) {
return Base64.getEncoder()
.encodeToString(key.getEncoded());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know that part of the codebase, but is this intended to be a PEM format?
RSA Key needs to use PKCS#1 format.

Copy link
Contributor Author

@mcruzdev mcruzdev Nov 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @cescoffier It is intended to be a PEM format. mp.jwt.verify.publickey uses it, see here.

EDIT: intended to be a base64 encoded key

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, this is NOT PEM format :-) This is just a base64 encoded key.
If you want PEM format you need the header and footer explaining what's the content (RSA KEY, PRIVATE KEY ...)

@cescoffier
Copy link
Member

I agree with @FroMage about generating a proper PEM file (Be aware, this is a trap) in the output directory (target or build) so it can be reused between runs and used for both test and dev.

Now, generating a proper PEM file can be tricky because there are several formats: PKCS#1, PKCS#8, PKCS#7., SEC1 (EC)... Also, I learned that PKCS#8 can be encrypted. In this case, I would just pick one (but the runtime would need to support most of them, if not all)

@sberyozkin
Copy link
Member

sberyozkin commented Nov 22, 2024

Hi @FroMage

But this is for DEV mode and test mode, most people spend time in DEV or test mode than the DEV UI. If they're using cookies (and any web application will use cookies), this will affect them.

Well, our plan is to offer a DevUI support for quarkus-smallrye-jwt users be able to interactively create signed JWTs, and having PEM files generated on the disk and have them staying around after the server is shutdown is unnecessary.
It probably won't even work if we go to the remote DevUI option again...

Also, while quarkus-smallrye-jwt can verify tokens provided as cookie values, most of its cases are about bearer access token verification where a token is generated and submitted - these cases would be supported in dev and test modes.

You say users spent most of their time in devmode, but in devmode one does not cold-stop the server, usually we do it if something goes wrong with the live coding. What is the scenario that you have in mind where a server is cold-stopped when the authenticated user is around ?
These users would get Can't access the server error while the server is down then, which is not a good UX. Having to re-login occasionally (rarely in devmode as cold-stopping the server in devmode should be rare) is the normal operational flow.

This comment has been minimized.

This comment has been minimized.

@mcruzdev
Copy link
Contributor Author

@FroMage, @sberyozkin any update about this one? We have a direction to follow?

@FroMage
Copy link
Member

FroMage commented Dec 19, 2024

Just rebase on the latest quarkus main and this will pass.

This comment has been minimized.

This comment has been minimized.

@mcruzdev
Copy link
Contributor Author

mcruzdev commented Jan 3, 2025

Works @FroMage, TY!

This comment has been minimized.

This comment has been minimized.

This comment has been minimized.

This comment has been minimized.

Copy link
Member

@FroMage FroMage left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, although I'd still prefer this would be stored in a file to survive restarts 🤷

This comment has been minimized.

@sberyozkin
Copy link
Member

I'll try to test this PR soon, thanks @mcruzdev

@mcruzdev
Copy link
Contributor Author

mcruzdev commented Feb 3, 2025

I'll try to test this PR soon, thanks @mcruzdev

Perfect @sberyozkin, I am excited to continue the improvement on devx :)

Copy link

quarkus-bot bot commented Feb 17, 2025

Status for workflow Quarkus Documentation CI

This is the status report for running Quarkus Documentation CI on commit 51d2494.

✅ The latest workflow run for the pull request has completed successfully.

It should be safe to merge provided you have a look at the other checks in the summary.

Warning

There are other workflow runs running, you probably need to wait for their status before merging.

Copy link

quarkus-bot bot commented Feb 17, 2025

Status for workflow Quarkus CI

This is the status report for running Quarkus CI on commit 51d2494.

✅ The latest workflow run for the pull request has completed successfully.

It should be safe to merge provided you have a look at the other checks in the summary.

You can consult the Develocity build scans.


Flaky tests - Develocity

⚙️ JVM Integration Tests - JDK 17

📦 integration-tests/vertx-http

io.quarkus.it.vertx.RandomTestPortTestCase.testLegacyProperties - History

  • expected: <Optional[36777]> but was: <Optional.empty> - org.opentest4j.AssertionFailedError
org.opentest4j.AssertionFailedError: expected: <Optional[36777]> but was: <Optional.empty>
	at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:151)
	at org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132)
	at org.junit.jupiter.api.AssertEquals.failNotEqual(AssertEquals.java:197)
	at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:182)
	at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:177)
	at org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:1145)
	at io.quarkus.it.vertx.RandomTestPortTestCase.testLegacyProperty(RandomTestPortTestCase.java:75)

⚙️ JVM Integration Tests - JDK 17 Windows

📦 integration-tests/grpc-hibernate

com.example.grpc.hibernate.VertxBlockingRawTest.shouldAdd - History

  • Condition with Lambda expression in com.example.grpc.hibernate.BlockingRawTestBase was not fulfilled within 30 seconds. - org.awaitility.core.ConditionTimeoutException
org.awaitility.core.ConditionTimeoutException: Condition with Lambda expression in com.example.grpc.hibernate.BlockingRawTestBase was not fulfilled within 30 seconds.
	at org.awaitility.core.ConditionAwaiter.await(ConditionAwaiter.java:167)
	at org.awaitility.core.CallableCondition.await(CallableCondition.java:78)
	at org.awaitility.core.CallableCondition.await(CallableCondition.java:26)
	at org.awaitility.core.ConditionFactory.until(ConditionFactory.java:1006)
	at org.awaitility.core.ConditionFactory.until(ConditionFactory.java:975)
	at com.example.grpc.hibernate.BlockingRawTestBase.shouldAdd(BlockingRawTestBase.java:59)
	at java.base/java.lang.reflect.Method.invoke(Method.java:569)

📦 integration-tests/vertx-http

io.quarkus.it.vertx.RandomTestPortTestCase.testLegacyProperties - History

  • expected: <Optional[59351]> but was: <Optional.empty> - org.opentest4j.AssertionFailedError
org.opentest4j.AssertionFailedError: expected: <Optional[59351]> but was: <Optional.empty>
	at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:151)
	at org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132)
	at org.junit.jupiter.api.AssertEquals.failNotEqual(AssertEquals.java:197)
	at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:182)
	at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:177)
	at org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:1145)
	at io.quarkus.it.vertx.RandomTestPortTestCase.testLegacyProperty(RandomTestPortTestCase.java:75)

⚙️ JVM Integration Tests - JDK 21

📦 integration-tests/vertx-http

io.quarkus.it.vertx.RandomTestPortTestCase.testLegacyProperties - History

  • expected: <Optional[46499]> but was: <Optional.empty> - org.opentest4j.AssertionFailedError
org.opentest4j.AssertionFailedError: expected: <Optional[46499]> but was: <Optional.empty>
	at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:151)
	at org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132)
	at org.junit.jupiter.api.AssertEquals.failNotEqual(AssertEquals.java:197)
	at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:182)
	at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:177)
	at org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:1145)
	at io.quarkus.it.vertx.RandomTestPortTestCase.testLegacyProperty(RandomTestPortTestCase.java:75)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Be able to have private/public key when using smallrye-jwt extension on dev mode
6 participants