Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring boot authentication - admin console 403 response to client

I'm using jdk 1.8 and Spring boot 2.1.2.

I would like to enable authentication in administration console of Spring Boot and in its clients.

I setted in Administration application.properties:

spring.security.user.name=admin
spring.security.user.password=secret

spring.boot.admin.discovery.enabled=true

management.endpoints.web.exposure.include=*
management.endpoints.web.cors.allowed-methods=GET,POST

In Administration project I added this class:

@EnableWebSecurity
@Configuration
public class SecuritySecureConfig extends WebSecurityConfigurerAdapter {

    private static final Logger logger = (Logger) LoggerFactory.getLogger(SecuritySecureConfig.class);

    private final String adminContextPath;

    public SecuritySecureConfig(AdminServerProperties adminServerProperties) {
        this.adminContextPath = adminServerProperties.getContextPath();
    }

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

    SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
    successHandler.setTargetUrlParameter("redirectTo");
    successHandler.setDefaultTargetUrl(adminContextPath + "/");

    http.authorizeRequests()
            .antMatchers(adminContextPath + "/assets/**").permitAll()
            .antMatchers(adminContextPath + "/login").permitAll()
            .anyRequest().authenticated()
            .and()
            .formLogin().loginPage(adminContextPath + "/login").successHandler(successHandler).and()
            .logout().logoutUrl(adminContextPath + "/logout").and()
            .httpBasic().and()
            .csrf()
                .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
            .ignoringAntMatchers(
                    adminContextPath + "/instances",
                    adminContextPath + "/actuator/**"
            );

    }

}

In administration pom.xml I added:

 <dependencies>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>de.codecentric</groupId>
        <artifactId>spring-boot-admin-starter-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-tomcat</artifactId>
    </dependency>

</dependencies>

I was forced to add the annotation @EnableWebFluxSecurity on the main class because without it, it gives an Exception:

org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'springSecurityFilterChain' defined in class path resource [org/springframework/boot/actuate/autoconfigure/security/reactive/ReactiveManagementWebSecurityAutoConfiguration.class]: Cannot register bean definition [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.actuate.autoconfigure.security.reactive.ReactiveManagementWebSecurityAutoConfiguration; factoryMethodName=springSecurityFilterChain; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/actuate/autoconfigure/security/reactive/ReactiveManagementWebSecurityAutoConfiguration.class]] for bean 'springSecurityFilterChain': There is already [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration; factoryMethodName=springSecurityFilterChain; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class]] bound.

In client application.properties:

spring.security.user.name=joe
spring.security.user.password=my-secret-password

spring.boot.admin.client.username=admin
spring.boot.admin.client.password=secret

spring.boot.admin.client.instance.metadata.user.name=admin
spring.boot.admin.client.instance.metadata.user.password=secret


spring.boot.admin.client.enabled=true

spring.boot.admin.client.auto-registration=true
spring.boot.admin.client.auto-deregistration=true

And in client pom.xml:

 <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-security</artifactId>
 </dependency>

Now if I access both of them using the browser, they prompt me with the login form. I type the login and password and all works as a charm, but the actuator of the client cannot access to the admin, it returns always 403 FORBIDDEN.

2019-02-12 15:21:52.004 - [registrationTask1] DEBUG o.s.core.log.CompositeLog.debug 142 - Response 403 FORBIDDEN

I really cannot understand why the communication between the administration console and the client does not work. Does anyone know where I'm wrong?

like image 925
Stefania Avatar asked Nov 06 '22 20:11

Stefania


1 Answers

I have the same problem so, use

@EnableWebFluxSecurity

and not

@EnableWebSecurity

like this

@Configuration
@EnableWebFluxSecurity
public class AppSecurityConfig   {

    private final AdminServerProperties adminServer;

    public AppSecurityConfig (AdminServerProperties adminServer) {
        this.adminServer = adminServer;
    }
    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        http
            .securityMatcher(new NegatedServerWebExchangeMatcher(
                ServerWebExchangeMatchers.pathMatchers("/instances")))
            .securityMatcher(new NegatedServerWebExchangeMatcher(
                ServerWebExchangeMatchers.pathMatchers("/actuator/**")))
            .authorizeExchange()
            .anyExchange().authenticated()
            .and()
            .formLogin()
            .loginPage(this.adminServer.getContextPath() + "/login")
            .and()
            .logout()
            .logoutUrl(this.adminServer.getContextPath() + "/logout")
            .and()
            .httpBasic()
            .and()
            .csrf().disable();
        return http.build();
    } }

in you application.yml

spring:
  security:
    user:
      password: ${ADMIN_PASSWORD}
      name: ${ADMIN_USER}
  application:
    name: Admin Server 
  boot:
    admin:
      client:
        username: ${ADMIN_USER}
        password: ${ADMIN_PASSWORD}
        url: ${ADMIN_SERVER_URL}
        enabled: true
      ui:
        cache:
          no-cache: true
        title: App Monitoring
        instance:
          name: ${spring.application.name}
  main:
    allow-bean-definition-overriding: true
management:
  endpoints:
    web:
      exposure:
        include: "*"
      cors:
        allowed-origins: "*"
        allowed-methods: GET,POST
  endpoint:
    health:
      show-details: always

It can monitor it self if you want


in the client side app

spring:
  boot:
    admin:
      client:
        url: ${ADMIN_SERVER_URL}
        username: ${ADMIN_USER}
        password: ${ADMIN_PASSWORD}
        instance:
          name: ${spring.application.name}
        auto-registration: true
  application:
    name: Client App
like image 110
Shaheed Avatar answered Nov 15 '22 10:11

Shaheed