2

I'm working on a Spring Boot projects that using default Thymeleaf and using REST API for accessing the database. Everything's working until a pentest finding required me to set the cookie flagged as secured. I have read these links:

  1. Add secure flag to JSESSIONID cookie in spring automatically
  2. https://javadeveloperzone.com/spring-boot/spring-boot-secure-session-cookies/

I already tried both approach, the secure flag was present.

Screenshot of secure flag cookie

Screenshot of secure flag cookie

The problem comes when I tried to log in into the application, I failed to logged in. I debugged the spring security source code on runtime, and I think the problem is the CSRF Token that sent from HTML Form and the tokenRepository in CsrfFilter is not match, resulting

"Invalid CSRF token found for http://localhost:8081/login"

and throwing MissingCsrfTokenException (doFilterInternal in CsrfFilter).

Below is my configurations:

WebSecurityConfig.java

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

@Bean("authenticationManager")
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
    return super.authenticationManagerBean();
}

@Autowired
private CustomAuthProvider customAuthProvider;


@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(customAuthProvider);
}

@Bean
public CustomAuthenticationFailureHandler authenticationFailureHandler() {
    return new CustomAuthenticationFailureHandler();
}

@Bean
public CustomLogoutSuccessHandler logoutSuccessHandler() {
    return new CustomLogoutSuccessHandler();
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
            .antMatchers("/login**").permitAll()
            .anyRequest().authenticated()
            .and()
        .exceptionHandling()
            .accessDeniedPage("/errors/403")
            .and()
        .formLogin()
            .loginPage("/login")
            .loginProcessingUrl("/login")
            .failureHandler(authenticationFailureHandler())
            .permitAll()
            .and()
        .logout()
            .logoutUrl("/logout")
            .logoutSuccessHandler(logoutSuccessHandler())
            .permitAll()
            .deleteCookies("JSESSIONID")
            .and()
        .sessionManagement()
            .maximumSessions(1);

    http.headers().frameOptions().sameOrigin()
        .addHeaderWriter(new StaticHeadersWriter("Content-Security-Policy","script-src 'self' 'unsafe-inline'"))
        .addHeaderWriter(new StaticHeadersWriter("X-Permitted-Cross-Domain-Policies","none"))
        .addHeaderWriter(new StaticHeadersWriter("Feature-Policy","geolocation 'none'"))
        .addHeaderWriter(new StaticHeadersWriter("Referrer-Policy","no-referrer"));
}

@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers("/img/**",
            "/misc/**",
            "/css/**",
            "/js/**",
            "/bower_components/**");
}

And this is snippet of my CustomAuthProvider

CustomAuthProvider.java

