Sancho
Sancho

Reputation: 437

Websession invalidation not working from Spring Boot 2.0.2

I wanted to upgrade my Spring Webflux project from Spring Boot 2.0.1 to Spring Boot 2.0.3. In my project, my sessions are backed by Spring Session Data Redis. When upgrading the Spring Boot version, I noticed a websession invalidation problem from Spring Boot 2.0.2+.

In Spring Boot 2.0.1, I invalidated my sessions this way :

webSession.invalidate().subscribe();

This caused my current session to be destroyed, and a new one was generated with a new session ID, creation time, etc.

However, from Spring Boot 2.0.2, the same code doesn't seem to fully destroy the session. The current session information are just "cleared", and the same session ID is still used afterward. This is a problem because it causes a null pointer exception in ReactiveRedisOperationsSessionRepository.class :

private static final class SessionMapper implements Function<Map<String, Object>, MapSession> {
        private final String id;

        private SessionMapper(String id) {
            this.id = id;
        }

        public MapSession apply(Map<String, Object> map) {
            MapSession session = new MapSession(this.id);
            session.setCreationTime(Instant.ofEpochMilli((Long)map.get("creationTime")));
            session.setLastAccessedTime(Instant.ofEpochMilli((Long)map.get("lastAccessedTime")));
            session.setMaxInactiveInterval(Duration.ofSeconds((long)(Integer)map.get("maxInactiveInterval")));
            map.forEach((name, value) -> {
                if (name.startsWith("sessionAttr:")) {
                    session.setAttribute(name.substring("sessionAttr:".length()), value);
                }

            });
            return session;
        }
    }

As session data are empty (no creation time, etc.), the following line raises a NPE:

session.setCreationTime(Instant.ofEpochMilli((Long)map.get("creationTime")));

Is it a bug or have I missed something new in Spring Boot 2.0.2+ regarding Spring Session?

UPDATE

To provide more information, I created a sample project reproducing the problem: https://github.com/adsanche/test-redis-session

This project contains a simple controller exposing two endpoints:

@Controller
public class HelloController {

    @GetMapping(value = "/hello")
    public String hello(final WebSession webSession) {

        webSession.getAttributes().put("test", "TEST");

        return "index";
    }

    @GetMapping(value = "/invalidate")
    public String invalidate(final WebSession webSession) {

        webSession.invalidate().subscribe();

        return UrlBasedViewResolver.REDIRECT_URL_PREFIX + "/hello";
    }
}

Behavior when running the project with Spring Boot 2.0.1

Sess

We notice the session ID starting with 7546ff, and the session data containing the "test" attribute plus the default session information (creation/last access time, etc.).

The current session is invalidated, and a redirection is performed on "/hello", where the test attribute is added in a new web session.

enter image description here

We notice the new session ID starting with ba7de, and the new session data still containing the test attribute plus the default session information.

Now, let's reproduce this scenario on the same project with Spring Boot 2.0.3.

Behavior when running the project with Spring Boot 2.0.3

enter image description here

We notice the session ID starting with 12d61, and the session data containing the "test" attribute plus the default session information (creation/last access time, etc.).

enter image description here

We notice here that the same session ID is still used, but the session has been cleared even from its default information (creation date, etc.). So, when it is invoked again, a NPE is triggered in the reactive redis session repository in the apply() method at the place I mention in my original post:

enter image description here

Hope this sample project helps to find out if its a bug or an implementation problem on my side.

Upvotes: 2

Views: 2636

Answers (1)

Vedran Pavic
Vedran Pavic

Reputation: 2389

This is a bug in Spring Session's SpringSessionWebSessionStore, or more specifically, its internal WebSession implementation. The problem is that on WebSession#invalidate session is only cleared from the underlying session store, but not marked as invalid so the subsequent request processing still ends up using the same session id.

I've openend gh-1114 to address this in Spring Session.

I believe you haven't experienced this previously i.e. with Spring Session 2.0.2.RELEASE and below due to another bug in SpringSessionWebSessionStore that was addressed in 2.0.3.RELEASE - see gh-1039. This issue was about failing to update the lastAccessedTime, and once we fixed that the scenario you described started failing due to session for invalidated (and deleted) session id being saved again only with lastAccessedTime attribute.

Upvotes: 1

Related Questions