9

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. :)

Pablo Thiele
  • 352
  • 4
  • 13
  • Do you set security.sessions=never in config? This is from angular and spring security but on react you need same auth https://spring.io/blog/2015/01/20/the-resource-server-angular-js-and-spring-security-part-iii#authentication-in-the-resource-server – seti Oct 01 '16 at 01:37
  • Can you inspect (using debugger) the value of `JdbcOperationsSessionRepository#defaultMaxInactiveInterval`? In addition to that, you can also set `org.springframework.session.jdbc.JdbcOperationsSessionRepository` logger to DEBUG level and see what's logged in `JdbcOperationsSessionRepository#cleanUpExpiredSessions`. – Vedran Pavic Oct 03 '16 at 07:20
  • Tried both and updated my question, the core default remains unchanged and it kill all sessions after 30 minutes. – Pablo Thiele Oct 03 '16 at 17:59
  • @VedranPavić could you please check my updates and tell me how to override correctly the "private Integer maxInactiveIntervalInSeconds = 1800;" from JdbcHttpSessionConfiguration?? – Pablo Thiele Oct 03 '16 at 19:44
  • 2
    What version of Spring Boot are you using and how exactly are you configuring Spring Session JDBC support? Assuming Boot 1.4 you should be able to configure what you want using `spring.session.store-type=jdbc` and the desired value for `server.session.timeout`. Alternatively, you'd use `@EnableJdbcHttpSession` with annotation attribute `maxInactiveIntervalInSeconds` set to the desired value. – Vedran Pavic Oct 03 '16 at 20:23
  • 1
    I'm using Spring Boot 1.3.5 and configuring all using annotations only. So I have : @EnableJdbcHttpSession(tableName="MY_SCHEMA.SPRING_SESSION", maxInactiveIntervalInSeconds = 84600) That provides the right infomations stored on the database and checked on the cleanUpExpiredSessions method. Since I'm looking for a 24hs session it's getting the yesterday time when trying to execute the SQL (expected). But something else still deletes my session after 30 minutes. Is there any other location to check or enable logs? Thank you in advance. – Pablo Thiele Oct 03 '16 at 23:37
  • Could you share a sample project that reproduces this issue? – Vedran Pavic Oct 06 '16 at 20:10
  • My actual project is a bit complex with multi project builds on using gradle. I'll try to create a brand new project just to test that enough. Thanks – Pablo Thiele Oct 10 '16 at 13:54
  • @PabloRS I am facing the same issue. Is there any fix for this ? – Sathesh S Sep 07 '17 at 11:50
  • are you using embedded Tomcat? – Amit K Bist Mar 25 '19 at 21:29

1 Answers1

2

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

Anand
  • 857
  • 1
  • 12
  • 18
tushar
  • 69
  • 5