You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by or...@apache.org on 2020/09/02 19:32:47 UTC

[qpid-broker-j] branch 7.1.x updated (54d2a9f -> 627ce9d)

This is an automated email from the ASF dual-hosted git repository.

orudyy pushed a change to branch 7.1.x
in repository https://gitbox.apache.org/repos/asf/qpid-broker-j.git.


    from 54d2a9f  [maven-release-plugin] prepare for next development iteration
     new 55bab0d  NO-JIRA: Fix Kerberos tests
     new 6ed3dd8  NO-JIRA: remove links etc from the documentation, missed from removal in QPID 7487
     new aa93436  QPID-8460: [Broker-j] Do not expose private information to exception message (#55)
     new 1c04466  QPID-8458: [Broker-J] Removed RewriteServlet from HTTP management
     new 351f449  QPID-8459: [Broker-J] AnonymousInteractiveAuthenticator uses request.getRequestDispatcher().forward() instead of parsing request URL
     new ee2293f  QPID-8461: [Broker-J] Repace Random with SecureRandom
     new ec885c0  QPID-8455: [Broker-J] Add allow/deny list alternatives for existing black/whilte list attributes and context variables
     new d547af8  QPID-8454:[Broker-J] Add Prometheus integration
     new f7f5145  QPID-8454:[Broker-J] Update documentation
     new 627ce9d  QPID-8454:[Broker-J] Add missing license

The 10 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../dependency-verification/DEPENDENCIES_REFERENCE |   6 +
 .../server/configuration/CommonProperties.java     |   5 +
 .../server/model/AbstractConfiguredObject.java     |  15 +
 .../java/org/apache/qpid/server/model/Broker.java  |  80 +++--
 .../qpid/server/model/BrokerAttributeInjector.java |  20 +-
 .../org/apache/qpid/server/model/BrokerLogger.java |   4 +-
 .../server/model/ConfiguredAutomatedAttribute.java |   3 +-
 .../model/ConfiguredObjectInjectedStatistic.java   |  20 +-
 .../model/ConfiguredObjectMethodStatistic.java     |  12 +
 .../server/model/ConfiguredObjectStatistic.java    |   4 +
 .../org/apache/qpid/server/model/Connection.java   |  14 +-
 .../org/apache/qpid/server/model/Consumer.java     |   4 +-
 .../org/apache/qpid/server/model/Exchange.java     |  10 +-
 .../apache/qpid/server/model/ManagedStatistic.java |   2 +
 .../java/org/apache/qpid/server/model/Port.java    |  17 +
 .../java/org/apache/qpid/server/model/Queue.java   |  36 +--
 .../java/org/apache/qpid/server/model/Session.java |   2 +-
 .../qpid/server/model/VirtualHostLogger.java       |   4 +-
 .../qpid/server/model/port/AbstractPort.java       |  32 +-
 .../apache/qpid/server/model/port/AmqpPort.java    |  12 +-
 ...ObjectRegistration.java => ContentFactory.java} |   9 +-
 .../AbstractScramAuthenticationManager.java        |  24 +-
 .../manager/SimpleLDAPAuthenticationManager.java   |  16 +
 .../SimpleLDAPAuthenticationManagerImpl.java       |  32 +-
 .../oauth2/OAuth2AuthenticationProvider.java       |  18 ++
 .../oauth2/OAuth2AuthenticationProviderImpl.java   |  32 +-
 .../crammd5/CramMd5Base64HashedNegotiator.java     |  25 +-
 .../sasl/crammd5/CramMd5Base64HexNegotiator.java   |  33 +-
 ...oudFoundryDashboardManagementGroupProvider.java |  14 +
 ...oundryDashboardManagementGroupProviderImpl.java |  37 ++-
 .../apache/qpid/server/util/ConnectionBuilder.java |  24 ++
 .../org/apache/qpid/server/util/StringUtil.java    |   4 +-
 .../java/org/apache/qpid/server/util/Strings.java  |  24 +-
 .../virtualhost/QueueManagingVirtualHost.java      |  28 +-
 .../qpid/server/model/port/AmqpPortImplTest.java   |  87 +++++
 .../hierarchy/InjectedAttributeTest.java           |  16 +-
 .../testmodels/hierarchy/TestAbstractCarImpl.java  |  21 ++
 .../hierarchy/TestAbstractEngineImpl.java          |   7 +
 .../hierarchy/TestAbstractInstrumentPanelImpl.java |   2 +
 .../hierarchy/TestAbstractSensorImpl.java          |   9 +
 .../server/model/testmodels/hierarchy/TestCar.java |  14 +
 .../model/testmodels/hierarchy/TestEngine.java     |   6 +
 .../model/testmodels/hierarchy/TestSensor.java     |   5 +
 .../hierarchy/TestTemperatureSensorImpl.java       |   9 +
 .../manager/KerberosAuthenticationManagerTest.java |  79 ++---
 .../SimpleLDAPAuthenticationManagerTest.java       |  86 ++++-
 .../auth/manager/SpnegoAuthenticatorTest.java      |  61 ++--
 .../OAuth2AuthenticationProviderImplTest.java      |  91 +++++-
 .../qpid/server/test/EmbeddedKdcResource.java      |  29 +-
 .../apache/qpid/server/test/KerberosUtilities.java | 196 ++++++++++-
 broker-core/src/test/resources/login.ibm.config    |  51 +++
 broker-plugins/management-http/pom.xml             |   5 +
 .../server/management/plugin/HttpManagement.java   |  29 +-
 .../plugin/HttpManagementConfiguration.java        |   5 +
 .../server/management/plugin/RewriteServlet.java   |  55 ----
 .../auth/AnonymousInteractiveAuthenticator.java    |  88 +++--
 .../auth/BasicAuthPreemptiveAuthenticator.java     |  24 +-
 .../auth/UsernamePasswordInteractiveLogin.java     |  17 +-
 .../management/plugin/servlet/ContentServlet.java  |  95 ++++++
 .../plugin/servlet/rest/AbstractServlet.java       |  21 +-
 .../plugin/servlet/rest/ApiDocsServlet.java        |  64 ++--
 .../pom.xml                                        |  40 +--
 .../IncludeDisabledStatisticPredicate.java         |  27 +-
 .../server/prometheus/IncludeMetricPredicate.java  |  31 +-
 .../prometheus/PrometheusContentFactory.java       | 105 ++++++
 .../qpid/server/prometheus/QpidCollector.java      | 257 +++++++++++++++
 .../prometheus/PrometheusContentFactoryTest.java   | 176 ++++++++++
 .../qpid/server/prometheus/QpidCollectorTest.java  | 359 +++++++++++++++++++++
 .../docbkx/Java-Broker-Initial-Configuration.xml   |  11 +-
 .../src/docbkx/Java-Broker-Management-Channels.xml |   1 +
 .../channels/Java-Broker-Management-Metrics.xml    |  49 +++
 pom.xml                                            |  20 ++
 .../java/org/apache/qpid/test/utils/JvmVendor.java |  25 +-
 .../org/apache/qpid/test/utils/UnitTestBase.java   |  18 +-
 .../PreemptiveAuthenticationTest.java              |   4 +-
 .../BrokerMetricsAuthenticationTest.java}          |  35 +-
 .../qpid/tests/http/metrics/BrokerMetricsTest.java | 100 ++++++
 .../qpid/tests/http/metrics/TestMetricsHelper.java |  93 ++++++
 .../tests/http/metrics/VirtualHostMetricsTest.java |  20 +-
 .../qpid/systests/admin/SpawnBrokerAdmin.java      |  26 +-
 .../qpid/systests/admin/SpawnBrokerAdminTest.java  |  16 +-
 81 files changed, 2602 insertions(+), 605 deletions(-)
 copy broker-core/src/main/java/org/apache/qpid/server/plugin/{ConfiguredObjectRegistration.java => ContentFactory.java} (81%)
 create mode 100644 broker-core/src/test/resources/login.ibm.config
 delete mode 100644 broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/RewriteServlet.java
 create mode 100644 broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/ContentServlet.java
 copy broker-plugins/{amqp-1-0-jdbc-store => prometheus-exporter}/pom.xml (68%)
 copy broker-core/src/test/java/org/apache/qpid/server/store/MessageCounter.java => broker-plugins/prometheus-exporter/src/main/java/org/apache/qpid/server/prometheus/IncludeDisabledStatisticPredicate.java (62%)
 copy broker-core/src/test/java/org/apache/qpid/server/store/MessageCounter.java => broker-plugins/prometheus-exporter/src/main/java/org/apache/qpid/server/prometheus/IncludeMetricPredicate.java (63%)
 create mode 100644 broker-plugins/prometheus-exporter/src/main/java/org/apache/qpid/server/prometheus/PrometheusContentFactory.java
 create mode 100644 broker-plugins/prometheus-exporter/src/main/java/org/apache/qpid/server/prometheus/QpidCollector.java
 create mode 100644 broker-plugins/prometheus-exporter/src/test/java/org/apache/qpid/server/prometheus/PrometheusContentFactoryTest.java
 create mode 100644 broker-plugins/prometheus-exporter/src/test/java/org/apache/qpid/server/prometheus/QpidCollectorTest.java
 create mode 100644 doc/java-broker/src/docbkx/management/channels/Java-Broker-Management-Metrics.xml
 copy systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/{query/QueryBrokerTest.java => metrics/BrokerMetricsAuthenticationTest.java} (51%)
 create mode 100644 systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/metrics/BrokerMetricsTest.java
 create mode 100644 systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/metrics/TestMetricsHelper.java
 copy broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/HttpManagementUtilTest.java => systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/metrics/VirtualHostMetricsTest.java (57%)


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[qpid-broker-j] 03/10: QPID-8460: [Broker-j] Do not expose private information to exception message (#55)

Posted by or...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

orudyy pushed a commit to branch 7.1.x
in repository https://gitbox.apache.org/repos/asf/qpid-broker-j.git

commit aa934369a6313dd26b501ed50405c4c200bd346b
Author: vavrtom <cz...@tiscali.cz>
AuthorDate: Thu Aug 6 23:41:42 2020 +0200

    QPID-8460: [Broker-j] Do not expose private information to exception message (#55)
    
    Co-authored-by: Tomas Vavricka <to...@deutsche-boerse.com>
    (cherry picked from commit 734fb3994f74ae066b587d3563322f10e47e6727)
---
 .../server/model/ConfiguredAutomatedAttribute.java |  3 +-
 .../AbstractScramAuthenticationManager.java        | 24 +++++++++-------
 .../crammd5/CramMd5Base64HashedNegotiator.java     | 25 +++++++---------
 .../sasl/crammd5/CramMd5Base64HexNegotiator.java   | 33 +++++++++-------------
 .../java/org/apache/qpid/server/util/Strings.java  | 24 +++++++++++++---
 .../auth/BasicAuthPreemptiveAuthenticator.java     | 24 ++++++++--------
 6 files changed, 70 insertions(+), 63 deletions(-)

diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredAutomatedAttribute.java b/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredAutomatedAttribute.java
index a5b3598..d98a96f 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredAutomatedAttribute.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredAutomatedAttribute.java
@@ -255,7 +255,8 @@ public class ConfiguredAutomatedAttribute<C extends ConfiguredObject, T>  extend
             Type returnType = getGetter().getGenericReturnType();
             String simpleName = returnType instanceof Class ? ((Class) returnType).getSimpleName() : returnType.toString();
 
-            throw new IllegalArgumentException("Cannot convert '" + value
+            throw new IllegalArgumentException("Cannot convert '" +
+                                               (isSecure() ? AbstractConfiguredObject.SECURED_STRING_VALUE : value)
                                                + "' into a " + simpleName
                                                + " for attribute " + getName()
                                                + " (" + iae.getMessage() + ")", iae);
diff --git a/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractScramAuthenticationManager.java b/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractScramAuthenticationManager.java
index e8bb81e..abc6cbf 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractScramAuthenticationManager.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractScramAuthenticationManager.java
@@ -159,17 +159,18 @@ public abstract class AbstractScramAuthenticationManager<X extends AbstractScram
         final String[] passwordFields = user.getPassword().split(",");
         if (passwordFields.length == 2)
         {
-            byte[] saltedPassword = Strings.decodeBase64(passwordFields[PasswordField.SALTED_PASSWORD.ordinal()]);
+            final byte[] saltedPassword = Strings.decodePrivateBase64(passwordFields[PasswordField.SALTED_PASSWORD.ordinal()],
+                    "user '" + user.getName() + "' salted password");
 
             try
             {
-                byte[] clientKey = computeHmac(saltedPassword, "Client Key");
+                final byte[] clientKey = computeHmac(saltedPassword, "Client Key");
 
-                byte[] storedKey = MessageDigest.getInstance(getDigestName()).digest(clientKey);
+                final byte[] storedKey = MessageDigest.getInstance(getDigestName()).digest(clientKey);
 
-                byte[] serverKey = computeHmac(saltedPassword, "Server Key");
+                final byte[] serverKey = computeHmac(saltedPassword, "Server Key");
 
-                String password = passwordFields[PasswordField.SALT.ordinal()] + ","
+                final String password = passwordFields[PasswordField.SALT.ordinal()] + ","
                                   + "," // remove previously insecure salted password field
                                   + Base64.getEncoder().encodeToString(storedKey) + ","
                                   + Base64.getEncoder().encodeToString(serverKey) + ","
@@ -183,7 +184,7 @@ public abstract class AbstractScramAuthenticationManager<X extends AbstractScram
         }
         else if (passwordFields.length == 4)
         {
-            String password = passwordFields[PasswordField.SALT.ordinal()] + ","
+            final String password = passwordFields[PasswordField.SALT.ordinal()] + ","
                     + "," // remove previously insecure salted password field
                     + passwordFields[PasswordField.STORED_KEY.ordinal()] + ","
                     + passwordFields[PasswordField.SERVER_KEY.ordinal()] + ","
@@ -296,7 +297,7 @@ public abstract class AbstractScramAuthenticationManager<X extends AbstractScram
     @Override
     public SaltAndPasswordKeys getSaltAndPasswordKeys(final String username)
     {
-        ManagedUser user = getUser(username);
+        final ManagedUser user = getUser(username);
 
         final byte[] salt;
         final byte[] storedKey;
@@ -318,9 +319,12 @@ public abstract class AbstractScramAuthenticationManager<X extends AbstractScram
         {
             updateStoredPasswordFormatIfNecessary(user);
             final String[] passwordFields = user.getPassword().split(",");
-            salt = Strings.decodeBase64(passwordFields[PasswordField.SALT.ordinal()]);
-            storedKey = Strings.decodeBase64(passwordFields[PasswordField.STORED_KEY.ordinal()]);
-            serverKey = Strings.decodeBase64(passwordFields[PasswordField.SERVER_KEY.ordinal()]);
+            salt = Strings.decodePrivateBase64(passwordFields[PasswordField.SALT.ordinal()],
+                    "user '" + user.getName() + "' salt");
+            storedKey = Strings.decodePrivateBase64(passwordFields[PasswordField.STORED_KEY.ordinal()],
+                    "user '" + user.getName() + "' stored key");
+            serverKey = Strings.decodePrivateBase64(passwordFields[PasswordField.SERVER_KEY.ordinal()],
+                    "user '" + user.getName() + "' server key");
             iterationCount = Integer.parseInt(passwordFields[PasswordField.ITERATION_COUNT.ordinal()]);
             exception = null;
         }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CramMd5Base64HashedNegotiator.java b/broker-core/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CramMd5Base64HashedNegotiator.java
index 3d3a551..91c9daa 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CramMd5Base64HashedNegotiator.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CramMd5Base64HashedNegotiator.java
@@ -27,21 +27,16 @@ import org.apache.qpid.server.util.Strings;
 public class CramMd5Base64HashedNegotiator extends AbstractCramMd5Negotiator
 {
     public static final String MECHANISM = "CRAM-MD5-HASHED";
-    private static final PasswordTransformer BASE64_PASSWORD_TRANSFORMER =
-            new PasswordTransformer()
-            {
-                @Override
-                public char[] transform(final char[] passwordData)
-                {
-                    byte[] passwordBytes = Strings.decodeBase64(new String(passwordData));
-                    char[] password = new char[passwordBytes.length];
-                    for (int i = 0; i < passwordBytes.length; i++)
-                    {
-                        password[i] = (char) passwordBytes[i];
-                    }
-                    return password;
-                }
-            };
+    private static final PasswordTransformer BASE64_PASSWORD_TRANSFORMER = passwordData ->
+    {
+        final byte[] passwordBytes = Strings.decodePrivateBase64(new String(passwordData), "CRAM MD5 hashed password");
+        final char[] password = new char[passwordBytes.length];
+        for (int i = 0; i < passwordBytes.length; i++)
+        {
+            password[i] = (char) passwordBytes[i];
+        }
+        return password;
+    };
 
     public CramMd5Base64HashedNegotiator(final PasswordCredentialManagingAuthenticationProvider<?> authenticationProvider,
                                          final String localFQDN,
diff --git a/broker-core/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CramMd5Base64HexNegotiator.java b/broker-core/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CramMd5Base64HexNegotiator.java
index 22fc95c..edcbff5 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CramMd5Base64HexNegotiator.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CramMd5Base64HexNegotiator.java
@@ -27,26 +27,19 @@ import org.apache.qpid.server.util.Strings;
 public class CramMd5Base64HexNegotiator extends AbstractCramMd5Negotiator
 {
     public static final String MECHANISM = "CRAM-MD5-HEX";
-    private static final PasswordTransformer BASE64_HEX_PASSWORD_TRANSFORMER =
-            new PasswordTransformer()
-            {
-                private final char[] HEX_CHARACTERS =
-                        {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
-
-                @Override
-                public char[] transform(final char[] passwordData)
-                {
-                    byte[] passwordBytes = Strings.decodeBase64(new String(passwordData));
-                    char[] password = new char[passwordBytes.length * 2];
-
-                    for (int i = 0; i < passwordBytes.length; i++)
-                    {
-                        password[2 * i] = HEX_CHARACTERS[(((int) passwordBytes[i]) & 0xf0) >> 4];
-                        password[(2 * i) + 1] = HEX_CHARACTERS[(((int) passwordBytes[i]) & 0x0f)];
-                    }
-                    return password;
-                }
-            };
+    private static final char[] HEX_CHARACTERS =
+            {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+    private static final PasswordTransformer BASE64_HEX_PASSWORD_TRANSFORMER = passwordData ->
+    {
+        final byte[] passwordBytes = Strings.decodePrivateBase64(new String(passwordData), "CRAM MD5 hex password");
+        final char[] password = new char[passwordBytes.length * 2];
+        for (int i = 0; i < passwordBytes.length; i++)
+        {
+            password[2 * i] = HEX_CHARACTERS[(((int) passwordBytes[i]) & 0xf0) >> 4];
+            password[(2 * i) + 1] = HEX_CHARACTERS[(((int) passwordBytes[i]) & 0x0f)];
+        }
+        return password;
+    };
 
     public CramMd5Base64HexNegotiator(final PasswordCredentialManagingAuthenticationProvider<?> authenticationProvider,
                                       final String localFQDN,
diff --git a/broker-core/src/main/java/org/apache/qpid/server/util/Strings.java b/broker-core/src/main/java/org/apache/qpid/server/util/Strings.java
index 0e468fb..b62fe7f 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/util/Strings.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/util/Strings.java
@@ -21,7 +21,6 @@
 package org.apache.qpid.server.util;
 
 import java.io.UnsupportedEncodingException;
-import java.io.Writer;
 import java.nio.ByteBuffer;
 import java.util.Arrays;
 import java.util.Base64;
@@ -129,17 +128,34 @@ public final class Strings
         return resolver;
     }
 
+    public static byte[] decodePrivateBase64(String base64String, String description)
+    {
+        if (isInvalidBase64String(base64String))
+        {
+            // do not add base64String to exception message as it can contain private data
+            throw new IllegalArgumentException("Cannot convert " + description +
+                    " string to a byte[] - it does not appear to be base64 data");
+        }
+
+        return Base64.getDecoder().decode(base64String);
+    }
+
     public static byte[] decodeBase64(String base64String)
     {
-        base64String = base64String.replaceAll("\\s","");
-        if(!base64String.matches("^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$"))
+        if (isInvalidBase64String(base64String))
         {
-            throw new IllegalArgumentException("Cannot convert string '"+ base64String+ "'to a byte[] - it does not appear to be base64 data");
+            throw new IllegalArgumentException("Cannot convert string '" + base64String +
+                    "' to a byte[] - it does not appear to be base64 data");
         }
 
         return Base64.getDecoder().decode(base64String);
     }
 
+    private static boolean isInvalidBase64String(String base64String)
+    {
+        return !base64String.replaceAll("\\s", "").matches("^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$");
+    }
+
     public static interface Resolver
     {
         String resolve(String variable, final Resolver resolver);
diff --git a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/auth/BasicAuthPreemptiveAuthenticator.java b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/auth/BasicAuthPreemptiveAuthenticator.java
index 76353f8..c79d4bd 100644
--- a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/auth/BasicAuthPreemptiveAuthenticator.java
+++ b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/auth/BasicAuthPreemptiveAuthenticator.java
@@ -45,16 +45,16 @@ public class BasicAuthPreemptiveAuthenticator implements HttpRequestPreemptiveAu
     @Override
     public Subject attemptAuthentication(final HttpServletRequest request, final HttpManagementConfiguration managementConfiguration)
     {
-        String header = request.getHeader("Authorization");
+        final String header = request.getHeader("Authorization");
         final Port<?> port = managementConfiguration.getPort(request);
         final AuthenticationProvider<?> authenticationProvider = managementConfiguration.getAuthenticationProvider(request);
-        SubjectCreator subjectCreator = port.getSubjectCreator(request.isSecure(), request.getServerName());
+        final SubjectCreator subjectCreator = port.getSubjectCreator(request.isSecure(), request.getServerName());
 
         if (header != null && authenticationProvider instanceof UsernamePasswordAuthenticationProvider)
         {
-            UsernamePasswordAuthenticationProvider<?> namePasswdAuthProvider = (UsernamePasswordAuthenticationProvider<?>)authenticationProvider;
+            final UsernamePasswordAuthenticationProvider<?> namePasswdAuthProvider = (UsernamePasswordAuthenticationProvider<?>)authenticationProvider;
 
-            String[] tokens = header.split("\\s");
+            final String[] tokens = header.split("\\s");
             if (tokens.length >= 2 && "BASIC".equalsIgnoreCase(tokens[0]))
             {
                 boolean isBasicAuthSupported = false;
@@ -68,19 +68,17 @@ public class BasicAuthPreemptiveAuthenticator implements HttpRequestPreemptiveAu
                 }
                 if (isBasicAuthSupported)
                 {
-                    String base64UsernameAndPassword = tokens[1];
-                    String[] credentials = (new String(Strings.decodeBase64(base64UsernameAndPassword),
-                                                       StandardCharsets.UTF_8)).split(":", 2);
+                    final String base64UsernameAndPassword = tokens[1];
+                    final String[] credentials = new String(Strings.decodePrivateBase64(base64UsernameAndPassword,
+                            "basic authentication credentials"), StandardCharsets.UTF_8).split(":", 2);
                     if (credentials.length == 2)
                     {
-                        String username = credentials[0];
-                        String password = credentials[1];
-                        AuthenticationResult authenticationResult = namePasswdAuthProvider.authenticate(username, password);
-                        SubjectAuthenticationResult result = subjectCreator.createResultWithGroups(authenticationResult);
+                        final String username = credentials[0];
+                        final String password = credentials[1];
+                        final AuthenticationResult authenticationResult = namePasswdAuthProvider.authenticate(username, password);
+                        final SubjectAuthenticationResult result = subjectCreator.createResultWithGroups(authenticationResult);
 
                         return result.getSubject();
-
-
                     }
                 }
             }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[qpid-broker-j] 08/10: QPID-8454:[Broker-J] Add Prometheus integration

Posted by or...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

orudyy pushed a commit to branch 7.1.x
in repository https://gitbox.apache.org/repos/asf/qpid-broker-j.git

commit d547af8d35306a22207d6ae25af3ff94cd7c6893
Author: Dedeepya T <de...@yahoo.co.in>
AuthorDate: Tue Aug 25 15:11:50 2020 +0100

    QPID-8454:[Broker-J] Add Prometheus integration
    
    (cherry picked from commit e9794802df6ee22bd3b9dc55faffc26d74459c71)
---
 .../dependency-verification/DEPENDENCIES_REFERENCE |   6 +
 .../java/org/apache/qpid/server/model/Broker.java  |  80 +++--
 .../qpid/server/model/BrokerAttributeInjector.java |  20 +-
 .../org/apache/qpid/server/model/BrokerLogger.java |   4 +-
 .../model/ConfiguredObjectInjectedStatistic.java   |  20 +-
 .../model/ConfiguredObjectMethodStatistic.java     |  12 +
 .../server/model/ConfiguredObjectStatistic.java    |   4 +
 .../org/apache/qpid/server/model/Connection.java   |  14 +-
 .../org/apache/qpid/server/model/Consumer.java     |   4 +-
 .../org/apache/qpid/server/model/Exchange.java     |  10 +-
 .../apache/qpid/server/model/ManagedStatistic.java |   2 +
 .../java/org/apache/qpid/server/model/Queue.java   |  36 +--
 .../java/org/apache/qpid/server/model/Session.java |   2 +-
 .../qpid/server/model/VirtualHostLogger.java       |   4 +-
 .../apache/qpid/server/model/port/AmqpPort.java    |  12 +-
 .../apache/qpid/server/plugin/ContentFactory.java} |  13 +-
 .../virtualhost/QueueManagingVirtualHost.java      |  28 +-
 .../hierarchy/InjectedAttributeTest.java           |  16 +-
 .../testmodels/hierarchy/TestAbstractCarImpl.java  |  21 ++
 .../hierarchy/TestAbstractEngineImpl.java          |   7 +
 .../hierarchy/TestAbstractInstrumentPanelImpl.java |   2 +
 .../hierarchy/TestAbstractSensorImpl.java          |   9 +
 .../server/model/testmodels/hierarchy/TestCar.java |  14 +
 .../model/testmodels/hierarchy/TestEngine.java     |   6 +
 .../model/testmodels/hierarchy/TestSensor.java     |   5 +
 .../hierarchy/TestTemperatureSensorImpl.java       |   9 +
 broker-plugins/management-http/pom.xml             |   5 +
 .../server/management/plugin/HttpManagement.java   |  18 ++
 .../plugin/HttpManagementConfiguration.java        |   5 +
 .../management/plugin/servlet/ContentServlet.java  |  95 ++++++
 .../plugin/servlet/rest/AbstractServlet.java       |  21 +-
 broker-plugins/prometheus-exporter/pom.xml         |  70 ++++
 .../IncludeDisabledStatisticPredicate.java         |  26 +-
 .../server/prometheus/IncludeMetricPredicate.java  |  26 +-
 .../prometheus/PrometheusContentFactory.java       | 105 ++++++
 .../qpid/server/prometheus/QpidCollector.java      | 257 +++++++++++++++
 .../prometheus/PrometheusContentFactoryTest.java   | 176 ++++++++++
 .../qpid/server/prometheus/QpidCollectorTest.java  | 359 +++++++++++++++++++++
 .../src/docbkx/Java-Broker-Management-Channels.xml |   1 +
 .../channels/Java-Broker-Management-Metrics.xml    |  48 +++
 pom.xml                                            |  20 ++
 .../metrics/BrokerMetricsAuthenticationTest.java   |  52 +++
 .../qpid/tests/http/metrics/BrokerMetricsTest.java |  80 +++++
 .../qpid/tests/http/metrics/TestMetricsHelper.java |  93 ++++++
 .../tests/http/metrics/VirtualHostMetricsTest.java |  25 +-
 45 files changed, 1712 insertions(+), 130 deletions(-)

diff --git a/apache-qpid-broker-j/src/main/assembly/dependency-verification/DEPENDENCIES_REFERENCE b/apache-qpid-broker-j/src/main/assembly/dependency-verification/DEPENDENCIES_REFERENCE
index c50e39d..d92150c 100644
--- a/apache-qpid-broker-j/src/main/assembly/dependency-verification/DEPENDENCIES_REFERENCE
+++ b/apache-qpid-broker-j/src/main/assembly/dependency-verification/DEPENDENCIES_REFERENCE
@@ -27,6 +27,10 @@ Apache Qpid Broker-J Bundles
 From: 'an unknown organization'
   - Guava: Google Core Libraries for Java (https://github.com/google/guava/guava) com.google.guava:guava:bundle:27.0-jre
     License: The Apache Software License, Version 2.0  (http://www.apache.org/licenses/LICENSE-2.0.txt)
+  - Prometheus Java Simpleclient (http://github.com/prometheus/client_java/simpleclient) io.prometheus:simpleclient:bundle:0.9.0
+    License: The Apache Software License, Version 2.0  (http://www.apache.org/licenses/LICENSE-2.0.txt)
+  - Prometheus Java Simpleclient Common (http://github.com/prometheus/client_java/simpleclient_common) io.prometheus:simpleclient_common:bundle:0.9.0
+    License: The Apache Software License, Version 2.0  (http://www.apache.org/licenses/LICENSE-2.0.txt)
   - dgrid (http://webjars.org) org.webjars.bower:dgrid:jar:1.2.1
     License: BSD 3-Clause  (https://spdx.org/licenses/BSD 3-Clause#licenseText)
   - dstore (http://webjars.org) org.webjars.bower:dstore:jar:1.1.2
@@ -111,6 +115,8 @@ From: 'The Apache Software Foundation' (https://www.apache.org/)
     License: Apache License, Version 2.0  (https://www.apache.org/licenses/LICENSE-2.0.txt)
   - Apache Qpid Broker-J Memory Message Store Plug-in (http://qpid.apache.org/components/broker-plugins/qpid-broker-plugins-memory-store) org.apache.qpid:qpid-broker-plugins-memory-store:jar
     License: Apache License, Version 2.0  (https://www.apache.org/licenses/LICENSE-2.0.txt)
+  - qpid-broker-plugins-prometheus-exporter (http://qpid.apache.org/components/broker-plugins/qpid-broker-plugins-prometheus-exporter) org.apache.qpid:qpid-broker-plugins-prometheus-exporter:jar
+    License: Apache License, Version 2.0  (https://www.apache.org/licenses/LICENSE-2.0.txt)
   - Apache Qpid Broker-J WebSocket Plug-in (http://qpid.apache.org/components/broker-plugins/qpid-broker-plugins-websocket) org.apache.qpid:qpid-broker-plugins-websocket:jar
     License: Apache License, Version 2.0  (https://www.apache.org/licenses/LICENSE-2.0.txt)
 
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/Broker.java b/broker-core/src/main/java/org/apache/qpid/server/model/Broker.java
index 62e2519..24bdccb 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/Broker.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/Broker.java
@@ -189,36 +189,52 @@ public interface Broker<X extends Broker<X>> extends ConfiguredObject<X>, EventL
     String getModelVersion();
 
     @SuppressWarnings("unused")
-    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.BYTES, label = "Inbound",
-                      description = "Total size of all messages received by the Broker.")
+    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE,
+            units = StatisticUnit.BYTES,
+            label = "Inbound",
+            description = "Total size of all messages received by the Broker.",
+            metricName = "inbound_bytes_count")
     long getBytesIn();
 
     @SuppressWarnings("unused")
-    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.BYTES, label = "Outbound",
-                      description = "Total size of all messages delivered by the Broker.")
+    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE,
+            units = StatisticUnit.BYTES,
+            label = "Outbound",
+            description = "Total size of all messages delivered by the Broker.",
+            metricName = "outbound_bytes_count")
     long getBytesOut();
 
     @SuppressWarnings("unused")
-    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES, label = "Inbound",
-                      description = "Total number of messages received by the Broker.")
+    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE,
+            units = StatisticUnit.MESSAGES,
+            label = "Inbound",
+            description = "Total number of messages received by the Broker.",
+            metricName = "inbound_messages_count")
     long getMessagesIn();
 
     @SuppressWarnings("unused")
-    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES, label = "Outbound",
-                      description = "Total number of messages delivered by the Broker.")
+    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE,
+            units = StatisticUnit.MESSAGES,
+            label = "Outbound",
+            description = "Total number of messages delivered by the Broker.",
+            metricName = "outbound_messages_count")
     long getMessagesOut();
 
 
     @SuppressWarnings("unused")
-    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES,
+    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE,
+            units = StatisticUnit.MESSAGES,
             label = "Transacted Inbound",
-            description = "Total number of messages delivered by the Broker within a transaction.")
+            description = "Total number of messages delivered by the Broker within a transaction.",
+            metricName = "inbound_transacted_messages_count")
     long getTransactedMessagesIn();
 
     @SuppressWarnings("unused")
-    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES,
+    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE,
+            units = StatisticUnit.MESSAGES,
             label = "Transacted Outbound",
-            description = "Total number of messages received by the Broker within a transaction.")
+            description = "Total number of messages received by the Broker within a transaction.",
+            metricName = "outbound_transacted_messages_count")
     long getTransactedMessagesOut();
 
     @ManagedOperation(nonModifying = true,
@@ -249,37 +265,44 @@ public interface Broker<X extends Broker<X>> extends ConfiguredObject<X>, EventL
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME,
-                      units = StatisticUnit.COUNT,
-                      label = "Live threads",
-                      description = "Number of live threads")
+            units = StatisticUnit.COUNT,
+            label = "Live threads",
+            description = "Number of live threads",
+            metricName = "live_threads_total",
+            metricDisabled = true)
     int getNumberOfLiveThreads();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME,
-                      units = StatisticUnit.BYTES,
-                      label = "Used Heap Memory Size",
-                      description = "Size of used heap memory")
+            units = StatisticUnit.BYTES,
+            label = "Used Heap Memory Size",
+            description = "Size of used heap memory",
+            metricDisabled = true)
     long getUsedHeapMemorySize();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME,
-                      units = StatisticUnit.BYTES,
-                      label = "Used Direct Memory Size",
-                      description = "Size of used direct memory")
+            units = StatisticUnit.BYTES,
+            label = "Used Direct Memory Size",
+            description = "Size of used direct memory",
+            metricDisabled = true)
     long getUsedDirectMemorySize();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME,
-                      units = StatisticUnit.BYTES,
-                      label = "Direct Memory Total Capacity",
-                      description = "Total capacity of direct memory allocated for the Broker process")
+            units = StatisticUnit.BYTES,
+            label = "Direct Memory Total Capacity",
+            description = "Total capacity of direct memory allocated for the Broker process",
+            metricName = "direct_memory_capacity_bytes_total",
+            metricDisabled = true)
     long getDirectMemoryTotalCapacity();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME,
-                      units = StatisticUnit.COUNT,
-                      label = "Number Of Object Pending Finalization",
-                      description = "Number of objects pending finalization")
+            units = StatisticUnit.COUNT,
+            label = "Number Of Object Pending Finalization",
+            description = "Number of objects pending finalization",
+            metricDisabled = true)
     int getNumberOfObjectsPendingFinalization();
 
     @SuppressWarnings("unused")
@@ -300,7 +323,8 @@ public interface Broker<X extends Broker<X>> extends ConfiguredObject<X>, EventL
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME,
             units = StatisticUnit.BYTES,
             label = "Maximum recorded size of inbound messages",
-            description = "Maximum size of messages published into the Broker since start-up.")
+            description = "Maximum size of messages published into the Broker since start-up.",
+            metricName = "inbound_message_size_high_watermark")
     long getInboundMessageSizeHighWatermark();
 
     @ManagedOperation(nonModifying = true,
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/BrokerAttributeInjector.java b/broker-core/src/main/java/org/apache/qpid/server/model/BrokerAttributeInjector.java
index 61be55f..a80a041 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/BrokerAttributeInjector.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/BrokerAttributeInjector.java
@@ -167,7 +167,9 @@ public class BrokerAttributeInjector implements ConfiguredObjectAttributeInjecto
                                                                 _typeValidator,
                                                                 StatisticUnit.BYTES,
                                                                 StatisticType.POINT_IN_TIME,
-                                                                memoryPoolMXBean.getName() + " Memory Used");
+                                                                memoryPoolMXBean.getName() + " Memory Used",
+                                                                null,
+                                                                true);
                 statistics.add(injectedStatistic);
             }
             catch (NoSuchMethodException e)
@@ -195,7 +197,9 @@ public class BrokerAttributeInjector implements ConfiguredObjectAttributeInjecto
                                                                 StatisticUnit.COUNT,
                                                                 StatisticType.CUMULATIVE,
                                                                 garbageCollectorMXBean.getName()
-                                                                + " GC Collection Time");
+                                                                + " GC Collection Time",
+                                                                null,
+                                                                true);
                 statistics.add(injectedStatistic);
             }
             catch (NoSuchMethodException e)
@@ -218,7 +222,9 @@ public class BrokerAttributeInjector implements ConfiguredObjectAttributeInjecto
                                                                 StatisticUnit.COUNT,
                                                                 StatisticType.CUMULATIVE,
                                                                 garbageCollectorMXBean.getName()
-                                                                + " GC Collection Count");
+                                                                + " GC Collection Count",
+                                                                null,
+                                                                true);
                 statistics.add(injectedStatistic);
             }
             catch (NoSuchMethodException e)
