2015-06-03 47 views
2

我的任務是通過Java GSS API連接到Kerberized LDAP服務器。我有一個小樣本應用程序,用於測試我的連接,Kerberos配置,連接參數等,以確保我可以連接到LDAP服務器並檢索數據。這樣做的代碼在下面給出:Kerberos和LDAP:爲什麼Java 6在使用Kerberos時截斷LDAP主機名?

import java.io.FileInputStream; 
import java.io.IOException; 
import java.security.PrivilegedActionException; 
import java.security.PrivilegedExceptionAction; 
import java.util.HashMap; 
import java.util.Hashtable; 
import java.util.Map; 
import java.util.Properties; 

import javax.naming.Context; 
import javax.naming.NamingEnumeration; 
import javax.naming.NamingException; 
import javax.naming.directory.Attributes; 
import javax.naming.directory.DirContext; 
import javax.naming.directory.SearchControls; 
import javax.naming.directory.SearchResult; 
import javax.naming.ldap.Control; 
import javax.naming.ldap.InitialLdapContext; 
import javax.security.auth.Subject; 
import javax.security.auth.login.LoginContext; 
import javax.security.auth.login.LoginException; 
import javax.security.auth.spi.LoginModule; 

public class TestKerberizedLdap implements Runnable { 

    public static void main(String[] args) { 
     Runnable rn = null; 
     if (args.length == 1) { 
      rn = new TestKerberizedLdap(args[0]); 
     } 
     else if (args.length == 0) { 
      rn = new TestKerberizedLdap("C:/dev/projects/TestKerberizedLdap/src/testkerberizedldap.properties"); 
     } 
     else { 
      printUsage(); 
      return; 
     } 

     rn.run(); 
    } 

    private static final String loginModuleClassName = "com.sun.security.auth.module.Krb5LoginModule"; 
    private static final String koid = "1.2.840.113554.1.2.2"; 
    private static final String soid = "1.3.6.1.5.5.2"; 

    private Subject subject; 
    private DirContext ldapContext; 
    private String username; 
    private String password; 
    private String ldapHost; 

    private TestKerberizedLdap(String propFileName) { 
     Properties prop = new Properties(); 
     try { 
      FileInputStream iStream = new FileInputStream(propFileName); 
      prop.load(iStream); 
      iStream.close(); 
     } 
     catch (IOException e) { 
      e.printStackTrace(); 
     } 

     System.out.println("Properties found:"); 
     for (String propName : prop.stringPropertyNames()) { 
      System.out.println(propName + " = " + prop.getProperty(propName)); 
     } 
     System.out.println(); 

     System.setProperty("java.security.krb5.conf", prop.getProperty("krbConf")); 
     System.setProperty("java.security.krb5.debug", "true"); 
     System.setProperty("sun.security.krb5.debug", "true"); 

     ldapHost = prop.getProperty("ldapHost"); 
     username = prop.getProperty("user"); 
     password = prop.getProperty("password"); 
     subject = null; 
     ldapContext = null; 
    } 

    public void run() { 
     try { 
      initSubject(); 
      if (subject != null) { 
       initContextKerberized(); 
      } 
     } 
     catch (Exception ex) { 
      ex.printStackTrace(); 
     } 
    } 

    private void initContextKerberized() throws Exception { 
     Subject.doAs(subject, new PrivilegedExceptionAction<Object>() { 
      public Object run() throws Exception { 
       Hashtable<String, String> env = new Hashtable<String, String>(); 
       env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); 
       env.put(Context.PROVIDER_URL, ldapHost); 
       env.put(Context.SECURITY_AUTHENTICATION, "GSSAPI"); 
       ldapContext = new InitialLdapContext(env, new Control[0]); 

       // Do stuff with ldapContext here... 
       searchLdapDirectory(); 

       return null; 
      } 
     }); 
    } 

    private void searchLdapDirectory() throws NamingException { 
     String base = "CN=Users"; 
     String filter = "(objectclass=user)"; 
     SearchControls sc = new SearchControls(); 
     sc.setSearchScope(SearchControls.SUBTREE_SCOPE); 
     NamingEnumeration<SearchResult> ne = ldapContext.search(base, filter, sc); 
     int numElements = 0; 
     System.out.println(); 
     while (ne.hasMoreElements()) { 
      SearchResult sr = ne.nextElement(); 
      Attributes attr = sr.getAttributes(); 
      System.out.println(attr.get("name").get()); 
      numElements++; 
     } 
     System.out.println("The number of elements returned was " + numElements); 
    } 

    private void initSubject() throws InstantiationException, ClassNotFoundException, IllegalAccessException { 
     LoginModule module = null; 
     try { 
      module = (LoginModule) Class.forName(loginModuleClassName).newInstance(); 
      subject = new Subject(); 
      Map<String, String> options = new HashMap<String, String>(); 
      Map<String, Object> sharedState = new HashMap<String, Object>(); 

      if ((username != null) && (password != null)) { 
       sharedState.put("javax.security.auth.login.password", password.toCharArray()); 
       sharedState.put("javax.security.auth.login.name", username); 
       options.put("principal", username); 
       options.put("storeKey", "true"); 
       options.put("useFirstPass", "true"); 
      } 
      else { 
       options.put("principal", username); 
       options.put("useTicketCache", "true"); 
       options.put("doNotPrompt", "true"); 
       options.put("renewTGT", "true"); 
      } 
      options.put("debug", "true"); 
      options.put("refreshKrb5Config", "true"); 

      module.initialize(subject, null, sharedState, options); 
      module.login(); 
      module.commit(); 
     } 
     catch (LoginException ex) { 
      ex.printStackTrace(); 
      subject = null; 
      if (module != null) { 
       try { 
        module.abort(); 
       } 
       catch (LoginException ex2) { 
        ex2.printStackTrace(); 
       } 
      } 
     } 
    } 

    private static void printUsage() { 
     System.out.println(); 
     System.out.println("Usage: TestKerberizedLdap <property file name>"); 
     System.out.println(); 
    } 
} 

內testkerberized.properties文件中, 「ldapHost」 屬性被定義爲「LDAP://dv2k8ad.2k8.hlp.net:389/DC = 2K8, DC = HLP,DC =淨」。

現在,當我用Java 7運行這個應用程序時,它就像一個魅力。 Kerberos身份驗證成功,並且從LDAP服務器成功檢索數據。但是,我不能讓它與Java 6,不斷給我下面的異常運行:

Found ticket for [email protected] to go to krbtgt/[email protected] expiring on Thu Jun 04 00:47:07 PDT 2015 
Entered Krb5Context.initSecContext with state=STATE_NEW 
Found ticket for [email protected] to go to krbtgt/[email protected] expiring on Thu Jun 04 00:47:07 PDT 2015 
Service ticket not found in the subject 
>>> Credentials acquireServiceCreds: same realm 
default etypes for default_tgs_enctypes: 23 16 3 1. 
>>> CksumType: sun.security.krb5.internal.crypto.RsaMd5CksumType 
>>> EType: sun.security.krb5.internal.crypto.ArcFourHmacEType 
>>> KrbKdcReq send: kdc=172.23.5.151 UDP:88, timeout=30000, number of retries =3, #bytes=1289 
>>> KDCCommunication: kdc=172.23.5.151 UDP:88, timeout=30000,Attempt =1, #bytes=1289 
>>> KrbKdcReq send: #bytes read=92 
>>> KrbKdcReq send: #bytes read=92 
>>> KdcAccessibility: remove 172.23.5.151:88 
>>> KDCRep: init() encoding tag is 126 req type is 13 
>>>KRBError: 
    sTime is Wed Jun 03 14:47:07 PDT 2015 1433368027000 
    suSec is 109093 
    error code is 7 
    error Message is Server not found in Kerberos database 
    realm is 2K8.HLP.NET 
    sname is ldap/2k8.hlp.net 
    msgType is 30 
java.security.PrivilegedActionException: javax.naming.AuthenticationException: GSSAPI [Root exception is javax.security.sasl.SaslException: GSS initiate failed [Caused by GSSException: No valid credentials provided (Mechanism level: Server not found in Kerberos database (7))]] 
    at java.security.AccessController.doPrivileged(Native Method) 
    at javax.security.auth.Subject.doAs(Subject.java:396) 
    at TestKerberizedLdap.initContextKerberized(TestKerberizedLdap.java:95) 
    at TestKerberizedLdap.run(TestKerberizedLdap.java:85) 
    at TestKerberizedLdap.main(TestKerberizedLdap.java:39) 
