I have a fairly simplistic Spring Security configuration in my Spring MVC web app. I am receiving REST requests from a remote web application that get authenticated through my preauth filter. I simply look for a header in the request, and if present, I return that String value (which is the username) as the authentication object. This works fine and when a request comes in, the user gets authenticated.
For whatever reason, any time I attempt to enforce a pattern-based security antMatcher or controller method annotated security, it results in the client getting a CORS error. I have to keep the access fully open to allow the actual request to take place in this cross-domain environment.
My issue is, after a while, the session seems to expire. When a user hits one of my controllers and I try to get the username from the Principal object, I get a NullPointerException because the Principal is null. Once it expires, it looks like the AnonymousAuthFilter kicks in and just lets the user connect as anonymous.
I'm assuming I don't want a completely stateless authentication session, because I'm also using the session for websockets, and when I use my messaging template to "convertAndSendToUser", I need to provide the username and Spring needs to lookup the websocket session. However, I would like to force the security chain to recognize if the incoming request does not have a principal assigned, to force the request back through my PreAuthFilter and re-establish the session.
Is this possible?
Here is a quick rundown of my configure method in my security config file:
@Override
protected void configure(HttpSecurity http) throws Exception {
// Create authentication providers and authentication manager
List<AuthenticationProvider> authenticationProviders = new ArrayList<>(1);
AuthenticationProvider authProvider = preAuthenticatedAuthenticationProvider();
authenticationProviders.add(authProvider);
AuthenticationManager authenticationManager = authenticationManager(authenticationProviders);
// Create the pre-authentication filter
MyPreAuthFilter myPreAuthFilter = myPreAuthFilter(authenticationManager);
myPreAuthFilter.setAuthenticationManager(authenticationManager);
// configure http security
http
.csrf().disable()
.headers().addHeaderWriter(new XFrameOptionsHeaderWriter(XFrameOptionsHeaderWriter.XFrameOptionsMode.SAMEORIGIN))
.and()
.authenticationProvider(authProvider)
.addFilter(myPreAuthFilter)
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.antMatchers("/stomp/**").permitAll()
.antMatchers("/**").permitAll();
}
UPDATE: So I just learned about this method on the http object:
.anonymous().disable()
However, when I use that, all my CORS requests fail again. I think the issue is specifically the preflight OPTIONS requests. This can't be authenticated -- it needs to be anonymously accessible. So I think to get the behavior I want out of my cross-domain authentication, I need to disable the anonymous filter, but doing so breaks one of the key tenants of being able to perform cross-domain requests. Ugh. Anybody know how to disable anonymous for all requests besides OPTIONS?