fsk5304
fsk5304

Reputation: 455

Spring Security without the WebSecurityConfigurerAdapter

I am trying to update to Spring Boot 2.7.0-SNAPSHOT. WebSecurityConfigurerAdapter is deprecated in this version.

Old WebSecurityConfig with WebSecurityConfigurerAdapter (working fine):

/**
 * SecurityConfig
 *
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;

    @Autowired
    private CustomAuthenticationFailureHandler customAuthenticationFailureHandler;

    @Autowired
    private OAuth2AuthenticationSuccessHandler oAuth2AuthenticationSuccessHandler;

    @Autowired
    private OAuth2AuthenticationFailureHandler oAuth2AuthenticationFailureHandler;

    @Autowired
    private OAuth2UserServiceImpl oAuth2UserServiceImpl;

    /**
     * for development
     * 
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        // for development
        return NoOpPasswordEncoder.getInstance();
    }

    @Override
    public void configure(WebSecurity web) {
        // ignoring
        web.ignoring().antMatchers("/css/**", "/js/**", "/img/**", "/lib/**", "/favicon.ico", "/oauth2");
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {

        http.authorizeRequests().antMatchers("/", "/login", "/error", "/message/**").permitAll();
        http.authorizeRequests().anyRequest().authenticated();
        http.formLogin();
        http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint("/login"));
        http.addFilterBefore(authenticationFilter(), UsernamePasswordAuthenticationFilter.class);

        // OAuth2
        http.oauth2Login().loginPage("/").defaultSuccessUrl("/home", false);
        http.oauth2Login().userInfoEndpoint().userService(oAuth2UserServiceImpl);
        http.oauth2Login().successHandler(oAuth2AuthenticationSuccessHandler);
        http.oauth2Login().failureHandler(oAuth2AuthenticationFailureHandler);


        http.logout().logoutUrl("/logout").logoutSuccessUrl("/login").deleteCookies("JSESSIONID");

        http.csrf().disable();

        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
                .enableSessionUrlRewriting(false);
    }

    private MyAuthenticationFilter authenticationFilter() throws Exception {
        MyAuthenticationFilter filter = new MyAuthenticationFilter();
        filter.setAuthenticationManager(authenticationManagerBean());
        filter.setAuthenticationSuccessHandler(customAuthenticationSuccessHandler);
        filter.setAuthenticationFailureHandler(customAuthenticationFailureHandler);

        filter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/authentication", "POST"));
        return filter;
    }

    private AuthenticationEntryPoint authenticationEntryPoint(String loginFormUrl) {
        return new MyLoginUrlAuthenticationEntryPoint(loginFormUrl);
    }

}

After reading this blog post, I have modified the new WebSecurityConfig:

/**
 * SecurityConfig
 *
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig {

    @Autowired
    private CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;

    @Autowired
    private CustomAuthenticationFailureHandler customAuthenticationFailureHandler;

    @Autowired
    private OAuth2AuthenticationSuccessHandler oAuth2AuthenticationSuccessHandler;

    @Autowired
    private OAuth2AuthenticationFailureHandler oAuth2AuthenticationFailureHandler;

    @Autowired
    private OAuth2UserServiceImpl oAuth2UserServiceImpl;

    /**
     * for development
     * 
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        // for development
        return NoOpPasswordEncoder.getInstance();
    }

    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return (web) -> web.ignoring().antMatchers(
                "/css/**", "/js/**", "/img/**", "/lib/**", "/favicon.ico", "/oauth2");
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

        http.authorizeRequests().antMatchers("/", "/login", "/error", "/message/**").permitAll();
        http.authorizeRequests().anyRequest().authenticated();
        http.formLogin();
        http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint("/login"));
        http.addFilterBefore(authenticationFilter(), UsernamePasswordAuthenticationFilter.class);

        // OAuth2
        http.oauth2Login().loginPage("/").defaultSuccessUrl("/home", false);
        http.oauth2Login().userInfoEndpoint().userService(oAuth2UserServiceImpl);
        http.oauth2Login().successHandler(oAuth2AuthenticationSuccessHandler);
        http.oauth2Login().failureHandler(oAuth2AuthenticationFailureHandler);

        http.logout().logoutUrl("/logout").logoutSuccessUrl("/login").deleteCookies("JSESSIONID");

        http.csrf().disable();

        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
                .enableSessionUrlRewriting(false);

        return http.build();
    }

    private MyAuthenticationFilter authenticationFilter() throws Exception {
        MyAuthenticationFilter filter = new MyAuthenticationFilter();

        // How can I fix this? ------------------------------------------
        filter.setAuthenticationManager(authenticationManagerBean());
        // --------------------------------------------------------------

        filter.setAuthenticationSuccessHandler(customAuthenticationSuccessHandler);
        filter.setAuthenticationFailureHandler(customAuthenticationFailureHandler);
        filter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/authentication", "POST"));
        return filter;
    }

    private AuthenticationEntryPoint authenticationEntryPoint(String loginFormUrl) {
        return new MyLoginUrlAuthenticationEntryPoint(loginFormUrl);
    }

}

I was able to fix two methods. (#configure(WebSecurity web) and #configure(HttpSecurity http))

However, I can't figure out how to fix authenticationManagerBean(). Where do I get the AuthenticationManager from?

Upvotes: 15

Views: 16625

Answers (3)

Tran Tai
Tran Tai

Reputation: 181

Here's the entire class that took me day to configure. Hope it could save your time.

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class ApplicationSecurityConfig {

    private final UserDetailsService userService;
    private final AuthenticationConfiguration configuration;
    
    @Bean
    SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        AbstractAuthenticationProcessingFilter filter = new CustomizedAuthenticationFilter(authenticationManager());
        filter.setFilterProcessesUrl("/api/login");
        http.csrf().disable();
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        http.authorizeRequests().antMatchers(HttpMethod.POST, "/api/login").permitAll();
        http.authorizeRequests().anyRequest().authenticated();
        http.addFilter(filter);
        
        return http.build();
    }

    @Bean
    AuthenticationManager authenticationManager() throws Exception {
        return configuration.getAuthenticationManager();
    }
    
    @Autowired
    void configure(AuthenticationManagerBuilder builder) throws Exception {
        builder.userDetailsService(userService).passwordEncoder(new BCryptPasswordEncoder());
    }
}

Upvotes: 9

Andrei Daneliuc
Andrei Daneliuc

Reputation: 294

If you want to inject AuthenticationManager into other spring components, you can use the following configuration.

@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
     return authenticationConfiguration.getAuthenticationManager();
}

This approach has solved the problem for me and you can inject AuthenticationManager wherever you need.

EDIT:

@EnableWebSecurity
@RequiredArgsConstructor
public class SpringSecurityConfiguration  {
    private final AuthenticationConfiguration authenticationConfiguration;

    @Bean
    public AuthenticationManager authenticationManager() throws Exception 
    {
        return authenticationConfiguration.getAuthenticationManager();
    }

Upvotes: 1

You can create a custom DSL. This is actually how Spring Security works internally.

public class MyCustomDsl extends AbstractHttpConfigurer<MyCustomDsl, HttpSecurity> {
    @Override
    public void configure(HttpSecurity http) throws Exception {
        AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class);
        http.addFilterBefore(new MyAuthenticationFilter(authenticationManager), UsernamePasswordAuthenticationFilter.class);
    }

    public static MyCustomDsl customDsl() {
        return new MyCustomDsl();
    }
}

Then you can apply the custom DSL when building the SecurityFilterChain:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    // ...
    http.apply(customDsl());
    return http.build();
}

Upvotes: 4

Related Questions