Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring session creation policy per-request?

TL;DR

Is it possible to control the session creation policy in Spring (Security) on a per request basis?

Long version...

I have been using normal login form user authentication for our application. Some of the controllers are @RestControllers and up to now, the default user session tracked by cookie has allowed it to work fine.

(I.e. when an XHR request comes from a page, the request is authenticated to the previously logged in user as the browser sends the JSESSIONID cookie as usual)

I now want to allow some of the @RestController end points to be called from a rest client, rather than browser, so I have created an API token authentication scheme - this works fine.

One of the last bits of cleanup is that the REST calls generate a session, which I'd like to avoid if possible.

I can't set the session policy to NEVER (because i'm still relying on sessions for my web users).

I have tried IF_REQUIRED to no avail.

I have looked at the HttpSessionSecurityContextRepository but it wraps the request, and a session is created whenever the response is flushed.

(See stacktrace below)

Is it possible elsewhere to hook into the session management on a per-request basis?

I can distinguish the type of request easily enough based on the class type of the Authentication object.

at myapp.cfg.WebConfig$1.sessionCreated(WebConfig.java:74)
at io.undertow.servlet.core.ApplicationListeners.sessionCreated(ApplicationListeners.java:300)
at io.undertow.servlet.core.SessionListenerBridge.sessionCreated(SessionListenerBridge.java:56)
at io.undertow.server.session.SessionListeners.sessionCreated(SessionListeners.java:52)
at io.undertow.server.session.InMemorySessionManager.createSession(InMemorySessionManager.java:187)
at io.undertow.servlet.spec.ServletContextImpl.getSession(ServletContextImpl.java:741)
at io.undertow.servlet.spec.HttpServletRequestImpl.getSession(HttpServletRequestImpl.java:370)
at javax.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:270)
at org.springframework.security.web.context.HttpSessionSecurityContextRepository$SaveToSessionResponseWrapper.createNewSessionIfAllowed(HttpSessionSecurityContextRepository.java:427)
at org.springframework.security.web.context.HttpSessionSecurityContextRepository$SaveToSessionResponseWrapper.saveContext(HttpSessionSecurityContextRepository.java:364)
at org.springframework.security.web.context.SaveContextOnUpdateOrErrorResponseWrapper.onResponseCommitted(SaveContextOnUpdateOrErrorResponseWrapper.java:85)
at org.springframework.security.web.util.OnCommittedResponseWrapper.doOnResponseCommitted(OnCommittedResponseWrapper.java:245)
at org.springframework.security.web.util.OnCommittedResponseWrapper.access$000(OnCommittedResponseWrapper.java:33)
at org.springframework.security.web.util.OnCommittedResponseWrapper$SaveContextServletOutputStream.flush(OnCommittedResponseWrapper.java:512)
at org.springframework.security.web.util.OnCommittedResponseWrapper$SaveContextServletOutputStream.flush(OnCommittedResponseWrapper.java:513)
at com.fasterxml.jackson.core.json.UTF8JsonGenerator.flush(UTF8JsonGenerator.java:1050)
at com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:953)
like image 677
Rob Shepherd Avatar asked Apr 20 '17 15:04

Rob Shepherd


People also ask

What is SessionCreationPolicy?

Enum SessionCreationPolicySpecifies the various session creation policies for Spring Security.

What is Jsessionid in spring?

JSESSIONID is a cookie generated by Servlet containers like Tomcat or Jetty and used for session management in the J2EE web application for HTTP protocol.

How does Spring Security concurrent session control work?

Concurrent Session Control When a user that is already authenticated tries to authenticate again, the application can deal with that event in one of a few ways. It can either invalidate the active session of the user and authenticate the user again with a new session, or allow both sessions to exist concurrently.

How do I set a session timeout in spring?

Spring Security Session Timeout In the case of Tomcat we can set the session timeout by configuring the maxInactiveInterval attribute on the manager element in server. xml or using the session-timeout element in web. xml. Note that the first option will affect every app that's deployed to the Tomcat instance.


1 Answers

Split your security configuration into separate sections for a form login (session based API access) and a stateless API token authentication scheme.

Example:

@Configuration
@EnableWebSecurity
public class SecurityConfiguration {

    @Order(1)
    @Configuration
    class ApiSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .antMatcher("/api/**")
            .authorizeRequests().anyRequest().authenticated()
            .and()
            .httpBasic().realmName("API") // your API token authentication scheme 
            .and()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER)
            .and()
            .exceptionHandling().authenticationEntryPoint(new Http401AuthenticationEntryPoint("Form realm=\"API\"")); // prevent basic authentication popup in browser
    }
    }

    @Order(2)
    @Configuration
    class DefaultSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .formLogin().loginPage("/login").permitAll()
            .and()
            .logout().logoutSuccessUrl("/login").permitAll();
    }
    }
}

Replace .httpBasic().realmName("API") with you own authentication scheme.

Call your API with e.g. curl -v ... and verify that there is no Set-Cookie header in the response. Otherwise your code somewhere creates an http session on its own.

like image 183
ksokol Avatar answered Sep 29 '22 09:09

ksokol