简体   繁体   English

校验和失败:Kerberos / Spring / Active Directory(2008)

[英]checksum failed: Kerberos / Spring / Active Directory (2008)

We are having trouble getting Kerberos/AD authentication to work with a Spring webapp, and I believe the problem has to do with encryption types for the Kerberos tickets and the Active Directory domain functional level. 我们无法使用Kerberos / AD身份验证来使用Spring Web应用程序,我认为该问题与Kerberos票证和Active Directory域功能级别的加密类型有关。

The basic setup is: 基本设置是:

I have one environment where the Active Directory domain functional level is Windows Server 2003 and everything works fine, with clients authenticating as expected if they are logged on to the domain. 我有一个环境,其中Active Directory域功能级别是Windows Server 2003,一切正常,如果客户端登录到域,则客户端按预期进行身份验证。 Using kerbtray to examine the tickets in this environment I can see that they all have both ticket encryption type and key encryption type "RSADSI RC4-HMAC". 使用kerbtray检查此环境中的票证我可以看到它们都具有票证加密类型和密钥加密类型“RSADSI RC4-HMAC”。

I have a new domain with functional level Windows Server 2008, and this is where the authentication does not work. 我有一个功能级别为Windows Server 2008的新域,这是身份验证不起作用的地方。 The application error returned when attempting to validate the ticket is: 尝试验证票证时返回的应用程序错误是:

Kerberos validation not successful...

Caused by: GSSException: Failure unspecified at GSS-API level (Mechanism level: Checksum failed)
    at sun.security.jgss.krb5.Krb5Context.acceptSecContext(Unknown Source)
    at sun.security.jgss.GSSContextImpl.acceptSecContext(Unknown Source)
    at sun.security.jgss.GSSContextImpl.acceptSecContext(Unknown Source)
    at sun.security.jgss.spnego.SpNegoContext.GSS_acceptSecContext(Unknown Source)
    at sun.security.jgss.spnego.SpNegoContext.acceptSecContext(Unknown Source)
    at sun.security.jgss.GSSContextImpl.acceptSecContext(Unknown Source)
    at sun.security.jgss.GSSContextImpl.acceptSecContext(Unknown Source)
    at org.springframework.security.extensions.kerberos.SunJaasKerberosTicketValidator$KerberosValidateAction.run(SunJaasKerberosTicketValidator.java:146)
    at org.springframework.security.extensions.kerberos.SunJaasKerberosTicketValidator$KerberosValidateAction.run(SunJaasKerberosTicketValidator.java:136)
    ... 34 more
Caused by: KrbException: Checksum failed
    at sun.security.krb5.internal.crypto.ArcFourHmacEType.decrypt(Unknown Source)
    at sun.security.krb5.internal.crypto.ArcFourHmacEType.decrypt(Unknown Source)
    at sun.security.krb5.EncryptedData.decrypt(Unknown Source)
    at sun.security.krb5.KrbApReq.authenticate(Unknown Source)
    at sun.security.krb5.KrbApReq.<init>(Unknown Source)
    at sun.security.jgss.krb5.InitSecContextToken.<init>(Unknown Source)
    ... 43 more
Caused by: java.security.GeneralSecurityException: Checksum failed
    at sun.security.krb5.internal.crypto.dk.ArcFourCrypto.decrypt(Unknown Source)
    at sun.security.krb5.internal.crypto.ArcFourHmac.decrypt(Unknown Source)

The stack trace shows "ArcfourCrypto.decrypt" so presumably is treating the Kerberos ticket as RC4-HMAC. 堆栈跟踪显示“ArcfourCrypto.decrypt”,因此可能将Kerberos票证视为RC4-HMAC。 Using kerbtray again to examine the tickets this time there are 2 tickets on the client for the domain: krbtgt/.COM. 再次使用kerbtray检查票证,客户端上有2个票证:krbtgt / .COM。 Both of tickets have key encryption type RSADS1 RC4-HMAC, one also has this for ticket encryption type, but the other has "Kerberos AES256-CTS-HMAC-SHA1-96". 两个票据都有密钥加密类型RSADS1 RC4-HMAC,其中一个也有票据加密类型,但另一个有“Kerberos AES256-CTS-HMAC-SHA1-96”。

