我正在尝试分析 Ldap 搜索期间出现异常/失败的原因。我正在使用 Active Directory 域控制器上的 JNDI 执行操作。
以下是我正在尝试做的事情的背景:
- 使用 SASL (
Kerberos authentication
) 使用 JAAS (KRB5LoginModule
) 生成LoginContext
。 - 一旦登录成功,
LoginContext
实例就拥有经过身份验证的主体,该主体TGT
在其PrivateCredentials
- 之后,我使用上述经过身份验证的 GSSAPI 生成 LdapContext
Subject
。 - 一旦
LdapContext
生成,我就用它来执行 JNDI 操作(主要使用分页搜索)
- 到目前为止一切都很好并且 LdapContext 已正确生成
- Active Directory 域控制器设置的一些详细信息:
- TGT 的生命周期设置为
1 hour
- 的生命周期服务票(
TGS
)设置为10分钟(由于某些限制而必须这样做,但就是这样)
现在的情况是:
使用
LdapContext
上面创建的,它开始使用查询域控制器,pagingcontrol
并且事情在一定时间或一定数量的搜索中顺利进行(这样说是为了避免大家误以为这可能实际上涉及时间,只是认为这发生在(大约)固定间隔之后 - 这些间隔可能是时间或搜索当它在一定间隔后获取下一页时,搜索失败:
Caused by: javax.naming.CommunicationException: Connection reset at com.sun.jndi.ldap.LdapCtx.getSearchReply(LdapCtx.java:1920) ~[?:1.8.0_73] at com.sun.jndi.ldap.AbstractLdapNamingEnumeration.getNextBatch(AbstractLdapNamingEnumeration.java:130) ~[?:1.8.0_73] at com.sun.jndi.ldap.AbstractLdapNamingEnumeration.hasMoreImpl(AbstractLdapNamingEnumeration.java:217) ~[?:1.8.0_73] at com.sun.jndi.ldap.AbstractLdapNamingEnumeration.hasMore(AbstractLdapNamingEnumeration.java:189) ~[?:1.8.0_73] ... 10 more Caused by: java.net.SocketException: Connection reset at java.net.SocketInputStream.read(SocketInputStream.java:209) ~[?:1.8.0_73] at java.net.SocketInputStream.read(SocketInputStream.java:141) ~[?:1.8.0_73] at java.io.BufferedInputStream.fill(BufferedInputStream.java:246) ~[?:1.8.0_73] at java.io.BufferedInputStream.read1(BufferedInputStream.java:286) ~[?:1.8.0_73] at java.io.BufferedInputStream.read(BufferedInputStream.java:345) ~[?:1.8.0_73] at com.sun.jndi.ldap.sasl.SaslInputStream.readFully(SaslInputStream.java:166) ~[?:1.8.0_73] at com.sun.jndi.ldap.sasl.SaslInputStream.fill(SaslInputStream.java:123) ~[?:1.8.0_73] at com.sun.jndi.ldap.sasl.SaslInputStream.read(SaslInputStream.java:90) ~[?:1.8.0_73] at com.sun.jndi.ldap.Connection.run(Connection.java:860) ~[?:1.8.0_73] at java.lang.Thread.run(Thread.java:745) ~[?:1.8.0_73]
同时,我在 Active Directory 域控制器上看到以下事件日志:EventId:2889
Log Name: Directory Service
Source: Microsoft-Windows-ActiveDirectory_DomainService
Event ID: 2889
Task Category: LDAP Interface
Level: Information
Keywords: Classic
User: ANONYMOUS LOGON
Computer: myad01.example.lab
Description:The following client performed a SASL (Negotiate/Kerberos/NTLM/Digest) LDAP bind without
requesting signing (integrity verification), or performed a simple bind over a clear text (non-
SSL/TLS-encrypted) LDAP connection.
Client IP address: X.X.X.X:56260
Identity the client attempted to authenticate as:EXAMPLE\Administrator
Binding Type:0
我还看到了一个EventID为1216的日志,详细信息如下:
Log Name: Directory Service
Source: Microsoft-Windows-ActiveDirectory_DomainService
Event ID: 1216
Task Category: LDAP Interface
Level: Warning
Keywords: Classic
User: N/A
Computer: myad01.example.lab
Description:Internal event: An LDAP client connection was closed because of an error.
Client IP:X.X.X.X:56244
Additional Data
Error value: 1236 The network connection was aborted by the local system.
Internal ID: c060420
我的理解是:每当(经过一段时间后)它去获取下一页时,ldap connection
服务器都会使该页面无效(如事件 ID 所示1216
) 因此我得到了CommunicationException
。我的问题是为什么我在一定时间间隔后而不是立即得到这个?是不是因为kerberos和服务票证的有效期已经过了?
如果是这样,那么我应该如何设计来克服分页问题?因为,在收到通信异常后,如果我创建一个新的 LdapContext 并设置分页控件,我会按预期收到以下异常:
javax.naming.OperationNotSupportedException: [LDAP: error code 12 - 00000057: LdapErr: DSID-0C090B0B, comment: Error processing control, data 0, v3839 ]
at com.sun.jndi.ldap.LdapCtx.mapErrorCode(Unknown Source) ~[?:1.8.0_201]
at com.sun.jndi.ldap.LdapCtx.processReturnCode(Unknown Source) ~[?:1.8.0_201]
at com.sun.jndi.ldap.LdapCtx.processReturnCode(Unknown Source) ~[?:1.8.0_201]
at com.sun.jndi.ldap.LdapCtx.searchAux(Unknown Source) ~[?:1.8.0_201]
at com.sun.jndi.ldap.LdapCtx.c_search(Unknown Source) ~[?:1.8.0_201]
at com.sun.jndi.toolkit.ctx.ComponentDirContext.p_search(Unknown Source) ~[?:1.8.0_201]
at com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.search(Unknown Source) ~[?:1.8.0_201]
at javax.naming.directory.InitialDirContext.search(Unknown Source) ~[?:1.8.0_201]
对我来说,同时拥有 SASL(kerberos)身份验证支持和 GSSAPI 创建 LdapContext 支持非常重要。此外,分页也很重要,因为数据量巨大,而且我无法控制客户的环境,因此我们无法对票证有效性进行任何限制!
请向我提供关于如何进一步调试此问题的指示,并建议适当的方法或解决方法(对此感到抱歉,但无论如何都需要它)来解决此问题。
答案1
我的观察可能有助于某些人分析他们的问题。首先,Event ID:1216
当客户端(如我的问题中提到的 JNDI,在这种情况下,客户端只是 LdapContext/DirContext)关闭其底层时,在 Active Directory 上生成Socket
。看看这个链接。
LdapContext
只不过是使用某些连接设置形成的连接,在客户端(例如:JNDI)和 LDAP 服务器(例如:Active Directory 目录服务)之间。当网络上任何两个实体之间存在连接时,它通常由客户端套接字和服务器端套接字的形成支持。对于 LdapContext 也是如此,LdapContext 有一个底层套接字。
在使用GSSAPI
获取 LdapContext 实例时,底层套接字带有一个等于有效性服务票证的生存期AD DS 上存在的设置。一旦底层套接字的有效性/超时结束,套接字就会关闭。如果LdapContext
尝试查询 AD DS,则会发生上述Caused by: javax.naming.CommunicationException: Connection reset
异常并且通信失败。
由于 TGT 和 TGS 的生命周期/有效性设置在 AD DS 上,因此无法使用 GSSAPI 绕过它们。如果存在需要使用LdapContext
更长时间的要求,那么唯一的出路就是增加相应票证的有效期。