После обновления некоторых зависимостей в нашем проекте maven для запуска проекта с контейнерами jdk11 мне пришлось обновить SpringSecurity 4.0.x до 4.2.x. Поэтому я хотел попробовать и преобразовать грязный XML в правильный Java-конфиг.
xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd" default-autowire="byName">
<!-- Spring Security Settings -->
<security:global-method-security pre-post-annotations="enabled"></security:global-method-security>
<security:http-firewall ref="defaultHttpFirewall"/>
<security:http pattern="/api/**" security="none" />
<security:http pattern="/prometheus/**" security="none" />
<security:http entry-point-ref="restEntryPoint" pattern="/login*">
<security:intercept-url pattern="/login*"/>
<security:custom-filter ref="managerRequestRedirectFilter" before="BASIC_AUTH_FILTER" />
<security:csrf disabled="true"/>
</security:http>
<security:http entry-point-ref="restEntryPoint" pattern="/login/sso*">
<security:intercept-url pattern="/login/sso*"/>
<security:custom-filter ref="managerRequestRedirectFilter" before="BASIC_AUTH_FILTER" />
<security:csrf disabled="true"/>
</security:http>
<security:http pattern="/authenticate" security="none" />
<security:http pattern="/resources/bootstrap/**" security="none" />
<security:http pattern="/resources/css/**" security="none" />
<security:http pattern="/resources/js/**" security="none" />
<security:http pattern="/WEB-INF/views/login.jsp*" security="none" />
<security:http pattern="/databaseStatus" security="none" />
<security:http pattern="/module/**" security="none" />
<security:http pattern="/myarea/**" security="none" />
<security:http pattern="/ajax/**" security="none" />
<security:http pattern="/logout/sso" security="none" />
<security:http pattern="/download/**" security="none" />
<bean id="managerRequestRedirectFilter" class="com.pany.managertemplate.authentication.service.ManagerRequestRedirectFilter"/>
<!-- Spring Security Kerberos Settings -->
<bean id="authenticationResultFilter" class="com.pany.managertemplate.authentication.service.ManagerAuthenticationResultFilter"/>
<!-- rest -->
<bean id="restAuthenticationProcessingFilter" class=" com.pany.managertemplate.authentication.service.RestAuthenticationProcessingFilter" />
<bean id="restEntryPoint" class="com.pany.managertemplate.authentication.service.RestAuthenticationEntryPoint" />
<security:http entry-point-ref="restEntryPoint" pattern="/rest/**">
<security:intercept-url pattern="/rest/**" access="hasRole('ROLE_USER')" />
<security:custom-filter ref="restAuthenticationProcessingFilter" position="BASIC_AUTH_FILTER" />
<security:custom-filter ref="authenticationResultFilter" after="BASIC_AUTH_FILTER" />
<security:csrf disabled="true"/>
</security:http>
<security:http entry-point-ref="restEntryPoint" pattern="/hooks/**">
<security:intercept-url pattern="/hooks/**" access="hasRole('ROLE_USER')" />
<security:custom-filter ref="restAuthenticationProcessingFilter" position="BASIC_AUTH_FILTER" />
<security:custom-filter ref="authenticationResultFilter" after="BASIC_AUTH_FILTER" />
<security:csrf disabled="true"/>
</security:http>
<security:http entry-point-ref="restEntryPoint" pattern="/get/**">
<security:intercept-url pattern="/get/**" access="hasRole('ROLE_USER')" />
<security:custom-filter ref="restAuthenticationProcessingFilter" position="BASIC_AUTH_FILTER" />
<security:custom-filter ref="authenticationResultFilter" after="BASIC_AUTH_FILTER" />
<security:csrf disabled="true"/>
</security:http>
<security:http entry-point-ref="restEntryPoint" pattern="/hook/**">
<security:intercept-url pattern="/hook/**" access="hasRole('ROLE_USER')" />
<security:custom-filter ref="restAuthenticationProcessingFilter" position="BASIC_AUTH_FILTER" />
<security:custom-filter ref="authenticationResultFilter" after="BASIC_AUTH_FILTER" />
<security:csrf disabled="true"/>
</security:http>
<security:http entry-point-ref="restEntryPoint" pattern="/hookhistories/**">
<security:intercept-url pattern="/hookhistories/**" access="hasRole('ROLE_USER')" />
<security:custom-filter ref="restAuthenticationProcessingFilter" position="BASIC_AUTH_FILTER" />
<security:custom-filter ref="authenticationResultFilter" after="BASIC_AUTH_FILTER" />
<security:csrf disabled="true"/>
</security:http>
<security:http entry-point-ref="restEntryPoint" pattern="/hookcalls/**">
<security:intercept-url pattern="/hookcalls/**" access="hasRole('ROLE_USER')" />
<security:custom-filter ref="restAuthenticationProcessingFilter" position="BASIC_AUTH_FILTER" />
<security:custom-filter ref="authenticationResultFilter" after="BASIC_AUTH_FILTER" />
<security:csrf disabled="true"/>
</security:http>
<security:http entry-point-ref="restEntryPoint" pattern="/hookversions/**">
<security:intercept-url pattern="/hookversions/**" access="hasRole('ROLE_USER')" />
<security:custom-filter ref="restAuthenticationProcessingFilter" position="BASIC_AUTH_FILTER" />
<security:custom-filter ref="authenticationResultFilter" after="BASIC_AUTH_FILTER" />
<security:csrf disabled="true"/>
</security:http>
<!-- -->
<bean id="webexpressionHandler" class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler" />
<bean id="accessDeniedHandler" class="org.springframework.security.web.access.AccessDeniedHandlerImpl">
<property name="errorPage" value="/login"/>
</bean>
<security:http entry-point-ref="spnegoEntryPoint">
<security:intercept-url pattern="/**" access="hasRole('ROLE_USER')"/>
<security:custom-filter ref="managerRequestRedirectFilter" before="BASIC_AUTH_FILTER" />
<security:custom-filter ref="spnegoAuthenticationProcessingFilter" position="BASIC_AUTH_FILTER" />
<security:custom-filter ref="authenticationResultFilter" after="BASIC_AUTH_FILTER" />
<security:session-management session-fixation-protection="newSession">
<security:concurrency-control max-sessions="1" expired-url="/login"/>
</security:session-management>
<security:csrf disabled="true"/>
</security:http>
<bean id="spnegoEntryPoint" class="com.pany.managertemplate.authentication.service.ManagerAuthenticationEntryPoint" />
<bean id="simpleUrlAuthenticationFailureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<property name="useForward" value="true"/>
<property name="defaultFailureUrl" value="/login"/>
</bean>
<bean id="authenticationSuccessHandler" class="com.pany.managertemplate.authentication.service.ManagerAuthenticationSuccessHandler" />
<bean id="spnegoAuthenticationProcessingFilter" class="com.pany.managertemplate.authentication.service.ManagerSpnegoAuthenticationProcessingFilter">
<property name="authenticationManager" ref="authenticationManager" />
<property name="failureHandler" ref="simpleUrlAuthenticationFailureHandler"/>
<property name="successHandler" ref="authenticationSuccessHandler"/>
</bean>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="kerberosServiceAuthenticationProvider" />
<security:authentication-provider ref="kerberosAuthenticationProvider"/>
</security:authentication-manager>
<bean id="kerberosAuthenticationProvider"
class="org.springframework.security.kerberos.authentication.KerberosAuthenticationProvider">
<property name="kerberosClient">
<bean class="org.springframework.security.kerberos.authentication.sun.SunJaasKerberosClient">
<property name="debug" value="false"/>
</bean>
</property>
<property name="userDetailsService" ref="kerberosUserDetailsService"/>
</bean>
<bean id="kerberosServiceAuthenticationProvider" class="org.springframework.security.kerberos.authentication.KerberosServiceAuthenticationProvider">
<property name="ticketValidator">
<bean class="org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator">
<property name="servicePrincipal"
value="HTTP/an.URL"/>
<property name="keyTabLocation"
value="file:/etc/krb5.keytab"/>
<property name="debug" value="false" />
</bean>
</property>
<property name="userDetailsService" ref="kerberosUserDetailsService" />
</bean>
<bean class="org.springframework.security.kerberos.authentication.sun.GlobalSunJaasKerberosConfig">
<property name="debug" value="false" />
<property name="krbConfLocation" value="/etc/krb5.conf"/>
</bean>
<bean id="kerberosUserDetailsService" class="com.pany.managertemplate.authentication.service.KerberosUserDetailsService"/>
</beans>
и попробовать конфигурацию, которую я использовал:
package com.pany.managertemplate.configuration.service;
import java.net.MalformedURLException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.kerberos.authentication.KerberosAuthenticationProvider;
import org.springframework.security.kerberos.authentication.KerberosServiceAuthenticationProvider;
import org.springframework.security.kerberos.authentication.sun.GlobalSunJaasKerberosConfig;
import org.springframework.security.kerberos.authentication.sun.SunJaasKerberosClient;
import org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator;
import org.springframework.security.kerberos.web.authentication.SpnegoAuthenticationProcessingFilter;
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.firewall.DefaultHttpFirewall;
import org.springframework.security.web.firewall.HttpFirewall;
import com.pany.managertemplate.authentication.service.KerberosUserDetailsService;
import com.pany.managertemplate.authentication.service.ManagerAuthenticationEntryPoint;
import com.pany.managertemplate.authentication.service.ManagerAuthenticationResultFilter;
import com.pany.managertemplate.authentication.service.ManagerAuthenticationSuccessHandler;
import com.pany.managertemplate.authentication.service.ManagerRequestRedirectFilter;
import com.pany.managertemplate.authentication.service.ManagerSpnegoAuthenticationProcessingFilter;
import com.pany.managertemplate.authentication.service.RestAuthenticationEntryPoint;
import com.pany.managertemplate.authentication.service.RestAuthenticationProcessingFilter;
@Configuration
@Order(1)
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter
{
@Configuration
@Order(3)
public static class GlobalSecurity extends WebSecurityConfigurerAdapter
{
@Autowired
@Qualifier("authenticationResultFilter")
private ManagerAuthenticationResultFilter authenticationResultFilter;
@Autowired
private KerberosAuthenticationProvider kerberosAuthenticationProvider;
@Autowired
private KerberosServiceAuthenticationProvider kerberosServiceAuthenticationProvider;
@Autowired
private ManagerRequestRedirectFilter managerRequestRedirectFilter;
@Autowired
@Qualifier("restEntryPoint")
private RestAuthenticationEntryPoint restEntryPoint;
@Autowired
private SpnegoAuthenticationProcessingFilter spnegoAuthenticationProcessingFilter;
@Autowired
@Qualifier("spnegoEntryPoint")
private ManagerAuthenticationEntryPoint spnegoEntryPoint;
@Bean(BeanIds.AUTHENTICATION_MANAGER)
@Override
public AuthenticationManager authenticationManagerBean() throws Exception
{
return super.authenticationManagerBean();
}
@Override
protected void configure(final AuthenticationManagerBuilder authManagerBuilder) throws Exception
{
authManagerBuilder.authenticationProvider(this.kerberosServiceAuthenticationProvider);
authManagerBuilder.authenticationProvider(this.kerberosAuthenticationProvider);
}
@Override
protected void configure(final HttpSecurity http) throws Exception
{
http.csrf().disable();
http.authorizeRequests().antMatchers(HttpMethod.GET, "/health").permitAll();
http.authorizeRequests().antMatchers("/authenticate").permitAll();
http.authorizeRequests().antMatchers("/resources/bootstrap/**").permitAll();
http.authorizeRequests().antMatchers("/resources/css/**").permitAll();
http.authorizeRequests().antMatchers("/resources/js/**").permitAll();
http.authorizeRequests().antMatchers("/WEB-INF/views/login.jsp*").permitAll();
http.authorizeRequests().antMatchers("/databaseStatus").permitAll();
http.authorizeRequests().antMatchers("/module/**").permitAll();
http.authorizeRequests().antMatchers("/myarea/**").permitAll();
http.authorizeRequests().antMatchers("/ajax/**").permitAll();
http.authorizeRequests().antMatchers("/logout/sso").permitAll();
http.authorizeRequests().antMatchers("/download/**").permitAll();
http.authorizeRequests().antMatchers("/api/**").permitAll();
http.authorizeRequests().antMatchers("/prometheus/**").permitAll();
http.authorizeRequests().antMatchers("/**").hasRole("USER");
http.exceptionHandling().authenticationEntryPoint(this.spnegoEntryPoint);
http.addFilterBefore(this.managerRequestRedirectFilter, BasicAuthenticationFilter.class);
http.addFilterAt(this.spnegoAuthenticationProcessingFilter, BasicAuthenticationFilter.class);
http.addFilterAfter(this.managerRequestRedirectFilter, BasicAuthenticationFilter.class);
}
}
@Configuration
@Order(1)
public static class LoginSecurity extends WebSecurityConfigurerAdapter
{
@Autowired
private KerberosAuthenticationProvider kerberosAuthenticationProvider;
@Autowired
private KerberosServiceAuthenticationProvider kerberosServiceAuthenticationProvider;
@Autowired
private ManagerRequestRedirectFilter managerRequestRedirectFilter;
@Autowired
@Qualifier("restEntryPoint")
private RestAuthenticationEntryPoint restEntryPoint;
@Override
protected void configure(final AuthenticationManagerBuilder authManagerBuilder) throws Exception
{
authManagerBuilder.authenticationProvider(this.kerberosServiceAuthenticationProvider);
authManagerBuilder.authenticationProvider(this.kerberosAuthenticationProvider);
}
@Override
protected void configure(final HttpSecurity http) throws Exception
{
http.csrf().disable();
http.antMatcher("/login*").antMatcher("/login/sso*");
http.authorizeRequests().anyRequest().permitAll();
http.exceptionHandling().authenticationEntryPoint(this.restEntryPoint);
http.addFilterBefore(this.managerRequestRedirectFilter, BasicAuthenticationFilter.class);
http.sessionManagement().sessionFixation().newSession().maximumSessions(1).expiredUrl("/login");
http.authorizeRequests().anyRequest().authenticated();
http.formLogin().loginPage("/login");
}
}
@Configuration
@Order(2)
public static class RestSecurity extends WebSecurityConfigurerAdapter
{
@Autowired
@Qualifier("authenticationResultFilter")
private ManagerAuthenticationResultFilter authenticationResultFilter;
@Autowired
private KerberosAuthenticationProvider kerberosAuthenticationProvider;
@Autowired
private KerberosServiceAuthenticationProvider kerberosServiceAuthenticationProvider;
@Autowired
private RestAuthenticationProcessingFilter restAuthenticationProcessingFilter;
@Autowired
@Qualifier("restEntryPoint")
private RestAuthenticationEntryPoint restEntryPoint;
@Override
protected void configure(final AuthenticationManagerBuilder authManagerBuilder) throws Exception
{
authManagerBuilder.authenticationProvider(this.kerberosServiceAuthenticationProvider);
authManagerBuilder.authenticationProvider(this.kerberosAuthenticationProvider);
}
@Override
protected void configure(final HttpSecurity http) throws Exception
{
http.csrf().disable();
http.antMatcher("/rest/**").antMatcher("/hooks/**").antMatcher("/get/**").antMatcher("/hook/**").antMatcher("/hookhistories/**")
.antMatcher("/hookcalls/**").antMatcher("/hookversions/**");
http.authorizeRequests().anyRequest().permitAll();
http.exceptionHandling().authenticationEntryPoint(this.restEntryPoint);
http.addFilterAt(this.restAuthenticationProcessingFilter, BasicAuthenticationFilter.class);
http.addFilterAfter(this.authenticationResultFilter, BasicAuthenticationFilter.class);
}
}
@Autowired
@Qualifier("authenticationResultFilter")
private ManagerAuthenticationResultFilter authenticationResultFilter;
@Autowired
@Qualifier("restEntryPoint")
private RestAuthenticationEntryPoint restEntryPoint;
@Autowired
@Qualifier("spnegoEntryPoint")
private ManagerAuthenticationEntryPoint spnegoEntryPoint;
@Bean
public AccessDeniedHandlerImpl accessDeniedHandler()
{
AccessDeniedHandlerImpl accessDeniedHandlerImpl = new AccessDeniedHandlerImpl();
accessDeniedHandlerImpl.setErrorPage("/login");
return accessDeniedHandlerImpl;
}
@Override
public void configure(final WebSecurity web) throws Exception
{
// though StrictHttpFirewall is advised
super.configure(web);
web.httpFirewall(this.defaultHttpFirewall());
}
@Bean
public HttpFirewall defaultHttpFirewall()
{
DefaultHttpFirewall firewall = new DefaultHttpFirewall();
firewall.setAllowUrlEncodedSlash(true);
return firewall;
}
@Bean
public GlobalSunJaasKerberosConfig globalSunJaasKerberosConfig()
{
GlobalSunJaasKerberosConfig globalSunJaasKerberosConfig = new GlobalSunJaasKerberosConfig();
globalSunJaasKerberosConfig.setDebug(false);
globalSunJaasKerberosConfig.setKrbConfLocation("/etc/krb5.conf");
return globalSunJaasKerberosConfig;
}
@Bean("kerberosAuthenticationProvider")
public KerberosAuthenticationProvider kerberosAuthenticationProvider(@Qualifier("kerberosClient") final SunJaasKerberosClient kerberosClient,
final KerberosUserDetailsService kerberosUserDetailsService)
{
KerberosAuthenticationProvider kerberosAuthenticationProvider = new KerberosAuthenticationProvider();
kerberosAuthenticationProvider.setKerberosClient(kerberosClient);
kerberosAuthenticationProvider.setUserDetailsService(kerberosUserDetailsService);
return kerberosAuthenticationProvider;
}
@Bean("kerberosServiceAuthenticationProvider")
public KerberosServiceAuthenticationProvider kerberosServiceAuthenticationProvider(final KerberosUserDetailsService kerberosUserDetailsService,
@Qualifier("ticketValidator") final SunJaasKerberosTicketValidator ticketValidator)
{
KerberosServiceAuthenticationProvider kerberosServiceAuthenticationProvider = new KerberosServiceAuthenticationProvider();
kerberosServiceAuthenticationProvider.setUserDetailsService(kerberosUserDetailsService);
kerberosServiceAuthenticationProvider.setTicketValidator(ticketValidator);
return kerberosServiceAuthenticationProvider;
}
@Bean
public KerberosUserDetailsService kerberosUserDetailsService()
{
return new KerberosUserDetailsService();
}
@Bean("spnegoEntryPoint")
public ManagerAuthenticationEntryPoint managerAuthenticationEntryPoint()
{
return new ManagerAuthenticationEntryPoint();
}
@Bean("authenticationResultFilter")
public ManagerAuthenticationResultFilter managerAuthenticationResultFilter()
{
return new ManagerAuthenticationResultFilter();
}
@Bean("authenticationSuccessHandler")
public ManagerAuthenticationSuccessHandler managerAuthenticationSuccessHandler()
{
return new ManagerAuthenticationSuccessHandler();
}
@Bean
public ManagerRequestRedirectFilter managerRequestRedirectFilter()
{
return new ManagerRequestRedirectFilter();
}
@Bean("spnegoAuthenticationProcessingFilter")
public ManagerSpnegoAuthenticationProcessingFilter managerSpnegoAuthenticationProcessingFilter(final AuthenticationManager authenticationManager,
final SimpleUrlAuthenticationFailureHandler simpleUrlAuthenticationFailureHandler,
@Qualifier("authenticationSuccessHandler") final AuthenticationSuccessHandler authenticationSuccessHandler)
{
ManagerSpnegoAuthenticationProcessingFilter managerSpnegoAuthenticationProcessingFilter = new ManagerSpnegoAuthenticationProcessingFilter();
managerSpnegoAuthenticationProcessingFilter.setAuthenticationManager(authenticationManager);
managerSpnegoAuthenticationProcessingFilter.setFailureHandler(simpleUrlAuthenticationFailureHandler);
managerSpnegoAuthenticationProcessingFilter.setSuccessHandler(authenticationSuccessHandler);
return managerSpnegoAuthenticationProcessingFilter;
}
@Bean("restEntryPoint")
public RestAuthenticationEntryPoint restAuthenticationEntryPoint()
{
return new RestAuthenticationEntryPoint();
}
@Bean
public RestAuthenticationProcessingFilter restAuthenticationProcessingFilter()
{
return new RestAuthenticationProcessingFilter();
}
@Bean("simpleUrlAuthenticationFailureHandler")
public SimpleUrlAuthenticationFailureHandler simpleUrlAuthenticationFailureHandler()
{
SimpleUrlAuthenticationFailureHandler simpleUrlAuthenticationFailureHandler = new SimpleUrlAuthenticationFailureHandler();
simpleUrlAuthenticationFailureHandler.setUseForward(true);
simpleUrlAuthenticationFailureHandler.setDefaultFailureUrl("/login");
return simpleUrlAuthenticationFailureHandler;
}
@Bean
public SunJaasKerberosClient sunJaasKerberosClient()
{
SunJaasKerberosClient sunJaasKerberosClient = new SunJaasKerberosClient();
sunJaasKerberosClient.setDebug(false);
return sunJaasKerberosClient;
}
@Bean("ticketValidator")
public SunJaasKerberosTicketValidator sunJaasKerberosTicketValidator() throws MalformedURLException
{
SunJaasKerberosTicketValidator sunJaasKerberosTicketValidator = new SunJaasKerberosTicketValidator();
sunJaasKerberosTicketValidator.setServicePrincipal("HTTP/an.URL");
Resource keyTabFile = new UrlResource("file:/etc/krb5.keytab");
sunJaasKerberosTicketValidator.setKeyTabLocation(keyTabFile);
sunJaasKerberosTicketValidator.setDebug(false);
return sunJaasKerberosTicketValidator;
}
}
Вход через / вход работает нормально, разрешения работают внутри веб-интерфейса приложения. Проблема, с которой я столкнулся, связана с межсерверной связью через REST. Отправка правильных учетных данных, как раньше, просто возвращает страницу входа в систему вместо запрошенного ресурса - это та точка, в которой я застрял. Я чувствую, что конфигурация является слишком сложной и запутанной в некоторых моментах из-за нескольких точек входа. но это было то, что я прочитал в официальной документации. Или есть более простой способ, и я просто считаю слишком сложным? Короче говоря, Java-Config ведет себя не так, как Java-Config, и я пока не понимаю, почему.