Overview
Kerberos is a network authentication protocol that provides strong authentication for client/server applications. Java provides comprehensive support for Kerberos through the Java Authentication and Authorization Service (JAAS) and the Generic Security Services API (GSS-API).
Core Components
- LoginContext: JAAS entry point for authentication
- Krb5LoginModule: Kerberos login module
- GSSContext: GSS-API context for secure communication
- Subject: Represents authenticated user
- Principal: Kerberos principal identity
Setup and Dependencies
Maven Dependencies
<dependencies> <!-- Kerberos support is included in Java SE --> <!-- Additional dependencies for specific use cases --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-kerberos</artifactId> <version>1.0.1.RELEASE</version> </dependency> </dependencies>
Kerberos Configuration
krb5.conf File
[libdefaults] default_realm = EXAMPLE.COM dns_lookup_realm = false dns_lookup_kdc = true ticket_lifetime = 24h renew_lifetime = 7d forwardable = true default_tkt_enctypes = aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96 default_tgs_enctypes = aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96 permitted_enctypes = aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96
[realms]
EXAMPLE.COM = { kdc = kdc.example.com admin_server = kdc.example.com default_domain = example.com }
[domain_realm]
.example.com = EXAMPLE.COM example.com = EXAMPLE.COM
JAAS Configuration File (jaas.conf)
KerberosClient {
com.sun.security.auth.module.Krb5LoginModule required
useKeyTab=false
useTicketCache=true
doNotPrompt=false
principal="[email protected]"
debug=true;
};
KerberosClientWithKeytab {
com.sun.security.auth.module.Krb5LoginModule required
useKeyTab=true
keyTab="/path/to/user.keytab"
principal="service/[email protected]"
storeKey=true
doNotPrompt=true
debug=true;
};
KerberosServer {
com.sun.security.auth.module.Krb5LoginModule required
useKeyTab=true
keyTab="/path/to/service.keytab"
principal="HTTP/[email protected]"
storeKey=true
doNotPrompt=true
debug=true;
};
Basic Kerberos Authentication
Example 1: Client-Side Kerberos Authentication
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import java.security.Principal;
import java.security.PrivilegedAction;
import java.util.Set;
public class KerberosClientAuth {
public static void main(String[] args) {
// Set Kerberos configuration
System.setProperty("java.security.krb5.conf", "/path/to/krb5.conf");
System.setProperty("java.security.auth.login.config", "/path/to/jaas.conf");
System.setProperty("sun.security.krb5.debug", "true");
try {
// Perform Kerberos authentication
LoginContext loginContext = new LoginContext("KerberosClient");
loginContext.login();
Subject subject = loginContext.getSubject();
System.out.println("Authentication successful!");
// Display subject information
displaySubjectInfo(subject);
// Perform actions as authenticated subject
performAuthenticatedAction(subject);
// Logout
loginContext.logout();
System.out.println("Logged out successfully");
} catch (LoginException e) {
System.err.println("Authentication failed: " + e.getMessage());
e.printStackTrace();
}
}
private static void displaySubjectInfo(Subject subject) {
System.out.println("Subject: " + subject);
System.out.println("Principals:");
Set<Principal> principals = subject.getPrincipals();
for (Principal principal : principals) {
System.out.println(" - " + principal.getName());
}
System.out.println("Public Credentials: " + subject.getPublicCredentials().size());
System.out.println("Private Credentials: " + subject.getPrivateCredentials().size());
}
private static void performAuthenticatedAction(Subject subject) {
Subject.doAs(subject, new PrivilegedAction<Void>() {
@Override
public Void run() {
System.out.println("Performing action as: " +
Subject.getSubject(AccessController.getContext()));
// Here you can make Kerberos-authenticated requests
return null;
}
});
}
}
Example 2: Service Authentication with Keytab
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
public class KerberosServiceAuth {
private Subject serviceSubject;
public KerberosServiceAuth() throws LoginException {
// Set Kerberos configuration
System.setProperty("java.security.krb5.conf", "/etc/krb5.conf");
System.setProperty("java.security.auth.login.config", "/path/to/jaas.conf");
System.setProperty("sun.security.krb5.debug", "true");
// Authenticate service using keytab
LoginContext loginContext = new LoginContext("KerberosServer");
loginContext.login();
this.serviceSubject = loginContext.getSubject();
System.out.println("Service authenticated successfully");
System.out.println("Service Principal: " +
serviceSubject.getPrincipals().iterator().next().getName());
}
public Subject getServiceSubject() {
return serviceSubject;
}
public void performServiceAction() {
Subject.doAs(serviceSubject, new PrivilegedAction<Void>() {
@Override
public Void run() {
try {
// Service can now accept Kerberos authentication
System.out.println("Service is ready to accept Kerberos requests");
// Implement service logic here
} catch (Exception e) {
System.err.println("Service action failed: " + e.getMessage());
}
return null;
}
});
}
public static void main(String[] args) {
try {
KerberosServiceAuth service = new KerberosServiceAuth();
service.performServiceAction();
} catch (LoginException e) {
System.err.println("Service authentication failed: " + e.getMessage());
e.printStackTrace();
}
}
}
GSS-API for Secure Communication
Example 3: Client-Server Authentication with GSS-API
import org.ietf.jgss.*;
import java.security.PrivilegedAction;
public class GSSClientServerExample {
// Client-side GSS-API
public static class GSSClient {
public byte[] authenticate(Subject clientSubject, String servicePrincipal)
throws GSSException {
return Subject.doAs(clientSubject, new PrivilegedAction<byte[]>() {
@Override
public byte[] run() {
try {
GSSManager manager = GSSManager.getInstance();
GSSName serverName = manager.createName(
servicePrincipal, GSSName.NT_HOSTBASED_SERVICE);
Oid krb5Mech = new Oid("1.2.840.113554.1.2.2"); // Kerberos OID
GSSContext context = manager.createContext(
serverName, krb5Mech, null, GSSContext.DEFAULT_LIFETIME);
context.requestMutualAuth(true);
context.requestConf(true);
context.requestInteg(true);
// Initiate security context
byte[] token = new byte[0];
token = context.initSecContext(token, 0, token.length);
System.out.println("Client context established: " + context.isEstablished());
return token;
} catch (GSSException e) {
throw new RuntimeException("GSS Client error", e);
}
}
});
}
}
// Server-side GSS-API
public static class GSSServer {
private GSSContext context;
public byte[] acceptSecurityContext(byte[] clientToken) throws GSSException {
GSSManager manager = GSSManager.getInstance();
Oid krb5Mech = new Oid("1.2.840.113554.1.2.2");
context = manager.createContext((GSSCredential) null);
byte[] serverToken = context.acceptSecContext(clientToken, 0, clientToken.length);
System.out.println("Server context established: " + context.isEstablished());
if (context.isEstablished()) {
System.out.println("Client Principal: " + context.getSrcName());
System.out.println("Server Principal: " + context.getTargName());
}
return serverToken;
}
public void verifyAuthentication() throws GSSException {
if (context != null && context.isEstablished()) {
System.out.println("Mutual authentication: " + context.getMutualAuthState());
System.out.println("Confidentiality: " + context.getConfState());
System.out.println("Integrity: " + context.getIntegState());
}
}
public byte[] wrapMessage(byte[] message) throws GSSException {
if (context != null && context.isEstablished()) {
return context.wrap(message, 0, message.length, new MessageProp(true, true));
}
throw new GSSException(GSSException.NO_CONTEXT);
}
public byte[] unwrapMessage(byte[] wrappedMessage) throws GSSException {
if (context != null && context.isEstablished()) {
MessageProp prop = new MessageProp(false);
byte[] unwrapped = context.unwrap(wrappedMessage, 0, wrappedMessage.length, prop);
System.out.println("Message QOP: " + prop.getQOP());
System.out.println("Privacy: " + prop.getPrivacy());
return unwrapped;
}
throw new GSSException(GSSException.NO_CONTEXT);
}
}
public static void main(String[] args) {
try {
// Setup
System.setProperty("java.security.krb5.conf", "/path/to/krb5.conf");
System.setProperty("java.security.auth.login.config", "/path/to/jaas.conf");
// Client authentication
LoginContext clientLogin = new LoginContext("KerberosClient");
clientLogin.login();
Subject clientSubject = clientLogin.getSubject();
// Create client and server
GSSClient client = new GSSClient();
GSSServer server = new GSSServer();
// Perform authentication handshake
String servicePrincipal = "HTTP/[email protected]";
byte[] clientToken = client.authenticate(clientSubject, servicePrincipal);
byte[] serverToken = server.acceptSecurityContext(clientToken);
// Verify authentication
server.verifyAuthentication();
// Test message protection
String originalMessage = "Secret message from client";
byte[] wrappedMessage = clientSubject.doAs(new PrivilegedAction<byte[]>() {
@Override
public byte[] run() {
try {
GSSManager manager = GSSManager.getInstance();
GSSName serverName = manager.createName(
servicePrincipal, GSSName.NT_HOSTBASED_SERVICE);
Oid krb5Mech = new Oid("1.2.840.113554.1.2.2");
GSSContext clientContext = manager.createContext(
serverName, krb5Mech, null, GSSContext.DEFAULT_LIFETIME);
clientContext.initSecContext(new byte[0], 0, 0);
MessageProp prop = new MessageProp(true, true);
return clientContext.wrap(
originalMessage.getBytes(), 0,
originalMessage.getBytes().length, prop);
} catch (GSSException e) {
throw new RuntimeException(e);
}
}
});
byte[] unwrappedMessage = server.unwrapMessage(wrappedMessage);
String receivedMessage = new String(unwrappedMessage);
System.out.println("Original: " + originalMessage);
System.out.println("Received: " + receivedMessage);
System.out.println("Match: " + originalMessage.equals(receivedMessage));
clientLogin.logout();
} catch (Exception e) {
e.printStackTrace();
}
}
}
HTTP SPNEGO Authentication
Example 4: Kerberos HTTP Client with SPNEGO
import org.ietf.jgss.*;
import sun.security.jgss.GSSUtil;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.PrivilegedAction;
public class KerberosHttpClient {
public static class SpnegoAuthenticator {
public String authenticateWithSpnego(Subject subject, String urlString)
throws Exception {
return Subject.doAs(subject, new PrivilegedAction<String>() {
@Override
public String run() {
try {
URL url = new URL(urlString);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// Perform SPNEGO authentication
String spnegoToken = generateSpnegoToken(url.getHost());
if (spnegoToken != null) {
connection.setRequestProperty("Authorization", "Negotiate " + spnegoToken);
}
connection.setRequestMethod("GET");
connection.setConnectTimeout(10000);
connection.setReadTimeout(10000);
int responseCode = connection.getResponseCode();
System.out.println("HTTP Response Code: " + responseCode);
if (responseCode == HttpURLConnection.HTTP_OK) {
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(connection.getInputStream()))) {
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
return response.toString();
}
} else if (responseCode == HttpURLConnection.HTTP_UNAUTHORIZED) {
// Handle WWW-Authenticate challenge
String authHeader = connection.getHeaderField("WWW-Authenticate");
if (authHeader != null && authHeader.startsWith("Negotiate")) {
System.out.println("Received Negotiate challenge");
// Extract server token and continue authentication
}
throw new RuntimeException("HTTP Unauthorized: " + responseCode);
} else {
throw new RuntimeException("HTTP Error: " + responseCode);
}
} catch (Exception e) {
throw new RuntimeException("HTTP request failed", e);
}
}
});
}
private String generateSpnegoToken(String serviceHost) {
try {
GSSManager manager = GSSManager.getInstance();
String servicePrincipal = "HTTP/" + serviceHost;
GSSName serverName = manager.createName(
servicePrincipal, GSSName.NT_HOSTBASED_SERVICE);
Oid spnegoOid = new Oid("1.3.6.1.5.5.2"); // SPNEGO OID
GSSContext context = manager.createContext(
serverName, spnegoOid, null, GSSContext.DEFAULT_LIFETIME);
context.requestMutualAuth(true);
byte[] token = context.initSecContext(new byte[0], 0, 0);
if (token != null) {
return java.util.Base64.getEncoder().encodeToString(token);
}
} catch (GSSException e) {
System.err.println("SPNEGO token generation failed: " + e.getMessage());
}
return null;
}
}
public static void main(String[] args) {
try {
// Configure Kerberos
System.setProperty("java.security.krb5.conf", "/path/to/krb5.conf");
System.setProperty("java.security.auth.login.config", "/path/to/jaas.conf");
System.setProperty("sun.security.krb5.debug", "true");
// Authenticate client
LoginContext loginContext = new LoginContext("KerberosClient");
loginContext.login();
Subject clientSubject = loginContext.getSubject();
// Make SPNEGO authenticated HTTP request
SpnegoAuthenticator authenticator = new SpnegoAuthenticator();
String response = authenticator.authenticateWithSpnego(
clientSubject, "https://kerberos-protected-service.example.com/api/data");
System.out.println("SPNEGO Authenticated Response: " + response);
loginContext.logout();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Example 5: Kerberos-Protected HTTP Server
import com.sun.net.httpserver.*;
import org.ietf.jgss.*;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import java.io.*;
import java.net.InetSocketAddress;
import java.security.Principal;
import java.security.PrivilegedAction;
import java.util.Base64;
public class KerberosHttpServer {
private HttpServer server;
private Subject serviceSubject;
public KerberosHttpServer(int port) throws Exception {
// Authenticate service
System.setProperty("java.security.krb5.conf", "/etc/krb5.conf");
System.setProperty("java.security.auth.login.config", "/path/to/jaas.conf");
LoginContext loginContext = new LoginContext("KerberosServer");
loginContext.login();
this.serviceSubject = loginContext.getSubject();
// Create HTTP server
this.server = HttpServer.create(new InetSocketAddress(port), 0);
server.createContext("/api", new KerberosHandler());
server.setExecutor(null);
}
public void start() {
server.start();
System.out.println("Kerberos HTTP Server started on port " +
server.getAddress().getPort());
}
public void stop() {
server.stop(0);
System.out.println("Server stopped");
}
class KerberosHandler implements HttpHandler {
@Override
public void handle(HttpExchange exchange) throws IOException {
Subject.doAs(serviceSubject, new PrivilegedAction<Void>() {
@Override
public Void run() {
try {
// Check for SPNEGO authentication
String authHeader = exchange.getRequestHeaders().getFirst("Authorization");
if (authHeader != null && authHeader.startsWith("Negotiate")) {
// Extract SPNEGO token
String spnegoToken = authHeader.substring("Negotiate".length()).trim();
byte[] token = Base64.getDecoder().decode(spnegoToken);
// Authenticate client
GSSContext context = authenticateClient(token);
if (context != null && context.isEstablished()) {
// Client authenticated successfully
String clientPrincipal = context.getSrcName().toString();
System.out.println("Authenticated client: " + clientPrincipal);
// Process request
String response = "Hello, " + clientPrincipal +
"! You are authenticated via Kerberos.";
sendResponse(exchange, 200, response);
context.dispose();
return null;
}
}
// Authentication required
exchange.getResponseHeaders().set("WWW-Authenticate", "Negotiate");
sendResponse(exchange, 401, "Authentication Required");
} catch (Exception e) {
System.err.println("Request handling failed: " + e.getMessage());
try {
sendResponse(exchange, 500, "Internal Server Error");
} catch (IOException ex) {
ex.printStackTrace();
}
}
return null;
}
});
}
private GSSContext authenticateClient(byte[] clientToken) throws GSSException {
GSSManager manager = GSSManager.getInstance();
GSSContext context = manager.createContext((GSSCredential) null);
byte[] serverToken = context.acceptSecContext(clientToken, 0, clientToken.length);
if (serverToken != null) {
// If server token is generated, client needs to continue authentication
// For simplicity, we're handling single-step authentication here
System.out.println("Server token generated, continuing authentication...");
}
return context;
}
private void sendResponse(HttpExchange exchange, int statusCode, String response)
throws IOException {
exchange.getResponseHeaders().set("Content-Type", "text/plain");
exchange.sendResponseHeaders(statusCode, response.length());
try (OutputStream os = exchange.getResponseBody()) {
os.write(response.getBytes());
}
}
}
public static void main(String[] args) {
try {
KerberosHttpServer server = new KerberosHttpServer(8080);
server.start();
// Keep server running
System.out.println("Press Enter to stop the server...");
System.in.read();
server.stop();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Spring Security Kerberos Integration
Example 6: Spring Boot with Kerberos
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.kerberos.authentication.KerberosAuthenticationProvider;
import org.springframework.security.kerberos.authentication.KerberosServiceAuthenticationProvider;
import org.springframework.security.kerberos.authentication.sun.SunJaasKerberosClient;
import org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator;
import org.springframework.security.kerberos.web.authentication.SpnegoAuthenticationProcessingFilter;
import org.springframework.security.kerberos.web.authentication.SpnegoEntryPoint;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
@SpringBootApplication
public class SpringKerberosApplication {
public static void main(String[] args) {
SpringApplication.run(SpringKerberosApplication.class, args);
}
@EnableWebSecurity
public static class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/public/**").permitAll()
.anyRequest().authenticated()
.and()
.exceptionHandling()
.authenticationEntryPoint(spnegoEntryPoint())
.and()
.addFilterBefore(
spnegoAuthenticationProcessingFilter(),
BasicAuthenticationFilter.class);
}
@Bean
public SpnegoEntryPoint spnegoEntryPoint() {
return new SpnegoEntryPoint();
}
@Bean
public SpnegoAuthenticationProcessingFilter spnegoAuthenticationProcessingFilter()
throws Exception {
SpnegoAuthenticationProcessingFilter filter =
new SpnegoAuthenticationProcessingFilter();
filter.setAuthenticationManager(authenticationManager());
return filter;
}
@Bean
public KerberosAuthenticationProvider kerberosAuthenticationProvider() {
KerberosAuthenticationProvider provider = new KerberosAuthenticationProvider();
provider.setKerberosClient(sunJaasKerberosClient());
provider.setUserDetailsService(dummyUserDetailsService());
return provider;
}
@Bean
public SunJaasKerberosClient sunJaasKerberosClient() {
SunJaasKerberosClient client = new SunJaasKerberosClient();
client.setDebug(true);
return client;
}
@Bean
public SunJaasKerberosTicketValidator sunJaasKerberosTicketValidator() {
SunJaasKerberosTicketValidator ticketValidator =
new SunJaasKerberosTicketValidator();
ticketValidator.setServicePrincipal("HTTP/[email protected]");
ticketValidator.setKeyTabLocation("classpath:service.keytab");
ticketValidator.setDebug(true);
return ticketValidator;
}
@Bean
public DummyUserDetailsService dummyUserDetailsService() {
return new DummyUserDetailsService();
}
}
}
// Simple user details service for demonstration
class DummyUserDetailsService implements org.springframework.security.core.userdetails.UserDetailsService {
@Override
public org.springframework.security.core.userdetails.UserDetails loadUserByUsername(
String username) {
return org.springframework.security.core.userdetails.User.builder()
.username(username)
.password("") // Password not used in Kerberos
.authorities("ROLE_USER")
.build();
}
}
Advanced Kerberos Features
Example 7: Kerberos Delegation
import org.ietf.jgss.*;
public class KerberosDelegation {
public static class DelegationClient {
public byte[] authenticateWithDelegation(Subject clientSubject,
String servicePrincipal)
throws Exception {
return Subject.doAs(clientSubject, new PrivilegedAction<byte[]>() {
@Override
public byte[] run() {
try {
GSSManager manager = GSSManager.getInstance();
GSSName serverName = manager.createName(
servicePrincipal, GSSName.NT_HOSTBASED_SERVICE);
Oid krb5Mech = new Oid("1.2.840.113554.1.2.2");
GSSContext context = manager.createContext(
serverName, krb5Mech, null, GSSContext.DEFAULT_LIFETIME);
// Request delegation
context.requestCredDeleg(true);
context.requestMutualAuth(true);
byte[] token = context.initSecContext(new byte[0], 0, 0);
if (context.isEstablished()) {
System.out.println("Delegation state: " + context.getCredDelegState());
if (context.getCredDelegState()) {
GSSCredential delegatedCreds = context.getDelegCred();
System.out.println("Delegated credentials obtained");
// Use delegated credentials for further authentication
}
}
return token;
} catch (GSSException e) {
throw new RuntimeException("Delegation failed", e);
}
}
});
}
}
public static class DelegationService {
public void useDelegatedCredentials(GSSCredential delegatedCreds,
String backendServicePrincipal)
throws GSSException {
GSSManager manager = GSSManager.getInstance();
GSSName backendServiceName = manager.createName(
backendServicePrincipal, GSSName.NT_HOSTBASED_SERVICE);
Oid krb5Mech = new Oid("1.2.840.113554.1.2.2");
GSSContext context = manager.createContext(
backendServiceName, krb5Mech, delegatedCreds, GSSContext.DEFAULT_LIFETIME);
context.requestMutualAuth(true);
byte[] token = context.initSecContext(new byte[0], 0, 0);
if (context.isEstablished()) {
System.out.println("Backend service authenticated using delegated credentials");
System.out.println("Original client: " + context.getSrcName());
}
context.dispose();
}
}
}
Troubleshooting and Debugging
Example 8: Kerberos Debug Utilities
import javax.security.auth.kerberos.KerberosPrincipal;
import javax.security.auth.kerberos.KerberosTicket;
import java.security.Principal;
import java.util.Set;
public class KerberosDebugUtils {
public static void printKerberosTicketInfo(Subject subject) {
Set<KerberosTicket> tickets = subject.getPrivateCredentials(KerberosTicket.class);
System.out.println("Number of Kerberos tickets: " + tickets.size());
for (KerberosTicket ticket : tickets) {
System.out.println("=== Kerberos Ticket ===");
System.out.println("Client: " + ticket.getClient());
System.out.println("Server: " + ticket.getServer());
System.out.println("Auth Time: " + ticket.getAuthTime());
System.out.println("Start Time: " + ticket.getStartTime());
System.out.println("End Time: " + ticket.getEndTime());
System.out.println("Renew Till: " + ticket.getRenewTill());
System.out.println("Client Addresses: " + ticket.getClientAddresses());
System.out.println("Session Key Type: " + ticket.getSessionKeyType());
System.out.println("Flags: " + ticket.getFlags());
System.out.println("=== End Ticket ===");
}
}
public static void printSubjectPrincipals(Subject subject) {
Set<Principal> principals = subject.getPrincipals();
System.out.println("Subject Principals (" + principals.size() + "):");
for (Principal principal : principals) {
System.out.println(" - " + principal.getClass().getSimpleName() +
": " + principal.getName());
if (principal instanceof KerberosPrincipal) {
KerberosPrincipal kprincipal = (KerberosPrincipal) principal;
System.out.println(" Realm: " + kprincipal.getRealm());
}
}
}
public static void checkKerberosConfiguration() {
System.out.println("=== Kerberos Configuration Check ===");
System.out.println("java.security.krb5.conf: " +
System.getProperty("java.security.krb5.conf"));
System.out.println("java.security.auth.login.config: " +
System.getProperty("java.security.auth.login.config"));
System.out.println("sun.security.krb5.debug: " +
System.getProperty("sun.security.krb5.debug"));
System.out.println("Default Realm: " +
javax.security.auth.kerberos.KerberosPrincipal.getDefaultRealm());
System.out.println("=== End Configuration Check ===");
}
public static void enableDebug() {
System.setProperty("sun.security.krb5.debug", "true");
System.setProperty("sun.security.jgss.debug", "true");
System.setProperty("javax.security.auth.debug", "true");
}
}
Best Practices
- Secure Keytab Files: Store keytab files securely with proper permissions
- Principal Management: Use appropriate service principals (HTTP/hostname@REALM)
- Ticket Lifetime: Configure appropriate ticket lifetimes
- Delegation Control: Use delegation only when necessary
- Error Handling: Implement comprehensive error handling and logging
- Configuration Management: Externalize Kerberos configuration
- Monitoring: Monitor authentication failures and ticket expiration
- Testing: Test with different Kerberos configurations
- Documentation: Document Kerberos setup and troubleshooting procedures
- Security Updates: Keep Java and Kerberos libraries updated
These examples provide a comprehensive foundation for integrating Kerberos authentication in Java applications, covering client authentication, server-side protection, HTTP SPNEGO, and advanced features like delegation.