I have a Java Spring rest api with Waffle authentication.
Here is my code.
@Configuration
public class WaffleConfig {
@Bean
public WindowsAuthProviderImpl waffleWindowsAuthProvider() {
return new WindowsAuthProviderImpl();
}
@Bean
public NegotiateSecurityFilterProvider negotiateSecurityFilterProvider(
WindowsAuthProviderImpl windowsAuthProvider) {
return new NegotiateSecurityFilterProvider(windowsAuthProvider);
}
@Bean
public BasicSecurityFilterProvider basicSecurityFilterProvider(
WindowsAuthProviderImpl windowsAuthProvider) {
return new BasicSecurityFilterProvider(windowsAuthProvider);
}
@Bean
public SecurityFilterProviderCollection waffleSecurityFilterProviderCollection(
NegotiateSecurityFilterProvider negotiateSecurityFilterProvider,
BasicSecurityFilterProvider basicSecurityFilterProvider) {
SecurityFilterProvider[] securityFilterProviders =
{negotiateSecurityFilterProvider, basicSecurityFilterProvider};
return new SecurityFilterProviderCollection(securityFilterProviders);
}
@Bean
public NegotiateSecurityFilterEntryPoint negotiateSecurityFilterEntryPoint(
SecurityFilterProviderCollection securityFilterProviderCollection) {
NegotiateSecurityFilterEntryPoint negotiateSecurityFilterEntryPoint =
new NegotiateSecurityFilterEntryPoint();
negotiateSecurityFilterEntryPoint.setProvider(securityFilterProviderCollection);
return negotiateSecurityFilterEntryPoint;
}
@Bean
public NegotiateSecurityFilter waffleNegotiateSecurityFilter(
SecurityFilterProviderCollection securityFilterProviderCollection) {
NegotiateSecurityFilter negotiateSecurityFilter = new NegotiateSecurityFilter();
negotiateSecurityFilter.setProvider(securityFilterProviderCollection);
return negotiateSecurityFilter;
}
// This is required for Spring Boot so it does not register the same filter twice
@Bean
public FilterRegistrationBean waffleNegotiateSecurityFilterRegistration(
NegotiateSecurityFilter waffleNegotiateSecurityFilter) {
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(waffleNegotiateSecurityFilter);
registrationBean.setEnabled(false);
return registrationBean;
}
}
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private NegotiateSecurityFilter negotiateSecurityFilter;
@Autowired
private NegotiateSecurityFilterEntryPoint entryPoint;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.addFilterBefore(negotiateSecurityFilter, BasicAuthenticationFilter.class)
.headers()
.addHeaderWriter(new StaticHeadersWriter("Access-Control-Allow-Credentials", "true"))
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS); // Disable session creation;
http.cors();
}
@Override
@Autowired
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication();
}
}
@GetMapping(value="/abc", produces = "application/json")
public ResponseEntity<<abc>> getAbc(){
....
}
When calling getAbc controller method from the angular frontend, it doesn't even gets to the breakpoint in the first line of the method.
Before that I get the following error:
[DEBUG] 2023-10-25 16:05:47.999 [http-nio-8080-exec-1] FilterChainProxy - Securing GET /abc
[DEBUG] 2023-10-25 16:05:48.003 [http-nio-8080-exec-1] SecurityContextPersistenceFilter - Set SecurityContextHolder to empty SecurityContext
[DEBUG] 2023-10-25 16:05:48.027 [http-nio-8080-exec-1] AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
[DEBUG] 2023-10-25 16:05:48.038 [http-nio-8080-exec-1] FilterSecurityInterceptor - Failed to authorize filter invocation [GET /abc] with attributes [authenticated]
[DEBUG] 2023-10-25 16:05:48.039 [http-nio-8080-exec-1] Http403ForbiddenEntryPoint - Pre-authenticated entry point called. Rejecting access
[DEBUG] 2023-10-25 16:05:48.041 [http-nio-8080-exec-1] SecurityContextPersistenceFilter - Cleared SecurityContextHolder to complete request
[DEBUG] 2023-10-25 16:05:48.045 [http-nio-8080-exec-1] FilterChainProxy - Securing GET /error
[DEBUG] 2023-10-25 16:05:48.045 [http-nio-8080-exec-1] SecurityContextPersistenceFilter - Set SecurityContextHolder to empty SecurityContext
[DEBUG] 2023-10-25 16:05:48.045 [http-nio-8080-exec-1] AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
[DEBUG] 2023-10-25 16:05:48.046 [http-nio-8080-exec-1] FilterChainProxy - Secured GET /error
[DEBUG] 2023-10-25 16:05:48.056 [http-nio-8080-exec-1] DefaultWebInvocationPrivilegeEvaluator - filter invocation [/error] denied for AnonymousAuthenticationToken [Principal=anonymousUser, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[ROLE_ANONYMOUS]]
org.springframework.security.access.AccessDeniedException: Access is denied
If I change the configure method to add .httpBasic authorization like in the code below, it enters the controller method and successfully authenticates the user.
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.httpBasic()
.authenticationEntryPoint(entryPoint)
.and()
.addFilterBefore(negotiateSecurityFilter, BasicAuthenticationFilter.class)
.headers()
.addHeaderWriter(new StaticHeadersWriter("Access-Control-Allow-Credentials", "true"));
http.cors();
}
But then I incur in a different issue that I reported here:
How to remove Firefox basic authentication window in a Java, Angular, Waffle application?
So that is the reason I would like to make it work without basic authentication now. Like in the first version of the configure method I mentioned above.