第 26 章 使用NTLM登录

NTLM是NT Lan Manager,即Window NT局域网管理器。它会以本地系统当前用户尝试访问远程主机,基本工作流程请去网上搜索。

ntlm

图 26.1. ntlm


NTLM验证允许Windows用户使用当前登录系统的身份进行认证,当前用户应该是登陆在一个域(domain)上,他的身份是可以自动通过浏览器传递给服务器的。它是一种单点登录的策略,系统可以通过NTLM重用登录到Windows系统中的用户凭证,不用再次要求用户输入密码进行认证。

不过,它只能用在IE中。使用Firefox时,你会被要求输入用户名和密码,这时可以使用下面的配置启用NTLM。

现在我们开始在Spring Security中配置NTLM。

首先在pom.xml中添加依赖:

<dependency>
  <groupId>org.springframework.security</groupId>
  <artifactId>spring-security-ntlm</artifactId>
  <version>2.0.5.RELEASE</version>
</dependency>
    

然后修改xml文件,添加NTLM的过滤器和入口点。

<http entry-point-ref="ntlmEntryPoint" servlet-api-provision="false">
    <intercept-url pattern="/access_denied.jsp" filters="none"/>
    <intercept-url pattern="/admin.jsp" access="ROLE_ADMIN" />
    <intercept-url pattern="/**" access="ROLE_USER" />
</http>

<beans:bean id="userDetailsAuthenticationProvider"
    class="com.family168.springsecuritybook.ch116.UserDetailsAuthenticationProvider">
    <custom-authentication-provider/>
    <beans:property name="userDetailsService" ref="userDetailsService"/>
</beans:bean>

<beans:bean id="ntlmEntryPoint" class="org.springframework.security.ui.ntlm.NtlmProcessingFilterEntryPoint">
    <beans:property name="authenticationFailureUrl" value="/access_denied.jsp"/>
</beans:bean>

<beans:bean id="ntlmFilter" class="org.springframework.security.ui.ntlm.NtlmProcessingFilter">
    <custom-filter position="NTLM_FILTER"/>
    <beans:property name="stripDomain" value="true"/>
    <beans:property name="defaultDomain" value="internal.mossle.com"/>
    <beans:property name="netbiosWINS" value="internal.mossle.com"/>
    <beans:property name="smbClientUsername" value="username"/>
    <beans:property name="smbClientPassword" value="password"/>
    <beans:property name="authenticationManager" ref="_authenticationManager"/>
</beans:bean>
    

警告

一定要使用servlet-api-provision="false",禁用掉savedRequest,否则在ntlm多段握手过程中永远也无法获得Authorization这个header。

netbiosWINS是域控服务器的地址,到时要去这个地址进行用户的校验。smb的用户名和密码也必须提供,否则无法让多个人登录,从第二个人开始就会失败。

我们还需要创建一个UserDetailsAuthenticationProvider,可以直接通过username从UserDetailsService中获得用户信息与相应的权限。


package com.family168.springsecuritybook.ch116;

import org.springframework.dao.DataAccessException;
import org.springframework.security.AuthenticationException;
import org.springframework.security.AuthenticationServiceException;
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
import org.springframework.security.providers.dao.AbstractUserDetailsAuthenticationProvider;
import org.springframework.security.userdetails.UserDetails;
import org.springframework.security.userdetails.UserDetailsService;

public class UserDetailsAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {

    private UserDetailsService userDetailsService;

    protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
            throws AuthenticationException {
        UserDetails loadedUser;
        try {
            loadedUser = this.getUserDetailsService().loadUserByUsername(username);
        } catch (DataAccessException repositoryProblem) {
            throw new AuthenticationServiceException(repositoryProblem.getMessage(), repositoryProblem);
        }
        if (loadedUser == null) throw new AuthenticationServiceException("User cannot be null");
        return loadedUser;
    }

    protected void additionalAuthenticationChecks(UserDetails userDetails,
        UsernamePasswordAuthenticationToken authentication)
        throws AuthenticationException{
    }

    public UserDetailsService getUserDetailsService() {
        return userDetailsService;
    }

    public void setUserDetailsService(UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }
}
    

现在的问题就是如何在NTLM中配置了,如何配置才能让ch116正常登陆。

实例在ch116。