Sachin
Sachin

Reputation: 507

How to work around SpringSessionBackedReactiveSessionRegistry bug? (Spring Security, Spring Session)

Any suggestions on how to work around the below bug, or am I doing something fundamentally wrong? Whenever I do something like val contextAttr = session.getAttribute<Map<String, Any>>(springAttribute), the contextAttr definitely comes back as a LinkedHashedMap.. These objects are stored in Redis as attributes to the main session, which I believe is all in JSON / Map <String, Any?> format.

Describe the bug

When my Spring logout handler calls this

fun invalidateSession(sessionId: String): Mono<Void> {
        logger.info("Invalidating sessionId: ${sessionId}")
        // handle the session invalidation process
        return reactiveSessionRegistry.getSessionInformation(sessionId)
            .flatMap { session ->
                // invalidate session
                session.invalidate()
                    .then(
                        // delete session
                        webSessionStore.removeSession(sessionId)
                    )
                    .doOnSuccess {
                        logger.info("Session invalidated and removed: ${sessionId}")
                    }
                    .doOnError { error ->
                        logger.error("Error invalidating session: ${sessionId}", error)
                    }
            }
    }

The following function inside SpringSessionBackedReactiveSessionRegistry gets called:

    @Override
    public Mono<ReactiveSessionInformation> getSessionInformation(String sessionId) {
        return this.sessionRepository.findById(sessionId).map(SpringSessionBackedReactiveSessionInformation::new);
    }

The inner class is implemented as follows:

class SpringSessionBackedReactiveSessionInformation extends ReactiveSessionInformation {

        SpringSessionBackedReactiveSessionInformation(S session) {
            super(resolvePrincipalName(session), session.getId(), session.getLastAccessedTime());
        }

        private static String resolvePrincipalName(Session session) {
            String principalName = session
                .getAttribute(ReactiveFindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME);
            if (principalName != null) {
                return principalName;
            }
            SecurityContext securityContext = session.getAttribute(SPRING_SECURITY_CONTEXT);
            if (securityContext != null && securityContext.getAuthentication() != null) {
                return securityContext.getAuthentication().getName();
            }
            return "";
        }

        @Override
        public Mono<Void> invalidate() {
            return super.invalidate()
                .then(Mono.defer(() -> SpringSessionBackedReactiveSessionRegistry.this.sessionRepository
                    .deleteById(getSessionId())));
        }

    }

But, here on this line:

SecurityContext securityContext = session.getAttribute(SPRING_SECURITY_CONTEXT);

SPRING_SECURITY_CONTEXT is received from Redis as a HashMap or LinkedHashMap, so cannot be cast to SecurityContext (w/o proper de-serialisation)

This is EXACTLY the error I see:

enter image description here

Two calls to get session?

Also, I'm not sure if this is calling Redis again to get the security context, but is it necessary?, given just before calling /logout endpoint, the session / security context is retrieved anyway, (see below.)

SessionId would come from the session, here, when this is called in the line just before fun invalidateSession(sessionId: String): Mono ) (to get the session ID), so calling getSessionInformation(String sessionId) and with it, this.sessionRepository.findById(sessionId), again, seems a bit wasteful...?

To Reproduce See above, just try the above, with sessions stored to redis, then try to invalidate a session calling the above functions

Expected behavior The casting should be properly deserialised. A linkedHashmap cannot be cast to a SecurityContext object directly

Sample

See above. Github code can be found here:

My implementations https://github.com/dreamstar-enterprises/docs/blob/master/Spring%20BFF/BFF/src/main/kotlin/com/frontiers/bff/auth/sessions/SessionRegistryConfig.kt

Spring implementation (where error is I believe) https://github.com/spring-projects/spring-session/blob/main/spring-session-core/src/main/java/org/springframework/session/security/SpringSessionBackedReactiveSessionRegistry.java

Appreciate any help or suggestions given!

Upvotes: 1

Views: 63

Answers (0)

Related Questions