Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ARTEMIS-1971 - close ldap context on clear and add support for connec… #2173

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -128,7 +130,9 @@ public void initialize(Subject subject,
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));
Expand Down Expand Up @@ -220,6 +224,7 @@ public boolean commit() throws LoginException {
private void clear() {
username = null;
userAuthenticated = false;
closeContext();
}

@Override
Expand Down Expand Up @@ -579,6 +584,12 @@ protected void openContext() throws Exception {
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"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@
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;
Expand All @@ -45,6 +49,7 @@
import org.apache.directory.server.core.annotations.ApplyLdifFiles;
import org.apache.directory.server.core.integ.AbstractLdapTestUnit;
import org.apache.directory.server.core.integ.FrameworkRunner;
import org.jboss.logging.Logger;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
Expand All @@ -60,6 +65,8 @@
@ApplyLdifFiles("test.ldif")
public class LDAPLoginModuleTest extends AbstractLdapTestUnit {

private static final Logger logger = Logger.getLogger(LDAPLoginModuleTest.class);

private static final String PRINCIPAL = "uid=admin,ou=system";
private static final String CREDENTIALS = "secret";

Expand Down Expand Up @@ -109,6 +116,9 @@ public void testRunning() throws Exception {

@Test
public void testLogin() throws LoginException {

logger.info("num session: " + ldapServer.getLdapSessionManager().getSessions().length);

LoginContext context = new LoginContext("LDAPLogin", new CallbackHandler() {
@Override
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
Expand All @@ -125,6 +135,97 @@ public void handle(Callback[] callbacks) throws IOException, UnsupportedCallback
});
context.login();
context.logout();

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;
while (numSession != expected && System.currentTimeMillis() < expiry) {
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException ok) {
break;
}
numSession = ldapServer.getLdapSessionManager().getSessions().length;
logger.info("num session " + numSession);

}
return numSession == expected;
}

@Test
Expand All @@ -150,6 +251,7 @@ public void handle(Callback[] callbacks) throws IOException, UnsupportedCallback
return;
}
fail("Should have failed authenticating");
assertTrue("no sessions after logout", waitForSessions(0));
}

@Test
Expand Down
21 changes: 21 additions & 0 deletions artemis-server/src/test/resources/login.config
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 7 additions & 0 deletions docs/user-manual/en/security.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down