@@ -263,7 +269,9 @@ public class BrokerAttributeInjector implements ConfiguredObjectAttributeInjecto
                                                                 StatisticUnit.TIME_DURATION,
                                                                 StatisticType.CUMULATIVE,
                                                                 _operatingSystemMXBeanClass.getName()
-                                                                + " Process CPU Time");
+                                                                + " Process CPU Time",
+                                                                "process_cpu_time_nanoseconds",
+                                                                true);
                 statistics.add(injectedStatistic);
 
             }
@@ -308,7 +316,9 @@ public class BrokerAttributeInjector implements ConfiguredObjectAttributeInjecto
                                                                 StatisticUnit.COUNT,
                                                                 StatisticType.POINT_IN_TIME,
                                                                 _operatingSystemMXBean.getName()
-                                                                + " Process CPU Load");
+                                                                + " Process CPU Load",
+                                                                null,
+                                                                true);
                 statistics.add(injectedStatistic);
 
             }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/BrokerLogger.java b/broker-core/src/main/java/org/apache/qpid/server/model/BrokerLogger.java
index 07e61cd..8c4ad5b 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/BrokerLogger.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/BrokerLogger.java
@@ -28,9 +28,9 @@ public interface BrokerLogger<X extends BrokerLogger<X>> extends ConfiguredObjec
 
     void stopLogging();
 
-    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.COUNT, label = "Errors")
+    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.COUNT, label = "Errors", metricName = "errors_count")
     long getErrorCount();
 
-    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.COUNT, label = "Warnings")
+    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.COUNT, label = "Warnings", metricName = "warnings_count")
     long getWarnCount();
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectInjectedStatistic.java b/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectInjectedStatistic.java
index 95c8507..f1d9c6b 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectInjectedStatistic.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectInjectedStatistic.java
@@ -41,6 +41,8 @@ final public class ConfiguredObjectInjectedStatistic<C extends ConfiguredObject,
     private final StatisticType _type;
     private final String _label;
     private final Object[] _staticParams;
+    private final String _metricName;
+    private final boolean _metricDisabled;
 
     public ConfiguredObjectInjectedStatistic(final String name,
                                              final Method method,
@@ -49,7 +51,9 @@ final public class ConfiguredObjectInjectedStatistic<C extends ConfiguredObject,
                                              final TypeValidator typeValidator,
                                              final StatisticUnit units,
                                              final StatisticType type,
-                                             final String label)
+                                             final String label,
+                                             final String metricName,
+                                             final boolean metricDisabled)
     {
         super(name,
               (Class<T>) AttributeValueConverter.getTypeFromMethod(method), method.getGenericReturnType(), typeValidator);
@@ -57,6 +61,8 @@ final public class ConfiguredObjectInjectedStatistic<C extends ConfiguredObject,
         _type = type;
         _label = label;
         _staticParams = staticParams == null ? new Object[0] : staticParams;
+        _metricName = metricName;
+        _metricDisabled = metricDisabled;
         if(!(method.getParameterTypes().length == 1 + _staticParams.length
              && ConfiguredObject.class.isAssignableFrom(method.getParameterTypes()[0])
              && Modifier.isStatic(method.getModifiers())
@@ -147,4 +153,16 @@ final public class ConfiguredObjectInjectedStatistic<C extends ConfiguredObject,
         }
 
     }
+
+    @Override
+    public String getMetricName()
+    {
+        return _metricName;
+    }
+
+    @Override
+    public boolean isMetricDisabled()
+    {
+        return _metricDisabled;
+    }
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectMethodStatistic.java b/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectMethodStatistic.java
index 2cc2fe9..528d80e 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectMethodStatistic.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectMethodStatistic.java
@@ -66,4 +66,16 @@ public final class ConfiguredObjectMethodStatistic<C extends ConfiguredObject, T
     {
         return _annotation.label();
     }
+
+    @Override
+    public String getMetricName()
+    {
+        return _annotation.metricName();
+    }
+
+    @Override
+    public boolean isMetricDisabled()
+    {
+        return _annotation.metricDisabled();
+    }
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectStatistic.java b/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectStatistic.java
index cc22d62..4585b42 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectStatistic.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectStatistic.java
@@ -29,4 +29,8 @@ public interface ConfiguredObjectStatistic<C extends ConfiguredObject, T extends
     StatisticType getStatisticType();
 
     String getLabel();
+
+    String getMetricName();
+
+    boolean isMetricDisabled();
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/Connection.java b/broker-core/src/main/java/org/apache/qpid/server/model/Connection.java
index 62cefc1..0638e53 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/Connection.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/Connection.java
@@ -117,24 +117,24 @@ public interface Connection<X extends Connection<X>> extends ConfiguredObject<X>
     // See also QPID-7689: https://issues.apache.org/jira/browse/QPID-7689?focusedCommentId=16022923#comment-16022923
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.BYTES, label = "Inbound",
-                      description = "Total size of all messages received by this connection.")
+                      description = "Total size of all messages received by this connection.", metricName = "inbound_bytes_count")
     long getBytesIn();
 
     // currently this reports outbound message content size without header.
     // See also QPID-7689: https://issues.apache.org/jira/browse/QPID-7689?focusedCommentId=16022923#comment-16022923
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.BYTES, label = "Outbound",
-                      description = "Total size of all messages delivered by this connection.")
+                      description = "Total size of all messages delivered by this connection.", metricName = "outbound_bytes_count")
     long getBytesOut();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES, label = "Inbound",
-                      description = "Total number of messages delivered by this connection.")
+                      description = "Total number of messages delivered by this connection.", metricName = "inbound_messages_count")
     long getMessagesIn();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES, label = "Outbound",
-                      description = "Total number of messages received by this connection.")
+                      description = "Total number of messages received by this connection.", metricName = "outbound_messages_count")
     long getMessagesOut();
 
     @SuppressWarnings("unused")
@@ -162,7 +162,7 @@ public interface Connection<X extends Connection<X>> extends ConfiguredObject<X>
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.COUNT, label = "Sessions",
-                      description = "Current number of sessions belonging to this connection.")
+                      description = "Current number of sessions belonging to this connection.", metricName = "sessions_total")
     int getSessionCount();
 
     @SuppressWarnings("unused")
@@ -188,12 +188,12 @@ public interface Connection<X extends Connection<X>> extends ConfiguredObject<X>
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES, label = "Transacted Inbound",
-            description = "Total number of messages delivered by this connection within a transaction.")
+            description = "Total number of messages delivered by this connection within a transaction.", metricName = "transacted_inbound_messages_count")
     long getTransactedMessagesIn();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES, label = "Transacted Outbound",
-            description = "Total number of messages received by this connection within a transaction.")
+            description = "Total number of messages received by this connection within a transaction.", metricName = "transacted_outbound_messages_count")
     long getTransactedMessagesOut();
 
     //children
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/Consumer.java b/broker-core/src/main/java/org/apache/qpid/server/model/Consumer.java
index 9db4b21..240d8a6 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/Consumer.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/Consumer.java
@@ -70,10 +70,10 @@ public interface Consumer<X extends Consumer<X,T>, T extends ConsumerTarget> ext
                         + "consumers.  Priority 2147483647 is the highest priority.")
     int getPriority();
 
-    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.BYTES, label = "Outbound")
+    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.BYTES, label = "Outbound", metricName = "outbound_bytes_count")
     long getBytesOut();
 
-    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES, label = "Outbound")
+    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES, label = "Outbound", metricName = "outbound_messages_count")
     long getMessagesOut();
 
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.BYTES, label = "Prefetch")
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/Exchange.java b/broker-core/src/main/java/org/apache/qpid/server/model/Exchange.java
index 800f57c..5e2d68f 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/Exchange.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/Exchange.java
@@ -88,27 +88,27 @@ public interface Exchange<X extends Exchange<X>> extends ConfiguredObject<X>, Me
     // Statistics
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.COUNT, label = "Bindings",
-                      description = "Current number of bindings to this exchange.")
+                      description = "Current number of bindings to this exchange.", metricName = "bindings_total")
     long getBindingCount();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.BYTES, label = "Dropped",
-                      description = "Total size of all unroutable messages dropped by this exchange.")
+                      description = "Total size of all unroutable messages dropped by this exchange.", metricName = "dropped_bytes_count")
     long getBytesDropped();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.BYTES, label = "Inbound",
-                      description = "Total size of messages received by this exchange.")
+                      description = "Total size of messages received by this exchange.", metricName = "inbound_bytes_count")
     long getBytesIn();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES, label = "Dropped",
-                      description = "Number of unroutable messages dropped by this exchange.")
+                      description = "Number of unroutable messages dropped by this exchange.", metricName = "dropped_messages_count")
     long getMessagesDropped();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES, label = "Inbound",
-                      description = "Number of messages received by this exchange.")
+                      description = "Number of messages received by this exchange.", metricName = "inbound_messages_count")
     long getMessagesIn();
 
 
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/ManagedStatistic.java b/broker-core/src/main/java/org/apache/qpid/server/model/ManagedStatistic.java
index d9bb129..1bcd52e 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/ManagedStatistic.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/ManagedStatistic.java
@@ -33,4 +33,6 @@ public @interface ManagedStatistic
     String label() default "";
     StatisticUnit units();
     StatisticType statisticType();
+    String metricName()  default "";
+    boolean metricDisabled() default false;
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/Queue.java b/broker-core/src/main/java/org/apache/qpid/server/model/Queue.java
index 3920a14..bfb7e16 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/Queue.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/Queue.java
@@ -370,17 +370,17 @@ public interface Queue<X extends Queue<X>> extends ConfiguredObject<X>,
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.COUNT, label = "Bindings",
-                      description = "Current number of bindings to this queue.")
+                      description = "Current number of bindings to this queue.", metricName = "bindings_total")
     int getBindingCount();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.COUNT, label = "Consumers",
-                      description = "Current number of consumers attached to this queue.")
+                      description = "Current number of consumers attached to this queue.", metricName = "consumers_total")
     int getConsumerCount();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.COUNT, label = "Consumers with credit",
-                      description = "Current number of consumers attached to this queue with credit")
+                      description = "Current number of consumers attached to this queue with credit", metricName = "consumers_with_credit_total")
     int getConsumerCountWithCredit();
 
     @SuppressWarnings("unused")
@@ -405,42 +405,42 @@ public interface Queue<X extends Queue<X>> extends ConfiguredObject<X>,
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.BYTES, label = "Queue Depth",
-                      description = "Current size of all messages enqueued by this queue.")
+                      description = "Current size of all messages enqueued by this queue.", metricName = "depth_bytes_total")
     long getQueueDepthBytes();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.MESSAGES, label = "Queue Depth",
-                      description = "Current number of messages enqueued by this queue.")
+                      description = "Current number of messages enqueued by this queue.", metricName = "depth_messages_total")
     int getQueueDepthMessages();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.BYTES, label = "Delivered",
-                      description = "Total size of all messages delivered by this queue.")
+                      description = "Total size of all messages delivered by this queue.", metricName = "dequeued_bytes_count")
     long getTotalDequeuedBytes();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES, label = "Delivered",
-                      description = "Total number of messages delivered by this queue.")
+                      description = "Total number of messages delivered by this queue.", metricName = "dequeued_messages_count")
     long getTotalDequeuedMessages();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.BYTES, label = "Enqueued",
-                      description = "Total size of all messages received by this queue.")
+                      description = "Total size of all messages received by this queue.", metricName = "enqueue_bytes_count")
     long getTotalEnqueuedBytes();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES, label = "Enqueued",
-                      description = "Total number of messages received by this queue.")
+                      description = "Total number of messages received by this queue.", metricName = "enqueued_messages_count")
     long getTotalEnqueuedMessages();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.BYTES, label = "Expired",
-            description = "Total size of all messages expired by message time-to-live on this queue.")
+            description = "Total size of all messages expired by message time-to-live on this queue.", metricName = "expired_bytes_count")
     long getTotalExpiredBytes();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES, label = "Expired",
-            description = "Total number of messages expired by message time-to-live on this queue.")
+            description = "Total number of messages expired by message time-to-live on this queue.", metricName = "expired_messages_count")
     long getTotalExpiredMessages();
 
 
@@ -466,37 +466,37 @@ public interface Queue<X extends Queue<X>> extends ConfiguredObject<X>,
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.BYTES, label = "Available HWM",
-                      description = "Maximum recorded size of available messages.")
+                      description = "Maximum recorded size of available messages.", metricName = "available_bytes_high_water_mark")
     long getAvailableBytesHighWatermark();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.MESSAGES, label = "Available HWM",
-                      description = "Maximum recorded number of available messages.")
+                      description = "Maximum recorded number of available messages.", metricName = "available_messages_high_water_mark")
     int getAvailableMessagesHighWatermark();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.BYTES, label = "Queue Depth HWM",
-                      description = "Maximum recorded size of enqueued messages.")
+                      description = "Maximum recorded size of enqueued messages.", metricName = "depth_bytes_high_water_mark")
     long getQueueDepthBytesHighWatermark();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.MESSAGES, label = "Queue Depth HWM",
-                      description = "Maximum recorded number of enqueued messages.")
+                      description = "Maximum recorded number of enqueued messages.", metricName = "depth_messages_high_water_mark")
     int getQueueDepthMessagesHighWatermark();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.TIME_DURATION, label = "Oldest Message",
-                      description = "Current age of oldest message on the queue.")
+                      description = "Current age of oldest message on the queue.", metricName = "oldest_message_age_milliseconds")
     long getOldestMessageAge();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.BYTES, label = "Malformed",
-            description = "Total size of enqueued malformed messages.")
+            description = "Total size of enqueued malformed messages.", metricName = "malformed_bytes_count")
     long getTotalMalformedBytes();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES, label = "Malformed",
-            description = "Total number of enqueued malformed messages.")
+            description = "Total number of enqueued malformed messages.", metricName = "malformed_messages_count")
     long getTotalMalformedMessages();
 
     @ManagedOperation(description = "move messages from this queue to another", changesConfiguredObjectState = false)
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/Session.java b/broker-core/src/main/java/org/apache/qpid/server/model/Session.java
index af1084e..343e5ba 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/Session.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/Session.java
@@ -55,7 +55,7 @@ public interface Session<X extends Session<X>> extends ConfiguredObject<X>
     boolean isProducerFlowBlocked();
 
 
-    @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.COUNT, label = "Consumers")
+    @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.COUNT, label = "Consumers", metricName = "consumers_total")
     long getConsumerCount();
 
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.MESSAGES, label = "Prefetched")
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/VirtualHostLogger.java b/broker-core/src/main/java/org/apache/qpid/server/model/VirtualHostLogger.java
index c30f6a7..6599a0f 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/VirtualHostLogger.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/VirtualHostLogger.java
@@ -25,9 +25,9 @@ public interface VirtualHostLogger <X extends VirtualHostLogger<X>> extends Conf
 {
     void stopLogging();
 
-    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.COUNT, label = "Errors")
+    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.COUNT, label = "Errors", metricName = "errors_count")
     long getErrorCount();
 
-    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.COUNT, label = "Warnings")
+    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.COUNT, label = "Warnings", metricName = "warnings_count")
     long getWarnCount();
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPort.java b/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPort.java
index f88b99a..530d603 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPort.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPort.java
@@ -159,12 +159,16 @@ public interface AmqpPort<X extends AmqpPort<X>> extends Port<X>
     @ManagedAttribute( defaultValue = "${" + PORT_MAX_OPEN_CONNECTIONS + "}" )
     int getMaxOpenConnections();
 
-    @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.COUNT, label = "Open Connections",
-                      description = "Current number of connections made through this port")
+    @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.COUNT,
+            label = "Open Connections",
+            description = "Current number of connections made through this port",
+            metricName = "open_connections_total")
     int getConnectionCount();
 
-    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.COUNT, label = "Total Connections",
-            description = "Total number of connections made through this port since broker startup")
+    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.COUNT,
+            label = "Total Connections",
+            description = "Total number of connections made through this port since broker startup",
+            metricName = "aggregate_connection_count")
     long getTotalConnectionCount();
 
     @DerivedAttribute(description = "Maximum time allowed for a new connection to send a protocol header."
diff --git a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestSensor.java b/broker-core/src/main/java/org/apache/qpid/server/plugin/ContentFactory.java
similarity index 75%
copy from broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestSensor.java
copy to broker-core/src/main/java/org/apache/qpid/server/plugin/ContentFactory.java
index 41e07f2..bc0ad33 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestSensor.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/plugin/ContentFactory.java
@@ -1,5 +1,4 @@
 /*
- *
  * 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
@@ -18,13 +17,15 @@
  * under the License.
  *
  */
-package org.apache.qpid.server.model.testmodels.hierarchy;
+
+package org.apache.qpid.server.plugin;
+
+import java.util.Map;
 
 import org.apache.qpid.server.model.ConfiguredObject;
-import org.apache.qpid.server.model.ManagedObject;
+import org.apache.qpid.server.model.Content;
 
-@ManagedObject( defaultType = TestTemperatureSensorImpl.TEST_TEMPERATURE_SENSOR_TYPE)
-public interface TestSensor<X extends TestSensor<X>> extends ConfiguredObject<X>
+public interface ContentFactory extends Pluggable
 {
-
+    Content createContent(ConfiguredObject<?> object, Map<String, String[]> filter);
 }
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..4cd276a 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
@@ -210,69 +210,69 @@ public interface QueueManagingVirtualHost<X extends QueueManagingVirtualHost<X>>
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.COUNT, label = "Queues",
-                      description = "Current number of queues on this virtualhost.")
+                      description = "Current number of queues on this virtualhost.", metricName = "queues_total")
     long getQueueCount();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.COUNT, label = "Exchanges",
-                      description = "Current number of exchanges on this virtualhost.")
+                      description = "Current number of exchanges on this virtualhost.", metricName = "exchanges_total")
     long getExchangeCount();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.COUNT, label = "Connections",
-                      description = "Current number of messaging connections made to this virtualhost.")
+                      description = "Current number of messaging connections made to this virtualhost.", metricName = "connections_total")
     long getConnectionCount();
 
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.COUNT, label = "Total Connections",
-            description = "Total number of messaging connections made to this virtualhost since broker startup")
+            description = "Total number of messaging connections made to this virtualhost since broker startup", metricName = "aggregate_connection_count")
     long getTotalConnectionCount();
 
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.BYTES, label = "Inbound",
-                      description = "Total size of all messages received by this virtualhost.")
+                      description = "Total size of all messages received by this virtualhost.", metricName = "inbound_bytes_count")
     long getBytesIn();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.BYTES, label = "Outbound",
-                      description = "Total size of all messages delivered by this virtualhost.")
+                      description = "Total size of all messages delivered by this virtualhost.", metricName = "outbound_bytes_count")
     long getBytesOut();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES, label = "Inbound",
-                      description = "Total number of messages received by this virtualhost.")
+                      description = "Total number of messages received by this virtualhost.", metricName = "inbound_messages_count")
     long getMessagesIn();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES, label = "Outbound",
-                      description = "Total number of messages delivered by this virtualhost.")
+                      description = "Total number of messages delivered by this virtualhost.", metricName = "outbound_messages_count")
     long getMessagesOut();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES,
             label = "Transacted Inbound",
-            description = "Total number of messages delivered by this virtualhost within a transaction.")
+            description = "Total number of messages delivered by this virtualhost within a transaction.", metricName = "inbound_transacted_messages_count")
     long getTransactedMessagesIn();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES,
             label = "Transacted Outbound",
-            description = "Total number of messages received by this virtualhost within a transaction.")
+            description = "Total number of messages received by this virtualhost within a transaction.", metricName = "outbound_transacted_messages_count")
     long getTransactedMessagesOut();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.BYTES, label = "Queue Depth",
-            description = "Current size of all messages enqueued by this virtualhost.")
+            description = "Current size of all messages enqueued by this virtualhost.", metricName = "queue_depth_bytes_total")
     long getTotalDepthOfQueuesBytes();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.MESSAGES, label = "Queue Depth",
-                      description = "Current number of messages enqueued by this virtualhost.")
+                      description = "Current number of messages enqueued by this virtualhost.", metricName = "queue_depth_messages_total")
     long getTotalDepthOfQueuesMessages();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.BYTES, label = "In-Memory Message Bytes",
-                      description="Current size of all messages cached in-memory.")
+                      description="Current size of all messages cached in-memory.", metricName = "in_memory_message_size_bytes_total")
     long getInMemoryMessageSize();
 
     @SuppressWarnings("unused")
@@ -284,7 +284,7 @@ public interface QueueManagingVirtualHost<X extends QueueManagingVirtualHost<X>>
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME,
             units = StatisticUnit.BYTES,
             label = "Maximum recorded size of inbound messages",
-            description = "Maximum size of message published into the Virtual Host since start-up.")
+            description = "Maximum size of message published into the Virtual Host since start-up.", metricName = "inbound_message_size_high_water_mark")
     long getInboundMessageSizeHighWatermark();
 
     @Override
diff --git a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/InjectedAttributeTest.java b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/InjectedAttributeTest.java
index 90ce83e..8afa95e 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/InjectedAttributeTest.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/InjectedAttributeTest.java
@@ -292,14 +292,16 @@ public class InjectedAttributeTest extends UnitTestBase
                                                                            TYPE_VALIDATOR,
                                                                            StatisticUnit.COUNT,
                                                                            StatisticType.POINT_IN_TIME,
-                                                                           "What is 6 x 9?");
+                                                                           "What is 6 x 9?",
+                                                                           null,
+                                                                           false);
 
         TestModel model = new TestModel(null, new TestInjector(statInjector));
 
         TestCar<?> testCar = new TestStandardCarImpl(Collections.<String,Object>singletonMap("name", "Arthur"), model);
 
         final Map<String, Object> statistics = testCar.getStatistics();
-        assertEquals("incorrect number of statistics", (long) 1, (long) statistics.size());
+        assertEquals("incorrect number of statistics", (long) 3, (long) statistics.size());
         assertEquals("incorrect statistic value", 42, statistics.get("meaningOfLife"));
     }
 
@@ -317,7 +319,9 @@ public class InjectedAttributeTest extends UnitTestBase
                                                                            TYPE_VALIDATOR,
                                                                            StatisticUnit.COUNT,
                                                                            StatisticType.POINT_IN_TIME,
-                                                                           "One");
+                                                                           "One",
+                                                                           null,
+                                                                           false);
         final ConfiguredObjectInjectedStatistic<?, ?> statInjector2 =
                 new ConfiguredObjectInjectedStatistic<TestCar<?>, Integer>("whatISent2",
                                                                            method,
@@ -325,13 +329,15 @@ public class InjectedAttributeTest extends UnitTestBase
                                                                            TYPE_VALIDATOR,
                                                                            StatisticUnit.COUNT,
                                                                            StatisticType.POINT_IN_TIME,
-                                                                           "Two");
+                                                                           "Two",
+                                                                           null,
+                                                                           false);
         TestModel model = new TestModel(null, new TestInjector(statInjector1, statInjector2));
 
         TestCar<?> testCar = new TestStandardCarImpl(Collections.<String,Object>singletonMap("name", "Arthur"), model);
 
         final Map<String, Object> statistics = testCar.getStatistics();
-        assertEquals("incorrect number of statistics", (long) 2, (long) statistics.size());
+        assertEquals("incorrect number of statistics", (long) 4, (long) statistics.size());
         assertEquals("incorrect statistic value", 1, statistics.get("whatISent1"));
         assertEquals("incorrect statistic value", 2, statistics.get("whatISent2"));
     }
diff --git a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestAbstractCarImpl.java b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestAbstractCarImpl.java
index 447c324..f01a6a4 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestAbstractCarImpl.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestAbstractCarImpl.java
@@ -22,6 +22,7 @@ package org.apache.qpid.server.model.testmodels.hierarchy;
 
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.qpid.server.configuration.IllegalConfigurationException;
 import org.apache.qpid.server.configuration.updater.CurrentThreadTaskExecutor;
@@ -37,6 +38,8 @@ public abstract class TestAbstractCarImpl<X extends TestAbstractCarImpl<X>> exte
     @ManagedAttributeField
     private Colour _interiorColour;
 
+    private AtomicInteger _mileage = new AtomicInteger();
+
     private volatile boolean _rejectStateChange;
 
     public TestAbstractCarImpl(final Map<String, Object> attributes)
@@ -102,4 +105,22 @@ public abstract class TestAbstractCarImpl<X extends TestAbstractCarImpl<X>> exte
     {
         _rejectStateChange = rejectStateChange;
     }
+
+    @Override
+    public int getMileage()
+    {
+        return _mileage.get();
+    }
+
+    @Override
+    public int move(final int value)
+    {
+        return _mileage.addAndGet(value);
+    }
+
+    @Override
+    public int getAge()
+    {
+        return 0;
+    }
 }
diff --git a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestAbstractEngineImpl.java b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestAbstractEngineImpl.java
index 722ddc8..5e84a12 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestAbstractEngineImpl.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestAbstractEngineImpl.java
@@ -34,6 +34,7 @@ import org.apache.qpid.server.model.StateTransition;
 
 public class TestAbstractEngineImpl<X extends TestAbstractEngineImpl<X>> extends AbstractConfiguredObject<X> implements TestEngine<X>
 {
+    public static final int TEST_TEMPERATURE = 50;
     @ManagedAttributeField
     private ListenableFuture<Void> _beforeCloseFuture = Futures.immediateFuture(null);
 
@@ -109,4 +110,10 @@ public class TestAbstractEngineImpl<X extends TestAbstractEngineImpl<X>> extends
         setState(State.ACTIVE);
         return (ListenableFuture<Void>) _stateChangeFuture;
     }
+
+    @Override
+    public int getTemperature()
+    {
+        return TEST_TEMPERATURE;
+    }
 }
diff --git a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestAbstractInstrumentPanelImpl.java b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestAbstractInstrumentPanelImpl.java
index 5ef7001..73db9d3 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestAbstractInstrumentPanelImpl.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestAbstractInstrumentPanelImpl.java
@@ -21,6 +21,7 @@
 package org.apache.qpid.server.model.testmodels.hierarchy;
 
 import java.util.Map;
