Java 单点登录在Spring web app中不起作用

Java 单点登录在Spring web app中不起作用,java,spring,authentication,spring-security,active-directory,Java,Spring,Authentication,Spring Security,Active Directory,我将我的web应用程序配置为通过Active Directory repo进行身份验证,它工作正常,但我始终需要在登录表单中插入凭据 应用程序客户端将是连接到公司网络的Windows计算机,所有这些计算机都在同一个域中 我需要将我的web应用配置为自动验证在Windows中已验证的用户 我将此配置用于Spring Security: <security:authentication-manager alias="authenticationManager"> <secu

我将我的web应用程序配置为通过Active Directory repo进行身份验证,它工作正常,但我始终需要在登录表单中插入凭据

应用程序客户端将是连接到公司网络的Windows计算机,所有这些计算机都在同一个域中

我需要将我的web应用配置为自动验证在Windows中已验证的用户

我将此配置用于Spring Security:

<security:authentication-manager alias="authenticationManager">
    <security:authentication-provider
        user-service-ref="userDetailsService">
        <security:password-encoder hash="plaintext" />
    </security:authentication-provider> <!-- for DB authentication -->
    <security:authentication-provider
        ref="adAuthenticationProvider" />
</security:authentication-manager>

<bean id="adAuthenticationProvider"
    class="org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider">
    <constructor-arg name="domain" value="mydomain.it" />
    <constructor-arg name="url" value="ldap://domaincontroller.mydomain.it/" />
</bean>

注意我还需要一个辅助身份验证提供商来提供DB身份验证

我还在IE(v 9)中设置了以下选项,该选项应启用自动登录:

但它不起作用。。。那么我的配置有什么问题


注意#2我使用的是SpringV3.2.9和SpringSecurityV3.2.3

您配置的是LDAP身份验证如果要进行自动身份验证,必须使用Kerberos/SPNEGO

Spring有一个用于Kerberos/SPNEGO身份验证检查的模块,该模块解释了Kerberos/SPNEGO如何工作以及如何配置Spring安全性

您还必须在IE中启用“Windows集成身份验证”,如下所示


正确的方法是使用Kerberos/SPNEGO。但是,服务器必须是Windows域上的受信任节点。如果您的服务器是Windows计算机,那么这应该足够简单。然而,如果它是一台“NIX/Linux机器”,那么它可以是一台真正的PITA

这包括在Active Directory中使用SPN(服务主体名称)进行设置,以及在服务器上安装一大堆东西,以便与a/D集成,并对用户进行身份验证

如果您(或您友好的Windows基础架构团队成员)对所有这些都感到满意,那么就去做吧!但是,如果您不熟悉它,我应该警告您,当它不起作用时,诊断问题就是地狱

但是,有一个快速且肮脏的选项,它不涉及对网络上的服务器的任何信任。事实上,整个过程都可以在你的Spring应用程序中完成。这是一个不太安全,但它的工作NTLM。设置起来很容易

首先,如果没有会话,您需要一个Servlet过滤器来拦截请求并执行握手:

import java.io.IOException;
导入org.apache.commons.codec.binary.Base64;
导入javax.servlet.Filter;
导入javax.servlet.FilterChain;
导入javax.servlet.FilterConfig;
导入javax.servlet.ServletException;
导入javax.servlet.ServletRequest;
导入javax.servlet.ServletResponse;
导入javax.servlet.http.HttpServletRequest;
导入javax.servlet.http.HttpServletResponse;
导入org.slf4j.Logger;
导入org.slf4j.LoggerFactory;
导入org.springframework.context.annotation.Profile;
导入org.springframework.stereotype.Component;
/**
*设计用于通过NTLM SSO获取用户名的简单身份验证过滤器。
*请参阅有关预认证过滤器的Spring文档,了解如何使用它。
*

* * *

*/ @组件(“ntlmFilter”) 公共类NtlmFilter实现过滤器{ 私有静态记录器log=LoggerFactory.getLogger(NtlmFilter.class); 公共静态最终字符串USERNAME\u KEY=“SM\u USER”; 公共NtlmFilter(){ log.info(“初始化NTLM过滤器”); } @凌驾 public void init(FilterConfig FilterConfig)抛出ServletException{ //没有初始化任务。 } @凌驾 公共空间销毁(){ //没有销毁任务。 } /** * */ @凌驾 公共无效doFilter(ServletRequest-req、ServletResponse-res、FilterChain链) 抛出IOException、ServletException{ HttpServletRequest请求=(HttpServletRequest)请求; HttpServletResponse=(HttpServletResponse)res; 如果(未验证(请求)){ debug(“会话已通过身份验证。继续向下筛选链”); setRequestHeaders(请求); 继续(请求、回复、链); }否则{ 调试(“会话尚未验证。正在尝试登录…”); 登录(请求、响应、链); } } 私有无效继续(ServletRequest-req、ServletResponse-res、FilterChain链) 抛出IOException、ServletException{ 试一试{ 链式过滤器(要求、恢复); }捕获(IOE异常){ 错误(“IOException processing NtlmAuthFilter Servlet filter.”,e); 投掷e; }捕获(ServletException e){ 错误(“ServletException处理NtlmAuthFilter Servlet筛选器”,e); 投掷e; } } /** *如果用户名已存储在会话中,则该用户已被删除 *由应用程序验证。 */ 私有布尔值已验证(HttpServletRequest请求){ if(req.getSession().getAttribute(用户名\密钥)!=null){ 返回true; }否则{ 返回false; } } 公共无效登录(HttpServletRequest-req、HttpServletResponse-res、FilterChain-chain)引发ServletException、IOException{ 字符串username=null; 字符串auth=req.getHeader(“授权”); if(auth==null){ //第一阶段。返回NTLM质询标头。 res.setHeader(“WWW-Authenticate”、“NTLM”); res.setStatus(HttpServletResponse.SC_未经授权); res.setContentLength(0); res.flushBuffer(); 返回; }else if(授权开始使用(“NTLM”)){ 字节[]msg=Base64.decodeBase64(验证子字符串(5)); int off=0,长度,偏移量; 如果(消息[8]==1){ //登录详细信息无效。请拒绝。 字节z=0; 字节[]msg1={(字节)'N',(字节)'T',(字节)'L', (字节)‘M’,(字节)‘S’,(字节
@Configuration
@EnableWebSecurity
@EnableWebMvcSecurity
@Profile("secure")
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired(required = true)
    @Qualifier("ntlmFilter")
    private Filter ntlmFilter;

    @Autowired(required = true)
    @Qualifier("headerAuthFilter")
    private Filter headerAuthFilter;

    // ...

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.addFilterBefore(ntlmFilter, RequestHeaderAuthenticationFilter.class)
            .anonymous().disable()
            .csrf().disable()
            .exceptionHandling().authenticationEntryPoint(http403ForbiddenEntryPoint());
    }

    @Bean(name = "headerAuthFilter")
    public Filter headerAuthFilter(AuthenticationManager authenticationManager) {
        RequestHeaderAuthenticationFilter filter = new RequestHeaderAuthenticationFilter();
        filter.setPrincipalRequestHeader("SM_USER");
        filter.setAuthenticationManager(authenticationManager);
        filter.setExceptionIfHeaderMissing(false);
        return filter;
    }

    // ...

}