Windows SSPI compatibility with Java GSSAPI to achieve single sign-on in EJB calls

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;
    }
+4

Source: https://habr.com/ru/post/1669028/


All Articles