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 REFERRAL = "referral";
private static final String PASSWORD_CODEC = "passwordCodec";
private static final String CONNECTION_POOL = "connectionPool";
private static final String CONNECTION_TIMEOUT = "connectionTimeout";
protected DirContext context;
@ -128,7 +130,9 @@ public class LDAPLoginModule implements LoginModule {
new LDAPLoginProperty(PASSWORD_CODEC, (String) options.get(PASSWORD_CODEC)),
new LDAPLoginProperty(SASL_LOGIN_CONFIG_SCOPE, (String) options.get(SASL_LOGIN_CONFIG_SCOPE)),
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)) {
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.PROVIDER_URL, getLDAPPropertyValue(CONNECTION_URL));
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
// 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.HashSet;
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.LDAPLoginModule;
@ -134,6 +138,79 @@ public class LDAPLoginModuleTest extends AbstractLdapTestUnit {
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) {
final long expiry = System.currentTimeMillis() + 5000;
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 {
org.apache.activemq.artemis.spi.core.security.jaas.LDAPLoginModule required
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
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
entries. The subtree is specified by a DN, which specifes the base node of
the subtree. For example, by setting this option to