spring-boot - Spring Boot + Ldap/AD + Kerberos SSO : KrbCryptoException - Checksum failed

标签 spring-boot single-sign-on kerberos spnego spring-security-kerberos

我正在尝试使用 Spring Boot、Ldap 和 kerberos 实现 SSO。对于不同的加密类型,我遇到多个校验和失败错误的地方。

环境细节:-

机器:Windows 10

JDK 版本:Oracle 1.8.0_144(64 位)

我似乎遇到了一个死胡同,我无法找到任何解决方案。

这是我在运行时遇到的错误

Added key: 17version: 5
Added key: 18version: 5
Added key: 23version: 5
Found unsupported keytype (3) for HTTP/host.test@EXAMPLE.COM
Found unsupported keytype (1) for HTTP/host.test@EXAMPLE.COM
>>> EType: sun.security.krb5.internal.crypto.Aes128CtsHmacSha1EType
2019-08-30 11:26:10.746  WARN 6640 --- [p-bio-80-exec-9] w.a.SpnegoAuthenticationProcessingFilter : Negotiate Header was invalid: Negotiate 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

org.springframework.security.authentication.BadCredentialsException: Kerberos validation not successful
    at org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator.validateTicket(SunJaasKerberosTicketValidator.java:71) ~[spring-security-kerberos-core-1.0.1.RELEASE.jar:1.0.1.RELEASE]
    at org.springframework.security.kerberos.authentication.KerberosServiceAuthenticationProvider.authenticate(KerberosServiceAuthenticationProvider.java:64) ~[spring-security-kerberos-core-1.0.1.RELEASE.jar:1.0.1.RELEASE]
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:174) ~[spring-security-core-4.2.3.RELEASE.jar:4.2.3.RELEASE]
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:199) ~[spring-security-core-4.2.3.RELEASE.jar:4.2.3.RELEASE]
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.authenticate(WebSecurityConfigurerAdapter.java:494) ~[spring-security-config-4.2.3.RELEASE.jar:4.2.3.RELEASE]
    at org.springframework.security.kerberos.web.authentication.SpnegoAuthenticationProcessingFilter.doFilter(SpnegoAuthenticationProcessingFilter.java:145) ~[spring-security-kerberos-web-1.0.1.RELEASE.jar:1.0.1.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]

Caused by: java.security.PrivilegedActionException: null
    at java.security.AccessController.doPrivileged(Native Method) ~[na:1.8.0_144]
    at javax.security.auth.Subject.doAs(Subject.java:422) ~[na:1.8.0_144]
    at org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator.validateTicket(SunJaasKerberosTicketValidator.java:68)

Caused by: org.ietf.jgss.GSSException: Failure unspecified at GSS-API level (Mechanism level: Checksum failed)
    at sun.security.jgss.krb5.Krb5Context.acceptSecContext(Krb5Context.java:856) ~[na:1.8.0_144]
    at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:342) ~[na:1.8.0_144]
    at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:285) ~[na:1.8.0_144]
    at sun.security.jgss.spnego.SpNegoContext.GSS_acceptSecContext(SpNegoContext.java:906) ~[na:1.8.0_144]
    at sun.security.jgss.spnego.SpNegoContext.acceptSecContext(SpNegoContext.java:556) ~[na:1.8.0_144]
    at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:342) ~[na:1.8.0_144]
    at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:285) ~[na:1.8.0_144]

Caused by: sun.security.krb5.KrbCryptoException: Checksum failed
    at sun.security.krb5.internal.crypto.Aes128CtsHmacSha1EType.decrypt(Aes128CtsHmacSha1EType.java:102) ~[na:1.8.0_144]
    at sun.security.krb5.internal.crypto.Aes128CtsHmacSha1EType.decrypt(Aes128CtsHmacSha1EType.java:94) ~[na:1.8.0_144]
    at sun.security.krb5.EncryptedData.decrypt(EncryptedData.java:175) ~[na:1.8.0_144]
    at sun.security.krb5.KrbApReq.authenticate(KrbApReq.java:281) ~[na:1.8.0_144]
    at sun.security.krb5.KrbApReq.<init>(KrbApReq.java:149) ~[na:1.8.0_144]
    at sun.security.jgss.krb5.InitSecContextToken.<init>(InitSecContextToken.java:108)

