no header added with addHeaderWriter in WebSecurityConfigurerAdapter - spring-security

I'd like to add a custom header in my Responses, but the following doesn't add anything to my responses:
#EnableWebSecurity
#Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.headers()
.addHeaderWriter(new StaticHeadersWriter("Salut","c'est Chico"));
}
}
However I've followed Spring documentation: https://docs.spring.io/spring-security/site/docs/current/reference/html/headers.html
Thanks for your help !
PS: the debugger well enters in addHeaderWriter()

Related

How to add an additional AuthenticationProvider without using WebSecurityConfigurerAdapter

Prior to Spring Security 5.7 it was possible to add additional AuthenticationProviders to the global AuthenticationManager this way:
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
...
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(customAuthenticationProvider);
}
}
With Spring Security 5.7 the WebSecurityConfigurerAdapter was deprecated.
Question: ho should i migrate this code to solve the deprecation?
When i try to register the additional AuthenticationProvider as #Bean, the autocreated authentication provider for username/password based authentication gets replaced, leading to
No AuthenticationProvider found for org.springframework.security.authentication.UsernamePasswordAuthenticationToken
I read the blog post https://spring.io/blog/2022/02/21/spring-security-without-the-websecurityconfigureradapter but found no hints about adding additional authentication providers to the global AuthenticationManager.
If you have a single AuthenticationProvider you can register it as a bean and it will be picked up by Spring Security:
#Bean
public CustomAuthenticationProvider customAuthenticationProvider() {
return new CustomAuthenticationProvider();
}
Alternatively, you can add additional AuthenticationProviders in the HttpSecurity configuration:
#Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
// ...
.authenticationProvider(new CustomAuthenticationProvider());
return http.build();
}
You can annotate your configuration class with #EnableGlobalAuthentication and will be able to configure a global instance of AuthenticationManagerBuilder:
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(customAuthenticationProvider);
}
Please see the related documentation: https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/config/annotation/authentication/configuration/EnableGlobalAuthentication.html
I had a same problem when I want to add an custom AuthenticationProvider using Spring Security without WebSecurityConfigurerAdapter.
Here is what I did.
Code with WebSecurityConfigurerAdapter
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
...
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(customAuthenticationProvider);
}
}
Code without WebSecurityConfigurerAdapter
#EnableWebSecurity
#EnableGlobalAuthentication
public class SecurityConfiguration {
...
#Autowired
CustomAuthenticationProvider customAuthenticationProvider;
#Autowired
void registerProvider(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(customAuthenticationProvider);
}
}
Note: #EnableGlobalAuthentication and registerProvider().
Hope this will help.
I had a similar problem. I have a custom user details service and I also use an additional custom authentication provider. One is for actual users and the custom provider is for automated devices.
This is my code with the WebSecurityConfigurerAdapter:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
...
#Autowired
private MyCustomAuthenticationProvider customAuthenticationProvider;
#Autowired
private UserDetailsService userDetailsService;
...
#Bean
PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
var encoder = passwordEncoder();
customAuthenticationProvider.encoder(encoder);
auth.userDetailsService(userDetailsService).passwordEncoder(encoder);
auth.authenticationProvider(customAuthenticationProvider);
}
...
}
This is my code without the WebSecurityConfigurerAdapter:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration {
...
#Autowired
private MyCustomAuthenticationProvider customAuthenticationProvider;
#Autowired
private UserDetailsService userDetailsService;
...
#Bean
PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
#Bean
AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
var encoder = passwordEncoder();
customAuthenticationProvider.encoder(encoder);
auth.userDetailsService(userDetailsService).passwordEncoder(encoder);
auth.authenticationProvider(customAuthenticationProvider);
}
...
}
note: you might need to set spring.main.allow-circular-references to true in your properties file for this to work.

Can not disable spring security with userdetailservice autoconfig?

