spring-securityjava-17spring-oauth2spring-authorization-server

Issue with authenticationManager in Spring SecurityConfig Authorization Server


for some reason the authenticationManager is not being added to the context, that's what I imagine, because I'm getting an error: "Factory method 'authorizationServerSecurityFilterChain' threw exception with message: authenticationManager cannot be null"

I've tried to add the line, but I get that authenticationManager as a parameter cannot be resolved symbol.

http.authenticationManager(authenticationManager);

I don't know if I'm forgetting to do something in this spring security oauth configuration. The Authorization server version (1.4.1) spring boot (3.4.2) and Java 17. I appreciate any help.

public class SecurityConfig {
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public UserDetailsService userDetailsService(UserRepository userRepository) {
        return new CustomUserDetailsService(userRepository);
    }

    @Bean
    public AuthenticationManager authenticationManager(
            UserDetailsService userDetailsService,
            PasswordEncoder passwordEncoder) {
        DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
        authProvider.setUserDetailsService(userDetailsService);
        authProvider.setPasswordEncoder(passwordEncoder);

        return new ProviderManager(authProvider);
    }

    @Bean
    @Order(1)
    public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
        OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =
                new OAuth2AuthorizationServerConfigurer();

        http.securityMatcher(authorizationServerConfigurer.getEndpointsMatcher())
                .authorizeHttpRequests(authorize -> authorize.anyRequest().authenticated())
                .csrf(AbstractHttpConfigurer::disable)
                .formLogin(Customizer.withDefaults());

        authorizationServerConfigurer.configure(http);

        return http.build();
    }

    @Bean
    @Order(2)
    public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests(authorize -> authorize
                        .requestMatchers("/api/auth/register").permitAll()
                        .anyRequest().authenticated()
                )
                .csrf(csrf -> csrf.ignoringRequestMatchers("/api/auth/register"))
                .formLogin(AbstractHttpConfigurer::disable)
                .httpBasic(AbstractHttpConfigurer::disable);

        return http.build();
    }
    ... more code


Solution

  • I can't see that I have a custom AuthenticationManager bean in my authorization server.

    I suspect there might be several issues here, but let's start with what I have and see if you can use that as a base. Code is based on this part of Spring Authorization Server docs.

    import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
    import org.springframework.boot.actuate.health.HealthEndpoint;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.annotation.Order;
    import org.springframework.http.MediaType;
    import org.springframework.security.config.Customizer;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
    import org.springframework.security.web.SecurityFilterChain;
    import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
    import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
    
    @Configuration
    public class SecurityConfig {
    
        @Bean
        public PasswordEncoder passwordEncoder() {
            return new BCryptPasswordEncoder();
        }
    
        @Bean
        @Order(1)
        public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
            var authorizationServerConfigurer =
                    OAuth2AuthorizationServerConfigurer.authorizationServer();
    
            http
                    .securityMatcher(authorizationServerConfigurer.getEndpointsMatcher())
                    .with(authorizationServerConfigurer, authorizationServer ->
                            authorizationServer.oidc(Customizer.withDefaults())
                    )
                    .authorizeHttpRequests(authorize ->
                            authorize.anyRequest().authenticated()
                    )
                    // Redirect to the login page when not authenticated from the
                    // authorization endpoint
                    .exceptionHandling(exceptions -> exceptions
                            .defaultAuthenticationEntryPointFor(
                                    new LoginUrlAuthenticationEntryPoint("/login"),
                                    new MediaTypeRequestMatcher(MediaType.TEXT_HTML)
                            )
                    );
    
            return http.build();
        }
    
        @Bean
        @Order(2)
        public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
            http
                    .authorizeHttpRequests(authorize -> authorize
                            // remove this if you don't have actuator endpoints
                            .requestMatchers(EndpointRequest.to(HealthEndpoint.class)).permitAll()
                            .anyRequest().authenticated()
                    )
                    // replace this with your URL
                    .logout(logout -> logout.logoutSuccessUrl("http://localhost:3000/"))
                    .formLogin(Customizer.withDefaults());
    
            return http.build();
        }
    }