Windows SSPI到Java GSSAPI的互操作性,以实现对EJB调用的SSO

我有在Windows机器上运行的Java客户机,它在Linux机器上运行的JBoss EAP / Wildfly上调用远程EJB。 我使用Kerberos来实现SSO。 Java客户端根据Windows域validation用户,并在EJB调用中将其身份传递给JBoss服务器。

我开始使用JAAS和内置的com.sun.security.auth.module.Krb5LoginModule 。 除了一件事以外,它正常工作:用户必须再次键入他的用户名和密码。 所以,这不是一个真正的SSO。

问题是Windows禁止从其LSA凭据caching导出Kerberos会话密钥。 可以通过在每台客户端机器上设置特定的Windowsregistry键来解决这个问题 – 但这是客户无法接受的。

所以我想find一个替代解决scheme。 我了解到Windows提供了可与Java使用的GSSAPI互操作的SSPI。 我使用Waffle库在客户端从Java访问SSPI。 在服务器上,我一直使用JAAS,因为它运行在Linux上,所以我不能在这里使用Waffle。

我也了解到,我不需要实现LoginModule,而是需要SASL客户端。

所以,我看看com.sun.security.sasl.gsskerb.GssKrb5Client是如何工作的,我试图用Waffle重新实现它。

第一步似乎正常工作 – 我从Waffle获得SSPI安全上下文,然后获取初始令牌并将其发送到服务器。 服务器接受令牌并用自己的令牌进行响应。

现在问题出现了。 在原始的SASL客户端中,“unwrap”操作用于从服务器令牌中提取数据,“wrap”操作用于创build要发送给服务器的回复令牌。

根据Microsoft文档, GSSAPI打包/解包操作应对应于SSPI EncryptMessage / DecryptMessage操作。 这两个方法在Waflle中不可用,但在NetAccountClient库中可用。

但是,我无法正确使用它们。 如果我使用单个SECBUFFER_STREAM,那么DecryptMessage是成功的,但是令牌的数据部分不会被提取,我不知道如何确定它开始的偏移量。

如果按照Microsoft文档的build议使用SECBUFFER_STREAM和SECBUFFER_DATA,则会出现以下错误: com.sun.jna.platform.win32.Win32Exception: The message or signature supplied for verification has been altered

我也试过其他的SECBUFFERtypes的其他组合,但没有成功。

任何想法我做错了什么?

到解包方法的源代码:

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