Безопасность Spring в тестовых и производственных средах

#maven #spring-security #integration-testing

#maven #spring-безопасность #интеграция-тестирование

Вопрос:

Я хотел бы запустить Spring Security в двух средах: тестовой среде и производственной среде.

Я попытался создать конфигурацию для производственной среды:

 @Configuration
@EnableWebSecurity
@ComponentScan(basePackages = { "com.thalasoft.learnintouch.rest.security" })
@Import({ WebSecurityInitializer.class })
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

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

    @Autowired
    CustomAuthenticationProvider customAuthenticationProvider;

    @Autowired
    RestAuthenticationEntryPoint restAuthenticationEntryPoint;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(customAuthenticationProvider);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
        .csrf().disable()
        .httpBasic()
        .authenticationEntryPoint(restAuthenticationEntryPoint)
        .and()
        .authorizeRequests()
        .antMatchers("/**").hasRole("ADMIN")
        .anyRequest().authenticated();
    }

}
  

И один для тестовой среды интеграции:

 @Configuration
@EnableWebSecurity
@ComponentScan(basePackages = { "com.thalasoft.learnintouch.rest.security" })
@Import({ WebSecurityInitializer.class })
public class WebSecurityTestConfiguration extends WebSecurityConfigurerAdapter {

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

    @Autowired
    RestAuthenticationEntryPoint restAuthenticationEntryPoint;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("stephane").password("mypassword").roles("ADMIN");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
        .csrf().disable()
        .httpBasic()
        .authenticationEntryPoint(restAuthenticationEntryPoint)
        .and()
        .authorizeRequests()
        .antMatchers("/**").hasRole("ADMIN")
        .anyRequest().authenticated();
    }

}
  

Эти два класса находятся в разных источниках, один в src / main / java и один в src / test / java, но у них одинаковое имя пакета.

Сборка Maven дает мне следующее исключение:

 Caused by: java.lang.IllegalStateException: @Order on WebSecurityConfigurers must be unique. Order of 100 was already used, so it cannot be used on com.thalasoft.learnintouch.rest.config.WebSecurityConfiguration$$EnhancerByCGLIB$$2d511ca8@536972 too.
  

Является ли причиной того, что повторное расширение WebSecurityConfigurerAdapter дважды является причиной того, что попытка создания экземпляра WebSecurityConfiguration снова завершается неудачей?

Как тогда это сделать?

Ответ №1:

Я мог бы решить проблему, добавив @Order(2) в WebSecurityConfigurerAdapter производственной среды и @Order(1) в тестовую среду.

 @Configuration
@EnableWebSecurity
@ComponentScan(basePackages = { "com.thalasoft.learnintouch.rest.security" })
@Import({ WebSecurityInitializer.class })
@Order(2)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
}

@Configuration
@EnableWebSecurity
@ComponentScan(basePackages = { "com.thalasoft.learnintouch.rest.security" })
@Import({ WebSecurityInitializer.class })
@Order(1)
public class WebSecurityTestConfiguration extends WebSecurityConfigurerAdapter {
}
  

РЕДАКТИРОВАТЬ: лучшим решением было избежать использования аннотации @Order, которая сама по себе является признаком беспорядочной конфигурации.

Проблема была связана с загрузкой как WebSecurityConfiguration, так и WebSecurityTestConfiguration при выполнении тестов, когда требовалось загрузить только один из них, WebSecurityTestConfiguration.

С помощью условной аннотации было легко загрузить только требуемую.

Вот интерфейс определения условия:

 @Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Conditional(EnvNotTestCondition.class)
public @interface EnvNotTest {
}
  

И вот его реализация:

 public class EnvNotTestCondition implements Condition {

  private static final String ENV_TEST = "test";

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return context.getEnvironment().getProperty("env") == null || !context.getEnvironment().getProperty("env").equals(ENV_TEST);
    }

}