2011-12-14 4 views
8

Kerberos/AD 인증이 Spring 웹 응용 프로그램과 함께 작동하는 데 문제가 있습니다. 문제는 Kerberos 티켓 및 Active Directory의 암호화 유형과 관련이 있다고 생각합니다. 도메인 기능 수준.체크섬 실패 : Kerberos/Spring/Active Directory (2008)

기본 설정은 다음과 같습니다

나는 하나의 Active Directory 도메인 기능 수준이 Windows Server 2003이고 모든 것이 잘 작동하며 클라이언트가 도메인에 로그온 한 경우 클라이언트가 예상대로 인증됩니다. 이 환경에서 kerbtray를 사용하여 티켓을 살펴보면 티켓 암호화 유형과 키 암호화 유형이 모두 "RSADSI RC4-HMAC"임을 알 수 있습니다.

기능 수준이 Windows Server 2008 인 새 도메인이 있으며 인증이 작동하지 않는 곳입니다.

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) 

스택 추적은 "ArcfourCrypto.decrypt"그래서 아마도 RC4-HMAC로 Kerberos 티켓을 취급하고를 보여줍니다 : 응용 프로그램 오류가 티켓의 유효성을 검사 할 때입니다 돌아왔다. 이번에 kerbtray를 사용하여 티켓을 다시 살펴보면 krbtgt/.COM이라는 도메인의 클라이언트에 2 개의 티켓이 있습니다. 두 티켓 모두 키 암호화 유형이 RSADS1 RC4-HMAC이고 티켓 암호화 유형에도이 티켓이 있지만 다른 카드에는 "Kerberos AES256-CTS-HMAC-SHA1-96"이 있습니다.

이 문제의 원인인지 확실하지 않지만 인증 예외를 설명 할 수있는 두 가지 환경에서 찾을 수있는 유일한 차이점이 있습니다. AD 암호화 정책을 변경해 보았습니다. IE와 Firefox를 사용하고 다른 모든 것들을 생각할 수 있었지만 아무 것도 효과가 없었습니다.

이 문제를 해결할 수있는 도움을 주시면 감사하겠습니다. 아마 내가 프로덕션 광고 설정에 대해 너무 많은 것을 지시 할 수는 없기 때문에 그것을 자바 엔드에서 수정하는 것을 선호한다.

+0

Wireshark에서 통신을 확인하고 티켓을 검사 받으셨습니까? –

+0

Thanks @ Michael-O - 이전에 작업 할 때 Wireshark를 사용했지만 더 이상 사용할 수있는 출력이 없습니다.이 작업을 전혀 수행 할 수 없었습니다. 테스트 도메인을 Windows Server 2003 기능 수준으로 되 돌렸습니다. 그런 다음 정상적으로 작동했습니다. 이제는 새로운 2008 테스트 도메인을 설정하여 실행 가능한 솔루션을 찾으십시오. – slt

답변

0

문제는 토큰이 생성되는 방식과 서버 측에서 검증되는 방식에 있습니다. 예외 추적에서 클라이언트 측에서 체크섬을 설정하지 않고 서버 측에서 체크섬의 유효성을 검사 할 문제가 있음을 보여줍니다. 체크섬은 확실한 의미가있는 토큰에 설정된 params 값 중 ​​하나입니다.

체크섬 검사를 무시하려면이 기능을 사용하지 않도록 설정하는 방법이 2008 년에 있어야합니다. 그러나 다른 문을 열면 잔여 위험을 평가해야 할 수도 있습니다.

16

문제는 키탭에있는 것 같습니다. 일부 특정 키탭 파일 상태로 이어지는 동작 시퀀스가 ​​있습니다. (A) keytab은 Java에서 작동하지만 k5start/kinit에서는 작동하지 않습니다. (B) keytab은 Java에서는 작동하지 않지만 k5start/kinit에서 작동합니다. (C) keytab은 두 키 탭 모두에서 작동합니다.

자바는 키 탭 파일을 사용하여 인증 할 수 있는지 확인 할 수 있습니다 짧은 Java 코드 :

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]); 
    } 
} 

을하고, 등록 정보 파일 사용하기 :

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

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

을 (우리가 KRB 가정 아래/kdc가 올바르게 설치되고 구성되면 데이터베이스가 kdb5_util로 생성됩니다. 각 명령 시퀀스의 시작 상태는 keytab 파일이 삭제되고 토큰 캐시가 삭제되며 사용자 "foo"가 데이터베이스에서 삭제됩니다.

,515,가

다음 동작 시퀀스가 ​​키 탭 상태 리드 (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 [email protected] 
Password for [email protected]: 
k5start: error getting credentials: Decrypt integrity check failed 
$ 

다음 동작 시퀀스가 ​​키 탭 상태 (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 [email protected]PLE.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 
$ 

그러나 "k5start foo"는 "kinit foo"뿐만 아니라이 상태에서도 괜찮습니다.


다음 동작 시퀀스는 상태 (C)로 이어진다

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

그 후 두 k5start/kinit는 상기 자바 검증이 긍정적 인 결과를 제공한다.


환경 : 또한

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) 

는 또한 동일한 동작이 MIT의 Kerberos를 5-1.10.3와 정확한 우분투 (12.04.1 LTS)에서 관찰되었다 컴파일 7. 자바 관찰 같은 동작 소스 배포판에서.

+4

좋은 철저한 답변! – Hbcdev

+0

@Ivan - 키탭에서 티켓을 가져올 수 있습니다. 그러나 Java 7 코드에서는 Checksum failed 오류로 갑자기 실패했습니다. keytab을 재 작성하는 것이 유일한 옵션입니까? –