Search code examples
spring-bootspring-securityspring-boot-admin

Spring Boot Admin UI login redirects either back to login page either to a "variables.css" file


Recently I have integrated Spring Boot Admin in my application. Everything fine, until I've stared adding security (nothing complicated, just Basic Auth). When I try to login in Spring Boot Admin UI, it redirects me back to the login page with "Login required to access the resource (Error: 401).", or to "variables.css". I am using Spring Boot 3.0.0 with Spring Boot Admin version 3.0.0-M6. I have to mention that everything works alright if I disable spring security.

Security Config class looks like this:

@Configuration(proxyBeanMethods = false)
@EnableWebSecurity
@AllArgsConstructor
public class AdminSecurityConfig {
    private final AdminServerProperties adminServerProperties;
    private final SecurityProperties securityProperties;
    private final AuthenticationConfiguration authenticationConfiguration;

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
        successHandler.setTargetUrlParameter("redirectTo");
        successHandler.setDefaultTargetUrl(this.adminServerProperties.path("/"));
        http
                .authorizeHttpRequests(
                        (authorizeRequests) ->
                                authorizeRequests.requestMatchers(this.adminServerProperties.path("/assets/**")).permitAll()
                                        .requestMatchers(this.adminServerProperties.path("/*.css")).permitAll()
                                        .requestMatchers(this.adminServerProperties.path("/actuator/info")).permitAll()
                                        .requestMatchers(this.adminServerProperties.path("/actuator/health")).permitAll()
                                        .requestMatchers(this.adminServerProperties.path("/login")).permitAll()
                                        .anyRequest().authenticated()
                ).formLogin(
                        (formLogin) -> formLogin.loginPage(this.adminServerProperties.path("/login")).successHandler(successHandler).and()
                ).logout((logout) -> logout.logoutUrl(this.adminServerProperties.path("/logout")))
                .httpBasic(Customizer.withDefaults())
                .csrf(
                        (csrf) -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
                                .ignoringRequestMatchers(
                                        new AntPathRequestMatcher(this.adminServerProperties.path("/instances"),
                                                HttpMethod.POST.name()),
                                        new AntPathRequestMatcher(this.adminServerProperties.path("/instances/*"),
                                                HttpMethod.DELETE.name()),
                                        new AntPathRequestMatcher(this.adminServerProperties.path("/actuator/**"))
                                ));
        return http.build();
    }

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

    @Bean
    public UserDetailsService userDetailsService() {
        UserDetails user =
                User.withUsername(securityProperties.getUser().getName())
                        .password("{noop}" + securityProperties.getUser().getPassword())
                        .roles("USER")
                        .build();
        return new InMemoryUserDetailsManager(user);
    }

also, I have added this in the application.yaml file


spring:
  security:
    user:
      name: ****
      password: ****
      roles:
        - USER


 boot:
    admin:
      monitor:
        status-interval: 30000
        status-lifetime: 30000
      ui:
        title: "Invoice Matching Admin"
        remember-me-enabled: false

Main class looks like this:

@EnableAdminServer
@SpringBootApplication
public class InvoiceAdminServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(InvoiceAdminServiceApplication.class, args);
    }

}

pom.xml contains this dependencies

 <dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>de.codecentric</groupId>
        <artifactId>spring-boot-admin-server</artifactId>
    </dependency>
    <dependency>
        <groupId>de.codecentric</groupId>
        <artifactId>spring-boot-admin-server-ui</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>


Solution

  • In case that somebody will encounter the same problem, I managed to find the solution.

    In the filterChain method you should add this:

     .dispatcherTypeMatchers(DispatcherType.ASYNC).permitAll()
    

    Here is a documentation (https://codecentric.github.io/spring-boot-admin/3.0.0-M7/security.html#securing-spring-boot-admin) for Spring Admin security.