Caused by: java.security.GeneralSecurityException: Checksum failed
    at sun.security.krb5.internal.crypto.dk.AesDkCrypto.decryptCTS(AesDkCrypto.java:451) ~[na:1.8.0_144]

Keytab 文件是我从 windows 服务器生成的,其中 AD 可通过此命令使用 -

ktpass /out test.keytab /mapuser ldap-read@EXAMPLE.COM /princ HTTP/host.test@EXAMPLE.COM /pass password /ptype KRB5_NT_PRINCIPAL /crypto All

通过

为同一用户设置SPN
Setspn –A HTTP/host.test@EXAMPLE.COM ldap-read

通过命令查看keytab文件

ktab -l -e -t -k "C:\Install\test.keytab"

结果

Keytab name: C:\Install\test.keytab
KVNO Timestamp      Principal
---- -------------- ---------------------------------------------------------------------
   5 1/1/70 5:30 AM http/host.test@example.com (1:DES CBC mode with CRC-32)
   5 1/1/70 5:30 AM http/host.test@example.com (3:DES CBC mode with MD5)
   5 1/1/70 5:30 AM http/host.test@example.com (23:RC4 with HMAC)
   5 1/1/70 5:30 AM http/host.test@example.com (18:AES256 CTS mode with HMAC SHA1-96)
   5 1/1/70 5:30 AM http/host.test@example.com (17:AES128 CTS mode with HMAC SHA1-96)

还更新了安全选项的客户端和服务器设置,并标记为允许加密类型

enter image description here

