After logging in successfully via POST /api/v1/auth/login, subsequent requests to GET /api/v1/userAccounts/me are considered to be anonymous according to Spring Security.
This is my security config:
@Configuration
@EnableGlobalMethodSecurity(
prePostEnabled = true,
securedEnabled = true,
jsr250Enabled = true
)
@Order(1)
@RequiredArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final UserDetailsServiceImpl userDetailsService;
private final Config config;
private final ObjectMapper objectMapper;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors()
.and()
.csrf()
.disable()
.authorizeRequests()
.antMatchers(
"/api/v1/auth/**",
"/api/v1/reference/**"
)
.permitAll()
.and()
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.formLogin()
.successHandler((request, response, authentication) -> {
response.getWriter().append("OK");
response.setStatus(HttpServletResponse.SC_OK);
})
.failureHandler((request, response, exception) -> {
response.getWriter().append("Invalid credentials or inactive account");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
})
.loginProcessingUrl("/api/v1/auth/login")
.permitAll()
.and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/api/v1/auth/logout", "POST"))
.permitAll()
.and()
.exceptionHandling()
.accessDeniedHandler((request, response, accessDeniedException) -> {
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
objectMapper.writeValue(
response.getWriter(),
ErrorResponseBody
.builder()
.code(ErrorType.ACCESS_DENIED)
.status(HttpServletResponse.SC_FORBIDDEN)
.message("Access denied")
.build()
);
})
.authenticationEntryPoint((request, response, authException) -> {
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
objectMapper.writeValue(
response.getWriter(),
ErrorResponseBody
.builder()
.code(ErrorType.LOGIN_REQUIRED)
.status(HttpServletResponse.SC_UNAUTHORIZED)
.message("You are not authorized to access this resource")
.build()
);
})
.and()
.userDetailsService(userDetailsService);
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
final var configuration = new CorsConfiguration();
configuration.setAllowCredentials(true);
configuration.setAllowedOrigins(config.getAllowedOrigins());
configuration.setAllowedMethods(asList("GET", "POST", "PUT", "PATCH", "DELETE"));
configuration.setAllowedHeaders(Arrays.asList(HttpHeaders.AUTHORIZATION, HttpHeaders.CACHE_CONTROL, HttpHeaders.CONTENT_TYPE, HttpHeaders.ACCEPT));
final var source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/api/**", configuration);
return source;
}
}
Here's the debug logging from the form login request:
2020-11-25 22:41:27.017 DEBUG 74979 --- [nio-8080-exec-9] o.s.security.web.FilterChainProxy : /api/v1/auth/login at position 1 of 12 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2020-11-25 22:41:27.017 DEBUG 74979 --- [nio-8080-exec-9] o.s.security.web.FilterChainProxy : /api/v1/auth/login at position 2 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2020-11-25 22:41:27.017 DEBUG 74979 --- [nio-8080-exec-9] w.c.HttpSessionSecurityContextRepository : No HttpSession currently exists
2020-11-25 22:41:27.017 DEBUG 74979 --- [nio-8080-exec-9] w.c.HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: null. A new one will be created.
2020-11-25 22:41:27.018 DEBUG 74979 --- [nio-8080-exec-9] o.s.security.web.FilterChainProxy : /api/v1/auth/login at position 3 of 12 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2020-11-25 22:41:27.018 DEBUG 74979 --- [nio-8080-exec-9] o.s.security.web.FilterChainProxy : /api/v1/auth/login at position 4 of 12 in additional filter chain; firing Filter: 'CorsFilter'
2020-11-25 22:41:27.018 DEBUG 74979 --- [nio-8080-exec-9] o.s.security.web.FilterChainProxy : /api/v1/auth/login at position 5 of 12 in additional filter chain; firing Filter: 'LogoutFilter'
2020-11-25 22:41:27.018 DEBUG 74979 --- [nio-8080-exec-9] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/api/v1/auth/login'; against '/api/v1/auth/logout'
2020-11-25 22:41:27.018 DEBUG 74979 --- [nio-8080-exec-9] o.s.security.web.FilterChainProxy : /api/v1/auth/login at position 6 of 12 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
2020-11-25 22:41:27.018 DEBUG 74979 --- [nio-8080-exec-9] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/api/v1/auth/login'; against '/api/v1/auth/login'
2020-11-25 22:41:27.018 DEBUG 74979 --- [nio-8080-exec-9] w.a.UsernamePasswordAuthenticationFilter : Request is to process authentication
2020-11-25 22:41:27.018 DEBUG 74979 --- [nio-8080-exec-9] o.s.s.authentication.ProviderManager : Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider
2020-11-25 22:41:27.145 DEBUG 74979 --- [nio-8080-exec-9] s.CompositeSessionAuthenticationStrategy : Delegating to org.springframework.security.web.authentication.session.ChangeSessionIdAuthenticationStrategy@454043bf
2020-11-25 22:41:27.145 DEBUG 74979 --- [nio-8080-exec-9] w.a.UsernamePasswordAuthenticationFilter : Authentication success. Updating SecurityContextHolder to contain: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@1fcaf72e: Principal: com.example.server.security.UserDetailsServiceImpl$UserDetailsImpl@3bd8fbc9; 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: ONBOARD
2020-11-25 22:41:27.145 DEBUG 74979 --- [nio-8080-exec-9] 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@2e14ccb
2020-11-25 22:41:27.145 DEBUG 74979 --- [nio-8080-exec-9] w.c.HttpSessionSecurityContextRepository : HttpSession being created as SecurityContext is non-default
2020-11-25 22:41:27.145 DEBUG 74979 --- [nio-8080-exec-9] w.c.HttpSessionSecurityContextRepository : SecurityContext 'org.springframework.security.core.context.SecurityContextImpl@1fcaf72e: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@1fcaf72e: Principal: com.example.server.security.UserDetailsServiceImpl$UserDetailsImpl@3bd8fbc9; 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: ONBOARD' stored to HttpSession: 'org.apache.catalina.session.StandardSessionFacade@481bcf3f
2020-11-25 22:41:27.145 DEBUG 74979 --- [nio-8080-exec-9] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
and the logs from the GET /api/v1/userAccounts/me request which follows:
2020-11-25 22:41:27.198 DEBUG 74979 --- [io-8080-exec-10] o.s.security.web.FilterChainProxy : /api/v1/userAccounts/me at position 1 of 12 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2020-11-25 22:41:27.198 DEBUG 74979 --- [io-8080-exec-10] o.s.security.web.FilterChainProxy : /api/v1/userAccounts/me at position 2 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2020-11-25 22:41:27.198 DEBUG 74979 --- [io-8080-exec-10] w.c.HttpSessionSecurityContextRepository : HttpSession returned null object for SPRING_SECURITY_CONTEXT
2020-11-25 22:41:27.198 DEBUG 74979 --- [io-8080-exec-10] w.c.HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade@6384c25. A new one will be created.
2020-11-25 22:41:27.198 DEBUG 74979 --- [io-8080-exec-10] o.s.security.web.FilterChainProxy : /api/v1/userAccounts/me at position 3 of 12 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2020-11-25 22:41:27.198 DEBUG 74979 --- [io-8080-exec-10] o.s.security.web.FilterChainProxy : /api/v1/userAccounts/me at position 4 of 12 in additional filter chain; firing Filter: 'CorsFilter'
2020-11-25 22:41:27.198 DEBUG 74979 --- [io-8080-exec-10] o.s.security.web.FilterChainProxy : /api/v1/userAccounts/me at position 5 of 12 in additional filter chain; firing Filter: 'LogoutFilter'
2020-11-25 22:41:27.198 DEBUG 74979 --- [io-8080-exec-10] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'GET /api/v1/userAccounts/me' doesn't match 'POST /api/v1/auth/logout'
2020-11-25 22:41:27.198 DEBUG 74979 --- [io-8080-exec-10] o.s.security.web.FilterChainProxy : /api/v1/userAccounts/me at position 6 of 12 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
2020-11-25 22:41:27.198 DEBUG 74979 --- [io-8080-exec-10] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'GET /api/v1/userAccounts/me' doesn't match 'POST /api/v1/auth/login'
2020-11-25 22:41:27.198 DEBUG 74979 --- [io-8080-exec-10] o.s.security.web.FilterChainProxy : /api/v1/userAccounts/me at position 7 of 12 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
2020-11-25 22:41:27.198 DEBUG 74979 --- [io-8080-exec-10] o.s.s.w.s.DefaultSavedRequest : pathInfo: both null (property equals)
2020-11-25 22:41:27.198 DEBUG 74979 --- [io-8080-exec-10] o.s.s.w.s.DefaultSavedRequest : queryString: both null (property equals)
2020-11-25 22:41:27.198 DEBUG 74979 --- [io-8080-exec-10] o.s.s.w.s.DefaultSavedRequest : requestURI: arg1=/api/v1/userAccounts/me; arg2=/api/v1/userAccounts/me (property equals)
2020-11-25 22:41:27.198 DEBUG 74979 --- [io-8080-exec-10] o.s.s.w.s.DefaultSavedRequest : serverPort: arg1=8080; arg2=8080 (property equals)
2020-11-25 22:41:27.198 DEBUG 74979 --- [io-8080-exec-10] o.s.s.w.s.DefaultSavedRequest : requestURL: arg1=http://localhost:8080/api/v1/userAccounts/me; arg2=http://localhost:8080/api/v1/userAccounts/me (property equals)
2020-11-25 22:41:27.199 DEBUG 74979 --- [io-8080-exec-10] o.s.s.w.s.DefaultSavedRequest : scheme: arg1=http; arg2=http (property equals)
2020-11-25 22:41:27.199 DEBUG 74979 --- [io-8080-exec-10] o.s.s.w.s.DefaultSavedRequest : serverName: arg1=localhost; arg2=localhost (property equals)
2020-11-25 22:41:27.199 DEBUG 74979 --- [io-8080-exec-10] o.s.s.w.s.DefaultSavedRequest : contextPath: arg1=; arg2= (property equals)
2020-11-25 22:41:27.199 DEBUG 74979 --- [io-8080-exec-10] o.s.s.w.s.DefaultSavedRequest : servletPath: arg1=/api/v1/userAccounts/me; arg2=/api/v1/userAccounts/me (property equals)
2020-11-25 22:41:27.199 DEBUG 74979 --- [io-8080-exec-10] o.s.s.w.s.HttpSessionRequestCache : Removing DefaultSavedRequest from session if present
2020-11-25 22:41:27.199 DEBUG 74979 --- [io-8080-exec-10] o.s.security.web.FilterChainProxy : /api/v1/userAccounts/me at position 8 of 12 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
2020-11-25 22:41:27.199 DEBUG 74979 --- [io-8080-exec-10] o.s.security.web.FilterChainProxy : /api/v1/userAccounts/me at position 9 of 12 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
2020-11-25 22:41:27.199 DEBUG 74979 --- [io-8080-exec-10] o.s.s.w.a.AnonymousAuthenticationFilter : Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@4c26704b: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 4ED2DAB934C3163D40A9FE32EFE26A2A; Granted Authorities: ROLE_ANONYMOUS'
2020-11-25 22:41:27.199 DEBUG 74979 --- [io-8080-exec-10] o.s.security.web.FilterChainProxy : /api/v1/userAccounts/me at position 10 of 12 in additional filter chain; firing Filter: 'SessionManagementFilter'
2020-11-25 22:41:27.199 DEBUG 74979 --- [io-8080-exec-10] o.s.security.web.FilterChainProxy : /api/v1/userAccounts/me at position 11 of 12 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
2020-11-25 22:41:27.199 DEBUG 74979 --- [io-8080-exec-10] o.s.security.web.FilterChainProxy : /api/v1/userAccounts/me at position 12 of 12 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
2020-11-25 22:41:27.200 DEBUG 74979 --- [io-8080-exec-10] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'GET /api/v1/userAccounts/me' doesn't match 'POST /api/v1/auth/logout'
2020-11-25 22:41:27.200 DEBUG 74979 --- [io-8080-exec-10] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/api/v1/userAccounts/me'; against '/api/v1/auth/**'
2020-11-25 22:41:27.200 DEBUG 74979 --- [io-8080-exec-10] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/api/v1/userAccounts/me'; against '/api/v1/reference/**'
2020-11-25 22:41:27.200 DEBUG 74979 --- [io-8080-exec-10] o.s.s.w.a.i.FilterSecurityInterceptor : Secure object: FilterInvocation: URL: /api/v1/userAccounts/me; Attributes: [authenticated]
2020-11-25 22:41:27.200 DEBUG 74979 --- [io-8080-exec-10] o.s.s.w.a.i.FilterSecurityInterceptor : Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@4c26704b: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 4ED2DAB934C3163D40A9FE32EFE26A2A; Granted Authorities: ROLE_ANONYMOUS
2020-11-25 22:41:27.200 DEBUG 74979 --- [io-8080-exec-10] o.s.s.access.vote.AffirmativeBased : Voter: org.springframework.security.web.access.expression.WebExpressionVoter@1970e63, returned: -1
2020-11-25 22:41:27.201 DEBUG 74979 --- [io-8080-exec-10] o.s.s.w.a.ExceptionTranslationFilter : Access is denied (user is anonymous); redirecting to authentication entry point
Any idea why the request is being considered anonymous?