Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Expand Timeout using Spring Session (JDBC) on Spring Boot

I'm using Spring Boot and Spring Session to control an application that uses ReactJS as frontend. My problem is simple and I tried several ways to deal with without success.

The React portion uses AJAX to call Spring REST services after the login (I'm using Spring Security as well) that's amazing for at least 30 minutes. After that the session is dead and all calls receives a 302 with the login page as response. This is EXPECTED.

But my problem is: what's the better way to expand a bit the back-end time to live (more than the 30 minutes default)?

    // Gradle portion
    compile('org.springframework.boot:spring-boot-devtools')
    compile('org.springframework.boot:spring-boot-starter-jdbc')
    compile('org.springframework.boot:spring-boot-starter-thymeleaf')
    compile('org.springframework.boot:spring-boot-starter-web')
    compile('org.springframework.boot:spring-boot-starter-aop')
    compile('org.springframework.boot:spring-boot-starter-security')
    compile('org.springframework.security:spring-security-test:4.1.1.RELEASE')

    // Cache configuration - JDBC
    compile('org.springframework.session:spring-session:1.2.2.RELEASE')
    compile('org.springframework.session:spring-session-jdbc:1.2.2.RELEASE')
    compile('org.springframework.boot:spring-boot-starter-jdbc')

I'm used to add:

// A 24 hours long session
server.session.timeout = 86400 

With that I'm able to see on the SPRING_SESSION table my session stored with the MAX_INACTIVE_INTERVAL = 86400. Everything seems fine... for 30 minutes only. On the 31th minute I try to click on another page that fires an AJAX call I'll receive the 302 to my login page on as response.

I got the exactly same behavior using another approach, setting through Java on the Auth Success:

@Component
public class AuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {

    @Value("${server.session.timeout}")
    private String defaultSessionTimeoutInSeconds;

    @Override
    public void onAuthenticationSuccess(
            HttpServletRequest request,
            HttpServletResponse response,
            Authentication authentication) throws ServletException, IOException {

        request.getSession().setMaxInactiveInterval(Integer.parseInt(defaultSessionTimeoutInSeconds));
        super.onAuthenticationSuccess(request, response, authentication);
    }
}

For sure I'm able to verify my numbers on the database stored session but after 30 minutes the session is deleted again.

So what's the correct way to REALLY expand the Spring Session timeout to more than 30 minutes? Since MAX_INACTIVE_INTERVAL is not doing what I think that should do, what's the correct approach?

I'm able to use latest versions of any lib.

PS: I'm able to consider another solution to redirect the whole browser when my AJAX calls (JQuery based) receive a /login redirect as well to fallback situations.

Thanks in advance.

UPDATE:

I tried the following:

Add the properties -> server.session.cookie.max-age= 777777 security.sessions=never

Nothing was changed on the behavior. Debugging I'm able to see at JdbcOperationsSessionRepository#cleanUpExpiredSessions:

@Scheduled(cron = "0 * * * * *")
public void cleanUpExpiredSessions() {
    long now = System.currentTimeMillis();
    long maxInactiveIntervalSeconds = (this.defaultMaxInactiveInterval != null)
            ? this.defaultMaxInactiveInterval
            : MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS;

    final long sessionsValidFromTime = now - (maxInactiveIntervalSeconds * 1000);

The this.defaultMaxInactiveInterval still always populated with "1800" that means 30 minutes to kill all sessions.

And this is the expected behavior by the comments:

Debugging Information from default value.

I'm still trying to change this persistent default value of 1800 to something bigger... :)

UPDATE 2

Looking more carefully at the code, in my case when the JdbcOperationsSessionRepository is instantiated, it's created by JdbcHttpSessionConfiguration#sessionRepository

Where specifically:

@Bean
public JdbcOperationsSessionRepository sessionRepository(
        @Qualifier("springSessionJdbcOperations") JdbcOperations jdbcOperations,
        PlatformTransactionManager transactionManager) {
    JdbcOperationsSessionRepository sessionRepository =
            new JdbcOperationsSessionRepository(jdbcOperations, transactionManager);
    String tableName = getTableName();
    if (StringUtils.hasText(tableName)) {
        sessionRepository.setTableName(tableName);
    }
    sessionRepository
            .setDefaultMaxInactiveInterval(this.maxInactiveIntervalInSeconds); // Always 1800 (private Integer maxInactiveIntervalInSeconds = 1800;)
    if (this.lobHandler != null) {
        sessionRepository.setLobHandler(this.lobHandler);
    }
    if (this.springSessionConversionService != null) {
        sessionRepository.setConversionService(this.springSessionConversionService);
    }
    else if (this.conversionService != null) {
        sessionRepository.setConversionService(this.conversionService);
    }
    else if (deserializingConverterSupportsCustomClassLoader()) {
        GenericConversionService conversionService = createConversionServiceWithBeanClassLoader();
        sessionRepository.setConversionService(conversionService);
    }
    return sessionRepository;
}

I did not found any clear option to override that beautifully.

UPDATE 3

Following the comments I'm able to configure only using the annotation as:

    import org.springframework.session.jdbc.config.annotation.web.http.EnableJdbcHttpSession;

@EnableJdbcHttpSession(tableName="MYSCHEMA.SPRING_SESSION", maxInactiveIntervalInSeconds = 86400)
public class HttpSessionConfig {
}

With that I'm able to store the session with the defined MAX_INACTIVE_INTERVAL = 86400.

But if I keep the related SPRING_SECURITY_CONTEXT (SPRING_SESSION_ATTRIBUTES table) information with my new session, the whole session and attributes are deleted after 30 minutes.

In a crazy test, I made a login, removed the SPRING_SECURITY_CONTEXT attribute of my session and the session still there...

The default session cleaner is right and it's NOT the offender here..

    2016-10-04 12:18:02,081 8808479 [pool-1-thread-1] INFO  d.s.t.s.ScheduledCacheRefresher - Checking refreshable caches now. 
2016-10-04 12:19:00,001 8866399 [pool-1-thread-1] DEBUG o.s.s.j.JdbcOperationsSessionRepository - Cleaning up sessions older than Mon Oct 03 12:19:00 BRT 2016 
2016-10-04 12:19:02,050 8868448 [pool-1-thread-1] DEBUG o.s.s.j.JdbcOperationsSessionRepository - Cleaned up 0 expired sessions 
2016-10-04 12:19:02,051 8868449 [pool-1-thread-1] INFO  d.s.t.s.ScheduledCacheRefresher - Checking refreshable caches now. 
2016-10-04 12:20:00,001 8926399 [pool-1-thread-1] INFO  d.s.t.s.ScheduledCacheRefresher - Checking refreshable caches now. 
2016-10-04 12:20:00,003 8926401 [pool-1-thread-1] DEBUG o.s.s.j.JdbcOperationsSessionRepository - Cleaning up sessions older than Mon Oct 03 12:20:00 BRT 2016 
2016-10-04 12:20:02,063 8928461 [pool-1-thread-1] DEBUG o.s.s.j.JdbcOperationsSessionRepository - Cleaned up 0 expired sessions

The log never showed a deletion for them.

So anything else that checks the SPRING_SECURITY_CONTEXT still have some 30 minutes default timeout and it triggers a whole session invalidation.

I'm trying to add more breakpoints to figure it out. :)

like image 423
Pablo Thiele Avatar asked Oct 01 '16 01:10

Pablo Thiele


People also ask

How do I set a Spring session timeout?

For setting the timeout of the session you can use the spring. session. timeout property. If that property is not set, the auto-configuration falls back to the value of server.


1 Answers

You have to set the server.session.timeout in your application.properties file. Refer this document: server properties

like image 66
tushar Avatar answered Oct 12 '22 23:10

tushar