Multi-Realm Kerberos Authentication in Java Applications
Kerberos Protocol Fundamentals
Kerberos provides mutual authentication between entities over insecure networks using symmetric key cryptography and a trusted third party. The protocol operates through ticket-based exchanges where authentication tokens are issued by a Key Distribution Center (KDC), eliminating password transmission after initial authentication.
Java Security Configuration
JAAS Login Configuration
Create a login configuration file defining authentication contexts for different service principals:
// auth.conf
ClientAuthContext {
com.sun.security.auth.module.Krb5LoginModule required
useKeyTab=true
keyTab="/secure/keys/client.keytab"
storeKey=true
principal="clientapp@CORP.DOMAIN";
};
ServiceAuthContext {
com.sun.security.auth.module.Krb5LoginModule required
useKeyTab=true
keyTab="/secure/keys/service.keytab"
storeKey=true
principal="HTTP/appserver.corp.domain@CORP.DOMAIN";
};
Kerberos Realm Configuration
The realm configuration specifies KDC locations and domain-to-realm mappings:
// krb5.ini
[libdefaults]
default_realm = CORP.DOMAIN
dns_lookup_realm = false
dns_lookup_kdc = false
[realms]
CORP.DOMAIN = {
kdc = kdc1.corp.domain:88
admin_server = kdc1.corp.domain:749
default_domain = corp.domain
}
[domain_realm]
.corp.domain = CORP.DOMAIN
corp.domain = CORP.DOMAIN
Programmatic Authentication Implementation
The following implementation demonstrates establishing a security context with a Kerberos-protected service:
import org.ietf.jgss.*;
public class MultiRealmKerberosAuth {
public static void main(String[] args) {
System.setProperty("java.security.auth.login.config", "/path/to/auth.conf");
System.setProperty("java.security.krb5.conf", "/path/to/krb5.ini");
try {
GSSManager gssManager = GSSManager.getInstance();
Oid krb5Mechanism = new Oid("1.2.840.113554.1.2.2");
GSSName clientIdentity = gssManager.createName(
"clientapp@CORP.DOMAIN",
GSSName.NT_USER_NAME
);
GSSCredential clientCredentials = gssManager.createCredential(
clientIdentity,
GSSCredential.DEFAULT_LIFETIME,
krb5Mechanism,
GSSCredential.INITIATE_ONLY
);
GSSName targetService = gssManager.createName(
"HTTP/appserver.corp.domain@CORP.DOMAIN",
GSSName.NT_HOSTBASED_SERVICE
);
GSSContext securityContext = gssManager.createContext(
targetService,
krb5Mechanism,
clientCredentials,
GSSContext.DEFAULT_LIFETIME
);
securityContext.requestMutualAuth(true);
securityContext.requestCredDeleg(false);
byte[] inputToken = new byte[0];
while (!securityContext.isEstablished()) {
byte[] outputToken = securityContext.initSecContext(
inputToken, 0, inputToken.length
);
inputToken = outputToken;
}
System.out.println("Security context established successfully");
securityContext.dispose();
clientCredentials.dispose();
} catch (GSSException ex) {
ex.printStackTrace();
}
}
}
Multi-Service Authentication Pattern
For applications requiring connections to multiple Kerberos services, instantiate separate GSSContext objects for each target service while reusing the client credentials:
// Establish context with first service
GSSName serviceOne = gssManager.createName(
"HTTP/service1.corp.domain@CORP.DOMAIN",
GSSName.NT_HOSTBASED_SERVICE
);
GSSContext ctxOne = gssManager.createContext(
serviceOne, krb5Mechanism, clientCredentials, GSSContext.DEFAULT_LIFETIME
);
// Establish context with second service
GSSName serviceTwo = gssManager.createName(
"HTTP/service2.corp.domain@CORP.DOMAIN",
GSSName.NT_HOSTBASED_SERVICE
);
GSSContext ctxTwo = gssManager.createContext(
serviceTwo, krb5Mechanism, clientCredentials, GSSContext.DEFAULT_LIFETIME
);
Each context maintains independent state while leveraging the same initial ticket-granting ticket, enabling efficient multi-service authantication within a single JVM process.