【发布时间】:2019-09-14 21:54:05
【问题描述】:
我们有一个使用 ldap 对用户进行身份验证的应用程序。我们使用https://www.ldaptive.org/ 作为我们的 ldap 客户端,并通过 jaas 登录配置文件对其进行配置。
这是我们的 jaas 登录配置文件的示例:
ourApplication {
org.ldaptive.jaas.LdapLoginModule required
storePass="true"
ldapUrl="ldap://ldapserver:10389"
baseDn="ou=People,dc=example,dc=com"
useStartTLS="false"
bindDn="uid=admin,ou=People,dc=example,dc=com"
bindCredential="password"
userFilter="(uid={user})";
org.ldaptive.jaas.LdapRoleAuthorizationModule required
useFirstPass="true"
ldapUrl="ldap://ldapserver:10389"
baseDn="ou=Roles,dc=example,dc=com"
roleFilter="(member={dn})"
roleAttribute="cn";
};
这很好用。随着时间的推移,我们开始出现错误,类似于此处描述的内容:
如果链接出错,则来自 confluence 用户的投诉,即用户有时无法通过 ldap 服务器进行身份验证。报告这样的错误:
2010-08-10 13:04:18,277 ERROR [http-80-8] [user.impl.ldap.LDAPUserManagerReadOnly] getUser Error retrieving user: 'Husein.Alatas' from LDAP.
-- url: /display/Test | userName: Husein.Alatas | referer: http://confluence/display/dashboard/Home | action: notpermitted
com.atlassian.user.impl.ldap.repository.LdapConnectionFailedException: javax.naming.CommunicationException: ldap.atlassian.com:389 [Root exception is java.net.BindException: Address already in use: connect]
at com.atlassian.user.impl.ldap.repository.DefaultLdapContextFactory.getLDAPContext(DefaultLdapContextFactory.java:93)
at com.atlassian.user.impl.ldap.search.DefaultLDAPUserAdaptor.search(DefaultLDAPUserAdaptor.java:70)
at com.atlassian.user.impl.ldap.search.DefaultLDAPUserAdaptor.search(DefaultLDAPUserAdaptor.java:54)
at com.atlassian.user.impl.ldap.LDAPUserManagerReadOnly.getUser(LDAPUserManagerReadOnly.java:70)
at com.atlassian.user.impl.delegation.DelegatingUserManager.getUser(DelegatingUserManager.java:68)
at bucket.user.DefaultUserAccessor.getUser(DefaultUserAccessor.java:146)
...
Caused by: javax.naming.CommunicationException: ldap.atlassian.com:389 [Root exception is java.net.BindException: Address already in use: connect]
at com.sun.jndi.ldap.Connection.<init>(Connection.java:200)
at com.sun.jndi.ldap.LdapClient.<init>(LdapClient.java:118)
at com.sun.jndi.ldap.LdapClientFactory.createPooledConnection(LdapClientFactory.java:46)
at com.sun.jndi.ldap.pool.Connections.getOrCreateConnection(Connections.java:185)
...
Caused by: java.net.BindException: Address already in use: connect
at java.net.PlainSocketImpl.socketConnect(Native Method)
...
我们遇到了类似的通信和绑定错误。
上面的链接建议运行
netstat -na
我们的应用服务器上的命令来查看是否有很多打开的连接到 ldap 服务器。当我这样做时,我会看到数百行如下所示:
TCP 129.135.249.138:65525 129.135.28.18:10389 ESTABLISHED
左边的地址是我们的 server:port,右边是 ldap server:port。最终,左边的端口变为 65535,这可能是导致无法认证的原因:所有端口都被占用,因此无法通信。
上面的 atlassian 链接指向 ldaptive jaas 配置页面,以获取如何为 ldaptive 配置连接池的示例:
https://www.ldaptive.org/docs/guide/jaas.html
这是 ldaptive 提供的示例,用于配置 ldaptive 以通过 jaas 配置使用连接池:
ldaptive {
org.ldaptive.jaas.LdapLoginModule required
ldapUrl="ldap://directory.ldaptive.org:389"
baseDn="ou=people,dc=ldaptive,dc=org"
bindDn="cn=priviledged_user,ou=services,dc=vt,dc=edu"
bindCredential="notarealpassword"
useStartTLS="true"
userFilter="(uid={user})"
userRoleAttribute="eduPersonAffiliation"
dnResolver="org.ldaptive.auth.SearchDnResolver"
authenticationHandler="org.ldaptive.auth.SimpleBindAuthenticationHandler"
connectionFactory="org.ldaptive.PooledConnectionFactory"
cacheId="ldaptive-pooled";
};
我无法让它工作。首先,我在示例中发现了几个错误:
- ldaptive 中没有 SimpleBindAuthenticationHandler 类。它 似乎最有可能的课程应该是 BindAuthenticationHandler。
- PooledConnectionFactory 的完全限定类名应为: org.ldaptive.pool.PooledConnectionFactory
进行这些更改后,我的 jaas 配置文件如下所示:
ourApplication {
org.ldaptive.jaas.LdapLoginModule required
storePass="true"
ldapUrl="ldap://ldapserver:10389"
baseDn="ou=People,dc=example,dc=com"
useStartTLS="false"
bindDn="uid=admin,ou=People,dc=example,dc=com"
bindCredential="password"
userFilter="(uid={user})"
dnResolver="org.ldaptive.auth.SearchDnResolver"
authenticationHandler="org.ldaptive.auth.BindAuthenticationHandler"
connectionFactory="org.ldaptive.pool.PooledConnectionFactory"
cacheId="ldaptive-pooled";
org.ldaptive.jaas.LdapRoleAuthorizationModule required
useFirstPass="true"
ldapUrl="ldap://ldapserver:10389"
baseDn="ou=Roles,dc=example,dc=com"
roleFilter="(member={dn})"
roleAttribute="cn";
};
现在,当我运行我们的应用程序并尝试进行身份验证时,我在日志文件中看到了这个错误:
2019-09-12 14:45:10,229 ERROR (ajp-nio-8009-exec-3)[org.ldaptive.props.AbstractPropertyInvoker] Error invoking public void org.ldaptive.auth.SearchDnResolver.setConnectionFactory(org.ldaptive.ConnectionFactory), on [org.ldaptive.auth.SearchDnResolver@1036972035::factory=null, baseDn=, userFilter=null, userFilterParameters=null, allowMultipleDns=false, subtreeSearch=false, derefAliases=null, referralHandler=null], with params org.ldaptive.pool.PooledConnectionFactory
因此,似乎 ldaptive 无法使用我定义的池配置,主要是根据他们的示例。
有没有人像这样使用 ldaptive(通过 jaas 配置并使用池化)?有没有人足够了解 ldaptive 来猜测这里出了什么问题以及如何正确配置它?
我想我还应该问,ldaptive 中的池化是否可以解决我通过 netstat -na 看到的端口明显耗尽的问题?
更新:
我能够在我的 jaas 配置文件中使用池配置:
ourApplication {
org.ldaptive.jaas.LdapLoginModule required
storePass="true"
ldapUrl="ldap://ldapserver:10389"
baseDn="ou=People,dc=example,dc=com"
useStartTLS="false"
bindDn="uid=admin,ou=People,dc=example,dc=com"
bindCredential="password"
userFilter="(uid={user})"
dnResolver="org.ldaptive.auth.PooledSearchDnResolver"
authenticationHandler="org.ldaptive.auth.PooledBindAuthenticationHandler"
pruneStrategy="org.ldaptive.pool.IdlePruneStrategy{{prunePeriod=PT3M}{idleTime=PT6M}}"
cacheId="ldaptive-users-pooled";
org.ldaptive.jaas.LdapRoleAuthorizationModule required
useFirstPass="true"
ldapUrl="ldap://ldapserver:10389"
baseDn="ou=Roles,dc=example,dc=com"
roleFilter="(member={dn})"
roleAttribute="cn"
dnResolver="org.ldaptive.auth.PooledSearchDnResolver"
authenticationHandler="org.ldaptive.auth.PooledBindAuthenticationHandler"
pruneStrategy="org.ldaptive.pool.IdlePruneStrategy{{prunePeriod=PT3M}{idleTime=PT6M}}"
cacheId="ldaptive-roles-pooled";
};
这似乎确实有所不同,但我仍然看到(在我看来)我们的应用程序服务器和 ldap 服务器之间保持打开的连接过多。 下面是一个 netstat -na 输出的例子:
TCP 129.135.28.210:61285 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61288 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61290 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61292 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61294 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61299 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61301 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61303 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61309 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61311 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61313 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61317 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61319 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61323 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61336 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61338 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61340 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61342 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61344 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61346 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61348 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61350 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61353 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61355 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61359 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61374 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61376 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61378 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61380 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61383 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61385 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61389 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61396 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61398 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61400 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61402 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61404 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61408 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61416 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61419 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61421 129.135.28.18:10389 ESTABLISHED
TCP 129.135.28.210:61423 129.135.28.18:10389 ESTABLISHED
当我第一次开始对此进行调查时,几乎所有在应用程序服务器端使用的端口都是连续的。现在看来,最多每个其他端口都在使用,甚至还有 2、3、4 甚至更多端口的间隙。请注意,此示例是在最后一次 ldap 活动后近两个小时拍摄的。
为什么这些连接在 ldap 活动停止后仍然保留这么长时间? 池化/修剪配置是否应该做更多的事情来减少连接数?我猜它会比它有更多的帮助。
【问题讨论】:
-
这表示 ldaptive 中的连接泄漏。您可以通过提供具有适当设置的 /jndi.properties 资源在 JNDI 级别启用连接池,这些设置与 JNDI LDAP 提供程序一起记录。这可能会有所帮助,但它确实是一个错误,而且是一个糟糕的错误。
-
非常感谢您提供的信息。在 ldaptive 网站上进行了更多挖掘之后,我想我已经看到了对相同错误的引用。
标签: java authentication ldap