+import java.util.Random;
 
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
@@ -51,4 +52,5 @@ public class TestAbstractInstrumentPanelImpl<X extends TestAbstractInstrumentPan
         setState(State.ACTIVE);
         return Futures.immediateFuture(null);
     }
+
 }
diff --git a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestAbstractSensorImpl.java b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestAbstractSensorImpl.java
index dc41c23..00ff611 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestAbstractSensorImpl.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestAbstractSensorImpl.java
@@ -21,6 +21,7 @@
 package org.apache.qpid.server.model.testmodels.hierarchy;
 
 import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
@@ -33,6 +34,8 @@ public class TestAbstractSensorImpl<X extends TestAbstractSensorImpl<X>> extends
         implements TestSensor<X>
 {
 
+    private AtomicInteger _alertCount;
+
     protected TestAbstractSensorImpl(final TestInstrumentPanel<?> parent,
                                      final Map<String, Object> attributes)
     {
@@ -51,4 +54,10 @@ public class TestAbstractSensorImpl<X extends TestAbstractSensorImpl<X>> extends
         setState(State.ACTIVE);
         return Futures.immediateFuture(null);
     }
+
+    @Override
+    public int getNumberOfAlerts()
+    {
+        return _alertCount.getAndIncrement();
+    }
 }
diff --git a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestCar.java b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestCar.java
index a184227..8588d60 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestCar.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestCar.java
@@ -25,7 +25,10 @@ import org.apache.qpid.server.model.ManagedAttribute;
 import org.apache.qpid.server.model.ManagedContextDefault;
 import org.apache.qpid.server.model.ManagedObject;
 import org.apache.qpid.server.model.ManagedOperation;
+import org.apache.qpid.server.model.ManagedStatistic;
 import org.apache.qpid.server.model.Param;
+import org.apache.qpid.server.model.StatisticType;
+import org.apache.qpid.server.model.StatisticUnit;
 
 @ManagedObject( defaultType = TestStandardCarImpl.TEST_STANDARD_CAR_TYPE)
 public interface TestCar<X extends TestCar<X>> extends ConfiguredObject<X>
@@ -60,4 +63,15 @@ public interface TestCar<X extends TestCar<X>> extends ConfiguredObject<X>
 
     void setRejectStateChange(boolean b);
 
+    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.COUNT)
+    int getMileage();
+
+    @ManagedStatistic(metricName = "age",
+            statisticType = StatisticType.CUMULATIVE,
+            units = StatisticUnit.TIME_DURATION,
+            metricDisabled = true)
+    int getAge();
+
+    @ManagedOperation(changesConfiguredObjectState = false)
+    int move(@Param(name = "mileage", mandatory = true) int mileage);
 }
diff --git a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestEngine.java b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestEngine.java
index d5284cb..97229b2 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestEngine.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestEngine.java
@@ -25,6 +25,9 @@ import com.google.common.util.concurrent.ListenableFuture;
 import org.apache.qpid.server.model.ConfiguredObject;
 import org.apache.qpid.server.model.ManagedAttribute;
 import org.apache.qpid.server.model.ManagedObject;
+import org.apache.qpid.server.model.ManagedStatistic;
+import org.apache.qpid.server.model.StatisticType;
+import org.apache.qpid.server.model.StatisticUnit;
 
 @ManagedObject(category = true, defaultType = TestElecEngineImpl.TEST_ELEC_ENGINE_TYPE)
 public interface TestEngine<X extends TestEngine<X>> extends ConfiguredObject<X>
@@ -52,4 +55,7 @@ public interface TestEngine<X extends TestEngine<X>> extends ConfiguredObject<X>
     Object getStateChangeException();
     void setStateChangeException(RuntimeException exception);
 
+    @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.COUNT)
+    int getTemperature();
+
 }
diff --git a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestSensor.java b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestSensor.java
index 41e07f2..c2bbc79 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestSensor.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestSensor.java
@@ -22,9 +22,14 @@ package org.apache.qpid.server.model.testmodels.hierarchy;
 
 import org.apache.qpid.server.model.ConfiguredObject;
 import org.apache.qpid.server.model.ManagedObject;
+import org.apache.qpid.server.model.ManagedStatistic;
+import org.apache.qpid.server.model.StatisticType;
+import org.apache.qpid.server.model.StatisticUnit;
 
 @ManagedObject( defaultType = TestTemperatureSensorImpl.TEST_TEMPERATURE_SENSOR_TYPE)
 public interface TestSensor<X extends TestSensor<X>> extends ConfiguredObject<X>
 {
 
+    @ManagedStatistic(metricName = "alert_count", statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.COUNT)
+    int getNumberOfAlerts();
 }
diff --git a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestTemperatureSensorImpl.java b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestTemperatureSensorImpl.java
index f2c176b..96f1fcf 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestTemperatureSensorImpl.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestTemperatureSensorImpl.java
@@ -21,6 +21,7 @@
 package org.apache.qpid.server.model.testmodels.hierarchy;
 
 import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.qpid.server.model.ManagedObject;
 import org.apache.qpid.server.model.ManagedObjectFactoryConstructor;
@@ -32,9 +33,17 @@ public class TestTemperatureSensorImpl extends TestAbstractSensorImpl<TestTemper
 
     public static final String TEST_TEMPERATURE_SENSOR_TYPE = "temperature";
 
+    private AtomicInteger _alertCount = new AtomicInteger();
+
     @ManagedObjectFactoryConstructor
     protected TestTemperatureSensorImpl(final Map<String, Object> attributes,final TestInstrumentPanel<?> parent)
     {
         super(parent, attributes);
     }
+
+    @Override
+    public int getNumberOfAlerts()
+    {
+        return _alertCount.getAndIncrement();
+    }
 }
diff --git a/broker-plugins/management-http/pom.xml b/broker-plugins/management-http/pom.xml
index 9fa84d0..fa5a233 100644
--- a/broker-plugins/management-http/pom.xml
+++ b/broker-plugins/management-http/pom.xml
@@ -101,6 +101,11 @@
       </exclusions>
     </dependency>
 
+    <dependency>
+      <groupId>org.apache.qpid</groupId>
+      <artifactId>qpid-broker-plugins-prometheus-exporter</artifactId>
+    </dependency>
+
     <!-- test dependencies -->
     <dependency>
       <groupId>org.apache.qpid</groupId>
diff --git a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java
index 39709df..43da9db 100644
--- a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java
+++ b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java
@@ -90,6 +90,7 @@ import org.apache.qpid.server.management.plugin.filter.RewriteRequestForUncompre
 import org.apache.qpid.server.management.plugin.portunification.TlsOrPlainConnectionFactory;
 import org.apache.qpid.server.management.plugin.servlet.FileServlet;
 import org.apache.qpid.server.management.plugin.servlet.RootServlet;
+import org.apache.qpid.server.management.plugin.servlet.ContentServlet;
 import org.apache.qpid.server.management.plugin.servlet.rest.ApiDocsServlet;
 import org.apache.qpid.server.management.plugin.servlet.rest.BrokerQueryServlet;
 import org.apache.qpid.server.management.plugin.servlet.rest.JsonValueServlet;
@@ -119,6 +120,8 @@ import org.apache.qpid.server.model.TrustStore;
 import org.apache.qpid.server.model.adapter.AbstractPluginAdapter;
 import org.apache.qpid.server.model.port.HttpPort;
 import org.apache.qpid.server.model.port.PortManager;
+import org.apache.qpid.server.plugin.ContentFactory;
+import org.apache.qpid.server.plugin.QpidServiceLoader;
 import org.apache.qpid.server.transport.PortBindFailureException;
 import org.apache.qpid.server.transport.network.security.ssl.SSLUtil;
 import org.apache.qpid.server.util.DaemonThreadFactory;
@@ -412,6 +415,21 @@ public class HttpManagement extends AbstractPluginAdapter<HttpManagement> implem
 
         root.addServlet(new ServletHolder(new TimeZoneServlet()), "/service/timezones");
 
+        final Iterable<ContentFactory> contentFactories = new QpidServiceLoader().instancesOf(ContentFactory.class);
+        contentFactories.forEach(f->{
+            ServletHolder metricsServlet = new ServletHolder(new ContentServlet(f));
+            String path = f.getType().toLowerCase();
+            root.addServlet(metricsServlet, "/" + path);
+            root.addServlet(metricsServlet, "/" + path  + "/*");
+
+            if (getContextValue(Boolean.class, HTTP_MANAGEMENT_ENABLE_CONTENT_AUTHENTICATION))
+            {
+                root.addFilter(restAuthorizationFilter, "/" + path, EnumSet.of(DispatcherType.REQUEST));
+                root.addFilter(restAuthorizationFilter, "/" + path  + "/*", EnumSet.of(DispatcherType.REQUEST));
+            }
+
+        });
+
         root.getSessionHandler().getSessionCookieConfig().setName(JSESSIONID_COOKIE_PREFIX + lastPort);
         root.getSessionHandler().getSessionCookieConfig().setHttpOnly(true);
         root.getSessionHandler().setMaxInactiveInterval(getSessionTimeout());
diff --git a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagementConfiguration.java b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagementConfiguration.java
index a5aadae..d33f2b8 100644
--- a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagementConfiguration.java
+++ b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagementConfiguration.java
@@ -85,6 +85,11 @@ public interface HttpManagementConfiguration<X extends HttpManagementConfigurati
     @ManagedContextDefault( name = SASL_EXCHANGE_EXPIRY_CONTEXT_NAME)
     long DEFAULT_SASL_EXCHANGE_EXPIRY = 60000L;
 
+    String HTTP_MANAGEMENT_ENABLE_CONTENT_AUTHENTICATION = "qpid.httpManagement.enableMetricContentAuthentication";
+    @SuppressWarnings("unused")
+    @ManagedContextDefault(name = HTTP_MANAGEMENT_ENABLE_CONTENT_AUTHENTICATION)
+    boolean DEFAULT_HTTP_MANAGEMENT_ENABLE_CONTENT_AUTHENTICATION = false;
+
     AuthenticationProvider getAuthenticationProvider(HttpServletRequest request);
     Port<?> getPort(HttpServletRequest request);
 }
diff --git a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/ContentServlet.java b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/ContentServlet.java
new file mode 100644
index 0000000..36ea0a7
--- /dev/null
+++ b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/ContentServlet.java
@@ -0,0 +1,95 @@
+/*
+ * 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.management.plugin.servlet;
+
+import java.io.IOException;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.qpid.server.management.plugin.servlet.rest.AbstractServlet;
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.model.ConfiguredObjectFinder;
+import org.apache.qpid.server.model.Content;
+import org.apache.qpid.server.model.VirtualHost;
+import org.apache.qpid.server.plugin.ContentFactory;
+
+public class ContentServlet extends AbstractServlet
+{
+    private static final long serialVersionUID = 1L;
+    private final ContentFactory _contentFactory;
+
+    public ContentServlet(final ContentFactory contentFactory)
+    {
+        super();
+        _contentFactory = contentFactory;
+    }
+
+    @Override
+    public void doGet(HttpServletRequest request,
+                      HttpServletResponse response,
+                      final ConfiguredObject<?> managedObject) throws IOException
+    {
+
+        ConfiguredObject root = managedObject;
+        String pathInfo = request.getPathInfo();
+        if (managedObject instanceof Broker && null != pathInfo && !pathInfo.isEmpty())
+        {
+            final ConfiguredObjectFinder finder = getConfiguredObjectFinder(managedObject);
+            final ConfiguredObject virtualHost = finder.findObjectFromPath(pathInfo.substring(1), VirtualHost.class);
+            if (null == virtualHost)
+            {
+                sendError(response, HttpServletResponse.SC_NOT_FOUND);
+                return;
+            }
+            else
+            {
+                root = virtualHost;
+            }
+        }
+        else if (managedObject instanceof VirtualHost && null != pathInfo && !pathInfo.isEmpty())
+        {
+            sendError(response, HttpServletResponse.SC_BAD_REQUEST);
+            return;
+        }
+        final Map<String, String[]> parameters = request.getParameterMap();
+        Content content = _contentFactory.createContent(root, parameters);
+        try
+        {
+            writeContent(content, request, response);
+        }
+        finally
+        {
+            content.release();
+        }
+    }
+
+    @Override
+    protected void doPost(final HttpServletRequest req,
+                          final HttpServletResponse resp,
+                          final ConfiguredObject<?> managedObject)
+            throws IOException
+    {
+        doGet(req, resp, managedObject);
+    }
+
+}
diff --git a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java
index 76d87f1..e324c7a 100644
--- a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java
+++ b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java
@@ -284,8 +284,22 @@ public abstract class AbstractServlet extends HttpServlet
     protected void writeTypedContent(Content content, HttpServletRequest request, HttpServletResponse response)
             throws IOException
     {
-        Map<String, Object> headers = getResponseHeaders(content);
+        try
+        {
+            writeContent(content, request, response);
+        }
+        catch (IOException e)
+        {
+            LOGGER.warn("Unexpected exception processing request", e);
+            sendJsonErrorResponse(request, response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
+        }
+    }
 
+    protected void writeContent(final Content content,
+                                final HttpServletRequest request,
+                                final HttpServletResponse response) throws IOException
+    {
+        Map<String, Object> headers = new HashMap<>(getResponseHeaders(content));
         try (OutputStream os = getOutputStream(request, response, headers))
         {
             response.setStatus(HttpServletResponse.SC_OK);
@@ -295,11 +309,6 @@ public abstract class AbstractServlet extends HttpServlet
             }
             content.write(os);
         }
-        catch (IOException e)
-        {
-            LOGGER.warn("Unexpected exception processing request", e);
-            sendJsonErrorResponse(request, response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
-        }
     }
 
     private OutputStream getOutputStream(final HttpServletRequest request,
diff --git a/broker-plugins/prometheus-exporter/pom.xml b/broker-plugins/prometheus-exporter/pom.xml
new file mode 100644
index 0000000..9f9885f
--- /dev/null
+++ b/broker-plugins/prometheus-exporter/pom.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  ~
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>qpid-broker-parent</artifactId>
+        <groupId>org.apache.qpid</groupId>
+        <version>7.1.9-SNAPSHOT</version>
+        <relativePath>../../pom.xml</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>qpid-broker-plugins-prometheus-exporter</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.qpid</groupId>
+            <artifactId>qpid-broker-codegen</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.qpid</groupId>
+            <artifactId>qpid-broker-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.prometheus</groupId>
+            <artifactId>simpleclient</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.prometheus</groupId>
+            <artifactId>simpleclient_common</artifactId>
+        </dependency>
+
+        <!-- test dependencies -->
+        <dependency>
+            <groupId>org.apache.qpid</groupId>
+            <artifactId>qpid-test-utils</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.qpid</groupId>
+            <artifactId>qpid-broker-core</artifactId>
+            <classifier>tests</classifier>
+            <scope>test</scope>
+        </dependency>
+
+    </dependencies>
+
+</project>
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectStatistic.java b/broker-plugins/prometheus-exporter/src/main/java/org/apache/qpid/server/prometheus/IncludeDisabledStatisticPredicate.java
similarity index 59%
copy from broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectStatistic.java
copy to broker-plugins/prometheus-exporter/src/main/java/org/apache/qpid/server/prometheus/IncludeDisabledStatisticPredicate.java
index cc22d62..f675e55 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectStatistic.java
+++ b/broker-plugins/prometheus-exporter/src/main/java/org/apache/qpid/server/prometheus/IncludeDisabledStatisticPredicate.java
@@ -1,5 +1,4 @@
 /*
- *
  * 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
@@ -18,15 +17,26 @@
  * under the License.
  *
  */
-package org.apache.qpid.server.model;
 