Caused by: javax.naming.AuthenticationException: GSSAPI [Root exception is javax.security.sasl.SaslException: GSS initiate failed [Caused by GSSException: No valid credentials provided (Mechanism level: Server not found in Kerberos database (7))]] 
    at com.sun.jndi.ldap.sasl.LdapSasl.saslBind(LdapSasl.java:150) 
    at com.sun.jndi.ldap.LdapClient.authenticate(LdapClient.java:214) 
    at com.sun.jndi.ldap.LdapCtx.connect(LdapCtx.java:2694) 
    at com.sun.jndi.ldap.LdapCtx.<init>(LdapCtx.java:293) 
    at com.sun.jndi.ldap.LdapCtxFactory.getUsingURL(LdapCtxFactory.java:175) 
    at com.sun.jndi.ldap.LdapCtxFactory.getUsingURLs(LdapCtxFactory.java:193) 
    at com.sun.jndi.ldap.LdapCtxFactory.getLdapCtxInstance(LdapCtxFactory.java:136) 
    at com.sun.jndi.ldap.LdapCtxFactory.getInitialContext(LdapCtxFactory.java:66) 
    at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:667) 
    at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:288) 
    at javax.naming.InitialContext.init(InitialContext.java:223) 
    at javax.naming.ldap.InitialLdapContext.<init>(InitialLdapContext.java:134) 
    at TestKerberizedLdap$1.run(TestKerberizedLdap.java:101) 
    ... 5 more 
Caused by: javax.security.sasl.SaslException: GSS initiate failed [Caused by GSSException: No valid credentials provided (Mechanism level: Server not found in Kerberos database (7))] 
    at com.sun.security.sasl.gsskerb.GssKrb5Client.evaluateChallenge(GssKrb5Client.java:194) 
    at com.sun.jndi.ldap.sasl.LdapSasl.saslBind(LdapSasl.java:105) 
    ... 17 more 
Caused by: GSSException: No valid credentials provided (Mechanism level: Server not found in Kerberos database (7)) 
    at sun.security.jgss.krb5.Krb5Context.initSecContext(Krb5Context.java:663) 
    at sun.security.jgss.GSSContextImpl.initSecContext(GSSContextImpl.java:230) 
    at sun.security.jgss.GSSContextImpl.initSecContext(GSSContextImpl.java:162) 
    at com.sun.security.sasl.gsskerb.GssKrb5Client.evaluateChallenge(GssKrb5Client.java:175) 
    ... 18 more 
Caused by: KrbException: Server not found in Kerberos database (7) 
    at sun.security.krb5.KrbTgsRep.<init>(KrbTgsRep.java:61) 
    at sun.security.krb5.KrbTgsReq.getReply(KrbTgsReq.java:185) 
    at sun.security.krb5.internal.CredentialsUtil.serviceCreds(CredentialsUtil.java:294) 
    at sun.security.krb5.internal.CredentialsUtil.acquireServiceCreds(CredentialsUtil.java:106) 
    at sun.security.krb5.Credentials.acquireServiceCreds(Credentials.java:557) 
    at sun.security.jgss.krb5.Krb5Context.initSecContext(Krb5Context.java:594) 
    ... 21 more 
Caused by: KrbException: Identifier doesn't match expected value (906) 
    at sun.security.krb5.internal.KDCRep.init(KDCRep.java:133) 
    at sun.security.krb5.internal.TGSRep.init(TGSRep.java:58) 
    at sun.security.krb5.internal.TGSRep.<init>(TGSRep.java:53) 
    at sun.security.krb5.KrbTgsRep.<init>(KrbTgsRep.java:46) 
    ... 26 more 

值得一提的是,module.commit()成功,併成功獲得的對象,所以沒有問題。但我注意到KrbError消息中的sname字段已關閉。它說ldap/2k8.hlp.net,而它應該是ldap/dv2k8ad.2k8.hlp.net。

之後,我運行了Wireshark會話來捕獲所有正在發送的Kerberos數據包,並且在Java 6和Java 7上運行TestKerberizedLdap時捕獲了數據包.GTT被成功獲取,因爲程序獲得了成功的AS- REP兩種情況。但是,發送給KDC的TGS-REQ具有不同的值。 Java 6發送的服務器名稱是ldap/2k8.hlp.net,Java 7發送的服務器名稱是ldap/dv2k8ad.2k8.hlp.net

我不知道爲什麼Java 6會選擇修剪LDAP主機名。如果有人知道解決方法或解決方法(缺少更新Java),我會很感激任何幫助。

+0

檢查反向DNS? –

+0

是的,但一切都在那裏。 –

回答

0

耶,解決了!

這是Java 1.6.0_22中的一個錯誤。我切換到使用Java 1.6.0_45,和一切工作像一個魅力:)