I have this HTTP config and some restful API to test login and register in the database but it always got "Unauthorized". But I disabled it? Why? pls, help.
#Configuration
#EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.anonymous().authorities("ROLE_ANONYMOUS")
.and()
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/**").permitAll();
}
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/**");
}
}
I added this #SpringBootApplication(exclude = {SecurityAutoConfiguration.class }) to main void then the issue resolve.

#ManagementContextConfiguration usage with WebSecurityConfigurerAdapter doesn't work

I have a working Spring Boot 1.x application, configured with different management port and security (Basic Auth).
After migration to Spring 2.1 it is not working anymore.
See the code:
#ManagementContextConfiguration
public class ManagementConfig {
#EnableWebSecurity
#Order(SecurityProperties.BASIC_AUTH_ORDER)
static class SecurityConfig extends WebSecurityConfigurerAdapter {
public SecurityConfig() {
super(true); // disable defaults
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
auth.inMemoryAuthentication()
.withUser("admin")
.password(encoder.encode("admin"))
.roles(Collections.emptyList().toArray(new String[]{}));
}
#Override
protected void configure(HttpSecurity http) throws Exception {
RequestMatcher matcher = new AntPathRequestMatcher("/**");
http
.authorizeRequests()
.requestMatchers(matcher).authenticated();
}
}
}
My spring.factories contains
org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration=\
com.test.config.ManagementConfig
During begugging, I can see that SecurityConfig instance created, but no configure() method called (as I see, there was a post-processor call in Spring Boot 1.x after ManagementConfig created...).
My application.yml contains:
management.server:
address: localhost
port: 18543
security:
enabled: true
The problem with it, that I can access any management endpoint now with simple
curl http://localhost:18543/info
I've solved this issue with separating
#ManagementContextConfiguration
and
#EnableWebSecurity
into 2 different file.

Using multiple WebSecurityConfigurerAdapter in spring boot

I'm having 2 classes which extends WebSecurityConfigurerAdapter. And can't make them work together.
The idea is as follows:
Have one WebSecurityConfigurerAdapter which only adds custom filter to security chain. The filter does some custom authentication and saves Authentication into SecurityContext. This generally works fine. Configured as follows (imports omitted):
#Order(1)
#Configuration
#EnableWebMvcSecurity
public class BestSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private BestPreAuthenticationFilter ssoAuthenticationFilter;
#Bean
protected FilterRegistrationBean getSSOAuthenticationFilter() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(ssoAuthenticationFilter);
// Avoid include to the default chain
filterRegistrationBean.setEnabled(false);
return filterRegistrationBean;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilterAfter(ssoAuthenticationFilter, SecurityContextPersistenceFilter.class);
}
#Configuration
protected static class AuthenticationConfiguration extends
GlobalAuthenticationConfigurerAdapter {
#Autowired
private BestAuthenticationProvider authenticationProvider;
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider);
}
}
}
I want the above to be kind of library class which anyone can include via #ComponentScan and get the custom authentication sorted. Obviously they want to provide custom HttpSecurity to secure edpoints. Trying something like:
#Configuration
#EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/testUrl").hasRole("NON_EXISTING")
.anyRequest().authenticated();
}
}
Obviously the test URL should not be accessible as my user is not member of role NON_EXISTING. Unfortunatelly she is.
If I move the security authorizeRequests() part to the configuration class form 1. next to adding the security filter then it blocks the access as expected. But in my case it looks like the second configuration is ignored.
I also debugged the configure() methods and noticed that HttpSecurity is not the same object which smells a bit.
Any tips how can I make this work much appreciated.
Sum up of the goal:
have one WebSecurityConfigurerAdapter which adds the filter and is hidden from the user of the library
let the user define her own custom endpoint security
Spring boot 1.1.6-RELEASE
Define a special interface
public interface ServiceWebSecurityConfigurer {
void configure(HttpSecurity http) throws Exception;
}
Then have just one ConfigurerAdapter:
public class MyConfigurerAdapter extends WebSecurityConfigurerAdapter {
#Autowired(required = false)
ServiceWebSecurityConfigurer serviceSecConfig;
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests(). // whatever
if (serviceSecConfig != null) serviceSecConfig.configure(http);
http.authorizeRequests(). // whatever
}
}
and then just implement ServiceWebSecurityConfigurer elsewhere when needed. There can be multiple implementations as well, just autowire them as list and iterate and use them all in your main configuration.
So one option I just found is:
Remove the #Configuration annotation from the first bean
And change the 2. to:
#Configuration
#EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfig extends BestSecurityConfig { //Note the changed extend !
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http); // Merge of the 2 HTTP configurations
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/testUrl").hasRole("NON_EXISTING")
.anyRequest().authenticated();
}
}
Any comments on whether this is right or wrong approach much appreciated
Edit: After few years I still didn't find other way but I like this way more and more. Even in the default case you extend the abstract WebSecurityConfigurerAdapter there is no reason why some other layer of abstraction can't provide another abstract extension which provides meaningful defaults.
I founded (in my opinion) a cleaner way of structuring some default configurations and make it simple to integrate in new projects by using Custom DSLs.
I'm using it to config JWT authentication filters, but i think a CORS filter is more simple and didactic:
public class CustomCorsFilterDsl extends AbstractHttpConfigurer<CustomCorsFilterDsl, HttpSecurity> {
#Override
public void init(HttpSecurity http) throws Exception {
//your init code here, no needed in this case
}
#Override
public void configure(HttpSecurity http) throws Exception {
CorsFilter corsFilter = corsFilter(corsProperties);
http.addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class);
}
private CorsFilter corsFilter(CorsProperties corsProperties) {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("http://localhost:9000");
config.addAllowedHeader("*");
config.addAllowedMethod("GET, POST, PUT, PATCH, DELETE");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
public static CustomCorsFilterDsl dsl() {
return new CustomCorsFilterDsl();
}
}
And in your WebSecurityConfig you can use it like this:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.exceptionHandling()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/foo/**").permitAll()
//... your configurations
.antMatchers("/**").authenticated()
.and()
.apply(CustomCorsFilterDsl.dsl());
}
}
And you accomplished your objective of having libraries with default configurations independent of your projects code, in a more clear way, because you can visualize in the project's WebSecurityConfig a custom CORS entry.

spring-security with spring-boot configuration

I have a Spring-boot app that is using Spring-security, configured with Java-config. Ideally, I will have a customer UserDetailsService so I can add/modify users. Until then I am failing to configure this correctly.
I am using the following dependencies:
compile("org.springframework.boot:spring-boot-starter-web:1.1.1.RELEASE")
compile("org.springframework.boot:spring-boot:1.0.1.RELEASE")
compile("org.springframework.boot:spring-boot-starter-thymeleaf")
compile("org.springframework.boot:spring-boot-starter-data-jpa:1.1.1.RELEASE")
compile("org.springframework.security:spring-security-web:4.0.0.M1")
compile("org.springframework.security:spring-security-config:4.0.0.M1")
I have the following Configurations
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
#Configuration
#EnableWebMvcSecurity
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {
#Autowired
private DataSource datasource;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/resources/**").permitAll()
.antMatchers("/css/**").permitAll();
http
.formLogin().failureUrl("/login?error")
.defaultSuccessUrl("/")
.loginPage("/login")
.permitAll()
.and()
.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/")
.permitAll();
http
.authorizeRequests().anyRequest().authenticated();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
JdbcUserDetailsManager userDetailsService = jdbcUserService();
// userDetailsService.setDataSource(datasource);
// PasswordEncoder encoder = new BCryptPasswordEncoder();
auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
auth.jdbcAuthentication().dataSource(datasource);
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public org.springframework.security.provisioning.JdbcUserDetailsManager jdbcUserService() throws Exception {
JdbcUserDetailsManager jdbcUserDetailsManager = new JdbcUserDetailsManager();
jdbcUserDetailsManager.setDataSource(datasource);
jdbcUserDetailsManager.setAuthenticationManager(authenticationManagerBean());
return jdbcUserDetailsManager;
}
}
#Order(Ordered.HIGHEST_PRECEDENCE)
#Configuration
public class AuthenticationSecurity extends GlobalAuthenticationConfigurerAdapter {
#Autowired
private DataSource dataSource;
#Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth
.jdbcAuthentication()
.dataSource( dataSource );
}
}
So, I realize that my configurations are wrong but not really sure how to best fix them. The symptoms are that when I log into my Thymeleaf UI, the session never exires.
I have used various online resources for my spring-security learning & implementation. Unfortunately, I am still not grasping why this is not correct.
You appear to be configuring 3 filter chains (3 WebSecurityConfigurerAdapters) but only one of them configures the HttpSecurity. That's probably not what you intended to do. Maybe consolidate down to WebSecurityConfigurerAdapter and one GlobalAuthenticationConfigurerAdapter and see where it gets you.

Resources