1

I have a java application build on spring boot 3 and I have a simple security configuration like this:

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {

    private static final String[] permitMethods = new String[]{
            "/api/games/**",
            "/swagger-ui/**",
            "/v3/api-docs/**",
            "/actuator/**"
    };

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .csrf(csrf -> csrf.disable())
                .authorizeRequests(authorizeRequests ->
                        authorizeRequests
                                .requestMatchers(permitMethods).permitAll()
                                .anyRequest().authenticated()
                )
                .userDetailsService(userDetailsService())
                .httpBasic(Customizer.withDefaults());
        return http.build();
    }
    @Bean
    public UserDetailsService userDetailsService() {
        UserDetails user = User.withDefaultPasswordEncoder()
                .username("admin")
                .password("admin")
                .build();
        return new CachingUserDetailsService(new InMemoryUserDetailsManager(user));
    }

}

The problem is that current application uses too much CPU over 70% while executing stress test. When I am removing .httpBasic(Customizer.withDefaults());

CPU usage goes down to 10%. I am executing stress test just with 40 parallel threads, the more parallel threads I set the more CPU usage becomes.

I am currently using spring boot 3.1.1 version but I have tried it on spring boot 3.0.0 version as well, but the result was same.

Do you have any ideas how can I minimize CPU usage with the basic authentication ?

Gog1nA
  • 376
  • 1
  • 8
  • 30
  • i run your code with new project and it consumes 0 cpu usage, do you have any other detail that might cause it? – Mohammed Fataka Jul 17 '23 at 13:30
  • Make sure you are sending requests for the methods which are secured and doesn't match to the "permitMethods" – Gog1nA Jul 17 '23 at 13:33
  • Enable profiling and figure out where the hotspot is else you will be only guessing. One thing is I would remove the `CachingUserDetailsService` as the default doesn't cache but only adds additional overhead of calling a noop cache. Also make sure you don't have TRACE or DEBUG logging enabled while you are running the tests as logging will severly impact your test results! – M. Deinum Jul 17 '23 at 13:37

1 Answers1

1

the issue is simple, the cause of high cpu is in your password encoder specifically at line which is UserDetails user = User.withDefaultPasswordEncoder() now at the stage if u go to the implantation of it, you can see it uses ByCrypt algorithm for encoding passwords, and ByCrypt is expensive for CPU, since it does hashing in many iterations, you can check how bycrypt works to understand more about how it works.

you can verify that the issue is bycrpt and not httbasic by doing following:

define bean password encoder:

@Bean
    public PasswordEncoder bCryptPasswordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }

and here try use plain text passwords!

also for registring users use

UserDetails user = User.builder()
                .username("admin")
                .password("admin")
                .build();

now that you know the issue what can you do? you can alter some bycrypt functionalities which is available when you define BCryptPasswordEncoder as bean(check constructor). like below:

@Bean
    public PasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder(strenght_number_that_suits_for_you);
    }

or you can use faster hashing algorithm for spring security you can check implemented classes of PasswordEncoder interface

also you can check some other related questions that might help you more like: this or this

Mohammed Fataka
  • 150
  • 1
  • 8
  • I just solved the issue with the method you just mentioned, I have set 4 as "Strength" and CPU usage is average 20%. here you just need to set encrypted password like this ```.password(bCryptPasswordEncoder("admin"))``` – Gog1nA Jul 17 '23 at 14:24