I don't know for sure that this is the cause of the problem, but it is the only difference I've been able to find in the two environments that might explain the authentication exception. 我不确定这是问题的原因,但这是我能够在两个可能解释身份验证异常的环境中找到的唯一区别。 I've tried changing the AD encryption policy, tried IE and Firefox, and pretty much everything else I could think of, but nothing has worked. 我已经尝试过更改AD加密策略,尝试过IE和Firefox,以及我能想到的其他所有内容,但没有任何效果。

Any help addressing this would be much appreciated. 任何解决这个问题的帮助都将非常感激。 I'd prefer to fix it on the java end as I probably can't dictate too much about the production AD setup. 我更喜欢在java端修复它,因为我可能无法过多地关注生产AD设置。

The problem seems to be in the keytab. 问题似乎在关键表中。 There are some action sequences leading to some specific keytab file states: (A) keytab works with Java but does not work with k5start/kinit; 有一些操作序列导致某些特定的keytab文件状态:(A)keytab与Java一起使用但不适用于k5start / kinit; (B) keytab does not work with Java, but works with k5start/kinit; (B)keytab不适用于Java,但适用于k5start / kinit; (C) keytab works with both them. (C)keytab适用于它们。

The short Java code that allows to check if Java can authenticate using the keytab file: 简短的Java代码,允许检查Java是否可以使用keytab文件进行身份验证:

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import javax.security.auth.Subject;

import com.sun.security.auth.module.Krb5LoginModule;

/**
 * This is simple Java program that tests ability to authenticate 
 * with Kerberos using the JDK implementation.
 * 
 * The program uses no libraries but JDK itself.
 */
public class Krb {

  private void loginImpl(final String propertiesFileName) throws Exception {
    System.out.println("NB: system property to specify the krb5 config: [java.security.krb5.conf]");
    //System.setProperty("java.security.krb5.conf", "/etc/krb5.conf");

    System.out.println(System.getProperty("java.version"));

    System.setProperty("sun.security.krb5.debug", "true");

    final Subject subject = new Subject();

    final Krb5LoginModule krb5LoginModule = new Krb5LoginModule();
    final Map<String,String> optionMap = new HashMap<String,String>();

    if (propertiesFileName == null) {
      //optionMap.put("ticketCache", "/tmp/krb5cc_1000");
      optionMap.put("keyTab", "/etc/krb5.keytab");
      optionMap.put("principal", "foo"); // default realm

      optionMap.put("doNotPrompt", "true");
      optionMap.put("refreshKrb5Config", "true");
      optionMap.put("useTicketCache", "true");
      optionMap.put("renewTGT", "true");
      optionMap.put("useKeyTab", "true");
      optionMap.put("storeKey", "true");
      optionMap.put("isInitiator", "true");
    } else {
      File f = new File(propertiesFileName);
      System.out.println("======= loading property file ["+f.getAbsolutePath()+"]");
      Properties p = new Properties();
      InputStream is = new FileInputStream(f);
      try {
        p.load(is);
      } finally {
        is.close();
      }
      optionMap.putAll((Map)p);
    }
    optionMap.put("debug", "true"); // switch on debug of the Java implementation

    krb5LoginModule.initialize(subject, null, new HashMap<String,String>(), optionMap);

    boolean loginOk = krb5LoginModule.login();
    System.out.println("======= login:  " + loginOk);

    boolean commitOk = krb5LoginModule.commit();
    System.out.println("======= commit: " + commitOk);

    System.out.println("======= Subject: " + subject);
  }

  public static void main(String[] args) throws Exception {
    System.out.println("A property file with the login context can be specified as the 1st and the only paramater.");
    final Krb krb = new Krb();
    krb.loginImpl(args.length == 0 ? null : args[0]);
  }
}

, and the property file to use: ,以及要使用的属性文件:

#ticketCache=/tmp/krb5cc_1000
keyTab=/etc/krb5.keytab
principal=foo

doNotPrompt=true
refreshKrb5Config=true
useTicketCache=true
renewTGT=true
useKeyTab=true
storeKey=true
isInitiator=true

(Below we assume that krb/kdc is correctly installed and configured, the database is created with kdb5_util. The starting state of each command sequence is: the keytab file deleted, token cache is deleted, user "foo" is deleted from the database.) (下面我们假设krb / kdc已正确安装和配置,数据库是用kdb5_util创建的。每个命令序列的起始状态是:删除keytab文件,删除令牌缓存,从数据库中删除用户“foo”。 )