这里是安全配置java文件

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {


@Value("${ldap.url}")
private String ldapUrl;
@Value("${ldap.manager.dn}")
private String ldapManagerDn;
@Value("${ldap.manager.password}")
private String ldapManagerPassword;
@Value("${ldap.user.searchbase}")
private String ldapUserSearchBase;
@Value("${app.service-principal}")
private String servicePrincipal;

@Autowired
private StaffService userService;
@Autowired
CustomAuthenticationProvider customAuthProvider;


@Override
protected void configure(HttpSecurity http) throws Exception {

http.csrf().disable().exceptionHandling().authenticationEntryPoint(spnegoEntryPoint())
    .and().authorizeRequests()
    .antMatchers("/signup","/logout").permitAll()
    .antMatchers("/","/login","/index","/index/**","/projects","/projects/**","/project")
        .fullyAuthenticated()
    .and()
    .formLogin().loginPage("/login")
    .defaultSuccessUrl("/index")
    .and()
    .logout().permitAll()
    .and().headers()
      .frameOptions()
         .sameOrigin()
    .and()
    .addFilterBefore(
    spnegoAuthenticationProcessingFilter(authenticationManagerBean()),
    BasicAuthenticationFilter.class);

}

@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception{

    auth.
    authenticationProvider(kerberosAuthenticationProvider())
    .authenticationProvider(kerberosServiceAuthenticationProvider());
}

    @Bean
    public KerberosAuthenticationProvider kerberosAuthenticationProvider() {
        KerberosAuthenticationProvider provider =
                new KerberosAuthenticationProvider();
        SunJaasKerberosClient client = new SunJaasKerberosClient();
        client.setDebug(true);
        provider.setKerberosClient(client);
        provider.setUserDetailsService(userService);
        return provider;
    }

     @Bean
    public SpnegoEntryPoint spnegoEntryPoint() {
        return new SpnegoEntryPoint("/login");
    }

@Bean
public SpnegoAuthenticationProcessingFilter spnegoAuthenticationProcessingFilter(
        AuthenticationManager authenticationManager) {
    SpnegoAuthenticationProcessingFilter filter =
            new SpnegoAuthenticationProcessingFilter();
    try {
        filter.setAuthenticationManager(authenticationManagerBean());
    } catch (Exception e) {
        e.printStackTrace();
    }
    return filter;
}

    @Bean
    public KerberosServiceAuthenticationProvider kerberosServiceAuthenticationProvider() {
        KerberosServiceAuthenticationProvider provider =
                new KerberosServiceAuthenticationProvider();
        provider.setTicketValidator(sunJaasKerberosTicketValidator());
        provider.setUserDetailsService(userService);
        return provider;
    }

    @Bean
    public SunJaasKerberosTicketValidator sunJaasKerberosTicketValidator() {
        SunJaasKerberosTicketValidator ticketValidator =
                new SunJaasKerberosTicketValidator();
        ticketValidator.setServicePrincipal(servicePrincipal);
        FileSystemResource fs = new FileSystemResource("C:/install/test.keytab");
        ticketValidator.setKeyTabLocation(fs);
        ticketValidator.setDebug(true);
        return ticketValidator;
    }

    @Bean
    public LdapTemplate ldapTemplate() throws Exception{
        LdapTemplate ldapTemplate = new LdapTemplate();
        ldapTemplate.setIgnorePartialResultException(true);
        ldapTemplate.setContextSource(kerberosLdapContextSource());
        return ldapTemplate;
    }

    @Bean
    public KerberosLdapContextSource kerberosLdapContextSource() {
        KerberosLdapContextSource contextSource = new KerberosLdapContextSource(ldapUrl);
        contextSource.setBase(ldapUserSearchBase);
        contextSource.setUserDn(ldapManagerDn);
        contextSource.setPassword(ldapManagerPassword);
        SunJaasKrb5LoginConfig loginConfig = new SunJaasKrb5LoginConfig();
        FileSystemResource fs = new FileSystemResource("C:/install/test.keytab");
        loginConfig.setKeyTabLocation(fs);
        loginConfig.setServicePrincipal(servicePrincipal);
        loginConfig.setDebug(true);
        loginConfig.setUseTicketCache(true);
        loginConfig.setIsInitiator(true);
        contextSource.setLoginConfig(loginConfig);
        return contextSource;
    }

    @Bean
    public LdapUserDetailsService ldapUserDetailsService() {
        FilterBasedLdapUserSearch userSearch =
                new FilterBasedLdapUserSearch(ldapUserSearchBase, ldapUserSearchFilter, kerberosLdapContextSource());
        LdapUserDetailsService service = new LdapUserDetailsService(userSearch);
        CustomLdapUserDetailsMapper customLdapUserDetailsMapper = new CustomLdapUserDetailsMapper();
        service.setUserDetailsMapper(customLdapUserDetailsMapper);
        return service;
    }

    @Bean
    public BCryptPasswordEncoder passwordEncoder() {        
        return new BCryptPasswordEncoder();
    }

    @Bean
    public RestTemplate restTemplate() {
        FileSystemResource fs = new FileSystemResource("C:/install/test.keytab");
        return new KerberosRestTemplate(fs.getPath(),servicePrincipal);
    }
}

以下是 Windows 10 机器中 C:\Windows 中的 krb5.ini 文件的内容:-

[libdefaults]
  forwardable = true
  dns_lookup_kdc = true
  dns_lookup_realm = true
  default_realm = BAUER.DE
  default_keytab_name = "C:\Install\test.keytab"

  default_tkt_enctypes = rc4-hmac aes256-cts aes128-cts des3-cbc-sha1 des-cbc-md5 des-cbc-crc
  default_tgs_enctypes = rc4-hmac aes256-cts aes128-cts des3-cbc-sha1 des-cbc-md5 des-cbc-crc
  permitted_enctypes   = rc4-hmac aes256-cts aes128-cts des3-cbc-sha1 des-cbc-md5 des-cbc-crc