@Component
public class CustomAuthProvider implements AuthenticationProvider {

@Override
public Authentication authenticate (Authentication authentication) throws AuthenticationException {

    String username = authentication.getName();
    String password = authentication.getCredentials().toString();

    HashMap<String, Object> userData;
    try{
        userData = AuthViaApi(username, password); //find by username password in api server
    }catch(Exception e){
        throw new BadCredentialsException(e.getMessage());
    }

    List<GrantedAuthority> grantedAuths = new ArrayList<>();
    try {
        ArrayList<HashMap<String, Object>> permissions = //get user's permission from database via api

        for(HashMap<String, Object> p : permissions){
            String authority = // generate authority string;
            grantedAuths.add(new SimpleGrantedAuthority(authority));
        }

    }catch(Exception e){
        //throw exception
    }

    //updates some userData here to put in auth object's detail

    UserDetails principal = new User(username, password, grantedAuths);

    Authentication auth = new UsernamePasswordAuthenticationToken(principal, password, grantedAuths);

    ((UsernamePasswordAuthenticationToken) authentication).setDetails(userData);

    return auth;

}

@Override
public boolean supports(Class<?> authentication) {
    return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}

This is my login form, the csrf hidden input was generated by spring:

<form th:action="@{/login}" method="post" id="form" autocomplete="off">
            <div class="form-group has-feedback">
                <input type="text" class="form-control" placeholder="Username" name="username" autocomplete="off">
                <span class="glyphicon glyphicon-envelope form-control-feedback"></span>
            </div>
            <div class="form-group has-feedback">
                <input type="password" class="form-control" placeholder="Password" name="password" autocomplete="off">
                <span class="glyphicon glyphicon-lock form-control-feedback"></span>
            </div>
</form>

The csrf token was indeed sent when submitting the form:

Screenshot of form data

Screenshot of form data

And this is my IntelliJ Debug Console when submitting the form (the timestamps was removed due to body chars limit):

DEBUG 10416 --- [nio-8081-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/img/**'
DEBUG 10416 --- [nio-8081-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/misc/**'
DEBUG 10416 --- [nio-8081-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/css/**'
DEBUG 10416 --- [nio-8081-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/js/**'
DEBUG 10416 --- [nio-8081-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/bower_components/**'
DEBUG 10416 --- [nio-8081-exec-3] o.s.security.web.FilterChainProxy        : /login at position 1 of 13 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
DEBUG 10416 --- [nio-8081-exec-3] o.s.security.web.FilterChainProxy        : /login at position 2 of 13 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
DEBUG 10416 --- [nio-8081-exec-3] w.c.HttpSessionSecurityContextRepository : No HttpSession currently exists
DEBUG 10416 --- [nio-8081-exec-3] w.c.HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: null. A new one will be created.
DEBUG 10416 --- [nio-8081-exec-3] o.s.security.web.FilterChainProxy        : /login at position 3 of 13 in additional filter chain; firing Filter: 'HeaderWriterFilter'
DEBUG 10416 --- [nio-8081-exec-3] o.s.security.web.FilterChainProxy        : /login at position 4 of 13 in additional filter chain; firing Filter: 'CsrfFilter'
DEBUG 10416 --- [nio-8081-exec-3] o.s.security.web.csrf.CsrfFilter         : Invalid CSRF token found for http://localhost:8081/login
 WARN 10416 --- [nio-8081-exec-3] o.s.web.servlet.PageNotFound             : Request method 'POST' not supported
DEBUG 10416 --- [nio-8081-exec-3] o.s.s.w.header.writers.HstsHeaderWriter  : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@b3a4b14
DEBUG 10416 --- [nio-8081-exec-3] w.c.HttpSessionSecurityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
DEBUG 10416 --- [nio-8081-exec-3] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
DEBUG 10416 --- [nio-8081-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/error'; against '/img/**'
DEBUG 10416 --- [nio-8081-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/error'; against '/misc/**'
DEBUG 10416 --- [nio-8081-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/error'; against '/css/**'
DEBUG 10416 --- [nio-8081-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/error'; against '/js/**'
DEBUG 10416 --- [nio-8081-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/error'; against '/bower_components/**'
DEBUG 10416 --- [nio-8081-exec-3] o.s.security.web.FilterChainProxy        : /error at position 1 of 13 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
DEBUG 10416 --- [nio-8081-exec-3] o.s.security.web.FilterChainProxy        : /error at position 2 of 13 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
DEBUG 10416 --- [nio-8081-exec-3] w.c.HttpSessionSecurityContextRepository : HttpSession returned null object for SPRING_SECURITY_CONTEXT
DEBUG 10416 --- [nio-8081-exec-3] w.c.HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade@1f953457. A new one will be created.
DEBUG 10416 --- [nio-8081-exec-3] o.s.security.web.FilterChainProxy        : /error at position 3 of 13 in additional filter chain; firing Filter: 'HeaderWriterFilter'
DEBUG 10416 --- [nio-8081-exec-3] o.s.security.web.FilterChainProxy        : /error at position 4 of 13 in additional filter chain; firing Filter: 'CsrfFilter'
DEBUG 10416 --- [nio-8081-exec-3] o.s.security.web.FilterChainProxy        : /error at position 5 of 13 in additional filter chain; firing Filter: 'LogoutFilter'
DEBUG 10416 --- [nio-8081-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/error'; against '/logout'
DEBUG 10416 --- [nio-8081-exec-3] o.s.security.web.FilterChainProxy        : /error at position 6 of 13 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
DEBUG 10416 --- [nio-8081-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/error'; against '/login'
DEBUG 10416 --- [nio-8081-exec-3] o.s.security.web.FilterChainProxy        : /error at position 7 of 13 in additional filter chain; firing Filter: 'ConcurrentSessionFilter'
DEBUG 10416 --- [nio-8081-exec-3] o.s.security.web.FilterChainProxy        : /error at position 8 of 13 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
DEBUG 10416 --- [nio-8081-exec-3] o.s.security.web.FilterChainProxy        : /error at position 9 of 13 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
DEBUG 10416 --- [nio-8081-exec-3] o.s.security.web.FilterChainProxy        : /error at position 10 of 13 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
DEBUG 10416 --- [nio-8081-exec-3] o.s.s.w.a.AnonymousAuthenticationFilter  : Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@ae899d55: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@ffff4c9c: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 885412450AE6A0685EDBC8C4A43C7D06; Granted Authorities: ROLE_ANONYMOUS'
DEBUG 10416 --- [nio-8081-exec-3] o.s.security.web.FilterChainProxy        : /error at position 11 of 13 in additional filter chain; firing Filter: 'SessionManagementFilter'
DEBUG 10416 --- [nio-8081-exec-3] o.s.security.web.FilterChainProxy        : /error at position 12 of 13 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
DEBUG 10416 --- [nio-8081-exec-3] o.s.security.web.FilterChainProxy        : /error at position 13 of 13 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
DEBUG 10416 --- [nio-8081-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/error'; against '/logout'
DEBUG 10416 --- [nio-8081-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/error'; against '/login**'
DEBUG 10416 --- [nio-8081-exec-3] o.s.s.w.a.i.FilterSecurityInterceptor    : Secure object: FilterInvocation: URL: /error; Attributes: [authenticated]
DEBUG 10416 --- [nio-8081-exec-3] o.s.s.w.a.i.FilterSecurityInterceptor    : Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@ae899d55: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@ffff4c9c: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 885412450AE6A0685EDBC8C4A43C7D06; Granted Authorities: ROLE_ANONYMOUS
DEBUG 10416 --- [nio-8081-exec-3] o.s.s.access.vote.AffirmativeBased       : Voter: org.springframework.security.web.access.expression.WebExpressionVoter@5bee5c02, returned: -1
DEBUG 10416 --- [nio-8081-exec-3] o.s.s.w.a.ExceptionTranslationFilter     : Access is denied (user is anonymous); redirecting to authentication entry point

org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:84) ~[spring-security-core-5.0.6.RELEASE.jar:5.0.6.RELEASE]
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:233) ~[spring-security-core-5.0.6.RELEASE.jar:5.0.6.RELEASE]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:124) ~[spring-security-web-5.0.6.RELEASE.jar:5.0.6.RELEASE]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91) ~[spring-security-web-5.0.6.RELEASE.jar:5.0.6.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.0.6.RELEASE.jar:5.0.6.RELEASE]
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:119) ~[spring-security-web-5.0.6.RELEASE.jar:5.0.6.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.0.6.RELEASE.jar:5.0.6.RELEASE]
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137) [spring-security-web-5.0.6.RELEASE.jar:5.0.6.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.0.6.RELEASE.jar:5.0.6.RELEASE]
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111) [spring-security-web-5.0.6.RELEASE.jar:5.0.6.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.0.6.RELEASE.jar:5.0.6.RELEASE]
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170) [spring-security-web-5.0.6.RELEASE.jar:5.0.6.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.0.6.RELEASE.jar:5.0.6.RELEASE]
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) [spring-security-web-5.0.6.RELEASE.jar:5.0.6.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.0.6.RELEASE.jar:5.0.6.RELEASE]
at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:155) [spring-security-web-5.0.6.RELEASE.jar:5.0.6.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.0.6.RELEASE.jar:5.0.6.RELEASE]
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200) [spring-security-web-5.0.6.RELEASE.jar:5.0.6.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.0.6.RELEASE.jar:5.0.6.RELEASE]
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116) [spring-security-web-5.0.6.RELEASE.jar:5.0.6.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.0.6.RELEASE.jar:5.0.6.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:101) [spring-web-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.0.6.RELEASE.jar:5.0.6.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:101) [spring-web-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.0.6.RELEASE.jar:5.0.6.RELEASE]
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) [spring-security-web-5.0.6.RELEASE.jar:5.0.6.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.0.6.RELEASE.jar:5.0.6.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:101) [spring-web-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.0.6.RELEASE.jar:5.0.6.RELEASE]
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215) [spring-security-web-5.0.6.RELEASE.jar:5.0.6.RELEASE]
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178) [spring-security-web-5.0.6.RELEASE.jar:5.0.6.RELEASE]
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:357) [spring-web-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:270) [spring-web-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.31.jar:8.5.31]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.31.jar:8.5.31]
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:728) [tomcat-embed-core-8.5.31.jar:8.5.31]
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:472) [tomcat-embed-core-8.5.31.jar:8.5.31]
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:395) [tomcat-embed-core-8.5.31.jar:8.5.31]
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:316) [tomcat-embed-core-8.5.31.jar:8.5.31]
at org.apache.catalina.core.StandardHostValve.custom(StandardHostValve.java:395) [tomcat-embed-core-8.5.31.jar:8.5.31]
at org.apache.catalina.core.StandardHostValve.status(StandardHostValve.java:254) [tomcat-embed-core-8.5.31.jar:8.5.31]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:177) [tomcat-embed-core-8.5.31.jar:8.5.31]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81) [tomcat-embed-core-8.5.31.jar:8.5.31]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.31.jar:8.5.31]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) [tomcat-embed-core-8.5.31.jar:8.5.31]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803) [tomcat-embed-core-8.5.31.jar:8.5.31]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.31.jar:8.5.31]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:790) [tomcat-embed-core-8.5.31.jar:8.5.31]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1468) [tomcat-embed-core-8.5.31.jar:8.5.31]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.31.jar:8.5.31]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_181]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_181]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.31.jar:8.5.31]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_181]

DEBUG 10416 --- [nio-8081-exec-3] o.s.s.w.util.matcher.AndRequestMatcher   : Trying to match using Ant [pattern='/**', GET]
DEBUG 10416 --- [nio-8081-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher  : Request 'POST /error' doesn't match 'GET /**
DEBUG 10416 --- [nio-8081-exec-3] o.s.s.w.util.matcher.AndRequestMatcher   : Did not match
DEBUG 10416 --- [nio-8081-exec-3] o.s.s.w.s.HttpSessionRequestCache        : Request not saved as configured RequestMatcher did not match
DEBUG 10416 --- [nio-8081-exec-3] o.s.s.w.a.ExceptionTranslationFilter     : Calling Authentication entry point.
DEBUG 10416 --- [nio-8081-exec-3] o.s.s.web.DefaultRedirectStrategy        : Redirecting to 'http://localhost:8081/login'
DEBUG 10416 --- [nio-8081-exec-3] w.c.HttpSessionSecurityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
DEBUG 10416 --- [nio-8081-exec-3] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
DEBUG 10416 --- [nio-8081-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/img/**'
DEBUG 10416 --- [nio-8081-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/misc/**'
DEBUG 10416 --- [nio-8081-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/css/**'
DEBUG 10416 --- [nio-8081-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/js/**'
DEBUG 10416 --- [nio-8081-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/bower_components/**'
DEBUG 10416 --- [nio-8081-exec-2] o.s.security.web.FilterChainProxy        : /login at position 1 of 13 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
DEBUG 10416 --- [nio-8081-exec-2] o.s.security.web.FilterChainProxy        : /login at position 2 of 13 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
DEBUG 10416 --- [nio-8081-exec-2] w.c.HttpSessionSecurityContextRepository : No HttpSession currently exists
DEBUG 10416 --- [nio-8081-exec-2] w.c.HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: null. A new one will be created.
DEBUG 10416 --- [nio-8081-exec-2] o.s.security.web.FilterChainProxy        : /login at position 3 of 13 in additional filter chain; firing Filter: 'HeaderWriterFilter'
DEBUG 10416 --- [nio-8081-exec-2] o.s.security.web.FilterChainProxy        : /login at position 4 of 13 in additional filter chain; firing Filter: 'CsrfFilter'
DEBUG 10416 --- [nio-8081-exec-2] o.s.security.web.FilterChainProxy        : /login at position 5 of 13 in additional filter chain; firing Filter: 'LogoutFilter'
DEBUG 10416 --- [nio-8081-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher  : Request 'GET /login' doesn't match 'POST /logout
DEBUG 10416 --- [nio-8081-exec-2] o.s.security.web.FilterChainProxy        : /login at position 6 of 13 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
DEBUG 10416 --- [nio-8081-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher  : Request 'GET /login' doesn't match 'POST /login
DEBUG 10416 --- [nio-8081-exec-2] o.s.security.web.FilterChainProxy        : /login at position 7 of 13 in additional filter chain; firing Filter: 'ConcurrentSessionFilter'
DEBUG 10416 --- [nio-8081-exec-2] o.s.security.web.FilterChainProxy        : /login at position 8 of 13 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
DEBUG 10416 --- [nio-8081-exec-2] o.s.security.web.FilterChainProxy        : /login at position 9 of 13 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
DEBUG 10416 --- [nio-8081-exec-2] o.s.security.web.FilterChainProxy        : /login at position 10 of 13 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
DEBUG 10416 --- [nio-8081-exec-2] o.s.s.w.a.AnonymousAuthenticationFilter  : Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@a34ec6dd: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS'
DEBUG 10416 --- [nio-8081-exec-2] o.s.security.web.FilterChainProxy        : /login at position 11 of 13 in additional filter chain; firing Filter: 'SessionManagementFilter'
DEBUG 10416 --- [nio-8081-exec-2] o.s.security.web.FilterChainProxy        : /login at position 12 of 13 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
DEBUG 10416 --- [nio-8081-exec-2] o.s.security.web.FilterChainProxy        : /login at position 13 of 13 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
DEBUG 10416 --- [nio-8081-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor    : Secure object: FilterInvocation: URL: /login; Attributes: [permitAll]
DEBUG 10416 --- [nio-8081-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor    : Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@a34ec6dd: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
DEBUG 10416 --- [nio-8081-exec-2] o.s.s.access.vote.AffirmativeBased       : Voter: org.springframework.security.web.access.expression.WebExpressionVoter@5bee5c02, returned: 1
DEBUG 10416 --- [nio-8081-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor    : Authorization successful
DEBUG 10416 --- [nio-8081-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor    : RunAsManager did not change Authentication object
DEBUG 10416 --- [nio-8081-exec-2] o.s.security.web.FilterChainProxy        : /login reached end of additional filter chain; proceeding with original chain
DEBUG 10416 --- [nio-8081-exec-2] o.s.s.w.header.writers.HstsHeaderWriter  : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@b3a4b14
DEBUG 10416 --- [nio-8081-exec-2] w.c.HttpSessionSecurityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
DEBUG 10416 --- [nio-8081-exec-2] o.s.s.w.a.ExceptionTranslationFilter     : Chain processed normally
DEBUG 10416 --- [nio-8081-exec-2] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed

Am I missing or misconfigured something?

ariaenggar
  • 111
  • 1
  • 9
  • Do you really call `http://localhost:8081/login` or is that message wrong? – dur Feb 18 '19 at 10:02
  • @dur, I opened the url on the browser, shows login form, I provide the credentials, and the message showed up on intellij console, and the page just refreshed. – ariaenggar Feb 18 '19 at 10:40
  • If you use secured cookies, you can't call unsecured URLs. You have to use HTTPS. – dur Feb 18 '19 at 14:15
  • @dur Do you mean this (https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#Secure_and_HttpOnly_cookies)? So what's the meaning of "They are not protocol specific: a cookie set on the HTTPS website (which is secure) will also be available to the HTTP version (which is not secure)." in this link (https://www.tunetheweb.com/security/http-security-headers/secure-cookies/)? – ariaenggar Feb 18 '19 at 23:39
  • I'm not sure, but your first link says: *Starting with Chrome 52 and Firefox 52, insecure sites (http:) can't set cookies with the Secure directive.* What version do you use? – dur Feb 19 '19 at 19:02
  • @dur I think that's the problem, I don't have access to https server for my apps. When I deployed on my client's server that provides https, it's working. – ariaenggar Mar 01 '19 at 07:39

2 Answers2

6

Update:

The problem is now solved, I think this is because I tried it on my localhost, which I think considered as "unsecured connection" by the browser, and since unsecured connection can't set secure cookie, spring boot apps can't create session, see here: https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#Secure_and_HttpOnly_cookies

When I deployed on my client's server that provides https, it's working. Thank you for all responders.

ariaenggar
  • 111
  • 1
  • 9
  • actually it is like this: HTTPS -> works; HTTP on anything than localhost -> does not work; HTTP to localhost -> works (as described on the link you posted) PS: It may have been different at the time you wrote. Now it behaves as I wrote, quoting from the linked doc: A cookie with the Secure attribute is only sent to the server with an encrypted request over the HTTPS protocol. It's never sent with unsecured HTTP (except on localhost) – David Balažic Aug 17 '22 at 14:06
  • I see @DavidBalažic, thank you so much for the explanation, I got better understanding now. – ariaenggar Aug 31 '22 at 03:16
0

It looks like the CSRF (Cross Site Request Forgery) protection in your Spring application is enabled. Actually it is enabled by default. So to keep CSRF protection enabled then you have to include in your form the csrftoken. You can do it like this:

<form .... >
  ....other fields here....
  <input type="hidden"  name="${_csrf.parameterName}"   value="${_csrf.token}"/>
</form>

include the CSRF token in the form's action:

<form action="./upload?${_csrf.parameterName}=${_csrf.token}" method="post" enctype="multipart/form-data">
mm6
  • 84
  • 6
  • The csrf token input is already there, the html I provided was from my source code, the html input was then added by spring thymeleaf. – ariaenggar Feb 18 '19 at 22:30
  • have you tried adding this in header: addHeaderWriter(new StaticHeadersWriter("Access-Control-Allow-Methods", "POST, GET")) – mm6 Feb 19 '19 at 09:23