-public interface ConfiguredObjectStatistic<C extends ConfiguredObject, T extends Object> extends ConfiguredObjectAttributeOrStatistic<C,T>
-{
-    String getDescription();
+package org.apache.qpid.server.prometheus;
+
+import java.util.function.Predicate;
 
-    StatisticUnit getUnits();
+import org.apache.qpid.server.model.ConfiguredObjectStatistic;
+
+public class IncludeDisabledStatisticPredicate implements Predicate<ConfiguredObjectStatistic<?,?>>
+
+{
+    private final boolean _includeDisabled;
 
-    StatisticType getStatisticType();
+    IncludeDisabledStatisticPredicate(final boolean includeDisabled)
+    {
+        _includeDisabled = includeDisabled;
+    }
 
-    String getLabel();
+    @Override
+    public boolean test(final ConfiguredObjectStatistic s)
+    {
+        return _includeDisabled || !s.isMetricDisabled();
+    }
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectStatistic.java b/broker-plugins/prometheus-exporter/src/main/java/org/apache/qpid/server/prometheus/IncludeMetricPredicate.java
similarity index 60%
copy from broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectStatistic.java
copy to broker-plugins/prometheus-exporter/src/main/java/org/apache/qpid/server/prometheus/IncludeMetricPredicate.java
index cc22d62..e921352 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectStatistic.java
+++ b/broker-plugins/prometheus-exporter/src/main/java/org/apache/qpid/server/prometheus/IncludeMetricPredicate.java
@@ -1,5 +1,4 @@
 /*
- *
  * 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
@@ -18,15 +17,26 @@
  * under the License.
  *
  */
-package org.apache.qpid.server.model;
 
-public interface ConfiguredObjectStatistic<C extends ConfiguredObject, T extends Object> extends ConfiguredObjectAttributeOrStatistic<C,T>
-{
-    String getDescription();
+package org.apache.qpid.server.prometheus;
 
-    StatisticUnit getUnits();
+import java.util.Set;
+import java.util.function.Predicate;
+
+public class IncludeMetricPredicate implements Predicate<String>
+{
+    private final Set<String> _allowedNames;
+    private final boolean _isEmpty;
 
-    StatisticType getStatisticType();
+    public IncludeMetricPredicate(final Set<String> allowedNames)
+    {
+        _allowedNames = allowedNames;
+        _isEmpty = _allowedNames.isEmpty();
+    }
 
-    String getLabel();
+    @Override
+    public boolean test(final String name)
+    {
+        return _isEmpty || _allowedNames.contains(name);
+    }
 }
diff --git a/broker-plugins/prometheus-exporter/src/main/java/org/apache/qpid/server/prometheus/PrometheusContentFactory.java b/broker-plugins/prometheus-exporter/src/main/java/org/apache/qpid/server/prometheus/PrometheusContentFactory.java
new file mode 100644
index 0000000..af98978
--- /dev/null
+++ b/broker-plugins/prometheus-exporter/src/main/java/org/apache/qpid/server/prometheus/PrometheusContentFactory.java
@@ -0,0 +1,105 @@
+/*
+ * 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.prometheus;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+
+import io.prometheus.client.exporter.common.TextFormat;
+
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.model.Content;
+import org.apache.qpid.server.model.RestContentHeader;
+import org.apache.qpid.server.plugin.ContentFactory;
+import org.apache.qpid.server.plugin.PluggableService;
+
+@PluggableService
+public class PrometheusContentFactory implements ContentFactory
+{
+    static final String INCLUDE_DISABLED = "includeDisabled";
+    static final String INCLUDE_METRIC = "name[]";
+    static final String INCLUDE_DISABLED_CONTEXT_VARIABLE = "qpid.metrics.includeDisabled";
+
+    @Override
+    public Content createContent(final ConfiguredObject<?> object, final Map<String, String[]> filter)
+    {
+        final String[] includeDisabledValues = filter.get(INCLUDE_DISABLED);
+        boolean includeDisabled = includeDisabledValues!= null && includeDisabledValues.length == 1 && Boolean.parseBoolean(includeDisabledValues[0]);
+        if (!includeDisabled)
+        {
+            Boolean val = object.getContextValue(Boolean.class, INCLUDE_DISABLED_CONTEXT_VARIABLE);
+            if (val != null)
+            {
+                includeDisabled = val;
+            }
+        }
+
+        final String[] includedMetricNames = filter.get(INCLUDE_METRIC);
+
+        final IncludeMetricPredicate metricIncludeFilter =
+                new IncludeMetricPredicate(includedMetricNames == null || includedMetricNames.length == 0
+                                                   ? Collections.emptySet()
+                                                   : new HashSet<>(Arrays.asList(includedMetricNames)));
+        final QpidCollector qpidCollector = new QpidCollector(object,
+                                                              new IncludeDisabledStatisticPredicate(includeDisabled),
+                                                              metricIncludeFilter);
+
+        return new Content()
+        {
+            @Override
+            public void write(final OutputStream outputStream) throws IOException
+            {
+                try (final Writer writer = new OutputStreamWriter(outputStream))
+                {
+                    TextFormat.write004(writer, Collections.enumeration(qpidCollector.collect()));
+                    writer.flush();
+                }
+            }
+
+            @Override
+            public void release()
+            {
+
+            }
+
+            @SuppressWarnings("unused")
+            @RestContentHeader("Content-Type")
+            public String getContentType()
+            {
+                return TextFormat.CONTENT_TYPE_004;
+            }
+
+        };
+
+    }
+
+    @Override
+    public String getType()
+    {
+        return "metrics";
+    }
+}
diff --git a/broker-plugins/prometheus-exporter/src/main/java/org/apache/qpid/server/prometheus/QpidCollector.java b/broker-plugins/prometheus-exporter/src/main/java/org/apache/qpid/server/prometheus/QpidCollector.java
new file mode 100644
index 0000000..3997700
--- /dev/null
+++ b/broker-plugins/prometheus-exporter/src/main/java/org/apache/qpid/server/prometheus/QpidCollector.java
@@ -0,0 +1,257 @@
+/*
+ * 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.prometheus;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Predicate;
+
+import io.prometheus.client.Collector;
+import io.prometheus.client.CounterMetricFamily;
+import io.prometheus.client.GaugeMetricFamily;
+
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.model.ConfiguredObjectStatistic;
+import org.apache.qpid.server.model.Model;
+import org.apache.qpid.server.model.StatisticType;
+import org.apache.qpid.server.model.StatisticUnit;
+
+public class QpidCollector extends Collector
+{
+    private final static MetricFamilySamples IGNORED = new MetricFamilySamples(null, null, null, null);
+    static final String COUNT_SUFFIX = "count";
+    static final String TOTAL_SUFFIX = "total";
+    private final Predicate<ConfiguredObjectStatistic<?,?>> _includeStatisticFilter;
+    private final Predicate<String> _includeMetricFilter;
+    private ConfiguredObject<?> _root;
+    private Model _model;
+
+
+    QpidCollector(final ConfiguredObject<?> root,
+                  final Predicate<ConfiguredObjectStatistic<?,?>> includeStatisticFilter,
+                  final Predicate<String> includeMetricFilter)
+    {
+        _root = root;
+        _model = _root.getModel();
+        _includeStatisticFilter = includeStatisticFilter;
+        _includeMetricFilter = includeMetricFilter;
+    }
+
+    @Override
+    public List<MetricFamilySamples> collect()
+    {
+        final List<MetricFamilySamples> metricFamilySamples = new ArrayList<>();
+        addObjectMetrics(_root, Collections.emptyList(), new HashMap<>(), metricFamilySamples);
+        addChildrenMetrics(metricFamilySamples, _root, Collections.singletonList("name"));
+        return metricFamilySamples;
+    }
+
+    private void addObjectMetrics(final ConfiguredObject<?> object,
+                                  final List<String> labelNames,
+                                  final Map<String, MetricFamilySamples> metricFamilyMap,
+                                  final List<MetricFamilySamples> metricFamilySamples)
+    {
+        final Map<String, Object> statsMap = object.getStatistics();
+        for (final Map.Entry<String, Object> entry : statsMap.entrySet())
+        {
+            MetricFamilySamples family = metricFamilyMap.get(entry.getKey());
+            if (family == null)
+            {
+                family = createMetricFamilySamples(entry.getKey(), object, labelNames);
+                metricFamilyMap.put(entry.getKey(), family);
+                if (family != IGNORED)
+                {
+                    metricFamilySamples.add(family);
+                }
+            }
+            if (family != IGNORED)
+            {
+                final List<String> labelsValues = buildLabelValues(object);
+                final double doubleValue = toDoubleValue(entry.getValue());
+                family.samples.add(new MetricFamilySamples.Sample(family.name, labelNames, labelsValues, doubleValue));
+            }
+        }
+    }
+
+    private MetricFamilySamples createMetricFamilySamples(final String statisticName,
+                                                          final ConfiguredObject<?> object,
+                                                          final List<String> labelNames)
+    {
+        final ConfiguredObjectStatistic<?, ?> configuredObjectStatistic =
+                findConfiguredObjectStatistic(statisticName, object.getTypeClass());
+        if (configuredObjectStatistic == null || !_includeStatisticFilter.test(configuredObjectStatistic))
+        {
+            return IGNORED;
+        }
+        final StatisticType type = configuredObjectStatistic.getStatisticType();
+        final String familyName = getFamilyName(object.getCategoryClass(), configuredObjectStatistic);
+
+        if (!_includeMetricFilter.test(familyName))
+        {
+            return IGNORED;
+        }
+
+        if (type == StatisticType.CUMULATIVE)
+        {
+            return new CounterMetricFamily(familyName, configuredObjectStatistic.getDescription(), labelNames);
+        }
+        else
+        {
+            return new GaugeMetricFamily(familyName, configuredObjectStatistic.getDescription(), labelNames);
+        }
+    }
+
+    private ConfiguredObjectStatistic<?, ?> findConfiguredObjectStatistic(final String statisticName,
+                                                                          final Class<? extends ConfiguredObject> typeClass)
+    {
+        final Collection<ConfiguredObjectStatistic<?, ?>> statisticsDefinitions =
+                _model.getTypeRegistry().getStatistics(typeClass);
+        return statisticsDefinitions.stream()
+                                    .filter(s -> statisticName.equals(s.getName()))
+                                    .findFirst()
+                                    .orElse(null);
+    }
+
+    private List<String> buildLabelValues(final ConfiguredObject<?> object)
+    {
+        final List<String> labelsValues = new ArrayList<>();
+        ConfiguredObject o = object;
+        while (o != null && o != _root)
+        {
+            labelsValues.add(o.getName());
+            o = o.getParent();
+        }
+        return labelsValues;
+    }
+
+    private void addChildrenMetrics(final List<MetricFamilySamples> metricFamilySamples,
+                                    final ConfiguredObject<?> object,
+                                    final List<String> childLabelNames)
+    {
+        final Class<? extends ConfiguredObject> category = object.getCategoryClass();
+        for (final Class<? extends ConfiguredObject> childClass : _model.getChildTypes(category))
+        {
+            final Collection<? extends ConfiguredObject> children = object.getChildren(childClass);
+            if (children != null && !children.isEmpty())
+            {
+                final Map<String, MetricFamilySamples> childrenMetricFamilyMap = new HashMap<>();
+                for (final ConfiguredObject<?> child : children)
+                {
+                    addObjectMetrics(child, childLabelNames, childrenMetricFamilyMap, metricFamilySamples);
+                    final List<String> labelNames = new ArrayList<>(childLabelNames);
+                    final String label = String.format("%s_name", toSnakeCase(childClass.getSimpleName()));
+                    labelNames.add(label);
+                    addChildrenMetrics(metricFamilySamples, child, labelNames);
+                }
+            }
+        }
+    }
+
+    static String toSnakeCase(final String simpleName)
+    {
+        final StringBuilder sb = new StringBuilder();
+        final char[] chars = simpleName.toCharArray();
+        for (int i = 0; i < chars.length; i++)
+        {
+            final char ch = chars[i];
+            if (Character.isUpperCase(ch))
+            {
+                if (i > 0)
+                {
+                    sb.append('_');
+                }
+                sb.append(Character.toLowerCase(ch));
+            }
+            else
+            {
+                sb.append(ch);
+            }
+        }
+        return sb.toString();
+    }
+
+    private double toDoubleValue(final Object value)
+    {
+        if (value instanceof Number)
+        {
+            return ((Number) value).doubleValue();
+        }
+        return 0;
+    }
+
+    static String getFamilyName(final Class<? extends ConfiguredObject> categoryClass,
+                                ConfiguredObjectStatistic<?, ?> statistics)
+    {
+        String metricName = statistics.getMetricName();
+        if (metricName == null || metricName.isEmpty())
+        {
+            metricName = generateMetricName(statistics);
+        }
+
+        return String.format("qpid_%s_%s",
+                             toSnakeCase(categoryClass.getSimpleName()),
+                             metricName);
+    }
+
+    private static String generateMetricName(final ConfiguredObjectStatistic<?, ?> statistics)
+    {
+        String metricName = toSnakeCase(statistics.getName());
+        String suffix;
+        switch (statistics.getStatisticType())
+        {
+            case CUMULATIVE:
+                suffix = generateMetricSuffix(statistics, COUNT_SUFFIX, metricName);
+                break;
+            case POINT_IN_TIME:
+                suffix = generateMetricSuffix(statistics, TOTAL_SUFFIX, metricName);
+                break;
+            default:
+                suffix = "";
+        }
+
+        return metricName + suffix;
+    }
+
+    private static String generateMetricSuffix(final ConfiguredObjectStatistic<?, ?> statistics,
+                                               final String typeSuffix,
+                                               final String metricName)
+    {
+        String suffix = "";
+        if (!statistics.getName().toLowerCase().contains(typeSuffix)
+            && statistics.getUnits() != StatisticUnit.ABSOLUTE_TIME
+            && statistics.getUnits() != StatisticUnit.TIME_DURATION)
+        {
+            if (statistics.getUnits() == StatisticUnit.MESSAGES || statistics.getUnits() == StatisticUnit.BYTES)
+            {
+                final String units = statistics.getUnits().toString() + "s";
+                if (!metricName.contains(units))
+                {
+                    suffix = "_" + units;
+                }
+            }
+            suffix = suffix + "_" + typeSuffix;
+        }
+        return suffix;
+    }
+}
diff --git a/broker-plugins/prometheus-exporter/src/test/java/org/apache/qpid/server/prometheus/PrometheusContentFactoryTest.java b/broker-plugins/prometheus-exporter/src/test/java/org/apache/qpid/server/prometheus/PrometheusContentFactoryTest.java
new file mode 100644
index 0000000..7959a77
--- /dev/null
+++ b/broker-plugins/prometheus-exporter/src/test/java/org/apache/qpid/server/prometheus/PrometheusContentFactoryTest.java
@@ -0,0 +1,176 @@
+/*
+ * 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.prometheus;
+
+import static org.apache.qpid.server.prometheus.PrometheusContentFactory.INCLUDE_DISABLED;
+import static org.apache.qpid.server.prometheus.PrometheusContentFactory.INCLUDE_METRIC;
+import static org.apache.qpid.server.prometheus.PrometheusContentFactory.INCLUDE_DISABLED_CONTEXT_VARIABLE;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.CoreMatchers.startsWith;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.model.Content;
+import org.apache.qpid.server.model.Model;
+import org.apache.qpid.server.model.testmodels.hierarchy.TestCar;
+import org.apache.qpid.server.model.testmodels.hierarchy.TestKitCarImpl;
+import org.apache.qpid.server.model.testmodels.hierarchy.TestModel;
+
+public class PrometheusContentFactoryTest
+{
+    public static final String QPID_TEST_CAR_MILEAGE_COUNT = "qpid_test_car_mileage_count";
+    public static final String QPID_TEST_CAR_AGE = "qpid_test_car_age";
+    public static final String PROMETHEUS_COMMENT = "#";
+    private ConfiguredObject _root;
+    private PrometheusContentFactory _prometheusContentFactory;
+
+    @Before
+    public void setUp()
+    {
+        final Model model = TestModel.getInstance();
+        final Map<String, Object> carAttributes = new HashMap<>();
+        carAttributes.put(ConfiguredObject.NAME, "MyPrometheusCar");
+        carAttributes.put(ConfiguredObject.TYPE, TestKitCarImpl.TEST_KITCAR_TYPE);
+
+        @SuppressWarnings("unchecked") final TestCar<?> car =
+                model.getObjectFactory().create(TestCar.class, carAttributes, null);
+        _root = car;
+        _prometheusContentFactory = new PrometheusContentFactory();
+    }
+
+    @Test
+    public void testCreateContent() throws Exception
+    {
+        final Content content = _prometheusContentFactory.createContent(_root, Collections.emptyMap());
+        assertThat(content, is(notNullValue()));
+        Collection<String> metrics;
+        try (final ByteArrayOutputStream output = new ByteArrayOutputStream())
+        {
+            content.write(output);
+            metrics = getMetricLines(output.toByteArray());
+        }
+        assertThat(metrics, is(notNullValue()));
+
+        assertThat(metrics.size(), is(equalTo(1)));
+        String metric = metrics.iterator().next();
+        assertThat(metric, startsWith(QPID_TEST_CAR_MILEAGE_COUNT));
+    }
+
+    @Test
+    public void testCreateContentIncludeDisabled() throws Exception
+    {
+        final Content content = _prometheusContentFactory.createContent(_root, Collections.singletonMap(INCLUDE_DISABLED, new String[]{"true"}));
+        assertThat(content, is(notNullValue()));
+        Collection<String> metrics;
+        try (final ByteArrayOutputStream output = new ByteArrayOutputStream())
+        {
+            content.write(output);
+            metrics = getMetricLines(output.toByteArray());
+        }
+        assertThat(metrics, is(notNullValue()));
+
+        assertThat(metrics.size(), is(equalTo(2)));
+        Map<String, String> metricsMap = convertMetricsToMap(metrics);
+        assertThat(metricsMap.containsKey(QPID_TEST_CAR_MILEAGE_COUNT), equalTo(Boolean.TRUE));
+        assertThat(metricsMap.containsKey(QPID_TEST_CAR_AGE), equalTo(Boolean.TRUE));
+    }
+
+    @Test
+    public void testCreateContentIncludeDisabledUsingContextVariable() throws Exception
+    {
+        _root.setContextVariable(INCLUDE_DISABLED_CONTEXT_VARIABLE, "true");
+        final Content content = _prometheusContentFactory.createContent(_root, Collections.emptyMap());
+        assertThat(content, is(notNullValue()));
+        Collection<String> metrics;
+        try (final ByteArrayOutputStream output = new ByteArrayOutputStream())
+        {
+            content.write(output);
+            metrics = getMetricLines(output.toByteArray());
+        }
+        assertThat(metrics, is(notNullValue()));
+        assertThat(metrics.size(), is(equalTo(2)));
+        Map<String, String> metricsMap = convertMetricsToMap(metrics);
+        assertThat(metricsMap.containsKey(QPID_TEST_CAR_MILEAGE_COUNT), equalTo(Boolean.TRUE));
+        assertThat(metricsMap.containsKey(QPID_TEST_CAR_AGE), equalTo(Boolean.TRUE));
+    }
+
+    @Test
+    public void testCreateContentIncludeName() throws Exception
+    {
+        final Map<String, String[]> filter = new HashMap<>();
+        filter.put(INCLUDE_DISABLED, new String[]{"true"});
+        filter.put(INCLUDE_METRIC, new String[]{QPID_TEST_CAR_AGE});
+        final Content content = _prometheusContentFactory.createContent(_root, filter);
+        assertThat(content, is(notNullValue()));
+        Collection<String> metrics;
+        try (final ByteArrayOutputStream output = new ByteArrayOutputStream())
+        {
+            content.write(output);
+            metrics = getMetricLines(output.toByteArray());
+        }
+        assertThat(metrics, is(notNullValue()));
+
+        assertThat(metrics.size(), is(equalTo(1)));
+        String metric = metrics.iterator().next();
+        assertThat(metric, startsWith(QPID_TEST_CAR_AGE));
+    }
+
+    private static Collection<String> getMetricLines(final byte[] metricsBytes) throws IOException
+    {
+        final List<String> results = new ArrayList<>();
+        try (BufferedReader reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(metricsBytes))))
+        {
+            String line;
+            while ((line = reader.readLine()) != null)
+            {
+                if (!(line.startsWith(PROMETHEUS_COMMENT) || line.isEmpty()))
+                {
+                    results.add(line);
+                }
+            }
+        }
+        return results;
+    }
+
+    private Map<String, String> convertMetricsToMap(final Collection<String> metrics)
+    {
+        return metrics.stream().map(m -> m.split(" ")).collect(Collectors.toMap(m -> m[0], m -> m[1]));
+    }
+
+}
diff --git a/broker-plugins/prometheus-exporter/src/test/java/org/apache/qpid/server/prometheus/QpidCollectorTest.java b/broker-plugins/prometheus-exporter/src/test/java/org/apache/qpid/server/prometheus/QpidCollectorTest.java
new file mode 100644
index 0000000..5efbc59
--- /dev/null
+++ b/broker-plugins/prometheus-exporter/src/test/java/org/apache/qpid/server/prometheus/QpidCollectorTest.java
@@ -0,0 +1,359 @@
+/*
+ * 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.prometheus;
+
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.closeTo;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import io.prometheus.client.Collector;
+import org.hamcrest.Matchers;
+import org.junit.Before;
+import org.junit.Test;
+
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.model.ConfiguredObjectStatistic;
+import org.apache.qpid.server.model.Model;
+import org.apache.qpid.server.model.StatisticType;
+import org.apache.qpid.server.model.StatisticUnit;
+import org.apache.qpid.server.model.testmodels.hierarchy.TestAbstractEngineImpl;
+import org.apache.qpid.server.model.testmodels.hierarchy.TestCar;
+import org.apache.qpid.server.model.testmodels.hierarchy.TestDigitalInstrumentPanelImpl;
+import org.apache.qpid.server.model.testmodels.hierarchy.TestElecEngineImpl;
+import org.apache.qpid.server.model.testmodels.hierarchy.TestEngine;
+import org.apache.qpid.server.model.testmodels.hierarchy.TestInstrumentPanel;
+import org.apache.qpid.server.model.testmodels.hierarchy.TestKitCarImpl;
+import org.apache.qpid.server.model.testmodels.hierarchy.TestModel;
+import org.apache.qpid.server.model.testmodels.hierarchy.TestPetrolEngineImpl;
+import org.apache.qpid.server.model.testmodels.hierarchy.TestSensor;
+import org.apache.qpid.server.model.testmodels.hierarchy.TestTemperatureSensorImpl;
+import org.apache.qpid.test.utils.UnitTestBase;
+
+public class QpidCollectorTest extends UnitTestBase
+{
+    private static final String CAR_NAME = "myCar";
+    private static final String ELECTRIC_ENGINE_NAME = "myEngine";
+    private static final String INSTRUMENT_PANEL_NAME = "instrumentPanel";
+    private static final String PETROL_ENGINE_NAME = "myPetrolModel";
+    private static final String SENSOR = "sensor";
+    private static final int DESIRED_MILEAGE = 100;
+    private static final String QPID_TEST_CAR_MILEAGE_COUNT = "qpid_test_car_mileage_count";
+    private static final String QPID_TEST_ENGINE_TEMPERATURE_TOTAL = "qpid_test_engine_temperature_total";
+    private static final String QPID_TEST_SENSOR_ALERT_COUNT = "qpid_test_sensor_alert_count";
+    private static final String QPID_TEST_CAR_AGE_COUNT = "qpid_test_car_age";
+
+    private TestCar<?> _root;
+    private QpidCollector _qpidCollector;
+    private static final StatisticUnit[] UNITS = new StatisticUnit[]{
+            StatisticUnit.BYTES,
+            StatisticUnit.MESSAGES,
+            StatisticUnit.COUNT,
+            StatisticUnit.ABSOLUTE_TIME,
+            StatisticUnit.TIME_DURATION};
+    private static final String[] UNIT_SUFFIXES = new String[]{"_bytes", "_messages", "", "", ""};
+
+    @Before
+    public void setUp()
+    {
+        final Model model = TestModel.getInstance();
+        final Map<String, Object> carAttributes = new HashMap<>();
+        carAttributes.put(ConfiguredObject.NAME, CAR_NAME);
+        carAttributes.put(ConfiguredObject.TYPE, TestKitCarImpl.TEST_KITCAR_TYPE);
+
+        @SuppressWarnings("unchecked") final TestCar<?> car =
+                model.getObjectFactory().create(TestCar.class, carAttributes, null);
+        _root = car;
+        _qpidCollector = new QpidCollector(_root, new IncludeDisabledStatisticPredicate(false), s->true);
+    }
+
+    @Test
+    public void testCollectForHierarchyOfTwoObjects()
+    {
+        createTestEngine(ELECTRIC_ENGINE_NAME, TestElecEngineImpl.TEST_ELEC_ENGINE_TYPE);
+        _root.move(DESIRED_MILEAGE);
+
+        final List<Collector.MetricFamilySamples> metrics = _qpidCollector.collect();
+
+        final String[] expectedFamilyNames = {QPID_TEST_CAR_MILEAGE_COUNT, QPID_TEST_ENGINE_TEMPERATURE_TOTAL};
+        final Map<String, Collector.MetricFamilySamples> metricsMap =
+                convertMetricFamilySamplesIntoMapAndAssert(metrics, expectedFamilyNames);
+
+        final Collector.MetricFamilySamples carMetricFamilySamples = metricsMap.get(QPID_TEST_CAR_MILEAGE_COUNT);
+        assertMetricFamilySamplesSize(carMetricFamilySamples, 1);
+        final Collector.MetricFamilySamples.Sample carSample = carMetricFamilySamples.samples.get(0);
+        assertThat(carSample.value, closeTo(DESIRED_MILEAGE, 0.01));
+        assertThat(carSample.labelNames.size(), is(equalTo(0)));
+
+        final Collector.MetricFamilySamples engineMetricFamilySamples = metricsMap.get(
+                QPID_TEST_ENGINE_TEMPERATURE_TOTAL);
+        assertMetricFamilySamplesSize(engineMetricFamilySamples, 1);
+        final Collector.MetricFamilySamples.Sample engineSample = engineMetricFamilySamples.samples.get(0);
+        assertThat(engineSample.labelNames, is(equalTo(Collections.singletonList("name"))));
+        assertThat(engineSample.labelValues, is(equalTo(Collections.singletonList(ELECTRIC_ENGINE_NAME))));
+        assertThat(engineSample.value, Matchers.closeTo(TestAbstractEngineImpl.TEST_TEMPERATURE, 0.01));
+    }
+
+    @Test
+    public void testCollectForHierarchyOfThreeObjects()
+    {
+        final TestInstrumentPanel instrumentPanel = getTestInstrumentPanel();
+        createTestSensor(instrumentPanel);
+
+        final List<Collector.MetricFamilySamples> metrics = _qpidCollector.collect();
+
+        final String[] expectedFamilyNames =
+                {QPID_TEST_CAR_MILEAGE_COUNT, QPID_TEST_SENSOR_ALERT_COUNT};
+        final Map<String, Collector.MetricFamilySamples> metricsMap =
+                convertMetricFamilySamplesIntoMapAndAssert(metrics, expectedFamilyNames);
+
+        final Collector.MetricFamilySamples carMetricFamilySamples = metricsMap.get(QPID_TEST_CAR_MILEAGE_COUNT);
+        assertMetricFamilySamplesSize(carMetricFamilySamples, 1);
+        final Collector.MetricFamilySamples.Sample carSample = carMetricFamilySamples.samples.get(0);
+        assertThat(carSample.labelNames.size(), is(equalTo(0)));
+        assertThat(carSample.labelValues.size(), is(equalTo(0)));
+        assertThat(carSample.value, closeTo(0, 0.01));
+
+        final Collector.MetricFamilySamples sensorlMetricFamilySamples =
+                metricsMap.get(QPID_TEST_SENSOR_ALERT_COUNT);
+        assertMetricFamilySamplesSize(sensorlMetricFamilySamples, 1);
+        final Collector.MetricFamilySamples.Sample sensorSample = sensorlMetricFamilySamples.samples.get(0);
+        assertThat(sensorSample.labelNames, is(equalTo(Arrays.asList("name", "test_instrument_panel_name"))));
+        assertThat(sensorSample.labelValues, is(equalTo(Arrays.asList(SENSOR, INSTRUMENT_PANEL_NAME))));
+    }
+
+    @Test
+    public void testCollectForSiblingObjects()
+    {
+        createTestEngine(ELECTRIC_ENGINE_NAME, TestElecEngineImpl.TEST_ELEC_ENGINE_TYPE);
+        createTestEngine(PETROL_ENGINE_NAME, TestPetrolEngineImpl.TEST_PETROL_ENGINE_TYPE);
+
+        final List<Collector.MetricFamilySamples> metrics = _qpidCollector.collect();
+
+        final String[] expectedFamilyNames = {QPID_TEST_CAR_MILEAGE_COUNT, QPID_TEST_ENGINE_TEMPERATURE_TOTAL};
+        final Map<String, Collector.MetricFamilySamples> metricsMap =
+                convertMetricFamilySamplesIntoMapAndAssert(metrics, expectedFamilyNames);
+
+        final Collector.MetricFamilySamples carMetricFamilySamples = metricsMap.get(QPID_TEST_CAR_MILEAGE_COUNT);
+        assertMetricFamilySamplesSize(carMetricFamilySamples, 1);
+        final Collector.MetricFamilySamples.Sample carSample = carMetricFamilySamples.samples.get(0);
+        assertThat(carSample.labelNames.size(), is(equalTo(0)));
+        assertThat(carSample.labelValues.size(), is(equalTo(0)));
+
+        final Collector.MetricFamilySamples engineMetricFamilySamples = metricsMap.get(
+                QPID_TEST_ENGINE_TEMPERATURE_TOTAL);
+        assertMetricFamilySamplesSize(engineMetricFamilySamples, 2);
+        final String[] engineNames = {PETROL_ENGINE_NAME, ELECTRIC_ENGINE_NAME};
+        for (String engineName : engineNames)
+        {
+            final Collector.MetricFamilySamples.Sample sample =
+                    findSampleByLabelValue(engineMetricFamilySamples, engineName);
+            assertThat(sample.labelNames, is(equalTo(Collections.singletonList("name"))));
+            assertThat(sample.labelValues, is(equalTo(Collections.singletonList(engineName))));
+            assertThat(sample.value, Matchers.closeTo(TestAbstractEngineImpl.TEST_TEMPERATURE, 0.01));
+        }
+    }
+
+    @Test
+    public void testCollectWithFilter(){
+        createTestEngine(ELECTRIC_ENGINE_NAME, TestElecEngineImpl.TEST_ELEC_ENGINE_TYPE);
+        _root.move(DESIRED_MILEAGE);
+
+        _qpidCollector = new QpidCollector(_root,
+                                           new IncludeDisabledStatisticPredicate(true),
+                                           new IncludeMetricPredicate(Collections.singleton(QPID_TEST_CAR_AGE_COUNT)));
+        final List<Collector.MetricFamilySamples> metrics = _qpidCollector.collect();
+
+        final String[] expectedFamilyNames = {QPID_TEST_CAR_AGE_COUNT};
+        final Map<String, Collector.MetricFamilySamples> metricsMap =
+                convertMetricFamilySamplesIntoMapAndAssert(metrics, expectedFamilyNames);
+
+
+        final Collector.MetricFamilySamples engineMetricFamilySamples = metricsMap.get(QPID_TEST_CAR_AGE_COUNT);
+        assertMetricFamilySamplesSize(engineMetricFamilySamples, 1);
+        final Collector.MetricFamilySamples.Sample engineSample = engineMetricFamilySamples.samples.get(0);
+        assertThat(engineSample.labelNames, is(equalTo(Collections.emptyList())));
+        assertThat(engineSample.labelValues, is(equalTo(Collections.emptyList())));
+        assertThat(engineSample.value, Matchers.closeTo(0.0, 0.01));
+
+    }
+
+
+    private Collector.MetricFamilySamples.Sample findSampleByLabelValue(final Collector.MetricFamilySamples metricFamilySamples,
+                                                                        final String nameLabelValue)
+    {
+        final List<Collector.MetricFamilySamples.Sample> found = metricFamilySamples.samples
+                .stream()
+                .filter(s -> s.labelValues != null
+                             && s.labelValues.size() > 0
+                             && nameLabelValue.equals(s.labelValues.get(0)))
+                .collect(Collectors.toList());
+        assertThat(found.size(), is(equalTo(1)));
+        return found.get(0);
+    }
+
+    private void createTestEngine(final String engineName, final String engineType)
+    {
+        final Map<String, Object> engineAttributes = new HashMap<>();
+        engineAttributes.put(ConfiguredObject.NAME, engineName);
+        engineAttributes.put(ConfiguredObject.TYPE, engineType);
+        _root.createChild(TestEngine.class, engineAttributes);
+    }
+
+    private void createTestSensor(final TestInstrumentPanel instrumentPanel)
+    {
+        final Map<String, Object> sensorAttributes = new HashMap<>();
+        sensorAttributes.put(ConfiguredObject.NAME, SENSOR);
+        sensorAttributes.put(ConfiguredObject.TYPE, TestTemperatureSensorImpl.TEST_TEMPERATURE_SENSOR_TYPE);
+        instrumentPanel.createChild(TestSensor.class, sensorAttributes);
+    }
+
+    private TestInstrumentPanel getTestInstrumentPanel()
+    {
+        final Map<String, Object> instrumentPanelAttributes = new HashMap<>();
+        instrumentPanelAttributes.put(ConfiguredObject.NAME, INSTRUMENT_PANEL_NAME);
+        instrumentPanelAttributes.put(ConfiguredObject.TYPE,
+                                      TestDigitalInstrumentPanelImpl.TEST_DIGITAL_INSTRUMENT_PANEL_TYPE);
+        return _root.createChild(TestInstrumentPanel.class, instrumentPanelAttributes);
+    }
+
+    private Map<String, Collector.MetricFamilySamples> convertMetricFamilySamplesIntoMap(List<Collector.MetricFamilySamples> metricFamilySamples)
+    {
+        Map<String, Collector.MetricFamilySamples> result = new HashMap<>();
+        for (Collector.MetricFamilySamples metricFamilySample : metricFamilySamples)
+        {
+            final String name = metricFamilySample.name;
+
+            if (result.put(name, metricFamilySample) != null)
+            {
+                fail(String.format("Duplicate family name : %s", name));
+            }
+        }
+        return result;
+    }
+
+    private void assertMetricFamilySamples(final Collector.MetricFamilySamples metricFamilySamples)
+    {
+        assertThat(metricFamilySamples, is(notNullValue()));
+        assertThat(metricFamilySamples.samples, is(notNullValue()));
+
+        for (final Collector.MetricFamilySamples.Sample sample : metricFamilySamples.samples)
+        {
+            assertThat(sample, is(notNullValue()));
+            assertThat(sample.name, is(equalTo(metricFamilySamples.name)));
+        }
+    }
+
+
+    private void assertMetricFamilySamplesSize(final Collector.MetricFamilySamples metricFamilySamples,
+                                               final int expectedSamplesSize)
+    {
+        assertThat(metricFamilySamples.samples.size(), equalTo(expectedSamplesSize));
+    }
+
+    private Map<String, Collector.MetricFamilySamples> convertMetricFamilySamplesIntoMapAndAssert(final List<Collector.MetricFamilySamples> metrics,
+                                                                                                  final String[] expectedFamilyNames)
+    {
+        assertThat(metrics.size(), equalTo(expectedFamilyNames.length));
+        final Map<String, Collector.MetricFamilySamples> metricsMap = convertMetricFamilySamplesIntoMap(metrics);
+
+        for (String expectedFamily : expectedFamilyNames)
+        {
+            assertMetricFamilySamples(metricsMap.get(expectedFamily));
+        }
+        return metricsMap;
+    }
+
+    @Test
+    public void testToSnakeCase()
+    {
+        assertThat(QpidCollector.toSnakeCase("carEngineOilChanges"), is(equalTo("car_engine_oil_changes")));
+    }
+
+    @Test
+    public void getFamilyNameForCumulativeStatistic()
+    {
+        for (int i = 0; i < UNITS.length; i++)
+        {
+            final ConfiguredObjectStatistic<?, ?> statistics = mock(ConfiguredObjectStatistic.class);
+            when(statistics.getUnits()).thenReturn(UNITS[i]);
+            when(statistics.getStatisticType()).thenReturn(StatisticType.CUMULATIVE);
+            when(statistics.getName()).thenReturn("diagnosticData");
+            final String familyName = QpidCollector.getFamilyName(TestCar.class, statistics);
+            final String expectedName =
+                    String.format("qpid_test_car_diagnostic_data%s%s", UNIT_SUFFIXES[i], getSuffix(UNITS[i],QpidCollector.COUNT_SUFFIX));
+            assertThat(String.format("unexpected metric name for units %s", UNITS[i]),
+                       familyName,
+                       is(equalTo(expectedName)));
+        }
+    }
+
+    @Test
+    public void getFamilyNameForCumulativeStatisticContainingCountInName()
+    {
+        final ConfiguredObjectStatistic<?, ?> statistics = mock(ConfiguredObjectStatistic.class);
+        when(statistics.getUnits()).thenReturn(StatisticUnit.BYTES);
+        when(statistics.getStatisticType()).thenReturn(StatisticType.CUMULATIVE);
+        when(statistics.getName()).thenReturn("CountOfDiagnosticData");
+        final String familyName = QpidCollector.getFamilyName(TestCar.class, statistics);
+        assertThat(familyName, is(equalTo("qpid_test_car_count_of_diagnostic_data")));
+    }
+
+    @Test
+    public void getFamilyNameForPointInTimeStatistic()
+    {
+        for (int i = 0; i < UNITS.length; i++)
+        {
+            final ConfiguredObjectStatistic<?, ?> statistics = mock(ConfiguredObjectStatistic.class);
+            when(statistics.getUnits()).thenReturn(UNITS[i]);
+            when(statistics.getStatisticType()).thenReturn(StatisticType.POINT_IN_TIME);
+            when(statistics.getName()).thenReturn("diagnosticData");
+            final String familyName = QpidCollector.getFamilyName(TestCar.class, statistics);
+
+            final String expectedName =
+                    String.format("qpid_test_car_diagnostic_data%s%s", UNIT_SUFFIXES[i],  getSuffix(UNITS[i],QpidCollector.TOTAL_SUFFIX));
+            assertThat(String.format("unexpected metric name for units %s", UNITS[i]),
+                       familyName,
+                       is(equalTo(expectedName)));
+        }
+    }
+
+    String getSuffix(final StatisticUnit unit,final String requiredSuffix)
+    {
+        String suffix = "_" + requiredSuffix;
+        if(unit.equals(StatisticUnit.ABSOLUTE_TIME) || unit.equals(StatisticUnit.TIME_DURATION)){
+            suffix = "";
+        }
+        return suffix;
+    }
+}
diff --git a/doc/java-broker/src/docbkx/Java-Broker-Management-Channels.xml b/doc/java-broker/src/docbkx/Java-Broker-Management-Channels.xml
index 9211056..13e7fa2 100644
--- a/doc/java-broker/src/docbkx/Java-Broker-Management-Channels.xml
+++ b/doc/java-broker/src/docbkx/Java-Broker-Management-Channels.xml
@@ -37,5 +37,6 @@
   <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="management/channels/Java-Broker-Management-Channel-HTTP.xml"/>
   <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="management/channels/Java-Broker-Management-Channel-Web-Console.xml"/>
   <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="management/channels/Java-Broker-Management-Channel-REST-API.xml"/>
+  <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="management/channels/Java-Broker-Management-Metrics.xml"/>
   <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="management/channels/Java-Broker-Management-Channel-AMQP-Intrinsic.xml"/>
 </chapter>
diff --git a/doc/java-broker/src/docbkx/management/channels/Java-Broker-Management-Metrics.xml b/doc/java-broker/src/docbkx/management/channels/Java-Broker-Management-Metrics.xml
new file mode 100644
index 0000000..c8aeb9d
--- /dev/null
+++ b/doc/java-broker/src/docbkx/management/channels/Java-Broker-Management-Metrics.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0"?>
+<!--
+  ~ 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.
+  ~
+  -->
+
+<section xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="Java-Broker-Management-Metrics">
+  <title>Prometheus Metrics</title>
+    <para>This section describes the metrics endpoints exposing broker statistics in
+      <link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="https://prometheus.io/">Prometheus format</link>.
+      The metrics endpoint is intended for scraping by Prometheus server to collect the Broker telemetry.</para>
+    <para>The Prometheus metric endpoints are mapped under /metrics path and /metrics/*.
+      The latter allows to get the Virtual Host statistics by specify the path to the virtual host as
+      /metrics/&lt;virtual host node name&gt;/&lt; virtual host name&gt;.
+      The former allow to get all Broker statistics or Virtual Host statistics when called with HOST header
+      set to the Virtual Host name</para>
+    <para>
+      The metrics endpoints allow anonymous access by default. If required, an authentication can be enabled for the
+      metrics endpoints by setting http management context variable
+      <literal>qpid.httpManagement.enableMetricContentAuthentication</literal> to <literal>true</literal>.
+    </para>
+
+    <para>The Broker JVM statistics are disabled by default. The metrics endpoints can be called with parameter
+      <literal>includeDisabled</literal> set to <literal>true</literal> to include JVM  broker metrics into endpoint
+      output.
+    </para>
+    <note>
+      <para>For more information about Prometheus, check out the
+        <link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="https://prometheus.io/docs/introduction/overview/">prometheus documentation</link>.
+      </para>
+    </note>
+
+</section>
diff --git a/pom.xml b/pom.xml
index 274b957..c49bcb8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -154,6 +154,7 @@
     <h2.version>1.4.199</h2.version>
     <apache-directory-version>2.0.0-M23</apache-directory-version>
     <kerby-version>1.0.1</kerby-version>
+    <prometheus-client-version>0.9.0</prometheus-client-version>
   </properties>
 
   <modules>
@@ -179,6 +180,7 @@
     <module>broker-plugins/websocket</module>
     <module>broker-plugins/amqp-1-0-bdb-store</module>
     <module>broker-plugins/amqp-1-0-jdbc-store</module>
+    <module>broker-plugins/prometheus-exporter</module>
     <module>tools</module>
 
     <module>qpid-systests-parent</module>
@@ -469,6 +471,12 @@
         <version>${project.version}</version>
       </dependency>
 
+      <dependency>
+        <groupId>org.apache.qpid</groupId>
+        <artifactId>qpid-broker-plugins-prometheus-exporter</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+
       <!-- External dependencies -->
       <dependency>
         <groupId>org.apache.qpid</groupId>
@@ -750,6 +758,18 @@
         <scope>test</scope>
         <version>${kerby-version}</version>
       </dependency>
+
+      <!-- prometheus client dependencies -->
+      <dependency>
+        <groupId>io.prometheus</groupId>
+        <artifactId>simpleclient</artifactId>
+        <version>${prometheus-client-version}</version>
+      </dependency>
+      <dependency>
+        <groupId>io.prometheus</groupId>
+        <artifactId>simpleclient_common</artifactId>
+        <version>${prometheus-client-version}</version>
+      </dependency>
     </dependencies>
   </dependencyManagement>
 
diff --git a/systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/metrics/BrokerMetricsAuthenticationTest.java b/systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/metrics/BrokerMetricsAuthenticationTest.java
new file mode 100644
index 0000000..fcfca5e
--- /dev/null
+++ b/systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/metrics/BrokerMetricsAuthenticationTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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.tests.http.metrics;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.junit.Test;
+
+import org.apache.qpid.server.management.plugin.HttpManagement;
+import org.apache.qpid.tests.http.HttpRequestConfig;
+import org.apache.qpid.tests.http.HttpTestBase;
+import org.apache.qpid.tests.http.HttpTestHelper;
+import org.apache.qpid.tests.utils.ConfigItem;
+
+@HttpRequestConfig(useVirtualHostAsHost = false)
+@ConfigItem(name = HttpManagement.HTTP_MANAGEMENT_ENABLE_CONTENT_AUTHENTICATION, value = "true")
+public class BrokerMetricsAuthenticationTest extends HttpTestBase
+{
+    @Test
+    public void testBrokerMetricsForAuthenticatedUser() throws Exception
+    {
+        getHelper().submitRequest("/metrics", "GET", HttpServletResponse.SC_OK);
+    }
+
+    @Test
+    public void testBrokerMetricsForUnauthenticatedUser() throws Exception
+    {
+        final HttpTestHelper helper = new HttpTestHelper(getBrokerAdmin(), null);
+        helper.setUserName(null);
+        helper.setPassword(null);
+        helper.submitRequest("/metrics", "GET", HttpServletResponse.SC_UNAUTHORIZED);
+    }
+
+}
diff --git a/systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/metrics/BrokerMetricsTest.java b/systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/metrics/BrokerMetricsTest.java
new file mode 100644
index 0000000..7423588
--- /dev/null
+++ b/systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/metrics/BrokerMetricsTest.java
@@ -0,0 +1,80 @@
+package org.apache.qpid.tests.http.metrics;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.apache.qpid.tests.http.metrics.TestMetricsHelper.QUEUE_NAME;
+import static org.apache.qpid.tests.http.metrics.TestMetricsHelper.assertMetricsInclusion;
+import static org.apache.qpid.tests.http.metrics.TestMetricsHelper.assertVirtualHostHierarchyMetrics;
+import static org.apache.qpid.tests.http.metrics.TestMetricsHelper.createQueueMetricPattern;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import java.util.Collection;
+import java.util.regex.Pattern;
+
+import org.junit.Test;
+
+import org.apache.qpid.tests.http.HttpRequestConfig;
+import org.apache.qpid.tests.http.HttpTestBase;
+
+@HttpRequestConfig(useVirtualHostAsHost = false)
+public class BrokerMetricsTest extends HttpTestBase
+{
+    private static final String[] EXPECTED_BROKER_METRIC_NAMES =
+            new String[]{"qpid_broker_inbound_bytes_count", "qpid_broker_outbound_bytes_count"};
+
+    @Test
+    public void testBrokerMetrics() throws Exception
+    {
+        final String[] unexpectedMetricNames =
+                {"qpid_broker_live_threads_total", "qpid_broker_direct_memory_capacity_bytes_total"};
+
+        final byte[] metricsBytes = getHelper().getBytes("/metrics");
+        final String metricsString = new String(metricsBytes, UTF_8);
+        assertMetricsInclusion(metricsString, EXPECTED_BROKER_METRIC_NAMES, true);
+        assertMetricsInclusion(metricsString, unexpectedMetricNames, false);
+
+        final byte[] metricsBytesIncludingDisabled = getHelper().getBytes("/metrics?includeDisabled=true");
+        final String metricsStringIncludingDisabled = new String(metricsBytesIncludingDisabled, UTF_8);
+        assertMetricsInclusion(metricsStringIncludingDisabled, unexpectedMetricNames, true);
+        assertMetricsInclusion(metricsStringIncludingDisabled, EXPECTED_BROKER_METRIC_NAMES, true);
+    }
+
+    @Test
+    public void testQueueMetrics() throws Exception
+    {
+        getBrokerAdmin().createQueue(QUEUE_NAME);
+        final byte[] metricsBytes = getHelper().getBytes("/metrics");
+        final String metricsString = new String(metricsBytes, UTF_8);
+
+        final Pattern[] expectedMetricPattens = {createQueueMetricPattern("qpid_queue_consumers_total"),
+                createQueueMetricPattern("qpid_queue_depth_messages_total")};
+
+        assertMetricsInclusion(metricsString, expectedMetricPattens, true);
+    }
+
+    @Test
+    public void testQueueMetricsIncludeOnlyMessageDepth() throws Exception
+    {
+        getBrokerAdmin().createQueue(QUEUE_NAME);
+        final byte[] metricsBytes = getHelper().getBytes("/metrics?name[]=qpid_queue_depth_messages_total&name[]=qpid_queue_depth_bytes_total");
+        Collection<String> metricLines = TestMetricsHelper.getMetricLines(metricsBytes);
+        assertThat(metricLines.size(), is(equalTo(2)));
+
+        final String metricsString = new String(metricsBytes, UTF_8);
+        final Pattern[] expectedMetricPattens = {createQueueMetricPattern("qpid_queue_depth_bytes_total"),
+                createQueueMetricPattern("qpid_queue_depth_messages_total")};
+
+        assertMetricsInclusion(metricsString, expectedMetricPattens, true);
+    }
+
+    @Test
+    public void testMappingForVirtualHost() throws Exception
+    {
+        getBrokerAdmin().createQueue(QUEUE_NAME);
+        final byte[] metricsBytes =
+                getHelper().getBytes(String.format("/metrics/%s/%s", getVirtualHostNode(), getVirtualHost()));
+
+        assertVirtualHostHierarchyMetrics(metricsBytes);
+    }
+}
diff --git a/systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/metrics/TestMetricsHelper.java b/systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/metrics/TestMetricsHelper.java
new file mode 100644
index 0000000..fa9b679
--- /dev/null
+++ b/systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/metrics/TestMetricsHelper.java
@@ -0,0 +1,93 @@
+/*
+ * 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.tests.http.metrics;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.fail;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.function.Predicate;
+import java.util.regex.Pattern;
+
+class TestMetricsHelper
+{
+    static final String QUEUE_NAME = "foo";
+
+    static void assertMetricsInclusion(final String metricsString,
+                                       final String[] metricNames,
+                                       final boolean inclusionFlag)
+    {
+        for (String expected : metricNames)
+        {
+            assertThat(metricsString.contains(expected), equalTo(inclusionFlag));
+        }
+    }
+
+    static void assertMetricsInclusion(final String metricsString,
+                                       final Pattern[] expectedMetricPattens,
+                                       final boolean inclusionFlag)
+    {
+        for (Pattern expected : expectedMetricPattens)
+        {
+            assertThat(expected.matcher(metricsString).find(), equalTo(inclusionFlag));
+        }
+    }
+
+    static Pattern createQueueMetricPattern(final String metricName)
+    {
+        return Pattern.compile(String.format("%s\\s*\\{.*name\\s*=\\s*\"%s\"\\s*,.*\\}\\s*0\\.0",
+                                             metricName,
+                                             QUEUE_NAME));
+    }
+
+    static void assertVirtualHostHierarchyMetrics(final byte[] metricsBytes) throws IOException
+    {
+        final Predicate<String> unexpectedMetricPredicate = line -> !(line.startsWith("qpid_virtual_host")
+                                                                      || line.startsWith("qpid_queue")
+                                                                      || line.startsWith("qpid_exchange"));
+        getMetricLines(metricsBytes).stream().filter(unexpectedMetricPredicate)
+                                    .findFirst().ifPresent(found -> fail("Unexpected metric: " + found));
+    }
+
+    static Collection<String> getMetricLines(final byte[] metricsBytes) throws IOException
+    {
+        final List<String> results = new ArrayList<>();
+        try(BufferedReader reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(metricsBytes))))
+        {
+            String line;
+            while ((line = reader.readLine()) != null)
+            {
+                if (!(line.startsWith("#") || line.isEmpty()))
+                {
+                    results.add(line);
+                }
+            }
+        }
+        return results;
+    }
+}
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectStatistic.java b/systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/metrics/VirtualHostMetricsTest.java
similarity index 54%
copy from broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectStatistic.java
copy to systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/metrics/VirtualHostMetricsTest.java
index cc22d62..bd06588 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectStatistic.java
+++ b/systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/metrics/VirtualHostMetricsTest.java
@@ -1,5 +1,4 @@
 /*
- *
  * 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
@@ -18,15 +17,25 @@
  * under the License.
  *
  */
-package org.apache.qpid.server.model;
 
-public interface ConfiguredObjectStatistic<C extends ConfiguredObject, T extends Object> extends ConfiguredObjectAttributeOrStatistic<C,T>
-{
-    String getDescription();
+package org.apache.qpid.tests.http.metrics;
 
-    StatisticUnit getUnits();
+import static org.apache.qpid.tests.http.metrics.TestMetricsHelper.QUEUE_NAME;
+import static org.apache.qpid.tests.http.metrics.TestMetricsHelper.assertVirtualHostHierarchyMetrics;
 
-    StatisticType getStatisticType();
+import org.junit.Test;
 
-    String getLabel();
+import org.apache.qpid.tests.http.HttpRequestConfig;
+import org.apache.qpid.tests.http.HttpTestBase;
+
+@HttpRequestConfig
+public class VirtualHostMetricsTest extends HttpTestBase
+{
+    @Test
+    public void testVirtualHostMetrics() throws Exception
+    {
+        getBrokerAdmin().createQueue(QUEUE_NAME);
+        final byte[] metricsBytes = getHelper().getBytes("/metrics");
+        assertVirtualHostHierarchyMetrics(metricsBytes);
+    }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[qpid-broker-j] 09/10: QPID-8454:[Broker-J] Update documentation

Posted by or...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

orudyy pushed a commit to branch 7.1.x
in repository https://gitbox.apache.org/repos/asf/qpid-broker-j.git

commit f7f5145132e67a4aead14a2156907834830160c8
Author: Alex Rudyy <or...@apache.org>
AuthorDate: Tue Sep 1 21:54:50 2020 +0100

    QPID-8454:[Broker-J] Update documentation
    
    (cherry picked from commit 2c071a3ee3ebd43b8655f9e42f8c986dd15ea68c)
---
 .../src/docbkx/management/channels/Java-Broker-Management-Metrics.xml  | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/doc/java-broker/src/docbkx/management/channels/Java-Broker-Management-Metrics.xml b/doc/java-broker/src/docbkx/management/channels/Java-Broker-Management-Metrics.xml
index c8aeb9d..a75ec05 100644
--- a/doc/java-broker/src/docbkx/management/channels/Java-Broker-Management-Metrics.xml
+++ b/doc/java-broker/src/docbkx/management/channels/Java-Broker-Management-Metrics.xml
@@ -37,7 +37,8 @@
 
     <para>The Broker JVM statistics are disabled by default. The metrics endpoints can be called with parameter
       <literal>includeDisabled</literal> set to <literal>true</literal> to include JVM  broker metrics into endpoint
-      output.
+      output. If required, the JVM metrics could be enabled by setting context variable
+      <literal>qpid.metrics.includeDisabled</literal> to <literal>true</literal>.
     </para>
     <note>
       <para>For more information about Prometheus, check out the


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[qpid-broker-j] 10/10: QPID-8454:[Broker-J] Add missing license

Posted by or...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

orudyy pushed a commit to branch 7.1.x
in repository https://gitbox.apache.org/repos/asf/qpid-broker-j.git

commit 627ce9dc00421c39abbf229fe38a5ac14206385d
Author: Alex Rudyy <or...@apache.org>
AuthorDate: Wed Sep 2 20:31:12 2020 +0100

    QPID-8454:[Broker-J] Add missing license
    
    (cherry picked from commit 59b25c8dc7f6caaf12981dff46f46db4bb02a746)
---
 .../qpid/tests/http/metrics/BrokerMetricsTest.java   | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/metrics/BrokerMetricsTest.java b/systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/metrics/BrokerMetricsTest.java
index 7423588..a86188f 100644
--- a/systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/metrics/BrokerMetricsTest.java
+++ b/systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/metrics/BrokerMetricsTest.java
@@ -1,3 +1,23 @@
+/*
+ * 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.tests.http.metrics;
 
 import static java.nio.charset.StandardCharsets.UTF_8;


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[qpid-broker-j] 04/10: QPID-8458: [Broker-J] Removed RewriteServlet from HTTP management

Posted by or...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

orudyy pushed a commit to branch 7.1.x
in repository https://gitbox.apache.org/repos/asf/qpid-broker-j.git

commit 1c0446625a438569d27f7a401fadefebd253de55
Author: Tomas Vavricka <to...@deutsche-boerse.com>
AuthorDate: Tue Aug 4 14:09:27 2020 +0000

    QPID-8458: [Broker-J] Removed RewriteServlet from HTTP management
    
    (cherry picked from commit 370fb357b766c2c5d3e3016a274601650181cd1a)
---
 .../server/management/plugin/HttpManagement.java   | 11 +---
 .../server/management/plugin/RewriteServlet.java   | 55 -------------------
 .../plugin/servlet/rest/ApiDocsServlet.java        | 64 ++++++++++------------
 3 files changed, 32 insertions(+), 98 deletions(-)

diff --git a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java
index c6bed8a..39709df 100644
--- a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java
+++ b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java
@@ -382,10 +382,10 @@ public class HttpManagement extends AbstractPluginAdapter<HttpManagement> implem
 
 
         ServletHolder apiDocsServlet = new ServletHolder(new ApiDocsServlet());
-        final ServletHolder rewriteSerlvet = new ServletHolder(new RewriteServlet("^(.*)$", "$1/"));
-        for(String path : new String[]{"/apidocs", "/apidocs/latest", "/apidocs/"+getLatestSupportedVersion()})
+        final String version = "v" + BrokerModel.MODEL_VERSION;
+        for (final String path : new String[]{"/apidocs", "/apidocs/latest", "/apidocs/" + version})
         {
-            root.addServlet(rewriteSerlvet, path);
+            root.addServlet(apiDocsServlet, path);
             root.addServlet(apiDocsServlet, path + "/");
         }
 
@@ -763,11 +763,6 @@ public class HttpManagement extends AbstractPluginAdapter<HttpManagement> implem
         root.addServlet(versionsServletHolder, "/api/");
     }
 
-    private String getLatestSupportedVersion()
-    {
-        return "v"+String.valueOf(BrokerModel.MODEL_VERSION);
-    }
-
     private void logOperationalListenMessages()
     {
         for (Map.Entry<HttpPort<?>, ServerConnector> portConnector : _portConnectorMap.entrySet())
diff --git a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/RewriteServlet.java b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/RewriteServlet.java
deleted file mode 100644
index c222662..0000000
--- a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/RewriteServlet.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- *
- * 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.management.plugin;
-
-import java.io.IOException;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-public class RewriteServlet extends HttpServlet
-{
-    private static final long serialVersionUID = 1L;
-
-    private final String _pattern;
-    private final String _replacement;
-
-    public RewriteServlet(final String pattern, final String replacement)
-    {
-        _pattern = pattern;
-        _replacement = replacement;
-
-    }
-
-    @Override
-    protected void service(final HttpServletRequest req, final HttpServletResponse resp)
-            throws ServletException, IOException
-    {
-        String location = req.getRequestURI().replaceAll(_pattern, _replacement);
-        if(req.getQueryString() != null)
-        {
-            location += "?" + req.getQueryString();
-        }
-        resp.sendRedirect(location);
-    }
-}
diff --git a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/ApiDocsServlet.java b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/ApiDocsServlet.java
index 6e5bddc..ca1c9d2 100644
--- a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/ApiDocsServlet.java
+++ b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/ApiDocsServlet.java
@@ -18,17 +18,24 @@ package org.apache.qpid.server.management.plugin.servlet.rest;
 
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
-import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import org.apache.qpid.server.model.ConfiguredObject;
 import org.apache.qpid.server.model.ConfiguredObjectAttribute;
 import org.apache.qpid.server.model.ConfiguredObjectAttributeOrStatistic;
@@ -45,23 +52,12 @@ public class ApiDocsServlet extends AbstractServlet
 {
     private static final long serialVersionUID = 1L;
 
-    private static final Logger LOGGER = LoggerFactory.getLogger(ApiDocsServlet.class);
-
     private static final Set<Character> VOWELS = new HashSet<>(Arrays.asList('a','e','i','o','u'));
 
     public static final Comparator<Class<? extends ConfiguredObject>> CLASS_COMPARATOR =
-            new Comparator<Class<? extends ConfiguredObject>>()
-            {
-                @Override
-                public int compare(final Class<? extends ConfiguredObject> o1,
-                                   final Class<? extends ConfiguredObject> o2)
-                {
-                    return o1.getSimpleName().compareTo(o2.getSimpleName());
-                }
-
-            };
+            Comparator.comparing(Class::getSimpleName);
 
-    private transient final ConcurrentMap<Class<? extends ConfiguredObject>, List<Class<? extends ConfiguredObject>>> _typeSpecialisations = new ConcurrentHashMap<>();
+    private final transient ConcurrentMap<Class<? extends ConfiguredObject>, List<Class<? extends ConfiguredObject>>> _typeSpecialisations = new ConcurrentHashMap<>();
 
     public ApiDocsServlet()
     {
@@ -71,9 +67,9 @@ public class ApiDocsServlet extends AbstractServlet
     @Override
     protected void doGet(HttpServletRequest request,
                          HttpServletResponse response,
-                         final ConfiguredObject<?> managedObject) throws ServletException, IOException
+                         final ConfiguredObject<?> managedObject) throws IOException
     {
-        ConfiguredObjectFinder finder = getConfiguredObjectFinder(managedObject);
+        final ConfiguredObjectFinder finder = getConfiguredObjectFinder(managedObject);
 
         final Class<? extends ConfiguredObject> configuredClass;
 
@@ -81,7 +77,7 @@ public class ApiDocsServlet extends AbstractServlet
 
         final String[] servletPathParts = request.getServletPath().split("/");
         final Model model = managedObject.getModel();
-        if(servletPathParts.length < 4)
+        if (servletPathParts.length < 4)
         {
             configuredClass = null;
             hierarchy = null;
@@ -100,10 +96,10 @@ public class ApiDocsServlet extends AbstractServlet
                 sendError(response, HttpServletResponse.SC_NOT_FOUND);
                 return;
             }
-            if(!_typeSpecialisations.containsKey(configuredClass))
+            if (!_typeSpecialisations.containsKey(configuredClass))
             {
-                List<Class<? extends ConfiguredObject>> types = new ArrayList<>(model
-                                                                                        .getTypeRegistry().getTypeSpecialisations(configuredClass));
+                final List<Class<? extends ConfiguredObject>> types =
+                        new ArrayList<>(model.getTypeRegistry().getTypeSpecialisations(configuredClass));
                 _typeSpecialisations.putIfAbsent(configuredClass, types);
             }
         }
@@ -111,12 +107,12 @@ public class ApiDocsServlet extends AbstractServlet
         response.setStatus(HttpServletResponse.SC_OK);
 
 
-        PrintWriter writer = response.getWriter();
+        final PrintWriter writer = response.getWriter();
 
         writePreamble(writer);
         writeHead(writer, hierarchy, configuredClass);
 
-        if(hierarchy == null)
+        if (hierarchy == null)
         {
             writer.println("<table class=\"api\">");
             writer.println("<thead>");
@@ -127,23 +123,21 @@ public class ApiDocsServlet extends AbstractServlet
             writer.println("</tr>");
             writer.println("</thead>");
             writer.println("<tbody>");
-            SortedSet<Class<? extends ConfiguredObject>> managedCategories = new TreeSet<>(CLASS_COMPARATOR);
+            final SortedSet<Class<? extends ConfiguredObject>> managedCategories = new TreeSet<>(CLASS_COMPARATOR);
             managedCategories.addAll(finder.getManagedCategories());
-            String pathStem = "/" + servletPathParts[1] + "/" + (servletPathParts.length == 2 ? "latest" : servletPathParts[2]) + "/";
-            for(Class<? extends ConfiguredObject> category : managedCategories)
+            final String pathStem = "/" + servletPathParts[1] + "/" + (servletPathParts.length == 2 ? "latest" : servletPathParts[2]) + "/";
+            for (final Class<? extends ConfiguredObject> category : managedCategories)
             {
-                Class<? extends ConfiguredObject> objClass = category;
-                String path = pathStem + category.getSimpleName().toLowerCase();
+                final String path = pathStem + category.getSimpleName().toLowerCase();
                 writer.println("<tr>");
-                writer.println("<td class=\"type\"><a href=" + ((servletPathParts.length == 2) ? "\"latest/" : "")+ objClass.getSimpleName().toLowerCase()+"\">"+objClass.getSimpleName()+"</a></td>");
+                writer.println("<td class=\"type\"><a href=" + path + ">" + category.getSimpleName() + "</a></td>");
                 writer.println("<td class=\"path\">" + path + "</td>");
-                writer.println("<td class=\"description\">"+
-                               objClass.getAnnotation(ManagedObject.class).description()+"</td>");
+                writer.println("<td class=\"description\">" +
+                        category.getAnnotation(ManagedObject.class).description()+"</td>");
                 writer.println("</tr>");
             }
             writer.println("</tbody>");
             writer.println("</table>");
-
         }
         else
         {


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[qpid-broker-j] 01/10: NO-JIRA: Fix Kerberos tests

Posted by or...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

orudyy pushed a commit to branch 7.1.x
in repository https://gitbox.apache.org/repos/asf/qpid-broker-j.git

commit 55bab0d6d226faf9077a6590cecb439f6c2071d8
Author: Alex Rudyy <or...@apache.org>
AuthorDate: Fri Nov 29 13:08:51 2019 +0000

    NO-JIRA: Fix Kerberos tests
---
 .../manager/KerberosAuthenticationManagerTest.java |  79 +++++----
 .../SimpleLDAPAuthenticationManagerTest.java       |  17 +-
 .../auth/manager/SpnegoAuthenticatorTest.java      |  61 +++----
 .../qpid/server/test/EmbeddedKdcResource.java      |  29 +--
 .../apache/qpid/server/test/KerberosUtilities.java | 196 +++++++++++++++++++--
 broker-core/src/test/resources/login.ibm.config    |  51 ++++++
 .../java/org/apache/qpid/test/utils/JvmVendor.java |  25 ++-
 .../org/apache/qpid/test/utils/UnitTestBase.java   |  18 +-
 8 files changed, 338 insertions(+), 138 deletions(-)

diff --git a/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/KerberosAuthenticationManagerTest.java b/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/KerberosAuthenticationManagerTest.java
index e24d56c..9211710 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/KerberosAuthenticationManagerTest.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/KerberosAuthenticationManagerTest.java
@@ -19,19 +19,22 @@
 
 package org.apache.qpid.server.security.auth.manager;
 
-import static org.apache.commons.codec.CharEncoding.UTF_8;
 import static org.apache.qpid.server.security.auth.manager.KerberosAuthenticationManager.GSSAPI_MECHANISM;
-import static org.hamcrest.Matchers.not;
+import static org.apache.qpid.server.test.KerberosUtilities.ACCEPT_SCOPE;
+import static org.apache.qpid.server.test.KerberosUtilities.CLIENT_PRINCIPAL_FULL_NAME;
+import static org.apache.qpid.server.test.KerberosUtilities.CLIENT_PRINCIPAL_NAME;
+import static org.apache.qpid.server.test.KerberosUtilities.HOST_NAME;
+import static org.apache.qpid.server.test.KerberosUtilities.LOGIN_CONFIG;
+import static org.apache.qpid.server.test.KerberosUtilities.REALM;
+import static org.apache.qpid.server.test.KerberosUtilities.SERVER_PROTOCOL;
+import static org.apache.qpid.server.test.KerberosUtilities.SERVICE_PRINCIPAL_NAME;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.fail;
-import static org.junit.Assume.assumeThat;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import java.io.File;
-import java.net.URL;
-import java.net.URLDecoder;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
 import java.util.Base64;
@@ -45,13 +48,10 @@ import javax.security.auth.login.LoginContext;
 import javax.security.sasl.Sasl;
 import javax.security.sasl.SaslClient;
 
-import org.ietf.jgss.GSSException;
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.ClassRule;
 import org.junit.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import org.apache.qpid.server.configuration.IllegalConfigurationException;
 import org.apache.qpid.server.model.AuthenticationProvider;
@@ -62,26 +62,20 @@ import org.apache.qpid.server.security.auth.sasl.SaslNegotiator;
 import org.apache.qpid.server.security.auth.sasl.SaslSettings;
 import org.apache.qpid.server.test.EmbeddedKdcResource;
 import org.apache.qpid.server.test.KerberosUtilities;
-import org.apache.qpid.test.utils.JvmVendor;
+import org.apache.qpid.server.util.StringUtil;
 import org.apache.qpid.test.utils.SystemPropertySetter;
 import org.apache.qpid.test.utils.UnitTestBase;
 
 public class KerberosAuthenticationManagerTest extends UnitTestBase
 {
-    private static final Logger LOGGER = LoggerFactory.getLogger(KerberosAuthenticationManagerTest.class);
-    private static final String LOGIN_CONFIG = "login.config";
-    private static final String REALM = "QPID.ORG";
-    private static final String SERVER_NAME = "localhost";
-    private static final String SERVER_PROTOCOL = "AMQP";
-    private static final String SERVICE_PRINCIPAL_NAME = SERVER_PROTOCOL + "/" + SERVER_NAME;
-    private static final String SERVER_PRINCIPAL_FULL_NAME = SERVICE_PRINCIPAL_NAME + "@" + REALM;
-    private static final String CLIENT_PRINCIPAL_NAME = "client";
-    private static final String CLIENT_PRINCIPAL_FULL_NAME = CLIENT_PRINCIPAL_NAME + "@" + REALM;
 
     private static final KerberosUtilities UTILS = new KerberosUtilities();
 
     @ClassRule
-    public static final EmbeddedKdcResource KDC = new EmbeddedKdcResource(REALM);
+    public static final EmbeddedKdcResource KDC = new EmbeddedKdcResource(HOST_NAME,
+                                                                          0,
+                                                                          "QpidTestKerberosServer",
+                                                                          REALM);
 
     @ClassRule
     public static final SystemPropertySetter SYSTEM_PROPERTY_SETTER = new SystemPropertySetter();
@@ -94,21 +88,15 @@ public class KerberosAuthenticationManagerTest extends UnitTestBase
     @BeforeClass
     public static void createKeyTabs() throws Exception
     {
-        assumeThat(getJvmVendor(), not(JvmVendor.IBM));
-        KDC.createPrincipal("broker.keytab", SERVER_PRINCIPAL_FULL_NAME);
-        _clientKeyTabFile = KDC.createPrincipal("client.keytab", CLIENT_PRINCIPAL_FULL_NAME);
-        final URL resource = KerberosAuthenticationManagerTest.class.getClassLoader().getResource(LOGIN_CONFIG);
-        LOGGER.debug("JAAS config:" + resource);
-        assertNotNull(resource);
-        SYSTEM_PROPERTY_SETTER.setSystemProperty("java.security.auth.login.config", URLDecoder.decode(resource.getPath(), UTF_8));
-        SYSTEM_PROPERTY_SETTER.setSystemProperty("javax.security.auth.useSubjectCredsOnly", "false");
+        UTILS.prepareConfiguration(HOST_NAME, SYSTEM_PROPERTY_SETTER);
+        _clientKeyTabFile = UTILS.prepareKeyTabs(KDC);
     }
 
     @Before
     public void setUp() throws Exception
     {
         Map<String, String> context = Collections.singletonMap(KerberosAuthenticationManager.GSSAPI_SPNEGO_CONFIG,
-                                                               "com.sun.security.jgss.accept");
+                                                               ACCEPT_SCOPE);
         final Map<String, Object> attributes = new HashMap<>();
         attributes.put(AuthenticationProvider.NAME, getTestName());
         attributes.put(AuthenticationProvider.CONTEXT, context);
@@ -123,7 +111,7 @@ public class KerberosAuthenticationManagerTest extends UnitTestBase
     public void testCreateSaslNegotiator() throws Exception
     {
         final SaslSettings saslSettings = mock(SaslSettings.class);
-        when(saslSettings.getLocalFQDN()).thenReturn(SERVER_NAME);
+        when(saslSettings.getLocalFQDN()).thenReturn(HOST_NAME);
         final SaslNegotiator negotiator = _kerberosAuthenticationProvider.createSaslNegotiator(GSSAPI_MECHANISM,
                                                                                                saslSettings,
                                                                                                null);
@@ -163,7 +151,7 @@ public class KerberosAuthenticationManagerTest extends UnitTestBase
     public void testCreateKerberosAuthenticationProvidersWithNonExistingJaasLoginModule()
     {
         when(_broker.getChildren(AuthenticationProvider.class)).thenReturn(Collections.emptySet());
-        SYSTEM_PROPERTY_SETTER.setSystemProperty("java.security.auth.login.config",
+        SYSTEM_PROPERTY_SETTER.setSystemProperty(LOGIN_CONFIG,
                                                  "config.module." + System.nanoTime());
         final Map<String, Object> attributes = Collections.singletonMap(AuthenticationProvider.NAME, getTestName());
         final KerberosAuthenticationManager kerberosAuthenticationProvider =
@@ -180,10 +168,11 @@ public class KerberosAuthenticationManagerTest extends UnitTestBase
     }
 
     @Test
-    public void testAuthenticateUsingNegotiationToken() throws GSSException
+    public void testAuthenticateUsingNegotiationToken() throws Exception
     {
-        final String token =
-                Base64.getEncoder().encodeToString(UTILS.buildToken(CLIENT_PRINCIPAL_NAME, SERVICE_PRINCIPAL_NAME));
+        byte[] negotiationTokenBytes =
+                UTILS.buildToken(CLIENT_PRINCIPAL_NAME, _clientKeyTabFile, SERVICE_PRINCIPAL_NAME);
+        final String token = Base64.getEncoder().encodeToString(negotiationTokenBytes);
         final String authenticationHeader = SpnegoAuthenticator.NEGOTIATE_PREFIX + token;
 
         final AuthenticationResult result = _kerberosAuthenticationProvider.authenticate(authenticationHeader);
@@ -197,19 +186,30 @@ public class KerberosAuthenticationManagerTest extends UnitTestBase
         final LoginContext lc = UTILS.createKerberosKeyTabLoginContext(getTestName(),
                                                                        CLIENT_PRINCIPAL_FULL_NAME,
                                                                        _clientKeyTabFile);
+
+        Subject clientSubject = null;
         try
         {
             lc.login();
-            final Subject clientSubject = lc.getSubject();
+            clientSubject = lc.getSubject();
+            debug("LoginContext subject {}", clientSubject);
             final SaslClient saslClient = createSaslClient(clientSubject);
             return performNegotiation(clientSubject, saslClient, negotiator);
         }
         finally
         {
-            lc.logout();
+            if (clientSubject != null)
+            {
+                lc.logout();
+            }
         }
     }
 
+    private void debug(String message, Object... args)
+    {
+        UTILS.debug(message, args);
+    }
+
     private AuthenticationResult performNegotiation(final Subject clientSubject,
                                                     final SaslClient saslClient,
                                                     final SaslNegotiator negotiator)
@@ -223,6 +223,7 @@ public class KerberosAuthenticationManagerTest extends UnitTestBase
             if (!initiated)
             {
                 initiated = true;
+                debug("Sending initial challenge");
                 response = Subject.doAs(clientSubject, (PrivilegedExceptionAction<byte[]>) () -> {
                     if (saslClient.hasInitialResponse())
                     {
@@ -230,19 +231,25 @@ public class KerberosAuthenticationManagerTest extends UnitTestBase
                     }
                     return null;
                 });
+                debug("Initial challenge sent");
             }
 
+            debug("Handling response: {}", StringUtil.toHex(response));
             result = negotiator.handleResponse(response);
 
             byte[] challenge = result.getChallenge();
+
             if (challenge != null)
             {
+                debug("Challenge: {}", StringUtil.toHex(challenge));
                 response = Subject.doAs(clientSubject,
                                         (PrivilegedExceptionAction<byte[]>) () -> saslClient.evaluateChallenge(
                                                 challenge));
             }
         }
         while (result.getStatus() == AuthenticationResult.AuthenticationStatus.CONTINUE);
+
+        debug("Result {}", result.getStatus());
         return result;
     }
 
@@ -256,7 +263,7 @@ public class KerberosAuthenticationManagerTest extends UnitTestBase
             return Sasl.createSaslClient(new String[]{GSSAPI_MECHANISM},
                                          null,
                                          SERVER_PROTOCOL,
-                                         SERVER_NAME,
+                                         HOST_NAME,
                                          props,
                                          null);
         });
diff --git a/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManagerTest.java b/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManagerTest.java
index 3f6efa5..ed33947 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManagerTest.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManagerTest.java
@@ -20,7 +20,7 @@ package org.apache.qpid.server.security.auth.manager;
 
 import static java.nio.charset.StandardCharsets.UTF_8;
 import static org.apache.qpid.server.security.auth.manager.CachingAuthenticationProvider.AUTHENTICATION_CACHE_MAX_SIZE;
-import static org.hamcrest.Matchers.not;
+import static org.hamcrest.CoreMatchers.not;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.fail;
@@ -31,8 +31,6 @@ import static org.mockito.Mockito.when;
 import java.io.File;
 import java.io.IOException;
 import java.net.InetSocketAddress;
-import java.net.URL;
-import java.net.URLDecoder;
 import java.nio.file.FileSystems;
 import java.nio.file.Path;
 import java.security.Principal;
@@ -49,7 +47,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
 import javax.security.auth.Subject;
 import javax.security.auth.kerberos.KerberosPrincipal;
 
-import org.apache.commons.codec.CharEncoding;
 import org.apache.directory.api.ldap.model.constants.SupportedSaslMechanisms;
 import org.apache.directory.api.ldap.model.entry.DefaultEntry;
 import org.apache.directory.api.ldap.model.entry.Entry;
@@ -91,6 +88,7 @@ import org.apache.qpid.server.security.auth.SocketConnectionPrincipal;
 import org.apache.qpid.server.security.auth.sasl.SaslNegotiator;
 import org.apache.qpid.server.security.auth.sasl.SaslSettings;
 import org.apache.qpid.test.utils.JvmVendor;
+import org.apache.qpid.server.test.KerberosUtilities;
 import org.apache.qpid.test.utils.SystemPropertySetter;
 import org.apache.qpid.test.utils.TestFileUtils;
 import org.apache.qpid.test.utils.UnitTestBase;
@@ -147,9 +145,9 @@ public class SimpleLDAPAuthenticationManagerTest extends UnitTestBase
     private static final String HOSTNAME = "localhost";
     private static final String BROKER_PRINCIPAL = "service/" + HOSTNAME;
     private static final String LINE_SEPARATOR = System.lineSeparator();
-    private static final String LOGIN_CONFIG = "login.config";
     private static final String LOGIN_SCOPE = "ldap-gssapi-bind";
     private static final AtomicBoolean KERBEROS_SETUP = new AtomicBoolean();
+    private static final KerberosUtilities UTILS = new KerberosUtilities();
 
     @ClassRule
     public static CreateLdapServerRule LDAP = new CreateLdapServerRule();
@@ -400,14 +398,11 @@ public class SimpleLDAPAuthenticationManagerTest extends UnitTestBase
         createPrincipal("Service", "LDAP Service", "ldap", UUID.randomUUID().toString(), servicePrincipalName);
     }
 
-    private void setUpJaas() throws LdapException, IOException
+    private void setUpJaas() throws Exception
     {
         createKeyTab(BROKER_PRINCIPAL);
-        final URL resource = SimpleLDAPAuthenticationManagerTest.class.getClassLoader().getResource(LOGIN_CONFIG);
-        LOGGER.debug("JAAS config:" + resource);
-        assertNotNull(resource);
-        SYSTEM_PROPERTY_SETTER.setSystemProperty("java.security.auth.login.config", URLDecoder.decode(resource.getPath(), CharEncoding.UTF_8));
-        SYSTEM_PROPERTY_SETTER.setSystemProperty("sun.security.krb5.debug", "true");
+
+        UTILS.prepareConfiguration(KerberosUtilities.HOST_NAME, SYSTEM_PROPERTY_SETTER);
     }
 
     private String createKrb5Conf(final int port) throws IOException
diff --git a/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/SpnegoAuthenticatorTest.java b/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/SpnegoAuthenticatorTest.java
index d3f8342..bbd65a4 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/SpnegoAuthenticatorTest.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/SpnegoAuthenticatorTest.java
@@ -19,52 +19,45 @@
 
 package org.apache.qpid.server.security.auth.manager;
 
-import static org.apache.commons.codec.CharEncoding.UTF_8;
-import static org.hamcrest.Matchers.not;
+import static org.apache.qpid.server.test.KerberosUtilities.ACCEPT_SCOPE;
+import static org.apache.qpid.server.test.KerberosUtilities.HOST_NAME;
+import static org.apache.qpid.server.test.KerberosUtilities.REALM;
+import static org.apache.qpid.server.test.KerberosUtilities.SERVICE_PRINCIPAL_NAME;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeThat;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-import java.net.URL;
-import java.net.URLDecoder;
+import java.io.File;
 import java.security.Principal;
 import java.util.Base64;
 import java.util.Map;
 
-import org.ietf.jgss.GSSException;
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.ClassRule;
 import org.junit.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import org.apache.qpid.server.security.TokenCarryingPrincipal;
 import org.apache.qpid.server.security.auth.AuthenticationResult;
 import org.apache.qpid.server.test.EmbeddedKdcResource;
 import org.apache.qpid.server.test.KerberosUtilities;
-import org.apache.qpid.test.utils.JvmVendor;
 import org.apache.qpid.test.utils.SystemPropertySetter;
 import org.apache.qpid.test.utils.UnitTestBase;
 
 public class SpnegoAuthenticatorTest extends UnitTestBase
 {
-    private static final Logger LOGGER = LoggerFactory.getLogger(SpnegoAuthenticatorTest.class);
-    private static final String CLIENT_NAME = "client";
-    private static final String SERVER_NAME = "AMQP/localhost";
-    private static final String ANOTHER_SERVICE = "foo/localhost";
-    private static final String REALM = "QPID.ORG";
-    private static final String LOGIN_CONFIG = "login.config";
-    private static final KerberosUtilities UTILS = new KerberosUtilities();;
+    private static final String ANOTHER_SERVICE = "foo/" + HOST_NAME;
+    private static final String ANOTHER_SERVICE_FULL_NAME = ANOTHER_SERVICE + "@" + REALM;
+    private static final KerberosUtilities UTILS = new KerberosUtilities();
 
     @ClassRule
-    public static final EmbeddedKdcResource KDC = new EmbeddedKdcResource(REALM);
+    public static final EmbeddedKdcResource KDC = new EmbeddedKdcResource(HOST_NAME, 0, "QpidTestKerberosServer", REALM);
 
     @ClassRule
     public static final SystemPropertySetter SYSTEM_PROPERTY_SETTER = new SystemPropertySetter();
+    private static File _clientKeyTab;
 
     private SpnegoAuthenticator _spnegoAuthenticator;
     private KerberosAuthenticationManager _kerberosAuthenticationManager;
@@ -72,31 +65,25 @@ public class SpnegoAuthenticatorTest extends UnitTestBase
     @BeforeClass
     public static void createKeyTabs() throws Exception
     {
-        assumeThat(getJvmVendor(), not(JvmVendor.IBM));
-        KDC.createPrincipal("broker.keytab", SERVER_NAME + "@" + REALM);
-        KDC.createPrincipal("client.keytab", CLIENT_NAME + "@" + REALM);
-        KDC.createPrincipal("another.keytab", ANOTHER_SERVICE + "@" + REALM);
-        final URL resource = KerberosAuthenticationManagerTest.class.getClassLoader().getResource(LOGIN_CONFIG);
-        LOGGER.debug("JAAS config:" + resource);
-        assertNotNull(resource);
-        SYSTEM_PROPERTY_SETTER.setSystemProperty("java.security.auth.login.config", URLDecoder.decode(resource.getPath(), UTF_8));
-        SYSTEM_PROPERTY_SETTER.setSystemProperty("javax.security.auth.useSubjectCredsOnly", "false");
+        KDC.createPrincipal("another.keytab", ANOTHER_SERVICE_FULL_NAME);
+        UTILS.prepareConfiguration(HOST_NAME, SYSTEM_PROPERTY_SETTER);
+        _clientKeyTab = UTILS.prepareKeyTabs(KDC);
     }
 
     @Before
     public void setUp()
     {
         _kerberosAuthenticationManager = mock(KerberosAuthenticationManager.class);
-        when(_kerberosAuthenticationManager.getSpnegoLoginConfigScope()).thenReturn("com.sun.security.jgss.accept");
+        when(_kerberosAuthenticationManager.getSpnegoLoginConfigScope()).thenReturn(ACCEPT_SCOPE);
         when(_kerberosAuthenticationManager.isStripRealmFromPrincipalName()).thenReturn(true);
 
         _spnegoAuthenticator = new SpnegoAuthenticator(_kerberosAuthenticationManager);
     }
 
     @Test
-    public void testAuthenticate() throws GSSException
+    public void testAuthenticate() throws Exception
     {
-        final String token = Base64.getEncoder().encodeToString(buildToken(SERVER_NAME));
+        final String token = Base64.getEncoder().encodeToString(buildToken(SERVICE_PRINCIPAL_NAME));
         final String authenticationHeader = SpnegoAuthenticator.NEGOTIATE_PREFIX + token;
 
         final AuthenticationResult result = _spnegoAuthenticator.authenticate(authenticationHeader);
@@ -105,7 +92,7 @@ public class SpnegoAuthenticatorTest extends UnitTestBase
         assertEquals(AuthenticationResult.AuthenticationStatus.SUCCESS, result.getStatus());
         final Principal principal = result.getMainPrincipal();
         assertTrue(principal instanceof TokenCarryingPrincipal);
-        assertEquals(CLIENT_NAME, principal.getName());
+        assertEquals(KerberosUtilities.CLIENT_PRINCIPAL_NAME, principal.getName());
 
         final Map<String, String> tokens = ((TokenCarryingPrincipal)principal).getTokens();
         assertNotNull(tokens);
@@ -121,9 +108,9 @@ public class SpnegoAuthenticatorTest extends UnitTestBase
     }
 
     @Test
-    public void testAuthenticateNoNegotiatePrefix() throws GSSException
+    public void testAuthenticateNoNegotiatePrefix() throws Exception
     {
-        final String token = Base64.getEncoder().encodeToString(buildToken(SERVER_NAME));
+        final String token = Base64.getEncoder().encodeToString(buildToken(SERVICE_PRINCIPAL_NAME));
         final AuthenticationResult result = _spnegoAuthenticator.authenticate(token);
         assertNotNull(result);
         assertEquals(AuthenticationResult.AuthenticationStatus.ERROR, result.getStatus());
@@ -148,10 +135,10 @@ public class SpnegoAuthenticatorTest extends UnitTestBase
     }
 
     @Test
-    public void testAuthenticateWrongConfigName() throws GSSException
+    public void testAuthenticateWrongConfigName() throws Exception
     {
         when(_kerberosAuthenticationManager.getSpnegoLoginConfigScope()).thenReturn("foo");
-        final String token = Base64.getEncoder().encodeToString(buildToken(SERVER_NAME));
+        final String token = Base64.getEncoder().encodeToString(buildToken(SERVICE_PRINCIPAL_NAME));
         final String authenticationHeader = SpnegoAuthenticator.NEGOTIATE_PREFIX + token;
 
         final AuthenticationResult result = _spnegoAuthenticator.authenticate(authenticationHeader);
@@ -160,7 +147,7 @@ public class SpnegoAuthenticatorTest extends UnitTestBase
     }
 
     @Test
-    public void testAuthenticateWrongServer() throws GSSException
+    public void testAuthenticateWrongServer() throws Exception
     {
         final String token = Base64.getEncoder().encodeToString(buildToken(ANOTHER_SERVICE));
         final String authenticationHeader = SpnegoAuthenticator.NEGOTIATE_PREFIX + token;
@@ -170,8 +157,8 @@ public class SpnegoAuthenticatorTest extends UnitTestBase
         assertEquals(AuthenticationResult.AuthenticationStatus.ERROR, result.getStatus());
     }
 
-    private byte[] buildToken(final String anotherService) throws GSSException
+    private byte[] buildToken(final String anotherService) throws Exception
     {
-        return UTILS.buildToken(CLIENT_NAME, anotherService);
+        return UTILS.buildToken(KerberosUtilities.CLIENT_PRINCIPAL_NAME, _clientKeyTab, anotherService);
     }
 }
diff --git a/broker-core/src/test/java/org/apache/qpid/server/test/EmbeddedKdcResource.java b/broker-core/src/test/java/org/apache/qpid/server/test/EmbeddedKdcResource.java
index cda31a8..8224189 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/test/EmbeddedKdcResource.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/test/EmbeddedKdcResource.java
@@ -21,11 +21,11 @@ package org.apache.qpid.server.test;
 
 import java.io.File;
 import java.io.IOException;
-import java.net.InetAddress;
 import java.nio.file.FileSystems;
 import java.nio.file.FileVisitResult;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.nio.file.SimpleFileVisitor;
 import java.nio.file.attribute.BasicFileAttributes;
 import java.util.ArrayList;
@@ -46,11 +46,6 @@ public class EmbeddedKdcResource extends ExternalResource
     private final List<File> _createdFiles = new ArrayList<>();
     private volatile File _kdcDirectory;
 
-    public EmbeddedKdcResource(final String realm)
-    {
-        this(InetAddress.getLoopbackAddress().getCanonicalHostName(), 0, "QpidTestKerberosServer", realm);
-    }
-
     public EmbeddedKdcResource(final String host, final int port, final String serviceName, final String realm)
     {
         _realm = realm;
@@ -80,6 +75,7 @@ public class EmbeddedKdcResource extends ExternalResource
         _simpleKdcServer.setWorkDir(_kdcDirectory);
         _simpleKdcServer.init();
         _simpleKdcServer.start();
+        LOGGER.info("SimpleKdcServer started on port {}, realm '{}'", getPort(), getRealm());
     }
 
     @Override
@@ -149,7 +145,8 @@ public class EmbeddedKdcResource extends ExternalResource
     public File createPrincipal(String keyTabFileName, String... principals)
             throws Exception
     {
-        final File ketTabFile = createFile(keyTabFileName);
+        final Path ketTabPath = Paths.get("target", keyTabFileName);
+        final File ketTabFile = ketTabPath.toFile();
         _createdFiles.add(ketTabFile);
         createPrincipal(ketTabFile, principals);
         return ketTabFile;
@@ -175,22 +172,4 @@ public class EmbeddedKdcResource extends ExternalResource
         }
     }
 
-    private static File createFile(final String keyTabFile) throws IOException
-    {
-        final File target = FileSystems.getDefault().getPath("target").toFile();
-        final File file = new File(target, keyTabFile);
-        if (file.exists())
-        {
-            if (!file.delete())
-            {
-                throw new IOException(String.format("Cannot delete existing file '%s'", keyTabFile));
-            }
-        }
-        if (!file.createNewFile())
-        {
-            throw new IOException(String.format("Cannot create file '%s'", keyTabFile));
-        }
-        return file;
-    }
-
 }
diff --git a/broker-core/src/test/java/org/apache/qpid/server/test/KerberosUtilities.java b/broker-core/src/test/java/org/apache/qpid/server/test/KerberosUtilities.java
index 182df06..88fe2db 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/test/KerberosUtilities.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/test/KerberosUtilities.java
@@ -20,8 +20,20 @@
 package org.apache.qpid.server.test;
 
 import static java.lang.Boolean.TRUE;
+import static java.nio.charset.StandardCharsets.UTF_8;
 
 import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetAddress;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.security.PrivilegedExceptionAction;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
@@ -38,6 +50,7 @@ import javax.security.auth.login.Configuration;
 import javax.security.auth.login.LoginContext;
 import javax.security.auth.login.LoginException;
 
+import com.google.common.io.ByteStreams;
 import org.ietf.jgss.GSSContext;
 import org.ietf.jgss.GSSCredential;
 import org.ietf.jgss.GSSException;
@@ -47,22 +60,112 @@ import org.ietf.jgss.Oid;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import org.apache.qpid.test.utils.JvmVendor;
+import org.apache.qpid.test.utils.SystemPropertySetter;
+
 public class KerberosUtilities
 {
+    public static final String REALM = "QPID.ORG";
+    public static final String HOST_NAME = InetAddress.getLoopbackAddress().getCanonicalHostName();
+    public static final String CLIENT_PRINCIPAL_NAME = "client";
+    public static final String CLIENT_PRINCIPAL_FULL_NAME = CLIENT_PRINCIPAL_NAME + "@" + REALM;
+    public static final String SERVER_PROTOCOL = "AMQP";
+    public static final String SERVICE_PRINCIPAL_NAME = SERVER_PROTOCOL + "/" + HOST_NAME;
+    public static final String ACCEPT_SCOPE = isIBM() ? "com.ibm.security.jgss.krb5.accept" : "com.sun.security.jgss.accept";
+    private static final String USE_SUBJECT_CREDS_ONLY = "javax.security.auth.useSubjectCredsOnly";
+    public static final String LOGIN_CONFIG = "java.security.auth.login.config";
+
+    private static final String INITIATE_SCOPE = isIBM() ? "com.ibm.security.jgss.krb5.initiate" : "com.sun.security.jgss.initiate";
     private static final Logger LOGGER = LoggerFactory.getLogger(KerberosUtilities.class);
     private static final String IBM_LOGIN_MODULE_CLASS = "com.ibm.security.auth.module.Krb5LoginModule";
     private static final String SUN_LOGIN_MODULE_CLASS = "com.sun.security.auth.module.Krb5LoginModule";
-    public static final String KERBEROS_LOGIN_MODULE_CLASS =
-            System.getProperty("java.vendor").contains("IBM") ? IBM_LOGIN_MODULE_CLASS : SUN_LOGIN_MODULE_CLASS;
+    private static final String KERBEROS_LOGIN_MODULE_CLASS = isIBM() ? IBM_LOGIN_MODULE_CLASS : SUN_LOGIN_MODULE_CLASS;
+    private static final String LOGIN_CONFIG_RESOURCE = "login.config";
+    private static final String LOGIN_IBM_CONFIG_RESOURCE = "login.ibm.config";
+    private static final String SERVICE_PRINCIPAL_FULL_NAME = SERVICE_PRINCIPAL_NAME + "@" + REALM;
+    private static final String BROKER_KEYTAB = "broker.keytab";
+    private static final String CLIENT_KEYTAB = "client.keytab";
+
+
+    public File prepareKeyTabs(final EmbeddedKdcResource kdc) throws Exception
+    {
+        final File clientKeyTabFile;
+        kdc.createPrincipal(BROKER_KEYTAB, SERVICE_PRINCIPAL_FULL_NAME);
+        clientKeyTabFile = kdc.createPrincipal(CLIENT_KEYTAB, CLIENT_PRINCIPAL_FULL_NAME);
+        return clientKeyTabFile;
+    }
+
+    public void prepareConfiguration(final String hostName, final SystemPropertySetter systemPropertySetter)
+            throws IOException
+    {
+        final Path loginConfig = transformLoginConfig(hostName);
+        systemPropertySetter.setSystemProperty(LOGIN_CONFIG,
+                                               URLDecoder.decode(loginConfig.toFile().getAbsolutePath(), UTF_8.name()));
+        systemPropertySetter.setSystemProperty(USE_SUBJECT_CREDS_ONLY, "false");
+    }
+
+    public byte[] buildToken(String clientPrincipalName, File clientKeyTabFile, String targetServerPrincipalName)
+            throws Exception
+    {
+        final LoginContext lc = createKerberosKeyTabLoginContext("test",
+                                                                 clientPrincipalName,
+                                                                 clientKeyTabFile);
+
+        Subject clientSubject = null;
+        String useSubjectCredsOnly = System.getProperty(USE_SUBJECT_CREDS_ONLY);
+        try
+        {
+            debug("Before login");
+            lc.login();
+            clientSubject = lc.getSubject();
+            debug("LoginContext subject {}", clientSubject);
+            System.setProperty(USE_SUBJECT_CREDS_ONLY, "true");
+            return Subject.doAs(clientSubject,
+                                (PrivilegedExceptionAction<byte[]>) () -> buildTokenWithinSubjectWithKerberosTicket(
+                                        clientPrincipalName,
+                                        targetServerPrincipalName));
+        }
+        finally
+        {
+            if (useSubjectCredsOnly == null)
+            {
+                System.clearProperty(USE_SUBJECT_CREDS_ONLY);
+            }
+            else
+            {
+                System.setProperty(USE_SUBJECT_CREDS_ONLY, useSubjectCredsOnly);
+            }
+            if (clientSubject != null)
+            {
+                lc.logout();
+            }
+        }
+    }
 
-    public byte[] buildToken(String clientPrincipalName, String targetServerPrincipalName) throws GSSException
+    private byte[] buildTokenWithinSubjectWithKerberosTicket(String clientPrincipalName,
+                                                             String targetServerPrincipalName) throws GSSException
     {
+        debug("Building token for client principal '{}' and server principal '{}'",
+              clientPrincipalName,
+              targetServerPrincipalName);
+
         final GSSManager manager = GSSManager.getInstance();
         final GSSName clientName = manager.createName(clientPrincipalName, GSSName.NT_USER_NAME);
-        final GSSCredential credential = manager.createCredential(clientName,
-                                                                  GSSCredential.DEFAULT_LIFETIME,
-                                                                  new Oid("1.2.840.113554.1.2.2"),
-                                                                  GSSCredential.INITIATE_ONLY);
+        final GSSCredential credential;
+        try
+        {
+            credential = manager.createCredential(clientName,
+                                                  GSSCredential.DEFAULT_LIFETIME,
+                                                  new Oid("1.2.840.113554.1.2.2"),
+                                                  GSSCredential.INITIATE_ONLY);
+        }
+        catch (GSSException e)
+        {
+            debug("Failure to create credential for {}", clientName, e);
+            throw e;
+        }
+
+        debug("Client credential '{}'", credential);
 
         final GSSName serverName = manager.createName(targetServerPrincipalName, GSSName.NT_USER_NAME);
         final Oid spnegoMechOid = new Oid("1.3.6.1.5.5.2");
@@ -70,11 +173,20 @@ public class KerberosUtilities
                                                                spnegoMechOid,
                                                                credential,
                                                                GSSContext.DEFAULT_LIFETIME);
+
+        debug("Requesting ticket using initiator's credentials");
+
         try
         {
             clientContext.requestCredDeleg(true);
+            debug("Requesting ticket");
             return clientContext.initSecContext(new byte[]{}, 0, 0);
         }
+        catch (GSSException e)
+        {
+            debug("Failure to request token", e);
+            throw e;
+        }
         finally
         {
             clientContext.dispose();
@@ -166,10 +278,19 @@ public class KerberosUtilities
         {
             final Map<String, String> options = new HashMap<>();
             options.put("principal", principalName);
-            options.put("useKeyTab", TRUE.toString());
-            options.put("keyTab", keyTabFile.getAbsolutePath());
-            options.put("refreshKrb5Config", TRUE.toString());
-            options.put("doNotPrompt", TRUE.toString());
+
+            if (isIBM())
+            {
+                options.put("useKeytab", keyTabFile.getAbsolutePath());
+                options.put("credsType", "both");
+            }
+            else
+            {
+                options.put("keyTab", keyTabFile.getAbsolutePath());
+                options.put("useKeyTab", TRUE.toString());
+                options.put("doNotPrompt", TRUE.toString());
+                options.put("refreshKrb5Config", TRUE.toString());
+            }
             _entry = new AppConfigurationEntry(KERBEROS_LOGIN_MODULE_CLASS,
                                                AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
                                                options);
@@ -186,4 +307,57 @@ public class KerberosUtilities
             return new AppConfigurationEntry[0];
         }
     }
+
+    public void debug(String message, Object... args)
+    {
+        LOGGER.debug(message, args);
+        if (Boolean.TRUE.toString().equalsIgnoreCase(System.getProperty("sun.security.krb5.debug")))
+        {
+            System.out.println(String.format(message.replace("{}", "%s"), args));
+        }
+    }
+
+    private Path transformLoginConfig(String hostName) throws IOException
+    {
+        final String resourceName = isIBM() ? LOGIN_IBM_CONFIG_RESOURCE : LOGIN_CONFIG_RESOURCE;
+        final URL resource = KerberosUtilities.class.getClassLoader().getResource(resourceName);
+        if (resource == null)
+        {
+            throw new IllegalArgumentException(String.format("Unknown resource '%s'", resourceName));
+        }
+        final String config;
+        try (InputStream is = resource.openStream())
+        {
+            config = new String(ByteStreams.toByteArray(is), UTF_8);
+        }
+        catch (IOException e)
+        {
+            throw new IOException(String.format("Failed to load resource '%s'", resource.toExternalForm()), e);
+        }
+        final String newConfig = config.replace("AMQP/localhost", "AMQP/" + hostName)
+                                       .replace("target/" + BROKER_KEYTAB, toAbsolutePath(BROKER_KEYTAB))
+                                       .replace("target/" + CLIENT_KEYTAB, toAbsolutePath(CLIENT_KEYTAB));
+
+        final Path file = Paths.get("target", LOGIN_CONFIG_RESOURCE);
+        Files.write(file,
+                    newConfig.getBytes(UTF_8),
+                    StandardOpenOption.WRITE,
+                    StandardOpenOption.CREATE,
+                    StandardOpenOption.TRUNCATE_EXISTING);
+        return file.toRealPath(LinkOption.NOFOLLOW_LINKS);
+    }
+
+    private String toAbsolutePath(String fileName)
+    {
+        final Path path = Paths.get("target", fileName)
+                               .toAbsolutePath()
+                               .normalize();
+        return path.toUri().getPath();
+    }
+
+    private static boolean isIBM()
+    {
+        return JvmVendor.getJvmVendor() == JvmVendor.IBM;
+    }
+
 }
diff --git a/broker-core/src/test/resources/login.ibm.config b/broker-core/src/test/resources/login.ibm.config
new file mode 100644
index 0000000..6e85f6e
--- /dev/null
+++ b/broker-core/src/test/resources/login.ibm.config
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+ldap-gssapi-bind {
+    com.ibm.security.auth.module.Krb5LoginModule required
+    credsType="both"
+    principal="service/localhost@QPID.ORG"
+    useKeytab="target/kerberos.keytab";
+};
+
+ldap-gssapi-bind-broken {
+    com.ibm.security.auth.module.Krb5LoginModule required
+    credsType="both"
+    principal="service/localhost@QPID.ORG"
+    useKeytab="target/kerberos-non-existing.keytab";
+};
+
+qpid-broker-j {
+    com.ibm.security.auth.module.Krb5LoginModule required
+    credsType="both"
+    principal="service/localhost@QPID.ORG"
+    useKeytab="target/kerberos.keytab";
+};
+
+com.ibm.security.jgss.krb5.accept {
+    com.ibm.security.auth.module.Krb5LoginModule required
+    credsType="acceptor"
+    principal="AMQP/localhost@QPID.ORG"
+    useKeytab="target/broker.keytab";
+};
+
+com.ibm.security.jgss.krb5.initiate {
+    com.ibm.security.auth.module.Krb5LoginModule required
+    credsType="both"
+    principal="client@QPID.ORG"
+    useKeytab="target/client.keytab";
+};
diff --git a/qpid-test-utils/src/main/java/org/apache/qpid/test/utils/JvmVendor.java b/qpid-test-utils/src/main/java/org/apache/qpid/test/utils/JvmVendor.java
index bd176d7..9ed7c28 100644
--- a/qpid-test-utils/src/main/java/org/apache/qpid/test/utils/JvmVendor.java
+++ b/qpid-test-utils/src/main/java/org/apache/qpid/test/utils/JvmVendor.java
@@ -20,10 +20,33 @@
 
 package org.apache.qpid.test.utils;
 
+import com.google.common.base.StandardSystemProperty;
+
 public enum JvmVendor
 {
     ORACLE,
     IBM,
     OPENJDK,
-    UNKNOWN
+    UNKNOWN;
+
+    public static JvmVendor getJvmVendor()
+    {
+        final String property = String.valueOf(System.getProperty(StandardSystemProperty.JAVA_VENDOR.key())).toUpperCase();
+        if (property.contains("IBM"))
+        {
+            return JvmVendor.IBM;
+        }
+        else if (property.contains("ORACLE"))
+        {
+            return JvmVendor.ORACLE;
+        }
+        else if (property.contains("OPENJDK"))
+        {
+            return JvmVendor.OPENJDK;
+        }
+        else
+        {
+            return JvmVendor.UNKNOWN;
+        }
+    }
 }
diff --git a/qpid-test-utils/src/main/java/org/apache/qpid/test/utils/UnitTestBase.java b/qpid-test-utils/src/main/java/org/apache/qpid/test/utils/UnitTestBase.java
index 4dcfab0..4d71700 100644
--- a/qpid-test-utils/src/main/java/org/apache/qpid/test/utils/UnitTestBase.java
+++ b/qpid-test-utils/src/main/java/org/apache/qpid/test/utils/UnitTestBase.java
@@ -77,23 +77,7 @@ public class UnitTestBase
 
     public static JvmVendor getJvmVendor()
     {
-        final String property = String.valueOf(System.getProperty(StandardSystemProperty.JAVA_VENDOR.key())).toUpperCase();
-        if (property.contains("IBM"))
-        {
-            return JvmVendor.IBM;
-        }
-        else if (property.contains("ORACLE"))
-        {
-            return JvmVendor.ORACLE;
-        }
-        else if (property.contains("OPENJDK"))
-        {
-            return JvmVendor.OPENJDK;
-        }
-        else
-        {
-            return JvmVendor.UNKNOWN;
-        }
+        return JvmVendor.getJvmVendor();
     }
 
     public VirtualHostNodeStoreType getVirtualHostNodeStoreType()


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[qpid-broker-j] 07/10: QPID-8455: [Broker-J] Add allow/deny list alternatives for existing black/whilte list attributes and context variables

Posted by or...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

orudyy pushed a commit to branch 7.1.x
in repository https://gitbox.apache.org/repos/asf/qpid-broker-j.git

commit ec885c06e367739e5741d15d12ea6124c30e199d
Author: Alex Rudyy <or...@apache.org>
AuthorDate: Wed Sep 2 17:11:55 2020 +0100

    QPID-8455: [Broker-J] Add allow/deny list alternatives for existing black/whilte list attributes and context variables
---
 .../server/configuration/CommonProperties.java     |  5 ++
 .../server/model/AbstractConfiguredObject.java     | 15 ++++
 .../java/org/apache/qpid/server/model/Port.java    | 17 ++++
 .../qpid/server/model/port/AbstractPort.java       | 32 +++++++-
 .../manager/SimpleLDAPAuthenticationManager.java   | 16 ++++
 .../SimpleLDAPAuthenticationManagerImpl.java       | 32 +++++++-
 .../oauth2/OAuth2AuthenticationProvider.java       | 18 +++++
 .../oauth2/OAuth2AuthenticationProviderImpl.java   | 32 +++++++-
 ...oudFoundryDashboardManagementGroupProvider.java | 14 ++++
 ...oundryDashboardManagementGroupProviderImpl.java | 37 ++++++++-
 .../apache/qpid/server/util/ConnectionBuilder.java | 24 ++++++
 .../qpid/server/model/port/AmqpPortImplTest.java   | 87 +++++++++++++++++++++
 .../SimpleLDAPAuthenticationManagerTest.java       | 69 ++++++++++++++++
 .../OAuth2AuthenticationProviderImplTest.java      | 91 +++++++++++++++++++---
 .../qpid/systests/admin/SpawnBrokerAdmin.java      | 26 ++++---
 .../qpid/systests/admin/SpawnBrokerAdminTest.java  | 16 +++-
 16 files changed, 490 insertions(+), 41 deletions(-)

diff --git a/broker-core/src/main/java/org/apache/qpid/server/configuration/CommonProperties.java b/broker-core/src/main/java/org/apache/qpid/server/configuration/CommonProperties.java
index 600f985..171d897 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/configuration/CommonProperties.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/configuration/CommonProperties.java
@@ -64,6 +64,11 @@ public class CommonProperties
     public static final String QPID_SECURITY_TLS_CIPHER_SUITE_BLACK_LIST = "qpid.security.tls.cipherSuiteBlackList";
     public static final String QPID_SECURITY_TLS_CIPHER_SUITE_BLACK_LIST_DEFAULT = "";
 
+    public static final String QPID_SECURITY_TLS_PROTOCOL_ALLOW_LIST = "qpid.security.tls.protocolAllowList";
+    public static final String QPID_SECURITY_TLS_PROTOCOL_DENY_LIST = "qpid.security.tls.protocolDenyList";
+    public static final String QPID_SECURITY_TLS_CIPHER_SUITE_ALLOW_LIST = "qpid.security.tls.cipherSuiteAllowList";
+    public static final String QPID_SECURITY_TLS_CIPHER_SUITE_DENY_LIST = "qpid.security.tls.cipherSuiteDenyList";
+
     private static final String MANIFEST_HEADER_IMPLEMENTATION_BUILD = "Implementation-Build";
 
     /** Defines the name of the version suffix property. */
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java b/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java
index 267356c..38d7135 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java
@@ -3498,6 +3498,21 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im
         return converter.convert("${" + propertyName + "}", this);
     }
 
+    protected <T> T getContextValue(final Class<T> clazz, final Type type, final String propertyName, final String fallbackName)
+    {
+        final Set<String> keys = getContextKeys(false);
+        String name;
+        if (keys.contains(propertyName))
+        {
+            name = propertyName;
+        }
+        else
+        {
+            name = fallbackName;
+        }
+        return getContextValue(clazz, type, name);
+    }
+
     @Override
     public Set<String> getContextKeys(final boolean excludeSystem)
     {
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/Port.java b/broker-core/src/main/java/org/apache/qpid/server/model/Port.java
index 510d4d5..a5aac32 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/Port.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/Port.java
@@ -90,18 +90,35 @@ public interface Port<X extends Port<X>> extends ConfiguredObject<X>
     @ManagedAttribute
     Collection<TrustStore> getTrustStores();
 
+    @Deprecated
     @DerivedAttribute
     List<String> getTlsProtocolWhiteList();
 
+    @Deprecated
     @DerivedAttribute
     List<String> getTlsProtocolBlackList();
 
+    @Deprecated
     @DerivedAttribute
     List<String> getTlsCipherSuiteWhiteList();
 
+    @Deprecated
     @DerivedAttribute
     List<String> getTlsCipherSuiteBlackList();
 
+    @DerivedAttribute
+    List<String> getTlsProtocolAllowList();
+
+    @DerivedAttribute
+    List<String> getTlsProtocolDenyList();
+
+    @DerivedAttribute
+    List<String> getTlsCipherSuiteAllowList();
+
+    @DerivedAttribute
+    List<String> getTlsCipherSuiteDenyList();
+
+
     @ManagedAttribute(defaultValue = "*",
                       description = "The network interface this port binds to expressed as an IP address or a"
                                     + "hostname.  If null or * then bind to all interfaces.")
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/port/AbstractPort.java b/broker-core/src/main/java/org/apache/qpid/server/model/port/AbstractPort.java
index a5fb3d2..f8d0b05 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/port/AbstractPort.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/port/AbstractPort.java
@@ -109,10 +109,10 @@ public abstract class AbstractPort<X extends AbstractPort<X>> extends AbstractCo
     protected void onOpen()
     {
         super.onOpen();
-        _tlsProtocolWhiteList = getContextValue(List.class, ParameterizedTypes.LIST_OF_STRINGS, CommonProperties.QPID_SECURITY_TLS_PROTOCOL_WHITE_LIST);
-        _tlsProtocolBlackList = getContextValue(List.class, ParameterizedTypes.LIST_OF_STRINGS, CommonProperties.QPID_SECURITY_TLS_PROTOCOL_BLACK_LIST);
-        _tlsCipherSuiteWhiteList = getContextValue(List.class, ParameterizedTypes.LIST_OF_STRINGS, CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_WHITE_LIST);
-        _tlsCipherSuiteBlackList = getContextValue(List.class, ParameterizedTypes.LIST_OF_STRINGS, CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_BLACK_LIST);
+        _tlsProtocolWhiteList = getContextValue(List.class, ParameterizedTypes.LIST_OF_STRINGS, CommonProperties.QPID_SECURITY_TLS_PROTOCOL_ALLOW_LIST, CommonProperties.QPID_SECURITY_TLS_PROTOCOL_WHITE_LIST);
+        _tlsProtocolBlackList = getContextValue(List.class, ParameterizedTypes.LIST_OF_STRINGS, CommonProperties.QPID_SECURITY_TLS_PROTOCOL_DENY_LIST, CommonProperties.QPID_SECURITY_TLS_PROTOCOL_BLACK_LIST);
+        _tlsCipherSuiteWhiteList = getContextValue(List.class, ParameterizedTypes.LIST_OF_STRINGS, CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_ALLOW_LIST, CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_WHITE_LIST);
+        _tlsCipherSuiteBlackList = getContextValue(List.class, ParameterizedTypes.LIST_OF_STRINGS, CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_DENY_LIST, CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_BLACK_LIST);
     }
 
     @Override
@@ -447,6 +447,30 @@ public abstract class AbstractPort<X extends AbstractPort<X>> extends AbstractCo
     }
 
     @Override
+    public List<String> getTlsProtocolAllowList()
+    {
+        return getTlsProtocolWhiteList();
+    }
+
+    @Override
+    public List<String> getTlsProtocolDenyList()
+    {
+        return getTlsProtocolBlackList();
+    }
+
+    @Override
+    public List<String> getTlsCipherSuiteAllowList()
+    {
+        return getTlsCipherSuiteWhiteList();
+    }
+
+    @Override
+    public List<String> getTlsCipherSuiteDenyList()
+    {
+        return getTlsCipherSuiteBlackList();
+    }
+
+    @Override
     public KeyStore getKeyStore()
     {
         return _keyStore;
diff --git a/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManager.java b/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManager.java
index fe650f7..8c0e0f7 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManager.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManager.java
@@ -104,16 +104,32 @@ public interface SimpleLDAPAuthenticationManager<X extends SimpleLDAPAuthenticat
             defaultValue = LOGIN_CONFIG_SCOPE_DEFAULT)
     String getLoginConfigScope();
 
+    @Deprecated
     @DerivedAttribute
     List<String> getTlsProtocolWhiteList();
 
+    @Deprecated
     @DerivedAttribute
     List<String> getTlsProtocolBlackList();
 
+    @Deprecated
     @DerivedAttribute
     List<String> getTlsCipherSuiteWhiteList();
 
+    @Deprecated
     @DerivedAttribute
     List<String> getTlsCipherSuiteBlackList();
 
+    @DerivedAttribute
+    List<String> getTlsProtocolAllowList();
+
+    @DerivedAttribute
+    List<String> getTlsProtocolDenyList();
+
+    @DerivedAttribute
+    List<String> getTlsCipherSuiteAllowList();
+
+    @DerivedAttribute
+    List<String> getTlsCipherSuiteDenyList();
+
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManagerImpl.java b/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManagerImpl.java
index 7a18c6c..704b649 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManagerImpl.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManagerImpl.java
@@ -189,10 +189,10 @@ public class SimpleLDAPAuthenticationManagerImpl
     {
         super.onOpen();
 
-        _tlsProtocolWhiteList = getContextValue(List.class, ParameterizedTypes.LIST_OF_STRINGS, CommonProperties.QPID_SECURITY_TLS_PROTOCOL_WHITE_LIST);
-        _tlsProtocolBlackList = getContextValue(List.class, ParameterizedTypes.LIST_OF_STRINGS, CommonProperties.QPID_SECURITY_TLS_PROTOCOL_BLACK_LIST);
-        _tlsCipherSuiteWhiteList = getContextValue(List.class, ParameterizedTypes.LIST_OF_STRINGS, CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_WHITE_LIST);
-        _tlsCipherSuiteBlackList = getContextValue(List.class, ParameterizedTypes.LIST_OF_STRINGS, CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_BLACK_LIST);
+        _tlsProtocolWhiteList = getContextValue(List.class, ParameterizedTypes.LIST_OF_STRINGS, CommonProperties.QPID_SECURITY_TLS_PROTOCOL_ALLOW_LIST, CommonProperties.QPID_SECURITY_TLS_PROTOCOL_WHITE_LIST);
+        _tlsProtocolBlackList = getContextValue(List.class, ParameterizedTypes.LIST_OF_STRINGS, CommonProperties.QPID_SECURITY_TLS_PROTOCOL_DENY_LIST, CommonProperties.QPID_SECURITY_TLS_PROTOCOL_BLACK_LIST);
+        _tlsCipherSuiteWhiteList = getContextValue(List.class, ParameterizedTypes.LIST_OF_STRINGS, CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_ALLOW_LIST, CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_WHITE_LIST);
+        _tlsCipherSuiteBlackList = getContextValue(List.class, ParameterizedTypes.LIST_OF_STRINGS, CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_DENY_LIST, CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_BLACK_LIST);
 
         Integer cacheMaxSize = getContextValue(Integer.class, AUTHENTICATION_CACHE_MAX_SIZE);
         Long cacheExpirationTime = getContextValue(Long.class, AUTHENTICATION_CACHE_EXPIRATION_TIME);
@@ -793,6 +793,30 @@ public class SimpleLDAPAuthenticationManagerImpl
         return _tlsCipherSuiteBlackList;
     }
 
+    @Override
+    public List<String> getTlsProtocolAllowList()
+    {
+        return getTlsProtocolWhiteList();
+    }
+
+    @Override
+    public List<String> getTlsProtocolDenyList()
+    {
+        return getTlsProtocolBlackList();
+    }
+
+    @Override
+    public List<String> getTlsCipherSuiteAllowList()
+    {
+        return getTlsCipherSuiteWhiteList();
+    }
+
+    @Override
+    public List<String> getTlsCipherSuiteDenyList()
+    {
+        return getTlsCipherSuiteBlackList();
+    }
+
     private void closeSafely(InitialDirContext ctx)
     {
         try
diff --git a/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/oauth2/OAuth2AuthenticationProvider.java b/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/oauth2/OAuth2AuthenticationProvider.java
index 9cbbcdf..1a9c95d 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/oauth2/OAuth2AuthenticationProvider.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/oauth2/OAuth2AuthenticationProvider.java
@@ -102,18 +102,36 @@ public interface OAuth2AuthenticationProvider<T extends OAuth2AuthenticationProv
     @DerivedAttribute( description = "Default OAuth access token scope passed to the authorization endpoint")
     String getDefaultScope();
 
+    @Deprecated
     @DerivedAttribute
     List<String> getTlsProtocolWhiteList();
 
+    @Deprecated
     @DerivedAttribute
     List<String> getTlsProtocolBlackList();
 
+    @Deprecated
     @DerivedAttribute
     List<String> getTlsCipherSuiteWhiteList();
 
+    @Deprecated
     @DerivedAttribute
     List<String> getTlsCipherSuiteBlackList();
 
+    @DerivedAttribute
+    List<String> getTlsProtocolAllowList();
+
+    @DerivedAttribute
+    List<String> getTlsProtocolDenyList();
+
+    @DerivedAttribute
+    List<String> getTlsCipherSuiteAllowList();
+
+    @DerivedAttribute
+    List<String> getTlsCipherSuiteDenyList();
+
+
+
     int getConnectTimeout();
 
     int getReadTimeout();
diff --git a/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/oauth2/OAuth2AuthenticationProviderImpl.java b/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/oauth2/OAuth2AuthenticationProviderImpl.java
index 6854bd5..583263c 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/oauth2/OAuth2AuthenticationProviderImpl.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/oauth2/OAuth2AuthenticationProviderImpl.java
@@ -130,10 +130,10 @@ public class OAuth2AuthenticationProviderImpl
         super.onOpen();
         String type = getIdentityResolverType();
         _identityResolverService = new QpidServiceLoader().getInstancesByType(OAuth2IdentityResolverService.class).get(type);
-        _tlsProtocolWhiteList = getContextValue(List.class, ParameterizedTypes.LIST_OF_STRINGS, CommonProperties.QPID_SECURITY_TLS_PROTOCOL_WHITE_LIST);
-        _tlsProtocolBlackList = getContextValue(List.class, ParameterizedTypes.LIST_OF_STRINGS, CommonProperties.QPID_SECURITY_TLS_PROTOCOL_BLACK_LIST);
-        _tlsCipherSuiteWhiteList = getContextValue(List.class, ParameterizedTypes.LIST_OF_STRINGS, CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_WHITE_LIST);
-        _tlsCipherSuiteBlackList = getContextValue(List.class, ParameterizedTypes.LIST_OF_STRINGS, CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_BLACK_LIST);
+        _tlsProtocolWhiteList = getContextValue(List.class, ParameterizedTypes.LIST_OF_STRINGS, CommonProperties.QPID_SECURITY_TLS_PROTOCOL_ALLOW_LIST, CommonProperties.QPID_SECURITY_TLS_PROTOCOL_WHITE_LIST);
+        _tlsProtocolBlackList = getContextValue(List.class, ParameterizedTypes.LIST_OF_STRINGS, CommonProperties.QPID_SECURITY_TLS_PROTOCOL_DENY_LIST, CommonProperties.QPID_SECURITY_TLS_PROTOCOL_BLACK_LIST);
+        _tlsCipherSuiteWhiteList = getContextValue(List.class, ParameterizedTypes.LIST_OF_STRINGS, CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_ALLOW_LIST, CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_WHITE_LIST);
+        _tlsCipherSuiteBlackList = getContextValue(List.class, ParameterizedTypes.LIST_OF_STRINGS, CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_DENY_LIST, CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_BLACK_LIST);
         _connectTimeout = getContextValue(Integer.class, AUTHENTICATION_OAUTH2_CONNECT_TIMEOUT);
         _readTimeout = getContextValue(Integer.class, AUTHENTICATION_OAUTH2_READ_TIMEOUT);
 
@@ -520,6 +520,30 @@ public class OAuth2AuthenticationProviderImpl
     }
 
     @Override
+    public List<String> getTlsProtocolAllowList()
+    {
+        return getTlsProtocolWhiteList();
+    }
+
+    @Override
+    public List<String> getTlsProtocolDenyList()
+    {
+        return getTlsProtocolBlackList();
+    }
+
+    @Override
+    public List<String> getTlsCipherSuiteAllowList()
+    {
+        return getTlsCipherSuiteWhiteList();
+    }
+
+    @Override
+    public List<String> getTlsCipherSuiteDenyList()
+    {
+        return getTlsCipherSuiteBlackList();
+    }
+
+    @Override
     public int getConnectTimeout()
     {
         return _connectTimeout;
diff --git a/broker-core/src/main/java/org/apache/qpid/server/security/group/cloudfoundry/CloudFoundryDashboardManagementGroupProvider.java b/broker-core/src/main/java/org/apache/qpid/server/security/group/cloudfoundry/CloudFoundryDashboardManagementGroupProvider.java
index fd1c5a0..2a7dd73 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/security/group/cloudfoundry/CloudFoundryDashboardManagementGroupProvider.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/security/group/cloudfoundry/CloudFoundryDashboardManagementGroupProvider.java
@@ -51,12 +51,26 @@ public interface CloudFoundryDashboardManagementGroupProvider<X extends CloudFou
     @ManagedAttribute( description = "A service instance id to qpid management group mapping. If the CloudFoundry endpoint grants a user permission to manage a service instance the user will be associated with the corresponding management group.", mandatory = true )
     Map<String, String> getServiceToManagementGroupMapping();
 
+    @Deprecated
     @DerivedAttribute
     List<String> getTlsProtocolWhiteList();
+    @Deprecated
     @DerivedAttribute
     List<String> getTlsProtocolBlackList();
+    @Deprecated
     @DerivedAttribute
     List<String> getTlsCipherSuiteWhiteList();
+    @Deprecated
     @DerivedAttribute
     List<String> getTlsCipherSuiteBlackList();
+
+    @DerivedAttribute
+    List<String> getTlsProtocolAllowList();
+    @DerivedAttribute
+    List<String> getTlsProtocolDenyList();
+    @DerivedAttribute
+    List<String> getTlsCipherSuiteAllowList();
+    @DerivedAttribute
+    List<String> getTlsCipherSuiteDenyList();
+
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/security/group/cloudfoundry/CloudFoundryDashboardManagementGroupProviderImpl.java b/broker-core/src/main/java/org/apache/qpid/server/security/group/cloudfoundry/CloudFoundryDashboardManagementGroupProviderImpl.java
index 88659b5..7818e89 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/security/group/cloudfoundry/CloudFoundryDashboardManagementGroupProviderImpl.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/security/group/cloudfoundry/CloudFoundryDashboardManagementGroupProviderImpl.java
@@ -21,8 +21,12 @@
 package org.apache.qpid.server.security.group.cloudfoundry;
 
 import static org.apache.qpid.server.configuration.CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_BLACK_LIST;
+import static org.apache.qpid.server.configuration.CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_DENY_LIST;
+import static org.apache.qpid.server.configuration.CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_ALLOW_LIST;
 import static org.apache.qpid.server.configuration.CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_WHITE_LIST;
 import static org.apache.qpid.server.configuration.CommonProperties.QPID_SECURITY_TLS_PROTOCOL_BLACK_LIST;
+import static org.apache.qpid.server.configuration.CommonProperties.QPID_SECURITY_TLS_PROTOCOL_DENY_LIST;
+import static org.apache.qpid.server.configuration.CommonProperties.QPID_SECURITY_TLS_PROTOCOL_ALLOW_LIST;
 import static org.apache.qpid.server.configuration.CommonProperties.QPID_SECURITY_TLS_PROTOCOL_WHITE_LIST;
 import static org.apache.qpid.server.util.ParameterizedTypes.LIST_OF_STRINGS;
 
@@ -106,10 +110,10 @@ public class CloudFoundryDashboardManagementGroupProviderImpl extends AbstractCo
     public void onOpen()
     {
         super.onOpen();
-        _tlsProtocolWhiteList = getContextValue(List.class, LIST_OF_STRINGS, QPID_SECURITY_TLS_PROTOCOL_WHITE_LIST);
-        _tlsProtocolBlackList = getContextValue(List.class, LIST_OF_STRINGS, QPID_SECURITY_TLS_PROTOCOL_BLACK_LIST);
-        _tlsCipherSuiteWhiteList = getContextValue(List.class, LIST_OF_STRINGS, QPID_SECURITY_TLS_CIPHER_SUITE_WHITE_LIST);
-        _tlsCipherSuiteBlackList = getContextValue(List.class, LIST_OF_STRINGS, QPID_SECURITY_TLS_CIPHER_SUITE_BLACK_LIST);
+        _tlsProtocolWhiteList = getContextValue(List.class, LIST_OF_STRINGS, QPID_SECURITY_TLS_PROTOCOL_ALLOW_LIST, QPID_SECURITY_TLS_PROTOCOL_WHITE_LIST);
+        _tlsProtocolBlackList = getContextValue(List.class, LIST_OF_STRINGS, QPID_SECURITY_TLS_PROTOCOL_DENY_LIST, QPID_SECURITY_TLS_PROTOCOL_BLACK_LIST);
+        _tlsCipherSuiteWhiteList = getContextValue(List.class, LIST_OF_STRINGS, QPID_SECURITY_TLS_CIPHER_SUITE_ALLOW_LIST, QPID_SECURITY_TLS_CIPHER_SUITE_WHITE_LIST);
+        _tlsCipherSuiteBlackList = getContextValue(List.class, LIST_OF_STRINGS, QPID_SECURITY_TLS_CIPHER_SUITE_DENY_LIST, QPID_SECURITY_TLS_CIPHER_SUITE_BLACK_LIST);
         _connectTimeout = getContextValue(Integer.class, QPID_GROUPPROVIDER_CLOUDFOUNDRY_CONNECT_TIMEOUT);
         _readTimeout = getContextValue(Integer.class, QPID_GROUPPROVIDER_CLOUDFOUNDRY_READ_TIMEOUT);
     }
@@ -313,4 +317,29 @@ public class CloudFoundryDashboardManagementGroupProviderImpl extends AbstractCo
         return _tlsCipherSuiteBlackList;
     }
 
+    @Override
+    public List<String> getTlsProtocolAllowList()
+    {
+        return getTlsProtocolWhiteList();
+    }
+
+    @Override
+    public List<String> getTlsProtocolDenyList()
+    {
+        return getTlsProtocolBlackList();
+    }
+
+    @Override
+    public List<String> getTlsCipherSuiteAllowList()
+    {
+        return getTlsCipherSuiteWhiteList();
+    }
+
+    @Override
+    public List<String> getTlsCipherSuiteDenyList()
+    {
+        return getTlsCipherSuiteBlackList();
+    }
+
+
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/util/ConnectionBuilder.java b/broker-core/src/main/java/org/apache/qpid/server/util/ConnectionBuilder.java
index a418e76..f00d8d6 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/util/ConnectionBuilder.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/util/ConnectionBuilder.java
@@ -77,30 +77,54 @@ public class ConnectionBuilder
         return this;
     }
 
+    @Deprecated
     public ConnectionBuilder setTlsProtocolWhiteList(final List<String> tlsProtocolWhiteList)
     {
         _tlsProtocolWhiteList = tlsProtocolWhiteList;
         return this;
     }
 
+    @Deprecated
     public ConnectionBuilder setTlsProtocolBlackList(final List<String> tlsProtocolBlackList)
     {
         _tlsProtocolBlackList = tlsProtocolBlackList;
         return this;
     }
 
+    @Deprecated
     public ConnectionBuilder setTlsCipherSuiteWhiteList(final List<String> tlsCipherSuiteWhiteList)
     {
         _tlsCipherSuiteWhiteList = tlsCipherSuiteWhiteList;
         return this;
     }
 
+    @Deprecated
     public ConnectionBuilder setTlsCipherSuiteBlackList(final List<String> tlsCipherSuiteBlackList)
     {
         _tlsCipherSuiteBlackList = tlsCipherSuiteBlackList;
         return this;
     }
 
+    public ConnectionBuilder setTlsProtocolAllowList(final List<String> tlsProtocolAllowList)
+    {
+        return setTlsProtocolWhiteList(tlsProtocolAllowList);
+    }
+
+    public ConnectionBuilder setTlsProtocolDenyList(final List<String> tlsProtocolDenyList)
+    {
+        return setTlsProtocolBlackList(tlsProtocolDenyList);
+    }
+
+    public ConnectionBuilder setTlsCipherSuiteAllowList(final List<String> tlsCipherSuiteAllowList)
+    {
+        return setTlsCipherSuiteWhiteList(tlsCipherSuiteAllowList);
+    }
+
+    public ConnectionBuilder setTlsCipherSuiteDenyList(final List<String> tlsCipherSuiteDenyList)
+    {
+        return setTlsCipherSuiteBlackList(tlsCipherSuiteDenyList);
+    }
+
     public HttpURLConnection build() throws IOException
     {
         HttpURLConnection connection = (HttpURLConnection) _url.openConnection();
diff --git a/broker-core/src/test/java/org/apache/qpid/server/model/port/AmqpPortImplTest.java b/broker-core/src/test/java/org/apache/qpid/server/model/port/AmqpPortImplTest.java
index 4775334..21c0b8d 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/model/port/AmqpPortImplTest.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/model/port/AmqpPortImplTest.java
@@ -19,8 +19,11 @@
 
 package org.apache.qpid.server.model.port;
 
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
@@ -37,6 +40,7 @@ import java.security.Principal;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 
@@ -44,6 +48,7 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
+import org.apache.qpid.server.configuration.CommonProperties;
 import org.apache.qpid.server.configuration.IllegalConfigurationException;
 import org.apache.qpid.server.configuration.updater.CurrentThreadTaskExecutor;
 import org.apache.qpid.server.configuration.updater.TaskExecutor;
@@ -327,6 +332,88 @@ public class AmqpPortImplTest extends UnitTestBase
         assertFalse(_port.canAcceptNewConnection(new InetSocketAddress("example.org", 0)));
     }
 
+    @Test
+    public void testTlProtocolsAndCypherSuitesUsingAllowDenyListContextVariable()
+    {
+        final Map<String, String> brokerContext = new HashMap<>();
+        brokerContext.put(CommonProperties.QPID_SECURITY_TLS_PROTOCOL_ALLOW_LIST, "[\"TLSv1.3\"]");
+        brokerContext.put(CommonProperties.QPID_SECURITY_TLS_PROTOCOL_DENY_LIST, "[\"Ssl.*\",\"TLSv1\",\"TLSv1.1\",\"TLSv1.2\"]");
+        brokerContext.put(CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_ALLOW_LIST, "[\"(TLS|SSL)_AES_128_GCM_SHA256\", \"(TLS|SSL)_AES_256_GCM_SHA384\"]");
+        brokerContext.put(CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_DENY_LIST, "[\".*CBC.*\"]");
+
+        when(_broker.getContext()).thenReturn(brokerContext);
+
+        _port = createPort(getTestName());
+        final List<String> expectedAllowedTlsProtocols = Collections.singletonList("TLSv1.3");
+        final List<String> expectedDeniedTlsProtocols = Arrays.asList("Ssl.*","TLSv1","TLSv1.1","TLSv1.2");
+        final List<String> expectedAllowedTlsCypherSuites = Arrays.asList("(TLS|SSL)_AES_128_GCM_SHA256", "(TLS|SSL)_AES_256_GCM_SHA384");
+        final List<String> expectedDeniedTlsCypherSuites = Collections.singletonList(".*CBC.*");
+        assertThat(_port.getTlsProtocolAllowList(), is(equalTo(expectedAllowedTlsProtocols)));
+        assertThat(_port.getTlsProtocolWhiteList(), is(equalTo(expectedAllowedTlsProtocols)));
+        assertThat(_port.getTlsProtocolDenyList(), is(equalTo(expectedDeniedTlsProtocols)));
+        assertThat(_port.getTlsProtocolBlackList(), is(equalTo(expectedDeniedTlsProtocols)));
+        assertThat(_port.getTlsCipherSuiteAllowList(), is(equalTo(expectedAllowedTlsCypherSuites)));
+        assertThat(_port.getTlsCipherSuiteWhiteList(), is(equalTo(expectedAllowedTlsCypherSuites)));
+        assertThat(_port.getTlsCipherSuiteDenyList(), is(equalTo(expectedDeniedTlsCypherSuites)));
+        assertThat(_port.getTlsCipherSuiteBlackList(), is(equalTo(expectedDeniedTlsCypherSuites)));
+    }
+
+    @Test
+    public void testTlProtocolsAndCypherSuitesUsingWhiteBlackListContextVariable()
+    {
+        final Map<String, String> brokerContext = new HashMap<>();
+        brokerContext.put(CommonProperties.QPID_SECURITY_TLS_PROTOCOL_WHITE_LIST, "[\"TLSv1.3\"]");
+        brokerContext.put(CommonProperties.QPID_SECURITY_TLS_PROTOCOL_BLACK_LIST, "[\"Ssl.*\",\"TLSv1\",\"TLSv1.1\",\"TLSv1.2\"]");
+        brokerContext.put(CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_WHITE_LIST, "[\"(TLS|SSL)_AES_128_GCM_SHA256\", \"(TLS|SSL)_AES_256_GCM_SHA384\"]");
+        brokerContext.put(CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_BLACK_LIST, "[\".*CBC.*\"]");
+
+        when(_broker.getContext()).thenReturn(brokerContext);
+
+        _port = createPort(getTestName());
+        final List<String> expectedAllowedTlsProtocols = Collections.singletonList("TLSv1.3");
+        final List<String> expectedDeniedTlsProtocols = Arrays.asList("Ssl.*","TLSv1","TLSv1.1","TLSv1.2");
+        final List<String> expectedAllowedTlsCypherSuites = Arrays.asList("(TLS|SSL)_AES_128_GCM_SHA256", "(TLS|SSL)_AES_256_GCM_SHA384");
+        final List<String> expectedDeniedTlsCypherSuites = Collections.singletonList(".*CBC.*");
+        assertThat(_port.getTlsProtocolAllowList(), is(equalTo(expectedAllowedTlsProtocols)));
+        assertThat(_port.getTlsProtocolWhiteList(), is(equalTo(expectedAllowedTlsProtocols)));
+        assertThat(_port.getTlsProtocolDenyList(), is(equalTo(expectedDeniedTlsProtocols)));
+        assertThat(_port.getTlsProtocolBlackList(), is(equalTo(expectedDeniedTlsProtocols)));
+        assertThat(_port.getTlsCipherSuiteAllowList(), is(equalTo(expectedAllowedTlsCypherSuites)));
+        assertThat(_port.getTlsCipherSuiteWhiteList(), is(equalTo(expectedAllowedTlsCypherSuites)));
+        assertThat(_port.getTlsCipherSuiteDenyList(), is(equalTo(expectedDeniedTlsCypherSuites)));
+        assertThat(_port.getTlsCipherSuiteBlackList(), is(equalTo(expectedDeniedTlsCypherSuites)));
+    }
+
+    @Test
+    public void testTlProtocolsAndCypherSuitesUsingAllowDenyAndWhiteBlackListContextVariable()
+    {
+        final Map<String, String> brokerContext = new HashMap<>();
+        brokerContext.put(CommonProperties.QPID_SECURITY_TLS_PROTOCOL_ALLOW_LIST, "[\"TLSv1.3\"]");
+        brokerContext.put(CommonProperties.QPID_SECURITY_TLS_PROTOCOL_DENY_LIST, "[\"Ssl.*\",\"TLSv1\",\"TLSv1.1\",\"TLSv1.2\"]");
+        brokerContext.put(CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_ALLOW_LIST, "[\"(TLS|SSL)_AES_128_GCM_SHA256\", \"(TLS|SSL)_AES_256_GCM_SHA384\"]");
+        brokerContext.put(CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_DENY_LIST, "[\".*CBC.*\"]");
+        brokerContext.put(CommonProperties.QPID_SECURITY_TLS_PROTOCOL_WHITE_LIST, "[\"TLSv1.2\"]");
+        brokerContext.put(CommonProperties.QPID_SECURITY_TLS_PROTOCOL_BLACK_LIST, "[\"Ssl.*\",\"TLSv1\",\"TLSv1.1\",\"TLSv1.3\"]");
+        brokerContext.put(CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_WHITE_LIST, "[\".*CBC.*\"]");
+        brokerContext.put(CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_BLACK_LIST, "[\".*GCM.*\"]");
+
+        when(_broker.getContext()).thenReturn(brokerContext);
+
+        _port = createPort(getTestName());
+        final List<String> expectedAllowedTlsProtocols = Collections.singletonList("TLSv1.3");
+        final List<String> expectedDeniedTlsProtocols = Arrays.asList("Ssl.*","TLSv1","TLSv1.1","TLSv1.2");
+        final List<String> expectedAllowedTlsCypherSuites = Arrays.asList("(TLS|SSL)_AES_128_GCM_SHA256", "(TLS|SSL)_AES_256_GCM_SHA384");
+        final List<String> expectedDeniedTlsCypherSuites = Collections.singletonList(".*CBC.*");
+        assertThat(_port.getTlsProtocolAllowList(), is(equalTo(expectedAllowedTlsProtocols)));
+        assertThat(_port.getTlsProtocolWhiteList(), is(equalTo(expectedAllowedTlsProtocols)));
+        assertThat(_port.getTlsProtocolDenyList(), is(equalTo(expectedDeniedTlsProtocols)));
+        assertThat(_port.getTlsProtocolBlackList(), is(equalTo(expectedDeniedTlsProtocols)));
+        assertThat(_port.getTlsCipherSuiteAllowList(), is(equalTo(expectedAllowedTlsCypherSuites)));
+        assertThat(_port.getTlsCipherSuiteWhiteList(), is(equalTo(expectedAllowedTlsCypherSuites)));
+        assertThat(_port.getTlsCipherSuiteDenyList(), is(equalTo(expectedDeniedTlsCypherSuites)));
+        assertThat(_port.getTlsCipherSuiteBlackList(), is(equalTo(expectedDeniedTlsCypherSuites)));
+    }
+
     private AmqpPortImpl createPort(final String portName)
     {
         return createPort(portName, Collections.emptyMap());
diff --git a/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManagerTest.java b/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManagerTest.java
index ed33947..17e6eb8 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManagerTest.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManagerTest.java
@@ -20,9 +20,12 @@ package org.apache.qpid.server.security.auth.manager;
 
 import static java.nio.charset.StandardCharsets.UTF_8;
 import static org.apache.qpid.server.security.auth.manager.CachingAuthenticationProvider.AUTHENTICATION_CACHE_MAX_SIZE;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.not;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
 import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeThat;
 import static org.mockito.Mockito.mock;
@@ -36,6 +39,7 @@ import java.nio.file.Path;
 import java.security.Principal;
 import java.security.PrivilegedAction;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
@@ -80,6 +84,7 @@ import org.junit.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import org.apache.qpid.server.configuration.CommonProperties;
 import org.apache.qpid.server.configuration.IllegalConfigurationException;
 import org.apache.qpid.server.model.Broker;
 import org.apache.qpid.server.model.BrokerTestHelper;
@@ -330,6 +335,70 @@ public class SimpleLDAPAuthenticationManagerTest extends UnitTestBase
         assertEquals(USER_1_DN, result.getMainPrincipal().getName());
     }
 
+    @Test
+    public void testTlProtocolsAndCypherSuitesUsingAllowDenyListContextVariable()
+    {
+        if (_authenticationProvider != null)
+        {
+            _authenticationProvider.close();
+        }
+
+        final Map<String, String> context = new HashMap<>();
+        context.put(CommonProperties.QPID_SECURITY_TLS_PROTOCOL_ALLOW_LIST, "[\"TLSv1.3\"]");
+        context.put(CommonProperties.QPID_SECURITY_TLS_PROTOCOL_DENY_LIST, "[\"Ssl.*\",\"TLSv1\",\"TLSv1.1\",\"TLSv1.2\"]");
+        context.put(CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_ALLOW_LIST, "[\"(TLS|SSL)_AES_128_GCM_SHA256\", \"(TLS|SSL)_AES_256_GCM_SHA384\"]");
+        context.put(CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_DENY_LIST, "[\".*CBC.*\"]");
+
+        final Map<String, Object> attributes =
+                Collections.singletonMap(SimpleLDAPAuthenticationManager.CONTEXT, context);
+        _authenticationProvider = createAuthenticationProvider(attributes);
+
+        final List<String> expectedAllowedTlsProtocols = Collections.singletonList("TLSv1.3");
+        final List<String> expectedDeniedTlsProtocols = Arrays.asList("Ssl.*", "TLSv1", "TLSv1.1", "TLSv1.2");
+        final List<String> expectedAllowedTlsCypherSuites = Arrays.asList("(TLS|SSL)_AES_128_GCM_SHA256", "(TLS|SSL)_AES_256_GCM_SHA384");
+        final List<String> expectedDeniedTlsCypherSuites = Collections.singletonList(".*CBC.*");
+        assertThat(_authenticationProvider.getTlsProtocolAllowList(), is(equalTo(expectedAllowedTlsProtocols)));
+        assertThat(_authenticationProvider.getTlsProtocolWhiteList(), is(equalTo(expectedAllowedTlsProtocols)));
+        assertThat(_authenticationProvider.getTlsProtocolDenyList(), is(equalTo(expectedDeniedTlsProtocols)));
+        assertThat(_authenticationProvider.getTlsProtocolBlackList(), is(equalTo(expectedDeniedTlsProtocols)));
+        assertThat(_authenticationProvider.getTlsCipherSuiteAllowList(), is(equalTo(expectedAllowedTlsCypherSuites)));
+        assertThat(_authenticationProvider.getTlsCipherSuiteWhiteList(), is(equalTo(expectedAllowedTlsCypherSuites)));
+        assertThat(_authenticationProvider.getTlsCipherSuiteDenyList(), is(equalTo(expectedDeniedTlsCypherSuites)));
+        assertThat(_authenticationProvider.getTlsCipherSuiteBlackList(), is(equalTo(expectedDeniedTlsCypherSuites)));
+    }
+
+    @Test
+    public void testTlProtocolsAndCypherSuitesUsingBlackWhiteListContextVariable()
+    {
+        if (_authenticationProvider != null)
+        {
+            _authenticationProvider.close();
+        }
+
+        final Map<String, String> context = new HashMap<>();
+        context.put(CommonProperties.QPID_SECURITY_TLS_PROTOCOL_WHITE_LIST, "[\"TLSv1.3\"]");
+        context.put(CommonProperties.QPID_SECURITY_TLS_PROTOCOL_BLACK_LIST, "[\"Ssl.*\",\"TLSv1\",\"TLSv1.1\",\"TLSv1.2\"]");
+        context.put(CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_WHITE_LIST, "[\"(TLS|SSL)_AES_128_GCM_SHA256\", \"(TLS|SSL)_AES_256_GCM_SHA384\"]");
+        context.put(CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_BLACK_LIST, "[\".*CBC.*\"]");
+
+        final Map<String, Object> attributes =
+                Collections.singletonMap(SimpleLDAPAuthenticationManager.CONTEXT, context);
+        _authenticationProvider = createAuthenticationProvider(attributes);
+
+        final List<String> expectedAllowedTlsProtocols = Collections.singletonList("TLSv1.3");
+        final List<String> expectedDeniedTlsProtocols = Arrays.asList("Ssl.*", "TLSv1", "TLSv1.1", "TLSv1.2");
+        final List<String> expectedAllowedTlsCypherSuites = Arrays.asList("(TLS|SSL)_AES_128_GCM_SHA256", "(TLS|SSL)_AES_256_GCM_SHA384");
+        final List<String> expectedDeniedTlsCypherSuites = Collections.singletonList(".*CBC.*");
+        assertThat(_authenticationProvider.getTlsProtocolAllowList(), is(equalTo(expectedAllowedTlsProtocols)));
+        assertThat(_authenticationProvider.getTlsProtocolWhiteList(), is(equalTo(expectedAllowedTlsProtocols)));
+        assertThat(_authenticationProvider.getTlsProtocolDenyList(), is(equalTo(expectedDeniedTlsProtocols)));
+        assertThat(_authenticationProvider.getTlsProtocolBlackList(), is(equalTo(expectedDeniedTlsProtocols)));
+        assertThat(_authenticationProvider.getTlsCipherSuiteAllowList(), is(equalTo(expectedAllowedTlsCypherSuites)));
+        assertThat(_authenticationProvider.getTlsCipherSuiteWhiteList(), is(equalTo(expectedAllowedTlsCypherSuites)));
+        assertThat(_authenticationProvider.getTlsCipherSuiteDenyList(), is(equalTo(expectedDeniedTlsCypherSuites)));
+        assertThat(_authenticationProvider.getTlsCipherSuiteBlackList(), is(equalTo(expectedDeniedTlsCypherSuites)));
+    }
+
     private SimpleLDAPAuthenticationManagerImpl createAuthenticationProvider()
     {
         return createAuthenticationProvider(Collections.emptyMap());
diff --git a/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/oauth2/OAuth2AuthenticationProviderImplTest.java b/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/oauth2/OAuth2AuthenticationProviderImplTest.java
index f4348dd..8d960dd 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/oauth2/OAuth2AuthenticationProviderImplTest.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/oauth2/OAuth2AuthenticationProviderImplTest.java
@@ -20,14 +20,19 @@
  */
 package org.apache.qpid.server.security.auth.manager.oauth2;
 
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import javax.net.ssl.HostnameVerifier;
@@ -41,6 +46,7 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
+import org.apache.qpid.server.configuration.CommonProperties;
 import org.apache.qpid.server.configuration.updater.CurrentThreadTaskExecutor;
 import org.apache.qpid.server.configuration.updater.TaskExecutor;
 import org.apache.qpid.server.model.Broker;
@@ -50,6 +56,7 @@ import org.apache.qpid.server.model.NamedAddressSpace;
 import org.apache.qpid.server.model.State;
 import org.apache.qpid.server.security.auth.AuthenticationResult;
 import org.apache.qpid.server.security.auth.manager.CachingAuthenticationProvider;
+import org.apache.qpid.server.security.auth.manager.SimpleLDAPAuthenticationManager;
 import org.apache.qpid.server.security.auth.manager.oauth2.cloudfoundry.CloudFoundryOAuth2IdentityResolverService;
 import org.apache.qpid.server.security.auth.sasl.SaslNegotiator;
 import org.apache.qpid.server.security.auth.sasl.oauth2.OAuth2Negotiator;
@@ -93,6 +100,20 @@ public class OAuth2AuthenticationProviderImplTest extends UnitTestBase
         _server = new OAuth2MockEndpointHolder();
         _server.start();
 
+        _authProvider = createAuthenticationProvider(Collections.emptyMap());
+
+        assertEquals("Could not successfully open authProvider", State.ACTIVE, _authProvider.getState());
+
+        final TrustManager[] trustingTrustManager = new TrustManager[] {new TrustingTrustManager() };
+
+        final SSLContext sc = SSLContext.getInstance("SSL");
+        sc.init(null, trustingTrustManager, new java.security.SecureRandom());
+        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
+        HttpsURLConnection.setDefaultHostnameVerifier(new BlindHostnameVerifier());
+    }
+
+    private OAuth2AuthenticationProvider<?> createAuthenticationProvider(Map<String, Object> attributes)
+    {
         Broker broker = BrokerTestHelper.createBrokerMock();
         TaskExecutor taskExecutor = CurrentThreadTaskExecutor.newStartedInstance();
         when(broker.getTaskExecutor()).thenReturn(taskExecutor);
@@ -125,18 +146,13 @@ public class OAuth2AuthenticationProviderImplTest extends UnitTestBase
                                                  TEST_POST_LOGOUT_PATH));
         authProviderAttributes.put("scope", TEST_SCOPE);
         authProviderAttributes.put("trustStore", TEST_TRUST_STORE_NAME);
+        authProviderAttributes.putAll(attributes);
 
         setTestSystemProperty(CachingAuthenticationProvider.AUTHENTICATION_CACHE_MAX_SIZE, "0");
-        _authProvider = new OAuth2AuthenticationProviderImpl(authProviderAttributes, broker);
-        _authProvider.open();
-        assertEquals("Could not successfully open authProvider", State.ACTIVE, _authProvider.getState());
-
-        final TrustManager[] trustingTrustManager = new TrustManager[] {new TrustingTrustManager() };
-
-        final SSLContext sc = SSLContext.getInstance("SSL");
-        sc.init(null, trustingTrustManager, new java.security.SecureRandom());
-        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
-        HttpsURLConnection.setDefaultHostnameVerifier(new BlindHostnameVerifier());
+        final OAuth2AuthenticationProviderImpl authenticationProvider =
+                new OAuth2AuthenticationProviderImpl(authProviderAttributes, broker);
+        authenticationProvider.open();
+        return authenticationProvider;
     }
 
     @After
@@ -250,6 +266,61 @@ public class OAuth2AuthenticationProviderImplTest extends UnitTestBase
         assertFailure(authenticationResult, "invalid_token");
     }
 