[realms]
  EXAMPLE.COM = {
     kdc = host.test
  }

[domain_realm]
  .host.test = EXAMPLE.COM
  host.test  = EXAMPLE.COM

我还更新了 C:\Program Files\Java\jre1.8.0_191\lib\security 和 C:\Program Files\Java\jdk1.8.0_144\jre 下的 JCE jar 文件\lib\security 文件夹。

应该如何克服这个异常? 是否有任何 Java 代码需要更新或 kerberos 的任何配置是否需要更改。有人有什么想法吗?

更新 1:

校验和问题仍然存在。但是,当我使用 kinit 命令从 JAVA JDK 检查 keytab 文件时,我发现了一个新问题,

我在 JDK 1.8 bin 目录中从服务器执行了以下命令

kinit -k -t "C:\Install\test.keytab" HTTP/host.test@EXAMPLE.COM

得到ICMP端口不可达错误

java.net.PortUnreachableException: ICMP Port Unreachable
        at java.net.DualStackPlainDatagramSocketImpl.socketReceiveOrPeekData(Native Method)
        at java.net.DualStackPlainDatagramSocketImpl.receive0(DualStackPlainDatagramSocketImpl.java:124)
        at java.net.AbstractPlainDatagramSocketImpl.receive(AbstractPlainDatagramSocketImpl.java:143)
        at java.net.DatagramSocket.receive(DatagramSocket.java:812)
        at sun.security.krb5.internal.UDPClient.receive(NetClient.java:206)
        at sun.security.krb5.KdcComm$KdcCommunication.run(KdcComm.java:411)
        at sun.security.krb5.KdcComm$KdcCommunication.run(KdcComm.java:364)
        at java.security.AccessController.doPrivileged(Native Method)
        at sun.security.krb5.KdcComm.send(KdcComm.java:348)
        at sun.security.krb5.KdcComm.sendIfPossible(KdcComm.java:253)
        at sun.security.krb5.KdcComm.send(KdcComm.java:229)
        at sun.security.krb5.KdcComm.send(KdcComm.java:200)

最佳答案

请检查这些(这是我的另一个答案 here 的副本):

  1. 用户登录到操作系统上的域帐户。
  2. 在您的浏览器中正确配置,请参阅 Spring documentation

例如对于 Internet Explorer:

E.3 Internet Explorer

Complete following steps to ensure that your Internet Explorer browser is enabled to perform Spnego authentication.

Open Internet Explorer.
Click Tools > Intenet Options > Security tab.
In Local intranet section make sure your server is trusted by i.e. adding it into a list.

那么您应该检查您的 Authorization HTTP header 值的样子并将其粘贴到此处,因为它不在问题描述中。最好的选择是实现日志过滤器(例如基于 this answer )。此过滤器必须添加在 spnegoAuthenticationProcessingFilter 之前,例如:

.addFilterBefore(serverRequestLoggingFilter(), WebAsyncManagerIntegrationFilter.class)

在您的 SecurityConfig 中。

关于spring-boot - Spring Boot + Ldap/AD + Kerberos SSO : KrbCryptoException - Checksum failed,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57726513/

相关文章:

c# - Nop commerce 从另一个网站单点登录

hadoop - 通过 Knox 获取与 Hive 的 JDBC 连接时出错

authentication - 通过 IP 地址访问站点时 Kerberos 失败

java - Apereo CAS 使用 NTLM 而不是 Kerberos

java - 如何在 Spring Boot 中将 Java 实体映射到多个 MongoDB 集合并为两个集合使用不同的索引?

java - 设置数据库连接属性的不同方式

gradle - spring boot jsps 没有被渲染

java - 集成 OpenAPI 3.0 架构以进行 Spring Boot json 响应测试

java - 如何从 Swing 应用程序获取 Windows 登录凭据?

firebase - 仅使用 Firebase 进行单点登录