3

I have to connect to a CIFS share from a Java program without mounting it, so I took KerberosAuthExample from jcifs-krb5 and slightly modified it; here is the code:

import java.util.HashMap;
import java.util.Map;

import javax.security.auth.Subject;
import javax.security.auth.login.LoginException;

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

import jcifs.Config;
import jcifs.smb.Kerb5Authenticator;
import jcifs.smb.SmbFile;

public class KerberosAuthExample {
    private static String NAME = "MySamAccountName";
    private static String PWD = "MyPassword";
    private static String URL = "smb://servername/path/" ;
    private static String KDC = "dc.mydomain";
    private static String REALM = "MYREALM";

    public static void main(String[] args) throws LoginException {
        // Nothing changes if I remove the following properties
        Config.setProperty("jcifs.smb.client.capabilities",Kerb5Authenticator.CAPABILITIES);
        Config.setProperty("jcifs.smb.client.flags2",Kerb5Authenticator.FLAGS2);
        Config.setProperty("jcifs.smb.client.signingPreferred", "true");
        try {
            Subject subject = new Subject();
            doLogin(subject);

            SmbFile file = new SmbFile(URL, new Kerb5Authenticator(subject));
            SmbFile[] files = file.listFiles();
            for( int i = 0; i < files.length; i++ )
                System.out.println( "-->" + files[i].getName() );

        } catch (Exception e) {
            e.printStackTrace();
        } 
    }

    public static void doLogin(Subject subject) throws LoginException{
        System.setProperty("java.security.krb5.kdc", KDC);
        System.setProperty("java.security.krb5.realm", REALM);
//        System.setProperty("sun.security.krb5.debug", "true") ;

        Map<String,Object> state = new HashMap<String,Object>();
        state.put("javax.security.auth.login.name", NAME);
        state.put("javax.security.auth.login.password", PWD.toCharArray());

        Map<String,Object> option = new HashMap<String,Object>();
//        option.put("debug", "true");
        option.put("tryFirstPass", "true");
        option.put("useTicketCache", "false");
        option.put("doNotPrompt", "false");
        option.put("storePass", "false");

        Krb5LoginModule login = new Krb5LoginModule();
        login.initialize(subject, null, state, option);

        if(login.login()){
            login.commit();
        }
    }
}

This program runs correctly, i.e., it prints the files and directories contained in the path defined in URL, but an exception is printed from SmbFile.listFiles:

GSSException: No valid credentials provided (Mechanism level: Server not found in Kerberos database (7))
    at sun.security.jgss.krb5.Krb5Context.initSecContext(Krb5Context.java:710)
    at sun.security.jgss.GSSContextImpl.initSecContext(GSSContextImpl.java:248)
    at sun.security.jgss.GSSContextImpl.initSecContext(GSSContextImpl.java:179)
    at jcifs.smb.SpnegoContext.initSecContext(SpnegoContext.java:80)
    at jcifs.smb.Kerb5Authenticator.setup(Kerb5Authenticator.java:196)
    at jcifs.smb.Kerb5Authenticator.access$000(Kerb5Authenticator.java:30)
    at jcifs.smb.Kerb5Authenticator$1.run(Kerb5Authenticator.java:168)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.security.auth.Subject.doAs(Subject.java:415)
    at jcifs.smb.Kerb5Authenticator.sessionSetup(Kerb5Authenticator.java:166)
    at jcifs.smb.SmbSession.sessionSetup(SmbSession.java:320)
    at jcifs.smb.SmbSession.send(SmbSession.java:239)
    at jcifs.smb.SmbTree.treeConnect(SmbTree.java:176)
    at jcifs.smb.SmbTree.send(SmbTree.java:74)
    at jcifs.smb.SmbTransport.getDfsReferrals(SmbTransport.java:771)
    at jcifs.smb.Dfs.getTrustedDomains(Dfs.java:85)
    at jcifs.smb.Dfs.resolve(Dfs.java:220)
    at jcifs.smb.SmbFile.doConnect(SmbFile.java:916)
    at jcifs.smb.SmbFile.connect(SmbFile.java:974)
    at <mypackage>.KerberosAuthExample.main(KerberosAuthExample.java:34)
Caused by: KrbException: Server not found in Kerberos database (7)
    at sun.security.krb5.KrbTgsRep.<init>(KrbTgsRep.java:70)
    at sun.security.krb5.KrbTgsReq.getReply(KrbTgsReq.java:192)
    at sun.security.krb5.KrbTgsReq.sendAndGetCreds(KrbTgsReq.java:203)
    at sun.security.krb5.internal.CredentialsUtil.serviceCreds(CredentialsUtil.java:311)
    at sun.security.krb5.internal.CredentialsUtil.acquireServiceCreds(CredentialsUtil.java:115)
    at sun.security.krb5.Credentials.acquireServiceCreds(Credentials.java:449)
    at sun.security.jgss.krb5.Krb5Context.initSecContext(Krb5Context.java:641)
    ... 19 more
Caused by: KrbException: Identifier doesn't match expected value (906)
    at sun.security.krb5.internal.KDCRep.init(KDCRep.java:143)
    at sun.security.krb5.internal.TGSRep.init(TGSRep.java:66)
    at sun.security.krb5.internal.TGSRep.<init>(TGSRep.java:61)
    at sun.security.krb5.KrbTgsRep.<init>(KrbTgsRep.java:55)
    ... 25 more

The exception is printed three times, then the list of files is correctly printed.

I found many pages with the error "Server not found in Kerberos database", which led me to double check DNS lookups and always use fully qualified names; anyway, in all the cases I could find the connection failed, while in my case it works, it's just very very noisy.

When I enable debugging, I get a lot of information, the most relevant appears to be the KRBError:

>>>KRBError:
     sTime is Fri Oct 28 11:00:51 CEST 2016 1477645251000
     suSec is 237586
     error code is 7
     error Message is Server not found in Kerberos database
     realm is <MYREALM>
     sname is cifs/<domainname>
     msgType is 30

We don't have a test Active Directory domain, so I am using our production domain, and I don't have much control over it. Any idea to avoid all this noise?

0 Answers0