+    @Test
+    public void testTlProtocolsAndCypherSuitesUsingAllowDenyListContextVariable()
+    {
+        final Map<String, String> context = new HashMap<>();
+        context.put(CommonProperties.QPID_SECURITY_TLS_PROTOCOL_ALLOW_LIST, "[\"TLSv1.3\"]");
+        context.put(CommonProperties.QPID_SECURITY_TLS_PROTOCOL_DENY_LIST, "[\"Ssl.*\",\"TLSv1\",\"TLSv1.1\",\"TLSv1.2\"]");
+        context.put(CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_ALLOW_LIST, "[\"(TLS|SSL)_AES_128_GCM_SHA256\", \"(TLS|SSL)_AES_256_GCM_SHA384\"]");
+        context.put(CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_DENY_LIST, "[\".*CBC.*\"]");
+
+        final Map<String, Object> attributes =
+                Collections.singletonMap(SimpleLDAPAuthenticationManager.CONTEXT, context);
+        final OAuth2AuthenticationProvider<?> _authenticationProvider = createAuthenticationProvider(attributes);
+
+        final List<String> expectedAllowedTlsProtocols = Collections.singletonList("TLSv1.3");
+        final List<String> expectedDeniedTlsProtocols = Arrays.asList("Ssl.*", "TLSv1", "TLSv1.1", "TLSv1.2");
+        final List<String> expectedAllowedTlsCypherSuites = Arrays.asList("(TLS|SSL)_AES_128_GCM_SHA256", "(TLS|SSL)_AES_256_GCM_SHA384");
+        final List<String> expectedDeniedTlsCypherSuites = Collections.singletonList(".*CBC.*");
+        assertThat(_authenticationProvider.getTlsProtocolAllowList(), is(equalTo(expectedAllowedTlsProtocols)));
+        assertThat(_authenticationProvider.getTlsProtocolWhiteList(), is(equalTo(expectedAllowedTlsProtocols)));
+        assertThat(_authenticationProvider.getTlsProtocolDenyList(), is(equalTo(expectedDeniedTlsProtocols)));
+        assertThat(_authenticationProvider.getTlsProtocolBlackList(), is(equalTo(expectedDeniedTlsProtocols)));
+        assertThat(_authenticationProvider.getTlsCipherSuiteAllowList(), is(equalTo(expectedAllowedTlsCypherSuites)));
+        assertThat(_authenticationProvider.getTlsCipherSuiteWhiteList(), is(equalTo(expectedAllowedTlsCypherSuites)));
+        assertThat(_authenticationProvider.getTlsCipherSuiteDenyList(), is(equalTo(expectedDeniedTlsCypherSuites)));
+        assertThat(_authenticationProvider.getTlsCipherSuiteBlackList(), is(equalTo(expectedDeniedTlsCypherSuites)));
+    }
+
+    @Test
+    public void testTlProtocolsAndCypherSuitesUsingBlackWhiteListContextVariable()
+    {
+        final Map<String, String> context = new HashMap<>();
+        context.put(CommonProperties.QPID_SECURITY_TLS_PROTOCOL_WHITE_LIST, "[\"TLSv1.3\"]");
+        context.put(CommonProperties.QPID_SECURITY_TLS_PROTOCOL_BLACK_LIST, "[\"Ssl.*\",\"TLSv1\",\"TLSv1.1\",\"TLSv1.2\"]");
+        context.put(CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_WHITE_LIST, "[\"(TLS|SSL)_AES_128_GCM_SHA256\", \"(TLS|SSL)_AES_256_GCM_SHA384\"]");
+        context.put(CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_BLACK_LIST, "[\".*CBC.*\"]");
+
+        final Map<String, Object> attributes =
+                Collections.singletonMap(SimpleLDAPAuthenticationManager.CONTEXT, context);
+        final OAuth2AuthenticationProvider<?> _authenticationProvider = createAuthenticationProvider(attributes);
+
+        final List<String> expectedAllowedTlsProtocols = Collections.singletonList("TLSv1.3");
+        final List<String> expectedDeniedTlsProtocols = Arrays.asList("Ssl.*", "TLSv1", "TLSv1.1", "TLSv1.2");
+        final List<String> expectedAllowedTlsCypherSuites = Arrays.asList("(TLS|SSL)_AES_128_GCM_SHA256", "(TLS|SSL)_AES_256_GCM_SHA384");
+        final List<String> expectedDeniedTlsCypherSuites = Collections.singletonList(".*CBC.*");
+        assertThat(_authenticationProvider.getTlsProtocolAllowList(), is(equalTo(expectedAllowedTlsProtocols)));
+        assertThat(_authenticationProvider.getTlsProtocolWhiteList(), is(equalTo(expectedAllowedTlsProtocols)));
+        assertThat(_authenticationProvider.getTlsProtocolDenyList(), is(equalTo(expectedDeniedTlsProtocols)));
+        assertThat(_authenticationProvider.getTlsProtocolBlackList(), is(equalTo(expectedDeniedTlsProtocols)));
+        assertThat(_authenticationProvider.getTlsCipherSuiteAllowList(), is(equalTo(expectedAllowedTlsCypherSuites)));
+        assertThat(_authenticationProvider.getTlsCipherSuiteWhiteList(), is(equalTo(expectedAllowedTlsCypherSuites)));
+        assertThat(_authenticationProvider.getTlsCipherSuiteDenyList(), is(equalTo(expectedDeniedTlsCypherSuites)));
+        assertThat(_authenticationProvider.getTlsCipherSuiteBlackList(), is(equalTo(expectedDeniedTlsCypherSuites)));
+    }
+
+
     private void assertSuccess(final AuthenticationResult authenticationResult)
     {
         assertEquals("Authentication was not successful: " + authenticationResult.getCause(),
diff --git a/systests/qpid-systests-spawn-admin/src/main/java/org/apache/qpid/systests/admin/SpawnBrokerAdmin.java b/systests/qpid-systests-spawn-admin/src/main/java/org/apache/qpid/systests/admin/SpawnBrokerAdmin.java
index c5a076c..9fa9235 100644
--- a/systests/qpid-systests-spawn-admin/src/main/java/org/apache/qpid/systests/admin/SpawnBrokerAdmin.java
+++ b/systests/qpid-systests-spawn-admin/src/main/java/org/apache/qpid/systests/admin/SpawnBrokerAdmin.java
@@ -732,8 +732,6 @@ public class SpawnBrokerAdmin implements BrokerAdmin, Closeable
 
         List<String> jvmArguments = new ArrayList<>();
         jvmArguments.add("java");
-        jvmArguments.add("-cp");
-        jvmArguments.add(classpath);
         jvmArguments.add("-Djava.io.tmpdir=" + escape(System.getProperty("java.io.tmpdir")));
         jvmArguments.add("-Dlogback.configurationFile=default-broker-logback.xml");
         jvmArguments.add("-Dqpid.tests.mms.messagestore.persistence=true");
@@ -766,7 +764,9 @@ public class SpawnBrokerAdmin implements BrokerAdmin, Closeable
         String[] cmd = jvmArguments.toArray(new String[jvmArguments.size()]);
 
         LOGGER.debug("command line:" + String.join(" ", jvmArguments));
-        return new ProcessBuilder(cmd);
+        ProcessBuilder ps = new ProcessBuilder(cmd);
+        ps.environment().put("CLASSPATH", classpath);
+        return ps;
     }
 
     private String escape(String value)
@@ -824,16 +824,18 @@ public class SpawnBrokerAdmin implements BrokerAdmin, Closeable
 
     private void doWindowsKill()
     {
-        try
+        if (_pid != null)
         {
-
-            Process p;
-            p = Runtime.getRuntime().exec(new String[]{"taskkill", "/PID", Integer.toString(_pid), "/T", "/F"});
-            consumeAllOutput(p);
-        }
-        catch (IOException e)
-        {
-            LOGGER.error("Error whilst killing process " + _pid, e);
+            try
+            {
+                Process p;
+                p = Runtime.getRuntime().exec(new String[]{"taskkill", "/PID", Integer.toString(_pid), "/T", "/F"});
+                consumeAllOutput(p);
+            }
+            catch (IOException e)
+            {
+                LOGGER.error("Error whilst killing process " + _pid, e);
+            }
         }
     }
 
diff --git a/systests/qpid-systests-spawn-admin/src/test/java/org/apache/qpid/systests/admin/SpawnBrokerAdminTest.java b/systests/qpid-systests-spawn-admin/src/test/java/org/apache/qpid/systests/admin/SpawnBrokerAdminTest.java
index c6a9164..05956ba 100644
--- a/systests/qpid-systests-spawn-admin/src/test/java/org/apache/qpid/systests/admin/SpawnBrokerAdminTest.java
+++ b/systests/qpid-systests-spawn-admin/src/test/java/org/apache/qpid/systests/admin/SpawnBrokerAdminTest.java
@@ -34,10 +34,8 @@ import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeThat;
 
 import java.io.File;
-import java.io.IOException;
 import java.net.InetSocketAddress;
 import java.nio.file.Files;
-import java.util.Arrays;
 
 import javax.jms.Connection;
 import javax.jms.DeliveryMode;
@@ -157,7 +155,8 @@ public class SpawnBrokerAdminTest extends UnitTestBase
     @Test
     public void afterTestClass() throws Exception
     {
-        try (SpawnBrokerAdmin admin = new SpawnBrokerAdmin())
+        SpawnBrokerAdmin admin = new SpawnBrokerAdmin();
+        try
         {
             admin.beforeTestClass(SpawnBrokerAdminTest.class);
             admin.beforeTestMethod(SpawnBrokerAdminTest.class, getClass().getMethod("afterTestClass"));
@@ -180,6 +179,17 @@ public class SpawnBrokerAdminTest extends UnitTestBase
             {
                 // pass
             }
+            finally
+            {
+                admin = null;
+            }
+        }
+        finally
+        {
+            if (admin != null)
+            {
+                admin.close();
+            }
         }
     }
 


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[qpid-broker-j] 05/10: QPID-8459: [Broker-J] AnonymousInteractiveAuthenticator uses request.getRequestDispatcher().forward() instead of parsing request URL

Posted by or...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

orudyy pushed a commit to branch 7.1.x
in repository https://gitbox.apache.org/repos/asf/qpid-broker-j.git

commit 351f4497b3ff64624170fbc63153d07655a86d3d
Author: Tomas Vavricka <to...@deutsche-boerse.com>
AuthorDate: Wed Aug 5 06:13:28 2020 +0000

    QPID-8459: [Broker-J] AnonymousInteractiveAuthenticator uses request.getRequestDispatcher().forward() instead of parsing request URL
    
    (cherry picked from commit 6676f224ff7e9149d077bddec1931ac5a9f46546)
---
 .../auth/AnonymousInteractiveAuthenticator.java    | 88 ++++++++++------------
 .../auth/UsernamePasswordInteractiveLogin.java     | 17 +----
 .../PreemptiveAuthenticationTest.java              |  4 +-
 3 files changed, 42 insertions(+), 67 deletions(-)

diff --git a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/auth/AnonymousInteractiveAuthenticator.java b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/auth/AnonymousInteractiveAuthenticator.java
index f165974..c0ad0ab 100644
--- a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/auth/AnonymousInteractiveAuthenticator.java
+++ b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/auth/AnonymousInteractiveAuthenticator.java
@@ -20,10 +20,13 @@
 
 package org.apache.qpid.server.management.plugin.auth;
 
+import java.io.IOException;
 import java.security.AccessControlException;
 
 import javax.security.auth.Subject;
+import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -54,45 +57,9 @@ public class AnonymousInteractiveAuthenticator implements HttpRequestInteractive
                                                           final HttpManagementConfiguration configuration)
     {
         final Port<?> port = configuration.getPort(request);
-        if(configuration.getAuthenticationProvider(request) instanceof AnonymousAuthenticationManager)
+        if (configuration.getAuthenticationProvider(request) instanceof AnonymousAuthenticationManager)
         {
-            return response ->
-            {
-                AnonymousAuthenticationManager authenticationProvider =
-                        (AnonymousAuthenticationManager) configuration.getAuthenticationProvider(request);
-                AuthenticationResult authenticationResult = authenticationProvider.getAnonymousAuthenticationResult();
-                try
-                {
-                    SubjectAuthenticationResult result = port.getSubjectCreator(request.isSecure(), request.getServerName()).createResultWithGroups(authenticationResult);
-                    Subject original = result.getSubject();
-
-                    if (original == null)
-                    {
-                        throw new SecurityException("Only authenticated users can access the management interface");
-                    }
-                    Subject subject = HttpManagementUtil.createServletConnectionSubject(request, original);
-                    Broker broker = (Broker) authenticationProvider.getParent();
-                    HttpManagementUtil.assertManagementAccess(broker, subject);
-                    HttpManagementUtil.saveAuthorisedSubject(request, subject);
-
-                    String originalRequestUri = getOriginalRequestUri(request);
-                    LOGGER.debug("Successful login. Redirect to original resource {}", originalRequestUri);
-                    response.sendRedirect(originalRequestUri);
-                }
-                catch (SecurityException e)
-                {
-                    if (e instanceof AccessControlException)
-                    {
-                        LOGGER.info("User '{}' is not authorised for management", authenticationResult.getMainPrincipal());
-                        response.sendError(403, "User is not authorised for management");
-                    }
-                    else
-                    {
-                        LOGGER.info("Authentication failed", authenticationResult.getCause());
-                        response.sendError(401);
-                    }
-                }
-            };
+            return response -> getLoginHandler(request, response, configuration, port);
         }
         else
         {
@@ -100,6 +67,39 @@ public class AnonymousInteractiveAuthenticator implements HttpRequestInteractive
         }
     }
 
