将Waffle Spring Security XML配置迁移到Spring Boot

4
我正在尝试使用Spring Boot方式在Spring Security中使用Waffle身份验证,期望的结果是“如果Negotiate失败,则阻止所有内容”。
Waffle项目提供了一个配置示例,用于这种用例(在此示例中,如果Negotiate失败,会回退到简单的HTTP身份验证,但我不需要),假定配置是通过web.xml完成的。但是,尽管尝试了许多次,我仍然不明白如何在使用Boot和Java-only配置的情况下将Waffle与Spring Security连接起来。我正在使用Spring Boot 1.2.1.RELEASE,具有Web和Security启动器,Waffle版本为1.7.3。
我意识到这不是一个具体的问题,但Spring论坛现在重定向到这里,而Waffle的人不知道Spring Boot。有人能帮我将XML Spring Security配置翻译成Spring Boot吗?
第一步是声明一个过滤器链和上下文加载器监听器。
<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/waffle-filter.xml</param-value> 
</context-param>
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

我假设(我错了吗?)这已经被@EnableWebMvcSecurity处理,所以这里不需要做任何事情。

接下来是声明一些提供者bean,所以我翻译一下:

<bean id="waffleWindowsAuthProvider" class="waffle.windows.auth.impl.WindowsAuthProviderImpl" />

<bean id="negotiateSecurityFilterProvider" class="waffle.servlet.spi.NegotiateSecurityFilterProvider">
    <constructor-arg ref="waffleWindowsAuthProvider" />
</bean>

<bean id="basicSecurityFilterProvider" class="waffle.servlet.spi.BasicSecurityFilterProvider">
    <constructor-arg ref="waffleWindowsAuthProvider" />
</bean>

<bean id="waffleSecurityFilterProviderCollection" class="waffle.servlet.spi.SecurityFilterProviderCollection">
    <constructor-arg>
        <list>
            <ref bean="negotiateSecurityFilterProvider" />               
            <ref bean="basicSecurityFilterProvider" />               
        </list>
    </constructor-arg>
</bean>

<bean id="waffleNegotiateSecurityFilter" class="waffle.spring.NegotiateSecurityFilter">
    <property name="Provider" ref="waffleSecurityFilterProviderCollection" />
</bean>

到这个

@Bean
public WindowsAuthProviderImpl waffleWindowsAuthProvider() {
    return new WindowsAuthProviderImpl();
}

@Bean
@Autowired
public NegotiateSecurityFilterProvider negotiateSecurityFilterProvider(final WindowsAuthProviderImpl windowsAuthProvider) {
    return new NegotiateSecurityFilterProvider(windowsAuthProvider);
}

@Bean
@Autowired
public BasicSecurityFilterProvider basicSecurityFilterProvider(final WindowsAuthProviderImpl windowsAuthProvider) {
    return new BasicSecurityFilterProvider(windowsAuthProvider);
}

@Bean
@Autowired
public SecurityFilterProviderCollection waffleSecurityFilterProviderCollection(final NegotiateSecurityFilterProvider negotiateSecurityFilterProvider, final BasicSecurityFilterProvider basicSecurityFilterProvider) {
    final SecurityFilterProvider[] securityFilterProviders = {
            negotiateSecurityFilterProvider,
            basicSecurityFilterProvider
    };
    return new SecurityFilterProviderCollection(securityFilterProviders);
}

@Bean
@Autowired
public NegotiateSecurityFilter waffleNegotiateSecurityFilter(final SecurityFilterProviderCollection securityFilterProviderCollection) {
    final NegotiateSecurityFilter negotiateSecurityFilter = new NegotiateSecurityFilter();
    negotiateSecurityFilter.setProvider(securityFilterProviderCollection);
    return negotiateSecurityFilter;
}

