-
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
Add support for Vert.x Web sessions #36310
base: main
Are you sure you want to change the base?
Conversation
@Ladicek Is it related to https://vertx.io/docs/vertx-web/java/#_handling_sessions ? @michalvavrik completed the PR providing support for OIDC session data (tokens) stored in DB - the concept is the same. OK, the local store would be of no use but https://vertx.io/docs/vertx-web/java/#_clustered_session_store and https://vertx.io/docs/vertx-web/java/#_infinispan_web_session_store may be of interest, @michalvavrik, lets discuss it a bit later - since it is part of Vert.x we won't even have to do another extension but may be can activate it with properties (sorry Ladislav if it is not related at all to your PR) |
Hi @sberyozkin, I've been meaning to reply to your email about stateful OIDC token management after I get this PR up, but you beat me to it :-) For one, sessions are just fine, and two, I also thought you could just use sessions. We can discuss in that thread. But yes, this is indeed about adding https://vertx.io/docs/vertx-web/java/#_handling_sessions to Quarkus. I aim to support all the "reasonable" session stores that Vert.x supports -- in-memory (local), clustered, Redis, Infinispan. I don't want to support cookieless sessions, and I don't want to support the cookie session store. It seems to work rather nicely, but I've only done some basic manual tests so far. Also, I'd love to know your (@sberyozkin @michalvavrik) opinion on the default value of the |
I don't want to pollute your fantastic PR with OIDC token state stuff, but I'm all in. Let's discuss it in Quarkus DEV group when you find time. I'll wait. Using sessions, especially with Redis / Infinispan makes total sense. Thanks!
I thought when samesite cookie is not present, browsers mostly treat is as
TBH I don't know what is reasonable default. FYI OIDC extension set |
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.
Looks great! I made a few comments. Nothing critical.
...nsions/infinispan-client/sessions/runtime/src/main/resources/META-INF/quarkus-extension.yaml
Outdated
Show resolved
Hide resolved
.../sessions/runtime/src/main/java/io/quarkus/redis/sessions/runtime/RedisSessionsRecorder.java
Outdated
Show resolved
Hide resolved
...vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/SessionsInfinispanConfig.java
Outdated
Show resolved
Hide resolved
...nsions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/VertxHttpRecorder.java
Outdated
Show resolved
Hide resolved
.setCookieSameSite(sessions.cookieSameSite.orElse(null)) | ||
.setCookieMaxAge(sessions.cookieMaxAge.map(Duration::toMillis).orElse(-1L)); | ||
// TODO verify if this is the correct router to which the session handler should be installed | ||
httpRouteRouter.route(path).handler(sessionHandler); |
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 would say yes. That's the main "public" router. The question, however, is the order of the route.
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.
Yes, good point. I need to explore more around this, that's why I added these TODOs.
...ions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/CurrentVertxRequest.java
Outdated
Show resolved
Hide resolved
@@ -186,6 +191,17 @@ public KubernetesPortBuildItem kubernetesForManagement( | |||
managementInterfaceBuildTimeConfig.enabled); | |||
} | |||
|
|||
@BuildStep | |||
public void sessionStoreRequest(HttpBuildTimeConfig config, BuildProducer<SessionStoreRequestBuildItem> request) { | |||
if (config.sessions.mode == SessionsBuildTimeConfig.SessionsMode.REDIS) { |
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 wonder if we should check the available capabilities here; i.e. consume the io.quarkus.deployment.Capabilities
and then capabilites.isPresent(Capability.REDIS_CLIENT)
...
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 originally had that, but the request/response protocol here (which I don't really like, but I don't have a better way at the moment) subsumes that. If the Redis extension isn't present, it won't reply, and we'll get an error.
@Ladicek sorry, haven't had time to review yet, but I would like to ask about your first question (regarding brining in the deps). Have you had that answered yet? |
@Ladicek Hey, given that your PR is relevant to what OIDC code flow does, I'll briefly reply to some comments
Default OIDC session management with encrypted cookies is simplest and most effective and it is recommended, but as I mentioned, what Michal did with providing an alternative option for users to get the session state saved in DB is conceptually exactly identical to what Vert.x Web Sessions offer - the actionable state is saved on the server, the cookie keeps some link to it only.
For OIDC, As far as the Can you please look at https://github.com/quarkusio/quarkus/blob/main/extensions/oidc-db-token-state-manager/runtime/src/main/java/io/quarkus/oidc/db/token/state/manager/runtime/OidcDbTokenStateManager.java ? For us in OIDC be able to select one of these Vert.x Web Session options, we'd need to sync OIDC Specifically, OIDC needs to Thanks |
I'd love to hear anything you have! |
A while back @aloubyansky introduced conditional extension dependencies. |
Yeah, so I looked into conditional dependencies and found that I can't really use them, or at least not easily. Or I don't understand conditional dependencies properly. The present situation is (described using Redis, but it's the same for Infinispan): To be able to store sessions to Redis, one needs to depend on If I wanted to use conditional dependencies, the Maybe I could use this to avoid the dependency circularity? I didn't find any actual usage of that, so I'm not sure how that's supposed to work. I'll try, I guess... |
Is there any way to move stuff into "common" type dependencies and then wire stuff up?
Okay, I indeed have not had to use that. |
Why not? This is really the easiest to use for our users, because it requires no server dependency (unlike redis/etc) and allows for backend scaling unlike in-memory sessions. |
I think you should be able to do that. Checking for a condition of Maven optional dependencies is a convenience, since, I was thinking at the time, typically they would be optional dependencies anyway. |
Because:
|
I've played video games with 2.5K ;) |
I'm thinking maybe if the qualifier defined by
I can imagine even a simple cookie-based flash scope hitting the 2.5K boundary relatively easily if you use it to store a form with modest number of fields and validation messages. But then, I don't really mind, adding a cookie-based session store would be easy. The only actual problem I can see is that the existing implementation in Vert.x Web does no size validation, and I'm not even sure what we could possibly do when we detect the limit was reached 🤷 |
I can see JWT cookies hitting that limit too. Can't we use more than one cookie if that happens? |
I don't know to be honest. I do know that the Vert.x Web cookie-based session store doesn't do that out of the box :-) |
Let's say we have "entity.name must have at least one character and at most 20 characters" as a validation constraint message (average size, I'd say), that's 71 chars. Most browsers have 4096 bytes for cookies. I'm not entirely sure as to the cookie value encoding, but Mozilla docs say US-ASCII, which is a pity, but 1 byte per char, so 71 bytes per message. So, in US-ASCII, we have store 57 error messages. That's a lot of elements for a form. I'm not sure why we have to base64 the value. Or encrypt it. I've never had the need to hide session data from the user. Sign it, sure, but hide or base64 (except for text encoding, yeah), not sure. If there's a real use-case for encrypting session data, perhaps we have to wrap the Vert.x session API to make room for two cookies: one for non-encrypted text, one for encrypted/encoded? |
The cookie-based session store takes all the entries in the session, adds some metadata, serializes all that into a buffer, and encodes its content with Base64. That, and the Base64-encoded signature, is what gets into the cookie. This is a generic implementation (though the set of possible types that you can put into the session is still fairly limited), a specialized one could be made more efficient I guess. |
Well, I think that the easiest and safest default for most users is the in-memory session store. And that's what you get with no additional dependency so 🤷. Also for cookie store the sessions survive server restart/crashes which is not always what a user expects. |
5b55897
to
05afa42
Compare
🎊 PR Preview 72e99a3 has been successfully built and deployed to https://quarkus-pr-main-36310-preview.surge.sh/version/main/guides/ |
af66d16
to
ebd03bd
Compare
I believe this is ready now. |
ebd03bd
to
79a9f4c
Compare
This comment has been minimized.
This comment has been minimized.
The failure in Lines 82 to 83 in 7a3fd94
Per the * @param handler the {@link io.vertx.core.Handler} to notify with the {@link io.vertx.core.AsyncResult}.
* The handler will get notified with the resolved address if a record was found. If non was found it
* will get notifed with {@code null}. If an error accours it will get failed. which the code linked above ignores. I believe we can treat the
I'll submit another PR with a fix. |
Submitted #36682 |
@Ladicek from Infinispan side everything looks good! if tests pass correctly, we should not experience any breaking change. thanks!! |
79a9f4c
to
b7d22d6
Compare
This comment has been minimized.
This comment has been minimized.
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.
only minor comments.
.../java/io/quarkus/infinispan/client/deployment/devservices/InfinispanDevServiceProcessor.java
Outdated
Show resolved
Hide resolved
b7d22d6
to
6a392f5
Compare
This comment has been minimized.
This comment has been minimized.
Some constants from the Infinispan Client runtime module are moved to the runtime SPI module, so that they can be used from other modules that cannot directly depend on the Infinispan Client extension. Two build items, `InfinispanClientBuildItem` and `InfinispanClientNameBuildItem`, are moved from the Infinispan Client deployment module to the deployment SPI module. This is technically a breaking change, because they are also moved to a different package, but these build items don't seem to be used anywhere outside of Quarkus, so it should be safe.
Some constants from the Redis Client runtime module are moved to the runtime SPI module, so that they can be used from other modules that cannot directly depend on the Redis Client extension. One build item, `RequestedRedisClientBuildItem`, is moved from the Redis Client deployment module to the deployment SPI module. This is technically a breaking change, because it is also moved to a different package, but this build item doesn't seem to be used anywhere outside of Quarkus, so it should be safe. Further, one new build item, `RedisClientBuildItem`, is added. It provides runtime access to the Redis clients (in the Mutiny variant) without having to perform a CDI lookup.
6a392f5
to
e6e973a
Compare
Tried to improve the documentation a little around the possibility of concurrent session access. |
Failing Jobs - Building e6e973a
Full information is available in the Build summary check run. Failures⚙️ Devtools Tests - JDK 11 #- Failing: integration-tests/devtools
📦 integration-tests/devtools✖
✖
✖
✖
✖
✖
✖
⚙️ Devtools Tests - JDK 11 Windows #- Failing: integration-tests/devtools
📦 integration-tests/devtools✖
✖
✖
✖
✖
✖
✖
⚙️ Devtools Tests - JDK 17 #- Failing: integration-tests/devtools
📦 integration-tests/devtools✖
✖
✖
✖
✖
✖
✖
⚙️ JVM Tests - JDK 11 #- Failing: integration-tests/hibernate-orm-compatibility-5.6/mariadb integration-tests/hibernate-orm-compatibility-5.6/postgresql
📦 integration-tests/hibernate-orm-compatibility-5.6/mariadb✖
📦 integration-tests/hibernate-orm-compatibility-5.6/postgresql✖
⚙️ JVM Tests - JDK 17 #- Failing: integration-tests/hibernate-orm-compatibility-5.6/mariadb integration-tests/hibernate-orm-compatibility-5.6/postgresql integration-tests/kubernetes-client-devservices
📦 integration-tests/hibernate-orm-compatibility-5.6/mariadb✖
📦 integration-tests/hibernate-orm-compatibility-5.6/postgresql✖
📦 integration-tests/kubernetes-client-devservices✖
⚙️ JVM Tests - JDK 21 #- Failing: integration-tests/hibernate-orm-compatibility-5.6/mariadb integration-tests/hibernate-orm-compatibility-5.6/postgresql
📦 integration-tests/hibernate-orm-compatibility-5.6/mariadb✖
📦 integration-tests/hibernate-orm-compatibility-5.6/postgresql✖
|
Moved back to draft after conversation with @stuartwdouglas who convinced me that Vert.x Web approach to concurrent session access (especially with external session stores) is not adequate enough for general purpose usage. |
Hey @Ladicek, are you planning to restart working on this amazing PR :-) ? |
One day, maybe :-) Sorry, busy with CDI these days. |
The individual commits are:
The last commit being the biggest obviously. Tagging @karesti for review of the 1st and 2nd commit, and @cescoffier for review of the 3rd commit.