+    private void getLoginHandler(HttpServletRequest request, HttpServletResponse response,
+                                 HttpManagementConfiguration configuration, Port<?> port) throws ServletException, IOException
+    {
+        final AnonymousAuthenticationManager authenticationProvider =
+                (AnonymousAuthenticationManager) configuration.getAuthenticationProvider(request);
+        final AuthenticationResult authenticationResult = authenticationProvider.getAnonymousAuthenticationResult();
+        try
+        {
+            final SubjectAuthenticationResult result = port.getSubjectCreator(request.isSecure(), request.getServerName()).createResultWithGroups(authenticationResult);
+            final Subject original = result.getSubject();
+
+            if (original == null)
+            {
+                throw new SecurityException("Only authenticated users can access the management interface");
+            }
+            final Subject subject = HttpManagementUtil.createServletConnectionSubject(request, original);
+            final Broker broker = (Broker) authenticationProvider.getParent();
+            HttpManagementUtil.assertManagementAccess(broker, subject);
+            HttpManagementUtil.saveAuthorisedSubject(request, subject);
+            request.getRequestDispatcher(HttpManagement.DEFAULT_LOGIN_URL).forward(request, response);
+        }
+        catch (AccessControlException e)
+        {
+            LOGGER.info("User '{}' is not authorised for management", authenticationResult.getMainPrincipal());
+            response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not authorised for management");
+        }
+        catch (SecurityException e)
+        {
+            LOGGER.info("Authentication failed", authenticationResult.getCause());
+            response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
+        }
+    }
+
     @Override
     public LogoutHandler getLogoutHandler(final HttpServletRequest request,
                                           final HttpManagementConfiguration configuration)
