I have a Java client running on a Windows machine that invokes a remote EJB on a JBoss EAP / Wildfly running on a Linux machine. I use Kerberos to achieve single sign-on. The Java client validates the user in the Windows domain and passes its identifier in the EJB call to the JBoss server.
I started with JAAS and inline com.sun.security.auth.module.Krb5LoginModule. It works correctly, except for one thing: the user must enter his username and password again. So this is not a real SSO.
The problem is that Windows prohibits exporting the Kerberos session key from its LSA account cache. It can be fixed by installing a specific Windows registry key on each client computer, but this is not acceptable for the client.
Therefore, I am trying to find an alternative solution. I found out that Windows provides an SSPI that needs to interact with the GSSAPI used by Java. I am using Waffle to access SSPI from Java on the client. On the server, I continue to use JAAS because it runs on Linux, so I cannot use Waffle.
I also found out that I do not need to implement LoginModule, rather I need a SASL client.
So, I looked at how it works com.sun.security.sasl.gsskerb.GssKrb5Client, and I'm trying to override it using Waffle.
, , - SSPI Waffle,
.
.
. SASL ""
, 'wrap'
token .
GSSAPI wrap/unwrap SSPI EncryptMessage/DecryptMessage
Microsoft. Waflle,
NetAccountClient library.
. SECBUFFER_STREAM, DecryptMessage
, , ,
, .
SECBUFFER_STREAM SECBUFFER_DATA, Microsoft docs, :
com.sun.jna.platform.win32.Win32Exception: The message or signature supplied for verification has been altered
SECBUFFER, , .
, ?
:
public byte[] unwrap(byte[] wrapper) throws LoginException {
Sspi.SecBuffer.ByReference inBuffer = new Sspi.SecBuffer.ByReference(Secur32Ext.SECBUFFER_STREAM, wrapper);
Sspi.SecBuffer.ByReference buffer = new Sspi.SecBuffer.ByReference();
buffer.BufferType = Sspi.SECBUFFER_DATA;
Secur32Ext.SecBufferDesc2 buffers = new Secur32Ext.SecBufferDesc2(inBuffer, buffer);
NativeLongByReference pfQOP = new NativeLongByReference();
int responseCode = Secur32Ext.INSTANCE.DecryptMessage(secCtx.getHandle(), buffers, new NativeLong(1), pfQOP);
if (responseCode != W32Errors.SEC_E_OK) {
throw handleError(responseCode);
}
byte[] data = buffer.getBytes();
return data;
}