-
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 proper identity propagation to WebSockets #20157
Conversation
Hi Stuart @stuartwdouglas It looks very good, thanks. How often is |
It's just a way of propagating a token to the client, basically the world's most roundabout addHeader call. |
@stuartwdouglas it sounds good :-) but what I don't get is how this token is verified, since |
The websocket handshake is HTTP, so the token is verified as part of the handshake. |
@stuartwdouglas Yes that bit I understand, thanks, but what happens when the web socket channel is on and the messages are flowing through it into Quarkus... The token is bound to it I believe, which is why |
Why would it need to be verified again? In case the user was disabled while the websocket connection is open? Refresh may be an issue if you want to propagate the token other servers. |
For the bearer access tokens,
Good point as well - though for the bearer tokens it is not possible since we don't have a refresh token - but for the one returned alongside the code flow id token it would be possible - but this PR does not cover picking up that access token yet - it would be fine to do it later - |
That is not how websockets work though, they are only authenticated on open, there is no per message authentication. |
Hi Stuart @stuartwdouglas
True, which is why everyone does some workarounds to have a per message authentication working :-) (for example, how would it work for Basic auth.. etc), so it is great a bearer token binding will work in Quarkus out of the box. One thing which I believe we can't really allow is to have I'd like to propose that an expiry check is done somewhere in the WSS code for the bearer token. For ex you can copy a simple code from Re the signature check, since it is IMHO these 2 simple tools would be enough. |
Per message authentication is not a thing, this is not like HTTP where you can have a different users for different messages. Once the session is established there is a 1:1 relationship of identity->connection. If you wanted to do per message authentication then you would need to add your own framing/headers mechanism, which is not something we can help with and just generally a bad idea. This will also work fine for basic auth, the identity is created on connection establishment. Regarding expiry this is only really an issue if you actually need to propagate the token, in which case we could have a setting to simply close the connection on token expiration (or ideally a bit before token expiration). |
I understand trying to address all these technical problems can probably cause side-effects etc. But presenting a kind of valid Security Identity to the endpoint which is in fact no longer valid for the last hour is a major problem of its own. There is a code in this PR preparing a WebSocket principal - why can't the expiry be checked there and what is fundamentally wrong with it ?
What do you mean by thanks |
Hi Stuart @stuartwdouglas I have another argument in favor of the expiry check (after a good coffee break :-) ):
Here you go, another try to convince you :-) |
If the application cares about expiry then we could add an option to close the connection on expiry, as this is the only course of action that makes sense. That said I don't think this should be the default, as most people will not care. A websocket is different to HTTP, once the connection is established so is the identity, it is impossible to change the identity after the establishment. The closed HTTP based analogy would be if you had an administrative task that took one minute to run, but your token expired in 30s. Should the server about the processing 30s into the request when the token expires?
It's not an endpoint, its an established authenticated session. If there is a requirement for a valid token (e.g. you are going to call another service using the token), then you will need to close the session and reconnect to the endpoint every time the token expires.
That is not how websockets work, you can't 'just transition to WSS' and do the same things you would do over HTTP. |
Let me start in the reverse order :-)
This is not what I implied, while I don't know all the mechanics I have a good enough idea of how WSS works :-) . My problem is about implicitly extending a lifetime of the time scoped credential without any control over it.
During this session a user code will get access to a security identity which may have been already invalid, the longer the session lasts the longer it will be invalid for. I believe RBAC decisions will be made based on this security identity. It should work the same from Quarkus Security's point of view - access to the resource should fail if the token has expired, be it with HTTP or WSS, esp send (though it is probably simpler to apply it to the in an out).
Token propagation from within a WSS session is a different and likely very advanced use case. We can support it with OidcClient in the future with auto-refreshing the token before it expires (would only be possible for a token acquired originally via the code flow as a refresh token will also be available - which is not the case with the bearer token).
+1, yes please :-), all I'm asking for is to let the users control what happens when the token has expired.
But someone has to be paranoid at the Quarkus end, and I don't mind to be the one, most people won't but by having a simple tool like an option you've proposed would let us support anyone who would be concerned to control the session lifetime and respond to possibly any, even if academic, vulnerability report. Non default as you suggest is fine for a start for sure.
I understand, the problem is about making a possibly expired identity available. In theory at least, the user code can do some other side-effects with it as well without propagating the token but making some decisions based on the user name, its roles, etc. Also if we go totally paranoid, then we can assume the WSS session can be hijacked and the token modified - hence another earlier proposal to block the identity propagation via a property (instead of the signature check) - but I'm fine if we won't add it right now, the expiry check will most likely do.
Good example, but I think the token is about verifying the token bearer can access the resource for whatever reasons (and start an admin task in the background if needed) - there is no requirement for the token to last for as long as the task itself runs. In general we can not control the misuse of the bearer token - taking your example, the user configures the background task with this token and this tasks keeps using this token long after it expired - but it is not something Quarkus can do anything about - as opposed to this case where it is what Quarkus controls. As I said the concern is about a possibly expired identity being visible to the endpoint code with the possible side-effects, so making it possible to control it would be great. Thanks (for your patience :-) ) |
@gsmet @geoand @cescoffier this will require a release of quarkus-http and AFAIK I don't have permission to release. |
Interesting... I'll give it a shot and let you know. |
I just released |
Should be good to go now. |
QuarkusHttpUser user = (QuarkusHttpUser) routingContext.user(); | ||
if (user != null) { | ||
//close the connection when the identity expires | ||
Long expire = user.getSecurityIdentity().getAttribute("quarkus.identity.expire-time"); |
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.
@stuartwdouglas thanks :-)
Given that |
Fixes #16602
Draft for now, as it needs quarkusio/quarkus-http#85 and a release of quarkus-http.