https://issues.apache.org/jira/browse/AMQ-3845 - handle LDAP restarts in cached ldap authorization map

git-svn-id: https://svn.apache.org/repos/asf/activemq/trunk@1348761 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Bosanac Dejan 2012-06-11 09:24:51 +00:00
parent 21a0465448
commit 06949a5074
2 changed files with 87 additions and 16 deletions

View File

@ -94,6 +94,22 @@ public class CachedLDAPAuthorizationMap extends DefaultAuthorizationMap implemen
protected HashMap<ActiveMQDestination, AuthorizationEntry> entries = protected HashMap<ActiveMQDestination, AuthorizationEntry> entries =
new HashMap<ActiveMQDestination, AuthorizationEntry>(); new HashMap<ActiveMQDestination, AuthorizationEntry>();
protected DirContext createContext() throws NamingException {
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, initialContextFactory);
if (connectionUsername != null || !"".equals(connectionUsername)) {
env.put(Context.SECURITY_PRINCIPAL, connectionUsername);
}
if (connectionPassword != null || !"".equals(connectionPassword)) {
env.put(Context.SECURITY_CREDENTIALS, connectionPassword);
}
env.put(Context.SECURITY_PROTOCOL, connectionProtocol);
env.put(Context.PROVIDER_URL, connectionURL);
env.put(Context.SECURITY_AUTHENTICATION, authentication);
//env.put("com.sun.jndi.ldap.connect.pool", "true");
return new InitialDirContext(env);
}
/** /**
* Returns the existing open context or creates a new one and registers listeners for * Returns the existing open context or creates a new one and registers listeners for
* push notifications if such an update style is enabled. This implementation should not * push notifications if such an update style is enabled. This implementation should not
@ -105,23 +121,20 @@ public class CachedLDAPAuthorizationMap extends DefaultAuthorizationMap implemen
*/ */
protected DirContext open() throws NamingException { protected DirContext open() throws NamingException {
if (context != null) { if (context != null) {
return context; boolean alive = true;
try {
context.getAttributes("");
} catch (Exception e) {
LOG.info("LDAP connection failed", e);
alive = false;
}
if (alive) {
return context;
}
} }
try { try {
Hashtable<String, String> env = new Hashtable<String, String>(); context = createContext();
env.put(Context.INITIAL_CONTEXT_FACTORY, initialContextFactory);
if (connectionUsername != null || !"".equals(connectionUsername)) {
env.put(Context.SECURITY_PRINCIPAL, connectionUsername);
}
if (connectionPassword != null || !"".equals(connectionPassword)) {
env.put(Context.SECURITY_CREDENTIALS, connectionPassword);
}
env.put(Context.SECURITY_PROTOCOL, connectionProtocol);
env.put(Context.PROVIDER_URL, connectionURL);
env.put(Context.SECURITY_AUTHENTICATION, authentication);
context = new InitialDirContext(env);
if (refreshInterval == -1 && !refreshDisabled) { if (refreshInterval == -1 && !refreshDisabled) {
eventContext = ((EventDirContext)context.lookup("")); eventContext = ((EventDirContext)context.lookup(""));
@ -158,6 +171,7 @@ public class CachedLDAPAuthorizationMap extends DefaultAuthorizationMap implemen
eventContext.addNamingListener(tempSearchBase, getFilterForPermissionType(permissionType), constraints, eventContext.addNamingListener(tempSearchBase, getFilterForPermissionType(permissionType), constraints,
this.new CachedLDAPAuthorizationMapNamespaceChangeListener(DestinationType.TEMP, permissionType)); this.new CachedLDAPAuthorizationMapNamespaceChangeListener(DestinationType.TEMP, permissionType));
} }
} }
} catch (NamingException e) { } catch (NamingException e) {
context = null; context = null;
@ -616,8 +630,15 @@ public class CachedLDAPAuthorizationMap extends DefaultAuthorizationMap implemen
* and are the refresh interval has elapsed. * and are the refresh interval has elapsed.
*/ */
protected void checkForUpdates() { protected void checkForUpdates() {
if (!refreshDisabled && (refreshInterval != -1 && System.currentTimeMillis() >= lastUpdated + refreshInterval)) { if (context == null || (!refreshDisabled && (refreshInterval != -1 && System.currentTimeMillis() >= lastUpdated + refreshInterval))) {
if (context == null) {
try {
context = createContext();
} catch (NamingException ne) {
// LDAP is down, use already cached values
return;
}
}
reset(); reset();
setTempDestinationAuthorizationEntry(null); setTempDestinationAuthorizationEntry(null);
entries.clear(); entries.clear();
@ -688,6 +709,7 @@ public class CachedLDAPAuthorizationMap extends DefaultAuthorizationMap implemen
* {@link AuthorizationEntry} is not setup for concurrent access. * {@link AuthorizationEntry} is not setup for concurrent access.
*/ */
public synchronized Set<Object> getReadACLs(ActiveMQDestination destination) { public synchronized Set<Object> getReadACLs(ActiveMQDestination destination) {
checkForUpdates();
return super.getReadACLs(destination); return super.getReadACLs(destination);
} }
@ -696,6 +718,7 @@ public class CachedLDAPAuthorizationMap extends DefaultAuthorizationMap implemen
* {@link AuthorizationEntry} is not setup for concurrent access. * {@link AuthorizationEntry} is not setup for concurrent access.
*/ */
public synchronized Set<Object> getWriteACLs(ActiveMQDestination destination) { public synchronized Set<Object> getWriteACLs(ActiveMQDestination destination) {
checkForUpdates();
return super.getWriteACLs(destination); return super.getWriteACLs(destination);
} }
@ -850,6 +873,7 @@ public class CachedLDAPAuthorizationMap extends DefaultAuthorizationMap implemen
* @param namingExceptionEvent the exception event * @param namingExceptionEvent the exception event
*/ */
public void namingExceptionThrown(NamingExceptionEvent namingExceptionEvent) { public void namingExceptionThrown(NamingExceptionEvent namingExceptionEvent) {
context = null;
LOG.error("Caught unexpected exception.", namingExceptionEvent.getException()); LOG.error("Caught unexpected exception.", namingExceptionEvent.getException());
} }

View File

@ -274,6 +274,53 @@ public abstract class AbstractCachedLDAPAuthorizationMapLegacyTest extends Abstr
failedACLs = map.getReadACLs(new ActiveMQQueue("TEST.FOO")); failedACLs = map.getReadACLs(new ActiveMQQueue("TEST.FOO"));
assertEquals("set size: " + failedACLs, 1, failedACLs.size()); assertEquals("set size: " + failedACLs, 1, failedACLs.size());
} }
@Test
public void testRestartAsync() throws Exception {
testRestart(false);
}
@Test
public void testRestartSync() throws Exception {
testRestart(true);
}
public void testRestart(boolean sync) throws Exception {
map.query();
if (sync) {
map.setRefreshInterval(1);
}
Set<?> failedACLs = map.getReadACLs(new ActiveMQQueue("FAILED"));
assertEquals("set size: " + failedACLs, 0, failedACLs.size());
failedACLs = map.getReadACLs(new ActiveMQQueue("TEST.FOO"));
assertEquals("set size: " + failedACLs, 2, failedACLs.size());
getLdapServer().stop();
Thread.sleep(1000);
failedACLs = map.getReadACLs(new ActiveMQQueue("TEST.FOO"));
assertEquals("set size: " + failedACLs, 2, failedACLs.size());
getLdapServer().start();
Thread.sleep(1000);
connection = getLdapConnection();
LdifReader reader = new LdifReader(getAddLdif());
for (LdifEntry entry : reader) {
connection.add(entry.getEntry());
}
Thread.sleep(2000);
failedACLs = map.getReadACLs(new ActiveMQQueue("FAILED"));
assertEquals("set size: " + failedACLs, 2, failedACLs.size());
}
protected CachedLDAPAuthorizationMap createMap() { protected CachedLDAPAuthorizationMap createMap() {
return new CachedLDAPAuthorizationMap(); return new CachedLDAPAuthorizationMap();