¿Un nombre principal de servicio (SPN) está vinculado a una máquina específica?
Pregunta
En este momento recibo una KrbException: la comprobación de integridad en el campo descifrado falló (31) con mi aplicación de demostración GSS (en el lado del servidor). Ahora estoy buscando la razón de esto. Tengo la sospecha de que proviene del hecho de que
- el cliente y la aplicación del servidor se ejecutan en la misma máquina (localhost) y / o
- el SPN se generó para otra máquina (computadora)
El segundo significa que el principal de servicio se generó para una máquina xxx0815.domain.net, por lo que el SPN es HTTP/xxx0815.domain.net@DOMAIN.NET. Y mi máquina no es esa, pero tengo el archivo de tabla de claves para que el método de inicio de sesión del servidor tenga éxito.
¿Sospecho correctamente o estoy cometiendo otro error?
Configuración del servidor y código fuente:
server.conf
Server {
com.sun.security.auth.module.Krb5LoginModule
required
isInitiator=false
doNotPrompt=true
useKeyTab=true
keyTab="gssdemo.keytab"
storeKey=true
principal="HTTP/xxx0815.domain.net@DOMAIN.NET"
debug=true;
};
GSSServer.java (se omitieron las cosas repetitivas)
GSSManager manager = GSSManager.getInstance();
GSSName serverName = manager.createName(getServerName(), null);
GSSCredential serverCred = manager.createCredential(serverName,
GSSCredential.INDEFINITE_LIFETIME,
createKerberosOid(),
GSSCredential.ACCEPT_ONLY);
GSSContext context = manager.createContext(serverCred);
System.out.println("Context created successfully. Now incoming tokens could be accepted.");
ServerSocket serverSocket = new ServerSocket(55555);
SocketAdapter ca = new SocketAdapter(serverSocket.accept());
while (!context.isEstablished()) {
byte[] inToken = ca.readToken();
byte[] outToken = context.acceptSecContext(inToken, 0, inToken.length);
if (outToken != null) {
ca.sendToken(outToken);
}
}
System.out.println("Context established");
System.out.println("Connected user is: " + context.getSrcName());
context.dispose();
Configuración del cliente y código fuente:
client.conf
Client {
com.sun.security.auth.module.Krb5LoginModule
required
useTicketCache=true
debug=true;
};
GssClient.java (repetitivo omitido)
GSSManager manager = GSSManager.getInstance();
GSSName clientName = manager.createName(getClientName(), null);
GSSCredential clientCred = manager.createCredential(clientName,
8 * 3600,
createKerberosOid(),
GSSCredential.INITIATE_ONLY);
GSSName serviceName = manager.createName("HTTP/xxx0815.domain.net@DOMAIN.NET", null);
GSSContext context = manager.createContext(serviceName,
createKerberosOid(),
clientCred,
GSSContext.DEFAULT_LIFETIME);
context.requestMutualAuth(true);
context.requestConf(false);
context.requestInteg(true);
System.out.println("Establishing context");
SocketAdapter ca = new SocketAdapter(new Socket("localhost", 55555));
byte[] inToken = new byte[0];
while (true) {
byte[] outToken = context.initSecContext(inToken, 0, inToken.length);
if (outToken != null) {
ca.sendToken(outToken);
}
if (context.isEstablished()) {
break;
}
inToken = ca.readToken();
}
System.out.println("Context established: " + context.isEstablished());
context.dispose();
He verificado los datos de la red entrante y saliente: es lo mismo en ambos lados, así que puedo descartar un problema allí (codifiqué BASE64 en la salida y luego la envié a través de las secuencias. Creo que no hay mucho eso puede salir mal allí ...).
La excepción que obtengo:
Caused by: GSSException: Failure unspecified at GSS-API level (Mechanism level: Integrity check on decrypted field failed (31))
at sun.security.jgss.krb5.Krb5Context.acceptSecContext(Krb5Context.java:741)
at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:323)
at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:267)
at de.westlb.mrm.sandbox.gss.GssServer.acceptAndEstablish(GssServer.java:88)
at de.westlb.mrm.sandbox.gss.GssServer.run(GssServer.java:66)
... 4 more
Caused by: KrbException: Integrity check on decrypted field failed (31)
at sun.security.krb5.internal.crypto.DesCbcEType.decrypt(DesCbcEType.java:154)
at sun.security.krb5.internal.crypto.DesCbcMd5EType.decrypt(DesCbcMd5EType.java:33)
at sun.security.krb5.internal.crypto.DesCbcEType.decrypt(DesCbcEType.java:125)
at sun.security.krb5.internal.crypto.DesCbcMd5EType.decrypt(DesCbcMd5EType.java:33)
at sun.security.krb5.EncryptedData.decrypt(EncryptedData.java:168)
at sun.security.krb5.KrbApReq.authenticate(KrbApReq.java:267)
at sun.security.krb5.KrbApReq.<init>(KrbApReq.java:134)
at sun.security.jgss.krb5.InitSecContextToken.<init>(InitSecContextToken.java:79)
at sun.security.jgss.krb5.Krb5Context.acceptSecContext(Krb5Context.java:724)
... 8 more
Solución
Si la comprobación de integridad falla, eso sugiere que los datos no se están enviando / recibiendo correctamente (eso o esto es un mensaje de error incorrecto). En otras palabras, se ha producido alguna modificación.
Sé que dice que ha verificado que los datos enviados coinciden con los datos recibidos a nivel de red, sin embargo, ¿está seguro de que no están dañados antes del envío o después de la recepción? Te sugiero que revises tu código para esto primero.
editar: en respuesta a su pregunta, un director de servicio (realmente, cualquier ticket) puede estar vinculado a una máquina específica, pero esto normalmente se hace en términos de dirección IP. En cualquier caso, algo así debería dar como resultado un error de nivel superior diferente.
El error que está recibiendo parece que está teniendo problemas para descifrar el ticket en primer lugar. Una posible causa de eso es que está usando la clave incorrecta, lo que puede estar relacionado con la copia de la tabla de claves. Una clave incorrecta también puede ser causada al usar el ticket incorrecto (ya que kerberos básicamente proporciona un protocolo de administración de claves). ¿Es posible que haya almacenado en caché un ticket antiguo / incorrecto?