LDAPConnectionPool重复获取连接触发强认证异常的解决方法
我原本用以下代码创建LDAP连接:
return LDAPConnection(opts, host, port).apply { connectionName = "foo-$userDn-$host-$port" processExtendedOperation(StartTLSExtendedRequest(SSLUtil(TrustAllTrustManager()).createSSLContext())) bind(userDn, password) }
现在想切换为使用LDAPConnectionPool,尝试了如下实现:
val simpleBindRequest = SimpleBindRequest(userDn, password) val exampleConnection = LDAPConnection(opts, host, port).apply { connectionName = "foo-$userDn-$host-$port" processExtendedOperation(StartTLSExtendedRequest(SSLUtil(TrustAllTrustManager()).createSSLContext())) bind(simpleBindRequest ) } val ldapConnectionPool = LDAPConnectionPool(exampleConnection , 1, 10) ldapConnectionPool.setBindRequest(simpleBindRequest)
首次调用connectionPool.getConnection()能正常工作,因为返回的是初始传入的exampleConnection;但第二次调用时触发了LDAPException:
LDAPException(resultCode=8 (strong auth required), diagnosticMessage='BindSimple: Transport encryption required.
', ldapSDKVersion=6.0.11, revision=8b21d0a4c6eb8b5c3e60a96fc3e9e13b9c2f650f)
at com.unboundid.ldap.sdk.LDAPConnectionPool.createConnection(LDAPConnectionPool.java:1388)
at com.unboundid.ldap.sdk.LDAPConnectionPool.createConnection(LDAPConnectionPool.java:1269)
at com.unboundid.ldap.sdk.LDAPConnectionPool.getConnection(LDAPConnectionPool.java:1866)
推测原因是新创建的连接未执行processExtendedOperation(StartTLSExtendedRequest(SSLUtil(TrustAllTrustManager()).createSSLContext()))操作,请问有什么解决办法?
问题根源在于:连接池在创建新连接时,不会复用初始连接的StartTLS配置,而是直接用基础参数创建连接,导致新连接未加密就尝试绑定,触发强认证错误。
正确的做法是自定义连接工厂,让连接池每次创建新连接时自动执行StartTLS和绑定流程:
- 实现自定义
LDAPConnectionFactory
继承DefaultLDAPConnectionFactory,重写createConnection方法,在创建连接后自动执行StartTLS和绑定:
class TLSLDAPConnectionFactory( private val opts: LDAPConnectionOptions, private val host: String, private val port: Int, private val userDn: String, private val password: String ) : DefaultLDAPConnectionFactory(opts, host, port) { override fun createConnection(): LDAPConnection { return super.createConnection().apply { connectionName = "foo-$userDn-$host-$port" // 执行StartTLS加密 processExtendedOperation(StartTLSExtendedRequest(SSLUtil(TrustAllTrustManager()).createSSLContext())) // 绑定用户 bind(userDn, password) } } }
- 使用自定义工厂初始化连接池
直接基于自定义工厂创建连接池,无需传入初始连接:
val connectionFactory = TLSLDAPConnectionFactory(opts, host, port, userDn, password) val ldapConnectionPool = LDAPConnectionPool(connectionFactory, 1, 10)
这样,连接池每次创建新连接时,都会自动完成StartTLS加密和用户绑定,避免出现强认证要求的错误。
注意:
TrustAllTrustManager仅适合测试环境,生产环境必须使用验证合法证书的TrustManager,防止安全风险。
内容的提问来源于stack exchange,提问作者gstackoverflow

