ARTEMIS-1971 Support connection pooling in LDAPLoginModule

This commit is contained in:
gtully 2018-07-06 16:48:13 +01:00 committed by Justin Bertram
parent 2ff4faab05
commit d54e5a7868
4 changed files with 116 additions and 1 deletions

View File

@ -85,6 +85,8 @@ public class LDAPLoginModule implements LoginModule {
private static final String AUTHENTICATE_USER = "authenticateUser"; private static final String AUTHENTICATE_USER = "authenticateUser";
private static final String REFERRAL = "referral"; private static final String REFERRAL = "referral";
private static final String PASSWORD_CODEC = "passwordCodec"; private static final String PASSWORD_CODEC = "passwordCodec";
private static final String CONNECTION_POOL = "connectionPool";
private static final String CONNECTION_TIMEOUT = "connectionTimeout";
protected DirContext context; protected DirContext context;
@ -128,7 +130,9 @@ public class LDAPLoginModule implements LoginModule {
new LDAPLoginProperty(PASSWORD_CODEC, (String) options.get(PASSWORD_CODEC)), new LDAPLoginProperty(PASSWORD_CODEC, (String) options.get(PASSWORD_CODEC)),
new LDAPLoginProperty(SASL_LOGIN_CONFIG_SCOPE, (String) options.get(SASL_LOGIN_CONFIG_SCOPE)), new LDAPLoginProperty(SASL_LOGIN_CONFIG_SCOPE, (String) options.get(SASL_LOGIN_CONFIG_SCOPE)),
new LDAPLoginProperty(AUTHENTICATE_USER, (String) options.get(AUTHENTICATE_USER)), new LDAPLoginProperty(AUTHENTICATE_USER, (String) options.get(AUTHENTICATE_USER)),
new LDAPLoginProperty(REFERRAL, (String) options.get(REFERRAL))}; new LDAPLoginProperty(REFERRAL, (String) options.get(REFERRAL)),
new LDAPLoginProperty(CONNECTION_POOL, (String) options.get(CONNECTION_POOL)),
new LDAPLoginProperty(CONNECTION_TIMEOUT, (String) options.get(CONNECTION_TIMEOUT))};
if (isLoginPropertySet(AUTHENTICATE_USER)) { if (isLoginPropertySet(AUTHENTICATE_USER)) {
authenticateUser = Boolean.valueOf(getLDAPPropertyValue(AUTHENTICATE_USER)); authenticateUser = Boolean.valueOf(getLDAPPropertyValue(AUTHENTICATE_USER));
@ -580,6 +584,12 @@ public class LDAPLoginModule implements LoginModule {
env.put(Context.SECURITY_PROTOCOL, getLDAPPropertyValue(CONNECTION_PROTOCOL)); env.put(Context.SECURITY_PROTOCOL, getLDAPPropertyValue(CONNECTION_PROTOCOL));
env.put(Context.PROVIDER_URL, getLDAPPropertyValue(CONNECTION_URL)); env.put(Context.PROVIDER_URL, getLDAPPropertyValue(CONNECTION_URL));
env.put(Context.SECURITY_AUTHENTICATION, getLDAPPropertyValue(AUTHENTICATION)); env.put(Context.SECURITY_AUTHENTICATION, getLDAPPropertyValue(AUTHENTICATION));
if (isLoginPropertySet(CONNECTION_POOL)) {
env.put("com.sun.jndi.ldap.connect.pool", getLDAPPropertyValue(CONNECTION_POOL));
}
if (isLoginPropertySet(CONNECTION_TIMEOUT)) {
env.put("com.sun.jndi.ldap.connect.timeout", getLDAPPropertyValue(CONNECTION_TIMEOUT));
}
// handle LDAP referrals // handle LDAP referrals
// valid values are "throw", "ignore" and "follow" // valid values are "throw", "ignore" and "follow"

View File

@ -36,6 +36,10 @@ import java.lang.reflect.Modifier;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import org.apache.activemq.artemis.spi.core.security.jaas.JaasCallbackHandler; import org.apache.activemq.artemis.spi.core.security.jaas.JaasCallbackHandler;
import org.apache.activemq.artemis.spi.core.security.jaas.LDAPLoginModule; import org.apache.activemq.artemis.spi.core.security.jaas.LDAPLoginModule;
@ -134,6 +138,79 @@ public class LDAPLoginModuleTest extends AbstractLdapTestUnit {
assertTrue("no sessions after logout", waitForSessions(0)); assertTrue("no sessions after logout", waitForSessions(0));
} }
@Test
public void testLoginPooled() throws LoginException {
LoginContext context = new LoginContext("LDAPLoginPooled", new CallbackHandler() {
@Override
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
for (int i = 0; i < callbacks.length; i++) {
if (callbacks[i] instanceof NameCallback) {
((NameCallback) callbacks[i]).setName("first");
} else if (callbacks[i] instanceof PasswordCallback) {
((PasswordCallback) callbacks[i]).setPassword("secret".toCharArray());
} else {
throw new UnsupportedCallbackException(callbacks[i]);
}
}
}
});
context.login();
context.logout();
// again
context.login();
context.logout();
// new context
context = new LoginContext("LDAPLoginPooled", new CallbackHandler() {
@Override
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
for (int i = 0; i < callbacks.length; i++) {
if (callbacks[i] instanceof NameCallback) {
((NameCallback) callbacks[i]).setName("first");
} else if (callbacks[i] instanceof PasswordCallback) {
((PasswordCallback) callbacks[i]).setPassword("secret".toCharArray());
} else {
throw new UnsupportedCallbackException(callbacks[i]);
}
}
}
});
context.login();
context.logout();
Executor pool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
((ExecutorService) pool).execute(new Runnable() {
@Override
public void run() {
try {
LoginContext context = new LoginContext("LDAPLoginPooled", new CallbackHandler() {
@Override
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
for (int i = 0; i < callbacks.length; i++) {
if (callbacks[i] instanceof NameCallback) {
((NameCallback) callbacks[i]).setName("first");
} else if (callbacks[i] instanceof PasswordCallback) {
((PasswordCallback) callbacks[i]).setPassword("secret".toCharArray());
} else {
throw new UnsupportedCallbackException(callbacks[i]);
}
}
}
});
context.login();
context.logout();
} catch (Exception ignored) {
}
}
});
}
assertTrue("no sessions after logout", waitForSessions(10));
}
private boolean waitForSessions(int expected) { private boolean waitForSessions(int expected) {
final long expiry = System.currentTimeMillis() + 5000; final long expiry = System.currentTimeMillis() + 5000;
int numSession = ldapServer.getLdapSessionManager().getSessions().length; int numSession = ldapServer.getLdapSessionManager().getSessions().length;

View File

@ -49,6 +49,27 @@ LDAPLogin {
; ;
}; };
LDAPLoginPooled {
org.apache.activemq.artemis.spi.core.security.jaas.LDAPLoginModule required
debug=true
initialContextFactory=com.sun.jndi.ldap.LdapCtxFactory
connectionURL="ldap://localhost:1024"
connectionUsername="uid=admin,ou=system"
connectionPassword=secret
connectionProtocol=s
authentication=simple
userBase="ou=system"
userSearchMatching="(uid={0})"
userSearchSubtree=false
roleBase="ou=system"
roleName=cn
roleSearchMatching="(member=uid={1},ou=system)"
roleSearchSubtree=false
connectionPool=true
connectionTimeout="2000"
;
};
UnAuthenticatedLDAPLogin { UnAuthenticatedLDAPLogin {
org.apache.activemq.artemis.spi.core.security.jaas.LDAPLoginModule required org.apache.activemq.artemis.spi.core.security.jaas.LDAPLoginModule required
debug=true debug=true

View File

@ -587,6 +587,13 @@ system. It is implemented by
for the connection to the directory server. This option must be set explicitly for the connection to the directory server. This option must be set explicitly
to an empty string, because it has no default value. to an empty string, because it has no default value.
- `connectionPool`. boolean, enable the ldap connection pool property
'com.sun.jndi.ldap.connect.pool'. Note that the pool is [configured at the jvm level with system properties](https://docs.oracle.com/javase/jndi/tutorial/ldap/connect/config.html).
- `connectionTimeout`. String milliseconds, that can time limit a ldap connection
attempt. The default is infinite.
- `userBase` - selects a particular subtree of the DIT to search for user - `userBase` - selects a particular subtree of the DIT to search for user
entries. The subtree is specified by a DN, which specifes the base node of entries. The subtree is specified by a DN, which specifes the base node of
the subtree. For example, by setting this option to the subtree. For example, by setting this option to