This is an automated email from the ASF dual-hosted git repository.
orudyy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/qpid-broker-j.git
The following commit(s) were added to refs/heads/master by this push:
new 1dd69d2 QPID-8369: [Broker-J] Add ability to limit a number of
connections per user
1dd69d2 is described below
commit 1dd69d26885abc6cf25b7c787d8b3bc727b2c74a
Author: Alex Rudyy <[email protected]>
AuthorDate: Fri Feb 28 14:08:44 2020 +0000
QPID-8369: [Broker-J] Add ability to limit a number of connections per user
This closes #43
---
.../apache/qpid/server/security/QpidPrincipal.java | 2 +-
.../security/auth/manager/SpnegoAuthenticator.java | 44 ++++-
.../qpid/server/transport/AMQPConnection.java | 7 +
.../server/transport/AbstractAMQPConnection.java | 28 ++++
.../server/virtualhost/AbstractVirtualHost.java | 46 ++++++
.../virtualhost/ConnectionPrincipalStatistics.java | 13 +-
.../ConnectionPrincipalStatisticsCheckingTask.java | 42 +++++
.../ConnectionPrincipalStatisticsRegistry.java | 15 +-
.../ConnectionStatisticsRegistrySettings.java | 13 +-
.../virtualhost/QueueManagingVirtualHost.java | 5 +
.../ConnectionPrincipalStatisticsImpl.java | 83 ++++++++++
.../ConnectionPrincipalStatisticsRegistryImpl.java | 182 +++++++++++++++++++++
.../apache/qpid/server/model/VirtualHostTest.java | 130 ++++++++++-----
...nectionPrincipalStatisticsCheckingTaskTest.java | 47 ++++++
.../ConnectionPrincipalStatisticsImplTest.java | 100 +++++++++++
...nectionPrincipalStatisticsRegistryImplTest.java | 136 +++++++++++++++
.../server/security/access/config/AclAction.java | 36 ++--
.../security/access/config/AclRulePredicates.java | 130 +++++++++++----
.../security/access/config/ClientAction.java | 22 +--
.../FirewallRule.java => config/DynamicRule.java} | 31 +++-
.../security/access/config/ObjectProperties.java | 4 +-
.../access/config/RuleBasedAccessControl.java | 26 +--
.../server/security/access/config/RuleSet.java | 18 +-
.../ConnectionPrincipalFrequencyLimitRule.java} | 25 ++-
.../connection/ConnectionPrincipalLimitRule.java} | 24 ++-
.../ConnectionPrincipalStatisticsRule.java | 70 ++++++++
.../security/access/firewall/FirewallRule.java | 37 ++++-
.../access/firewall/HostnameFirewallRule.java | 20 +--
.../access/firewall/NetworkFirewallRule.java | 20 +--
.../security/access/config/AclActionTest.java | 2 +-
.../access/config/AclRulePredicatesTest.java | 19 +++
.../security/access/config/ClientActionTest.java | 88 ++++++++--
.../security/access/config/DynamicRuleTest.java | 57 +++++++
.../access/config/RuleBasedAccessControlTest.java | 5 +-
.../ConnectionPrincipalFrequencyLimitRuleTest.java | 84 ++++++++++
.../ConnectionPrincipalLimitRuleTest.java | 84 ++++++++++
.../server/protocol/v0_10/ServerSessionTest.java | 11 +-
...Java-Broker-Security-AccessControlProviders.xml | 54 +++++-
.../jms_1_1/extensions/acl/MessagingACLTest.java | 139 ++++++++++++++--
39 files changed, 1620 insertions(+), 279 deletions(-)
diff --git
a/broker-core/src/main/java/org/apache/qpid/server/security/QpidPrincipal.java
b/broker-core/src/main/java/org/apache/qpid/server/security/QpidPrincipal.java
index 382fea8..3393098 100644
---
a/broker-core/src/main/java/org/apache/qpid/server/security/QpidPrincipal.java
+++
b/broker-core/src/main/java/org/apache/qpid/server/security/QpidPrincipal.java
@@ -55,8 +55,8 @@ public interface QpidPrincipal extends Principal, Serializable
"Can't find single %s in the authenticated
subject. There were %d "
+ "%s principals out of a total number of
principals of: %s",
principalClazz.getSimpleName(),
- principalClazz.getSimpleName(),
numberOfAuthenticatedPrincipals,
+ principalClazz.getSimpleName(),
authSubject.getPrincipals()));
}
return principals.iterator().next();
diff --git
a/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SpnegoAuthenticator.java
b/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SpnegoAuthenticator.java
index 48cf4f9..70db671 100644
---
a/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SpnegoAuthenticator.java
+++
b/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SpnegoAuthenticator.java
@@ -215,11 +215,15 @@ public class SpnegoAuthenticator
{
TokenCarryingPrincipal principal = new TokenCarryingPrincipal()
{
+
+ private Map<String, String> _tokens =
Collections.singletonMap(RESPONSE_AUTH_HEADER_NAME,
+
NEGOTIATE_PREFIX + Base64.getEncoder()
+
.encodeToString(outToken));
+
@Override
public Map<String, String> getTokens()
{
- return
Collections.singletonMap(RESPONSE_AUTH_HEADER_NAME,
- NEGOTIATE_PREFIX +
Base64.getEncoder().encodeToString(outToken));
+ return _tokens;
}
@Override
@@ -233,6 +237,42 @@ public class SpnegoAuthenticator
{
return principalName;
}
+
+ @Override
+ public boolean equals(final Object o)
+ {
+ if (this == o)
+ {
+ return true;
+ }
+ if (!(o instanceof TokenCarryingPrincipal))
+ {
+ return false;
+ }
+
+ final TokenCarryingPrincipal that =
(TokenCarryingPrincipal) o;
+
+ if (!getName().equals(that.getName()))
+ {
+ return false;
+ }
+
+ if (!getTokens().equals(that.getTokens()))
+ {
+ return false;
+ }
+ return getOrigin() != null ?
getOrigin().equals(that.getOrigin()) : that.getOrigin() == null;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ int result = getName().hashCode();
+ result = 31 * result + (getOrigin() != null ?
getOrigin().hashCode() : 0);
+ result = 31 * result + getTokens().hashCode();
+ return result;
+ }
+
};
return new AuthenticationResult(principal);
}
diff --git
a/broker-core/src/main/java/org/apache/qpid/server/transport/AMQPConnection.java
b/broker-core/src/main/java/org/apache/qpid/server/transport/AMQPConnection.java
index e99c254..ebcd737 100644
---
a/broker-core/src/main/java/org/apache/qpid/server/transport/AMQPConnection.java
+++
b/broker-core/src/main/java/org/apache/qpid/server/transport/AMQPConnection.java
@@ -39,6 +39,7 @@ import org.apache.qpid.server.txn.LocalTransaction;
import org.apache.qpid.server.txn.ServerTransaction;
import org.apache.qpid.server.util.Action;
import org.apache.qpid.server.util.Deletable;
+import org.apache.qpid.server.virtualhost.ConnectionPrincipalStatistics;
public interface AMQPConnection<C extends AMQPConnection<C>>
extends Connection<C>, Deletable<C>, EventLoggerProvider
@@ -147,4 +148,10 @@ public interface AMQPConnection<C extends
AMQPConnection<C>>
@Override
AmqpPort<?> getPort();
+ void registered(ConnectionPrincipalStatistics
connectionPrincipalStatistics);
+
+ int getAuthenticatedPrincipalConnectionCount();
+
+ int getAuthenticatedPrincipalConnectionFrequency();
+
}
diff --git
a/broker-core/src/main/java/org/apache/qpid/server/transport/AbstractAMQPConnection.java
b/broker-core/src/main/java/org/apache/qpid/server/transport/AbstractAMQPConnection.java
index ae4dee2..e45e993 100644
---
a/broker-core/src/main/java/org/apache/qpid/server/transport/AbstractAMQPConnection.java
+++
b/broker-core/src/main/java/org/apache/qpid/server/transport/AbstractAMQPConnection.java
@@ -83,6 +83,7 @@ import org.apache.qpid.server.util.Action;
import org.apache.qpid.server.util.ConnectionScopedRuntimeException;
import org.apache.qpid.server.util.FixedKeyMapCreator;
import org.apache.qpid.server.util.ServerScopedRuntimeException;
+import org.apache.qpid.server.virtualhost.ConnectionPrincipalStatistics;
import org.apache.qpid.server.virtualhost.QueueManagingVirtualHost;
public abstract class AbstractAMQPConnection<C extends
AbstractAMQPConnection<C,T>, T>
@@ -148,6 +149,7 @@ public abstract class AbstractAMQPConnection<C extends
AbstractAMQPConnection<C,
private long _maxUncommittedInMemorySize;
private final Map<ServerTransaction, Set<Ticker>> _transactionTickers =
new ConcurrentHashMap<>();
+ private volatile ConnectionPrincipalStatistics
_connectionPrincipalStatistics;
public AbstractAMQPConnection(Broker<?> broker,
ServerNetworkConnection network,
@@ -1157,4 +1159,30 @@ public abstract class AbstractAMQPConnection<C extends
AbstractAMQPConnection<C,
{
_localTransactionBegins.incrementAndGet();
}
+
+ @Override
+ public void registered(final ConnectionPrincipalStatistics
connectionPrincipalStatistics)
+ {
+ _connectionPrincipalStatistics = connectionPrincipalStatistics;
+ }
+
+ @Override
+ public int getAuthenticatedPrincipalConnectionCount()
+ {
+ if (_connectionPrincipalStatistics == null)
+ {
+ return 0;
+ }
+ return _connectionPrincipalStatistics.getConnectionCount();
+ }
+
+ @Override
+ public int getAuthenticatedPrincipalConnectionFrequency()
+ {
+ if (_connectionPrincipalStatistics == null)
+ {
+ return 0;
+ }
+ return _connectionPrincipalStatistics.getConnectionFrequency();
+ }
}
diff --git
a/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractVirtualHost.java
b/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractVirtualHost.java
index 3ddd26a..699f3c0 100644
---
a/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractVirtualHost.java
+++
b/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractVirtualHost.java
@@ -38,6 +38,7 @@ import java.nio.charset.StandardCharsets;
import java.security.AccessControlContext;
import java.security.Principal;
import java.security.PrivilegedAction;
+import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -147,6 +148,7 @@ import org.apache.qpid.server.txn.LocalTransaction;
import org.apache.qpid.server.txn.ServerTransaction;
import org.apache.qpid.server.util.HousekeepingExecutor;
import org.apache.qpid.server.util.Strings;
+import
org.apache.qpid.server.virtualhost.connection.ConnectionPrincipalStatisticsRegistryImpl;
public abstract class AbstractVirtualHost<X extends AbstractVirtualHost<X>>
extends AbstractConfiguredObject<X>
implements QueueManagingVirtualHost<X>
@@ -282,6 +284,8 @@ public abstract class AbstractVirtualHost<X extends
AbstractVirtualHost<X>> exte
private PreferenceStore _preferenceStore;
private long _flowToDiskCheckPeriod;
private volatile boolean _isDiscardGlobalSharedSubscriptionLinksOnDetach;
+ private volatile ConnectionPrincipalStatisticsRegistry
_connectionPrincipalStatisticsRegistry;
+ private volatile HouseKeepingTask _statisticsCheckTask;
public AbstractVirtualHost(final Map<String, Object> attributes,
VirtualHostNode<?> virtualHostNode)
{
@@ -2441,6 +2445,7 @@ public abstract class AbstractVirtualHost<X extends
AbstractVirtualHost<X>> exte
@Override
public void run()
{
+ resetConnectionPrincipalStatisticsRegistry();
shutdownHouseKeeping();
closeNetworkConnectionScheduler();
if (_linkRegistry != null)
@@ -2596,6 +2601,9 @@ public abstract class AbstractVirtualHost<X extends
AbstractVirtualHost<X>> exte
{
if
(connectionEstablishmentPolicy.mayEstablishNewConnection(_connections,
connection))
{
+ final ConnectionPrincipalStatistics cps =
+
_connectionPrincipalStatisticsRegistry.connectionOpened(connection);
+ connection.registered(cps);
_connections.add(connection);
_totalConnectionCount.incrementAndGet();
@@ -2658,6 +2666,7 @@ public abstract class AbstractVirtualHost<X extends
AbstractVirtualHost<X>> exte
{
connection.popScheduler();
_connections.remove(connection);
+
_connectionPrincipalStatisticsRegistry.connectionClosed(connection);
return Futures.immediateFuture(null);
}
@@ -2701,6 +2710,7 @@ public abstract class AbstractVirtualHost<X extends
AbstractVirtualHost<X>> exte
updateAccessControl();
initialiseStatisticsReporting();
+ initialiseConnectionPrincipalStatisticsRegistry();
MessageStore messageStore = getMessageStore();
messageStore.openMessageStore(this);
@@ -2749,6 +2759,42 @@ public abstract class AbstractVirtualHost<X extends
AbstractVirtualHost<X>> exte
}
}
+ private void initialiseConnectionPrincipalStatisticsRegistry()
+ {
+ final long connectionFrequencyPeriodMillis =
getContextValue(Long.class, CONNECTION_FREQUENCY_PERIOD);
+ final Duration connectionFrequencyPeriod =
Duration.ofMillis(connectionFrequencyPeriodMillis);
+ final ConnectionPrincipalStatisticsRegistryImpl
connectionStatisticsRegistry =
+ new ConnectionPrincipalStatisticsRegistryImpl(() ->
connectionFrequencyPeriod);
+ HouseKeepingTask task = null;
+ long taskRunPeriod = connectionFrequencyPeriodMillis / 2;
+ if (taskRunPeriod > 0)
+ {
+ final AccessControlContext context =
+
getSystemTaskControllerContext("ConnectionPrincipalStatisticsCheck",
_principal);
+ task = new ConnectionPrincipalStatisticsCheckingTask(this,
context, connectionStatisticsRegistry);
+ scheduleHouseKeepingTask(taskRunPeriod, task);
+ }
+ _statisticsCheckTask = task;
+ _connectionPrincipalStatisticsRegistry = connectionStatisticsRegistry;
+ }
+
+ private void resetConnectionPrincipalStatisticsRegistry()
+ {
+ final HouseKeepingTask previousStatisticsCheckTask =
_statisticsCheckTask;
+ if (previousStatisticsCheckTask != null)
+ {
+ previousStatisticsCheckTask.cancel();
+ }
+ _statisticsCheckTask = null;
+ final ConnectionPrincipalStatisticsRegistry
connectionPrincipalStatisticsRegistry =
+ _connectionPrincipalStatisticsRegistry;
+ if (connectionPrincipalStatisticsRegistry != null)
+ {
+ connectionPrincipalStatisticsRegistry.reset();
+ }
+ _connectionPrincipalStatisticsRegistry = null;
+ }
+
private void postCreateDefaultExchangeTasks()
{
if(getContextValue(Boolean.class, USE_ASYNC_RECOVERY))
diff --git
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/FirewallRule.java
b/broker-core/src/main/java/org/apache/qpid/server/virtualhost/ConnectionPrincipalStatistics.java
similarity index 71%
copy from
broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/FirewallRule.java
copy to
broker-core/src/main/java/org/apache/qpid/server/virtualhost/ConnectionPrincipalStatistics.java
index 72d8d69..661b89b 100644
---
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/FirewallRule.java
+++
b/broker-core/src/main/java/org/apache/qpid/server/virtualhost/ConnectionPrincipalStatistics.java
@@ -16,17 +16,12 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.qpid.server.security.access.firewall;
-import java.net.InetAddress;
+package org.apache.qpid.server.virtualhost;
-import org.apache.qpid.server.security.access.config.ObjectProperties;
-
-public interface FirewallRule
+public interface ConnectionPrincipalStatistics
{
- boolean matches(InetAddress addressOfClient);
-
- ObjectProperties.Property getPropertyName();
+ int getConnectionCount();
- String getPropertyValue();
+ int getConnectionFrequency();
}
diff --git
a/broker-core/src/main/java/org/apache/qpid/server/virtualhost/ConnectionPrincipalStatisticsCheckingTask.java
b/broker-core/src/main/java/org/apache/qpid/server/virtualhost/ConnectionPrincipalStatisticsCheckingTask.java
new file mode 100644
index 0000000..85322bd
--- /dev/null
+++
b/broker-core/src/main/java/org/apache/qpid/server/virtualhost/ConnectionPrincipalStatisticsCheckingTask.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.qpid.server.virtualhost;
+
+import java.security.AccessControlContext;
+
+public class ConnectionPrincipalStatisticsCheckingTask extends HouseKeepingTask
+{
+ private static final String TASK_NAME =
"ConnectionPrincipalStatisticsCheck";
+ private final ConnectionPrincipalStatisticsRegistry
_connectionPrincipalStatisticsRegistry;
+
+ public ConnectionPrincipalStatisticsCheckingTask(final
QueueManagingVirtualHost virtualHost,
+ final
AccessControlContext controlContext,
+ final
ConnectionPrincipalStatisticsRegistry connectionPrincipalStatisticsRegistry)
+ {
+ super(TASK_NAME, virtualHost, controlContext);
+ _connectionPrincipalStatisticsRegistry =
connectionPrincipalStatisticsRegistry;
+ }
+
+ @Override
+ public void execute()
+ {
+
_connectionPrincipalStatisticsRegistry.reevaluateConnectionStatistics();
+ }
+}
diff --git
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/FirewallRule.java
b/broker-core/src/main/java/org/apache/qpid/server/virtualhost/ConnectionPrincipalStatisticsRegistry.java
similarity index 68%
copy from
broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/FirewallRule.java
copy to
broker-core/src/main/java/org/apache/qpid/server/virtualhost/ConnectionPrincipalStatisticsRegistry.java
index 72d8d69..2f0afba 100644
---
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/FirewallRule.java
+++
b/broker-core/src/main/java/org/apache/qpid/server/virtualhost/ConnectionPrincipalStatisticsRegistry.java
@@ -16,17 +16,18 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.qpid.server.security.access.firewall;
-import java.net.InetAddress;
+package org.apache.qpid.server.virtualhost;
-import org.apache.qpid.server.security.access.config.ObjectProperties;
+import org.apache.qpid.server.transport.AMQPConnection;
-public interface FirewallRule
+public interface ConnectionPrincipalStatisticsRegistry
{
- boolean matches(InetAddress addressOfClient);
+ ConnectionPrincipalStatistics connectionOpened(AMQPConnection<?>
connection);
- ObjectProperties.Property getPropertyName();
+ ConnectionPrincipalStatistics connectionClosed(AMQPConnection<?>
connection);
- String getPropertyValue();
+ void reevaluateConnectionStatistics();
+
+ void reset();
}
diff --git
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/FirewallRule.java
b/broker-core/src/main/java/org/apache/qpid/server/virtualhost/ConnectionStatisticsRegistrySettings.java
similarity index 71%
copy from
broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/FirewallRule.java
copy to
broker-core/src/main/java/org/apache/qpid/server/virtualhost/ConnectionStatisticsRegistrySettings.java
index 72d8d69..d9611e6 100644
---
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/FirewallRule.java
+++
b/broker-core/src/main/java/org/apache/qpid/server/virtualhost/ConnectionStatisticsRegistrySettings.java
@@ -16,17 +16,12 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.qpid.server.security.access.firewall;
-import java.net.InetAddress;
+package org.apache.qpid.server.virtualhost;
-import org.apache.qpid.server.security.access.config.ObjectProperties;
+import java.time.Duration;
-public interface FirewallRule
+public interface ConnectionStatisticsRegistrySettings
{
- boolean matches(InetAddress addressOfClient);
-
- ObjectProperties.Property getPropertyName();
-
- String getPropertyValue();
+ Duration getConnectionFrequencyPeriod();
}
diff --git
a/broker-core/src/main/java/org/apache/qpid/server/virtualhost/QueueManagingVirtualHost.java
b/broker-core/src/main/java/org/apache/qpid/server/virtualhost/QueueManagingVirtualHost.java
index 9f1b318..f76835d 100644
---
a/broker-core/src/main/java/org/apache/qpid/server/virtualhost/QueueManagingVirtualHost.java
+++
b/broker-core/src/main/java/org/apache/qpid/server/virtualhost/QueueManagingVirtualHost.java
@@ -104,6 +104,11 @@ public interface QueueManagingVirtualHost<X extends
QueueManagingVirtualHost<X>>
+ " link detaches. This is to avoid
leaking links with the Qpid JMS client.")
boolean DEFAULT_DISCARD_GLOBAL_SHARED_SUBSCRIPTION_LINKS_ON_DETACH = true;
+ String CONNECTION_FREQUENCY_PERIOD =
"qpid.virtualhost.connectionFrequencyPeriodInMillis";
+ @ManagedContextDefault(name = CONNECTION_FREQUENCY_PERIOD, description =
"Interval (in milliseconds) to evaluate connection frequency")
+ @SuppressWarnings("unused")
+ long DEFAULT_CONNECTION_FREQUENCY_PERIOD = 60 * 1000;
+
@ManagedAttribute( defaultValue = "${" +
VIRTUALHOST_STATISTICS_REPORING_PERIOD + "}", description = "Period (in
seconds) of the statistic report.")
int getStatisticsReportingPeriod();
diff --git
a/broker-core/src/main/java/org/apache/qpid/server/virtualhost/connection/ConnectionPrincipalStatisticsImpl.java
b/broker-core/src/main/java/org/apache/qpid/server/virtualhost/connection/ConnectionPrincipalStatisticsImpl.java
new file mode 100644
index 0000000..9acd7a5
--- /dev/null
+++
b/broker-core/src/main/java/org/apache/qpid/server/virtualhost/connection/ConnectionPrincipalStatisticsImpl.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.qpid.server.virtualhost.connection;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.qpid.server.virtualhost.ConnectionPrincipalStatistics;
+
+class ConnectionPrincipalStatisticsImpl implements
ConnectionPrincipalStatistics
+{
+ private final int _connectionCount;
+ private final List<Long> _latestConnectionCreatedTimes;
+
+ ConnectionPrincipalStatisticsImpl(final int connectionCount, final
List<Long> latestConnectionCreatedTimes)
+ {
+ _connectionCount = connectionCount;
+ _latestConnectionCreatedTimes =
Collections.unmodifiableList(latestConnectionCreatedTimes);
+ }
+
+ @Override
+ public int getConnectionCount()
+ {
+ return _connectionCount;
+ }
+
+ @Override
+ public int getConnectionFrequency()
+ {
+ return _latestConnectionCreatedTimes.size();
+ }
+
+ List<Long> getLatestConnectionCreatedTimes()
+ {
+ return _latestConnectionCreatedTimes;
+ }
+
+ @Override
+ public boolean equals(final Object o)
+ {
+ if (this == o)
+ {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass())
+ {
+ return false;
+ }
+
+ final ConnectionPrincipalStatisticsImpl that =
(ConnectionPrincipalStatisticsImpl) o;
+
+ if (_connectionCount != that._connectionCount)
+ {
+ return false;
+ }
+ return
_latestConnectionCreatedTimes.equals(that._latestConnectionCreatedTimes);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ int result = _connectionCount;
+ result = 31 * result + _latestConnectionCreatedTimes.hashCode();
+ return result;
+ }
+}
diff --git
a/broker-core/src/main/java/org/apache/qpid/server/virtualhost/connection/ConnectionPrincipalStatisticsRegistryImpl.java
b/broker-core/src/main/java/org/apache/qpid/server/virtualhost/connection/ConnectionPrincipalStatisticsRegistryImpl.java
new file mode 100644
index 0000000..59d03ea
--- /dev/null
+++
b/broker-core/src/main/java/org/apache/qpid/server/virtualhost/connection/ConnectionPrincipalStatisticsRegistryImpl.java
@@ -0,0 +1,182 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.qpid.server.virtualhost.connection;
+
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+
+import javax.security.auth.Subject;
+
+import org.apache.qpid.server.security.auth.AuthenticatedPrincipal;
+import org.apache.qpid.server.transport.AMQPConnection;
+import org.apache.qpid.server.virtualhost.ConnectionPrincipalStatistics;
+import
org.apache.qpid.server.virtualhost.ConnectionPrincipalStatisticsRegistry;
+import org.apache.qpid.server.virtualhost.ConnectionStatisticsRegistrySettings;
+
+public class ConnectionPrincipalStatisticsRegistryImpl implements
ConnectionPrincipalStatisticsRegistry
+{
+ private final Map<Principal, ConnectionPrincipalStatisticsImpl>
_principalStatistics = new ConcurrentHashMap<>();
+ private final ConnectionStatisticsRegistrySettings _settings;
+
+ public ConnectionPrincipalStatisticsRegistryImpl(final
ConnectionStatisticsRegistrySettings settings)
+ {
+ _settings = settings;
+ }
+
+ @Override
+ public ConnectionPrincipalStatistics connectionOpened(final
AMQPConnection<?> connection)
+ {
+ final Subject subject = connection.getSubject();
+ final AuthenticatedPrincipal principal =
AuthenticatedPrincipal.getAuthenticatedPrincipalFromSubject(subject);
+ return _principalStatistics.compute(principal,
+ (p, s) -> connectionOpened(s,
connection.getCreatedTime()));
+ }
+
+ @Override
+ public ConnectionPrincipalStatistics connectionClosed(final
AMQPConnection<?> connection)
+ {
+ final Subject subject = connection.getSubject();
+ final AuthenticatedPrincipal principal =
AuthenticatedPrincipal.getAuthenticatedPrincipalFromSubject(subject);
+ return _principalStatistics.computeIfPresent(principal, (p, s) ->
connectionClosed(s));
+ }
+
+ @Override
+ public void reevaluateConnectionStatistics()
+ {
+ new
HashSet<>(_principalStatistics.keySet()).forEach(this::reevaluateConnectionStatistics);
+ }
+
+ @Override
+ public void reset()
+ {
+ _principalStatistics.clear();
+ }
+
+ int getConnectionCount(final Principal principal)
+ {
+ ConnectionPrincipalStatistics cs = _principalStatistics.get(principal);
+ if (cs != null)
+ {
+ return cs.getConnectionCount();
+ }
+ return 0;
+ }
+
+ int getConnectionFrequency(final Principal principal)
+ {
+ ConnectionPrincipalStatistics cs = _principalStatistics.get(principal);
+ if (cs != null)
+ {
+ return cs.getConnectionFrequency();
+ }
+ return 0;
+ }
+
+ private ConnectionPrincipalStatisticsImpl connectionOpened(final
ConnectionPrincipalStatisticsImpl current,
+ final Date
createdTime)
+ {
+ if (current == null)
+ {
+ return new ConnectionPrincipalStatisticsImpl(1,
Collections.singletonList(createdTime.getTime()));
+ }
+ else
+ {
+ final long frequencyPeriod = getConnectionFrequencyPeriodMillis();
+ final List<Long> connectionCreatedTimes;
+ if (frequencyPeriod > 0)
+ {
+ connectionCreatedTimes =
findTimesWithinPeriod(current.getLatestConnectionCreatedTimes(),
frequencyPeriod);
+ connectionCreatedTimes.add(createdTime.getTime());
+ }
+ else
+ {
+ connectionCreatedTimes = Collections.emptyList();
+ }
+ return new
ConnectionPrincipalStatisticsImpl(current.getConnectionCount() + 1,
connectionCreatedTimes);
+ }
+ }
+
+ private ConnectionPrincipalStatisticsImpl connectionClosed(final
ConnectionPrincipalStatisticsImpl current)
+ {
+ return createStatisticsOrNull(Math.max(0, current.getConnectionCount()
- 1), current.getLatestConnectionCreatedTimes());
+ }
+
+ private void reevaluateConnectionStatistics(final Principal
authenticatedPrincipal)
+ {
+ _principalStatistics.computeIfPresent(authenticatedPrincipal,
(principal, current) -> reevaluate(current));
+ }
+
+ private ConnectionPrincipalStatisticsImpl reevaluate(final
ConnectionPrincipalStatisticsImpl current)
+ {
+ return createStatisticsOrNull(current.getConnectionCount(),
current.getLatestConnectionCreatedTimes());
+ }
+
+ private ConnectionPrincipalStatisticsImpl createStatisticsOrNull(final int
openConnectionCount,
+ final
List<Long> currentConnectionCreatedTimes)
+ {
+ final List<Long> connectionCreatedTimes =
findTimesWithinPeriod(currentConnectionCreatedTimes,
getConnectionFrequencyPeriodMillis());
+ if (openConnectionCount == 0 && connectionCreatedTimes.isEmpty())
+ {
+ return null;
+ }
+ return new ConnectionPrincipalStatisticsImpl(openConnectionCount,
connectionCreatedTimes);
+ }
+
+ private List<Long> findTimesWithinPeriod(final Collection<Long>
currentConnectionCreatedTimes,
+ final long frequencyPeriod)
+ {
+
+ final List<Long> connectionCreatedTimes;
+ if (frequencyPeriod > 0)
+ {
+ final long periodEnd = System.currentTimeMillis();
+ final long periodStart = periodEnd - frequencyPeriod;
+ connectionCreatedTimes =
findTimesBetween(currentConnectionCreatedTimes, periodStart, periodEnd);
+ }
+ else
+ {
+ connectionCreatedTimes = Collections.emptyList();
+ }
+ return connectionCreatedTimes;
+ }
+
+ private List<Long> findTimesBetween(final Collection<Long>
connectionCreatedTimes,
+ final long periodStart,
+ final long periodEnd)
+ {
+ return connectionCreatedTimes.stream().mapToLong(Long::longValue)
+ .filter(t -> t >= periodStart && t <=
periodEnd)
+ .boxed()
+
.collect(Collectors.toCollection(ArrayList::new));
+ }
+
+ private long getConnectionFrequencyPeriodMillis()
+ {
+ return _settings.getConnectionFrequencyPeriod().toMillis();
+ }
+}
diff --git
a/broker-core/src/test/java/org/apache/qpid/server/model/VirtualHostTest.java
b/broker-core/src/test/java/org/apache/qpid/server/model/VirtualHostTest.java
index dc96a93..b3dea1b 100644
---
a/broker-core/src/test/java/org/apache/qpid/server/model/VirtualHostTest.java
+++
b/broker-core/src/test/java/org/apache/qpid/server/model/VirtualHostTest.java
@@ -26,7 +26,6 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.same;
@@ -43,18 +42,20 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;
+import javax.security.auth.Subject;
+
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatcher;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
@@ -67,6 +68,7 @@ import org.apache.qpid.server.exchange.ExchangeDefaults;
import org.apache.qpid.server.security.AccessControl;
import org.apache.qpid.server.security.Result;
import org.apache.qpid.server.security.access.Operation;
+import org.apache.qpid.server.security.auth.AuthenticatedPrincipal;
import org.apache.qpid.server.store.ConfiguredObjectRecord;
import org.apache.qpid.server.store.DurableConfigurationStore;
import org.apache.qpid.server.store.Event;
@@ -75,8 +77,7 @@ import
org.apache.qpid.server.store.handler.ConfiguredObjectRecordHandler;
import org.apache.qpid.server.store.preferences.PreferenceStore;
import org.apache.qpid.server.store.preferences.PreferenceStoreUpdater;
import org.apache.qpid.server.transport.AMQPConnection;
-import org.apache.qpid.server.transport.AbstractAMQPConnection;
-import org.apache.qpid.server.util.Action;
+import org.apache.qpid.server.virtualhost.ConnectionPrincipalStatistics;
import org.apache.qpid.server.virtualhost.NodeAutoCreationPolicy;
import org.apache.qpid.server.virtualhost.NoopConnectionEstablishmentPolicy;
import org.apache.qpid.server.virtualhost.QueueManagingVirtualHost;
@@ -333,13 +334,11 @@ public class VirtualHostTest extends UnitTestBase
QueueManagingVirtualHost<?> virtualHost =
createVirtualHost(virtualHostName);
assertEquals("Unexpected state", State.ACTIVE, virtualHost.getState());
- AbstractAMQPConnection connection =
createMockProtocolConnection(virtualHost);
assertEquals("Unexpected number of connections before connection
registered",
(long) 0,
virtualHost.getConnectionCount());
- AMQPConnection modelConnection = mock(AMQPConnection.class);
-
when(modelConnection.closeAsync()).thenReturn(Futures.immediateFuture(null));
+ AMQPConnection modelConnection = getMockConnection();
virtualHost.registerConnection(modelConnection, new
NoopConnectionEstablishmentPolicy());
assertEquals("Unexpected number of connections after connection
registered",
@@ -364,13 +363,11 @@ public class VirtualHostTest extends UnitTestBase
QueueManagingVirtualHost<?> virtualHost =
createVirtualHost(virtualHostName);
assertEquals("Unexpected state", State.ACTIVE, virtualHost.getState());
- AbstractAMQPConnection connection =
createMockProtocolConnection(virtualHost);
assertEquals("Unexpected number of connections before connection
registered",
(long) 0,
virtualHost.getConnectionCount());
- AMQPConnection modelConnection = mock(AMQPConnection.class);
-
when(modelConnection.closeAsync()).thenReturn(Futures.immediateFuture(null));
+ AMQPConnection modelConnection = getMockConnection();
virtualHost.registerConnection(modelConnection, new
NoopConnectionEstablishmentPolicy());
assertEquals("Unexpected number of connections after connection
registered",
@@ -502,9 +499,9 @@ public class VirtualHostTest extends UnitTestBase
public void testExistingConnectionBlocking()
{
VirtualHost<?> host = createVirtualHost(getTestName());
- AbstractAMQPConnection connection = mock(AbstractAMQPConnection.class);
+ AMQPConnection connection = getMockConnection();
host.registerConnection(connection, new
NoopConnectionEstablishmentPolicy());
- ((EventListener)host).event(Event.PERSISTENT_MESSAGE_SIZE_OVERFULL);
+ ((EventListener) host).event(Event.PERSISTENT_MESSAGE_SIZE_OVERFULL);
verify(connection).block();
}
@@ -590,6 +587,46 @@ public class VirtualHostTest extends UnitTestBase
}
@Test
+ public void
testRegisterConnectionCausesUpdateOfAuthenticatedPrincipalConnectionCountAndFrequency()
+ {
+ final NoopConnectionEstablishmentPolicy policy = new
NoopConnectionEstablishmentPolicy();
+ final QueueManagingVirtualHost<?> vhost =
createVirtualHost(getTestName());
+ final Principal principal = mockAuthenticatedPrincipal(getTestName());
+ final Principal principal2 = mockAuthenticatedPrincipal(getTestName()
+ "_2");
+ final AMQPConnection<?> connection1 = mockAmqpConnection(principal);
+ final AMQPConnection<?> connection2 = mockAmqpConnection(principal);
+ final AMQPConnection<?> connection3 = mockAmqpConnection(principal2);
+
+ vhost.registerConnection(connection1, policy);
+ verify(connection1).registered(argThat(new
ConnectionPrincipalStatisticsArgumentMatcher(1, 1)));
+
+ vhost.registerConnection(connection2, policy);
+ verify(connection2).registered(argThat(new
ConnectionPrincipalStatisticsArgumentMatcher(2, 2)));
+
+ vhost.registerConnection(connection3, policy);
+ verify(connection3).registered(argThat(new
ConnectionPrincipalStatisticsArgumentMatcher(1, 1)));
+ }
+
+ @Test
+ public void
testDeregisterConnectionAffectsAuthenticatedPrincipalConnectionCountAndFrequency()
+ {
+ final Principal principal = mockAuthenticatedPrincipal(getTestName());
+ final NoopConnectionEstablishmentPolicy policy = new
NoopConnectionEstablishmentPolicy();
+ final QueueManagingVirtualHost<?> vhost =
createVirtualHost(getTestName());
+
+ final AMQPConnection<?> connection1 = mockAmqpConnection(principal);
+ final AMQPConnection<?> connection2 = mockAmqpConnection(principal);
+
+ vhost.registerConnection(connection1, policy);
+ verify(connection1).registered(argThat(new
ConnectionPrincipalStatisticsArgumentMatcher(1, 1)));
+
+ vhost.deregisterConnection(connection1);
+ vhost.registerConnection(connection2, policy);
+
+ verify(connection2).registered(argThat(new
ConnectionPrincipalStatisticsArgumentMatcher(1, 2)));
+ }
+
+ @Test
public void testStopVirtualhostClosesConnections()
{
QueueManagingVirtualHost<?> vhost = createVirtualHost("sdf");
@@ -775,12 +812,29 @@ public class VirtualHostTest extends UnitTestBase
private AMQPConnection<?> getMockConnection()
{
+ return mockAmqpConnection(mockAuthenticatedPrincipal(getTestName()));
+ }
+
+ private AMQPConnection<?> mockAmqpConnection(final Principal principal)
+ {
AMQPConnection<?> connection = mock(AMQPConnection.class);
+ when(connection.getAuthorizedPrincipal()).thenReturn(principal);
+ final Subject subject =
+ new Subject(true, Collections.singleton(principal),
Collections.emptySet(), Collections.emptySet());
+ when(connection.getSubject()).thenReturn(subject);
final ListenableFuture<Void> listenableFuture =
Futures.immediateFuture(null);
when(connection.closeAsync()).thenReturn(listenableFuture);
+ when(connection.getCreatedTime()).thenReturn(new Date());
return connection;
}
+ private Principal mockAuthenticatedPrincipal(final String principalName)
+ {
+ final Principal principal = mock(Principal.class);
+ when(principal.getName()).thenReturn(principalName);
+ return new AuthenticatedPrincipal(principal);
+ }
+
private QueueManagingVirtualHost<?> createVirtualHost(final String
virtualHostName)
{
return createVirtualHost(virtualHostName, Collections.<String,
Object>emptyMap());
@@ -803,37 +857,6 @@ public class VirtualHostTest extends UnitTestBase
return host;
}
- private AbstractAMQPConnection createMockProtocolConnection(final
VirtualHost<?> virtualHost)
- {
- final AbstractAMQPConnection connection =
mock(AbstractAMQPConnection.class);
- final List<Action<?>> tasks = new ArrayList<>();
- final ArgumentCaptor<Action> deleteTaskCaptor =
ArgumentCaptor.forClass(Action.class);
- Answer answer = new Answer()
- {
- @Override
- public Object answer(final InvocationOnMock invocation)
- {
- return tasks.add(deleteTaskCaptor.getValue());
- }
- };
-
doAnswer(answer).when(connection).addDeleteTask(deleteTaskCaptor.capture());
- when(connection.getAddressSpace()).thenReturn(virtualHost);
- doAnswer(new Answer()
- {
- @Override
- public Object answer(final InvocationOnMock invocation)
- {
- for(Action action : tasks)
- {
- action.performAction(connection);
- }
- return null;
- }
-
}).when(connection).sendConnectionCloseAsync(any(AMQPConnection.CloseReason.class),
anyString());
- when(connection.getRemoteAddressString()).thenReturn("peer:1234");
- return connection;
- }
-
private static ConfiguredObjectRecord matchesRecord(UUID id, String type)
{
return argThat(new MinimalConfiguredObjectRecordMatcher(id, type));
@@ -856,4 +879,25 @@ public class VirtualHostTest extends UnitTestBase
return (_id.equals(rhs.getId()) || _type.equals(rhs.getType()));
}
}
+
+ private static class ConnectionPrincipalStatisticsArgumentMatcher
implements ArgumentMatcher<ConnectionPrincipalStatistics>
+ {
+
+ private final int _expectedConnectionCount;
+ private final int _expectedConnectionFrequency;
+
+ ConnectionPrincipalStatisticsArgumentMatcher(final int
expectedConnectionCount,
+ final int
expectedConnectionFrequency)
+ {
+ _expectedConnectionCount = expectedConnectionCount;
+ _expectedConnectionFrequency = expectedConnectionFrequency;
+ }
+
+ @Override
+ public boolean matches(final ConnectionPrincipalStatistics
connectionPrincipalStatistics)
+ {
+ return connectionPrincipalStatistics.getConnectionFrequency() ==
_expectedConnectionFrequency
+ && connectionPrincipalStatistics.getConnectionCount() ==
_expectedConnectionCount;
+ }
+ }
}
diff --git
a/broker-core/src/test/java/org/apache/qpid/server/virtualhost/ConnectionPrincipalStatisticsCheckingTaskTest.java
b/broker-core/src/test/java/org/apache/qpid/server/virtualhost/ConnectionPrincipalStatisticsCheckingTaskTest.java
new file mode 100644
index 0000000..1764050
--- /dev/null
+++
b/broker-core/src/test/java/org/apache/qpid/server/virtualhost/ConnectionPrincipalStatisticsCheckingTaskTest.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.qpid.server.virtualhost;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.security.AccessController;
+
+import org.junit.Test;
+
+import org.apache.qpid.test.utils.UnitTestBase;
+
+public class ConnectionPrincipalStatisticsCheckingTaskTest extends UnitTestBase
+{
+ @Test
+ public void execute()
+ {
+ final QueueManagingVirtualHost vh =
mock(QueueManagingVirtualHost.class);
+ when(vh.getName()).thenReturn(getTestName());
+ final ConnectionPrincipalStatisticsRegistry registry =
mock(ConnectionPrincipalStatisticsRegistry.class);
+ ConnectionPrincipalStatisticsCheckingTask task =
+ new ConnectionPrincipalStatisticsCheckingTask(vh,
AccessController.getContext(), registry);
+
+ task.execute();
+
+ verify(registry).reevaluateConnectionStatistics();
+ }
+}
diff --git
a/broker-core/src/test/java/org/apache/qpid/server/virtualhost/connection/ConnectionPrincipalStatisticsImplTest.java
b/broker-core/src/test/java/org/apache/qpid/server/virtualhost/connection/ConnectionPrincipalStatisticsImplTest.java
new file mode 100644
index 0000000..fd08684
--- /dev/null
+++
b/broker-core/src/test/java/org/apache/qpid/server/virtualhost/connection/ConnectionPrincipalStatisticsImplTest.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.qpid.server.virtualhost.connection;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Test;
+
+import org.apache.qpid.server.virtualhost.ConnectionPrincipalStatistics;
+import org.apache.qpid.test.utils.UnitTestBase;
+
+public class ConnectionPrincipalStatisticsImplTest extends UnitTestBase
+{
+
+ @Test
+ public void getOpenConnectionCount()
+ {
+ final ConnectionPrincipalStatistics stats =
+ new ConnectionPrincipalStatisticsImpl(1,
Collections.singletonList(System.currentTimeMillis()));
+
+ assertEquals(1, stats.getConnectionCount());
+ }
+
+ @Test
+ public void getOpenConnectionFrequency()
+ {
+ final long connectionCreatedTime = System.currentTimeMillis();
+ final ConnectionPrincipalStatistics stats =
+ new ConnectionPrincipalStatisticsImpl(1,
+
Arrays.asList(connectionCreatedTime - 1000, connectionCreatedTime));
+ assertEquals(2, stats.getConnectionFrequency());
+ }
+
+ @Test
+ public void getLatestConnectionCreatedTimes()
+ {
+ final long connectionCreatedTime = System.currentTimeMillis();
+ final List<Long> connectionCreatedTimes =
Arrays.asList(connectionCreatedTime - 1000, connectionCreatedTime);
+ final ConnectionPrincipalStatisticsImpl stats = new
ConnectionPrincipalStatisticsImpl(1, connectionCreatedTimes);
+ assertEquals(connectionCreatedTimes,
stats.getLatestConnectionCreatedTimes());
+ }
+
+ @Test
+ public void equals()
+ {
+ final long connectionCreatedTime = System.currentTimeMillis();
+ final ConnectionPrincipalStatistics stats1 =
+ new ConnectionPrincipalStatisticsImpl(1,
Collections.singletonList(connectionCreatedTime));
+ final ConnectionPrincipalStatistics stats2 =
+ new ConnectionPrincipalStatisticsImpl(1,
Collections.singletonList(connectionCreatedTime));
+ assertEquals(stats1, stats2);
+
+ final long connectionCreatedTime2 = System.currentTimeMillis();
+ final ConnectionPrincipalStatistics stats3 =
+ new ConnectionPrincipalStatisticsImpl(2,
Arrays.asList(connectionCreatedTime, connectionCreatedTime2));
+
+ assertNotEquals(stats2, stats3);
+ assertNotEquals(stats1, stats3);
+ }
+
+ @Test
+ public void testHashCode()
+ {
+ final long connectionCreatedTime = System.currentTimeMillis();
+ final ConnectionPrincipalStatistics stats1 =
+ new ConnectionPrincipalStatisticsImpl(1,
Collections.singletonList(connectionCreatedTime));
+ final ConnectionPrincipalStatistics stats2 =
+ new ConnectionPrincipalStatisticsImpl(1,
Collections.singletonList(connectionCreatedTime));
+ assertEquals(stats1.hashCode(), stats2.hashCode());
+
+ final long connectionCreatedTime2 = System.currentTimeMillis();
+ final ConnectionPrincipalStatistics stats3 =
+ new ConnectionPrincipalStatisticsImpl(2,
Arrays.asList(connectionCreatedTime, connectionCreatedTime2));
+
+ assertNotEquals(stats2.hashCode(), stats3.hashCode());
+ assertNotEquals(stats1.hashCode(), stats3.hashCode());
+ }
+}
diff --git
a/broker-core/src/test/java/org/apache/qpid/server/virtualhost/connection/ConnectionPrincipalStatisticsRegistryImplTest.java
b/broker-core/src/test/java/org/apache/qpid/server/virtualhost/connection/ConnectionPrincipalStatisticsRegistryImplTest.java
new file mode 100644
index 0000000..fa7b294
--- /dev/null
+++
b/broker-core/src/test/java/org/apache/qpid/server/virtualhost/connection/ConnectionPrincipalStatisticsRegistryImplTest.java
@@ -0,0 +1,136 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.qpid.server.virtualhost.connection;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.security.Principal;
+import java.time.Duration;
+import java.util.Collections;
+import java.util.Date;
+
+import javax.security.auth.Subject;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.apache.qpid.server.security.auth.AuthenticatedPrincipal;
+import org.apache.qpid.server.transport.AMQPConnection;
+import org.apache.qpid.server.virtualhost.ConnectionStatisticsRegistrySettings;
+import org.apache.qpid.test.utils.UnitTestBase;
+
+public class ConnectionPrincipalStatisticsRegistryImplTest extends UnitTestBase
+{
+ private static final Duration CONNECTION_FREQUENCY_PERIOD =
Duration.ofMillis(5000);
+ private ConnectionPrincipalStatisticsRegistryImpl _statisticsRegistry;
+ private AuthenticatedPrincipal _authorizedPrincipal;
+ private ConnectionStatisticsRegistrySettings _settings;
+
+ @Before
+ public void setUp()
+ {
+ _settings = mock(ConnectionStatisticsRegistrySettings.class);
+
when(_settings.getConnectionFrequencyPeriod()).thenReturn(CONNECTION_FREQUENCY_PERIOD);
+ _statisticsRegistry = new
ConnectionPrincipalStatisticsRegistryImpl(_settings);
+ _authorizedPrincipal = new
AuthenticatedPrincipal(mock(Principal.class));
+ }
+
+ @Test
+ public void onConnectionOpen()
+ {
+ final AMQPConnection connection = mockConnection();
+
+ _statisticsRegistry.connectionOpened(connection);
+
+
assertThat(_statisticsRegistry.getConnectionCount(_authorizedPrincipal),
is(equalTo(1)));
+
assertThat(_statisticsRegistry.getConnectionCount(_authorizedPrincipal),
is(equalTo(1)));
+ }
+
+ @Test
+ public void onConnectionClose()
+ {
+ final AMQPConnection connection1 = mockConnection();
+
+ _statisticsRegistry.connectionOpened(connection1);
+ _statisticsRegistry.connectionClosed(connection1);
+
+ final AMQPConnection connection2 = mockConnection();
+ _statisticsRegistry.connectionOpened(connection2);
+
+
assertThat(_statisticsRegistry.getConnectionCount(_authorizedPrincipal),
is(equalTo(1)));
+
assertThat(_statisticsRegistry.getConnectionFrequency(_authorizedPrincipal),
is(equalTo(2)));
+ }
+
+ @Test
+ public void reevaluateConnectionPrincipalStatistics() throws
InterruptedException
+ {
+ final AMQPConnection connection1 = mockConnection();
+
+ _statisticsRegistry.connectionOpened(connection1);
+
assertThat(_statisticsRegistry.getConnectionFrequency(_authorizedPrincipal),
is(equalTo(1)));
+
+ _statisticsRegistry.reevaluateConnectionStatistics();
+
assertThat(_statisticsRegistry.getConnectionFrequency(_authorizedPrincipal),
is(equalTo(1)));
+
+
when(_settings.getConnectionFrequencyPeriod()).thenReturn(Duration.ofMillis(1));
+ Thread.sleep(_settings.getConnectionFrequencyPeriod().toMillis() + 1);
+
+ _statisticsRegistry.reevaluateConnectionStatistics();
+
assertThat(_statisticsRegistry.getConnectionCount(_authorizedPrincipal),
is(equalTo(1)));
+
assertThat(_statisticsRegistry.getConnectionFrequency(_authorizedPrincipal),
is(equalTo(0)));
+ }
+
+ @Test
+ public void getConnectionFrequencyAfterExpirationOfFrequencyPeriod()
throws InterruptedException
+ {
+ final AMQPConnection connection1 = mockConnection();
+ _statisticsRegistry.connectionOpened(connection1);
+
+
assertThat(_statisticsRegistry.getConnectionFrequency(_authorizedPrincipal),
is(equalTo(1)));
+
assertThat(_statisticsRegistry.getConnectionCount(_authorizedPrincipal),
is(equalTo(1)));
+
+
when(_settings.getConnectionFrequencyPeriod()).thenReturn(Duration.ofMillis(1));
+ Thread.sleep(_settings.getConnectionFrequencyPeriod().toMillis() + 1);
+
+ final AMQPConnection connection2 = mockConnection();
+ _statisticsRegistry.connectionOpened(connection2);
+
+
assertThat(_statisticsRegistry.getConnectionCount(_authorizedPrincipal),
is(equalTo(2)));
+
assertThat(_statisticsRegistry.getConnectionFrequency(_authorizedPrincipal),
is(equalTo(1)));
+ }
+
+ private AMQPConnection mockConnection()
+ {
+ final Subject subject = new Subject(true,
+
Collections.singleton(_authorizedPrincipal),
+ Collections.emptySet(),
+ Collections.emptySet());
+
+ final AMQPConnection connection = mock(AMQPConnection.class);
+
when(connection.getAuthorizedPrincipal()).thenReturn(_authorizedPrincipal);
+ when(connection.getSubject()).thenReturn(subject);
+ when(connection.getCreatedTime()).thenReturn(new Date());
+ return connection;
+ }
+}
diff --git
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/AclAction.java
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/AclAction.java
index 78866f5..89a09bc 100644
---
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/AclAction.java
+++
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/AclAction.java
@@ -18,21 +18,18 @@
*/
package org.apache.qpid.server.security.access.config;
-import java.util.HashMap;
import java.util.Map;
-import java.util.Set;
-
-import org.apache.qpid.server.security.access.firewall.FirewallRule;
+import java.util.Objects;
public class AclAction
{
private Action _action;
- private FirewallRule _firewallRule;
+ private AclRulePredicates _predicates;
public AclAction(LegacyOperation operation, ObjectType object,
AclRulePredicates predicates)
{
_action = new Action(operation, object,
predicates.getObjectProperties());
- _firewallRule = predicates.getFirewallRule();
+ _predicates = predicates;
}
public AclAction(LegacyOperation operation)
@@ -45,9 +42,9 @@ public class AclAction
_action = new Action(operation, object, properties);
}
- public FirewallRule getFirewallRule()
+ public DynamicRule getDynamicRule()
{
- return _firewallRule;
+ return _predicates == null ? null : _predicates.getDynamicRule();
}
public Action getAction()
@@ -78,9 +75,7 @@ public class AclAction
{
return false;
}
- return !(getFirewallRule() != null
- ? !getFirewallRule().equals(aclAction.getFirewallRule())
- : aclAction.getFirewallRule() != null);
+ return Objects.equals(_predicates, aclAction._predicates);
}
@@ -88,7 +83,7 @@ public class AclAction
public int hashCode()
{
int result = getAction() != null ? getAction().hashCode() : 0;
- result = 31 * result + (getFirewallRule() != null ?
getFirewallRule().hashCode() : 0);
+ result = 31 * result + (_predicates != null ? _predicates.hashCode() :
0);
return result;
}
@@ -97,24 +92,13 @@ public class AclAction
{
return "AclAction[" +
"action=" + _action +
- ", firewallRule=" + _firewallRule +
+ ", predicates=" + _predicates +
']';
}
public Map<ObjectProperties.Property, String> getAttributes()
{
- final ObjectProperties properties = _action.getProperties();
- final Map<ObjectProperties.Property, String> attributes = new
HashMap<>(properties.asPropertyMap());
- final Set<String> attributeNames = properties.getAttributeNames();
- if (attributeNames != null && !attributeNames.isEmpty())
- {
- attributes.put(ObjectProperties.Property.ATTRIBUTES,
String.join(",", attributeNames));
- }
- final FirewallRule firewallRule = getFirewallRule();
- if (firewallRule != null)
- {
- attributes.put(firewallRule.getPropertyName(),
firewallRule.getPropertyValue());
- }
- return attributes;
+ return _predicates.getParsedProperties();
}
+
}
diff --git
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/AclRulePredicates.java
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/AclRulePredicates.java
index 5b5b73d..a172b01 100644
---
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/AclRulePredicates.java
+++
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/AclRulePredicates.java
@@ -18,19 +18,23 @@
*/
package org.apache.qpid.server.security.access.config;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.Map;
+import java.util.stream.Collectors;
import com.google.common.collect.Sets;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.qpid.server.security.access.config.ObjectProperties.Property;
-import org.apache.qpid.server.security.access.firewall.FirewallRule;
+import
org.apache.qpid.server.security.access.config.connection.ConnectionPrincipalFrequencyLimitRule;
+import
org.apache.qpid.server.security.access.config.connection.ConnectionPrincipalLimitRule;
import org.apache.qpid.server.security.access.firewall.FirewallRuleFactory;
/**
* Represents the predicates on an ACL rule by combining predicates relating
to the object being operated on
- * (e.g. name=foo) with firewall rules.
+ * (e.g. name=foo) with dynamic rules.
*/
public class AclRulePredicates
{
@@ -38,11 +42,10 @@ public class AclRulePredicates
private static final String SEPARATOR = ",";
- private ObjectProperties _properties = new ObjectProperties();
-
- private FirewallRule _firewallRule;
-
- private FirewallRuleFactory _firewallRuleFactory = new
FirewallRuleFactory();
+ private final ObjectProperties _properties = new ObjectProperties();
+ private final Map<Property, String> _parsedProperties = new HashMap<>();
+ private volatile DynamicRule _dynamicRule = s -> true;
+ private volatile FirewallRuleFactory _firewallRuleFactory = new
FirewallRuleFactory();
public AclRulePredicates()
{
@@ -50,9 +53,9 @@ public class AclRulePredicates
public AclRulePredicates(Map<Property, String> values)
{
- if(values != null)
+ if (values != null)
{
- for(Map.Entry<Property, String> entry : values.entrySet())
+ for (Map.Entry<Property, String> entry : values.entrySet())
{
addPropertyValue(entry.getKey(), entry.getValue());
}
@@ -64,64 +67,129 @@ public class AclRulePredicates
ObjectProperties.Property property =
ObjectProperties.Property.parse(key);
addPropertyValue(property, value);
-
- LOGGER.debug("Parsed {} with value {}", property, value);
+ _parsedProperties.put(property, value);
+ LOGGER.debug("Parsed {} with value {}", property, value);
}
private void addPropertyValue(final Property property, final String value)
{
- if(property == Property.FROM_HOSTNAME)
+ final DynamicRule dynamicRule = _dynamicRule;
+ if (property == Property.FROM_HOSTNAME)
{
- checkFirewallRuleNotAlreadyDefined(property.name(), value);
- _firewallRule =
_firewallRuleFactory.createForHostname(value.split(SEPARATOR));
+ checkFirewallRuleNotAlreadyDefined(property, value,
Property.FROM_NETWORK);
+ _dynamicRule =
dynamicRule.and(_firewallRuleFactory.createForHostname(value.split(SEPARATOR)));
}
- else if(property == Property.FROM_NETWORK)
+ else if (property == Property.FROM_NETWORK)
{
- checkFirewallRuleNotAlreadyDefined(property.name(), value);
- _firewallRule =
_firewallRuleFactory.createForNetwork(value.split(SEPARATOR));
+ checkFirewallRuleNotAlreadyDefined(property, value,
Property.FROM_HOSTNAME);
+ _dynamicRule =
dynamicRule.and(_firewallRuleFactory.createForNetwork(value.split(SEPARATOR)));
}
else if (property == Property.ATTRIBUTES)
{
_properties.setAttributeNames(Sets.newHashSet((value.split(SEPARATOR))));
}
+ else if (property == Property.CONNECTION_LIMIT)
+ {
+ checkPropertyAlreadyDefined(property);
+ final int limit = getLimit(property, value);
+ _dynamicRule = dynamicRule.and(new
ConnectionPrincipalLimitRule(limit));
+ }
+ else if (property == Property.CONNECTION_FREQUENCY_LIMIT)
+ {
+ checkPropertyAlreadyDefined(property);
+ final int limit = getLimit(property, value);
+ _dynamicRule = dynamicRule.and(new
ConnectionPrincipalFrequencyLimitRule(limit));
+ }
else
{
_properties.put(property, value);
}
}
- private void checkFirewallRuleNotAlreadyDefined(String key, String value)
+ private int getLimit(final Property property, final String value)
+ {
+ int limit;
+ try
+ {
+ limit = Integer.parseInt(value);
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException(String.format("Property '%s' value
'%s' is not integer", property, value));
+ }
+ return limit;
+ }
+
+ private void checkFirewallRuleNotAlreadyDefined(Property property, String
value, Property... exclusiveProperty)
+ {
+ checkPropertyAlreadyDefined(property);
+ for (Property p : exclusiveProperty)
+ {
+ if (_parsedProperties.containsKey(p))
+ {
+ throw new IllegalStateException(
+ String.format("Cannot parse '%s=%s' because property
'%s' has already been defined",
+ property.toString().toLowerCase(),
+ value,
+ p));
+ }
+ }
+ }
+
+ private void checkPropertyAlreadyDefined(Property property)
+ {
+ if (_parsedProperties.containsKey(property))
+ {
+ throw new IllegalStateException(String.format("Property '%s' has
already been defined", property.toString().toLowerCase()));
+ }
+ }
+
+ @Override
+ public boolean equals(final Object o)
{
- if(_firewallRule != null)
+ if (this == o)
{
- throw new IllegalStateException(
- "Cannot parse " + key + "=" + value
- + " because firewall rule " + _firewallRule + " has
already been defined");
+ return true;
}
+ if (o == null || getClass() != o.getClass())
+ {
+ return false;
+ }
+
+ final AclRulePredicates that = (AclRulePredicates) o;
+
+ return _parsedProperties.equals(that._parsedProperties);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return _parsedProperties.hashCode();
}
@Override
public String toString()
{
- return "AclRulePredicates[" +
- "properties=" + _properties +
- ", firewallRule=" + _firewallRule +
- ']';
+ return String.format("AclRulePredicates[%s]",
+ _parsedProperties.entrySet()
+ .stream()
+ .map(e -> e.getKey() + "=" +
e.getValue())
+ .collect(Collectors.joining("
")));
}
- public FirewallRule getFirewallRule()
+ DynamicRule getDynamicRule()
{
- return _firewallRule;
+ return _dynamicRule;
}
- public ObjectProperties getObjectProperties()
+ ObjectProperties getObjectProperties()
{
return _properties;
}
- public ObjectProperties getFirewallProperties()
+ Map<Property, String> getParsedProperties()
{
- return _properties;
+ return Collections.unmodifiableMap(_parsedProperties);
}
void setFirewallRuleFactory(FirewallRuleFactory firewallRuleFactory)
diff --git
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/ClientAction.java
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/ClientAction.java
index b18bd2a..23f0605 100644
---
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/ClientAction.java
+++
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/ClientAction.java
@@ -18,9 +18,7 @@
*/
package org.apache.qpid.server.security.access.config;
-import java.net.InetAddress;
-
-import org.apache.qpid.server.security.access.firewall.FirewallRule;
+import javax.security.auth.Subject;
/**
* I represent an {@link Action} taken by a client from a known address. The
address is used to
@@ -30,7 +28,7 @@ public class ClientAction
{
private Action _clientAction;
- public ClientAction(Action clientAction)
+ ClientAction(Action clientAction)
{
_clientAction = clientAction;
}
@@ -40,23 +38,15 @@ public class ClientAction
_clientAction = new Action(operation, objectType, properties);
}
- public boolean matches(AclAction ruleAction, InetAddress addressOfClient)
+ public boolean matches(AclAction ruleAction, final Subject subject)
{
return _clientAction.matches(ruleAction.getAction())
- && addressOfClientMatches(ruleAction, addressOfClient);
+ && dynamicMatches(ruleAction.getDynamicRule(), subject);
}
- private boolean addressOfClientMatches(AclAction ruleAction, InetAddress
addressOfClient)
+ private boolean dynamicMatches(final DynamicRule dynamicRule, final
Subject subject)
{
- FirewallRule firewallRule = ruleAction.getFirewallRule();
- if(firewallRule == null || addressOfClient == null)
- {
- return true;
- }
- else
- {
- return firewallRule.matches(addressOfClient);
- }
+ return dynamicRule == null || dynamicRule.matches(subject);
}
public LegacyOperation getOperation()
diff --git
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/FirewallRule.java
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/DynamicRule.java
similarity index 53%
copy from
broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/FirewallRule.java
copy to
broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/DynamicRule.java
index 72d8d69..ede7d13 100644
---
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/FirewallRule.java
+++
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/DynamicRule.java
@@ -16,17 +16,34 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.qpid.server.security.access.firewall;
-import java.net.InetAddress;
+package org.apache.qpid.server.security.access.config;
-import org.apache.qpid.server.security.access.config.ObjectProperties;
+import java.util.Objects;
-public interface FirewallRule
+import javax.security.auth.Subject;
+
+public interface DynamicRule
{
- boolean matches(InetAddress addressOfClient);
+ boolean matches(Subject subject);
+
+ default DynamicRule and(DynamicRule other)
+ {
+ Objects.requireNonNull(other);
- ObjectProperties.Property getPropertyName();
+ return new DynamicRule()
+ {
+ @Override
+ public boolean matches(final Subject subject)
+ {
+ return DynamicRule.this.matches(subject) &&
other.matches(subject);
+ }
- String getPropertyValue();
+ @Override
+ public String toString()
+ {
+ return String.format("%s and %s", DynamicRule.this.toString(),
other.toString());
+ }
+ };
+ }
}
diff --git
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/ObjectProperties.java
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/ObjectProperties.java
index deec6f7..a3bc747 100644
---
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/ObjectProperties.java
+++
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/ObjectProperties.java
@@ -64,7 +64,9 @@ public class ObjectProperties
VIRTUALHOST_NAME,
METHOD_NAME,
ATTRIBUTES,
- CREATED_BY;
+ CREATED_BY,
+ CONNECTION_LIMIT,
+ CONNECTION_FREQUENCY_LIMIT;
private static final Map<String, Property> _canonicalNameToPropertyMap
= new HashMap<String, ObjectProperties.Property>();
diff --git
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleBasedAccessControl.java
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleBasedAccessControl.java
index 44fa558..07cb206 100644
---
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleBasedAccessControl.java
+++
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleBasedAccessControl.java
@@ -20,21 +20,17 @@
*/
package org.apache.qpid.server.security.access.config;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.SocketAddress;
import java.security.AccessController;
import java.util.Collections;
import java.util.Map;
-import java.util.Set;
import javax.security.auth.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.apache.qpid.server.connection.ConnectionPrincipal;
-import org.apache.qpid.server.model.*;
+import org.apache.qpid.server.model.Model;
+import org.apache.qpid.server.model.PermissionedObject;
import org.apache.qpid.server.security.AccessControl;
import org.apache.qpid.server.security.Result;
import org.apache.qpid.server.security.access.Operation;
@@ -78,7 +74,6 @@ public class RuleBasedAccessControl implements
AccessControl<CachingSecurityToke
@Override
public Result authorise(LegacyOperation operation, ObjectType objectType,
ObjectProperties properties)
{
- InetAddress addressOfClient = null;
final Subject subject =
Subject.getSubject(AccessController.getContext());
// Abstain if there is no subject/principal associated with this thread
@@ -87,30 +82,19 @@ public class RuleBasedAccessControl implements
AccessControl<CachingSecurityToke
return Result.DEFER;
}
- Set<ConnectionPrincipal> principals =
subject.getPrincipals(ConnectionPrincipal.class);
- if(!principals.isEmpty())
- {
- SocketAddress address =
principals.iterator().next().getConnection().getRemoteSocketAddress();
- if(address instanceof InetSocketAddress)
- {
- addressOfClient = ((InetSocketAddress) address).getAddress();
- }
- }
if(LOGGER.isDebugEnabled())
{
- LOGGER.debug("Checking " + operation + " " + objectType + " " +
- (addressOfClient == null ? "" : addressOfClient));
+ LOGGER.debug("Checking " + operation + " " + objectType );
}
try
{
- return _ruleSet.check(subject, operation, objectType, properties,
addressOfClient);
+ return _ruleSet.check(subject, operation, objectType, properties);
}
catch(Exception e)
{
- LOGGER.error("Unable to check " + operation + " " + objectType + "
"
- + (addressOfClient == null ? "" : addressOfClient),
e);
+ LOGGER.error("Unable to check " + operation + " " + objectType ,
e);
return Result.DENIED;
}
}
diff --git
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleSet.java
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleSet.java
index 151e1ac..6b3371c 100644
---
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleSet.java
+++
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleSet.java
@@ -18,7 +18,6 @@
*/
package org.apache.qpid.server.security.access.config;
-import java.net.InetAddress;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Collection;
@@ -123,16 +122,6 @@ public class RuleSet implements EventLoggerProvider
}
/**
- * Checks for the case when the client's address is not known.
- *
- * @see #check(Subject, LegacyOperation, ObjectType, ObjectProperties,
InetAddress)
- */
- public Result check(Subject subject, LegacyOperation operation, ObjectType
objectType, ObjectProperties properties)
- {
- return check(subject, operation, objectType, properties, null);
- }
-
- /**
* Check the authorisation granted to a particular identity for an
operation on an object type with
* specific properties.
*
@@ -141,7 +130,10 @@ public class RuleSet implements EventLoggerProvider
* the first match found, or denies access if there are no matching rules.
Normally, it would be expected
* to have a default deny or allow rule at the end of an access
configuration however.
*/
- public Result check(Subject subject, LegacyOperation operation, ObjectType
objectType, ObjectProperties properties, InetAddress addressOfClient)
+ public Result check(Subject subject,
+ LegacyOperation operation,
+ ObjectType objectType,
+ ObjectProperties properties)
{
ClientAction action = new ClientAction(operation, objectType,
properties);
@@ -186,7 +178,7 @@ public class RuleSet implements EventLoggerProvider
{
LOGGER.debug("Checking against rule: {}", rule);
- if (action.matches(rule.getAclAction(), addressOfClient))
+ if (action.matches(rule.getAclAction(), subject))
{
RuleOutcome ruleOutcome = rule.getRuleOutcome();
LOGGER.debug("Action matches. Result: {}", ruleOutcome);
diff --git
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/FirewallRule.java
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/connection/ConnectionPrincipalFrequencyLimitRule.java
similarity index 53%
copy from
broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/FirewallRule.java
copy to
broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/connection/ConnectionPrincipalFrequencyLimitRule.java
index 72d8d69..8f4e7e4 100644
---
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/FirewallRule.java
+++
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/connection/ConnectionPrincipalFrequencyLimitRule.java
@@ -16,17 +16,30 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.qpid.server.security.access.firewall;
-import java.net.InetAddress;
+package org.apache.qpid.server.security.access.config.connection;
import org.apache.qpid.server.security.access.config.ObjectProperties;
+import org.apache.qpid.server.transport.AMQPConnection;
-public interface FirewallRule
+public class ConnectionPrincipalFrequencyLimitRule extends
ConnectionPrincipalStatisticsRule
{
- boolean matches(InetAddress addressOfClient);
+ public ConnectionPrincipalFrequencyLimitRule(final int limit)
+ {
+ super(limit);
+ }
- ObjectProperties.Property getPropertyName();
+ @Override
+ boolean matches(final AMQPConnection<?> connection)
+ {
+ return connection.getAuthenticatedPrincipalConnectionFrequency() <=
getLimit();
+ }
- String getPropertyValue();
+ @Override
+ public String toString()
+ {
+ return String.format("ConnectionPrincipalFrequencyLimitRule{%s=%d}",
+
ObjectProperties.Property.CONNECTION_FREQUENCY_LIMIT.name().toLowerCase(),
+ getLimit());
+ }
}
diff --git
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/FirewallRule.java
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/connection/ConnectionPrincipalLimitRule.java
similarity index 55%
copy from
broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/FirewallRule.java
copy to
broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/connection/ConnectionPrincipalLimitRule.java
index 72d8d69..94a93f5 100644
---
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/FirewallRule.java
+++
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/connection/ConnectionPrincipalLimitRule.java
@@ -16,17 +16,29 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.qpid.server.security.access.firewall;
-import java.net.InetAddress;
+package org.apache.qpid.server.security.access.config.connection;
import org.apache.qpid.server.security.access.config.ObjectProperties;
+import org.apache.qpid.server.transport.AMQPConnection;
-public interface FirewallRule
+public class ConnectionPrincipalLimitRule extends
ConnectionPrincipalStatisticsRule
{
- boolean matches(InetAddress addressOfClient);
+ public ConnectionPrincipalLimitRule(final int limit)
+ {
+ super(limit);
+ }
- ObjectProperties.Property getPropertyName();
+ protected boolean matches(final AMQPConnection<?> connection)
+ {
+ return connection.getAuthenticatedPrincipalConnectionCount() <=
getLimit();
+ }
- String getPropertyValue();
+ @Override
+ public String toString()
+ {
+ return String.format("ConnectionPrincipalLimitRule{%s=%d}",
+
ObjectProperties.Property.CONNECTION_LIMIT.name().toLowerCase(),
+ getLimit());
+ }
}
diff --git
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/connection/ConnectionPrincipalStatisticsRule.java
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/connection/ConnectionPrincipalStatisticsRule.java
new file mode 100644
index 0000000..466eb9f
--- /dev/null
+++
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/connection/ConnectionPrincipalStatisticsRule.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.qpid.server.security.access.config.connection;
+
+import javax.security.auth.Subject;
+
+import org.apache.qpid.server.connection.ConnectionPrincipal;
+import org.apache.qpid.server.security.access.config.DynamicRule;
+import org.apache.qpid.server.transport.AMQPConnection;
+
+public abstract class ConnectionPrincipalStatisticsRule implements DynamicRule
+{
+ private final int _limit;
+
+ ConnectionPrincipalStatisticsRule(final int limit)
+ {
+ _limit = limit;
+ }
+
+ int getLimit()
+ {
+ return _limit;
+ }
+
+ @Override
+ public boolean matches(final Subject subject)
+ {
+ AMQPConnection<?> connection = getConnection(subject);
+ if (connection != null)
+ {
+ return matches(connection);
+ }
+ return false;
+ }
+
+ abstract boolean matches(final AMQPConnection<?> connection);
+
+ private AMQPConnection<?> getConnection(final Subject subject)
+ {
+ if (subject != null)
+ {
+ final ConnectionPrincipal principal =
subject.getPrincipals(ConnectionPrincipal.class)
+ .stream()
+ .findFirst()
+ .orElse(null);
+ if (principal != null)
+ {
+ return principal.getConnection();
+ }
+ }
+ return null;
+ }
+}
diff --git
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/FirewallRule.java
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/FirewallRule.java
index 72d8d69..d627655 100644
---
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/FirewallRule.java
+++
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/FirewallRule.java
@@ -19,14 +19,43 @@
package org.apache.qpid.server.security.access.firewall;
import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.util.Set;
+import javax.security.auth.Subject;
+
+import org.apache.qpid.server.connection.ConnectionPrincipal;
+import org.apache.qpid.server.security.access.config.DynamicRule;
import org.apache.qpid.server.security.access.config.ObjectProperties;
-public interface FirewallRule
+public abstract class FirewallRule implements DynamicRule
{
- boolean matches(InetAddress addressOfClient);
+ @Override
+ public boolean matches(final Subject subject)
+ {
+ final InetAddress addressOfClient = getAddressOfClient(subject);
+ if (addressOfClient == null)
+ {
+ return true;
+ }
+ return matches(addressOfClient);
+ }
+
+ private InetAddress getAddressOfClient(final Subject subject)
+ {
+ final Set<ConnectionPrincipal> principals =
subject.getPrincipals(ConnectionPrincipal.class);
+ if(!principals.isEmpty())
+ {
+ final SocketAddress address =
principals.iterator().next().getConnection().getRemoteSocketAddress();
+ if(address instanceof InetSocketAddress)
+ {
+ return ((InetSocketAddress) address).getAddress();
+ }
+ }
+ return null;
+ }
- ObjectProperties.Property getPropertyName();
+ protected abstract boolean matches(InetAddress addressOfClient);
- String getPropertyValue();
}
diff --git
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/HostnameFirewallRule.java
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/HostnameFirewallRule.java
index dfc0e22..ac95a15 100644
---
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/HostnameFirewallRule.java
+++
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/HostnameFirewallRule.java
@@ -30,9 +30,7 @@ import java.util.regex.Pattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.apache.qpid.server.security.access.config.ObjectProperties;
-
-public class HostnameFirewallRule implements FirewallRule
+public class HostnameFirewallRule extends FirewallRule
{
private static final Logger LOGGER =
LoggerFactory.getLogger(HostnameFirewallRule.class);
@@ -58,7 +56,7 @@ public class HostnameFirewallRule implements FirewallRule
}
@Override
- public boolean matches(InetAddress remote)
+ protected boolean matches(InetAddress remote)
{
String hostname = getHostname(remote);
if (hostname == null)
@@ -84,23 +82,11 @@ public class HostnameFirewallRule implements FirewallRule
return false;
}
- @Override
- public ObjectProperties.Property getPropertyName()
- {
- return ObjectProperties.Property.FROM_HOSTNAME;
- }
-
- @Override
- public String getPropertyValue()
- {
- return String.join(",", _hostnames);
- }
-
/**
* @param remote
* the InetAddress to look up
* @return the hostname, null if not found, takes longer than
- * {@value #DNS_LOOKUP} to find or otherwise fails
+ * {@link #DNS_LOOKUP} to find or otherwise fails
*/
private String getHostname(final InetAddress remote) throws
AccessControlFirewallException
{
diff --git
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/NetworkFirewallRule.java
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/NetworkFirewallRule.java
index de7511f..e4d41e8 100644
---
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/NetworkFirewallRule.java
+++
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/NetworkFirewallRule.java
@@ -25,17 +25,13 @@ import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.apache.qpid.server.security.access.config.ObjectProperties;
-
-public class NetworkFirewallRule implements FirewallRule
+public class NetworkFirewallRule extends FirewallRule
{
private static final Logger LOGGER =
LoggerFactory.getLogger(NetworkFirewallRule.class);
- private final String _originalNetworks;
private List<InetNetwork> _networks;
public NetworkFirewallRule(String... networks)
{
- _originalNetworks = String.join(",", networks);
_networks = new ArrayList<InetNetwork>();
for (int i = 0; i < networks.length; i++)
{
@@ -58,7 +54,7 @@ public class NetworkFirewallRule implements FirewallRule
}
@Override
- public boolean matches(InetAddress ip)
+ protected boolean matches(InetAddress ip)
{
for (InetNetwork network : _networks)
{
@@ -107,16 +103,4 @@ public class NetworkFirewallRule implements FirewallRule
"networks=" + _networks +
']';
}
-
- @Override
- public ObjectProperties.Property getPropertyName()
- {
- return ObjectProperties.Property.FROM_NETWORK;
- }
-
- @Override
- public String getPropertyValue()
- {
- return _originalNetworks;
- }
}
diff --git
a/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/AclActionTest.java
b/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/AclActionTest.java
index d2f4e7c..5e53f0b 100644
---
a/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/AclActionTest.java
+++
b/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/AclActionTest.java
@@ -89,7 +89,7 @@ public class AclActionTest extends UnitTestBase
private AclRulePredicates createAclRulePredicates()
{
AclRulePredicates predicates = mock(AclRulePredicates.class);
-
when(predicates.getFirewallRule()).thenReturn(mock(FirewallRule.class));
+ when(predicates.getDynamicRule()).thenReturn(mock(FirewallRule.class));
when(predicates.getObjectProperties()).thenReturn(mock(ObjectProperties.class));
return predicates;
}
diff --git
a/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/AclRulePredicatesTest.java
b/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/AclRulePredicatesTest.java
index 0cd767b..b40fe8d 100644
---
a/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/AclRulePredicatesTest.java
+++
b/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/AclRulePredicatesTest.java
@@ -20,16 +20,21 @@ package org.apache.qpid.server.security.access.config;
import static
org.apache.qpid.server.security.access.config.ObjectProperties.Property.ATTRIBUTES;
import static
org.apache.qpid.server.security.access.config.ObjectProperties.Property.CLASS;
+import static
org.apache.qpid.server.security.access.config.ObjectProperties.Property.CONNECTION_LIMIT;
import static
org.apache.qpid.server.security.access.config.ObjectProperties.Property.FROM_HOSTNAME;
import static
org.apache.qpid.server.security.access.config.ObjectProperties.Property.FROM_NETWORK;
import static
org.apache.qpid.server.security.access.config.ObjectProperties.Property.NAME;
+import static org.hamcrest.CoreMatchers.allOf;
+import static org.hamcrest.collection.IsMapContaining.hasEntry;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import java.util.Map;
import java.util.Set;
import org.junit.Before;
@@ -114,4 +119,18 @@ public class AclRulePredicatesTest extends UnitTestBase
_aclRulePredicates.getObjectProperties().getAttributeNames());
}
+
+ @Test
+ public void testGetParsedProperties()
+ {
+ _aclRulePredicates.parse(ATTRIBUTES.name(), "attribute1,attribute2");
+ _aclRulePredicates.parse(FROM_NETWORK.name(), "network1,network2");
+ _aclRulePredicates.parse(CONNECTION_LIMIT.name(), "20");
+
+ final Map<ObjectProperties.Property, String> properties =
_aclRulePredicates.getParsedProperties();
+
+ assertThat(properties, allOf(hasEntry(ATTRIBUTES,
"attribute1,attribute2"),
+ hasEntry(FROM_NETWORK,
"network1,network2"),
+ hasEntry(CONNECTION_LIMIT, "20")));
+ }
}
diff --git
a/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/ClientActionTest.java
b/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/ClientActionTest.java
index 682aae2..bb5479c 100644
---
a/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/ClientActionTest.java
+++
b/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/ClientActionTest.java
@@ -26,68 +26,120 @@ import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.security.Principal;
+import java.util.Collections;
+import java.util.Set;
+import javax.security.auth.Subject;
+
+import org.junit.Before;
import org.junit.Test;
+import org.apache.qpid.server.connection.ConnectionPrincipal;
import org.apache.qpid.server.security.access.firewall.FirewallRule;
+import org.apache.qpid.server.transport.AMQPConnection;
+import org.apache.qpid.server.virtualhost.QueueManagingVirtualHost;
import org.apache.qpid.test.utils.UnitTestBase;
public class ClientActionTest extends UnitTestBase
{
- private Action _action = mock(Action.class);
- private AclAction _ruleAction = mock(AclAction.class);
- private InetAddress _addressOfClient = mock(InetAddress.class);
-
- private ClientAction _clientAction = new ClientAction(_action);
+ private Action _action;
+ private AclAction _ruleAction;
+ private ClientAction _clientAction;
+ private Subject _subject;
+ private QueueManagingVirtualHost _addressSpace;
+ private AMQPConnection _connection;
+
+ @Before
+ public void setUp()
+ {
+ final InetSocketAddress address =
InetSocketAddress.createUnresolved("localhost", 5672);
+
+ _addressSpace = mock(QueueManagingVirtualHost.class);
+ _connection = mock(AMQPConnection.class);
+ when(_connection.getAddressSpace()).thenReturn(_addressSpace);
+
+ final ConnectionPrincipal connectionPrincipal =
mock(ConnectionPrincipal.class);
+ when(connectionPrincipal.getConnection()).thenReturn(_connection);
+ when(_connection.getRemoteSocketAddress()).thenReturn(address);
+
when(_connection.getAuthorizedPrincipal()).thenReturn(connectionPrincipal);
+ final Set<? extends Principal> principals =
Collections.singleton(connectionPrincipal);
+ _subject = new Subject(false, principals, Collections.emptySet(),
Collections.emptySet());
+ _ruleAction = mock(AclAction.class);
+ when(_ruleAction.getDynamicRule()).thenReturn(subject -> true);
+ _action = mock(Action.class);
+ _clientAction = new ClientAction(_action);
+ }
@Test
public void testMatches_returnsTrueWhenActionsMatchAndNoFirewallRule()
{
when(_action.matches(any(Action.class))).thenReturn(true);
- when(_ruleAction.getFirewallRule()).thenReturn(null);
+ when(_ruleAction.getDynamicRule()).thenReturn(null);
when(_ruleAction.getAction()).thenReturn(mock(Action.class));
- assertTrue(_clientAction.matches(_ruleAction, _addressOfClient));
+ assertTrue(_clientAction.matches(_ruleAction, _subject));
}
@Test
public void testMatches_returnsFalseWhenActionsDontMatch()
{
FirewallRule firewallRule = mock(FirewallRule.class);
- when(firewallRule.matches(_addressOfClient)).thenReturn(true);
+ when(firewallRule.matches(_subject)).thenReturn(true);
+ when(_ruleAction.getDynamicRule()).thenReturn(firewallRule);
when(_action.matches(any(Action.class))).thenReturn(false);
- when(_ruleAction.getFirewallRule()).thenReturn(firewallRule);
+ when(_ruleAction.getDynamicRule()).thenReturn(firewallRule);
when(_ruleAction.getAction()).thenReturn(mock(Action.class));
- assertFalse(_clientAction.matches(_ruleAction, _addressOfClient));
+ assertFalse(_clientAction.matches(_ruleAction, _subject));
}
@Test
public void testMatches_returnsTrueWhenActionsAndFirewallRuleMatch()
{
FirewallRule firewallRule = mock(FirewallRule.class);
- when(firewallRule.matches(_addressOfClient)).thenReturn(true);
+ when(firewallRule.matches(_subject)).thenReturn(true);
+ when(_ruleAction.getDynamicRule()).thenReturn(firewallRule);
when(_action.matches(any(Action.class))).thenReturn(true);
- when(_ruleAction.getFirewallRule()).thenReturn(firewallRule);
+ when(_ruleAction.getDynamicRule()).thenReturn(firewallRule);
when(_ruleAction.getAction()).thenReturn(mock(Action.class));
- assertTrue(_clientAction.matches(_ruleAction, _addressOfClient));
+ assertTrue(_clientAction.matches(_ruleAction, _subject));
}
@Test
public void testMatches_ignoresFirewallRuleIfClientAddressIsNull()
{
- FirewallRule firewallRule = mock(FirewallRule.class);
+ FirewallRule firewallRule = new FirewallRule()
+ {
+ @Override
+ protected boolean matches(final InetAddress addressOfClient)
+ {
+ return false;
+ }
+ };
when(_action.matches(any(Action.class))).thenReturn(true);
- when(_ruleAction.getFirewallRule()).thenReturn(firewallRule);
+ when(_ruleAction.getDynamicRule()).thenReturn(firewallRule);
when(_ruleAction.getAction()).thenReturn(mock(Action.class));
- assertTrue(_clientAction.matches(_ruleAction, null));
-
- verifyNoInteractions(firewallRule);
+ assertTrue(_clientAction.matches(_ruleAction, _subject));
}
+ @Test
+ public void testMatchesWhenConnectionLimitBreached()
+ {
+ final ObjectProperties properties = new ObjectProperties("foo");
+ final AclRulePredicates predicates = new AclRulePredicates();
+ predicates.parse(ObjectProperties.Property.CONNECTION_LIMIT.name(),
"1");
+ final AclAction ruleAction = new AclAction(LegacyOperation.ACCESS,
ObjectType.VIRTUALHOST, predicates);
+ final ClientAction clientAction = new
ClientAction(LegacyOperation.ACCESS, ObjectType.VIRTUALHOST, properties);
+
+
when(_connection.getAuthenticatedPrincipalConnectionCount()).thenReturn(2);
+ boolean matches = clientAction.matches(ruleAction, _subject);
+ assertFalse(matches);
+ }
}
diff --git
a/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/DynamicRuleTest.java
b/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/DynamicRuleTest.java
new file mode 100644
index 0000000..9b533bb
--- /dev/null
+++
b/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/DynamicRuleTest.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.qpid.server.security.access.config;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.*;
+
+import javax.security.auth.Subject;
+
+import org.junit.Test;
+
+import org.apache.qpid.test.utils.UnitTestBase;
+
+public class DynamicRuleTest extends UnitTestBase
+{
+
+ @Test
+ public void subjectMatchesAllRules()
+ {
+ final Subject subject = new Subject();
+ final DynamicRule rule1 = s -> s.equals(subject);
+ final DynamicRule rule2 = s -> s.equals(subject);
+
+ final DynamicRule combined = rule1.and(rule2);
+
+ assertThat(combined.matches(subject), is(true));
+ }
+
+ @Test
+ public void subjectDoesNotMatchAllRules()
+ {
+ final Subject subject = new Subject();
+ final DynamicRule rule1 = s -> s.equals(subject);
+ final DynamicRule rule2 = s -> !s.equals(subject);
+
+ final DynamicRule combined = rule1.and(rule2);
+
+ assertThat(combined.matches(subject), is(false));
+ }
+}
diff --git
a/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/RuleBasedAccessControlTest.java
b/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/RuleBasedAccessControlTest.java
index 02429de..bda1f74 100644
---
a/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/RuleBasedAccessControlTest.java
+++
b/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/RuleBasedAccessControlTest.java
@@ -272,7 +272,7 @@ public class RuleBasedAccessControlTest extends UnitTestBase
ObjectProperties properties = new
ObjectProperties(testVirtualHost);
accessControl.authorise(LegacyOperation.ACCESS,
ObjectType.VIRTUALHOST, properties);
- verify(mockRuleSet).check(subject, LegacyOperation.ACCESS,
ObjectType.VIRTUALHOST, properties, inetAddress);
+ verify(mockRuleSet).check(subject, LegacyOperation.ACCESS,
ObjectType.VIRTUALHOST, properties);
return null;
}
});
@@ -303,8 +303,7 @@ public class RuleBasedAccessControlTest extends UnitTestBase
subject,
LegacyOperation.ACCESS,
ObjectType.VIRTUALHOST,
- ObjectProperties.EMPTY,
- inetAddress)).thenThrow(new RuntimeException());
+ ObjectProperties.EMPTY)).thenThrow(new
RuntimeException());
RuleBasedAccessControl accessControl = new
RuleBasedAccessControl(mockRuleSet,
BrokerModel.getInstance());
diff --git
a/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/connection/ConnectionPrincipalFrequencyLimitRuleTest.java
b/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/connection/ConnectionPrincipalFrequencyLimitRuleTest.java
new file mode 100644
index 0000000..1619e72
--- /dev/null
+++
b/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/connection/ConnectionPrincipalFrequencyLimitRuleTest.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.qpid.server.security.access.config.connection;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Collections;
+
+import javax.security.auth.Subject;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.apache.qpid.server.connection.ConnectionPrincipal;
+import org.apache.qpid.server.transport.AMQPConnection;
+import org.apache.qpid.test.utils.UnitTestBase;
+
+public class ConnectionPrincipalFrequencyLimitRuleTest extends UnitTestBase
+{
+
+ private AMQPConnection _connection;
+ private Subject _subject;
+
+ @Before
+ public void setUp()
+ {
+ _connection = mock(AMQPConnection.class);
+
+ final ConnectionPrincipal connectionPrincipal =
mock(ConnectionPrincipal.class);
+ when(connectionPrincipal.getConnection()).thenReturn(_connection);
+
when(_connection.getAuthorizedPrincipal()).thenReturn(connectionPrincipal);
+ _subject = new Subject(false,
+ Collections.singleton(connectionPrincipal),
+ Collections.emptySet(),
+ Collections.emptySet());
+ }
+
+ @Test
+ public void limitBreached()
+ {
+
when(_connection.getAuthenticatedPrincipalConnectionFrequency()).thenReturn(2);
+ final ConnectionPrincipalFrequencyLimitRule rule = new
ConnectionPrincipalFrequencyLimitRule(1);
+
+ assertThat(rule.matches(_subject), is(false));
+ }
+
+ @Test
+ public void frequencyEqualsLimit()
+ {
+
when(_connection.getAuthenticatedPrincipalConnectionFrequency()).thenReturn(2);
+ final ConnectionPrincipalFrequencyLimitRule rule = new
ConnectionPrincipalFrequencyLimitRule(2);
+
+ assertThat(rule.matches(_subject), is(true));
+ }
+
+ @Test
+ public void frequencyBelowLimit()
+ {
+
when(_connection.getAuthenticatedPrincipalConnectionFrequency()).thenReturn(1);
+ final ConnectionPrincipalFrequencyLimitRule rule = new
ConnectionPrincipalFrequencyLimitRule(2);
+
+ assertThat(rule.matches(_subject), is(true));
+ }
+}
diff --git
a/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/connection/ConnectionPrincipalLimitRuleTest.java
b/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/connection/ConnectionPrincipalLimitRuleTest.java
new file mode 100644
index 0000000..4b5598a
--- /dev/null
+++
b/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/connection/ConnectionPrincipalLimitRuleTest.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.qpid.server.security.access.config.connection;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Collections;
+
+import javax.security.auth.Subject;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.apache.qpid.server.connection.ConnectionPrincipal;
+import org.apache.qpid.server.transport.AMQPConnection;
+import org.apache.qpid.test.utils.UnitTestBase;
+
+public class ConnectionPrincipalLimitRuleTest extends UnitTestBase
+{
+
+ private AMQPConnection _connection;
+ private Subject _subject;
+
+ @Before
+ public void setUp()
+ {
+ _connection = mock(AMQPConnection.class);
+
+ final ConnectionPrincipal connectionPrincipal =
mock(ConnectionPrincipal.class);
+ when(connectionPrincipal.getConnection()).thenReturn(_connection);
+
when(_connection.getAuthorizedPrincipal()).thenReturn(connectionPrincipal);
+ _subject = new Subject(false,
+ Collections.singleton(connectionPrincipal),
+ Collections.emptySet(),
+ Collections.emptySet());
+ }
+
+ @Test
+ public void limitBreached()
+ {
+
when(_connection.getAuthenticatedPrincipalConnectionCount()).thenReturn(2);
+ final ConnectionPrincipalLimitRule rule = new
ConnectionPrincipalLimitRule(1);
+
+ assertThat(rule.matches(_subject), is(false));
+ }
+
+ @Test
+ public void frequencyEqualsLimit()
+ {
+
when(_connection.getAuthenticatedPrincipalConnectionCount()).thenReturn(2);
+ final ConnectionPrincipalLimitRule rule = new
ConnectionPrincipalLimitRule(2);
+
+ assertThat(rule.matches(_subject), is(true));
+ }
+
+ @Test
+ public void frequencyBelowLimit()
+ {
+
when(_connection.getAuthenticatedPrincipalConnectionCount()).thenReturn(1);
+ final ConnectionPrincipalLimitRule rule = new
ConnectionPrincipalLimitRule(2);
+
+ assertThat(rule.matches(_subject), is(true));
+ }
+}
diff --git
a/broker-plugins/amqp-0-10-protocol/src/test/java/org/apache/qpid/server/protocol/v0_10/ServerSessionTest.java
b/broker-plugins/amqp-0-10-protocol/src/test/java/org/apache/qpid/server/protocol/v0_10/ServerSessionTest.java
index d5bd980..f7e0259 100644
---
a/broker-plugins/amqp-0-10-protocol/src/test/java/org/apache/qpid/server/protocol/v0_10/ServerSessionTest.java
+++
b/broker-plugins/amqp-0-10-protocol/src/test/java/org/apache/qpid/server/protocol/v0_10/ServerSessionTest.java
@@ -26,6 +26,8 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
import java.util.List;
import javax.security.auth.Subject;
@@ -40,6 +42,7 @@ import
org.apache.qpid.server.configuration.updater.CurrentThreadTaskExecutor;
import org.apache.qpid.server.configuration.updater.TaskExecutor;
import org.apache.qpid.server.configuration.updater.TaskExecutorImpl;
import org.apache.qpid.server.logging.EventLogger;
+import org.apache.qpid.server.model.AuthenticationProvider;
import org.apache.qpid.server.model.Broker;
import org.apache.qpid.server.model.BrokerModel;
import org.apache.qpid.server.model.BrokerTestHelper;
@@ -54,6 +57,8 @@ import
org.apache.qpid.server.protocol.v0_10.transport.ExecutionErrorCode;
import org.apache.qpid.server.protocol.v0_10.transport.ExecutionException;
import org.apache.qpid.server.protocol.v0_10.transport.MessageTransfer;
import org.apache.qpid.server.protocol.v0_10.transport.Method;
+import org.apache.qpid.server.security.auth.AuthenticatedPrincipal;
+import org.apache.qpid.server.security.auth.UsernamePrincipal;
import org.apache.qpid.test.utils.UnitTestBase;
public class ServerSessionTest extends UnitTestBase
@@ -120,9 +125,13 @@ public class ServerSessionTest extends UnitTestBase
when(modelConnection.getModel()).thenReturn(BrokerModel.getInstance());
when(modelConnection.getPort()).thenReturn(port);
- Subject subject = new Subject();
+ final AuthenticatedPrincipal principal =
+ new AuthenticatedPrincipal(new
UsernamePrincipal(getTestName(), mock(AuthenticationProvider.class)));
+ final Subject subject =
+ new Subject(false, Collections.singleton(principal),
Collections.emptySet(), Collections.emptySet());
when(modelConnection.getSubject()).thenReturn(subject);
when(modelConnection.getMaxMessageSize()).thenReturn(1024l);
+ when(modelConnection.getCreatedTime()).thenReturn(new Date());
ServerConnection connection = new ServerConnection(1, broker, port,
Transport.TCP, modelConnection);
connection.setVirtualHost(_virtualHost);
diff --git
a/doc/java-broker/src/docbkx/security/Java-Broker-Security-AccessControlProviders.xml
b/doc/java-broker/src/docbkx/security/Java-Broker-Security-AccessControlProviders.xml
index 0fecf48..37e5bfa 100644
---
a/doc/java-broker/src/docbkx/security/Java-Broker-Security-AccessControlProviders.xml
+++
b/doc/java-broker/src/docbkx/security/Java-Broker-Security-AccessControlProviders.xml
@@ -283,7 +283,7 @@
<entry> <command>VIRTUALHOST</command> </entry>
<entry> <para>A virtualhost</para> </entry>
<entry><para>ALL, CREATE, UPDATE, DELETE, ACCESS, ACCESS_LOGS,
INVOKE</para> </entry>
- <entry><para>name</para> </entry>
+ <entry><para>name, connection_limit,
connection_frequency_limit</para> </entry>
<entry><para>No</para> </entry>
</row>
<row>
@@ -415,6 +415,36 @@
</entry>
</row>
<row>
+ <entry><command>connection_limit</command></entry>
+ <entry>
+ <para>
+ A maximum number of connections the users belonging to the given
identity can establish to the Virtual Host
+ </para>
+ <para>
+ Intended for use in ACCESS VIRTUALHOST rules to restrict the
number of connections which can be made
+ by the messaging user.
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry><command>connection_frequency_limit</command></entry>
+ <entry>
+ <para>
+ A maximum number of connections the user belonging to the given
identity can establish to the Virtual Host
+ within pre-defined period of time, which is 1 minute by default.
+ </para>
+ <para>
+ Intended for use in ACCESS VIRTUALHOST rules to restrict the
frequency of connections which can be made
+ by the messaging user.
+ </para>
+ <para>If required, the frequency period can be changed using
context variable
+
<emphasis>qpid.virtualhost.connectionFrequencyPeriodInMillis</emphasis>. As
name suggests, its value needs
+ to be specified in milliseconds. Setting it to zero or negative
value turns off the
+ <command>connection_frequency</command> evaluation.
+ </para>
+ </entry>
+ </row>
+ <row>
<entry><command>virtualhost_name</command></entry>
<entry>
<para>
@@ -478,6 +508,28 @@
</example>
</section>
+ <section role="h4"
xml:id="Java-Broker-Security-AccessControlProviders-ResourceRestrictions">
+ <title>
+ Resource restrictions
+ </title>
+ <para>
+ The number of Virtual Host connections and frequency of connections
can be restricted with
+ <emphasis>ACCESS</emphasis> rule.
+ </para>
+ <example>
+ <title>Restricting user connections to virtual host</title>
+ <programlisting><![CDATA[
+ ACL ALLOW-LOG guest ACCESS VIRTUALHOST connection_limit=1
+ ACL ALLOW-LOG messaging-users ACCESS VIRTUALHOST
connection_frequency_limit=100
+ ...]]>
+ </programlisting>
+ </example>
+ <para>In the example above the maximum number of connections allowed to
establish to the Virtual Host by user
+ <emphasis>guest</emphasis> is set to <emphasis>1</emphasis>. The
maximum connection frequency for every user
+ belonging to the user group <emphasis>messaging-users</emphasis> is
set to <emphasis>100</emphasis> (per minute,
+ by default).
+ </para>
+ </section>
<section role="h4"
xml:id="Java-Broker-Security-AccessControlProviders-WorkedExample2">
<title>
Worked example 2 - Simple Messaging
diff --git
a/systests/qpid-systests-jms_1.1/src/test/java/org/apache/qpid/systests/jms_1_1/extensions/acl/MessagingACLTest.java
b/systests/qpid-systests-jms_1.1/src/test/java/org/apache/qpid/systests/jms_1_1/extensions/acl/MessagingACLTest.java
index 8a9fecd..cb591e8 100644
---
a/systests/qpid-systests-jms_1.1/src/test/java/org/apache/qpid/systests/jms_1_1/extensions/acl/MessagingACLTest.java
+++
b/systests/qpid-systests-jms_1.1/src/test/java/org/apache/qpid/systests/jms_1_1/extensions/acl/MessagingACLTest.java
@@ -51,6 +51,7 @@ import javax.jms.Session;
import javax.jms.TemporaryQueue;
import javax.jms.TemporaryTopic;
import javax.jms.TextMessage;
+import javax.naming.NamingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Sets;
@@ -70,9 +71,6 @@ import
org.apache.qpid.server.security.access.config.ObjectProperties;
import org.apache.qpid.server.security.access.config.ObjectType;
import org.apache.qpid.server.security.access.config.Rule;
import org.apache.qpid.server.security.access.config.RuleSet;
-import org.apache.qpid.server.security.access.firewall.FirewallRule;
-import org.apache.qpid.server.security.access.firewall.HostnameFirewallRule;
-import org.apache.qpid.server.security.access.firewall.NetworkFirewallRule;
import org.apache.qpid.server.security.access.plugins.AclRule;
import
org.apache.qpid.server.security.access.plugins.RuleBasedVirtualHostAccessControlProvider;
import org.apache.qpid.server.security.access.plugins.RuleOutcome;
@@ -184,6 +182,125 @@ public class MessagingACLTest extends JmsTestBase
}
@Test
+ public void testAuthorizationWithConnectionLimit() throws Exception
+ {
+ final int connectionLimit = 2;
+ configureACL(String.format("ACL ALLOW-LOG %s ACCESS VIRTUALHOST
connection_limit='%d'",
+ USER2,
+ connectionLimit));
+
+ final List<Connection> establishedConnections = new ArrayList<>();
+ try
+ {
+ establishConnections(connectionLimit, establishedConnections);
+
+ verifyConnectionEstablishmentFails(connectionLimit);
+
+ establishedConnections.remove(0).close();
+
getConnectionBuilder().setUsername(USER2).setPassword(USER2_PASSWORD).build().close();
+ }
+ finally
+ {
+ closeConnections(establishedConnections);
+ }
+ }
+
+ @Test
+ public void testAuthorizationWithConnectionFrequencyLimit() throws
Exception
+ {
+ final int connectionFrequencyLimit = 1;
+ configureACL(String.format("ACL ALLOW-LOG %s ACCESS VIRTUALHOST
connection_frequency_limit='%d'",
+ USER2,
+ connectionFrequencyLimit));
+
+ final List<Connection> establishedConnections = new ArrayList<>();
+ try
+ {
+ establishConnections(connectionFrequencyLimit,
establishedConnections);
+
+ verifyConnectionEstablishmentFails(connectionFrequencyLimit);
+
+ establishedConnections.remove(0).close();
+
+ verifyConnectionEstablishmentFails(connectionFrequencyLimit);
+ }
+ finally
+ {
+ closeConnections(establishedConnections);
+ }
+ }
+
+ @Test
+ public void testAuthorizationWithConnectionLimitAndFrequencyLimit() throws
Exception
+ {
+ final int connectionFrequencyLimit = 2;
+ final int connectionLimit = 3;
+ configureACL(String.format("ACL ALLOW-LOG %s ACCESS VIRTUALHOST
connection_limit='%d' connection_frequency_limit='%d'",
+ USER2,
+ connectionLimit,
+ connectionFrequencyLimit));
+
+ final List<Connection> establishedConnections = new ArrayList<>();
+ try
+ {
+ establishConnections(connectionFrequencyLimit,
establishedConnections);
+
+ verifyConnectionEstablishmentFails(connectionFrequencyLimit);
+
+ establishedConnections.remove(0).close();
+
+ verifyConnectionEstablishmentFails(connectionFrequencyLimit);
+ }
+ finally
+ {
+ closeConnections(establishedConnections);
+ }
+ }
+
+ private void establishConnections(final int connectionNumber, final
List<Connection> establishedConnections)
+ throws NamingException, JMSException
+ {
+ for (int i = 0; i < connectionNumber; i++)
+ {
+
establishedConnections.add(getConnectionBuilder().setUsername(USER2)
+
.setPassword(USER2_PASSWORD)
+
.setClientId(getTestName() + i)
+ .build());
+ }
+ }
+
+ private void closeConnections(final List<Connection>
establishedConnections) throws JMSException
+ {
+ for (Connection c : establishedConnections)
+ {
+ c.close();
+ }
+ }
+
+ private void verifyConnectionEstablishmentFails(final int frequencyLimit)
throws NamingException
+ {
+ try
+ {
+ final Connection connection =
getConnectionBuilder().setUsername(USER2)
+
.setPassword(USER2_PASSWORD)
+
.setClientId(getTestName() + frequencyLimit)
+ .build();
+ try
+ {
+ fail("Connection creation should fail due to exceeding limit");
+ }
+ finally
+ {
+ connection.close();
+ }
+ }
+ catch (JMSException e)
+ {
+ //pass
+ }
+ }
+
+ @Test
public void testConsumeFromTempQueueSuccess() throws Exception
{
configureACL(String.format("ACL ALLOW-LOG %s ACCESS VIRTUALHOST",
USER1),
@@ -865,21 +982,7 @@ public class MessagingACLTest extends JmsTestBase
@Override
public Map<ObjectProperties.Property, String>
getAttributes()
{
- Map<ObjectProperties.Property, String> attributes =
new HashMap<>(rule.getAction().getProperties().asPropertyMap());
- FirewallRule firewallRule =
rule.getAclAction().getFirewallRule();
- if (firewallRule != null)
- {
- if (firewallRule instanceof HostnameFirewallRule)
- {
-
attributes.put(ObjectProperties.Property.FROM_HOSTNAME, "127.0.0.1");
- }
- else if (firewallRule instanceof
NetworkFirewallRule)
- {
- // tests use only 127.0.0.1 at the moment
-
attributes.put(ObjectProperties.Property.FROM_NETWORK, "127.0.0.1");
- }
- }
- return attributes;
+ return rule.getAttributes();
}
@Override
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]