The following action sequence leads to the keytab state (A): 以下操作序列将导致keytab状态(A):

$ echo -e "foo\nfoo" | kadmin.local -q "addprinc foo"
$ echo -e "foo\nfoo" | kadmin.local -q "ktadd foo"
$ java -cp . Krb ./krb5.properties 
# Now java auth okay, but the following command fails:
$ k5start foo
Kerberos initialization for foo@EXAMPLE.COM
Password for foo@EXAMPLE.COM: 
k5start: error getting credentials: Decrypt integrity check failed
$

The following action sequence leads to the keytab state (B): 以下操作序列将导致keytab状态(B):

$ echo -e "foo\nfoo" | kadmin.local -q "addprinc foo"
$ echo -e "foo\nfoo" | kadmin.local -q "ktadd foo"
$ echo -e "foo\nfoo" | kadmin.local -q "cpw foo"
$ java -cp . Krb ./krb5.properties 
A property file with the login context can be specified as the 1st and the only paramater.
NB: system property to specify the krb5 config: [java.security.krb5.conf]
1.6.0_33
======= loading property file [/tmp/krb-test/yhadoop-common/./krb5.properties]
Debug is  true storeKey true useTicketCache true useKeyTab true doNotPrompt true ticketCache is null isInitiator true KeyTab is /etc/krb5.keytab refreshKrb5Config is true principal is foo tryFirstPass is false useFirstPass is false storePass is false clearPass is false
Refreshing Kerberos configuration
Config name: /etc/krb5.conf
>>> KdcAccessibility: reset
>>> KdcAccessibility: reset
Acquire TGT from Cache
>>>KinitOptions cache name is /tmp/krb5cc_0
Principal is foo@EXAMPLE.COM
null credentials from Ticket Cache
>>> KeyTabInputStream, readName(): EXAMPLE.COM
>>> KeyTabInputStream, readName(): foo
>>> KeyTab: load() entry length: 49; type: 23
Added key: 23version: 3
Ordering keys wrt default_tkt_enctypes list
default etypes for default_tkt_enctypes: 23.
0: EncryptionKey: keyType=23 kvno=3 keyValue (hex dump)=
0000: 5F 7F 9B 42 BB 02 51 81   32 05 1D 7B C0 9F 19 C0  _..B..Q.2.......


principal's key obtained from the keytab
Acquire TGT using AS Exchange
default etypes for default_tkt_enctypes: 23.
>>> KrbAsReq calling createMessage
>>> KrbAsReq in createMessage
>>> KrbKdcReq send: kdc=localhost UDP:88, timeout=30000, number of retries =3, #bytes=128
>>> KDCCommunication: kdc=localhost UDP:88, timeout=30000,Attempt =1, #bytes=128
>>> KrbKdcReq send: #bytes read=611
>>> KrbKdcReq send: #bytes read=611
>>> KdcAccessibility: remove localhost:88
>>> EType: sun.security.krb5.internal.crypto.ArcFourHmacEType
Checksum failed !
                [Krb5LoginModule] authentication failed 
Checksum failed
Exception in thread "main" javax.security.auth.login.LoginException: Checksum failed
        at com.sun.security.auth.module.Krb5LoginModule.attemptAuthentication(Krb5LoginModule.java:696)
        at com.sun.security.auth.module.Krb5LoginModule.login(Krb5LoginModule.java:542)
        at Krb.loginImpl(Krb.java:65)
        at Krb.main(Krb.java:77)
Caused by: KrbException: Checksum failed
        at sun.security.krb5.internal.crypto.ArcFourHmacEType.decrypt(ArcFourHmacEType.java:85)
        at sun.security.krb5.internal.crypto.ArcFourHmacEType.decrypt(ArcFourHmacEType.java:77)
        at sun.security.krb5.EncryptedData.decrypt(EncryptedData.java:168)
        at sun.security.krb5.KrbAsRep.<init>(KrbAsRep.java:87)
        at sun.security.krb5.KrbAsReq.getReply(KrbAsReq.java:446)
        at sun.security.krb5.Credentials.sendASRequest(Credentials.java:401)
        at sun.security.krb5.Credentials.acquireTGT(Credentials.java:350)
        at com.sun.security.auth.module.Krb5LoginModule.attemptAuthentication(Krb5LoginModule.java:672)
        ... 3 more