@@ -119,16 +119,4 @@ public class AnonymousInteractiveAuthenticator implements HttpRequestInteractive
     {
         return ANONYMOUS;
     }
-
-    private String getOriginalRequestUri(final HttpServletRequest request)
-    {
-        StringBuffer originalRequestURL = request.getRequestURL();
-        final String queryString = request.getQueryString();
-        if (queryString != null)
-        {
-            originalRequestURL.append("?").append(queryString);
-        }
-        return originalRequestURL.toString();
-    }
-
 }
diff --git a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/auth/UsernamePasswordInteractiveLogin.java b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/auth/UsernamePasswordInteractiveLogin.java
index 4f7b98b..541ee43 100644
--- a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/auth/UsernamePasswordInteractiveLogin.java
+++ b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/auth/UsernamePasswordInteractiveLogin.java
@@ -20,11 +20,7 @@
  */
 package org.apache.qpid.server.management.plugin.auth;
 
-import java.io.IOException;
-
-import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 
 import org.apache.qpid.server.management.plugin.HttpManagement;
 import org.apache.qpid.server.management.plugin.HttpManagementConfiguration;
@@ -35,16 +31,7 @@ import org.apache.qpid.server.security.auth.manager.UsernamePasswordAuthenticati
 @PluggableService
 public class UsernamePasswordInteractiveLogin implements HttpRequestInteractiveAuthenticator
 {
-    private static final String DEFAULT_LOGIN_URL = "/index.html";
-
-    private static  final LogoutHandler LOGOUT_HANDLER = new LogoutHandler()
-    {
-        @Override
-        public void handleLogout(final HttpServletResponse response) throws IOException
-        {
-            response.sendRedirect(HttpManagement.DEFAULT_LOGOUT_URL);
-        }
-    };
+    private static final LogoutHandler LOGOUT_HANDLER = response -> response.sendRedirect(HttpManagement.DEFAULT_LOGOUT_URL);
 
     @Override
     public AuthenticationHandler getAuthenticationHandler(final HttpServletRequest request,
@@ -52,7 +39,7 @@ public class UsernamePasswordInteractiveLogin implements HttpRequestInteractiveA
     {
         if(configuration.getAuthenticationProvider(request) instanceof UsernamePasswordAuthenticationProvider)
         {
-            return response -> request.getRequestDispatcher(DEFAULT_LOGIN_URL).forward(request, response);
+            return response -> request.getRequestDispatcher(HttpManagement.DEFAULT_LOGIN_URL).forward(request, response);
         }
         else
         {
diff --git a/systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/authentication/PreemptiveAuthenticationTest.java b/systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/authentication/PreemptiveAuthenticationTest.java
index ded03df..47b0971 100644
--- a/systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/authentication/PreemptiveAuthenticationTest.java
+++ b/systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/authentication/PreemptiveAuthenticationTest.java
@@ -124,7 +124,7 @@ public class PreemptiveAuthenticationTest extends HttpTestBase
         assumeThat(canGenerateCerts(), is(true));
         HttpTestHelper helper = configForClientAuth("CN=foo");
 
-        HttpURLConnection authenticateConnection = helper.openManagementConnection("/index.html", "GET");
+        HttpURLConnection authenticateConnection = helper.openManagementConnection(HttpManagement.DEFAULT_LOGIN_URL, "GET");
         authenticateConnection.setInstanceFollowRedirects(false);
 
         int status = authenticateConnection.getResponseCode();
@@ -133,7 +133,7 @@ public class PreemptiveAuthenticationTest extends HttpTestBase
 
         assertThat(status, is(equalTo(HttpURLConnection.HTTP_MOVED_TEMP)));
 
-        authenticateConnection = helper.openManagementConnection("/index.html", "GET");
+        authenticateConnection = helper.openManagementConnection(HttpManagement.DEFAULT_LOGIN_URL, "GET");
         authenticateConnection.setRequestProperty("Cookie", cookies);
         status = authenticateConnection.getResponseCode();
         authenticateConnection.disconnect();


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[qpid-broker-j] 06/10: QPID-8461: [Broker-J] Repace Random with SecureRandom

Posted by or...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

orudyy pushed a commit to branch 7.1.x
in repository https://gitbox.apache.org/repos/asf/qpid-broker-j.git

commit ee2293f09fb27262995daf7e0853a5d161be6635
Author: YYTVicky <61...@users.noreply.github.com>
AuthorDate: Wed Apr 29 22:07:25 2020 -0400

    QPID-8461: [Broker-J] Repace Random with SecureRandom
    
    (cherry picked from commit be89e42fb6cd1629d17fae8ddb35a9efeeda85c3)
---
 broker-core/src/main/java/org/apache/qpid/server/util/StringUtil.java | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/broker-core/src/main/java/org/apache/qpid/server/util/StringUtil.java b/broker-core/src/main/java/org/apache/qpid/server/util/StringUtil.java
index 8f785d1..a93ec9c 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/util/StringUtil.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/util/StringUtil.java
@@ -24,6 +24,7 @@ import java.nio.charset.StandardCharsets;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.util.Random;
+import java.security.SecureRandom;
 
 public class StringUtil
 {
@@ -33,7 +34,8 @@ public class StringUtil
     private static final char[] CHARACTERS = (NUMBERS + LETTERS + LETTERS.toUpperCase() + OTHERS).toCharArray();
     private static final char[] HEX = "0123456789ABCDEF".toCharArray();
 
-    private Random _random = new Random();
+   
+    private Random _random = new SecureRandom();
 
     public static String elideDataUrl(final String path)
     {


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[qpid-broker-j] 02/10: NO-JIRA: remove links etc from the documentation, missed from removal in QPID 7487

Posted by or...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

orudyy pushed a commit to branch 7.1.x
in repository https://gitbox.apache.org/repos/asf/qpid-broker-j.git

commit 6ed3dd885a50d5fee676f3a9db77977d8ee34349
Author: Robbie Gemmell <ro...@apache.org>
AuthorDate: Wed Aug 5 13:09:14 2020 +0100

    NO-JIRA: remove links etc from the documentation, missed from removal in QPID 7487
    
    (cherry picked from commit 7ba6bbeef8d402b2e55ced9ca0a83bd71648e1ff)
---
 .../src/docbkx/Java-Broker-Initial-Configuration.xml          | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/doc/java-broker/src/docbkx/Java-Broker-Initial-Configuration.xml b/doc/java-broker/src/docbkx/Java-Broker-Initial-Configuration.xml
index 3a99393..82ab64a 100644
--- a/doc/java-broker/src/docbkx/Java-Broker-Initial-Configuration.xml
+++ b/doc/java-broker/src/docbkx/Java-Broker-Initial-Configuration.xml
@@ -68,8 +68,7 @@
         <para>Broker startup involves two configuration related items, the 'Initial Configuration'
             and the Configuration Store. When the broker is started, if a Configuration Store does
             not exist at the current <link linkend="Java-Broker-Initial-Configuration-Location">store location</link> then one will be initialised with the current <link linkend="Java-Broker-Initial-Configuration-Initial-Config-Location">'Initial
-                Configuration'</link>. Unless otherwise requested to <link linkend="Java-Broker-Initial-Configuration-Location">overwrite the configuration
-                store</link> then subsequent broker restarts will use the existing configuration
+                Configuration'</link>. Subsequent broker restarts will use the existing configuration
             store and ignore the contents of the 'Initial Configuration'. </para>
     </section>
 
@@ -103,8 +102,7 @@ $ ./qpid-server -icp ./my-initial-configuration.json
         </screen>
 
         <para> If a Configuration Store already exists at the current <link linkend="Java-Broker-Initial-Configuration-Location">store location</link> then the
-            current 'Initial Configuration' will be ignored unless otherwise requested to <link linkend="Java-Broker-Initial-Configuration-Location">overwrite the configuration
-                store</link>
+            current 'Initial Configuration' will be ignored.
         </para>
     </section>
 
@@ -247,9 +245,8 @@ $ ./qpid-server -prop "qpid.amqp_port=10000" -prop "qpid.http_port=10001"
         <para> In the example above, property used to set the port number of the default AMQP port
             is specified with the value 10000, overriding the default value of 5672, and similarly
             the value 10001 is used to override the default HTTP port number of 8080. When using the
-            'Initial Configuration' to initialise a new Configuration Store (either at first broker
-            startup, when requesting to <link linkend="Java-Broker-Initial-Configuration-Location">overwrite the configuration store</link>) these new values will be used for the
-            port numbers instead. </para>
+            'Initial Configuration' to initialise a new Configuration Store at first broker
+            startup these new values will be used for the port numbers instead. </para>
         <para> NOTE: When running the broker on Windows and starting it via the qpid-server.bat
             file, the "name=value" argument MUST be quoted. </para>
 


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org