问题
I'm trying to implement session reinitialization for Vaadin for security reasons (Session_fixation) but failing to do so.
I am using Vaadin 8.9.4 with @Push and WildFly 8.1.0.Final. Also using the Vaadin heartbeat and @PreserveOnRefresh annotation.
I have tried using the VaadinService.reinitializeSession
but with no luck. App just hangs, refresh will throw me back to login screen (with new JSESSSIONID though).
Here's an example what I have tried: VaadinService.reinitializeSession(VaadinService.getCurrentRequest());
from which I'm getting the following error:
16:23:35,520 WARNING [com.vaadin.server.communication.PushHandler] (default task-41) Error while ending request: java.lang.IllegalStateException: UT000010: Session not found mGoJr6uWAgVH3yCuW5zq_-sg
at io.undertow.server.session.InMemorySessionManager$SessionImpl.getMaxInactiveInterval(InMemorySessionManager.java:310) [undertow-core-1.0.15.Final.jar:1.0.15.Final]
at io.undertow.servlet.spec.HttpSessionImpl.getMaxInactiveInterval(HttpSessionImpl.java:108) [undertow-servlet-1.0.15.Final.jar:1.0.15.Final]
at com.vaadin.server.WrappedHttpSession.getMaxInactiveInterval(WrappedHttpSession.java:49) [vaadin-server-8.9.4.jar:8.9.4]
at com.vaadin.server.VaadinService.getUidlRequestTimeout(VaadinService.java:1344) [vaadin-server-8.9.4.jar:8.9.4]
at com.vaadin.server.VaadinService.isSessionActive(VaadinService.java:1406) [vaadin-server-8.9.4.jar:8.9.4]
at com.vaadin.server.VaadinService.cleanupSession(VaadinService.java:1236) [vaadin-server-8.9.4.jar:8.9.4]
at com.vaadin.server.VaadinService.requestEnd(VaadinService.java:1451) [vaadin-server-8.9.4.jar:8.9.4]
at com.vaadin.server.communication.PushHandler.callWithUi(PushHandler.java:285) [vaadin-server-8.9.4.jar:8.9.4]
at com.vaadin.server.communication.PushHandler.onMessage(PushHandler.java:534) [vaadin-server-8.9.4.jar:8.9.4]
at com.vaadin.server.communication.PushAtmosphereHandler.onMessage(PushAtmosphereHandler.java:87) [vaadin-server-8.9.4.jar:8.9.4]
at com.vaadin.server.communication.PushAtmosphereHandler.onRequest(PushAtmosphereHandler.java:77) [vaadin-server-8.9.4.jar:8.9.4]
at org.atmosphere.cpr.AsynchronousProcessor.action(AsynchronousProcessor.java:225) [atmosphere-runtime-2.4.30.vaadin1.jar:2.4.30.vaadin1]
at org.atmosphere.cpr.AsynchronousProcessor.suspended(AsynchronousProcessor.java:114) [atmosphere-runtime-2.4.30.vaadin1.jar:2.4.30.vaadin1]
at org.atmosphere.container.Servlet30CometSupport.service(Servlet30CometSupport.java:67) [atmosphere-runtime-2.4.30.vaadin1.jar:2.4.30.vaadin1]
at org.atmosphere.cpr.AtmosphereFramework.doCometSupport(AtmosphereFramework.java:2297) [atmosphere-runtime-2.4.30.vaadin1.jar:2.4.30.vaadin1]
at org.atmosphere.websocket.DefaultWebSocketProcessor.dispatch(DefaultWebSocketProcessor.java:594) [atmosphere-runtime-2.4.30.vaadin1.jar:2.4.30.vaadin1]
at org.atmosphere.websocket.DefaultWebSocketProcessor$3.run(DefaultWebSocketProcessor.java:345) [atmosphere-runtime-2.4.30.vaadin1.jar:2.4.30.vaadin1]
at org.atmosphere.util.VoidExecutorService.execute(VoidExecutorService.java:101) [atmosphere-runtime-2.4.30.vaadin1.jar:2.4.30.vaadin1]
at org.atmosphere.websocket.DefaultWebSocketProcessor.dispatch(DefaultWebSocketProcessor.java:340) [atmosphere-runtime-2.4.30.vaadin1.jar:2.4.30.vaadin1]
at org.atmosphere.websocket.DefaultWebSocketProcessor.invokeWebSocketProtocol(DefaultWebSocketProcessor.java:448) [atmosphere-runtime-2.4.30.vaadin1.jar:2.4.30.vaadin1]
at org.atmosphere.container.JSR356Endpoint$3.onMessage(JSR356Endpoint.java:272) [atmosphere-runtime-2.4.30.vaadin1.jar:2.4.30.vaadin1]
at org.atmosphere.container.JSR356Endpoint$3.onMessage(JSR356Endpoint.java:269) [atmosphere-runtime-2.4.30.vaadin1.jar:2.4.30.vaadin1]
at io.undertow.websockets.jsr.FrameHandler$7.run(FrameHandler.java:257) [undertow-websockets-jsr-1.0.15.Final.jar:1.0.15.Final]
at io.undertow.websockets.jsr.ServerWebSocketContainer$1.run(ServerWebSocketContainer.java:303) [undertow-websockets-jsr-1.0.15.Final.jar:1.0.15.Final]
at io.undertow.websockets.jsr.OrderedExecutor$ExecutorTask.run(OrderedExecutor.java:49) [undertow-websockets-jsr-1.0.15.Final.jar:1.0.15.Final]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [rt.jar:1.8.0_242]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [rt.jar:1.8.0_242]
at java.lang.Thread.run(Thread.java:748) [rt.jar:1.8.0_242]
The error is thrown when Vaadin is trying to "Restores all attributes (security key, reference to this context instance) with
newSession.setAttribute(name, value);
(VaadinService.java:1150 onwards)
Is this Vaadin problem or WildFly problem and how to solve it?
EDIT: I noticed that if I reinitialize the sessionID in UI.init()
the sessionID will get changed and updated on browser but of course user has not logged in yet. When I try to reinitialize anywhere else, it will change the server side sessionID but not on browser. My login screen is a custom component instantiated on UI.init().
EDIT 31.7.2020 (making progress?)
I started experimenting again by using @Push with LONG_POLLING mode and I might be making some progress but still facing an issues.
After login I'm issuing the VaadinService.reinitializeSession
and the server side sessionId is getting changed and I'm not getting any errors on log. Client side sessionId is not changed and after ~15s I get "Communication problem" from app and the sessionId on client gets changed to completely new one (not any that server has had).
Also, Chrome console show that hearbeat is getting "404 (Not Found)" as soon as reinitializeSession has been called. After 5 or so 404 errors console shows this:
[Deprecation] Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
And it's about exactly the same behaviour with using @Push with WEBSOCKET_XHR.
I have tried this using also Wildfly 20.0.1 - it's the same with that too.
回答1:
The problem you have is probably due use of WebSocket with Push. There are some workarounds which are discussed in detail in blog post on Vaadin site.
The post says
You can use the WEBSOCKET_XHR transport instead of Websocket.
Disable push completely in the login page (i.e. don’t put @Push on your UI) and programmatically enable it after the user has logged on.
Use a push mechanism that uses basic HTTP, i.e. transport mode LONG_POLLING.
The further investigation revealed, that the info is a bit outdated, since Chrome from version 80 onwards removed support of synchronous XHR during page dismissal.
This narrows the working option actually to combination of 1. and 2. The Push needs to be disabled during re-initialization, i.e.
public static void sessionFixation() {
// Chrome 80 does not support synchronous XHR during page dismissal anymore
// thus Push needs to be disabled during session re-initialization
UI.getCurrent().getPushConfiguration().setPushMode(PushMode.DISABLED);
VaadinService.reinitializeSession(VaadinService.getCurrentRequest());
UI.getCurrent().getPushConfiguration().setPushMode(PushMode.AUTOMATIC);
}
There is a fully functioning demo app in https://github.com/TatuLund/cdi-demo
PS. Just to point out, the latest Vaadin version as writing of this answer is 8.11.1, I recommend to upgrade. Also Wildfly 8 is quite old.
来源:https://stackoverflow.com/questions/63035590/how-to-change-jsessionid-after-login-in-vaadin8