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?