具有 spring 安全性的 LDAP 连接池
LDAP Connection Pooling with spring security
我正在尝试使用 spring 安全性和基于 xml 的配置设置 LDAP 连接池。
下面是我的配置,
<authentication-manager id="authenticationManager">
<ldap-authentication-provider server-ref="ldapServer"
user-dn-pattern="uid={0},ou=users"
group-search-filter="(&(objectClass=groupOfUniqueNames)(uniqueMember={0}))"
group-search-base="ou=groups"
group-role-attribute="cn"
role-prefix="ROLE_"
user-context-mapper-ref="ldapContextMapperImpl">
</ldap-authentication-provider>
</authentication-manager>
如何提供所有连接池配置?
我打算使用 PoolingContextSource class 因为它提供了配置池大小等的属性
合并的连接不适用于身份验证,因为 LDAP 身份验证的工作方式是在创建连接时对连接进行身份验证。
他们明确删除了 ldap 绑定的池(或者在 Spring 的情况下 authenticate
):
https://github.com/spring-projects/spring-ldap/issues/216
ldapTemplate.authenticate
搜索用户并调用 contextSource.getContext
执行 ldap 绑定。
private AuthenticationStatus authenticate(Name base,
String filter,
String password,
SearchControls searchControls,
final AuthenticatedLdapEntryContextCallback callback,
final AuthenticationErrorCallback errorCallback) {
List<LdapEntryIdentification> result = search(base, filter, searchControls, new LdapEntryIdentificationContextMapper());
if (result.size() == 0) {
String msg = "No results found for search, base: '" + base + "'; filter: '" + filter + "'.";
LOG.info(msg);
return AuthenticationStatus.EMPTYRESULT;
} else if (result.size() > 1) {
String msg = "base: '" + base + "'; filter: '" + filter + "'.";
throw new IncorrectResultSizeDataAccessException(msg, 1, result.size());
}
final LdapEntryIdentification entryIdentification = result.get(0);
try {
DirContext ctx = contextSource.getContext(entryIdentification.getAbsoluteName().toString(), password);
executeWithContext(new ContextExecutor<Object>() {
public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException {
callback.executeWithContext(ctx, entryIdentification);
return null;
}
}, ctx);
return AuthenticationStatus.SUCCESS;
}
catch (Exception e) {
LOG.debug("Authentication failed for entry with DN '" + entryIdentification.getAbsoluteName() + "'", e);
errorCallback.execute(e);
return AuthenticationStatus.UNDEFINED_FAILURE;
}
}
默认情况下,上下文源禁用池化。从 AbstractContextSource.java
(这是 LdapContextSource
继承的):
public abstract class AbstractContextSource implements BaseLdapPathContextSource, InitializingBean {
...
public DirContext getContext(String principal, String credentials) {
// This method is typically called for authentication purposes, which means that we
// should explicitly disable pooling in case passwords are changed (LDAP-183).
return doGetContext(principal, credentials, EXPLICITLY_DISABLE_POOLING);
}
private DirContext doGetContext(String principal, String credentials, boolean explicitlyDisablePooling) {
Hashtable<String, Object> env = getAuthenticatedEnv(principal, credentials);
if(explicitlyDisablePooling) {
env.remove(SUN_LDAP_POOLING_FLAG);
}
DirContext ctx = createContext(env);
try {
authenticationStrategy.processContextAfterCreation(ctx, principal, credentials);
return ctx;
}
catch (NamingException e) {
closeContext(ctx);
throw LdapUtils.convertLdapException(e);
}
}
...
}
如果您尝试使用 PoolingContextSource
,那么当 authenticate
尝试调用 getContext
:
时,您将得到一个 UnsupportedOperationException
public class PoolingContextSource
extends DelegatingBaseLdapPathContextSourceSupport
implements ContextSource, DisposableBean {
...
@Override
public DirContext getContext(String principal, String credentials) {
throw new UnsupportedOperationException("Not supported for this implementation");
}
}
此代码来自 spring-ldap-core 2.3.1.RELEASE
maven 神器。
您仍然可以使用 PoolingContextSource
为 ldap 搜索执行连接池,但用于身份验证的连接池将不起作用。
我正在尝试使用 spring 安全性和基于 xml 的配置设置 LDAP 连接池。
下面是我的配置,
<authentication-manager id="authenticationManager">
<ldap-authentication-provider server-ref="ldapServer"
user-dn-pattern="uid={0},ou=users"
group-search-filter="(&(objectClass=groupOfUniqueNames)(uniqueMember={0}))"
group-search-base="ou=groups"
group-role-attribute="cn"
role-prefix="ROLE_"
user-context-mapper-ref="ldapContextMapperImpl">
</ldap-authentication-provider>
</authentication-manager>
如何提供所有连接池配置? 我打算使用 PoolingContextSource class 因为它提供了配置池大小等的属性
合并的连接不适用于身份验证,因为 LDAP 身份验证的工作方式是在创建连接时对连接进行身份验证。
他们明确删除了 ldap 绑定的池(或者在 Spring 的情况下 authenticate
):
https://github.com/spring-projects/spring-ldap/issues/216
ldapTemplate.authenticate
搜索用户并调用 contextSource.getContext
执行 ldap 绑定。
private AuthenticationStatus authenticate(Name base,
String filter,
String password,
SearchControls searchControls,
final AuthenticatedLdapEntryContextCallback callback,
final AuthenticationErrorCallback errorCallback) {
List<LdapEntryIdentification> result = search(base, filter, searchControls, new LdapEntryIdentificationContextMapper());
if (result.size() == 0) {
String msg = "No results found for search, base: '" + base + "'; filter: '" + filter + "'.";
LOG.info(msg);
return AuthenticationStatus.EMPTYRESULT;
} else if (result.size() > 1) {
String msg = "base: '" + base + "'; filter: '" + filter + "'.";
throw new IncorrectResultSizeDataAccessException(msg, 1, result.size());
}
final LdapEntryIdentification entryIdentification = result.get(0);
try {
DirContext ctx = contextSource.getContext(entryIdentification.getAbsoluteName().toString(), password);
executeWithContext(new ContextExecutor<Object>() {
public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException {
callback.executeWithContext(ctx, entryIdentification);
return null;
}
}, ctx);
return AuthenticationStatus.SUCCESS;
}
catch (Exception e) {
LOG.debug("Authentication failed for entry with DN '" + entryIdentification.getAbsoluteName() + "'", e);
errorCallback.execute(e);
return AuthenticationStatus.UNDEFINED_FAILURE;
}
}
默认情况下,上下文源禁用池化。从 AbstractContextSource.java
(这是 LdapContextSource
继承的):
public abstract class AbstractContextSource implements BaseLdapPathContextSource, InitializingBean {
...
public DirContext getContext(String principal, String credentials) {
// This method is typically called for authentication purposes, which means that we
// should explicitly disable pooling in case passwords are changed (LDAP-183).
return doGetContext(principal, credentials, EXPLICITLY_DISABLE_POOLING);
}
private DirContext doGetContext(String principal, String credentials, boolean explicitlyDisablePooling) {
Hashtable<String, Object> env = getAuthenticatedEnv(principal, credentials);
if(explicitlyDisablePooling) {
env.remove(SUN_LDAP_POOLING_FLAG);
}
DirContext ctx = createContext(env);
try {
authenticationStrategy.processContextAfterCreation(ctx, principal, credentials);
return ctx;
}
catch (NamingException e) {
closeContext(ctx);
throw LdapUtils.convertLdapException(e);
}
}
...
}
如果您尝试使用 PoolingContextSource
,那么当 authenticate
尝试调用 getContext
:
UnsupportedOperationException
public class PoolingContextSource
extends DelegatingBaseLdapPathContextSourceSupport
implements ContextSource, DisposableBean {
...
@Override
public DirContext getContext(String principal, String credentials) {
throw new UnsupportedOperationException("Not supported for this implementation");
}
}
此代码来自 spring-ldap-core 2.3.1.RELEASE
maven 神器。
您仍然可以使用 PoolingContextSource
为 ldap 搜索执行连接池,但用于身份验证的连接池将不起作用。