https://issues.apache.org/jira/browse/AMQ-3294 - further refinement of dispose on security exception, now only on connection attempts. A security exception on an authenticated connection is reported back to the client and remains intact. Made use of inactivitymonitor w useKeepAlive=false to abort dos style hogging connections

git-svn-id: https://svn.apache.org/repos/asf/activemq/trunk@1367553 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Gary Tully 2012-07-31 13:54:41 +00:00
parent 78529d4eaf
commit c9b49d8b07
5 changed files with 52 additions and 21 deletions

View File

@ -1301,7 +1301,7 @@ public class ActiveMQConnection implements Connection, TopicConnection, QueueCon
* @return
* @throws JMSException
*/
public void syncSendPacket(Command command, final AsyncCallback onComplete) throws JMSException {
public void syncSendPacket(final Command command, final AsyncCallback onComplete) throws JMSException {
if(onComplete==null) {
syncSendPacket(command);
} else {
@ -1336,8 +1336,8 @@ public class ActiveMQConnection implements Connection, TopicConnection, QueueCon
} catch(Throwable e) {
LOG.error("Caught an exception trying to create a JMSException for " +exception,e);
}
//dispose of transport for security exceptions
if (exception instanceof SecurityException){
// dispose of transport for security exceptions on connection initiation
if (exception instanceof SecurityException && command instanceof ConnectionInfo){
Transport t = transport;
if (null != t){
ServiceSupport.dispose(t);
@ -1380,7 +1380,7 @@ public class ActiveMQConnection implements Connection, TopicConnection, QueueCon
LOG.error("Caught an exception trying to create a JMSException for " +er.getException(),e);
}
//dispose of transport for security exceptions
if (er.getException() instanceof SecurityException){
if (er.getException() instanceof SecurityException && command instanceof ConnectionInfo){
Transport t = this.transport;
if (null != t){
ServiceSupport.dispose(t);

View File

@ -299,11 +299,6 @@ public class TransportConnection implements Connection, Task, CommandVisitor {
+ " command: " + command + ", exception: " + e, e);
}
if (e instanceof java.lang.SecurityException) {
// still need to close this down - in case the peer of this transport doesn't play nice
delayedStop(2000, "Failed with SecurityException: " + e.getLocalizedMessage(), e);
}
if (responseRequired) {
response = new ExceptionResponse(e);
} else {
@ -722,6 +717,10 @@ public class TransportConnection implements Connection, Task, CommandVisitor {
if (LOG.isDebugEnabled()) {
LOG.debug("Exception detail:", e);
}
if (e instanceof SecurityException) {
// close this down - in case the peer of this transport doesn't play nice
delayedStop(2000, "Failed with SecurityException: " + e.getLocalizedMessage(), e);
}
throw e;
}
if (info.isManageable()) {

View File

@ -180,7 +180,7 @@ public abstract class AbstractInactivityMonitor extends TransportFilter {
}
if (!commandReceived.get() && monitorStarted.get() && !ASYNC_TASKS.isTerminating()) {
if (LOG.isDebugEnabled()) {
LOG.debug("No message received since last read check for " + toString() + "! Throwing InactivityIOException.");
LOG.debug("No message received since last read check for " + toString() + ". Throwing InactivityIOException.");
}
ASYNC_TASKS.execute(new Runnable() {
public void run() {

View File

@ -17,6 +17,8 @@
package org.apache.activemq.security;
import java.net.URI;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.jms.Connection;
import javax.jms.JMSException;
@ -29,7 +31,7 @@ import org.slf4j.LoggerFactory;
/**
* The configuration is set to except a maximum of 2 concurrent connections
* As the exception is delibrately ignored, the ActiveMQConnection would continue to
* As the exception is deliberately ignored, the ActiveMQConnection would continue to
* attempt to connect unless the connection's transport was also stopped on an error.
* <p/>
* As the maximum connections allowed is 2, no more connections would be allowed unless
@ -42,20 +44,48 @@ public class DoSTest extends JmsTestSupport {
public void testInvalidAuthentication() throws Throwable {
for (int i = 0; i < 1000; i++) {
// with failover reconnect, we don't expect this thread to complete
// but periodically the failure changes from ExceededMaximumConnectionsException on the broker
// side to a SecurityException.
// A failed to authenticated but idle connection (dos style) is aborted by the inactivity monitor
// since useKeepAlive=false
try {
// Bad password
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory();
Connection c = factory.createConnection("bad", "krap");
c.start();
fail("Expected exception.");
} catch (JMSException e) {
final AtomicBoolean done = new AtomicBoolean(false);
Thread thread = new Thread() {
Connection connection = null;
public void run() {
for (int i = 0; i < 1000 && !done.get(); i++) {
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory();
try {
// Bad password
connection = factory.createConnection("bad", "krap");
connection.start();
fail("Expected exception.");
} catch (JMSException e) {
// ignore exception and don't close
e.printStackTrace();
}
}
}
}
};
thread.start();
// run dos for a while
TimeUnit.SECONDS.sleep(10);
LOG.info("trying genuine connection ...");
// verify a valid connection can work with one of the 2 allowed connections provided it is eager!
// it could take a while as it is competing with the three other reconnect threads.
// wonder if it makes sense to serialise these reconnect attempts on an executor
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("failover:(tcp://127.0.0.1:61616)?useExponentialBackOff=false&reconnectDelay=10");
Connection goodConnection = factory.createConnection("user", "password");
goodConnection.start();
goodConnection.close();
LOG.info("giving up on DOS");
done.set(true);
}
protected BrokerService createBroker() throws Exception {

View File

@ -57,7 +57,9 @@
</authorizationPlugin>
</plugins>
<transportConnectors>
<transportConnector uri="tcp://localhost:61616?maximumConnections=2"/>
<!-- disable keepalive and use low tolerance for inactive connections such that rogue clients that connect
and do nothing (dos style) get aborted -->
<transportConnector uri="tcp://localhost:61616?maximumConnections=2&amp;wireFormat.maxInactivityDuration=500&amp;transport.useKeepAlive=false"/>
</transportConnectors>
</broker>