最后一步是sec:http部分的配置。声明了入口点,并在BASIC认证过滤器之前放置了过滤器。
示例:
<sec:http entry-point-ref="negotiateSecurityFilterEntryPoint">
    <sec:intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
    <sec:custom-filter ref="waffleNegotiateSecurityFilter" position="BASIC_AUTH_FILTER" />
</sec:http>

<bean id="negotiateSecurityFilterEntryPoint" class="waffle.spring.NegotiateSecurityFilterEntryPoint">
    <property name="Provider" ref="waffleSecurityFilterProviderCollection" />
</bean>

我的引导翻译:

@Autowired
private NegotiateSecurityFilterEntryPoint authenticationEntryPoint;

@Autowired
private NegotiateSecurityFilter negotiateSecurityFilter;    

@Override
protected void configure(final HttpSecurity http) throws Exception {
    http
            .authorizeRequests().anyRequest().authenticated()
            .and()
            .addFilterBefore(this.negotiateSecurityFilter, BasicAuthenticationFilter.class)
            .httpBasic().authenticationEntryPoint(this.authenticationEntryPoint);
}

@Bean
@Autowired
public NegotiateSecurityFilterEntryPoint negotiateSecurityFilterEntryPoint(final SecurityFilterProviderCollection securityFilterProviderCollection) {
    final NegotiateSecurityFilterEntryPoint negotiateSecurityFilterEntryPoint = new NegotiateSecurityFilterEntryPoint();
    negotiateSecurityFilterEntryPoint.setProvider(securityFilterProviderCollection);
    return negotiateSecurityFilterEntryPoint;
}

运行此配置会导致奇怪的行为:有时会触发NTLM并成功,有时Negotiate过滤器会崩溃并显示“提供的令牌无效”错误(相同的凭据、用户、浏览器、配置)。 提供的示例非常有效,这让我想到我的引导配置可能存在问题。
任何帮助都将不胜感激!

如果过滤器触发了,我想它一定是在工作。我真的不知道关于华夫饼还有什么其他的(但它看起来很有趣)。我注意到你的代码和XML示例之间的一个区别是,你只安装了自定义入口点到HTTP基本过滤器中(而没有对整个链进行异常处理)。也许你需要这样做,但我不知道它是否会解决所有问题。 - Dave Syer
感谢您的反馈。这并没有解决“无效令牌”问题(我会再次联系Waffle团队),但这是一个开始。 - LeRiton
这个问题有任何更新吗?我遇到了同样的问题(我想)。关于 Spring Boot 的 Waffle。它似乎在 Chrome 和其他浏览器中运行良好,但在使用 IE11 时会失败。服务器记录了一个 Win32Exception 错误:“函数接收到的令牌无效”。 - Mike
我不再处理这个问题了,但如果您发现有用的信息,请告诉我,我很乐意了解更多。如果需要,我可以进行一些测试。 - LeRiton
1个回答

2

Spring Boot自动注册所有过滤器bean,因此在这种情况下,NegotiateSecurityFilter在过滤器链中出现了两次。

您需要通过创建一个FilterRegistrationBean来禁用特定过滤器的自动注册以覆盖此行为:

@Bean
public FilterRegistrationBean registration(NegotiateSecurityFilter filter) {
    FilterRegistrationBean registration = new FilterRegistrationBean(filter);
    registration.setEnabled(false);
    return registration;
}

此外,正如Dave Syer所提到的那样,您应该使用ExceptionHandlingConfigurer设置身份验证入口点bean。
@Override
protected void configure(HttpSecurity http) throws Exception {
    http.exceptionHandling()
        .authenticationEntryPoint(authenticationEntryPoint);
    // ...
}

谢谢澄清! 不幸的是,我已经不再使用Waffle参与任何项目,所以无法测试您的建议。 如果有人能够尝试并告诉我们结果,我很乐意批准您的答案。 - LeRiton
是的!这对我起作用了(Spring Boot 2.2 + Waffle 2.2.1) - Brice Roncace

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接