Caused by: java.security.GeneralSecurityException: Checksum failed
        at sun.security.krb5.internal.crypto.dk.ArcFourCrypto.decrypt(ArcFourCrypto.java:388)
        at sun.security.krb5.internal.crypto.ArcFourHmac.decrypt(ArcFourHmac.java:74)
        at sun.security.krb5.internal.crypto.ArcFourHmacEType.decrypt(ArcFourHmacEType.java:83)
        ... 10 more
$

But the "k5start foo" is okay in this state, as well as "kinit foo". 但是“k5start foo”在这个状态下还可以,还有“kinit foo”。


And the following action sequence leads to state (C): 并且以下动作序列导致状态(C):

$ echo -e "foo\nfoo" | kadmin.local -q "addprinc foo"
$ ktutil 
ktutil:  addent -password -p foo -k 1 -e rc4-hmac
Password for foo@EXAMPLE.COM: 
ktutil:  wkt /etc/krb5.keytab
ktutil:  q

after that both k5start/kinit and the java verification give positive result. 之后,k5start / kinit和java验证都给出了积极的结果。


Environment: 环境:

yum list krb5-appl-servers krb5-libs krb5-server krb5-workstation kstart pam_krb5 
...
Installed Packages
krb5-libs.x86_64                                                                            1.9-33.el6_3.3                                                                      @updates
krb5-server.x86_64                                                                          1.9-33.el6_3.3                                                                      @updates
krb5-workstation.x86_64                                                                     1.9-33.el6_3.3                                                                      @updates
kstart.x86_64                                                                               4.1-2.el6                                                                           @epel   
...
$ cat /etc/redhat-release 
CentOS release 6.3 (Final)
$ java -version
java version "1.6.0_33"
Java(TM) SE Runtime Environment (build 1.6.0_33-b03)
Java HotSpot(TM) 64-Bit Server VM (build 20.8-b03, mixed mode)

Also the same behavior observed with Java 7. Also the same behavior was observed on Ubuntu precise (12.04.1 LTS) with MIT's kerberos 5-1.10.3 compiled from the source distribution. 使用Java 7也观察到相同的行为。在Ubuntu精确(12.04.1 LTS)上观察到相同的行为,MIT的kerberos 5-1.10.3从源分发编译。

The problem is with how token is generated vs how it is validated on server side. 问题在于如何生成令牌与在服务器端验证令牌的方式。 From the exception trace, it shows the issue is, client side is not setting checksum and server side is looking to validate the checksum. 从异常跟踪,它显示的问题是,客户端没有设置校验和,服务器端正在寻找验证校验和。 Checksum is one of the params value set in the token which has it obvious meaning. 校验和是令牌中设置的参数值之一,具有明显的含义。

There must be a way in 2008 to disable this feature to ignore checksum check. 在2008年必须有一种方法来禁用此功能以忽略校验和检查。 But opens another door and you may need to evaluate residual risk. 但打开另一扇门,你可能需要评估剩余风险。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Kerberos/Spring Security/IE/Active Directory 出现“检测到缺陷令牌”错误(NTLM 而非 Kerberos) - "Defective token detected" error (NTLM not Kerberos) with Kerberos/Spring Security/IE/Active Directory Spring Security Kerberos + AD,校验和失败 - Spring Security Kerberos + AD, Checksum Fail 通过Kerberos使用Active Directory进行身份验证 - Authenticating with Active Directory via Kerberos 使用活动目录的Spring Security身份验证失败 - Spring security authentication using active directory failed Java SSO:针对 Active Directory 的 Kerberos 身份验证 - Java SSO: Kerberos authentication against Active Directory Spring Security / SPNEGO身份验证问题:校验和失败 - Spring Security/SPNEGO authentication issue: Checksum failed Gerrit 2.15.12 - Kerberos + GSSAPI + Active Directory - 发送SPN时可能出现的错误 - Gerrit 2.15.12 - Kerberos + GSSAPI + Active Directory - possible bug in sending SPN 使用Active Directory用户主体名称进行Java Kerberos身份验证 - Java Kerberos authentication using Active Directory User Principal Name Java-JNDI / Active Directory / Kerberos / WebLogic Server-密码配置 - Java - JNDI / Active Directory / Kerberos / WebLogic Server - Password Configuration JRE错误? (使用kerberos的Active Directory身份验证问题) - JRE bug? (Active directory authentication issue using kerberos)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM