简体   繁体   中英

How to change JSESSIONID after login in Vaadin8?

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.

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

  1. You can use the WEBSOCKET_XHR transport instead of Websocket.

  2. Disable push completely in the login page (ie don't put @Push on your UI) and programmatically enable it after the user has logged on.

  3. Use a push mechanism that uses basic HTTP, ie 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, ie

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM